diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/CREDITS linux.14p16/CREDITS
--- linux.vanilla/CREDITS	Wed Oct 20 01:12:32 1999
+++ linux.14p16/CREDITS	Tue Dec 21 00:31:10 1999
@@ -137,12 +137,9 @@
 S: USA
 
 N: James Banks
-E: james.banks@caldera.com
+E: james@sovereign.org
 D: TLAN network driver
-S: Caldera, Inc.
-S: 633 South 550 East
-S: Provo, Utah 84606
-S: USA
+D: Logitech Busmouse driver
 
 N: Paul Barton-Davis
 E: pbd@op.net
@@ -789,12 +786,12 @@
 D: Selection mechanism
 
 N: Jochen Hein
-E: jochen.hein@delphi.central.de
+E: jochen@jochen.org
 P: 1024/4A27F015 25 72 FB E3 85 9F DE 3B  CB 0A DA DA 40 77 05 6C
 D: National Language Support
 D: Linux Internationalization Project
 D: German Localization for Linux and GNU software
-S: Frankenstraße
+S: Frankenstraße 33
 S: 34131 Kassel
 S: Germany
 
@@ -866,7 +863,7 @@
 S: United Kingdom
 
 N: Ron Holt
-E: ron@caldera.com
+E: ron@sovereign.org
 W: http://www.holt.org/
 P: 1024/1FD44539 DF 4B EB 9F 5B 68 38 9A  40 E3 FB 71 D1 C8 0B 56
 D: Kernel development
@@ -942,12 +939,12 @@
 S: United Kingdom
 
 N: Jakub Jelinek
-E: jj@sunsite.mff.cuni.cz
+E: jakub@redhat.com
 W: http://sunsite.mff.cuni.cz/~jj
 P: 1024/0F7623C5 53 95 71 3C EB 73 99 97  02 49 40 47 F9 19 68 20
 D: Sparc hacker, SILO, mc
 D: Maintain sunsite.mff.cuni.cz
-S: Na Orechovce 7
+S: K osmidomkum 723
 S: 160 00 Praha 6
 S: Czech Republic
 
@@ -997,6 +994,7 @@
 
 N: Jan Kara
 E: jack@atrey.karlin.mff.cuni.cz
+E: jack@suse.cz
 D: Quota fixes for 2.2 kernel
 D: Few other fixes in filesystem area (isofs, loopback)
 W: http://atrey.karlin.mff.cuni.cz/~jack/
@@ -1282,11 +1280,11 @@
 S: Czech Republic
 
 N: Paul Mackerras
-E: paulus@cs.anu.edu.au
+E: paulus@linuxcare.com
 D: Linux port for PCI Power Macintosh
-S: Dept. of Computer Science
-S: Australian National University
-S: Canberra  ACT  0200
+S: Linuxcare, Inc.
+S: 24 Marcus Clarke Street
+S: Canberra ACT 2601
 S: Australia
 
 N: Pat Mackinlay
@@ -1535,7 +1533,7 @@
 S: Australia
 
 N: Greg Page
-E: greg@caldera.com
+E: gpage@sovereign.org
 D: IPX development and support
 
 N: David Parsons
@@ -1543,10 +1541,11 @@
 D: improved memory detection code.
 
 N: Vojtech Pavlik
-E: vojtech@ucw.cz
+E: vojtech@suse.cz
 D: Joystick driver
 D: arcnet-hardware readme
 D: Minor ARCnet hacking
+D: USB development
 S: Ucitelska 1576
 S: Prague 8
 S: 182 00 Czech Republic
@@ -1713,8 +1712,8 @@
 S: Germany
 
 N: Stephen Rothwell
-E: Stephen.Rothwell@canb.auug.org.au
-W: http://www.canb.auug.org.au/~sfr
+E: sfr@linuxcare.com
+W: http://linuxcare.com.au/sfr
 P: 1024/BD8C7805 CD A4 9D 01 10 6E 7E 3B  91 88 FA D9 C8 40 AA 02
 D: Boot/setup/build work for setup > 2K
 D: Author, APM driver
@@ -1963,7 +1962,8 @@
 S: Canada K2L 1S2
 
 N: Andrew Tridgell
-E: Andrew.Tridgell@anu.edu.au
+E: tridge@samba.org
+W: http://linuxcare.com.au/tridge/
 D: dosemu, networking, samba
 S: 3 Ballow Crescent
 S: MacGregor A.C.T 2615
@@ -2122,9 +2122,10 @@
 N: Tim Waugh
 E: tim@cyberelk.demon.co.uk
 D: Co-architect of the parallel-port sharing system
-S: 4 Fox Close
-S: Bishopstoke
-S: SO50 8NB
+S: 34 Bladon Close
+S: GUILDFORD
+S: Surrey
+S: GU1 1TY
 S: United Kingdom
 
 N: Juergen Weigert
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/Changes linux.14p16/Documentation/Changes
--- linux.vanilla/Documentation/Changes	Sat Aug 14 02:27:12 1999
+++ linux.14p16/Documentation/Changes	Thu Dec  9 15:34:40 1999
@@ -43,7 +43,7 @@
 
    for all your Linux kernel needs.
 
-Last updated: July 13, 1999
+Last updated: October 13, 1999
 Current Author: Chris Ricker (kaboom@gatech.edu or
 	chris.ricker@genetics.utah.edu).
 
@@ -61,19 +61,20 @@
 - Linux libc6 C Library  2.0.7pre6               ; ls -l /lib/libc*
 - Dynamic Linker (ld.so) 1.9.9                   ; ldd --version or ldd -v
 - Linux C++ Library	 2.7.2.8                 ; ls -l /usr/lib/libg++.so.*
-- Procps		 1.2.9                   ; ps --version
+- Procps		 2.0.3                   ; ps --version
 - Procinfo               16                      ; procinfo -v
 - Psmisc		 17			 ; pstree -V
 - Net-tools              1.52                    ; hostname -V
 - Loadlin                1.6a
 - Sh-utils               1.16                    ; basename --v
-- Autofs                 3.1.1                   ; automount --version
+- Autofs                 3.1.3                   ; automount --version
 - NFS                    2.2beta40               ; showmount --version
 - Bash                   1.14.7                  ; bash -version
 - Ncpfs                  2.2.0                   ; ncpmount -v
-- Pcmcia-cs              3.0.13                  ; cardmgr -V
-- PPP                    2.3.8                   ; pppd --version
-- Util-linux             2.9t                    ; chsh -v
+- Pcmcia-cs              3.0.14                  ; cardmgr -V
+- PPP                    2.3.10                  ; pppd --version
+- Util-linux             2.9z                    ; chsh -v
+- isdn4k-utils           v3.1beta7               ; isdnctrl 2>&1|grep version
 
 Upgrade notes
 *************
@@ -226,7 +227,7 @@
    Note that the latest compilers (egcs, pgcc, gcc 2.8) may do Bad
 Things while compiling your kernel, particularly if absurd
 optimizations (like -O9) are used.  Caveat emptor.  Currently, the only
-C compiler available in a binary distribution is egcs.  Version 1.0.3
+C compiler available in a binary distribution is egcs.  Version 1.1.2
 seems okay; if you have to have a binary, you may be successful using
 that.  In general, however, gcc-2.7.2.3 is known to be stable, while
 egcs and others have not been as thoroughly tested yet.
@@ -272,9 +273,6 @@
    DHCP clients for 2.0 do not work with the new networking code in the
 2.2 kernel.  You will need to upgrade your dhcpcd / dhcpclient.
 
-   The ISDN code in the stock 2.2 kernel may not work for you.  If it
-doesn't, look in ftp://ftp.suse.com/pub/isdn4linux for updated versions.
-
    In 2.0.x the kernel could be configured to drop source routed IP
 packets via a compile time configuration option.  In 2.2.x, this has
 been replaced by a sysctl.  See Documentation/networking/ip-sysctl.txt
@@ -284,8 +282,8 @@
 ======
 
    As of 2.1.41, the format of /proc/meminfo has changed.  This broke
-many memory utils, which have to be upgraded.  Get the new procps-1.2
-and you should be set.
+many memory utils, which have to be upgraded.  Get the new procps and
+you should be set.
 
 Network File System
 ===================
@@ -513,29 +511,26 @@
 
    so be sure to check that when you recompile.
 
+ISDN4Linux
+==========
+Older isdn4k-utils versions don't support EXTRAVERSION into kernel version
+string. A upgrade to isdn4k-utils.v3.1beta7 or later is recomented.
+
 Where to get the files
 **********************
 
 Binutils
 ========
 
-The 2.8.1.0.23 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.1.0.23.bin.tar.gz
-ftp://metalab.unc.edu/pub/Linux/GCC/binutils-2.8.1.0.23.bin.tar.gz
+The 2.9.1.0.25 release:
+ftp://ftp.varesearch.com/pub/support/hjl/binutils/2.9.1/binutils-2.9.1.0.25.tar.gz
 Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.1.0.23
-ftp://metalab.unc.edu/pub/Linux/GCC/release.binutils-2.8.1.0.23
+ftp://ftp.varesearch.com/pub/support/hjl/binutils/2.9.1/release.binutils-2.9.1.0.25
 
-The 2.9.1.0.15 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.15-glibc.x86.tar.gz
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.15-libc5.x86.tar.gz
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.15.tar.gz
-ftp://metalab.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.15-glibc.x86.tar.gz
-ftp://metalab.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.15-libc5.x86.tar.gz
-ftp://metalab.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.15.tar.gz
+The 2.9.5.0.16 release:
+ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.16.tar.bz2
 Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.9.1.0.15
-ftp://metalab.unc.edu/pub/Linux/GCC/release.binutils-2.9.1.0.15
+ftp://ftp.varesearch.com/pub/support/hjl/binutils/release.binutils-2.9.5.0.16
 
 Bin86
 =====
@@ -547,14 +542,12 @@
 Gnu C
 =====
 
-The egcs-1.0.3 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.3-glibc.x86.tar.bz2
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.3-libc5.x86.tar.bz2
-ftp://metalab.unc.edu/pub/Linux/GCC/egcs-1.0.3-glibc.x86.tar.bz2
-ftp://metalab.unc.edu/pub/Linux/GCC/egcs-1.0.3-libc5.x86.tar.bz2
+The egcs-1.1.2 release:
+ftp://ftp.varesearch.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-glibc.x86.tar.bz2
+ftp://ftp.varesearch.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-libc5.x86.tar.bz2
+ftp://ftp.varesearch.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-alpha.x86.tar.bz2
 Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.egcs-1.0.3
-ftp://metalab.unc.edu/pub/Linux/GCC/release.egcs-1.0.3
+ftp://ftp.varesearch.com/pub/support/hjl/gcc/egcs-1.1.2/release.egcs-1.1.2
 
 Gnu C 2.7.2.3 source:
 ftp://ftp.gnu.org/gnu/gcc/gcc-2.7.2.3.tar.gz
@@ -596,15 +589,14 @@
 Procps utilities
 ================
 
-The 1.2 release:
-ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.9.tar.gz
-ftp://metalab.unc.edu/pub/Linux/system/status/ps/procps-1.2.9.tgz
+The 2.0.3 release:
+ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-2.0.3.tar.gz
 
 Procinfo utilities
 ==================
 
-The 16 release:
-ftp://ftp.cistron.nl/pub/people/svm/procinfo-16.tar.gz
+The 17 release:
+ftp://ftp.cistron.nl/pub/people/svm/procinfo-17.tar.gz
 
 Psmisc utilities
 ================
@@ -624,7 +616,6 @@
 ======
 
 The 0.98.6 release:
-ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/dosemu-0.98.6.tgz
 ftp://ftp.dosemu.org/dosemu/dosemu-0.98.6.tgz
 
 Loadlin
@@ -645,7 +636,7 @@
 ==========
 
 The 2.9 release:
-ftp://ftp.win.tue.nl/pub/linux/utils/util-linux/util-linux-2.9t.tar.gz
+ftp://ftp.win.tue.nl/pub/linux/utils/util-linux/util-linux-2.9z.tar.gz
 
 Autofs
 ======
@@ -660,9 +651,9 @@
 ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/nfs-server-2.2beta40.tar.gz
 ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/nfs-server-2.2beta40.tar.gz
 
-The kernel-level 1.4.4 release:
-ftp://ftp.varesearch.com/pub/support/hjl/knfsd/knfsd-1.4.4.tar.gz
-ftp://ftp.kernel.org/pub/linux/devel/gcc/knfsd-1.4.4.tar.gz
+The kernel-level 1.4.7 release:
+ftp://ftp.varesearch.com/pub/support/hjl/knfsd/knfsd-1.4.7.tar.gz
+ftp://ftp.kernel.org/pub/linux/devel/gcc/knfsd-1.4.7.tar.gz
 
 Net-tools
 =========
@@ -707,8 +698,8 @@
 Pcmcia-cs
 =========
 
-The 3.0.13 release:
-ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs.3.0.13.tar.gz
+The 3.0.14 release:
+ftp://sourceforge.org/pcmcia/pcmcia-cs.3.0.14.tar.gz
 
 Setserial
 =========
@@ -720,15 +711,15 @@
 PPP
 ===
 
-The 2.3.8 release:
-ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.8.tar.gz
+The 2.3.10 release:
+ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.10.tar.gz
 
 IP Chains
 =========
 
-The 1.3.8 release:
-ftp://ftp.rustcorp.com/ipchains/ipchains-1.3.8.tar.gz
-ftp://ftp.rustcorp.com/ipchains/ipchains-1.3.8.tar.bz2
+The 1.3.9 release:
+ftp://ftp.rustcorp.com/ipchains/ipchains-1.3.9.tar.gz
+ftp://ftp.rustcorp.com/ipchains/ipchains-1.3.9.tar.bz2
 
 IP Masq Adm
 ===========
@@ -739,11 +730,11 @@
 DHCP clients
 ============
 
-The 2.0b1pl27 ISC dhcpclient release:
-ftp://ftp.isc.org/isc/dhcp/test/dhcp-2.0b1pl27.tar.gz
+The 2.0 ISC dhcpclient release:
+ftp://ftp.isc.org/isc/dhcp/test/dhcp-2.0.tar.gz
 
-The 1.3.17-pl2 PhysTech dhcpcd release:
-ftp://ftp.phystech.com/pub/dhcpcd-1.3.17-pl2.tar.gz
+The 1.3.18-pl1 PhysTech dhcpcd release:
+ftp://ftp.phystech.com/pub/dhcpcd-1.3.18-pl1.tar.gz
 
 iBCS
 ====
@@ -754,8 +745,8 @@
 Asun netatalk
 =============
 
-The 2.0a18.2 release:
-ftp://ftp.u.washington.edu/pub/user-supported/asun/netatalk-1.4b2+asun2.0a18.2.tar.gz
+The 2.1.3 release:
+ftp://ftp.u.washington.edu/pub/user-supported/asun/netatalk-1.4b2+asun2.1.3.tar.gz
 
 Fbset
 =====
@@ -792,15 +783,20 @@
 IP utils
 ========
 
-The June 1999 release:
-ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss990630.tar.gz
-ftp://ftp.inr.ac.ru/ip-routing/iputils-ss990610.tar.gz
+The latest releases:
+ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss990824.tar.gz
+ftp://ftp.inr.ac.ru/ip-routing/iputils-ss990915.tar.gz
 
 Patch
 =====
 
 The 2.5 release:
 ftp://ftp.gnu.org/gnu/patch/patch-2.5.tar.gz
+
+ISDN4Linux
+==========
+The v3.1beta7 release:
+ftp://ftp.isdn4linux.de/pub/isdn4linux/utils/testing/isdn4k-utils.v3.1beta7.tar.gz
 
 Other Info
 ==========
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/Configure.help linux.14p16/Documentation/Configure.help
--- linux.vanilla/Documentation/Configure.help	Wed Oct 20 01:12:32 1999
+++ linux.14p16/Documentation/Configure.help	Tue Dec 21 00:31:10 1999
@@ -1199,7 +1199,7 @@
   is no need for the legitimate users to change their TCP/IP software;
   SYN cookies work transparently to them. For technical information
   about SYN cookies, check out
-  ftp://koobera.math.uic.edu/pub/docs/syncookies-archive.
+  ftp://koobera.math.uic.edu/syncookies.html .
 
   If you are SYN flooded, the source address reported by the kernel is
   likely to have been forged by the attacker; it is only reported as
@@ -2532,6 +2532,8 @@
 
   from a boot time script after the /proc filesystem has been mounted.
 
+  Enabling masquerading automagically enables ip_always_defrag too.
+
   Details on how to set things up are contained in the IP Masquerade
   mini-HOWTO, available via FTP (user: anonymous) from
   ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini; there's also some
@@ -2643,25 +2645,6 @@
   The module will be called ip_masq_markfw.o. If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
-IP: always defragment (required for masquerading)
-CONFIG_IP_ALWAYS_DEFRAG
-  If you say Y here, then all incoming fragments (parts of IP packets
-  that arose when some host between origin and destination decided
-  that the packets were too large and cut them into pieces) will be
-  reassembled (defragmented) before being processed, even if they are
-  about to be forwarded.
-
-  You must say Y here if you want to enable "IP: masquerading" or "IP:
-  transparent proxying".
-
-  When using "IP: firewalling" support, you might also want to say Y
-  here, to have a more reliable firewall (otherwise second and further
-  fragments must be dealt with by the firewall, which can be tricky).
-
-  Only say Y here if running either a firewall that is the sole link
-  to your network or a transparent proxy; never ever say Y here for a
-  normal router or host.
-
 IP: aliasing support
 CONFIG_IP_ALIAS
   Sometimes it is useful to give several IP addresses to a single
@@ -3515,8 +3498,9 @@
   to work, choose Y. This driver is also available as a module called
   af_packet.o ( = code which can be inserted in and removed from the
   running kernel whenever you want). If you want to compile it as a
-  module, say M here and read Documentation/modules.txt. If unsure,
-  say Y.
+  module, say M here and read Documentation/modules.txt.  You will
+  need to add 'alias net-pf-17 af_packet' to your /etc/conf.modules
+  file for the module version to function automatically.  If unsure, say Y.
 
 Kernel/User network link driver
 CONFIG_NETLINK
@@ -5266,7 +5250,7 @@
   ftp://ftp.sangoma.com. Read Documentation/networking/wan-router.txt
   for more information.
 
-  The WAN routing support is also available as a module called
+  The WAN routing support is only available as a module called
   wanrouter.o ( = code which can be inserted in and removed from the
   running kernel whenever you want). If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
@@ -5290,6 +5274,7 @@
 
   If unsure, say N.
 
+
 Forwarding between high speed interfaces
 CONFIG_NET_HW_FLOWCONTROL
   This option enables NIC (Network Interface Card) hardware throttling
@@ -5548,9 +5533,12 @@
   that has a program like lynx or netscape) is a family of intelligent
   multiprotocol WAN adapters 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. These cards support the X.25,
-  Frame Relay, and PPP protocols. If you have one or more of these
-  cards, say Y to this option; you may then also want to read the file
+  and designated S503 or S508. These cards support the X.25, Frame
+  Relay, PPP, Cisco HDLC protocols. The driver also offers API support
+  for protocols like HDLC (LAPB), HDLC Streaming and BiSync. 
+
+  If you have one or more of these cards, say M to this option; you
+  may then also want to read the file
   Documentation/networking/wanpipe.txt. The next questions will ask
   you about the protocols you want the driver to support.
 
@@ -5570,26 +5558,103 @@
 WANPIPE X.25 support
 CONFIG_WANPIPE_X25
   Say Y to this option if you are planning to connect a WANPIPE card
-  to an X.25 network. You should then also have said Y to "CCITT X.25
-  Packet Layer" and "LAPB Data Link Driver", above. If you say N, the
-  X.25 support will not be included in the driver (saves about 16 KB
-  of kernel memory).
+  to an X.25 network. If you say N, the X.25 support will not be
+  included in the driver. The X.25 option is ONLY supported on S508
+  cards.
 
 WANPIPE Frame Relay support
 CONFIG_WANPIPE_FR
   Say Y to this option if you are planning to connect a WANPIPE card
-  to a frame relay network. You should then also have said Y to "Frame
-  Relay (DLCI) support", above. If you say N, the frame relay
-  support will not be included in the driver (saves about 16 KB of
-  kernel memory).
+  to a frame relay network. If you say N, the frame relay support will
+  not be included in the driver. The Frame Relay option is ONLY
+  supported on S508 cards.
 
 WANPIPE PPP support
 CONFIG_WANPIPE_PPP
   Say Y to this option if you are planning to connect a WANPIPE card
-  to a leased line using Point-to-Point protocol (PPP). You should
-  then also have said Y to "PPP (point-to-point) support", above. If
-  you say N, the PPP support will not be included in the driver (saves
-  about 16 KB of kernel memory).
+  to a leased line using Point-to-Point protocol (PPP). If you say N,
+  the PPP support will not be included in the driver. The PPP option
+  is ONLY supported on S508 cards.
+
+WANPIPE Cisco HDLC support
+CONFIG_WANPIPE_CHDLC
+  Say Y to this option if you are planning to connect a WANPIPE card
+  to a leased line using the Cisco HDLC protocol. This now supports
+  Dual Port Cisco HDLC on the S508 card ONLY. This support also allows
+  user to build applications using the HDLC streaming API. If you say
+  N, the Cisco HDLC support and HDLC streaming API will not be
+  included in the driver.
+
+MultiGate/COMX support
+CONFIG_COMX
+  Say Y if you want to use any board from the MultiGate (COMX) family. 
+  These boards are synchronous serial adapters for the PC, manufactured 
+  by ITConsult-Pro Co, Hungary. 
+
+  Read linux/Documentation/networking/comx.txt  for help on configuring 
+  and using COMX interfaces. Further info on these cards can be found at 
+  http://www.itc.hu or <info@itc.hu>.
+
+  If you want to compile this as a module, say M and read
+  Documentation/modules.txt. The module will be called comx.o.
+
+COMX/CMX/HiCOMX board support
+CONFIG_COMX_HW_COMX
+  Hardware driver for the 'CMX', 'COMX' and 'HiCOMX' boards from the
+  MultiGate family. Say Y if you have one of these. 
+
+  You will need additional firmware to use these cards, which are
+  downloadable from ftp://ftp.itc.hu/.
+
+  If you want to compile this as a module, say M and read
+  Documentation/modules.txt. The module will be called comx-hw-comx.o.
+
+LoCOMX board support
+CONFIG_COMX_HW_LOCOMX
+  Hardware driver for the 'LoCOMX' board from the MultiGate family. Say Y
+  if you have a board like this. 
+
+  If you want to compile this as a module, say M and read
+  Documentation/modules.txt. The module will be called comx-hw-locomx.o.
+
+MixCOM board support
+CONFIG_COMX_HW_MIXCOM
+  Hardware driver for the 'MixCOM' board from the MultiGate family. Say Y
+  if you have a board like this.
+
+  If you want to use the watchdog device on this card, you should
+  select it in the Watchdog Cards section of the Character Devices
+  configuration. The ISDN interface of this card is Teles 16.3 compatible,
+  you should enable it in the ISDN configuration menu. The driver for the 
+  flash ROM of this card is available separately on ftp://ftp.itc.hu/.
+
+  If you want to compile this as a module, say M and read
+  Documentation/modules.txt. The module will be called comx-hw-mixcom.o.
+
+MultiGate Cisco-HDLC and synchronous PPP protocol support
+CONFIG_COMX_PROTO_PPP
+  Cisco-HDLC and synchronous PPP protocol driver for all MultiGate boards. 
+  Say Y if you want to use either protocol on your MultiGate boards.
+
+  If you want to compile this as a module, say M and read
+  Documentation/modules.txt. The module will be called 
+  comx-proto-ppp.o.
+
+MultiGate LAPB protocol support
+CONFIG_COMX_PROTO_LAPB
+  LAPB protocol driver for all MultiGate boards. Say Y if you 
+  want to use this protocol on your MultiGate boards.
+
+  If you want to compile this as a module, say M and read
+  Documentation/modules.txt. The module will be called comx-proto-lapb.o.
+
+MultiGate Frame Relay protocol support
+CONFIG_COMX_PROTO_FR
+  Frame Relay protocol driver for all MultiGate boards. Say Y if you 
+  want to use this protocol on your MultiGate boards.
+
+  If you want to compile this as a module, say M and read
+  Documentation/modules.txt. The module will be called comx-proto-fr.o.
 
 Ethernet (10 or 100Mbit)
 CONFIG_NET_ETHERNET
@@ -5802,6 +5867,24 @@
   say M here and read Documentation/modules.txt. This is recommended.
   The module will be called rtl8139.o.
 
+SiS 900/7016 support
+CONFIG_SIS900
+  This is a driver for the Fast Ethernet PCI network cards based on
+  the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in
+  SiS 630 and SiS 540 chipsets. If you have one of those, say Y and
+  read the Ethernet-HOWTO, available via FTP (user: anonymous) in   
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Please read 
+  Documentation/networking/sis900.txt and comments at the beginning
+  of drivers/net/sis900.c for more information.
+
+  This driver also supports AMD 79C901 HomePNA such that you can use
+  your phone line as network cable.
+
+  If you want to compile this driver 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. This is recommended. 
+  The module will be called sis900.o.
+
 Packet Engines Yellowfin Gigabit-NIC support
 CONFIG_YELLOWFIN
   Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet
@@ -5848,6 +5931,27 @@
   say M here and read Documentation/modules.txt. This is recommended.
   The module will be called acenic.o.
 
+SysKonnect SK-98xx support
+CONFIG_SK98LIN
+  Say Y here if you have a SysKonnect SK-98xx Gigabit Ethernet Server
+  Adapter. The following adapters are supported by this driver:
+  - SK-9841 (single link 1000Base-LX)
+  - SK-9842 (dual link   1000Base-LX)
+  - SK-9843 (single link 1000Base-SX)
+  - SK-9844 (dual link   1000Base-SX)
+  - SK-9821 (single link 1000Base-T)
+  - SK-9822 (dual link   1000Base-T)
+  The dual link adapters support a link-failover feature.
+  Read Documentation/networking/sk98lin.txt for information about
+  optional driver parameters.
+  Questions concerning this driver may be addresse to:
+    linux@syskonnect.de
+
+  If you want to compile this driver 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. This is recommended.
+  The module will be called sk98lin.o.
+
 AMD LANCE and PCnet (AT1500 and NE2100) support
 CONFIG_LANCE
   If you have a network (Ethernet) card of this type, say Y and read
@@ -6392,6 +6496,32 @@
   More specific information is contained in
   Documentation/networking/tulip.txt.
 
+  This is the new version of this driver. If it does not work for
+  you please try older version which is also available.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called tulip.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt.
+
+Old DECchip Tulip (dc21x4x) PCI support
+CONFIG_DEC_ELCP_OLD
+  This driver is developed for the SMC EtherPower series Ethernet
+  cards and also works with cards based on the DECchip
+  21040/21041/21140 (Tulip series) chips. Some LinkSys PCI cards are
+  of this type. (If your card is NOT SMC EtherPower 10/100 PCI
+  (smc9332dst), you can also try the driver for "Generic DECchip"
+  cards, above. However, most people with a network card of this type
+  will say Y here.) Do read the Ethernet-HOWTO, available via FTP
+  (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  More specific information is contained in
+  Documentation/networking/tulip.txt.
+
+  This an older version of the driver which supports some cards the
+  new version does not (yet) support. Use it if the new driver does
+  not work for you.
+
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called tulip.o. If you want to compile it as a
@@ -8884,9 +9014,15 @@
   APM is a BIOS specification for saving power using several different
   techniques. This is mostly useful for battery powered laptops with
   APM compliant BIOSes. If you say Y here, the system time will be
-  reset after a USER RESUME operation, the /proc/apm device will
-  provide battery status information, and user-space programs will
-  receive notification of APM "events" (e.g., battery status change).
+  reset after a RESUME operation, the /proc/apm device will provide
+  battery status information, and user-space programs will receive
+  notification of APM "events" (e.g. battery status change).
+
+  If you select "Y" here, you can disable actual use of the APM
+  BIOS by passing the "apm=off" option to the kernel at boot time.
+
+  Note that the APM support is almost completely disabled for
+  machines with more than one CPU.
 
   Supporting software is available; for more information, read the
   Battery Powered Linux mini-HOWTO, available via FTP (user:
@@ -8899,9 +9035,7 @@
   This driver does not support the TI 4000M TravelMate and the ACER
   486/DX4/75 because they don't have compliant BIOSes. Many "green"
   desktop machines also don't have compliant BIOSes, and this driver
-  will cause those machines to panic during the boot phase (typically,
-  these machines are using a data segment of 0040, which is reserved
-  for the Linux kernel). 
+  may cause those machines to panic during the boot phase.
 
   If you are running Linux on a laptop, you may also want to read the
   Linux Laptop home page on the WWW at
@@ -9191,83 +9325,117 @@
 
 Joystick support
 CONFIG_JOYSTICK
-  If you have a joystick, you can say Y here to enable generic
-  joystick support. You will also need to say Y or M to at least one
-  of the hardware specific joystick drivers. This will make the
-  joysticks available as /dev/jsX devices. Please read the file
-  Documentation/joystick.txt which contains more information and the
-  location of the joystick package that you'll need.
+  If you have a joystick, 6dof controller, gamepad, steering wheel,
+  weapon control system or something like that you can say Y here to
+  enable generic support for these controllers. You will also need to
+  say Y or M to at least one of the hardware specific drivers. This
+  will make the controllers available as /dev/jsX devices. Please read
+  the file Documentation/joystick.txt which contains more information
+  and the location of the joystick package that you'll need.
 
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called joystick.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
-
-Classic PC analog joysticks and gamepads
+Classic PC analog
 CONFIG_JOY_ANALOG
-  Say Y here if you have an analog joystick or gamepad that connects
-  to the PC gameport. This supports many different types, including
-  joysticks with throttle control, with rudders, or with extensions
-  like additional hats and buttons compatible with CH Flightstick Pro,
+  Say Y here if you have a controller that connects to the PC
+  gameport. This supports many different types, including joysticks
+  with throttle control, with rudders, or with extensions like
+  additional hats and buttons compatible with CH Flightstick Pro,
   ThrustMaster FCS or 6 and 8 button gamepads. For more information on
   how to use the driver please read Documentation/joystick.txt
 
-FPGaming and MadCatz A3D controllers
-CONFIG_JOY_ASSASIN
-  Say Y here if you have an FPGaming Assasin 3D, MadCatz Panther or
-  MadCatz Panther XL. For more information on how to use the driver
-  please read Documentation/joystick.txt
+FPGaming and MadCatz A3D
+CONFIG_JOY_ASSASSIN
+  Say Y here if you have an FPGaming or MadCatz controller using the
+  A3D protocol over the PC gameport. For more information on how to
+  use the driver please read Documentation/joystick.txt
 
-Gravis GrIP joysticks and gamepads
+Gravis GrIP
 CONFIG_JOY_GRAVIS
-  Say Y here if you have a Gravis GamePad Pro, Gravis Xterminator or
-  Gravis Blackhawk Digital. For more information on how to use the
-  driver please read Documentation/joystick.txt
+  Say Y here if you have a Gravis controller using the GrIP protocol
+  over the PC gameport. For more information on how to use the driver
+  please read Documentation/joystick.txt
+
+Logitech ADI
+CONFIG_JOY_LOGITECH
+  Say Y here if you have a Logitech controller using the ADI
+  protocol over the PC gameport. For more information on how to use
+  the driver please read Documentation/joystick.txt
+
+Microsoft SideWinder
+CONFIG_JOY_SIDEWINDER
+  Say Y here if you have a Microsoft controller using the Digital
+  Overdrive protocol over PC gameport. For more information on how to
+  use the driver please read Documentation/joystick.txt
+
+ThrustMaster DirectConnect
+CONFIG_JOY_THRUSTMASTER
+  Say Y here if you have a ThrustMaster controller using the
+  DirectConnect (BSP) protocol over the PC gameport. For more
+  information on how to use the driver please read
+  Documentation/joystick.txt
 
-PDPI Lightning 4 gamecards
+Creative Labs Blaster
+CONFIG_JOY_CREATIVE
+  Say Y here if you have a Creative Labs controller using the
+  Blaster protocol over the PC gameport. For more information on how
+  to use the driver please read Documentation/joystick.txt
+
+PDPI Lightning 4 card
 CONFIG_JOY_LIGHTNING
   Say Y here if you have a PDPI Lightning 4 gamecard and an analog
   joystick or gamepad connected to it. For more information on how to
   use the driver please read Documentation/joystick.txt
 
-Logitech Digital joysticks and gamepads
-CONFIG_JOY_LOGITECH
-  Say Y here if you have a Logitech WingMan Extreme Digital,
-  Logitech ThunderPad Digital or Logitech CyberMan 2. For more
+Trident 4DWave and Aureal Vortex gameport
+CONFIG_JOY_PCI
+  Say Y here if you have a Trident 4DWave DX/NX or Aureal Vortex 1/2
+  card and want to use its gameport in its enhanced digital mode
+  with and ordinary analog joystick. For more information on how to
+  use the driver please read Documentation/joystick.txt
+
+Magellan and Space Mouse
+CONFIG_JOY_MAGELLAN
+  Say Y here if you have a Magellan or Space Mouse 6DOF controller
+  connected to your computer's serial port.  For more information on
+  how to use the driver please read Documentation/joystick.txt
+
+SpaceTec SpaceOrb 360 and SpaceBall Avenger
+CONFIG_JOY_SPACEORB
+  Say Y here if you have a SpaceOrb 360 or SpaceBall Avenger 6DOF
+  controller connected to your computer's serial port.  For more
   information on how to use the driver please read
   Documentation/joystick.txt
 
-Microsoft SideWinder, Genius Digital joysticks and gamepads
-CONFIG_JOY_SIDEWINDER
-  Say Y here if you have a Microsoft SideWinder 3d Pro, Microsoft
-  SideWinder Precision Pro, Microsoft SideWinder Force Feedback Pro,
-  Microsoft Sidewinder GamePad or Genius Flight2000 F-23 Digital. For
-  more information on how to use the driver please read
+SpaceTec SpaceBall 4000 FLX
+CONFIG_JOY_SPACEBALL
+  Say Y here if you have a SpaceTec SpaceBall 4000 FLX
+  controller connected to your computer's serial port.  For more
+  information on how to use the driver please read
   Documentation/joystick.txt
 
-ThrustMaster DirectConnect joysticks and gamepads
-CONFIG_JOY_THRUSTMASTER
-  Say Y here if you have a ThrustMaster Millenium 3D Inceptor or a
-  ThrustMaster 3D Rage Pad. For more information on how to use the
-  driver please read Documentation/joystick.txt
+Logitech WingMan Warrior
+CONFIG_JOY_WARRIOR
+  Say Y here if you have a Logitech WingMan Warrior controller
+  connected to your computer's serial port.  For more information on
+  how to use the driver please read Documentation/joystick.txt
 
-NES, SNES, PSX, Multisystem joysticks and gamepads
+NES, SNES, N64, PSX, Multi
 CONFIG_JOY_CONSOLE
   Say Y here if you have a Nintendo Entertainment System gamepad,
-  Super Nintendo Entertainment System gamepad, Sony PlayStation
-  gamepad or a Multisystem -- Atari, Amiga, Commodore, Amstrad CPC
-  joystick. For more information on how to use the driver please read
+  Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
+  Sony PlayStation gamepad or a Multisystem -- Atari, Amiga,
+  Commodore, Amstrad CPC joystick connected to your parallel port.
+  For more information on how to use the driver please read
   Documentation/joystick.txt and Documentation/joystick-parport.txt
 
-Sega, Multisystem joysticks and gamepads
+Sega, Multi
 CONFIG_JOY_DB9
   Say Y here if you have a Sega Master System gamepad, Sega Genesis
   gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
-  Commodore, Amstrad CPC joystick. For more information on how to use
-  the driver please read Documentation/joystick.txt and
-  Documentation/joystick-parport.txt
+  Commodore, Amstrad CPC joystick connected to your parallel port. For
+  more information on how to use the driver please read
+  Documentation/joystick.txt and Documentation/joystick-parport.txt
 
-TurboGraFX Multisystem joystick interface
+TurboGraFX interface
 CONFIG_JOY_TURBOGRAFX
   Say Y here if you have the TurboGraFX interface by Steffen Schwenke,
   and want to use it with Multiststem -- Atari, Amiga, Commodore,
@@ -9422,20 +9590,6 @@
   You can say M here to compile this driver as a module; the module is
   called sb.o.
 
-Generic OPL2/OPL3 FM synthesizer support
-CONFIG_SOUND_ADLIB
-  Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
-  Answering Y is usually a safe and recommended choice, however some
-  cards may have software (TSR) FM emulation. Enabling FM support with
-  these cards may cause trouble (I don't currently know of any such
-  cards, however). 
-
-  Please read the file Documentation/sound/OPL3 if your card has an
-  OPL3 chip.
-
-  If unsure, say Y.
-  
-
 #Loopback MIDI device support
 #CONFIG_SOUND_VMIDI
 ###
@@ -9715,7 +9869,15 @@
 
 FM synthesizer (YM3812/OPL-3) support
 CONFIG_SOUND_YM3812
-  Answer Y here, unless you know you will not need the option.
+  Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
+  Answering Y is usually a safe and recommended choice, however some
+  cards may have software (TSR) FM emulation. Enabling FM support with
+  these cards may cause trouble (I don't currently know of any such
+  cards, however).
+  Please read the file Documentation/sound/OPL3 if your card has an
+  OPL3 chip.
+
+  If unsure, say Y.
 
 Sun Audio support
 CONFIG_SUN_AUDIO
@@ -9953,11 +10115,6 @@
 
 ISDN subsystem
 CONFIG_ISDN
-  CAUTION: the ISDN driver shipped with this kernel distribution
-  is outdated and might not work without problems. An updated driver
-  is available for download. Please read http://www.isdn4linux.de
-  on the WWW for a list of servers.
-
   ISDN ("Integrated Services Digital Networks", called RNIS in France)
   is a special type of fully digital telephone service; it's mostly
   used to connect to your Internet service provider (with SLIP or
@@ -9966,9 +10123,7 @@
   conversations while downloading stuff. It only works if your
   computer is equipped with an ISDN card and both you and your service
   provider purchased an ISDN line from the phone company. For details,
-  read http://alumni.caltech.edu/~dank/isdn/ on the WWW. (To browse
-  the WWW, you need to have access to a machine on the Internet that
-  has a program like lynx or netscape.)
+  read http://alumni.caltech.edu/~dank/isdn/ on the WWW.
 
   This driver allows you to use an ISDN-card for networking
   connections and as dialin/out device. The isdn-tty's have a built in
@@ -10018,25 +10173,28 @@
   is the only voice-supporting driver. See
   Documentation/isdn/README.audio for more information.
 
-X.25 PLP on top of ISDN (EXPERIMENTAL)
+X.25 PLP on top of ISDN
 CONFIG_ISDN_X25
-  This experimental feature provides the X.25 protocol over ISDN
-  connections. See Documentation/isdn/README.x25 for more information
+  This feature provides the X.25 protocol over ISDN connections.
+  See Documentation/isdn/README.x25 for more information
   if you are thinking about using this.
 
 ISDN diversion services support
 CONFIG_ISDN_DIVERSION
   This option allows you to use some supplementary diversion
   services in conjunction with the HiSax driver on an EURO/DSS1
-  line. Supported options are CD (call deflection), CFU (Call 
-  forward unconditional), CFB (Call forward when busy) and CFNR 
-  (call forward not reachable).
-  Additionally the actual CFU, CFB and CFNR state may be 
-  interrogated. The use of CFU, CFB, CFNR and interrogation may
-  be limited to some countries. The keypad protocol is still not
-  implemented.
-  CD should work in all countries if this service has been sub-
-  scribed.
+  line. 
+
+  Supported options are CD (call deflection), CFU (Call forward
+  unconditional), CFB (Call forward when busy) and CFNR (call forward
+  not reachable). Additionally the actual CFU, CFB and CFNR state may
+  be interrogated.
+
+  The use of CFU, CFB, CFNR and interrogation may be limited to some
+  countries. The keypad protocol is still not implemented. CD should
+  work in all countries if the service has been subscribed to.
+
+  Please read the file Documentation/isdn/README.diversion.
 
 ICN 2B and 4B support
 CONFIG_ISDN_DRV_ICN
@@ -10278,7 +10436,7 @@
   
   For more informations see under Documentation/isdn/README.hfc-pci.
 
-HiSax Support for Winbond W6692 based cards (EXPERIMENTAL)
+HiSax Support for Winbond W6692 based cards
 CONFIG_HISAX_W6692
   This enables HiSax support for Winbond W6692 based PCI ISDN cards.
   
@@ -10311,35 +10469,33 @@
   can be inserted in and removed from the running kernel whenever you
   want, details in Documentation/modules.txt); the module will be
   called sc.o. See Documentation/isdn/README.sc and
-  http://www.spellcast.com for more information (to browse the WWW,
-  you need to have access to a machine on the Internet that has a
-  program like lynx or netscape).
+  http://www.spellcast.com for more information.
 
 Eicon.Diehl active card support
 CONFIG_ISDN_DRV_EICON
   Say Y here if you have an Eicon active ISDN card. In order to use
   this card, additional firmware is necessary, which has to be loaded
-  into the card using the eiconctrl utility which is part of the latest
-  isdn4k-utils package. Please read the file
+  into the card using the eiconctrl utility which is part of the
+  latest isdn4k-utils package. Please read the file
   Documentation/isdn/README.eicon for more information.
   
 Eicon old-type card support
 CONFIG_ISDN_DRV_EICON_ISA
-  Say Y here if you have an old-type Eicon active ISDN card. In order to
-  use this card, additional firmware is necessary, which has to be loaded
-  into the card using the eiconctrl utility which is part of the latest
-  isdn4k-utils package. Please read the file
+  Say Y here if you have an old-type Eicon active ISDN card. In order
+  to use this card, additional firmware is necessary, which has to be
+  loaded into the card using the eiconctrl utility which is part of
+  the latest isdn4k-utils package. Please read the file
   Documentation/isdn/README.eicon for more information.
 
 Support AT-Fax Class 2 commands
 CONFIG_ISDN_TTY_FAX
   If you say Y here, the modem-emulator will support a subset of the
   Fax Class 2 commands. Using a getty with fax-support
-  (mgetty+sendfax, hylafax), you will be able to use your Linux box 
-  as an ISDN-fax-machine. This must be supported by the lowlevel driver
+  (mgetty+sendfax, hylafax), you will be able to use your Linux box as
+  an ISDN-fax-machine. This must be supported by the lowlevel driver
   also. See Documentation/isdn/README.fax for more information.
 
-AVM-B1 with CAPI2.0 support
+AVM CAPI2.0 support
 CONFIG_ISDN_DRV_AVMB1
   This enables support for the AVM B1/T1 ISDN networking cards.In
   addition, a CAPI (Common ISDN Application Programming Interface, a
@@ -10350,7 +10506,7 @@
   additional firmware is necessary, which has to be downloaded into
   the card using a utility which is distributed separately. Please
   read the file Documentation/isdn/README.avmb1. 
-
+  
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called avmb1.o. If you want to compile it as a
@@ -10364,7 +10520,7 @@
 CONFIG_ISDN_DRV_AVMB1_B1PCI
   Enable support for the PCI version of the AVM B1 card.
 
-AVM T1/T1B ISA support
+AVM T1/T1-B ISA support
 CONFIG_ISDN_DRV_AVMB1_T1ISA
   Enable support for the AVM T1 T1B card.
   Note: This is a PRI card and handle 30 B-channels.
@@ -10373,12 +10529,18 @@
 CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
   Enable support for the PCMCIA version of the AVM B1 card.
 
+AVM T1/T1-B PCI support
+CONFIG_ISDN_DRV_AVMB1_T1PCI
+  Enable support for the AVM T1 T1B card.
+  Note: This is a PRI card and handle 30 B-channels.
+
 Verbose reason code reporting (kernel size +=7K)
 CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
   If you say Y here, the AVM B1 driver will give verbose reasons for
   disconnecting. This will increase the size of the kernel by 7 KB. If
   unsure, say Y.
 
+
 IBM Active 2000 support (EXPERIMENTAL)
 CONFIG_ISDN_DRV_ACT2000
   Say Y here if you have an IBM Active 2000 ISDN card. In order to use
@@ -10519,6 +10681,7 @@
   Note that even if you say N here, you can still use your expansion
   cards. If in doubt, say Y.
 
+Amiga 1200/600 PCMCIA support
 CONFIG_AMIGA_PCMCIA
   Include support in the kernel for pcmcia on Amiga 1200 and Amiga 600.
   If you intend to use pcmcia cards say Y; otherwise say N.
@@ -11783,6 +11946,68 @@
   boards from BVM Ltd.  Everyone using one of these boards should say
   Y here.
 
+IBM's S/390 architecture
+CONFIG_ARCH_S390
+  Select this option, if you want to run the Kernel on one of IBM's
+  mainframes of the S/390 generation. You should have installed the
+  s390-compiler released by IBM (based on gcc-2.95.1) before.
+
+Merge some code into the kernel to make the image IPLable
+CONFIG_IPLABLE
+  If you want to use the produced kernel to IPL directly from a
+  device, you have to merge a bootsector specific to the device
+  into the first bytes of the kernel. You will have to select the
+  IPL device on another question, that pops up, when you select
+  CONFIG_IPLABE.
+
+IPL from a S/390 tape unit
+CONFIG_IPL_TAPE
+  Select this option if you want to IPL the image from a tape.
+
+IPL from a virtual card reader emulated by VM/ESA
+CONFIG_IPL_RDR_VM
+  Select this option if you are running under VM/ESA and want 
+  to IPL the image from the emulated card reader.
+
+IPL from a real card reader
+CONFIG_IPL_RDR
+  Select this option if you want to IPL the image from a real
+  card reader. Maybe you still got one and want to try. We didn't
+  test.
+
+IBMs S/390 Harddisks (DASDs)
+CONFIG_DASD
+  Enable this option if you want to access DASDs directly utilizing
+  S/390s channel subsystem commands. This is necessary for running
+  natively on a single image or an LPAR.
+
+Enable DASD fast write
+CONFIG_DASD_FAST_IO
+  Enable fast I/O for DASDs. That means that the next I/O command
+  is already issued at interrupt time, if an I/O request is pending.
+  This option gives significant speedup of I/O, because we don't
+  schedule the bottom-halves as often as Intel.
+
+Support for IBM-style disk-labels (S/390)
+CONFIG_S390_PARTITION
+  Enable this option to assure standard IBM labels on the DASDs.
+  You must enable it, if you are planning to access DASDs also
+  attached to another IBM mainframe operation system (OS/390, 
+  VM/ESA, VSE/ESA).
+
+ECKD devices
+CONFIG_DASD_ECKD
+  ECKD devices are the most commonly used devices. you should enable
+  this option unless you are very sure to have no ECKD device.
+
+CKD devices
+CONFIG_DASD_CKD
+  CKD devices are currently unsupported.
+
+FBA devices
+CONFIG_DASD_FBA
+  FBA devices are currently unsupported.
+
 Compaq SMART2 support
 CONFIG_BLK_CPQ_DA
    This is the driver for Compaq Smart Array controllers.  
@@ -11790,6 +12015,24 @@
    See "linux/Documentation/cpqarray.txt" for the current list of 
    boards supported by this driver, and for further information 
    on the use of this driver. 
+
+QuickNet Internet LineJack/PhoneJack support
+CONFIG_PHONE_IXJ
+  Say M if you have a telephony card manufactured by Quicknet
+  Technologies, Inc.  These include the Internet PhoneJACK and
+  Internet LineJACK Telephony Cards.
+
+  For the ISA versions of these products, you can configure the
+  cards using the isapnp tools (pnpdump/isapnp) or you can use the
+  backported isapnp module.  Please read:
+
+  /usr/src/linux/Documentation/telephony/ixj.txt.
+
+  For more information on these cards, see Quicknet's website at:
+  http://www.quicknet.net/
+
+  If you do not have any Quicknet telephony cards, you can safely
+  ignore this option.
  
 #
 # A couple of things I keep forgetting:
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/devices.tex linux.14p16/Documentation/devices.tex
--- linux.vanilla/Documentation/devices.tex	Sun Aug 16 19:35:51 1998
+++ linux.14p16/Documentation/devices.tex	Thu Jan  1 01:00:00 1970
@@ -1,2165 +0,0 @@
-\documentstyle{article}
-% $Id: devices.tex,v 1.14 1998/08/10 22:39:24 hpa Exp $
-% ---------------------------------------------------------------------------
-% Adopt somewhat reasonable margins, so it doesn't take a million
-% pages to print... :-)  If you're actually putting this in print, you
-% may wish to change these.
-\oddsidemargin=0in
-\textwidth=6.5in
-\topmargin=0in
-\headheight=0.5in
-\headsep=0.25in
-\textheight=7.5in
-\footskip=0.75in
-\footheight=0.5in
-%
-\begin{document}
-\newcommand{\file}{\tt}			% Style to use for a filename
-\newcommand{\url}{\it}		        % Style to use for an URL
-\newcommand{\hex}{\tt}			% Style to use for a hex number
-\newcommand{\ud}{(Under development)}	% Abbreviation
-\newcommand{\1}{\({}^1\)}
-\newcommand{\2}{\({}^2\)}
-\newcommand{\3}{\({}^3\)}
-\newcommand{\4}{\({}^4\)}
-\newlength{\dig}
-\settowidth{\dig}{0}			% Get width of digits
-\newcommand{\num}[2]{\makebox[#1\dig][r]{#2}}
-\newcommand{\major}[4]{\num{3}{#1}#2 \> #3 \> #4 \\}
-\newcommand{\minor}[3]{\> \> \num{3}{#1} \> {\file #2} \> #3 \\}
-\newcommand{\minordots}{\> \> \> \dots \\}
-\newenvironment{devicelist}%
- {\begin{tabbing}%
-000--000 \= blockxxx \= 000 \= {\file /dev/input/keyboardxxx} \= foo \kill}%
- {\end{tabbing}}
-\newcommand{\link}[4]{{\file #1} \> {\file #2} \> #3 \> #4 \\}
-\newcommand{\vlink}[4]{{\file #1} \> {\em #2 \/} \> #3 \> #4 \\}
-\newcommand{\node}[3]{{\file #1} \> #2 \> #3 \\}
-\newcommand{\tum}{$''$}
-\newenvironment{nodelist}%
- {\begin{tabbing}%
-{\file /dev/crambamboli} \= {\file /proc/self/fd/99} \= symbolicxxx \=
-foo \kill}%
- {\end{tabbing}}
-%
-% If you reformat this document, *please* make sure this information
-% gets included!  This list changes frequently, so it is crucial to
-% know the date of the revision.
-%
-\title{{\bf Linux Allocated Devices}}
-\author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: August 10, 1998}
-\maketitle
-%
-\noindent
-This list is the Linux Device List, the official registry of allocated
-device numbers and {\file /dev} directory nodes for the Linux
-operating system.
-
-The latest version of this list is included with the Linux kernel
-sources in \LaTeX\ and ASCII form.  It is also available separately
-from {\url ftp://ftp.kernel.org/pub/linux/docs/device-list/}.  In case
-of discrepancy between the text and \LaTeX\ versions, the \LaTeX\
-version is authoritative.
-
-This document is included by reference into the Linux Filesystem
-Standard (FSSTND).  The FSSTND is available from
-{\url ftp://tsx-11.mit.edu/pub/linux/docs/linux-standards/fsstnd/}.
-
-Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga
-platform only.  Allocations marked (68k/Atari) apply to Linux/68k on
-the Atari platform only.
-
-This document is in the public domain.  The author requests, however,
-that semantically altered versions are not distributed without
-permission of the author, assuming the author can be contacted without
-an unreasonable effort.
-
-In particular, please don't sent patches for this list to Linus, at
-least not without contacting me first.
-
-I do not have any information about these devices beyond what appears
-on this list.  Any such information requests will be deleted without
-reply.
-
-\section{How to submit a device entry}
-
-To have a major number allocated, or a minor number in situations
-where that applies (e.g. busmice), please contact me with the
-appropriate device information.  Also, if you have additional
-information regarding any of the devices listed below, or if I have
-made a mistake, I would greatly appreciate a note.
-
-I do, however, make two requests about the nature of your report.
-This is necessary for me to be able to keep this list up to date and
-correct in a timely manner.  First of all, {\em please\/} include the
-word ``device'' in the subject so your mail won't accidentally get
-buried!  I receive hundreds of email messages a day, so mail sent with
-other subjects may very well get lost in the avalanche.
-
-Second, please include a description of the device {\em in the same
-format as this list\/}.  The reason for this is that it is the only
-way I have found to ensure I have all the requisite information to
-publish your device and avoid conflicts.
-
-Your cooperation is appreciated.
-
-\section{Major numbers}
-
-\begin{devicelist}
-\major{ 0}{}{     }{Unnamed devices (e.g. non-device mounts)}
-\major{ 1}{}{char }{Memory devices}
-\major{  }{}{block}{RAM disk}
-\major{ 2}{}{char }{Pseudo-TTY masters}
-\major{  }{}{block}{Floppy disks}
-\major{ 3}{}{char }{Pseudo-TTY slaves}
-\major{  }{}{block}{First MFM, RLL or IDE hard disk/CD-ROM interface}
-\major{ 4}{}{char }{TTY devices}
-\major{ 5}{}{char }{Alternate TTY devices}
-\major{ 6}{}{char }{Parallel printer devices}
-\major{ 7}{}{char }{Virtual console access devices}
-\major{  }{}{block}{Loopback devices}
-\major{ 8}{}{block}{SCSI disk devices (0-15)}
-\major{ 9}{}{char }{SCSI tape devices}
-\major{  }{}{block}{Metadisk (RAID) devices}
-\major{10}{}{char }{Non-serial mice, misc features}
-\major{11}{}{char }{Raw keyboard device}
-\major{  }{}{block}{SCSI CD-ROM devices}
-\major{12}{}{char }{QIC-02 tape}
-\major{  }{}{block}{MSCDEX CD-ROM callback support}
-\major{13}{}{char }{PC speaker}
-\major{  }{}{block}{8-bit MFM/RLL/IDE controller}
-\major{14}{}{char }{Sound card}
-\major{  }{}{block}{BIOS harddrive callback support}
-\major{15}{}{char }{Joystick}
-\major{  }{}{block}{Sony CDU-31A/CDU-33A CD-ROM}
-\major{16}{}{char }{Non-SCSI scanners}
-\major{  }{}{block}{GoldStar CD-ROM}
-\major{17}{}{char }{Chase serial card}
-\major{  }{}{block}{Optics Storage CD-ROM}
-\major{18}{}{char }{Chase serial card -- alternate devices}
-\major{  }{}{block}{Sanyo CD-ROM}
-\major{19}{}{char }{Cyclades serial card}
-\major{  }{}{block}{``Double'' compressed disk}
-\major{20}{}{char }{Cyclades serial card -- alternate devices}
-\major{  }{}{block}{Hitachi CD-ROM}
-\major{21}{}{char }{Generic SCSI access}
-\major{  }{}{block }{Acorn MFM hard drive interface}
-\major{22}{}{char }{Digiboard serial card}
-\major{  }{}{block}{Second IDE hard disk/CD-ROM interface}
-\major{23}{}{char }{Digiboard serial card -- alternate devices}
-\major{  }{}{block}{Mitsumi proprietary CD-ROM}
-\major{24}{}{char }{Stallion serial card}
-\major{  }{}{block}{Sony CDU-535 CD-ROM}
-\major{25}{}{char }{Stallion serial card -- alternate devices}
-\major{  }{}{block}{First Matsushita (Panasonic/SoundBlaster) CD-ROM}
-\major{26}{}{char }{Quanta WinVision frame grabber}
-\major{  }{}{block}{Second Matsushita (Panasonic/SoundBlaster) CD-ROM}
-\major{27}{}{char }{QIC-117 tape}
-\major{  }{}{block}{Third Matsushita (Panasonic/SoundBlaster) CD-ROM}
-\major{28}{}{char }{Stallion serial card -- card programming}
-\major{  }{}{char }{Atari SLM ACSI laser printer (68k/Atari)}
-\major{  }{}{block}{Fourth Matsushita (Panasonic/SoundBlaster) CD-ROM}
-\major{  }{}{block}{ACSI disk/CD-ROM (68k/Atari)}
-\major{29}{}{char }{Universal frame buffer}
-\major{  }{}{block}{Aztech/Orchid/Okano/Wearnes CD-ROM}
-\major{30}{}{char }{iBCS-2 compatibility devices}
-\major{  }{}{block}{Philips LMS CM-205 CD-ROM}
-\major{31}{}{char }{MPU-401 MIDI}
-\major{  }{}{block}{ROM/flash memory card}
-\major{32}{}{char }{Specialix serial card}
-\major{  }{}{block}{Philips LMS CM-206 CD-ROM}
-\major{33}{}{char }{Specialix serial card -- alternate devices}
-\major{  }{}{block}{Third IDE hard disk/CD-ROM interface}
-\major{34}{}{char }{Z8530 HDLC driver}
-\major{  }{}{block}{Fourth IDE hard disk/CD-ROM interface}
-\major{35}{}{char }{tclmidi MIDI driver}
-\major{  }{}{block}{Slow memory ramdisk}
-\major{36}{}{char }{Netlink support}
-\major{  }{}{block}{MCA ESDI hard disk}
-\major{37}{}{char }{IDE tape}
-\major{  }{}{block}{Zorro II ramdisk}
-\major{38}{}{char }{Myricom PCI Myrinet board}
-\major{  }{}{block}{Reserved for Linux/AP+}
-\major{39}{}{char }{ML-16P experimental I/O board}
-\major{  }{}{block}{Reserved for Linux/AP+}
-\major{40}{}{char }{Matrox Meteor frame grabber}
-\major{  }{}{block}{Syquest EZ135 parallel port removable drive}
-\major{41}{}{char }{Yet Another Micro Monitor}
-\major{  }{}{block}{MicroSolutions BackPack parallel port CD-ROM}
-\major{42}{}{}{Demo/sample use}
-\major{43}{}{char }{isdn4linux virtual modem}
-\major{  }{}{block}{Network block devices}
-\major{44}{}{char }{isdn4linux virtual modem -- alternate devices}
-\major{  }{}{block}{Flash Translation Layer (FTL) filesystems}
-\major{45}{}{char }{isdn4linux ISDN BRI driver}
-\major{  }{}{block}{Parallel port IDE disk devices}
-\major{46}{}{char }{Comtrol Rocketport serial card}
-\major{  }{}{block}{Parallel port ATAPI CD-ROM devices}
-\major{47}{}{char }{Comtrol Rocketport serial card -- alternate devices}
-\major{  }{}{block}{Parallel port ATAPI disk devices}
-\major{48}{}{char }{SDL RISCom serial card}
-\major{  }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\major{49}{}{char }{SDL RISCom serial card -- alternate devices}
-\major{  }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\major{50}{}{char}{Reserved for GLINT}
-\major{  }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\major{51}{}{char }{Baycom radio modem}
-\major{  }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\major{52}{}{char }{Spellcaster DataComm/BRI ISDN card}
-\major{  }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\major{53}{}{char }{BDM interface for remote debugging MC683xx microcontrollers}
-\major{  }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\major{54}{}{char }{Electrocardiognosis Holter serial card}
-\major{  }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\major{55}{}{char }{DSP56001 digital signal processor}
-\major{  }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\major{56}{}{char }{Apple Desktop Bus}
-\major{  }{}{block}{Fifth IDE hard disk/CD-ROM interface}
-\major{57}{}{char }{Hayes ESP serial card}
-\major{  }{}{block}{Sixth IDE hard disk/CD-ROM interface}
-\major{58}{}{char }{Hayes ESP serial card -- alternate devices}
-\major{  }{}{block}{Reserved for logical volume manager}
-\major{59}{}{char }{sf firewall package}
-\major{60}{--63}{}{Local/experimental use}
-\major{64}{}{char }{ENskip kernel encryption package}
-\major{65}{}{char }{Sundance ``plink'' Transputer boards}
-\major{  }{}{block}{SCSI disk devices (16-31)}
-\major{66}{}{char }{YARC PowerPC PCI coprocessor card}
-\major{  }{}{block}{SCSI disk devices (32-47)}
-\major{67}{}{char }{Coda network filesystem}
-\major{  }{}{block}{SCSI disk devices (48-63)}
-\major{68}{}{char }{CAPI 2.0 interface}
-\major{  }{}{block}{SCSI disk devices (64-79)}
-\major{69}{}{char }{MA16 numeric accelerator card}
-\major{  }{}{block}{SCSI disk devices (80-95)}
-\major{70}{}{char }{SpellCaster Protocol Services Interface}
-\major{  }{}{block}{SCSI disk devices (96-111)}
-\major{71}{}{char }{Computone IntelliPort II serial card}
-\major{  }{}{block}{SCSI disk devices (112-127)}
-\major{72}{}{char }{Computone IntelliPort II serial card -- alternate devices}
-\major{73}{}{char }{Computone IntelliPort II serial card -- control devices}
-\major{74}{}{char }{SCI bridge}
-\major{75}{}{char }{Specialix IO8+ serial card}
-\major{76}{}{char }{Specialix IO8+ serial card -- alternate devices}
-\major{77}{}{char }{ComScire Quantum Noise Generator}
-\major{78}{}{char }{PAM Software's multimodem boards}
-\major{79}{}{char }{PAM Software's multimodem boards -- alternate devices}
-\major{80}{}{char }{Photometrics AT200 CCD camera}
-\major{81}{}{char }{video4linux}
-\major{82}{}{char }{WiNRADiO communications receiver card}
-\major{83}{}{char }{Teletext/videotext interfaces}
-\major{84}{}{char }{Ikon 1011[57] Versatec Greensheet Interface}
-\major{85}{}{char }{Linux/SGI shared memory input queue}
-\major{86}{}{char }{SCSI media changer}
-\major{87}{}{char }{Sony Control-A1 stereo control bus}
-\major{88}{}{char }{COMX synchronous serial card}
-\major{89}{}{char }{I$^2$C bus interface}
-\major{90}{}{char }{Memory Technology Device (RAM, ROM, Flash)}
-\major{91}{}{char }{CAN-Bus controller}
-\major{92}{}{char }{Reserved for ith Kommunikationstechnik MIC ISDN card}
-\major{93}{}{char }{IBM Smart Capture Card frame grabber}
-\major{94}{}{char }{miroVIDEO DC10/30 capture/playback device}
-\major{95}{}{char }{IP filter}
-\major{96}{}{char }{Parallel port ATAPI tape devices}
-\major{97}{}{char }{Parallel port generic ATAPI interface}
-\major{98}{}{char }{Control and Mesurement Device (comedi)}
-\major{99}{}{char }{Raw parallel ports}
-\major{100}{}{char }{POTS (analogue telephone) A/B port}
-\major{101}{}{char }{Motorola DSP 56xxx board}
-\major{102}{}{char }{Philips SAA5249 Teletext signal decoder}
-\major{103}{}{char }{Arla network file system}
-\major{104}{}{char }{Flash BIOS support}
-\major{105}{}{char }{Comtrol VS-1000 serial card}
-\major{106}{}{char }{Comtrol VS-1000 serial card -- alternate devices}
-\major{107}{}{char }{3Dfx Voodoo Graphics device}
-\major{108}{}{char }{Device independent PPP interface}
-\major{109}{}{char }{Reserved for logical volume manager}
-\major{110}{}{char }{miroMEDIA Surround board}
-\major{111}{--119}{}{Unallocated}
-\major{120}{--127}{}{Local/experimental use}
-\major{128}{--135}{char }{Unix98 PTY masters}
-\major{136}{--143}{char }{Unix98 PTY slaves}
-\major{144}{--239}{}{Unallocated}
-\major{240}{--254}{}{Local/experimental use}
-\major{255}{}{}{Reserved}
-\end{devicelist}
-
-\section{Minor numbers}
-
-\begin{devicelist}
-\major{ 0}{}{}{Unnamed devices (e.g. non-device mounts)}
-	\minor{0}{}{reserved as null device number}
-\end{devicelist}
-
-\begin{devicelist}
-\major{ 1}{}{char}{Memory devices}
-	\minor{1}{/dev/mem}{Physical memory access}
-	\minor{2}{/dev/kmem}{Kernel virtual memory access}
-	\minor{3}{/dev/null}{Null device}
-	\minor{4}{/dev/port}{I/O port access}
-	\minor{5}{/dev/zero}{Null byte source}
-	\minor{6}{/dev/core}{OBSOLETE -- should be a link to {\file /proc/kcore}}
-	\minor{7}{/dev/full}{Returns ENOSPC on write}
-	\minor{8}{/dev/random}{Nondeterministic random number generator}
-	\minor{9}{/dev/urandom}{Less secure, but faster random number generator}
-\\
-\major{}{}{block}{RAM disk}
-	\minor{0}{/dev/ram0}{First RAM disk}
-	\minordots
-	\minor{7}{/dev/ram7}{Eighth RAM disk}
-	\minor{250}{/dev/initrd}{Initial RAM disk}
-\end{devicelist}
-
-\noindent
-Earlier kernels had {\file /dev/ramdisk} (1, 1) here.  {\file /dev/initrd}
-refers to a RAM disk which was preloaded by the boot loader.
-
-\begin{devicelist}
-\major{ 2}{}{char}{Pseudo-TTY masters}
-	\minor{0}{/dev/ptyp0}{First PTY master}
-	\minor{1}{/dev/ptyp1}{Second PTY master}
-	\minordots
-	\minor{255}{/dev/ptyef}{256th PTY master}
-\end{devicelist}
-
-\noindent
-Pseudo-TTY's are named as follows:
-\begin{itemize}
-\item Masters are {\file pty}, slaves are {\file tty};
-\item the fourth letter is one of {\file pqrstuvwxyzabcde} indicating
-the 1st through 16th series of 16 pseudo-ttys each, and
-\item the fifth letter is one of {\file 0123456789abcdef} indicating
-the position within the series.
-\end{itemize}
-
-\noindent
-These are the old-style (BSD) PTY devices; Unix98 devices are on major
-128 and above and use the PTY master multiplex ({\file /dev/ptmx}) to
-acquire a PTY on demand.
-
-\begin{devicelist}
-\major{}{}{block}{Floppy disks}
-	\minor{0}{/dev/fd0}{Controller 1, drive 1 autodetect}
-	\minor{1}{/dev/fd1}{Controller 1, drive 2 autodetect}
-	\minor{2}{/dev/fd2}{Controller 1, drive 3 autodetect}
-	\minor{3}{/dev/fd3}{Controller 1, drive 4 autodetect}
-	\minor{128}{/dev/fd4}{Controller 2, drive 1 autodetect}
-	\minor{129}{/dev/fd5}{Controller 2, drive 2 autodetect}
-	\minor{130}{/dev/fd6}{Controller 2, drive 3 autodetect}
-	\minor{131}{/dev/fd7}{Controller 2, drive 4 autodetect}
-\\
-\major{}{}{}{To specify format, add to the autodetect device number}
-	\minor{  0}{/dev/fd?}{Autodetect format}
-	\minor{}{}{}
-	\minor{  4}{/dev/fd?d360}{5.25\tum\ \num{4}{360}K in a \num{4}{360}K drive\1}
-	\minor{ 20}{/dev/fd?h360}{5.25\tum\ \num{4}{360}K in a 1200K drive\1}
-	\minor{ 48}{/dev/fd?h410}{5.25\tum\ \num{4}{410}K in a 1200K drive}
-	\minor{ 64}{/dev/fd?h420}{5.25\tum\ \num{4}{420}K in a 1200K drive}
-	\minor{ 24}{/dev/fd?h720}{5.25\tum\ \num{4}{720}K in a 1200K drive}
-	\minor{ 80}{/dev/fd?h880}{5.25\tum\ \num{4}{880}K in a 1200K drive\1}
-	\minor{  8}{/dev/fd?h1200}{5.25\tum\ 1200K in a 1200K drive\1}
-	\minor{ 40}{/dev/fd?h1440}{5.25\tum\ 1440K in a 1200K drive\1}
-	\minor{ 56}{/dev/fd?h1476}{5.25\tum\ 1476K in a 1200K drive}
-	\minor{ 72}{/dev/fd?h1494}{5.25\tum\ 1494K in a 1200K drive}
-	\minor{ 92}{/dev/fd?h1600}{5.25\tum\ 1600K in a 1200K drive\1}
-	\minor{}{}{}
-	\minor{ 12}{/dev/fd?u360}{3.5\tum\ \num{4}{360}K Double Density\2}
-	\minor{ 16}{/dev/fd?u720}{3.5\tum\ \num{4}{720}K Double Density\1}
-	\minor{120}{/dev/fd?u800}{3.5\tum\ \num{4}{800}K Double Density\2}
-	\minor{ 52}{/dev/fd?u820}{3.5\tum\ \num{4}{820}K Double Density}
-	\minor{ 68}{/dev/fd?u830}{3.5\tum\ \num{4}{830}K Double Density}
-	\minor{ 84}{/dev/fd?u1040}{3.5\tum\ 1040K Double Density\1}
-	\minor{ 88}{/dev/fd?u1120}{3.5\tum\ 1120K Double Density\1}
-	\minor{ 28}{/dev/fd?u1440}{3.5\tum\ 1440K High Density\1}
-	\minor{124}{/dev/fd?u1600}{3.5\tum\ 1600K High Density\1}
-	\minor{ 44}{/dev/fd?u1680}{3.5\tum\ 1680K High Density\3}
-	\minor{ 60}{/dev/fd?u1722}{3.5\tum\ 1722K High Density}
-	\minor{ 76}{/dev/fd?u1743}{3.5\tum\ 1743K High Density}
-	\minor{ 96}{/dev/fd?u1760}{3.5\tum\ 1760K High Density}
-	\minor{116}{/dev/fd?u1840}{3.5\tum\ 1840K High Density\3}
-	\minor{100}{/dev/fd?u1920}{3.5\tum\ 1920K High Density\1}
-	\minor{ 32}{/dev/fd?u2880}{3.5\tum\ 2880K Extra Density\1}
-	\minor{104}{/dev/fd?u3200}{3.5\tum\ 3200K Extra Density}
-	\minor{108}{/dev/fd?u3520}{3.5\tum\ 3520K Extra Density}
-	\minor{112}{/dev/fd?u3840}{3.5\tum\ 3840K Extra Density\1}
-	\minor{}{}{}
-	\minor{36}{/dev/fd?CompaQ}{Compaq 2880K drive; probably obsolete}
-\\
-\major{}{}{}{\1 Autodetectable format}
-\major{}{}{}{\2 Autodetectable format in a Double Density (720K) drive only}
-\major{}{}{}{\3 Autodetectable format in a High Density (1440K) drive only}
-\end{devicelist}
-
-NOTE: The letter in the device name ({\file d}, {\file q}, {\file h}
-or {\file u}) signifies the type of drive supported: 5.25\tum\ Double
-Density ({\file d}), 5.25\tum\ Quad Density ({\file q}), 5.25\tum\
-High Density ({\file h}) or 3.5\tum\ (any type, {\file u}).  The
-capital letters {\file D}, {\file H}, or {\file E} for the 3.5\tum\
-models have been deprecated, since the drive type is insignificant for
-these devices.
-
-\begin{devicelist}
-\major{ 3}{}{char}{Pseudo-TTY slaves}
-	\minor{0}{/dev/ttyp0}{First PTY slave}
-	\minor{1}{/dev/ttyp1}{Second PTY slave}
-	\minordots
-	\minor{255}{/dev/ttyef}{256th PTY slave}
-\end{devicelist}
-
-\noindent
-These are the old-style (BSD) PTY devices; Unix98 devices are on major
-136 and above.
-
-\begin{devicelist}
-\major{}{}{block}{First MFM, RLL and IDE hard disk/CD-ROM interface}
-	\minor{0}{/dev/hda}{Master: whole disk (or CD-ROM)}
-	\minor{64}{/dev/hdb}{Slave: whole disk (or CD-ROM)}
-\\
-\major{}{}{}{For partitions, add to the whole disk device number}
-	\minor{0}{/dev/hd?}{Whole disk}
-	\minor{1}{/dev/hd?1}{First partition}
-	\minor{2}{/dev/hd?2}{Second partition}
-	\minordots
-	\minor{63}{/dev/hd?63}{63rd partition}
-\end{devicelist}
-
-\noindent
-For MS-DOS style partition tables (typically used by Linux/i386 and
-sometimes on Linux/Alpha), partitions 1-4 are the primary partitions,
-partitions 5 and up are logical partitions.  For other partitioning
-schemes, the meaning of the numbers vary.
-
-\begin{devicelist}
-\major{ 4}{}{char }{TTY devices}
-	\minor{0}{/dev/tty0}{Current virtual console}
-	\minor{1}{/dev/tty1}{First virtual console}
-	\minordots
-	\minor{63}{/dev/tty63}{63rd virtual console}
-	\minor{64}{/dev/ttyS0}{First serial port}
-	\minordots
-	\minor{127}{/dev/ttyS63}{64th serial port}
-	\minor{128}{/dev/ptyp0}{OBSOLETE}
-	\minordots
-	\minor{191}{/dev/ptysf}{OBSOLETE}
-	\minor{192}{/dev/ttyp0}{OBSOLETE}
-	\minordots
-	\minor{255}{/dev/ttysf}{OBSOLETE}
-\end{devicelist}
-
-\noindent
-Older versions of the Linux kernel used this major number for BSD PTY
-devices.  As of Linux 2.1.115, this is no longer supported.  Use major
-numbers 2 and 3.
-
-\begin{devicelist}
-\major{ 5}{}{char }{Alternate TTY devices}
-	\minor{0}{/dev/tty}{Current TTY device}
-	\minor{1}{/dev/console}{System console}
-	\minor{2}{/dev/ptmx}{PTY master multiplex}
-	\minor{64}{/dev/cua0}{Callout device corresponding to {\file ttyS0}}
-	\minordots
-	\minor{127}{/dev/cua63}{Callout device corresponding to {\file ttyS63}}
-\end{devicelist}
-
-\noindent
-(5,1) is {\file /dev/console} starting with Linux 2.1.71.  See the
-section on terminal devices for more information on {\file /dev/console}.
-
-\begin{devicelist}
-\major{ 6}{}{char }{Parallel printer devices}
-	\minor{0}{/dev/lp0}{First parallel printer ({\hex 0x3bc})}
-	\minor{1}{/dev/lp1}{Second parallel printer ({\hex 0x378})}
-	\minor{2}{/dev/lp2}{Third parallel printer ({\hex 0x278})}
-\end{devicelist}
-
-\noindent
-Not all computers have the {\hex 0x3bc} parallel port, hence the
-"first" printer may be either {\file /dev/lp0} or {\file /dev/lp1}.
-
-\begin{devicelist}
-\major{ 7}{}{char }{Virtual console access devices}
-	\minor{0}{/dev/vcs}{Current vc text access}
-	\minor{1}{/dev/vcs1}{tty1 text access}
-	\minordots
-	\minor{63}{/dev/vcs63}{tty63 text access}
-	\minor{128}{/dev/vcsa}{Current vc text/attribute access}
-	\minor{129}{/dev/vcsa1}{tty1 text/attribute access}
-	\minordots
-	\minor{191}{/dev/vcsa63}{tty63 text/attribute access}
-\end{devicelist}
-
-\noindent
-NOTE: These devices permit both read and write access.
-
-\begin{devicelist}
-\major{  }{}{block}{Loopback devices}
-	\minor{0}{/dev/loop0}{First loopback device}
-	\minor{1}{/dev/loop1}{Second loopback device}
-	\minordots
-\end{devicelist}
-
-\noindent
-The loopback devices are used to mount filesystems not associated with
-block devices.  The binding to the loopback devices is handled by
-{\bf mount}(8) or {\bf losetup}(8).
-
-\begin{devicelist}
-\major{ 8}{}{block}{SCSI disk devices (0-15)}
-	\minor{0}{/dev/sda}{First SCSI disk whole disk}
-	\minor{16}{/dev/sdb}{Second SCSI disk whole disk}
-	\minor{32}{/dev/sdc}{Third SCSI disk whole disk}
-	\minordots
-	\minor{240}{/dev/sdp}{Sixteenth SCSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{ 9}{}{char }{SCSI tape devices}
-	\minor{0}{/dev/st0}{First SCSI tape, mode 0}
-	\minor{1}{/dev/st1}{Second SCSI tape, mode 0}
-	\minordots
-	\minor{32}{/dev/st0l}{First SCSI tape, mode 1}
-	\minor{33}{/dev/st1l}{Second SCSI tape, mode 1}
-	\minordots
-	\minor{64}{/dev/st0m}{First SCSI tape, mode 2}
-	\minor{65}{/dev/st1m}{Second SCSI tape, mode 2}
-	\minordots
-	\minor{96}{/dev/st0a}{First SCSI tape, mode 3}
-	\minor{97}{/dev/st1a}{Second SCSI tape, mode 4}
-	\minordots
-	\minor{128}{/dev/nst0}{First SCSI tape, mode 0, no rewind}
-	\minor{129}{/dev/nst1}{Second SCSI tape, mode 0, no rewind}
-	\minordots
-	\minor{160}{/dev/nst0l}{First SCSI tape, mode 1, no rewind}
-	\minor{161}{/dev/nst1l}{Second SCSI tape, mode 1, no rewind}
-	\minordots
-	\minor{192}{/dev/nst0m}{First SCSI tape, mode 2, no rewind}
-	\minor{193}{/dev/nst1m}{Second SCSI tape, mode 2, no rewind}
-	\minordots
-	\minor{224}{/dev/nst0a}{First SCSI tape, mode 3, no rewind}
-	\minor{225}{/dev/nst1a}{Second SCSI tape, mode 3, no rewind}
-	\minordots
-\end{devicelist}
-
-\noindent
-``No rewind'' refers to the omission of the default automatic rewind
-on device close.  The {\file MTREW} or {\file MTOFFL} ioctl()s can be
-used to rewind the tape regardless of the device used to access it.
-
-\begin{devicelist}
-\major{  }{}{block}{Metadisk (RAID) devices}
-	\minor{0}{/dev/md0}{First metadisk group}
-	\minor{1}{/dev/md1}{Second metadisk group}
-	\minordots
-\end{devicelist}
-
-\noindent
-The metadisk driver is used to span a filesystem across multiple
-physical disks.
-
-\begin{devicelist}
-\major{10}{}{char }{Non-serial mice, misc features}
-	\minor{0}{/dev/logibm}{Logitech bus mouse}
-	\minor{1}{/dev/psaux}{PS/2-style mouse port}
-	\minor{2}{/dev/inportbm}{Microsoft Inport bus mouse}
-	\minor{3}{/dev/atibm}{ATI XL bus mouse}
-	\minor{4}{/dev/jbm}{J-mouse}
-	\minor{4}{/dev/amigamouse}{Amiga mouse (68k/Amiga)}
-	\minor{5}{/dev/atarimouse}{Atari mouse}
-	\minor{6}{/dev/sunmouse}{Sun mouse}
-	\minor{7}{/dev/amigamouse1}{Second Amiga mouse}
-	\minor{8}{/dev/smouse}{Simple serial mouse driver}
-	\minor{9}{/dev/pc110pad}{IBM PC-110 digitizer pad}
-	\minor{128}{/dev/beep}{Fancy beep device}
-	\minor{129}{/dev/modreq}{Kernel module load request}
-	\minor{130}{/dev/watchdog}{Watchdog timer port}
-	\minor{131}{/dev/temperature}{Machine internal temperature}
-	\minor{132}{/dev/hwtrap}{Hardware fault trap}
-	\minor{133}{/dev/exttrp}{External device trap}
-	\minor{134}{/dev/apm\_bios}{Advanced Power Management BIOS}
-	\minor{135}{/dev/rtc}{Real Time Clock}
-	\minor{139}{/dev/openprom}{SPARC OpenBoot PROM}
-	\minor{140}{/dev/relay8}{Berkshire Products Octal relay card}
-	\minor{141}{/dev/relay16}{Berkshire Products ISO-16 relay card}
-	\minor{142}{/dev/msr}{x86 model specific registers}
-	\minor{143}{/dev/pciconf}{PCI configuration space}
-	\minor{144}{/dev/nvram}{Non-volatile configuration RAM}
-	\minor{145}{/dev/hfmodem}{Soundcard shortwave modem control}
-	\minor{146}{/dev/graphics}{Linux/SGI graphics device}
-	\minor{147}{/dev/opengl}{Linux/SGI OpenGL pipe}
-	\minor{148}{/dev/gfx}{Linux/SGI graphics effects device}
-	\minor{149}{/dev/input/mouse}{Linux/SGI Irix emulation mouse}
-	\minor{150}{/dev/input/keyboard}{Linux/SGI Irix emulation keyboard}
-	\minor{151}{/dev/led}{Front panel LEDs}
-	\minor{153}{/dev/mergemem}{Memory merge device}
-	\minor{154}{/dev/pmu}{Macintosh PowerBook power manager}
-\end{devicelist}
-
-\begin{devicelist}
-\major{11}{}{char }{Raw keyboard device}
-	\minor{0}{/dev/kbd}{Raw keyboard device}
-\end{devicelist}
-
-\noindent
-The raw keyboard device is used on Linux/SPARC only.
-
-\begin{devicelist}
-\major{  }{}{block}{SCSI CD-ROM devices}
-	\minor{0}{/dev/sr0}{First SCSI CD-ROM}
-	\minor{1}{/dev/sr1}{Second SCSI CD-ROM}
-	\minordots
-\end{devicelist}
-
-\noindent
-The prefix {\file /dev/scd} instead of {\file /dev/sr} has been used
-as well, and might make more sense.
-
-\begin{devicelist}
-\major{12}{}{char }{QIC-02 tape}
-	\minor{2}{/dev/ntpqic11}{QIC-11, no rewind-on-close}
-	\minor{3}{/dev/tpqic11}{QIC-11, rewind-on-close}
-	\minor{4}{/dev/ntpqic24}{QIC-24, no rewind-on-close}
-	\minor{5}{/dev/tpqic24}{QIC-24, rewind-on-close}
-	\minor{6}{/dev/ntpqic120}{QIC-120, no rewind-on-close}
-	\minor{7}{/dev/tpqic120}{QIC-120, rewind-on-close}
-	\minor{8}{/dev/ntpqic150}{QIC-150, no rewind-on-close}
-	\minor{9}{/dev/tpqic150}{QIC-150, rewind-on-close}
-\end{devicelist}
-
-\noindent
-The device names specified are proposed -- if there are ``standard''
-names for these devices, please let me know.
-
-\begin{devicelist}
-\major{  }{}{block}{MSCDEX CD-ROM callback support}
-	\minor{0}{/dev/dos\_cd0}{First MSCDEX CD-ROM}
-	\minor{1}{/dev/dos\_cd1}{Second MSCDEX CD-ROM}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{13}{}{char }{PC speaker}
-	\minor{0}{/dev/pcmixer}{Emulates {\file /dev/mixer}}
-	\minor{3}{/dev/pcsp}{Emulates {\file /dev/dsp} (8-bit)}
-	\minor{4}{/dev/pcaudio}{Emulates {\file /dev/audio}}
-	\minor{5}{/dev/pcsp16}{Emulates {\file /dev/dsp} (16-bit)}
-\\
-\major{  }{}{block}{8-bit MFM/RLL/IDE controller}
-	\minor{0}{/dev/xda}{First XT disk whole disk}
-	\minor{64}{/dev/xdb}{Second XT disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3).
-
-\begin{devicelist}
-\major{14}{}{char }{Sound card}
-	\minor{0}{/dev/mixer}{Mixer control}
-	\minor{1}{/dev/sequencer}{Audio sequencer}
-	\minor{2}{/dev/midi00}{First MIDI port}
-	\minor{3}{/dev/dsp}{Digital audio}
-	\minor{4}{/dev/audio}{Sun-compatible digital audio}
-	\minor{6}{/dev/sndstat}{Sound card status information}
-	\minor{8}{/dev/sequencer2}{Sequencer -- alternate device}
-	\minor{16}{/dev/mixer1}{Second soundcard mixer control}
-	\minor{17}{/dev/patmgr0}{Sequencer patch manager}
-	\minor{18}{/dev/midi01}{Second MIDI port}
-	\minor{19}{/dev/dsp1}{Second soundcard digital audio}
-	\minor{20}{/dev/audio1}{Second soundcard Sun digital audio}
-	\minor{33}{/dev/patmgr1}{Sequencer patch manager}
-	\minor{34}{/dev/midi02}{Third MIDI port}
-	\minor{50}{/dev/midi03}{Fourth MIDI port}
-\\
-\major{  }{}{block}{BIOS harddrive callback support}
-	\minor{0}{/dev/dos\_hda}{First BIOS harddrive whole disk}
-	\minor{64}{/dev/dos\_hdb}{Second BIOS harddrive whole disk}
-	\minor{128}{/dev/dos\_hdc}{Third BIOS harddrive whole disk}
-	\minor{192}{/dev/dos\_hdd}{Fourth BIOS harddrive whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3).
-
-\begin{devicelist}
-\major{15}{}{char }{Joystick}
-	\minor{0}{/dev/js0}{First analog joystick}
-	\minor{1}{/dev/js1}{Second analog joystick}
-	\minordots
-	\minor{128}{/dev/djs0}{First digital joystick}
-	\minor{129}{/dev/djs1}{Second digital joystick}
-	\minordots
-\\
-\major{  }{}{block}{Sony CDU-31A/CDU-33A CD-ROM}
-	\minor{0}{/dev/sonycd}{Sony CDU-31A CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{16}{}{char }{Non-SCSI scanners}
-	\minor{0}{/dev/gs4500}{Genius 4500 handheld scanner}
-\\
-\major{  }{}{block}{GoldStar CD-ROM}
-	\minor{0}{/dev/gscd}{GoldStar CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{17}{}{char }{Chase serial card}
-	\minor{0}{/dev/ttyH0}{First Chase port}
-	\minor{1}{/dev/ttyH1}{Second Chase port}
-	\minordots
-\\
-\major{  }{}{block}{Optics Storage CD-ROM}
-	\minor{0}{/dev/optcd}{Optics Storage CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{18}{}{char }{Chase serial card -- alternate devices}
-	\minor{0}{/dev/cuh0}{Callout device corresponding to {\file ttyH0}}
-	\minor{1}{/dev/cuh1}{Callout device corresponding to {\file ttyH1}}
-	\minordots
-\\
-\major{  }{}{block}{Sanyo CD-ROM}
-	\minor{0}{/dev/sjcd}{Sanyo CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{19}{}{char }{Cyclades serial card}
-	\minor{0}{/dev/ttyC0}{First Cyclades port}
-	\minordots
-	\minor{31}{/dev/ttyC31}{32nd Cyclades port}
-\\
-\major{  }{}{block}{``Double'' compressed disk}
-	\minor{0}{/dev/double0}{First compressed disk}
-	\minordots
-	\minor{7}{/dev/double7}{Eighth compressed disk}
-	\minor{128}{/dev/cdouble0}{Mirror of first compressed disk}
-	\minordots
-	\minor{135}{/dev/cdouble7}{Mirror of eighth compressed disk}
-\end{devicelist}
-
-\noindent
-See the Double documentation for an explanation of the ``mirror'' devices.
-
-\begin{devicelist}
-\major{20}{}{char }{Cyclades serial card -- alternate devices}
-	\minor{0}{/dev/cub0}{Callout device corresponding to {\file ttyC0}}
-	\minordots
-	\minor{31}{/dev/cub31}{Callout device corresponding to {\file ttyC31}}
-\\
-\major{  }{}{block}{Hitachi CD-ROM}
-	\minor{0}{/dev/hitcd}{Hitachi CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{21}{}{char }{Generic SCSI access}
-	\minor{0}{/dev/sg0}{First generic SCSI device}
-	\minor{1}{/dev/sg1}{Second generic SCSI device}
-	\minordots
-\end{devicelist}
-
-\noindent
-Most distributions name these {\file /dev/sga}, {\file /dev/sgb}...
-This sets an unneccesary limit of 26 SCSI devices in the system, and
-is counter to standard Linux device-naming practice.
-
-\begin{devicelist}
-\major{  }{}{block }{Acorn MFM hard drive interface}
-	\minor{0}{/dev/mfma}{First MFM drive whole disk}
-	\minor{64}{/dev/mfmb}{Second MFM drive whole disk}
-\end{devicelist}
-
-\noindent
-This device is used on the ARM-based Acorn RiscPC.  Partitions are
-handled the same way as for IDE disks (see major number 3).
-
-\begin{devicelist}
-\major{22}{}{char }{Digiboard serial card}
-	\minor{0}{/dev/ttyD0}{First Digiboard port}
-	\minor{1}{/dev/ttyD1}{Second Digiboard port}
-	\minordots
-\\
-\major{  }{}{block}{Second IDE hard disk/CD-ROM interface}
-	\minor{0}{/dev/hdc}{Master: whole disk (or CD-ROM)}
-	\minor{64}{/dev/hdd}{Slave: whole disk (or CD-ROM)}
-\end{devicelist}
-
-\noindent
-Partitions are handled the same way as for the first interface (see
-major number 3).
-
-\begin{devicelist}
-\major{23}{}{char }{Digiboard serial card -- alternate devices}
-	\minor{0}{/dev/cud0}{Callout device corresponding to {\file ttyD0}}
-	\minor{1}{/dev/cud1}{Callout device corresponding to {\file ttyD1}}
-	\minordots
-\major{  }{}{block}{Mitsumi proprietary CD-ROM}
-	\minor{0}{/dev/mcd}{Mitsumi CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}\
-\major{24}{}{char }{Stallion serial card}
-	\minor{0}{/dev/ttyE0}{Stallion port 0 board 0}
-	\minor{1}{/dev/ttyE1}{Stallion port 1 board 0}
-	\minordots
-	\minor{64}{/dev/ttyE64}{Stallion port 0 board 1}
-	\minor{65}{/dev/ttyE65}{Stallion port 1 board 1}
-	\minordots
-	\minor{128}{/dev/ttyE128}{Stallion port 0 board 2}
-	\minor{129}{/dev/ttyE129}{Stallion port 1 board 2}
-	\minordots
-	\minor{192}{/dev/ttyE192}{Stallion port 0 board 3}
-	\minor{193}{/dev/ttyE193}{Stallion port 1 board 3}
-	\minordots
-\\
-\major{  }{}{block}{Sony CDU-535 CD-ROM}
-	\minor{0}{/dev/cdu535}{Sony CDU-535 CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{25}{}{char }{Stallion serial card -- alternate devices}
-	\minor{0}{/dev/cue0}{Callout device corresponding to {\file ttyE0}}
-	\minor{1}{/dev/cue1}{Callout device corresponding to {\file ttyE1}}
-	\minordots
-	\minor{64}{/dev/cue64}{Callout device corresponding to {\file ttyE64}}
-	\minor{65}{/dev/cue65}{Callout device corresponding to {\file ttyE65}}
-	\minordots
-	\minor{128}{/dev/cue128}{Callout device corresponding to {\file ttyE128}}
-	\minor{129}{/dev/cue129}{Callout device corresponding to {\file ttyE129}}
-	\minordots
-	\minor{192}{/dev/cue192}{Callout device corresponding to {\file ttyE192}}
-	\minor{193}{/dev/cue193}{Callout device corresponding to {\file ttyE193}}
-	\minordots
-\\
-\major{  }{}{block}{First Matsushita (Panasonic/SoundBlaster) CD-ROM}
-	\minor{0}{/dev/sbpcd0}{Panasonic CD-ROM controller 0 unit 0}
-	\minor{1}{/dev/sbpcd1}{Panasonic CD-ROM controller 0 unit 1}
-	\minor{2}{/dev/sbpcd2}{Panasonic CD-ROM controller 0 unit 2}
-	\minor{3}{/dev/sbpcd3}{Panasonic CD-ROM controller 0 unit 3}
-\end{devicelist}
-
-\begin{devicelist}
-\major{26}{}{char }{Quanta WinVision frame grabber}
-	\minor{0}{/dev/wvisfgrab}{Quanta WinVision frame grabber}
-\\
-\major{  }{}{block}{Second Matsushita (Panasonic/SoundBlaster) CD-ROM}
-	\minor{0}{/dev/sbpcd4}{Panasonic CD-ROM controller 1 unit 0}
-	\minor{1}{/dev/sbpcd5}{Panasonic CD-ROM controller 1 unit 1}
-	\minor{2}{/dev/sbpcd6}{Panasonic CD-ROM controller 1 unit 2}
-	\minor{3}{/dev/sbpcd7}{Panasonic CD-ROM controller 1 unit 3}
-\end{devicelist}
-
-\begin{devicelist}
-\major{27}{}{char }{QIC-117 tape}
-	\minor{0}{/dev/qft0}{Unit 0, rewind-on-close}
-	\minor{1}{/dev/qft1}{Unit 1, rewind-on-close}
-	\minor{2}{/dev/qft2}{Unit 2, rewind-on-close}
-	\minor{3}{/dev/qft3}{Unit 3, rewind-on-close}
-	\minor{4}{/dev/nqft0}{Unit 0, no rewind-on-close}
-	\minor{5}{/dev/nqft1}{Unit 1, no rewind-on-close}
-	\minor{6}{/dev/nqft2}{Unit 2, no rewind-on-close}
-	\minor{7}{/dev/nqft3}{Unit 3, no rewind-on-close}
-	\minor{16}{/dev/zqft0}{Unit 0, rewind-on-close, compression}
-	\minor{17}{/dev/zqft1}{Unit 1, rewind-on-close, compression}
-	\minor{18}{/dev/zqft2}{Unit 2, rewind-on-close, compression}
-	\minor{19}{/dev/zqft3}{Unit 3, rewind-on-close, compression}
-	\minor{20}{/dev/nzqft0}{Unit 0, no rewind-on-close, compression}
-	\minor{21}{/dev/nzqft1}{Unit 1, no rewind-on-close, compression}
-	\minor{22}{/dev/nzqft2}{Unit 2, no rewind-on-close, compression}
-	\minor{23}{/dev/nzqft3}{Unit 3, no rewind-on-close, compression}
-	\minor{32}{/dev/rawqft0}{Unit 0, rewind-on-close, no file marks}
-	\minor{33}{/dev/rawqft1}{Unit 1, rewind-on-close, no file marks}
-	\minor{34}{/dev/rawqft2}{Unit 2, rewind-on-close, no file marks}
-	\minor{35}{/dev/rawqft3}{Unit 3, rewind-on-close, no file marks}
-	\minor{36}{/dev/nrawqft0}{Unit 0, no rewind-on-close, no file marks}
-	\minor{37}{/dev/nrawqft1}{Unit 1, no rewind-on-close, no file marks}
-	\minor{38}{/dev/nrawqft2}{Unit 2, no rewind-on-close, no file marks}
-	\minor{39}{/dev/nrawqft3}{Unit 3, no rewind-on-close, no file marks}
-\\
-\major{  }{}{block}{Third Matsushita (Panasonic/SoundBlaster) CD-ROM}
-	\minor{0}{/dev/sbpcd8}{Panasonic CD-ROM controller 2 unit 0}
-	\minor{1}{/dev/sbpcd9}{Panasonic CD-ROM controller 2 unit 1}
-	\minor{2}{/dev/sbpcd10}{Panasonic CD-ROM controller 2 unit 2}
-	\minor{3}{/dev/sbpcd11}{Panasonic CD-ROM controller 2 unit 3}
-\end{devicelist}
-
-\begin{devicelist}
-\major{28}{}{char }{Stallion serial card -- card programming}
-	\minor{0}{/dev/staliomem0}{First Stallion I/O card memory}
-	\minor{1}{/dev/staliomem1}{Second Stallion I/O card memory}
-	\minor{2}{/dev/staliomem2}{Third Stallion I/O card memory}
-	\minor{3}{/dev/staliomem3}{Fourth Stallion I/O card memory}
-\\
-\major{  }{}{char }{Atari SLM ACSI laser printer (68k/Atari)}
-	\minor{0}{/dev/slm0}{First SLM laser printer}
-	\minor{1}{/dev/slm1}{Second SLM laser printer}
-	\minordots
-\\
-\major{  }{}{block}{Fourth Matsushita (Panasonic/SoundBlaster) CD-ROM}
-	\minor{0}{/dev/sbpcd12}{Panasonic CD-ROM controller 3 unit 0}
-	\minor{1}{/dev/sbpcd13}{Panasonic CD-ROM controller 3 unit 1}
-	\minor{2}{/dev/sbpcd14}{Panasonic CD-ROM controller 3 unit 2}
-	\minor{3}{/dev/sbpcd15}{Panasonic CD-ROM controller 3 unit 3}
-\\
-\major{  }{}{block}{ACSI disk/CD-ROM (68k/Atari)}
-	\minor{0}{/dev/ada}{First ACSI disk whole disk}
-	\minor{16}{/dev/adb}{Second ACSI disk whole disk}
-	\minor{32}{/dev/adc}{Third ACSI disk whole disk}
-	\minordots
-	\minor{240}{/dev/adp}{Sixteenth ACSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk (same as SCSI.)
-
-\begin{devicelist}
-\major{29}{}{char }{Universal frame buffer}
-	\minor{0}{/dev/fb0}{First frame buffer}
-	\minor{32}{/dev/fb1}{Second frame buffer}
-	\minor{64}{/dev/fb2}{Third frame buffer}
-	\minordots
-	\minor{224}{/dev/fb7}{Eighth frame buffer}
-\end{devicelist}
-
-\noindent
-All additional minor device numbers are reserved.
-
-\begin{devicelist}
-\major{  }{}{block}{Aztech/Orchid/Okano/Wearnes CD-ROM}
-	\minor{0}{/dev/aztcd}{Aztech CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{30}{}{char }{iBCS-2 compatibility devices}
-	\minor{0}{/dev/socksys}{Socket access}
-	\minor{1}{/dev/spx}{SVR3 local X interface}
-	\minor{2}{/dev/inet/arp}{Network access}
-	\minor{2}{/dev/inet/icmp}{Network access}
-	\minor{2}{/dev/inet/ip}{Network access}
-	\minor{2}{/dev/inet/udp}{Network access}
-	\minor{2}{/dev/inet/tcp}{Network access}
-\end{devicelist}
-
-\noindent
-Additionally, iBCS-2 requires {\file /dev/nfsd} to be a link to {\file
-/dev/socksys} and {\file /dev/X0R} to be a link to {\file /dev/null}.
-
-\begin{devicelist}
-\major{  }{}{block}{Philips LMS CM-205 CD-ROM}
-	\minor{0}{/dev/cm205cd}{Philips LMS CM-205 CD-ROM}
-\end{devicelist}
-
-\noindent
-{\file /dev/lmscd} is an older name for this drive.  This driver does
-not work with the CM-205MS CD-ROM.
-
-\begin{devicelist}
-\major{31}{}{char }{MPU-401 MIDI}
-	\minor{0}{/dev/mpu401data}{MPU-401 data port}
-	\minor{1}{/dev/mpu401stat}{MPU-401 status port}
-\\
-\major{  }{}{block}{ROM/flash memory card}
-	\minor{0}{/dev/rom0}{First ROM card (rw)}
-	\minordots
-	\minor{7}{/dev/rom7}{Eighth ROM card (rw)}
-	\minor{8}{/dev/rrom0}{First ROM card (ro)}
-	\minordots
-	\minor{15}{/dev/rrom0}{Eighth ROM card (ro)}
-	\minor{16}{/dev/flash0}{First flash memory card (rw)}
-	\minordots
-	\minor{23}{/dev/flash7}{Eighth flash memory card (rw)}
-	\minor{24}{/dev/rflash0}{First flash memory card (ro)}
-	\minordots
-	\minor{31}{/dev/rflash7}{Eighth flash memory card (ro)}
-\end{devicelist}
-
-\noindent
-The read-write (rw) devices support back-caching written data in RAM,
-as well as writing to flash RAM devices.  The read-only devices (ro)
-support reading only.
-
-\begin{devicelist}
-\major{32}{}{char }{Specialix serial card}
-	\minor{0}{/dev/ttyX0}{First Specialix port}
-	\minor{1}{/dev/ttyX1}{Second Specialix port}
-	\minordots
-\\
-\major{  }{}{block}{Philips LMS CM-206 CD-ROM}
-	\minor{0}{/dev/cm206cd}{Philips LMS CM-206 CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{33}{}{char }{Specialix serial card -- alternate devices}
-	\minor{0}{/dev/cux0}{Callout device corresponding to {\file ttyX0}}
-	\minor{1}{/dev/cux1}{Callout device corresponding to {\file ttyX1}}
-	\minordots
-\\
-\major{  }{}{block}{Third IDE hard disk/CD-ROM interface}
-	\minor{0}{/dev/hde}{Master: whole disk (or CD-ROM)}
-	\minor{64}{/dev/hdf}{Slave: whole disk (or CD-ROM)}
-\end{devicelist}
-
-\noindent
-Partitions are handled the same way as for the first interface (see
-major number 3).
-
-\begin{devicelist}
-\major{34}{}{char }{Z8530 HDLC driver}
-	\minor{0}{/dev/scc0}{First Z8530, first port}
-	\minor{1}{/dev/scc1}{First Z8530, second port}
-	\minor{2}{/dev/scc2}{Second Z8530, first port}
-	\minor{3}{/dev/scc3}{Second Z8530, second port}
-	\minordots
-\end{devicelist}
-
-\noindent
-In a previous version these devices were named {\file /dev/sc1} for
-{\file /dev/scc0}, {\file /dev/sc2} for {\file /dev/scc1}, and so on.
-
-\begin{devicelist}
-\major{  }{}{block}{Fourth IDE hard disk/CD-ROM interface}
-	\minor{0}{/dev/hdg}{Master: whole disk (or CD-ROM)}
-	\minor{64}{/dev/hdh}{Slave: whole disk (or CD-ROM)}
-\end{devicelist}
-
-\noindent
-Partitions are handled the same way as for the first interface (see
-major number 3).
-
-\begin{devicelist}
-\major{35}{}{char }{tclmidi MIDI driver}
-	\minor{0}{/dev/midi0}{First MIDI port, kernel timed}
-	\minor{1}{/dev/midi1}{Second MIDI port, kernel timed}
-	\minor{2}{/dev/midi2}{Third MIDI port, kernel timed}
-	\minor{3}{/dev/midi3}{Fourth MIDI port, kernel timed}
-	\minor{64}{/dev/rmidi0}{First MIDI port, untimed}
-	\minor{65}{/dev/rmidi1}{Second MIDI port, untimed}
-	\minor{66}{/dev/rmidi2}{Third MIDI port, untimed}
-	\minor{67}{/dev/rmidi3}{Fourth MIDI port, untimed}
-	\minor{128}{/dev/smpte0}{First MIDI port, SMPTE timed}
-	\minor{129}{/dev/smpte1}{Second MIDI port, SMPTE timed}
-	\minor{130}{/dev/smpte2}{Third MIDI port, SMPTE timed}
-	\minor{131}{/dev/smpte3}{Fourth MIDI port, SMPTE timed}
-\\
-\major{  }{}{block}{Slow memory ramdisk}
-	\minor{0}{/dev/slram}{Slow memory ramdisk}
-\end{devicelist}
-
-\begin{devicelist}
-\major{36}{}{char }{Netlink support}
-	\minor{0}{/dev/route}{Routing, device updates (kernel to user)}
-	\minor{1}{/dev/skip}{enSKIP security cache control}
-\\
-\major{  }{}{block}{MCA ESDI hard disk}
-	\minor{0}{/dev/eda}{First ESDI disk whole disk}
-	\minor{64}{/dev/edb}{Second ESDI disk whole disk}
-	\minordots
-\end{devicelist}
-
-\noindent
-Partitions are handled the same way as for IDE disks (see major number
-3).
-
-\begin{devicelist}
-\major{37}{}{char }{IDE tape}
-	\minor{0}{/dev/ht0}{First IDE tape}
-	\minor{128}{/dev/nht0}{First IDE tape, no rewind-on-close}
-\end{devicelist}
-
-\noindent
-Currently, only one IDE tape drive is supported.
-
-\begin{devicelist}
-\major{  }{}{block}{Zorro II ramdisk}
-	\minor{0}{/dev/z2ram}{Zorro II ramdisk}
-\end{devicelist}
-
-\begin{devicelist}
-\major{38}{}{char }{Myricom PCI Myrinet board}
-	\minor{0}{/dev/mlanai0}{First Myrinet board}
-	\minor{1}{/dev/mlanai1}{Second Myrinet board}
-	\minordots
-\end{devicelist}
-
-\noindent
-This device is used for board control, status query and ``user level
-packet I/O''.  The board is also accessible as a regular {\file eth}
-networking device.
-
-\begin{devicelist}
-\major{  }{}{block}{Reserved for Linux/AP+}
-\end{devicelist}
-
-\begin{devicelist}
-\major{39}{}{char }{ML-16P experimental I/O board}
-	\minor{0}{/dev/ml16pa-a0}{First card, first analog channel}
-	\minor{1}{/dev/ml16pa-a1}{First card, second analog channel}
-	\minordots
-	\minor{15}{/dev/ml16pa-a15}{First card, 16th analog channel}
-	\minor{16}{/dev/ml16pa-d}{First card, digital lines}
-	\minor{17}{/dev/ml16pa-c0}{First card, first counter/timer}
-	\minor{18}{/dev/ml16pa-c1}{First card, second counter/timer}
-	\minor{19}{/dev/ml16pa-c2}{First card, third counter/timer}
-	\minor{32}{/dev/ml16pb-a0}{Second card, first analog channel}
-	\minor{33}{/dev/ml16pb-a1}{Second card, second analog channel}
-	\minordots
-	\minor{47}{/dev/ml16pb-a15}{Second card, 16th analog channel}
-	\minor{48}{/dev/ml16pb-d}{Second card, digital lines}
-	\minor{49}{/dev/ml16pb-c0}{Second card, first counter/timer}
-	\minor{50}{/dev/ml16pb-c1}{Second card, second counter/timer}
-	\minor{51}{/dev/ml16pb-c2}{Second card, third counter/timer}
-	\minordots
-\\
-\major{  }{}{block}{Reserved for Linux/AP+}
-\end{devicelist}
-
-\begin{devicelist}
-\major{40}{}{char }{Matrox Meteor frame grabber}
-	\minor{0}{/dev/mmetfgrab}{Matrox Meteor frame grabber}
-\\
-\major{  }{}{block}{Syquest EZ135 parallel port removable drive}
-	\minor{0}{/dev/eza}{Parallel EZ135 drive whole disk}
-\end{devicelist}
-
-\noindent
-This device is obsolete and will be removed in a future version of
-Linux.  It has been replaced with the parallel port IDE disk driver at
-major number 45.  Partitions are handled the same way as for IDE disks
-(see major number 3).
-
-\begin{devicelist}
-\major{41}{}{char }{Yet Another Micro Monitor}
-	\minor{0}{/dev/yamm}{Yet Another Micro Monitor}
-\\
-\major{  }{}{block}{MicroSolutions BackPack parallel port CD-ROM}
-	\minor{0}{/dev/bpcd}{BackPack CD-ROM}
-\end{devicelist}
-
-\noindent
-This device is obsolete and will be removed in a future version of
-Linux.  It has been replaced with the parallel port ATAPI CD-ROM
-driver at major number 46.
-
-\begin{devicelist}
-\major{42}{}{}{Demo/sample use}
-\end{devicelist}
-
-\noindent
-This number is intended for use in sample code, as well as a general
-``example'' device number.  It should never be used for a device
-driver that is being distributed; either obtain an official number or
-use the local/experimental range.  The sudden addition or removal of a
-driver with this number should not cause ill effects to the system
-(bugs excepted.)
-
-IN PARTICULAR, ANY DISTRIBUTION WHICH CONTAINS A DEVICE DRIVER USING
-MAJOR NUMBER 42 IS NONCOMPLIANT.
-
-\begin{devicelist}
-\major{43}{}{char }{isdn4linux virtual modem}
-	\minor{0}{/dev/ttyI0}{First virtual modem}
-	\minordots
-	\minor{63}{/dev/ttyI63}{64th virtual modem}
-\\
-\major{  }{}{block}{Network block devices}
-	\minor{0}{/dev/nd0}{First network block device}
-	\minor{1}{/dev/nd1}{Second network block device}
-	\minordots
-\end{devicelist}
-
-\noindent
-Network Block Device is somehow similar to loopback devices: If you
-read from it, it sends packet accross network asking server for
-data. If you write to it, it sends packet telling server to write. It
-could be used to mounting filesystems over the net, swapping over the
-net, implementing block device in userland etc.
-
-\begin{devicelist}
-\major{44}{}{char }{isdn4linux virtual modem -- alternate devices}
-	\minor{0}{/dev/cui0}{Callout device corresponding to {\file ttyI0}}
-	\minordots
-	\minor{63}{/dev/cui63}{Callout device corresponding to {\file ttyI63}}
-\\
-\major{  }{}{block}{Flash Translation Layer (FTL) filesystems}
-        \minor{0}{/dev/ftla}{FTL on first Memory Technology Device}
-        \minor{16}{/dev/ftlb}{FTL on second Memory Technology Device}
-        \minor{32}{/dev/ftlc}{FTL on third Memory Technology Device}
-        \minordots
-        \minor{240}{/dev/ftlp}{FTL on 16th Memory Technology Device}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) expect that the partition limit is 15 rather than 63 per
-disk (same as SCSI.)
-
-\begin{devicelist}
-\major{45}{}{char }{isdn4linux ISDN BRI driver}
-	\minor{0}{/dev/isdn0}{First virtual B channel raw data}
-	\minordots
-	\minor{63}{/dev/isdn63}{64th virtual B channel raw data}
-	\minor{64}{/dev/isdnctrl0}{First channel control/debug}
-	\minordots
-	\minor{127}{/dev/isdnctrl63}{64th channel control/debug}
-	\minor{128}{/dev/ippp0}{First SyncPPP device}
-	\minordots
-	\minor{191}{/dev/ippp63}{64th SyncPPP device}
-	\minor{255}{/dev/isdninfo}{ISDN monitor interface}
-\\
-\major{  }{}{block}{Parallel port IDE disk devices}
-	\minor{0}{/dev/pda}{First parallel port IDE disk}
-	\minor{16}{/dev/pdb}{Second parallel port IDE disk}
-	\minor{32}{/dev/pdc}{Third parallel port IDE disk}
-	\minor{48}{/dev/pdd}{Fourth parallel port IDE disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{46}{}{char }{Comtrol Rocketport serial card}
-	\minor{0}{/dev/ttyR0}{First Rocketport port}
-	\minor{1}{/dev/ttyR1}{Second Rocketport port}
-	\minordots
-\\
-\major{  }{}{block}{Parallel port ATAPI CD-ROM devices}
-	\minor{0}{/dev/pcd0}{First parallel port ATAPI CD-ROM}
-	\minor{1}{/dev/pcd1}{Second parallel port ATAPI CD-ROM}
-	\minor{2}{/dev/pcd2}{Third parallel port ATAPI CD-ROM}
-	\minor{3}{/dev/pcd3}{Fourth parallel port ATAPI CD-ROM}
-\end{devicelist}
-
-\begin{devicelist}
-\major{47}{}{char }{Comtrol Rocketport serial card -- alternate devices}
-	\minor{0}{/dev/cur0}{Callout device corresponding to {\file ttyR0}}
-	\minor{1}{/dev/cur1}{Callout device corresponding to {\file ttyR1}}
-	\minordots
-\\
-\major{  }{}{block}{Parallel port ATAPI disk devices}
-	\minor{0}{/dev/pf0}{First parallel port ATAPI disk}
-	\minor{1}{/dev/pf1}{Second parallel port ATAPI disk}
-	\minor{2}{/dev/pf2}{Third parallel port ATAPI disk}
-	\minor{3}{/dev/pf3}{Fourth parallel port ATAPI disk}
-\end{devicelist}
-
-\noindent
-This driver is intended for floppy disks and similar devices and hence
-does not support partitioning.
-
-\begin{devicelist}
-\major{48}{}{char }{SDL RISCom serial card}
-	\minor{0}{/dev/ttyL0}{First RISCom port}
-	\minor{1}{/dev/ttyL1}{Second RISCom port}
-	\minordots
-\\
-\major{  }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\end{devicelist}
-
-\begin{devicelist}
-\major{49}{}{char }{SDL RISCom serial card -- alternate devices}
-	\minor{0}{/dev/cul0}{Callout device corresponding to {\file ttyL0}}
-	\minor{1}{/dev/cul1}{Callout device corresponding to {\file ttyL1}}
-	\minordots
-\\
-\major{  }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\end{devicelist}
-
-\begin{devicelist}
-\major{50}{}{char}{Reserved for GLINT}
-\\
-\major{  }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\end{devicelist}
-
-\begin{devicelist}
-\major{51}{}{char }{Baycom radio modem}
-	\minor{0}{/dev/bc0}{First Baycom radio modem}
-	\minor{1}{/dev/bc1}{Second Baycom radio modem}
-	\minordots
-\\
-\major{  }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\end{devicelist}
-
-\begin{devicelist}
-\major{52}{}{char }{Spellcaster DataComm/BRI ISDN card}
-	\minor{0}{/dev/dcbri0}{First DataComm card}
-	\minor{1}{/dev/dcbri1}{Second DataComm card}
-	\minor{2}{/dev/dcbri2}{Third DataComm card}
-	\minor{3}{/dev/dcbri3}{Fourth DataComm card}
-\\
-\major{  }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\end{devicelist}
-
-\begin{devicelist}
-\major{53}{}{char }{BDM interface for remote debugging MC683xx microcontrollers}
-	\minor{0}{/dev/pd\_bdm0}{PD BDM interface on {\file lp0}}
-	\minor{1}{/dev/pd\_bdm1}{PD BDM interface on {\file lp1}}
-	\minor{2}{/dev/pd\_bdm2}{PD BDM interface on {\file lp2}}
-	\minor{4}{/dev/icd\_bdm0}{ICD BDM interface on {\file lp0}}
-	\minor{5}{/dev/icd\_bdm1}{ICD BDM interface on {\file lp1}}
-	\minor{6}{/dev/icd\_bdm2}{ICD BDM interface on {\file lp2}}
-\end{devicelist}
-
-\noindent
-This device is used for the interfacing to the MC683xx
-microcontrollers via Background Debug Mode by use of a Parallel Port
-interface. PD is the Motorola Public Domain Interface and ICD is the
-commercial interface by P\&E.
-
-\begin{devicelist}
-\major{  }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\end{devicelist}
-
-\begin{devicelist}
-\major{54}{}{char }{Electrocardiognosis Holter serial card}
-	\minor{0}{/dev/holter0}{First Holter port}
-	\minor{1}{/dev/holter1}{Second Holter port}
-	\minor{2}{/dev/holter2}{Third Holter port}
-\end{devicelist}
-
-\noindent
-A custom serial card used by Electrocardiognosis SRL
-$<$mseritan@ottonel.pub.ro$>$ to transfer data from Holter 24-hour
-heart monitoring equipment.
-
-\begin{devicelist}
-\major{  }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\end{devicelist}
-
-\begin{devicelist}
-\major{55}{}{char }{DSP56001 digital signal processor}
-	\minor{0}{/dev/dsp56k}{First DSP56001}
-\\
-\major{  }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller}
-\end{devicelist}
-
-\begin{devicelist}
-\major{56}{}{char }{Apple Desktop Bus}
-	\minor{0}{/dev/adb}{ADB bus control}
-\end{devicelist}
-
-\noindent
-Additional devices will be added to this number, all starting with
-{\file /dev/adb}.
-
-\begin{devicelist}
-\major{  }{}{block}{Fifth IDE hard disk/CD-ROM interface}
-	\minor{0}{/dev/hdi}{Master: whole disk (or CD-ROM)}
-	\minor{64}{/dev/hdj}{Slave: whole disk (or CD-ROM)}
-\end{devicelist}
-
-\noindent
-Partitions are handled the same way as for the first interface (see
-major number 3).
-
-\begin{devicelist}
-\major{57}{}{char }{Hayes ESP serial card}
-	\minor{0}{/dev/ttyP0}{First ESP port}
-	\minor{1}{/dev/ttyP1}{Second ESP port}
-	\minordots
-\\
-\major{  }{}{block}{Sixth IDE hard disk/CD-ROM interface}
-	\minor{0}{/dev/hdk}{Master: whole disk (or CD-ROM)}
-	\minor{64}{/dev/hdl}{Slave: whole disk (or CD-ROM)}
-\end{devicelist}
-
-\noindent
-Partitions are handled the same way as for the first interface (see
-major number 3).
-
-\begin{devicelist}
-\major{58}{}{char }{Hayes ESP serial card -- alternate devices}
-	\minor{0}{/dev/cup0}{Callout device corresponding to {\file ttyP0}}
-	\minor{1}{/dev/cup1}{Callout device corresponding to {\file ttyP1}}
-	\minordots
-\\
-\major{  }{}{block}{Reserved for logical volume manager}
-\end{devicelist}
-
-\begin{devicelist}
-\major{59}{}{char }{sf firewall package}
-	\minor{0}{/dev/firewall}{Communication with sf kernel module}
-\end{devicelist}
-
-\begin{devicelist}
-\major{60}{--63}{}{Local/experimental use}
-\end{devicelist}
-
-\noindent
-For devices not assigned official numbers, these ranges should be
-used, in order to avoid conflict with future assignments.
-
-\begin{devicelist}
-\major{64}{}{char }{ENskip kernel encryption package}
-	\minor{0}{/dev/enskip}{Communication with ENskip kernel
-	module}
-\end{devicelist}
-
-\begin{devicelist}
-\major{65}{}{char }{Sundance ``plink'' Transputer boards}
-	\minor{0}{/dev/plink0}{First plink device}
-	\minor{1}{/dev/plink1}{Second plink device}
-	\minor{2}{/dev/plink2}{Third plink device}
-	\minor{3}{/dev/plink3}{Fourth plink device}
-	\minor{64}{/dev/rplink0}{First plink device, raw}
-	\minor{65}{/dev/rplink1}{Second plink device, raw}
-	\minor{66}{/dev/rplink2}{Third plink device, raw}
-	\minor{67}{/dev/rplink3}{Fourth plink device, raw}
-	\minor{128}{/dev/plink0d}{First plink device, debug}
-	\minor{129}{/dev/plink1d}{Second plink device, debug}
-	\minor{130}{/dev/plink2d}{Third plink device, debug}
-	\minor{131}{/dev/plink3d}{Fourth plink device, debug}
-	\minor{192}{/dev/rplink0d}{First plink device, raw, debug}
-	\minor{193}{/dev/rplink1d}{Second plink device, raw, debug}
-	\minor{194}{/dev/rplink2d}{Third plink device, raw, debug}
-	\minor{195}{/dev/rplink3d}{Fourth plink device, raw, debug}
-\end{devicelist}
-
-\noindent
-This is a commercial driver; contact James Howes
-$<$jth@prosig.demon.co.uk$>$ for information. 
-
-\begin{devicelist}
-\major{  }{}{block}{SCSI disk devices (16-31)}
-	\minor{0}{/dev/sdq}{17th SCSI disk whole disk}
-	\minor{16}{/dev/sdr}{18th SCSI disk whole disk}
-	\minor{32}{/dev/sds}{19th SCSI disk whole disk}
-	\minordots
-	\minor{240}{/dev/sdaf}{32nd SCSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{66}{}{char }{YARC PowerPC PCI coprocessor card}
-	\minor{0}{/dev/yppcpci0}{First YARC card}
-	\minor{1}{/dev/yppcpci1}{Second YARC card}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{  }{}{block}{SCSI disk devices (32-47)}
-	\minor{0}{/dev/sdag}{33rd SCSI disk whole disk}
-	\minor{16}{/dev/sdah}{34th SCSI disk whole disk}
-	\minor{32}{/dev/sdai}{35th SCSI disk whole disk}
-	\minordots
-	\minor{240}{/dev/sdav}{48th SCSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{67}{}{char }{Coda network filesystem}
-	\minor{0}{/dev/cfs0}{Coda cache manager}
-\end{devicelist}
-
-\noindent
-See {\url http://www.coda.cs.cmu.edu\/} for information about Coda.
-
-\begin{devicelist}
-\major{  }{}{block}{SCSI disk devices (48-63)}
-	\minor{0}{/dev/sdaw}{49th SCSI disk whole disk}
-	\minor{16}{/dev/sdax}{50th SCSI disk whole disk}
-	\minor{32}{/dev/sday}{51st SCSI disk whole disk}
-	\minordots
-	\minor{240}{/dev/sdbl}{64th SCSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{68}{}{char }{CAPI 2.0 interface}
-	\minor{0}{/dev/capi20}{Control device}
-	\minor{1}{/dev/capi20.00}{First CAPI 2.0 application}
-	\minor{2}{/dev/capi20.01}{Second CAPI 2.0 application}
-	\minordots
-	\minor{20}{/dev/capi20.19}{19th CAPI 2.0 application}
-\end{devicelist}
-
-\noindent
-ISDN CAPI 2.0 driver for use with CAPI 2.0 applications; currently
-supports the AVM B1 card.
-
-\begin{devicelist}
-\major{  }{}{block}{SCSI disk devices (64-79)}
-	\minor{0}{/dev/sdbm}{65th SCSI disk whole disk}
-	\minor{16}{/dev/sdbn}{66th SCSI disk whole disk}
-	\minor{32}{/dev/sdbo}{67th SCSI disk whole disk}
-	\minordots
-	\minor{240}{/dev/sdcb}{80th SCSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{69}{}{char }{MA16 numeric accelerator card}
-	\minor{0}{/dev/ma16}{Board memory access}
-\end{devicelist}
-
-\begin{devicelist}
-\major{  }{}{block}{SCSI disk devices (80-95)}
-	\minor{0}{/dev/sdcc}{81st SCSI disk whole disk}
-	\minor{16}{/dev/sdcd}{82nd SCSI disk whole disk}
-	\minor{32}{/dev/sdce}{83th SCSI disk whole disk}
-	\minordots
-	\minor{240}{/dev/sdcr}{96th SCSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{70}{}{char }{SpellCaster Protocol Services Interface}
-	\minor{0}{/dev/apscfg}{Configuration interface}
-	\minor{1}{/dev/apsauth}{Authentication interface}
-	\minor{2}{/dev/apslog}{Logging interface}
-	\minor{3}{/dev/apsdbg}{Debugging interface}
-	\minor{64}{/dev/apsisdn}{ISDN command interface}
-	\minor{65}{/dev/apsasync}{Async command interface}
-	\minor{128}{/dev/apsmon}{Monitor interface}
-\end{devicelist}
-
-\begin{devicelist}
-\major{  }{}{block}{SCSI disk devices (96-111)}
-	\minor{0}{/dev/sdcs}{97th SCSI disk whole disk}
-	\minor{16}{/dev/sdct}{98th SCSI disk whole disk}
-	\minor{32}{/dev/sdcu}{99th SCSI disk whole disk}
-	\minordots
-	\minor{240}{/dev/sddh}{112th SCSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{71}{}{char }{Computone IntelliPort II serial card}
-	\minor{0}{/dev/ttyF0}{IntelliPort II board 0, port 0}
-	\minor{1}{/dev/ttyF1}{IntelliPort II board 0, port 1}
-	\minordots
-	\minor{63}{/dev/ttyF63}{IntelliPort II board 0, port 63}
-	\minor{64}{/dev/ttyF64}{IntelliPort II board 1, port 0}
-	\minor{65}{/dev/ttyF65}{IntelliPort II board 1, port 1}
-	\minordots
-	\minor{127}{/dev/ttyF127}{IntelliPort II board 1, port 63}
-	\minor{128}{/dev/ttyF128}{IntelliPort II board 2, port 0}
-	\minor{129}{/dev/ttyF129}{IntelliPort II board 2, port 1}
-	\minordots
-	\minor{191}{/dev/ttyF191}{IntelliPort II board 2, port 63}
-	\minor{192}{/dev/ttyF192}{IntelliPort II board 3, port 0}
-	\minor{193}{/dev/ttyF193}{IntelliPort II board 3, port 1}
-	\minordots
-	\minor{255}{/dev/ttyF255}{IntelliPort II board 3, port 63}
-\end{devicelist}
-
-\begin{devicelist}
-\major{  }{}{block}{SCSI disk devices (112-127)}
-	\minor{0}{/dev/sddi}{113th SCSI disk whole disk}
-	\minor{16}{/dev/sddj}{114th SCSI disk whole disk}
-	\minor{32}{/dev/sddk}{115th SCSI disk whole disk}
-	\minordots
-	\minor{240}{/dev/sddx}{128th SCSI disk whole disk}
-\end{devicelist}
-
-\noindent
-Partitions are handled in the same way as for IDE disks (see major
-number 3) except that the partition limit is 15 rather than 63 per
-disk.
-
-\begin{devicelist}
-\major{72}{}{char }{Computone IntelliPort II serial card -- alternate devices}
-	\minor{0}{/dev/cuf0}{Callout device corresponding to {\file ttyF0}}
-	\minor{1}{/dev/cuf1}{Callout device corresponding to {\file ttyF1}}
-	\minordots
-	\minor{63}{/dev/cuf63}{Callout device corresponding to {\file ttyF63}}
-	\minor{64}{/dev/cuf64}{Callout device corresponding to {\file ttyF64}}
-	\minor{65}{/dev/cuf65}{Callout device corresponding to {\file ttyF65}}
-	\minordots
-	\minor{127}{/dev/cuf127}{Callout device corresponding to {\file ttyF127}}
-	\minor{128}{/dev/cuf128}{Callout device corresponding to {\file ttyF128}}
-	\minor{129}{/dev/cuf129}{Callout device corresponding to {\file ttyF129}}
-	\minordots
-	\minor{191}{/dev/cuf191}{Callout device corresponding to {\file ttyF191}}
-	\minor{192}{/dev/cuf192}{Callout device corresponding to {\file ttyF192}}
-	\minor{193}{/dev/cuf193}{Callout device corresponding to {\file ttyF193}}
-	\minordots
-	\minor{255}{/dev/cuf255}{Callout device corresponding to {\file ttyF255}}
-\end{devicelist}
-
-\begin{devicelist}
-\major{73}{}{char }{Computone IntelliPort II serial card -- control devices}
-	\minor{0}{/dev/ip2ipl0}{Loadware device for board 0}
-	\minor{1}{/dev/ip2stat0}{Status device for board 0}
-	\minor{4}{/dev/ip2ipl1}{Loadware device for board 1}
-	\minor{5}{/dev/ip2stat1}{Status device for board 1}
-	\minor{8}{/dev/ip2ipl2}{Loadware device for board 2}
-	\minor{9}{/dev/ip2stat2}{Status device for board 2}
-	\minor{12}{/dev/ip2ipl3}{Loadware device for board 3}
-	\minor{13}{/dev/ip2stat3}{Status device for board 3}
-\end{devicelist}
-
-\begin{devicelist}
-\major{74}{}{char }{SCI bridge}
-	\minor{0}{/dev/SCI/0}{SCI device 0}
-	\minor{1}{/dev/SCI/1}{SCI device 1}
-	\minordots
-\end{devicelist}
-
-\noindent
-Currently for Dolphin Interconnect Solutions' PCI-SCI bridge.
-
-\begin{devicelist}
-\major{75}{}{char }{Specialix IO8+ serial card}
-	\minor{0}{/dev/ttyW0}{First IO8+ port, first card}
-	\minor{1}{/dev/ttyW1}{Second IO8+ port, first card}
-	\minordots
-	\minor{8}{/dev/ttyW8}{First IO8+ port, second card}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{76}{}{char }{Specialix IO8+ serial card -- alternate devices}
-	\minor{0}{/dev/cuw0}{Callout device corresponding to {\file ttyW0}}
-	\minor{1}{/dev/cuw1}{Callout device corresponding to {\file ttyW1}}
-	\minordots
-	\minor{8}{/dev/cuw8}{Callout device corresponding to {\file ttyW8}}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{77}{}{char }{ComScire Quantum Noise Generator}
-	\minor{0}{/dev/qng}{ComScire Quantum Noise Generator}
-\end{devicelist}
-
-\begin{devicelist}
-\major{78}{}{char }{PAM Software's multimodem boards}
-	\minor{0}{/dev/ttyM0}{First PAM modem}
-	\minor{1}{/dev/ttyM1}{Second PAM modem}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{79}{}{char }{PAM Software's multimodem boards -- alternate devices}
-	\minor{0}{/dev/cum0}{Callout device corresponding to {\file ttyM0}}
-	\minor{1}{/dev/cum1}{Callout device corresponding to {\file ttyM1}}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{80}{}{char }{Photometrics AT200 CCD camera}
-	\minor{0}{/dev/at200}{Photometrics AT200 CCD camera}
-\end{devicelist}
-
-\begin{devicelist}
-\major{81}{}{char }{video4linux}
-	\minor{0}{/dev/video0}{Video capture/overlay device}
-	\minordots
-	\minor{63}{/dev/video63}{Video capture/overlay device}
-	\minor{64}{/dev/radio0}{Radio device}
-	\minordots
-	\minor{127}{/dev/radio63}{Radio device}
-	\minor{192}{/dev/vtx0}{Teletext device}
-	\minordots
-	\minor{223}{/dev/vtx31}{Teletext device}
-	\minor{224}{/dev/vbi0}{Vertical blank interupt}
-	\minordots
-	\minor{255}{/dev/vbi31}{Vertical blank interupt}
-\end{devicelist}
-
-\begin{devicelist}
-\major{82}{}{char }{WiNRADiO communications receiver card}
-	\minor{0}{/dev/winradio0}{First WiNRADiO card}
-	\minor{1}{/dev/winradio1}{Second WiNRADiO card}
-	\minordots
-\end{devicelist}
-
-\noindent
-The driver and documentation may be obtained from
-{\url http://www.proximity.com.au/~brian/winradio/\/}.
-
-\begin{devicelist}
-\major{83}{}{char }{Teletext/videotext interfaces}
-        \minor{0}{/dev/vtx}{Teletext decoder}
-        \minor{16}{/dev/vttuner}{TV tuner on teletext interface}
-\end{devicelist}
-
-\noindent
-Devices for the driver contained in the VideoteXt package. More information
-on {\url http://home.pages.de/~videotext/\/}.
-
-\begin{devicelist}
-\major{84}{}{char }{Ikon 1011[57] Versatec Greensheet Interface}
-	\minor{0}{/dev/ihcp0}{First Greensheet port}
-	\minor{1}{/dev/ihcp1}{Second Greensheet port}
-\end{devicelist}
-
-\begin{devicelist}
-\major{85}{}{char }{Linux/SGI shared memory input queue}
-	\minor{0}{/dev/shmiq}{Master shared input queue}
-	\minor{1}{/dev/qcntl0}{First device pushed}
-	\minor{2}{/dev/qcntl1}{Second device pushed}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{86}{}{char }{SCSI media changer}
-	\minor{0}{/dev/sch0}{First SCSI media changer}
-	\minor{1}{/dev/sch1}{Second SCSI media changer}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{87}{}{char }{Sony Control-A1 stereo control bus}
-	\minor{0}{/dev/controla0}{First device on chain}
-	\minor{1}{/dev/controla1}{Second device on chain}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{88}{}{char }{COMX synchronous serial card}
-	\minor{0}{/dev/comx0}{Channel 0}
-	\minor{1}{/dev/comx1}{Channel 1}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{89}{}{char }{I$^2$C bus interface}
-	\minor{0}{/dev/i2c0}{First I$^2$C adapter}
-	\minor{1}{/dev/i2c1}{Second I$^2$C adapter}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{90}{}{char }{Memory Technology Device (RAM, ROM, Flash)}
-        \minor{0}{/dev/mtd0}{First MTD (rw)}
-        \minor{1}{/dev/mtdr0}{First MTD (ro)}
-        \minordots
-        \minor{30}{/dev/mtd15}{16th MTD (rw)}
-        \minor{31}{/dev/mtdr15}{16th MTD (ro)}
-\end{devicelist}
-
-\begin{devicelist}
-\major{91}{}{char }{CAN-Bus controller}
-	\minor{0}{/dev/can0}{First CAN-Bus controller}
-	\minor{1}{/dev/can1}{Second CAN-Bus controller}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{92}{}{char }{Reserved for ith Kommunikationstechnik MIC ISDN card}
-\end{devicelist}
-
-\begin{devicelist}
-\major{93}{}{char }{IBM Smart Capture Card frame grabber}
-	\minor{0}{/dev/iscc0}{First Smart Capture Card}
-	\minor{1}{/dev/iscc1}{Second Smart Capture Card}
-	\minordots
-	\minor{128}{/dev/isccctl0}{First Smart Capture Card control}
-	\minor{129}{/dev/isccctl1}{Second Smart Capture Card control}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{94}{}{char }{miroVIDEO DC10/30 capture/playback device}
-	\minor{0}{/dev/dcxx0}{First capture card}
-	\minor{1}{/dev/dcxx1}{Second capture card}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{95}{}{char }{IP filter}
-	\minor{0}{/dev/ipl}{Filter control device/log file}
-	\minor{1}{/dev/ipnat}{NAT control device/log file}
-	\minor{2}{/dev/ipstate}{State information log file}
-	\minor{3}{/dev/ipauth}{Authentication control device/log file}
-\end{devicelist}
-
-\begin{devicelist}
-\major{96}{}{char }{Parallel port ATAPI tape devices}
-	\minor{0}{/dev/pt0}{First parallel port ATAPI tape}
-	\minor{1}{/dev/pt1}{Second parallel port ATAPI tape}
-	\minor{2}{/dev/pt2}{Third parallel port ATAPI tape}
-	\minor{3}{/dev/pt3}{Fourth parallel port ATAPI tape}
-	\minor{128}{/dev/npt0}{First parallel port ATAPI tape, no rewind}
-	\minor{129}{/dev/npt1}{Second parallel port ATAPI tape, no rewind}
-	\minor{130}{/dev/npt2}{Third parallel port ATAPI tape, no rewind}
-	\minor{131}{/dev/npt3}{Fourth parallel port ATAPI tape, no rewind}
-\end{devicelist}
-
-\begin{devicelist}
-\major{97}{}{char }{Parallel port generic ATAPI interface}
-	\minor{0}{/dev/pg0}{First parallel port ATAPI device}
-	\minor{1}{/dev/pg1}{Second parallel port ATAPI device}
-	\minor{2}{/dev/pg2}{Third parallel port ATAPI device}
-	\minor{3}{/dev/pg3}{Fourth parallel port ATAPI device}
-\end{devicelist}
-
-\noindent
-These devices support the same API as the generic SCSI devices.
-
-\begin{devicelist}
-\major{98}{}{char }{Control and Mesurement Device (comedi)}
-	\minor{0}{/dev/comedi0}{First comedi device}
-	\minor{1}{/dev/comedi1}{Second comedi device}
-	\minordots
-\end{devicelist}
-
-\noindent
-See {\url http://stm.lbl.gov/comedi/} or {\url
-http://www.llp.fu-berlin.de/}.
-
-\begin{devicelist}
-\major{99}{}{char }{Raw parallel ports}
-	\minor{0}{/dev/parport0}{First parallel port}
-	\minor{1}{/dev/parport1}{Second parallel port}
-	\minordots
-\end{devicelist}
-
-\noindent
-These devices can be used to drive parallel port devices from
-user-space while interacting with the parport sharing code.
-
-\begin{devicelist}
-\major{100}{}{char }{POTS (analogue telephone) A/B port}
-	\minor{0}{/dev/phone0}{First telephone port}
-	\minor{1}{/dev/phone1}{Second telephone port}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{101}{}{char }{Motorola DSP 56xxx board}
-	\minor{0}{/dev/mdspstat}{Status information}
-	\minor{1}{/dev/mdsp1}{First DSP board I/O and controls}
-	\minordots
-	\minor{16}{/dev/mdsp16}{16th DSP board I/O and controls}
-\end{devicelist}
-
-\begin{devicelist}
-\major{102}{}{char }{Philips SAA5249 Teletext signal decoder}
-	\minor{0}{/dev/tlk0}{First Teletext decoder}
-	\minor{1}{/dev/tlk1}{Second Teletext decoder}
-	\minor{2}{/dev/tlk2}{Third Teletext decoder}
-	\minor{3}{/dev/tlk3}{Fourth Teletext decoder}
-\end{devicelist}
-
-\begin{devicelist}
-\major{103}{}{char }{Arla network file system}
-	\minor{0}{/dev/xfs0}{Arla XFS}
-\end{devicelist}
-
-\noindent
-Arla is a free clone of the Andrew File System, AFS.  Any resemblance
-with the Swedish milk producer is coincidental.  For more information
-about the project, write to $<$arla-drinkers@stacken.kth.se$>$ or
-subscribe to the arla-announce mailing list by sending a mail to
-$<$arla-announce-request@stacken.kth.se$>$.
-
-\begin{devicelist}
-\major{104}{}{char }{Flash BIOS support}
-\end{devicelist}
-
-\begin{devicelist}
-\major{105}{}{char }{Comtrol VS-1000 serial card}
-	\minor{0}{/dev/ttyV0}{First VS-1000 port}
-	\minor{1}{/dev/ttyV1}{Second VS-1000 port}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{106}{}{char }{Comtrol VS-1000 serial card -- alternate devices}
-	\minor{0}{/dev/cuv0}{Callout device corresponding to {\file ttyV0}}
-	\minor{1}{/dev/cuv1}{Callout device corresponding to {\file ttyV1}}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{107}{}{char }{3Dfx Voodoo Graphics device}
-	\minor{0}{/dev/3dfx}{Primary 3Dfx graphics device}
-\end{devicelist}
-
-\begin{devicelist}
-\major{108}{}{char }{Device independent PPP interface}
-	\minor{0}{/dev/ppp}{Device independent PPP interface}
-\end{devicelist}
-
-\begin{devicelist}
-\major{109}{}{char }{Reserved for logical volume manager}
-\end{devicelist}
-
-\begin{devicelist}
-\major{110}{}{char }{miroMEDIA Surround board}
-	\minor{0}{/dev/srnd0}{First miroMEDIA Surround board}
-	\minor{1}{/dev/srnd1}{First miroMEDIA Surround board}
-	\minordots
-\end{devicelist}
-
-\begin{devicelist}
-\major{111}{--119}{}{Unallocated}
-\end{devicelist}
-
-\begin{devicelist}
-\major{120}{--127}{}{Local/experimental use}
-\end{devicelist}
-
-\begin{devicelist}
-\major{128}{--135}{char }{Unix98 PTY masters}
-\end{devicelist}
-
-\noindent
-These devices should not have corresponding device nodes; instead they
-should be accessed through the {\file /dev/ptmx} cloning device.
-
-\begin{devicelist}
-\major{136}{--143}{char }{Unix98 PTY slaves}
-	\minor{0}{/dev/pts/0}{First Unix98 pseudo-TTY}
-	\minor{1}{/dev/pts/1}{Second Unix98 pseudo-TTY}
-	\minordots
-\end{devicelist}
-
-\noindent
-These device nodes are automatically generated with the proper
-permissions and modes by mounting the {\file devpts} filesystem onto
-{\file /dev/pts} with the appropriate mount options (distribution
-dependent.)
-
-\begin{devicelist}
-\major{144}{--239}{}{Unallocated}
-\end{devicelist}
-
-\begin{devicelist}
-\major{240}{--254}{}{Local/experimental use}
-\end{devicelist}
-
-\begin{devicelist}
-\major{255}{}{}{Reserved}
-\end{devicelist}
-
-\noindent
-This major is reserved to assist the expansion to a larger number
-space.  No device nodes with this major should ever be created on any
-filesystem.
-
-\section{Additional /dev directory entries}
-
-This section details additional entries that should or may exist in the
-{\file /dev} directory.  It is preferred that symbolic links use the
-same form (absolute or relative) as is indicated here.  Links are
-classified as {\em hard\/} or {\em symbolic\/} depending on the
-preferred type of link; if possible, the indicated type of link should
-be used.
-
-\subsection{Compulsory links}
-
-These links should exist on all systems:
-
-\begin{nodelist}
-\link{/dev/fd}{/proc/self/fd}{symbolic}{File descriptors}
-\link{/dev/stdin}{fd/0}{symbolic}{Standard input file descriptor}
-\link{/dev/stdout}{fd/1}{symbolic}{Standard output file descriptor}
-\link{/dev/stderr}{fd/2}{symbolic}{Standard error file descriptor}
-\link{/dev/nfsd}{socksys}{symbolic}{Required by iBCS-2}
-\link{/dev/X0R}{null}{symbolic}{Required by iBCS-2}
-\end{nodelist}
-
-\noindent
-Note: The last device is: $<$letter {\tt X}$>$-$<$digit {\tt
-0}$>$-$<$letter {\tt R}$>$.
-
-\subsection{Recommended links}
-
-It is recommended that these links exist on all systems:
-
-\begin{nodelist}
-\link{/dev/core}{/proc/kcore}{symbolic}{Backward compatibility}
-\link{/dev/ramdisk}{ram0}{symbolic}{Backward compatibility}
-\link{/dev/ftape}{qft0}{symbolic}{Backward compatibility}
-\link{/dev/bttv0}{video0}{symbolic}{Backward compatibility}
-\link{/dev/radio}{radio0}{symbolic}{Backward compatibility}
-\link{/dev/scd?}{sr?}{hard}{Alternate name for CD-ROMs}
-\end{nodelist}
-
-\subsection{Locally defined links}
-
-The following links may be established locally to conform to the
-configuration of the system.  This is merely a tabulation of existing
-practice, and does not constitute a recommendation.  However, if they
-exist, they should have the following uses.
-
-\begin{nodelist}
-\vlink{/dev/mouse}{mouse port}{symbolic}{Current mouse device}
-\vlink{/dev/tape}{tape device}{symbolic}{Current tape device}
-\vlink{/dev/cdrom}{CD-ROM device}{symbolic}{Current CD-ROM device}
-\vlink{/dev/cdwriter}{CD-writer}{symbolic}{Current CD-writer device}
-\vlink{/dev/scanner}{scanner device}{symbolic}{Current scanner device}
-\vlink{/dev/modem}{modem port}{symbolic}{Current dialout device}
-\vlink{/dev/root}{root device}{symbolic}{Current root filesystem}
-\vlink{/dev/swap}{swap device}{symbolic}{Current swap device}
-\end{nodelist}
-
-\noindent
-{\file /dev/modem} should not be used for a modem which supports
-dialin as well as dialout, as it tends to cause lock file problems.
-If it exists, {\file /dev/modem} should point to the appropriate
-primary TTY device (the use of the alternate callout devices is
-deprecated.)
-
-For SCSI devices, {\file /dev/tape} and {\file /dev/cdrom} should
-point to the ``cooked'' devices ({\file /dev/st*} and {\file
-/dev/sr*}, respectively), whereas {\file /dev/cdwriter} and {\file
-/dev/scanner} should point to the appropriate generic SCSI devices
-({\file /dev/sg*}).
-
-{\file /dev/mouse} may point to a primary serial TTY device, a
-hardware mouse device, or a socket for a mouse driver program
-(e.g. {\file /dev/gpmdata}).
-
-\subsection{Sockets and pipes}
-
-Non-transient sockets or named pipes may exist in {\file /dev}.
-Common entries are:
-
-\begin{nodelist}
-\node{/dev/printer}{socket}{{\file lpd} local socket}
-\node{/dev/log}{socket}{{\file syslog} local socket}
-\node{/dev/gpmdata}{socket}{{\file gpm} mouse multiplexer}
-\end{nodelist}
-
-\section{Terminal devices}
-
-Terminal, or TTY devices are a special class of character devices.  A
-terminal device is any device that could act as a controlling terminal
-for a session; this includes virtual consoles, serial ports, and
-pseudoterminals (PTYs).
-
-All terminal devices share a common set of capabilities known as line
-diciplines; these include the common terminal line dicipline as well
-as SLIP and PPP modes.
-
-All terminal devices are named similarly; this section explains the
-naming and use of the various types of TTYs.  Note that the naming
-conventions include several historical warts; some of these are
-Linux-specific, some were inherited from other systems, and some
-reflect Linux outgrowing a borrowed convention.
-
-A hash mark ($\#$) in a device name is in all cases used here to
-indicate a decimal number without leading zeroes.
-
-\subsection{Virtual consoles and the console device}
-
-Virtual consoles are full-screen terminal displays on the system video
-monitor.  Virtual consoles are named {\file /dev/tty$\#$}, with
-numbering starting at {\file /dev/tty1}; {\file /dev/tty0} is the
-current virtual console.  {\file /dev/tty0} is the device that should
-be used to access the system video card on those architectures for
-which the frame buffer devices ({\file /dev/fb*}) are not applicable.
-Do not use {\file /dev/console} for this purpose.
-
-The {\em console device\/}, {\file /dev/console}, is the device to
-which system messages should be sent, and on which logins should be
-permitted in single-user mode.  Starting with Linux 2.1.71, {\file
-/dev/console} is managed by the kernel; for previous versions it
-should be a symbolic link to either {\file /dev/tty0}, a specific
-virtual console such as {\file /dev/tty1}, or to a serial port primary
-({\file tty*}, not {\file cu*}) device, depending on the configuration
-of the system.
-
-\subsection{Serial ports}
-
-Serial ports are RS-232 serial ports and any device which simulates
-one, either in hardware (such as internal modems) or in software (such
-as the ISDN driver.)  Under Linux, each serial ports has two device
-names, the primary or callin device and the alternate or callout one.
-Each kind of device is indicated by a different letter.  For any
-letter $X$, the names of the devices are {\file /dev/tty${X\#}$} and
-{\file /dev/cu${x\#}$}, respectively; for historical reasons, {\file
-/dev/ttyS$\#$} and {\file /dev/ttyC$\#$} correspond to {\file
-/dev/cua$\#$} and {\file /dev/cub$\#$}.  In the future, it should be
-expected that multiple letters will be used; all letters will be upper
-case for the {\file tty} device (e.g. {\file /dev/ttyDP$\#$} and lower
-case for the {\file cu} device (e.g. {\file /dev/cudp$\#$}.
-
-The use of the callout devices is deprecated.
-
-The names {\file /dev/ttyQ$\#$} and {\file /dev/cuq$\#$} are reserved
-for local use.
-
-The alternate devices provide for kernel-based exclusion and somewhat
-different defaults than the primary devices.  Their main purpose is to
-allow the use of serial ports with programs with no inherent or broken
-support for serial ports.  Their use is deprecated, and they may be
-removed from a future version of Linux.
-
-Arbitration of serial ports is provided by the use of lock files with
-the names {\file /var/lock/LCK..tty${X\#}$}.  The contents of the lock
-file should be the PID of the locking process as an ASCII number.
-
-It is common practice to install links such as {\file /dev/modem\/}
-which point to serial ports.  In order to ensure proper locking in the
-presence of these links, it is recommended that software chase
-symlinks and lock all possible names; additionally, it is recommended
-that a lock file be installed with the corresponding alternate
-device.  In order to avoid deadlocks, it is recommended that the locks
-are acquired in the following order, and released in the reverse:
-\begin{itemize}
-\item{The symbolic link name, if any ({\file /var/lock/LCK..modem})}
-\item{The {\file tty} name ({\file /var/lock/LCK..ttyS2})}
-\item{The alternate device name ({\file /var/lock/LCK..cua2})}
-\end{itemize}
-In the case of nested symbolic links, the lock files should be
-installed in the order the symlinks are resolved.
-
-Under no circumstances should an application hold a lock while waiting
-for another to be released.  In addition, applications which attempt
-to create lock files for the corresponding alternate device names
-should take into account the possibility of being used on a non-serial
-port TTY, for which no alternate device would exist.
-
-\subsection{Pseudoterminals (PTYs)}
-
-Pseudoterminals, or PTYs, are used to create login sessions or provide
-other capabilities requiring a TTY line dicipline (including SLIP or
-PPP capability) to arbitrary data-generation processes.  Each PTY has
-a {\em master\/} side, named {\file /dev/pty[p-za-e][0-9a-f]\/}, and a
-{\em slave\/} side, named {\file /dev/tty[p-za-e][0-9a-f]\/}.  The
-kernel arbitrates the use of PTYs by allowing each master side to be
-opened only once.
-
-Once the master side has been opened, the corresponding slave device
-can be used in the same manner as any TTY device.  The master and
-slave devices are connected by the kernel, generating the equivalent
-of a bidirectional pipe with TTY capabilities.
-
-Recent versions of the Linux kernels and GNU libc contain support for
-the System V/Unix98 naming scheme for PTYs, which assigns a common
-device {\file /dev/ptmx\/} to all the masters (opening it will
-automatically give you a previously unassigned PTY) and a subdirectory
-{\file /dev/pts\/} for the slaves; the slaves are named with decimal
-integers ({\file /dev/pts/$\#$\/} in our notation).  This removes the
-problem of exhausting the namespace and enables the kernel to
-automatically create the device nodes for the slaves on demand using
-the {\file devpts\/} filesystem.
-
-\end{document}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/devices.txt linux.14p16/Documentation/devices.txt
--- linux.vanilla/Documentation/devices.txt	Wed Dec 16 20:52:00 1998
+++ linux.14p16/Documentation/devices.txt	Fri Dec 17 17:47:28 1999
@@ -1,21 +1,21 @@
+
 		       LINUX ALLOCATED DEVICES
 	     Maintained by H. Peter Anvin <hpa@zytor.com>
 
-		    Last revised: August 10, 1998
+		   Last revised: December 16, 1999
 
 This list is the Linux Device List, the official registry of allocated
 device numbers and /dev directory nodes for the Linux operating
 system.
 
 The latest version of this list is included with the Linux kernel
-sources in LaTeX and ASCII form.  It is also available separately from
-ftp://ftp.kernel.org/pub/linux/docs/device-list/.  In case of
-discrepancy between the text and LaTeX versions, the LaTeX version is
-authoritative.
-
-This document is included by reference into the Linux Filesystem
-Standard (FSSTND).  The FSSTND is available from
-ftp://tsx-11.mit.edu/pub/linux/docs/linux-standards/fsstnd/.
+sources.  It is also available separately from 
+http://www.kernel.org/pub/linux/docs/device-list/ or
+ftp://ftp.kernel.org/pub/linux/docs/device-list/.  The LaTeX version
+of this document is no longer maintained.
+
+This document is included by reference into the Filesystem Hierarchy
+Standard (FHS).  The FHS is available from http://www.pathname.com/fhs/.
 
 Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga
 platform only.	Allocations marked (68k/Atari) apply to Linux/68k on
@@ -33,6 +33,7 @@
 on this list.  Any such information requests will be deleted without
 reply.
 
+
      **** PLEASE READ THIS BEFORE SUBMITTING A DEVICE ENTRY ****
 
 To have a major number allocated, or a minor number in situations
@@ -53,6 +54,13 @@
 found to ensure I have all the requisite information to publish your
 device and avoid conflicts.
 
+Finally, sometimes I have to play "namespace police."  Please don't be
+offended.  I often get submissions for /dev names that would be bound
+to cause conflicts down the road.  I am trying to avoid getting in a
+situation where we would have to suffer an incompatible forward
+change.
+
+
 Your cooperation is appreciated.
 
 
@@ -98,14 +106,14 @@
 		demand.
   
     block	Floppy disks
-		  0 = /dev/fd0		Controller 1, drive 1 autodetect
-		  1 = /dev/fd1		Controller 1, drive 2 autodetect
-		  2 = /dev/fd2		Controller 1, drive 3 autodetect
-		  3 = /dev/fd3		Controller 1, drive 4 autodetect
-		128 = /dev/fd4		Controller 2, drive 1 autodetect
-		129 = /dev/fd5		Controller 2, drive 2 autodetect
-		130 = /dev/fd6		Controller 2, drive 3 autodetect
-		131 = /dev/fd7		Controller 2, drive 4 autodetect
+		  0 = /dev/fd0		Controller 0, drive 0, autodetect
+		  1 = /dev/fd1		Controller 0, drive 1, autodetect
+		  2 = /dev/fd2		Controller 0, drive 2, autodetect
+		  3 = /dev/fd3		Controller 0, drive 3, autodetect
+		128 = /dev/fd4		Controller 1, drive 0, autodetect
+		129 = /dev/fd5		Controller 1, drive 1, autodetect
+		130 = /dev/fd6		Controller 1, drive 2, autodetect
+		131 = /dev/fd7		Controller 1, drive 3, autodetect
 
 		To specify format, add to the autodetect device number:
 		  0 = /dev/fd?		Autodetect format
@@ -183,17 +191,11 @@
 		  0 = /dev/tty0		Current virtual console
 
 		  1 = /dev/tty1		First virtual console
-		      ...
+		    ...
 		 63 = /dev/tty63	63rd virtual console
-		 64 = /dev/ttyS0	First serial port
-		      ...
-		127 = /dev/ttyS63	64th serial port
-		128 = /dev/ptyp0	OBSOLETE
-		      ...
-		191 = /dev/ptysf	OBSOLETE
-		192 = /dev/ttyp0	OBSOLETE
-		      ...
-		255 = /dev/ttysf	OBSOLETE
+		 64 = /dev/ttyS0	First UART serial port
+		    ...
+		255 = /dev/ttyS191	192nd UART serial port
 
 		Older versions of the Linux kernel used this major
 		number for BSD PTY devices.  As of Linux 2.1.115, this
@@ -203,31 +205,31 @@
 		  0 = /dev/tty		Current TTY device
 		  1 = /dev/console	System console
 		  2 = /dev/ptmx		PTY master multiplex
-		 64 = /dev/cua0		Callout device corresponding to ttyS0
-		      ...
-		127 = /dev/cua63	Callout device corresponding to ttyS63
+		 64 = /dev/cua0		Callout device for ttyS0
+		    ...
+		255 = /dev/cua191	Callout device for ttyS191
 
 		(5,1) is /dev/console starting with Linux 2.1.71.  See
 		the section on terminal devices for more information
 		on /dev/console.
 
   6 char	Parallel printer devices
-		  0 = /dev/lp0		First parallel printer (0x3bc)
-		  1 = /dev/lp1		Second parallel printer (0x378)
-		  2 = /dev/lp2		Third parallel printer (0x278)
-
-		Not all computers have the 0x3bc parallel port; hence
-		the "first" printer may be either /dev/lp0 or
-		/dev/lp1.
+		  0 = /dev/lp0		Parallel printer on parport0
+		  1 = /dev/lp1		Parallel printer on parport1
+		    ...
+
+		Current Linux kernels no longer have a fixed mapping
+		between parallel ports and I/O addresses.  Instead,
+		they are redirected through the parport multiplex layer.
 
   7 char	Virtual console capture devices
 		  0 = /dev/vcs		Current vc text contents
 		  1 = /dev/vcs1		tty1 text contents
-		      ...
+		    ...
 		 63 = /dev/vcs63	tty63 text contents
 		128 = /dev/vcsa		Current vc text/attribute contents
 		129 = /dev/vcsa1	tty1 text/attribute contents
-		      ...
+		    ...
 		191 = /dev/vcsa63	tty63 text/attribute contents
 	
 		NOTE: These devices permit both read and write access.
@@ -235,7 +237,7 @@
     block	Loopback devices
 		  0 = /dev/loop0	First loopback device
 		  1 = /dev/loop1	Second loopback device
-		      ...
+		    ...
 
 		The loopback devices are used to mount filesystems not
 		associated with block devices.	The binding to the
@@ -245,7 +247,7 @@
 		  0 = /dev/sda		First SCSI disk whole disk
 		 16 = /dev/sdb		Second SCSI disk whole disk
 		 32 = /dev/sdc		Third SCSI disk whole disk
-		      ...
+		    ...
 		240 = /dev/sdp		Sixteenth SCSI disk whole disk
 
 		Partitions are handled in the same way as for IDE
@@ -255,28 +257,28 @@
   9 char	SCSI tape devices
 		  0 = /dev/st0		First SCSI tape, mode 0
 		  1 = /dev/st1		Second SCSI tape, mode 0
-		      ...
+		    ...
 		 32 = /dev/st0l		First SCSI tape, mode 1
 		 33 = /dev/st1l		Second SCSI tape, mode 1
-		      ...
+		    ...
 		 64 = /dev/st0m		First SCSI tape, mode 2
 		 65 = /dev/st1m		Second SCSI tape, mode 2
-		      ...
+		    ...
 		 96 = /dev/st0a		First SCSI tape, mode 3
 		 97 = /dev/st1a		Second SCSI tape, mode 3
 		      ...
 		128 = /dev/nst0		First SCSI tape, mode 0, no rewind
 		129 = /dev/nst1		Second SCSI tape, mode 0, no rewind
-		      ...
+		    ...
 		160 = /dev/nst0l	First SCSI tape, mode 1, no rewind
 		161 = /dev/nst1l	Second SCSI tape, mode 1, no rewind
-		      ...
+		    ...
 		192 = /dev/nst0m	First SCSI tape, mode 2, no rewind
 		193 = /dev/nst1m	Second SCSI tape, mode 2, no rewind
-		      ...
+		    ...
 		224 = /dev/nst0a	First SCSI tape, mode 3, no rewind
 		225 = /dev/nst1a	Second SCSI tape, mode 3, no rewind
-		      ...
+		    ...
 
 		"No rewind" refers to the omission of the default
 		automatic rewind on device close.  The MTREW or MTOFFL
@@ -286,7 +288,7 @@
     block	Metadisk (RAID) devices
 		  0 = /dev/md0		First metadisk group
 		  1 = /dev/md1		Second metadisk group
-		      ...
+		    ...
 
 		The metadisk driver is used to span a
 		filesystem across multiple physical disks.
@@ -326,6 +328,32 @@
 		151 = /dev/led		Front panel LEDs
 		153 = /dev/mergemem	Memory merge device
 		154 = /dev/pmu		Macintosh PowerBook power manager
+		155 = /dev/isictl	MultiTech ISICom serial control
+		156 = /dev/lcd		Front panel LCD display
+		157 = /dev/ac		Applicom Intl Profibus card
+		158 = /dev/nwbutton	Netwinder external button
+		159 = /dev/nwdebug	Netwinder debug interface
+		160 = /dev/nwflash	Netwinder flash memory
+		161 = /dev/userdma	User-space DMA access
+		162 = /dev/smbus	System Management Bus
+		163 = /dev/lik		Logitech Internet Keyboard
+		164 = /dev/ipmo		Intel Intelligent Platform Management
+		165 = /dev/vmmon	VMWare virtual machine monitor
+		166 = /dev/i2o/ctl	I2O configuration manager
+		167 = /dev/specialix_sxctl Specialix serial control
+		168 = /dev/tcldrv	Technology Concepts serial control
+		169 = /dev/specialix_rioctl Specialix RIO serial control
+		170 = /dev/smapi	IBM Thinkpad SMAPI
+		171 = /dev/srripc	QNX4 API IPC manager
+		172 = /dev/usemaclone	Semaphore clone device
+		173 = /dev/ipmikcs	Intelligent Platform Management
+		174 = /dev/uctrl	SPARCbook 3 microcontroller
+		175 = /dev/agpgart	AGP Graphics Address Remapping Table
+		176 = /dev/gtrsc	Gorgy Timing radio clock
+		177 = /dev/cbm		Serial CBM bus
+		178 = /dev/jsflash	JavaStation OS flash SIMM
+		179 = /dev/xsvc		High-speed shared-mem/semaphore service
+		240-255			Reserved for local use
 
  11 char	Raw keyboard device
 		  0 = /dev/kbd		Raw keyboard device
@@ -335,7 +363,7 @@
     block	SCSI CD-ROM devices
 		  0 = /dev/sr0		First SCSI CD-ROM
 		  1 = /dev/sr1		Second SCSI CD-ROM
-		      ...
+		    ...
 
 		The prefix /dev/scd instead of /dev/sr has been used
 		as well, and might make more sense.
@@ -356,13 +384,17 @@
     block	MSCDEX CD-ROM callback support
 		  0 = /dev/dos_cd0	First MSCDEX CD-ROM
 		  1 = /dev/dos_cd1	Second MSCDEX CD-ROM
-		      ...
+		    ...
 
- 13 char	PC speaker
+ 13 char	PC speaker (OBSOLETE)
 		  0 = /dev/pcmixer	Emulates /dev/mixer
 		  1 = /dev/pcsp		Emulates /dev/dsp (8-bit)
 		  4 = /dev/pcaudio	Emulates /dev/audio
 		  5 = /dev/pcsp16	Emulates /dev/dsp (16-bit)
+
+		The current PC speaker driver uses the Open Sound
+		System interface, and these devices are obsolete.
+
     block	8-bit MFM/RLL/IDE controller
 		  0 = /dev/xda		First XT disk whole disk
 		 64 = /dev/xdb		Second XT disk whole disk
@@ -370,13 +402,14 @@
 		Partitions are handled in the same way as IDE disks
 		(see major number 3).
 
- 14 char	Sound card
+ 14 char	Open Sound System (OSS)
 		  0 = /dev/mixer	Mixer control
 		  1 = /dev/sequencer	Audio sequencer
 		  2 = /dev/midi00	First MIDI port
 		  3 = /dev/dsp		Digital audio
 		  4 = /dev/audio	Sun-compatible digital audio
 		  6 = /dev/sndstat	Sound card status information
+		  7 = /dev/audioctl	SPARC audio control device
 		  8 = /dev/sequencer2	Sequencer -- alternate device
 		 16 = /dev/mixer1	Second soundcard mixer control
 		 17 = /dev/patmgr0	Sequencer patch manager
@@ -413,43 +446,43 @@
  17 char	Chase serial card
 		  0 = /dev/ttyH0	First Chase port
 		  1 = /dev/ttyH1	Second Chase port
-		      ...
+		    ...
     block	Optics Storage CD-ROM
 		  0 = /dev/optcd	Optics Storage CD-ROM
 
  18 char	Chase serial card - alternate devices
-		  0 = /dev/cuh0		Callout device corresponding to ttyH0
-		  1 = /dev/cuh1		Callout device corresponding to ttyH1
-		      ...
+		  0 = /dev/cuh0		Callout device for ttyH0
+		  1 = /dev/cuh1		Callout device for ttyH1
+		    ...
     block	Sanyo CD-ROM
 		  0 = /dev/sjcd		Sanyo CD-ROM
 
  19 char	Cyclades serial card
 		  0 = /dev/ttyC0	First Cyclades port
-		      ...
+		    ...
 		 31 = /dev/ttyC31	32nd Cyclades port
     block	"Double" compressed disk
 		  0 = /dev/double0	First compressed disk
-		      ...
+		    ...
 		  7 = /dev/double7	Eighth compressed disk
 		128 = /dev/cdouble0	Mirror of first compressed disk
-		      ...
+		    ...
 		135 = /dev/cdouble7	Mirror of eighth compressed disk
 
 		See the Double documentation for the meaning of the
 		mirror devices.
 
  20 char	Cyclades serial card - alternate devices
-		  0 = /dev/cub0		Callout device corresponding to ttyC0
-		      ...
-		 31 = /dev/cub31	Callout device corresponding to ttyC31
+		  0 = /dev/cub0		Callout device for ttyC0
+		    ...
+		 31 = /dev/cub31	Callout device for ttyC31
     block	Hitachi CD-ROM (under development)
 		  0 = /dev/hitcd	Hitachi CD-ROM
 
  21 char	Generic SCSI access
 		  0 = /dev/sg0		First generic SCSI device
 		  1 = /dev/sg1		Second generic SCSI device
-		      ...
+		    ...
 
 		Most distributions name these /dev/sga, /dev/sgb...;
 		this sets an unnecessary limit of 26 SCSI devices in
@@ -467,7 +500,7 @@
  22 char	Digiboard serial card
 		  0 = /dev/ttyD0	First Digiboard port
 		  1 = /dev/ttyD1	Second Digiboard port
-		      ...
+		    ...
     block	Second IDE hard disk/CD-ROM interface
 		  0 = /dev/hdc		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdd		Slave: whole disk (or CD-ROM)
@@ -476,8 +509,8 @@
 		interface (see major number 3).
 
  23 char	Digiboard serial card - alternate devices
-		  0 = /dev/cud0		Callout device corresponding to ttyD0
-		  1 = /dev/cud1		Callout device corresponding to ttyD1
+		  0 = /dev/cud0		Callout device for ttyD0
+		  1 = /dev/cud1		Callout device for ttyD1
 		      ...
     block	Mitsumi proprietary CD-ROM
 		  0 = /dev/mcd		Mitsumi CD-ROM
@@ -485,31 +518,31 @@
  24 char	Stallion serial card
 		  0 = /dev/ttyE0	Stallion port 0 card 0
 		  1 = /dev/ttyE1	Stallion port 1 card 0
-		      ...
+		    ...
 		 64 = /dev/ttyE64	Stallion port 0 card 1
 		 65 = /dev/ttyE65	Stallion port 1 card 1
 		      ...
 		128 = /dev/ttyE128	Stallion port 0 card 2
 		129 = /dev/ttyE129	Stallion port 1 card 2
-		      ...
+		    ...
 		192 = /dev/ttyE192	Stallion port 0 card 3
 		193 = /dev/ttyE193	Stallion port 1 card 3
-		      ...
+		    ...
     block	Sony CDU-535 CD-ROM
 		  0 = /dev/cdu535	Sony CDU-535 CD-ROM
 
  25 char	Stallion serial card - alternate devices
-		  0 = /dev/cue0		Callout device corresponding to ttyE0
-		  1 = /dev/cue1		Callout device corresponding to ttyE1
-		      ...
-		 64 = /dev/cue64	Callout device corresponding to ttyE64
-		 65 = /dev/cue65	Callout device corresponding to ttyE65
-		      ...
-		128 = /dev/cue128	Callout device corresponding to ttyE128
-		129 = /dev/cue129	Callout device corresponding to ttyE129
-		      ...
-		192 = /dev/cue192	Callout device corresponding to ttyE192
-		193 = /dev/cue193	Callout device corresponding to ttyE193
+		  0 = /dev/cue0		Callout device for ttyE0
+		  1 = /dev/cue1		Callout device for ttyE1
+		    ...
+		 64 = /dev/cue64	Callout device for ttyE64
+		 65 = /dev/cue65	Callout device for ttyE65
+		    ...
+		128 = /dev/cue128	Callout device for ttyE128
+		129 = /dev/cue129	Callout device for ttyE129
+		    ...
+		192 = /dev/cue192	Callout device for ttyE192
+		193 = /dev/cue193	Callout device for ttyE193
 		      ...
     block	First Matsushita (Panasonic/SoundBlaster) CD-ROM
 		  0 = /dev/sbpcd0	Panasonic CD-ROM controller 0 unit 0
@@ -537,7 +570,7 @@
 		 16 = /dev/zqft0	Unit 0, rewind-on-close, compression
 		 17 = /dev/zqft1	Unit 1, rewind-on-close, compression
 		 18 = /dev/zqft2	Unit 2, rewind-on-close, compression
-		 19 = /dev/zqt3		Unit 3, rewind-on-close, compression
+		 19 = /dev/zqtf3	Unit 3, rewind-on-close, compression
 		 20 = /dev/nzqft0	Unit 0, no rewind-on-close, compression
 		 21 = /dev/nzqft1	Unit 1, no rewind-on-close, compression
 		 22 = /dev/nzqft2	Unit 2, no rewind-on-close, compression
@@ -546,10 +579,10 @@
 		 33 = /dev/rawqft1	Unit 1, rewind-on-close, no file marks
 		 34 = /dev/rawqft2	Unit 2, rewind-on-close, no file marks
 		 35 = /dev/rawqft3	Unit 3, rewind-on-close, no file marks
-		 32 = /dev/nrawqft0	Unit 0, no rewind-on-close, no file marks
-		 33 = /dev/nrawqft1	Unit 1, no rewind-on-close, no file marks
-		 34 = /dev/nrawqft2	Unit 2, no rewind-on-close, no file marks
-		 35 = /dev/nrawqft3	Unit 3, no rewind-on-close, no file marks
+		 36 = /dev/nrawqft0	Unit 0, no rewind-on-close, no file marks
+		 37 = /dev/nrawqft1	Unit 1, no rewind-on-close, no file marks
+		 38 = /dev/nrawqft2	Unit 2, no rewind-on-close, no file marks
+		 39 = /dev/nrawqft3	Unit 3, no rewind-on-close, no file marks
     block	Third Matsushita (Panasonic/SoundBlaster) CD-ROM
 		  0 = /dev/sbpcd8	Panasonic CD-ROM controller 2 unit 0
 		  1 = /dev/sbpcd9	Panasonic CD-ROM controller 2 unit 1
@@ -564,7 +597,7 @@
     char	Atari SLM ACSI laser printer (68k/Atari)
 		  0 = /dev/slm0		First SLM laser printer
 		  1 = /dev/slm1		Second SLM laser printer
-		      ...
+		    ...
     block	Fourth Matsushita (Panasonic/SoundBlaster) CD-ROM
 		  0 = /dev/sbpcd12	Panasonic CD-ROM controller 3 unit 0
 		  1 = /dev/sbpcd13	Panasonic CD-ROM controller 3 unit 1
@@ -574,7 +607,7 @@
 		  0 = /dev/ada		First ACSI disk whole disk
 		 16 = /dev/adb		Second ACSI disk whole disk
 		 32 = /dev/adc		Third ACSI disk whole disk
-		      ...
+		    ...
 		240 = /dev/adp		16th ACSI disk whole disk
 
 		Partitions are handled in the same way as for IDE
@@ -584,8 +617,8 @@
  29 char	Universal frame buffer
 		  0 = /dev/fb0		First frame buffer
 		 32 = /dev/fb1		Second frame buffer
-		      ...
-		240 = /dev/fb7		Eighth frame buffer
+		    ...
+		224 = /dev/fb7		Eighth frame buffer
 
 		All additional minor numbers are reserved.
 
@@ -619,13 +652,13 @@
 		      ...
 		  7 = /dev/rom7		Eighth ROM card (rw)
 		  8 = /dev/rrom0	First ROM card (ro)
-		      ...
+		    ...
 		 15 = /dev/rrom7	Eighth ROM card (ro)
 		 16 = /dev/flash0	First flash memory card (rw)
-		      ...
+		    ...
 		 23 = /dev/flash7	Eighth flash memory card (rw)
 		 24 = /dev/rflash0	First flash memory card (ro)
-		      ...
+		    ...
 		 31 = /dev/rflash7	Eighth flash memory card (ro)
 
 		The read-write (rw) devices support back-caching
@@ -636,14 +669,14 @@
  32 char	Specialix serial card
 		  0 = /dev/ttyX0	First Specialix port
 		  1 = /dev/ttyX1	Second Specialix port
-		      ...
+		    ...
     block	Philips LMS CM-206 CD-ROM
 		  0 = /dev/cm206cd	Philips LMS CM-206 CD-ROM
 
  33 char	Specialix serial card - alternate devices
-		  0 = /dev/cux0		Callout device corresponding to ttyX0
-		  1 = /dev/cux1		Callout device corresponding to ttyX1
-		      ...
+		  0 = /dev/cux0		Callout device for ttyX0
+		  1 = /dev/cux1		Callout device for ttyX1
+		    ...
     block	Third IDE hard disk/CD-ROM interface
 		  0 = /dev/hde		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdf		Slave: whole disk (or CD-ROM)
@@ -656,7 +689,7 @@
 		  1 = /dev/scc1		First Z8530, second port
 		  2 = /dev/scc2		Second Z8530, first port
 		  3 = /dev/scc3		Second Z8530, second port
-		      ...
+		    ...
 
 		In a previous version these devices were named
 		/dev/sc1 for /dev/scc0, /dev/sc2 for /dev/scc1, and so
@@ -688,17 +721,25 @@
  36 char	Netlink support
 		  0 = /dev/route	Routing, device updates, kernel to user
 		  1 = /dev/skip		enSKIP security cache control
+		  3 = /dec/fwmonitor	Firewall packet copies
+		 16 = /dev/tap0		First Ethertap device
+		    ...
+		 31 = /dev/tap15	16th Ethertap device
     block	MCA ESDI hard disk
 		  0 = /dev/eda		First ESDI disk whole disk
 		 64 = /dev/edb		Second ESDI disk whole disk
-		      ...
+		    ...
 
 		Partitions are handled in the same way as IDE disks
 		(see major number 3).
 
  37 char	IDE tape
 		  0 = /dev/ht0		First IDE tape
+		  1 = /dev/ht1		Second IDE tape
+		    ...
 		128 = /dev/nht0		First IDE tape, no rewind-on-close
+		129 = /dev/nht1		Second IDE tape, no rewind-on-close
+		    ...
 
 		Currently, only one IDE tape drive is supported.
 
@@ -708,7 +749,7 @@
  38 char	Myricom PCI Myrinet board
 		  0 = /dev/mlanai0	First Myrinet board
 		  1 = /dev/mlanai1	Second Myrinet board
-		      ...
+		    ...
 
 		This device is used for status query, board control
 		and "user level packet I/O."  This board is also
@@ -719,7 +760,7 @@
  39 char	ML-16P experimental I/O board
 		  0 = /dev/ml16pa-a0	First card, first analog channel
 		  1 = /dev/ml16pa-a1	First card, second analog channel
-		      ...
+		    ...
 		 15 = /dev/ml16pa-a15	First card, 16th analog channel
 		 16 = /dev/ml16pa-d	First card, digital lines
 		 17 = /dev/ml16pa-c0	First card, first counter/timer
@@ -727,7 +768,7 @@
 		 19 = /dev/ml16pa-c2	First card, third counter/timer
 		 32 = /dev/ml16pb-a0	Second card, first analog channel
 		 33 = /dev/ml16pb-a1	Second card, second analog channel
-		      ...
+		    ...
 		 47 = /dev/ml16pb-a15	Second card, 16th analog channel
 		 48 = /dev/ml16pb-d	Second card, digital lines
 		 49 = /dev/ml16pb-c0	Second card, first counter/timer
@@ -771,12 +812,12 @@
 
  43 char	isdn4linux virtual modem
 		  0 = /dev/ttyI0	First virtual modem
-		      ...
+		    ...
 		 63 = /dev/ttyI63	64th virtual modem
     block	Network block devices
 		  0 = /dev/nb0		First network block device
 		  1 = /dev/nb1		Second network block device
-		      ...
+		    ...
 
 		Network Block Device is somehow similar to loopback
 		devices: If you read from it, it sends packet accross
@@ -786,14 +827,14 @@
 		the net, implementing block device in userland etc.
 
  44 char	isdn4linux virtual modem - alternate devices
-		  0 = /dev/cui0		Callout device corresponding to ttyI0
-		      ...
-		 63 = /dev/cui63	Callout device corresponding to ttyI63
+		  0 = /dev/cui0		Callout device for ttyI0
+		    ...
+		 63 = /dev/cui63	Callout device for ttyI63
     block	Flash Translatio Layer (FTL) filesystems
 		  0 = /dev/ftla		FTL on first Memory Technology Device
 		 16 = /dev/ftlb		FTL on second Memory Technology Device
 		 32 = /dev/ftlc		FTL on third Memory Technology Device
-		      ...
+		    ...
 		240 = /dev/ftlp		FTL on 16th Memory Technology Device 
 
 		Partitions are handled in the same way as for IDE
@@ -802,14 +843,14 @@
 
  45 char	isdn4linux ISDN BRI driver
 		  0 = /dev/isdn0	First virtual B channel raw data
-		      ...
+		    ...
 		 63 = /dev/isdn63	64th virtual B channel raw data
 		 64 = /dev/isdnctrl0	First channel control/debug
-		      ...
+		    ...
 		127 = /dev/isdnctrl63	64th channel control/debug
 
 		128 = /dev/ippp0	First SyncPPP device
-		      ...
+		    ...
 		191 = /dev/ippp63	64th SyncPPP device
 
 		255 = /dev/isdninfo	ISDN monitor interface
@@ -826,7 +867,7 @@
  46 char	Comtrol Rocketport serial card
 		  0 = /dev/ttyR0	First Rocketport port
 		  1 = /dev/ttyR1	Second Rocketport port
-		      ...
+		    ...
     block	Parallel port ATAPI CD-ROM devices
 		  0 = /dev/pcd0		First parallel port ATAPI CD-ROM
 		  1 = /dev/pcd1		Second parallel port ATAPI CD-ROM
@@ -834,9 +875,9 @@
 		  3 = /dev/pcd3		Fourth parallel port ATAPI CD-ROM
 
  47 char	Comtrol Rocketport serial card - alternate devices
-		  0 = /dev/cur0		Callout device corresponding to ttyR0
-		  1 = /dev/cur1		Callout device corresponding to ttyR1
-		      ...
+		  0 = /dev/cur0		Callout device for ttyR0
+		  1 = /dev/cur1		Callout device for ttyR1
+		    ...
     block	Parallel port ATAPI disk devices
 		  0 = /dev/pf0		First parallel port ATAPI disk
 		  1 = /dev/pf1		Second parallel port ATAPI disk
@@ -849,13 +890,13 @@
  48 char	SDL RISCom serial card
 		  0 = /dev/ttyL0	First RISCom port
 		  1 = /dev/ttyL1	Second RISCom port
-		      ...
+		    ...
     block	Reserved for Mylex DAC960 PCI RAID controller
 
  49 char	SDL RISCom serial card - alternate devices
-		  0 = /dev/cul0		Callout device corresponding to ttyL0
-		  1 = /dev/cul1		Callout device corresponding to ttyL1
-		      ...
+		  0 = /dev/cul0		Callout device for ttyL0
+		  1 = /dev/cul1		Callout device for ttyL1
+		    ...
     block	Reserved for Mylex DAC960 PCI RAID controller
 
  50 char	Reserved for GLINT
@@ -864,7 +905,7 @@
  51 char	Baycom radio modem
 		  0 = /dev/bc0		First Baycom radio modem
 		  1 = /dev/bc1		Second Baycom radio modem
-		      ...
+		    ...
     block	Reserved for Mylex DAC960 PCI RAID controller
 
  52 char	Spellcaster DataComm/BRI ISDN card
@@ -921,7 +962,7 @@
  57 char	Hayes ESP serial card
 		  0 = /dev/ttyP0	First ESP port
 		  1 = /dev/ttyP1	Second ESP port
-		      ...
+		    ...
 
     block	Sixth IDE hard disk/CD-ROM interface
 		  0 = /dev/hdk		Master: whole disk (or CD-ROM)
@@ -931,14 +972,25 @@
 		interface (see major number 3).
 
  58 char	Hayes ESP serial card - alternate devices
-		  0 = /dev/cup0		Callout device corresponding to ttyP0
-		  1 = /dev/cup1		Callout device corresponding to ttyP1
-		      ...
+		  0 = /dev/cup0		Callout device for ttyP0
+		  1 = /dev/cup1		Callout device for ttyP1
+		    ...
     block	Reserved for logical volume manager
 
  59 char	sf firewall package
 		  0 = /dev/firewall	Communication with sf kernel module
 
+    block	Generic PDA filesystem device
+		  0 = /dev/pda0		First PDA device
+		  1 = /dev/pda1		Second PDA device
+		    ...
+
+		The pda devices are used to mount filesystems on
+		remote pda's (basically slow handheld machines with
+		proprietary OS's and limited memory and storage
+		running small fs translation drivers) through serial /
+		IRDA / parallel links.
+
  60-63		LOCAL/EXPERIMENTAL USE
 		Allocated for local/experimental use.  For devices not
 		assigned official numbers, these ranges should be
@@ -972,7 +1024,7 @@
 		  0 = /dev/sdq		16th SCSI disk whole disk
 		 16 = /dev/sdr		17th SCSI disk whole disk
 		 32 = /dev/sds		18th SCSI disk whole disk
-		      ...
+		    ...
 		240 = /dev/sdaf		32nd SCSI disk whole disk
 
 		Partitions are handled in the same way as for IDE
@@ -982,13 +1034,13 @@
  66 char	YARC PowerPC PCI coprocessor card
 		  0 = /dev/yppcpci0	First YARC card
 		  1 = /dev/yppcpci1	Second YARC card
-		      ...
+		    ...
 
     block	SCSI disk devices (32-47)
 		  0 = /dev/sdag		33th SCSI disk whole disk
 		 16 = /dev/sdah		34th SCSI disk whole disk
 		 32 = /dev/sdai		35th SCSI disk whole disk
-		      ...
+		    ...
 		240 = /dev/sdav		48nd SCSI disk whole disk
 
 		Partitions are handled in the same way as for IDE
@@ -1004,7 +1056,7 @@
 		  0 = /dev/sdaw		49th SCSI disk whole disk
 		 16 = /dev/sdax		50th SCSI disk whole disk
 		 32 = /dev/sday		51st SCSI disk whole disk
-		      ...
+		    ...
 		240 = /dev/sdbl		64th SCSI disk whole disk
 
 		Partitions are handled in the same way as for IDE
@@ -1015,7 +1067,7 @@
 		  0 = /dev/capi20	Control device
 		  1 = /dev/capi20.00	First CAPI 2.0 application
 		  2 = /dev/capi20.01	Second CAPI 2.0 application
-		      ...
+		    ...
 		 20 = /dev/capi20.19	19th CAPI 2.0 application
 
 		ISDN CAPI 2.0 driver for use with CAPI 2.0
@@ -1025,7 +1077,7 @@
 		  0 = /dev/sdbm		64th SCSI disk whole disk
 		 16 = /dev/sdbn		65th SCSI disk whole disk
 		 32 = /dev/sdbo		66th SCSI disk whole disk
-		      ...
+		    ...
 		240 = /dev/sdcb		80th SCSI disk whole disk
 
 		Partitions are handled in the same way as for IDE
@@ -1039,7 +1091,7 @@
 		  0 = /dev/sdcc		81st SCSI disk whole disk
 		 16 = /dev/sdcd		82nd SCSI disk whole disk
 		 32 = /dev/sdce		83th SCSI disk whole disk
-		      ...
+		    ...
 		240 = /dev/sdcr		96th SCSI disk whole disk
 
 		Partitions are handled in the same way as for IDE
@@ -1059,7 +1111,7 @@
 		  0 = /dev/sdcs		97th SCSI disk whole disk
 		 16 = /dev/sdct		98th SCSI disk whole disk
 		 32 = /dev/sdcu		99th SCSI disk whole disk
-		      ...
+		    ...
 		240 = /dev/sddh		112nd SCSI disk whole disk
 
 		Partitions are handled in the same way as for IDE
@@ -1069,26 +1121,26 @@
  71 char	Computone IntelliPort II serial card
 		  0 = /dev/ttyF0	IntelliPort II board 0, port 0
 		  1 = /dev/ttyF1	IntelliPort II board 0, port 1
-		      ...
+		    ...
 		 63 = /dev/ttyF63	IntelliPort II board 0, port 63
 		 64 = /dev/ttyF64	IntelliPort II board 1, port 0
 		 65 = /dev/ttyF65	IntelliPort II board 1, port 1
-		      ...
+		    ...
 		127 = /dev/ttyF127	IntelliPort II board 1, port 63
 		128 = /dev/ttyF128	IntelliPort II board 2, port 0
 		129 = /dev/ttyF129	IntelliPort II board 2, port 1
-		      ...
+		    ...
 		191 = /dev/ttyF191	IntelliPort II board 2, port 63
 		192 = /dev/ttyF192	IntelliPort II board 3, port 0
 		193 = /dev/ttyF193	IntelliPort II board 3, port 1
-		      ...
+		    ...
 		255 = /dev/ttyF255	IntelliPort II board 3, port 63
 
     block	SCSI disk devices (112-127)
 		  0 = /dev/sddi		113th SCSI disk whole disk
 		 16 = /dev/sddj		114th SCSI disk whole disk
 		 32 = /dev/sddk		115th SCSI disk whole disk
-		      ...
+		    ...
 		240 = /dev/sddx		128th SCSI disk whole disk
 
 		Partitions are handled in the same way as for IDE
@@ -1096,22 +1148,22 @@
 		partitions is 15.
 
  72 char	Computone IntelliPort II serial card - alternate devices
-		  0 = /dev/cuf0		Callout device corresponding to ttyF0
-		  1 = /dev/cuf1		Callout device corresponding to ttyF1
-		      ...
-		 63 = /dev/cuf63	Callout device corresponding to ttyF63
-		 64 = /dev/cuf64	Callout device corresponding to ttyF64
-		 65 = /dev/cuf65	Callout device corresponding to ttyF65
-		      ...
-		127 = /dev/cuf127	Callout device corresponding to ttyF127
-		128 = /dev/cuf128	Callout device corresponding to ttyF128
-		129 = /dev/cuf129	Callout device corresponding to ttyF129
-		      ...
-		191 = /dev/cuf191	Callout device corresponding to ttyF191
-		192 = /dev/cuf192	Callout device corresponding to ttyF192
-		193 = /dev/cuf193	Callout device corresponding to ttyF193
-		      ...
-		255 = /dev/cuf255	Callout device corresponding to ttyF255
+		  0 = /dev/cuf0		Callout device for ttyF0
+		  1 = /dev/cuf1		Callout device for ttyF1
+		    ...
+		 63 = /dev/cuf63	Callout device for ttyF63
+		 64 = /dev/cuf64	Callout device for ttyF64
+		 65 = /dev/cuf65	Callout device for ttyF65
+		    ...
+		127 = /dev/cuf127	Callout device for ttyF127
+		128 = /dev/cuf128	Callout device for ttyF128
+		129 = /dev/cuf129	Callout device for ttyF129
+		    ...
+		191 = /dev/cuf191	Callout device for ttyF191
+		192 = /dev/cuf192	Callout device for ttyF192
+		193 = /dev/cuf193	Callout device for ttyF193
+		    ...
+		255 = /dev/cuf255	Callout device for ttyF255
 
  73 char	Computone IntelliPort II serial card - control devices
 		  0 = /dev/ip2ipl0	Loadware device for board 0
@@ -1126,7 +1178,7 @@
  74 char	SCI bridge
 		  0 = /dev/SCI/0	SCI device 0
 		  1 = /dev/SCI/1	SCI device 1
-		      ...
+		    ...
 
 		Currently for Dolphin Interconnect Solutions' PCI-SCI
 		bridge.
@@ -1134,16 +1186,16 @@
  75 char	Specialix IO8+ serial card
 		  0 = /dev/ttyW0	First IO8+ port, first card
 		  1 = /dev/ttyW1	Second IO8+ port, first card
-		      ...
+		    ...
 		  8 = /dev/ttyW8	First IO8+ port, second card
-		      ...
+		    ...
 
  76 char	Specialix IO8+ serial card - alternate devices
-		  0 = /dev/cuw0		Callout device corresponding to ttyW0
-		  1 = /dev/cuw1		Callout device corresponding to ttyW1
-		      ...
-		  8 = /dev/cuw8		Callout device corresponding to ttyW8
-		      ...
+		  0 = /dev/cuw0		Callout device for ttyW0
+		  1 = /dev/cuw1		Callout device for ttyW1
+		    ...
+		  8 = /dev/cuw8		Callout device for ttyW8
+		    ...
 
  77 char	ComScire Quantum Noise Generator
 		  0 = /dev/qng		ComScire Quantum Noise Generator
@@ -1151,38 +1203,68 @@
  78 char	PAM Software's multimodem boards
 		  0 = /dev/ttyM0	First PAM modem
 		  1 = /dev/ttyM1	Second PAM modem
-		      ...
+		    ...
 
  79 char	PAM Software's multimodem boards - alternate devices
-		  0 = /dev/cum0		Callout device corresponding to ttyM0
-		  1 = /dev/cum1		Callout device corresponding to ttyM1
-		      ...
+		  0 = /dev/cum0		Callout device for ttyM0
+		  1 = /dev/cum1		Callout device for ttyM1
+		    ...
 
  80 char	Photometrics AT200 CCD camera
 		  0 = /dev/at200	Photometrics AT200 CCD camera
 
+    block	I2O hard disk
+		  0 = /dev/i2o/hda	First I2O hard disk, whole disk
+		 16 = /dev/i2o/hdb	Second I2O hard disk, whole disk
+		    ...
+		240 = /dev/i2o/hdp	16th I2O hard disk, whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
  81 char	video4linux
 		  0 = /dev/video0	Video capture/overlay device
-		      ...
+		    ...
 		 63 = /dev/video63	Video capture/overlay device
 		 64 = /dev/radio0	Radio device
-		      ...
+		    ...
 		127 = /dev/radio63	Radio device
 		192 = /dev/vtx0		Teletext device
-		      ...
+		    ...
 		223 = /dev/vtx31	Teletext device
 		224 = /dev/vbi0		Vertical blank interrupt
-		      ...
+		    ...
 		255 = /dev/vbi31	Vertical blank interrupt
 
+    block	I2O hard disk
+		  0 = /dev/i2o/hdq	17th I2O hard disk, whole disk
+		 16 = /dev/i2o/hdr	18th I2O hard disk, whole disk
+		    ...
+		240 = /dev/i2o/hdaf	32nd I2O hard disk, whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
  82 char	WiNRADiO communications receiver card
 		  0 = /dev/winradio0	First WiNRADiO card
 		  1 = /dev/winradio1	Second WiNRADiO card
-		      ...
+		    ...
 
 		The driver and documentation may be obtained from
 		http://www.proximity.com.au/~brian/winradio/
 
+    block	I2O hard disk
+		  0 = /dev/i2o/hdag	33rd I2O hard disk, whole disk
+		 16 = /dev/i2o/hdah	34th I2O hard disk, whole disk
+		    ...
+		240 = /dev/i2o/hdav	48th I2O hard disk, whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
  83 char	Teletext/videotext interfaces
 		  0 = /dev/vtx		Teletext decoder
 		 16 = /dev/vttuner	TV tuner on teletext interface
@@ -1190,36 +1272,101 @@
 		Devices for the driver contained in the VideoteXt package.
 		More information on http://home.pages.de/~videotext/
 
+    block	I2O hard disk
+		  0 = /dev/i2o/hdaw	49th I2O hard disk, whole disk
+		 16 = /dev/i2o/hdax	50th I2O hard disk, whole disk
+		    ...
+		240 = /dev/i2o/hdbl	64th I2O hard disk, whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
  84 char	Ikon 1011[57] Versatec Greensheet Interface
 		  0 = /dev/ihcp0	First Greensheet port
 		  1 = /dev/ihcp1	Second Greensheet port
 
+    block	I2O hard disk
+		  0 = /dev/i2o/hdbm	65th I2O hard disk, whole disk
+		 16 = /dev/i2o/hdbn	66th I2O hard disk, whole disk
+		    ...
+		240 = /dev/i2o/hdcb	80th I2O hard disk, whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
  85 char	Linux/SGI shared memory input queue
 		  0 = /dev/shmiq	Master shared input queue
 		  1 = /dev/qcntl0	First device pushed
 		  2 = /dev/qcntl1	Second device pushed
 		    ...
 
+    block	I2O hard disk
+		  0 = /dev/i2o/hdcc	81st I2O hard disk, whole disk
+		 16 = /dev/i2o/hdcd	82nd I2O hard disk, whole disk
+		    ...
+		240 = /dev/i2o/hdcr	96th I2O hard disk, whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
  86 char	SCSI media changer
 		  0 = /dev/sch0		First SCSI media changer
 		  1 = /dev/sch1		Second SCSI media changer
 		    ...
 
+    block	I2O hard disk
+		  0 = /dev/i2o/hdcs	97th I2O hard disk, whole disk
+		 16 = /dev/i2o/hdct	98th I2O hard disk, whole disk
+		    ...
+		240 = /dev/i2o/hddh	112th I2O hard disk, whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
  87 char	Sony Control-A1 stereo control bus
 		  0 = /dev/controla0	First device on chain
 		  1 = /dev/controla1	Second device on chain
 		    ...
 
+    block	I2O hard disk
+		  0 = /dev/i2o/hddi	113rd I2O hard disk, whole disk
+		 16 = /dev/i2o/hddj	114th I2O hard disk, whole disk
+		    ...
+		240 = /dev/i2o/hddx	128th I2O hard disk, whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
  88 char	COMX synchronous serial card
 		  0 = /dev/comx0	COMX channel 0
 		  1 = /dev/comx1	COMX channel 1
 		    ...
 
+    block	Seventh IDE hard disk/CD-ROM interface
+		  0 = /dev/hdm		Master: whole disk (or CD-ROM)
+		 64 = /dev/hdn		Slave: whole disk (or CD-ROM)
+
+		Partitions are handled the same way as for the first
+		interface (see major number 3).
+
+
  89 char	I2C bus interface
 		  0 = /dev/i2c0		First I2C adapter
 		  1 = /dev/i2c1		Second I2C adapter
 		    ...
 
+    block	Eighth IDE hard disk/CD-ROM interface
+		  0 = /dev/hdo		Master: whole disk (or CD-ROM)
+		 64 = /dev/hdp		Slave: whole disk (or CD-ROM)
+
+		Partitions are handled the same way as for the first
+		interface (see major number 3).
+
  90 char	Memory Technology Device (RAM, ROM, Flash)
 		  0 = /dev/mtd0		First MTD (rw)
 		  1 = /dev/mtdr0	First MTD (ro)
@@ -1227,13 +1374,36 @@
 		 30 = /dev/mtd15	16th MTD (rw)
 		 31 = /dev/mtdr15	16th MTD (ro)
 
+    block	Ninth IDE hard disk/CD-ROM interface
+		  0 = /dev/hdq		Master: whole disk (or CD-ROM)
+		 64 = /dev/hdr		Slave: whole disk (or CD-ROM)
+
+		Partitions are handled the same way as for the first
+		interface (see major number 3).
+
  91 char	CAN-Bus devices
 		  0 = /dev/can0		First CAN-Bus controller
 		  1 = /dev/can1		Second CAN-Bus controller
 		    ...
 
+    block	Tenth IDE hard disk/CD-ROM interface
+		  0 = /dev/hds		Master: whole disk (or CD-ROM)
+		 64 = /dev/hdt		Slave: whole disk (or CD-ROM)
+
+		Partitions are handled the same way as for the first
+		interface (see major number 3).
+
  92 char	Reserved for ith Kommunikationstechnik MIC ISDN card
 
+    block	PPDD encrypted disk driver
+		  0 = /dev/ppdd0	First encrypted disk
+		  1 = /dev/ppdd1	Second encrypted disk
+		    ...
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
  93 char	IBM Smart Capture Card frame grabber
 		  0 = /dev/iscc0	First Smart Capture Card
 		  1 = /dev/iscc1	Second Smart Capture Card
@@ -1242,6 +1412,12 @@
 		129 = /dev/isccctl1	Second Smart Capture Card control
 		    ...
 
+    block	NAND Flash Translation Layer filesystem
+		  0 = /dev/nftla	First NFTL layer
+		 16 = /dev/nftlb	Second NFTL layer
+		    ...
+		240 = /dev/nftlp	16th NTFL layer
+
  94 char	miroVIDEO DC10/30 capture/playback device
 		  0 = /dev/dcxx0	First capture card
 		  1 = /dev/dcxx1	Second capture card
@@ -1253,15 +1429,29 @@
 		  2 = /dev/ipstate	State information log file
 		  3 = /dev/ipauth	Authentication control device/log file
 
+    block	IBM S/390 DASD block storage
+		  0 = /dev/dasd0	First DASD device, major
+		  1 = /dev/dasd0a	First DASD device, block 1
+		  2 = /dev/dasd0b	First DASD device, block 2
+		  3 = /dev/dasd0c	First DASD device, block 3
+		  4 = /dev/dasd1	Second DASD device, major
+		  5 = /dev/dasd1a	Second DASD device, block 1
+		  6 = /dev/dasd1b	Second DASD device, block 2
+		  7 = /dev/dasd1c	Second DASD device, block 3
+		    ...		
+
  96 char	Parallel port ATAPI tape devices
 		  0 = /dev/pt0		First parallel port ATAPI tape
 		  1 = /dev/pt1		Second parallel port ATAPI tape
-		  2 = /dev/pt2		Third parallel port ATAPI tape
-		  3 = /dev/pt3		Fourth parallel port ATAPI tape
+		    ...
 		128 = /dev/npt0		First p.p. ATAPI tape, no rewind
 		129 = /dev/npt1		Second p.p. ATAPI tape, no rewind
-		130 = /dev/npt2		Third p.p. ATAPI tape, no rewind
-		131 = /dev/npt3		Fourth p.p. ATAPI tape, no rewind
+		    ...
+
+    block	IBM S/390 VM/ESA minidisk
+		  0 = /dev/msd0		First VM/ESA minidisk
+		  1 = /dev/msd1		Second VM/ESA minidisk
+		    ...
 
  97 char	Parallel port generic ATAPI interface
 		  0 = /dev/pg0		First parallel port ATAPI device
@@ -1336,7 +1526,64 @@
 		  1 = /dev/srnd1	Second miroMEDIA Surround board
 		    ...
 
-111-119		UNALLOCATED
+111 char	Philips SAA7146-based audio/video card
+		  0 = /dev/av0		First A/V card
+		  1 = /dev/av1		Second A/V card
+		    ...
+
+112 char	ISI serial card
+		  0 = /dev/ttyM0	First ISI port
+		  1 = /dev/ttyM1	Second ISI port
+		    ...
+
+		There is currently a device-naming conflict between
+		these and PAM multimodems (major 78).
+
+113 char	ISI serial card - alternate devices
+		  0 = /dev/cum0		Callout device for ttyM0
+		  1 = /dev/cum1		Callout device for ttyM1
+		    ...
+
+114 char	Picture Elements ISE board
+		  0 = /dev/ise0		First ISE board
+		  1 = /dev/ise1		Second ISE board
+		    ...
+		128 = /dev/isex0	Control node for first ISE board
+		129 = /dev/isex1	Control node for second ISE board
+		    ...
+
+		The ISE board is an embedded computer, optimized for
+		image processing. The /dev/iseN nodes are the general
+		I/O access to the board, the /dev/isex0 nodes command
+		nodes used to control the board.
+
+115 char	Console driver speaker
+		  0 = /dev/speaker	Speaker device file
+
+		Plays music using IBM BASIC style strings.
+
+116 char	Advanced Linux System Driver (ALSA)
+
+117 char	COSA/SRP synchronous serial card
+		  0 = /dev/cosa0c0	1st board, 1st channel
+		  1 = /dev/cosa0c1	1st board, 2nd channel
+		    ...
+		 16 = /dev/cosa1c0	2nd board, 1st channel
+		 17 = /dev/cosa1c1	2nd board, 2nd channel
+		    ...
+
+118 char	Solidum ???
+		  0 = /dev/solnp0
+		  1 = /dev/solnp1
+		    ...
+		128 = /dev/solnpctl0
+		129 = /dev/solnpctl1
+		    ...
+
+119 char	VMware virtual network control
+		  0 = /dev/vnet0	1st virtual network
+		  1 = /dev/vnet1	2nd virtual network
+		    ...
 
 120-127		LOCAL/EXPERIMENTAL USE
 
@@ -1349,13 +1596,285 @@
 136-143 char	Unix98 PTY slaves
 		  0 = /dev/pts/0	First Unix98 pseudo-TTY
 		  1 = /dev/pts/1	Second Unix98 pesudo-TTY
+		    ...
 
 		These device nodes are automatically generated with
 		the proper permissions and modes by mounting the
 		devpts filesystem onto /dev/pts with the appropriate
-		mount options (distribution dependent).
+		mount options (distribution dependent, however, on
+		*most* distributions the appropriate options are
+		"mode=0620,gid=<gid of the "tty" group>".)
+
+144 char	Encapsulated PPP
+		  0 = /dev/pppox0	First PPP over Ethernet
+		    ...
+		 63 = /dev/pppox63	64th PPP over Ethernet
+
+		This is primarily used for ADSL.
+
+		The SST 5136-DN DeviceNet interface driver has been
+		relocated to major 183 due to an unfortunate conflict.
+
+145 char	SAM9407-based soundcard
+		  0 = /dev/sam0_mixer
+		  1 = /dev/sam0_sequencer
+		  2 = /dev/sam0_midi00
+		  3 = /dev/sam0_dsp
+		  4 = /dev/sam0_audio
+		  6 = /dev/sam0_sndstat
+		 18 = /dev/sam0_midi01
+		 34 = /dev/sam0_midi02
+		 50 = /dev/sam0_midi03
+		 64 = /dev/sam1_mixer
+		    ...
+		128 = /dev/sam2_mixer
+		    ...
+		192 = /dev/sam3_mixer
+		    ...
+
+		Device functions match OSS, but offer a number of
+		addons, which are sam9407 specific.  OSS can be
+		operated simultaneously, taking care of the codec.
+
+146 char	SYSTRAM SCRAMNet mirrored-memory network
+		  0 = /dev/scramnet0	First SCRAMNet device
+		  1 = /dev/scramnet1	Second SCRAMNet device
+		    ...
+
+147 char	Aueral Semiconductor Vortex Audio device
+		  0 = /dev/aureal0	First Aureal Vortex
+		  1 = /dev/aureal1	Second Aureal Vortex
+		    ...
+
+148 char	Technology Concepts serial card
+		  0 = /dev/ttyT0	First TCL port
+		  1 = /dev/ttyT1	Second TCL port
+		    ...
+
+149 char	Technology Concepts serial card - alternate devices
+		  0 = /dev/cut0		Callout device for ttyT0
+		  1 = /dev/cut0		Callout device for ttyT1
+		    ...
+
+150 char	Real-Time Linux FIFOs
+		  0 = /dev/rtf0		First RTLinux FIFO
+		  1 = /dev/rtf1		Second RTLinux FIFO
+		    ...
+
+151 char	DPT I2O SmartRaid V controller
+		  0 = /dev/dpti0	First DPT I2O adapter
+		  1 = /dev/dpti1	Second DPT I2O adapter
+		    ...
+
+154 char	Specialix RIO serial card
+		  0 = /dev/ttySR0	First RIO port
+		    ...
+		255 = /dev/ttySR255	256th RIO port
+
+155 char	Specialix RIO serial card - alternate devices
+		  0 = /dev/cusr0	Callout device for ttySR0
+		    ...
+		255 = /dev/cusr255	Callout device for ttySR255
+
+156 char	Specialix RIO serial card
+		  0 = /dev/ttySR256	257th RIO port
+		    ...
+		255 = /dev/ttySR511	512th RIO port
+
+157 char	Specialix RIO serial card - alternate devices
+		  0 = /dev/cusr256	Callout device for ttySR256
+		    ...
+		255 = /dev/cusr511	Callout device for ttySR511
+
+158 char	Dialogic GammaLink fax driver
+		  0 = /dev/gfax0	GammaLink channel 0
+		  1 = /dev/gfax1	GammaLink channel 1
+		    ...
+
+159 char	Quicknet Technologies Internet PhoneJack/LineJack
+		  0 = /dev/ixj0		First device
+		  1 = /dev/ixj1		Second device
+		    ...
+
+160 char	General Purpose Instrument Bus (GPIB)
+		  0 = /dev/gpib0	First GPIB bus
+		  1 = /dev/gpib1	Second GPIB bus
+		    ...
+
+161 char	IrCOMM devices (IrDA serial/parallel emulation)
+		  0 = /dev/ircomm0	First IrCOMM device
+		  1 = /dev/ircomm1	Second IrCOMM device
+		    ...
+		 16 = /dev/irlpt0	First IrLPT device
+		 17 = /dev/irlpt1	Second IrLPT device
+		    ...
+
+162 char	Raw block device interface
+		  0 = /dev/raw		Raw I/O control device
+		  1 = /dev/raw1		First raw I/O device
+		  2 = /dev/raw2		Second raw I/O device
+		    ...
+
+163 char	Radio Tech BIM-XXX-RS232 radio modem
+		  0 = /dev/bimrt0	First BIM radio modem
+		  1 = /dev/bimrt1	Second BIM radio modem
+		    ...
+
+164 char	Chase Research AT/PCI-Fast serial card
+		  0 = /dev/ttyCH0	AT/PCI-Fast board 0, port 0
+		    ...
+		 15 = /dev/ttyCH15	AT/PCI-Fast board 0, port 15
+		 16 = /dev/ttyCH16	AT/PCI-Fast board 1, port 0
+		    ...
+		 31 = /dev/ttyCH31	AT/PCI-Fast board 1, port 15
+		 32 = /dev/ttyCH32	AT/PCI-Fast board 2, port 0
+		    ...
+		 47 = /dev/ttyCH47	AT/PCI-Fast board 2, port 15
+		 48 = /dev/ttyCH48	AT/PCI-Fast board 3, port 0
+		    ...
+		 63 = /dev/ttyCH63	AT/PCI-Fast board 3, port 15
+
+165 char	Chase Research AT/PCI-Fast serial card - alternate devices
+		  0 = /dev/cuch0	Callout device corresponding to ttyCH0
+		    ...
+		 63 = /dev/cuch63	Callout device corresponding to ttyCH63
+
+166 char	ACM USB modems
+		  0 = /dev/ttyACM0	First ACM modem
+		  1 = /dev/ttyACM1	Second ACM modem
+		    ...
+
+167 char	ACM USB modems - alternate devices
+		  0 = /dev/cuacm0	Callout device for ttyACM0
+		  1 = /dev/cuacm1	Callout device for ttyACM1
+		    ...
+
+168 char	Eracom CSA7000 PCI encryption adaptor
+		  0 = /dev/ecsa0	First CSA7000
+		  1 = /dev/ecsa1	Second CSA7000
+		    ...
+
+169 char	Eracom CSA8000 PCI encryption adaptor
+		  0 = /dev/ecsa8-0	First CSA8000
+		  1 = /dev/ecsa8-1	Second CSA8000
+		    ...
 
-144-239		UNALLOCATED
+170 char	AMI MegaRAC remote access controller
+		  0 = /dev/megarac0	First MegaRAC card
+		  1 = /dev/megarac1	Second MegaRAC card
+		    ...
+
+171 char	Reserved for IEEE 1394 (Firewire)
+
+
+172 char	Moxa Intellio serial card
+		  0 = /dev/ttyMX0	First Moxa port
+		  1 = /dev/ttyMX1	Second Moxa port
+		    ...
+		127 = /dev/ttyMX127	128th Moxa port
+		128 = /dev/moxactl	Moxa control port
+
+173 char	Moxa Intellio serial card - alternate devices
+		  0 = /dev/cumx0	Callout device for ttyMX0
+		  1 = /dev/cumx1	Callout device for ttyMX1
+		    ...
+		127 = /dev/cumx127	Callout device for ttyMX127
+
+174 char	SmartIO serial card
+		  0 = /dev/ttySI0	First SmartIO port
+		  1 = /dev/ttySI1	Second SmartIO port
+		    ...
+
+175 char	SmartIO serial card - alternate devices
+		  0 = /dev/cusi0	Callout device for ttySI0
+		  1 = /dev/cusi1	Callout device for ttySI1
+		    ...
+
+176 char	nCipher nFast PCI crypto accelerator
+		  0 = /dev/nfastpci0	First nFast PCI device
+		  1 = /dev/nfastpci1	First nFast PCI device
+		    ...
+
+177 char	TI PCILynx memory spaces
+		  0 = /dev/pcilynx/aux0  AUX space of first PCILynx card
+		    ...
+		 15 = /dev/pcilynx/aux15 AUX space of 16th PCILynx card
+		 16 = /dev/pcilynx/rom0  ROM space of first PCILynx card
+		    ...
+		 31 = /dev/pcilynx/rom15 ROM space of 16th PCILynx card
+		 32 = /dev/pcilynx/ram0  RAM space of first PCILynx card
+		    ...
+		 47 = /dev/pcilynx/ram15 RAM space of 16th PCILynx card
+
+178 char	Giganet cLAN1xxx virtual interface adapter
+		  0 = /dev/clanvi0	First cLAN adapter
+		  1 = /dev/clanvi1	Second cLAN adapter
+		    ...
+
+179 char	CCube DVXChip-based PCI products
+		  0 = /dev/dvxirq0	First DVX device
+		  1 = /dev/dvxirq1	Second DVX device
+		    ...
+
+180 char	USB devices
+		  0 = /dev/usb/lp0	First USB printer
+		    ...
+		 15 = /dev/usb/lp15	16th USB printer
+		 16 = /dev/usb/mouse0	First USB mouse
+		    ...
+		 31 = /dev/usb/mouse15	16th USB mouse
+		 32 = /dev/usb/ez0	First USB firmware loader
+		    ...
+		 47 = /dev/usb/ez15	16th USB firmware loader
+		 48 = /dev/usb/scanner0	First USB scanner
+		    ...
+		 63 = /dev/usb/scanner15 16th USB scanner
+
+181 char	Conrad Electronic parallel port radio clocks
+		  0 = /dev/pcfclock0	First Conrad radio clock
+		  1 = /dev/pcfclock1	Second Conrad radio clock
+		    ...
+
+182 char	Picture Elements THR2 binarizer
+		  0 = /dev/pethr0       First THR2 board
+		  1 = /dev/pethr1	Second THR2 board
+		    ...
+
+183 char	SST 5136-DN DeviceNet interface
+		  0 = /dev/ss5136dn0	First DeviceNet interface
+		  1 = /dev/ss5136dn1	Second DeviceNet interface
+		    ...
+
+		This device used to be assigned to major number 144.
+		It had to be moved due to an unfortunate conflict.
+
+184 char	Picture Elements' video simulator/sender
+		  0 = /dev/pevss0	First sender board
+		  1 = /dev/pevss1	Second sender board
+		    ...
+
+185 char	Reserved for InterMezzo high availability file system
+
+186 char	Object-based storage control device
+		  0 = /dev/obd0		First obd control device
+		  1 = /dev/obd1		Second obd control device
+		    ...
+
+		See ftp://ftp.lustre.org/pub/obd for code and information.
+
+187 char	UNALLOCATED
+
+188 char	USB serial converters
+		  0 = /dev/ttyUSB0	First USB serial converter
+		  1 = /dev/ttyUSB1	Second USB serial converter
+		    ...
+
+189 char	USB serial converters - alternate devices
+		  0 = /dev/cuusb0	Callout device corresponding to ttyUSB0
+		  1 = /dev/cuusb1	Callout device corresponding to ttyUSB1
+		    ...
+
+190-239		UNALLOCATED
 
 240-254		LOCAL/EXPERIMENTAL USE
 
@@ -1384,8 +1903,9 @@
 /dev/stderr	fd/2		symbolic	stderr file descriptor
 /dev/nfsd	socksys		symbolic	Required by iBCS-2
 /dev/X0R	null		symbolic	Required by iBCS-2
+/dev/i2o*	/dev/i2o/*	symbolic	Backward compatibility
 
-Note: the last device is <letter X>-<digit 0>-<letter R>.
+Note: /dev/X0R is <letter X>-<digit 0>-<letter R>.
 
 	Recommended links
 
@@ -1543,3 +2063,4 @@
 in our notation).  This removes the problem of exhausting the
 namespace and enables the kernel to automatically create the device
 nodes for the slaves on demand using the "devpts" filesystem.
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/00-INDEX linux.14p16/Documentation/isdn/00-INDEX
--- linux.vanilla/Documentation/isdn/00-INDEX	Thu Apr  2 01:20:56 1998
+++ linux.14p16/Documentation/isdn/00-INDEX	Thu Dec  9 15:34:41 1999
@@ -6,12 +6,18 @@
 	- description of Linklevel and Hardwarelevel ISDN interface.
 README
 	- general info on what you need and what to do for Linux ISDN.
+README.FAQ
+	- general info for FAQ.
 README.audio
 	- info for running audio over ISDN.
+README.fax
+	- info for using Fax over ISDN.
 README.icn
 	- info on the ICN-ISDN-card and its driver.
 README.HiSax
 	- info on the HiSax driver which replaces the old teles.
+README.hfc-pci
+	- info on hfc-pci based cards.
 README.pcbit
 	- info on the PCBIT-D ISDN adapter and driver.
 README.syncppp
@@ -22,8 +28,12 @@
 	- info on driver for AVM-B1 ISDN card.
 README.act2000
 	- info on driver for IBM ACT-2000 card.
+README.eicon
+	- info on driver for Eicon active cards.
 README.concap
 	- info on "CONCAP" ecapsulation protocol interface used for X.25.
+README.diversion
+	- info on module for isdn diversion services.
 README.sc
 	- info on driver for Spellcaster cards.
 README.x25
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/README linux.14p16/Documentation/isdn/README
--- linux.vanilla/Documentation/isdn/README	Wed Oct 20 01:12:32 1999
+++ linux.14p16/Documentation/isdn/README	Thu Dec  9 15:34:40 1999
@@ -11,7 +11,7 @@
   necessary. Those programs and some contributed utilities are available
   at
 
-   ftp.franken.de
+   ftp.isdn4linux.de
 
    /pub/isdn4linux/isdn4k-utils-<VersionNumber>.tar.gz
 
@@ -22,11 +22,11 @@
    reasons, the mailing-list's primary language is german. However mails
    written in english have been welcome all the time.
 
-   to subscribe: write a email to majordomo@hub-wue.franken.de,
+   to subscribe: write a email to majordomo@listserv.isdn4linux.de,
    Subject irrelevant, in the message body:
    subscribe isdn4linux <your_email_address>
 
-   To write to the mailing-list, write to isdn4linux@hub-wue.franken.de
+   To write to the mailing-list, write to isdn4linux@listserv.isdn4linux.de
 
    This mailinglist is bidirectionally gated to the newsgroup
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/README.FAQ linux.14p16/Documentation/isdn/README.FAQ
--- linux.vanilla/Documentation/isdn/README.FAQ	Thu Jan  1 01:00:00 1970
+++ linux.14p16/Documentation/isdn/README.FAQ	Thu Dec  9 15:34:41 1999
@@ -0,0 +1,26 @@
+
+The FAQ for isdn4linux
+======================
+
+Please note that there is a big FAQ available in the isdn4k-utils.
+You find it in:
+ isdn4k-utils/FAQ/i4lfaq.sgml
+
+In case you just want to see the FAQ online, or download the newest version,
+you can have a look at my website:
+http://www.mhessler.de/i4lfaq/ (view + download)
+or:
+http://www.isdn4linux.de/faq/ (view)
+
+As the extension tells, the FAQ is in SGML format, and you can convert it
+into text/html/... format by using the sgml2txt/sgml2html/... tools.
+Alternatively, you can also do a 'configure; make all' in the FAQ directory.
+
+
+Please have a look at the FAQ before posting anything in the Mailinglist,
+or the newsgroup!
+
+
+Matthias Hessler
+hessler@isdn4linux.de
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/README.avmb1 linux.14p16/Documentation/isdn/README.avmb1
--- linux.vanilla/Documentation/isdn/README.avmb1	Sat Aug 14 02:27:12 1999
+++ linux.14p16/Documentation/isdn/README.avmb1	Thu Dec  9 15:34:41 1999
@@ -169,7 +169,7 @@
 
 Questions
 ---------
-Check out the FAQ (ftp.franken.de) or subscribe to the
+Check out the FAQ (ftp.isdn4linux.de) or subscribe to the
 linux-avmb1@calle.in-berlin.de mailing list by sending
 a mail to majordomo@calle.in-berlin.de with
 subscribe linux-avmb1
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/README.eicon linux.14p16/Documentation/isdn/README.eicon
--- linux.vanilla/Documentation/isdn/README.eicon	Sat Aug 14 02:27:12 1999
+++ linux.14p16/Documentation/isdn/README.eicon	Thu Dec  9 15:34:41 1999
@@ -1,6 +1,6 @@
-$Id: README.eicon,v 1.4 1999/07/11 17:17:30 armin Exp $
+$Id: README.eicon,v 1.5 1999/10/11 18:13:25 armin Exp $
 
-(c) 1999 Cytronics & Melware
+(c) 1999 Cytronics & Melware (info@melware.de)
 
 This document describes the eicon driver for the
 Eicon.Diehl active ISDN cards.
@@ -24,17 +24,26 @@
 
 
 Supported Cards
----------------
+===============
 
+Old ISA type
+------------
 - S-Card ISA
 - SX-Card ISA
 - SXn-Card ISA
 - SCOM-Card ISA
 - Quadro-Card ISA
 - S2M-Card ISA
+
+DIVA Server family
+------------------
 - DIVA Server BRI/PCI 2M
 - DIVA Server PRI/PCI 2M (9M 23M 30M)
-  (Only analog modem functions of the DSPs are currently implemented)
+	supported functions of onboard DSPs:
+	- analog modem
+	- fax group 2/3 (Fax Class 2 commands)
+	- DTMF detection
+
 
 ISDN D-Channel Protocols
 ------------------------
@@ -76,6 +85,10 @@
 Details about using the eiconctrl utility are in 'man eiconctrl'
 or will be printed by starting eiconctrl without any parameters.
 
+Thanks to 
+	Deutsche Mailbox Saar-Lor-Lux GmbH
+	for sponsoring and testing fax
+	capabilities with Diva Server cards.
 
 
 Any reports about bugs, errors and even wishes are welcome.
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/README.fax linux.14p16/Documentation/isdn/README.fax
--- linux.vanilla/Documentation/isdn/README.fax	Sat Aug 28 20:00:52 1999
+++ linux.14p16/Documentation/isdn/README.fax	Thu Dec  9 15:34:41 1999
@@ -9,7 +9,7 @@
 
 - You need the commands as dummy, because you are using
   hylafax (with patch) for AVM capi.
-- You want to use the fax capabillities of your isdn-card.
+- You want to use the fax capabilities of your isdn-card.
   (supported cards are listed below)
 
 
@@ -21,8 +21,12 @@
 Supported ISDN-Cards
 --------------------
 
-Eicon DIVA Server BRI/PCI (will be ready soon)
-Eicon DIVA Server PRI/PCI (will be ready soon)
+Eicon DIVA Server BRI/PCI
+	- full support with both B-channels.
+
+Eicon DIVA Server PRI/PCI
+	- full support on amount of B-channels
+		depending on DSPs on board.
 
 
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/README.pcbit linux.14p16/Documentation/isdn/README.pcbit
--- linux.vanilla/Documentation/isdn/README.pcbit	Tue Apr 28 22:22:04 1998
+++ linux.14p16/Documentation/isdn/README.pcbit	Thu Dec  9 15:34:41 1999
@@ -32,7 +32,7 @@
 the manufacturer in order to solve this problem.
 
 Information/hints/help can be obtained in the linux isdn
-mailing list (isdn4linux@hub-wue.franken.de) or directly from me.
+mailing list (isdn4linux@listserv.isdn4linux.de) or directly from me.
 
 regards,
   Pedro.
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/joystick-api.txt linux.14p16/Documentation/joystick-api.txt
--- linux.vanilla/Documentation/joystick-api.txt	Wed Oct 21 16:43:33 1998
+++ linux.14p16/Documentation/joystick-api.txt	Tue Dec 21 00:31:10 1999
@@ -1,7 +1,7 @@
 		      Joystick API Documentation                -*-Text-*-
 
 		       Ragnar Hojland Espinosa
-		     <ragnar@lightside.ddns.org>
+		     <ragnar@lightside.dhis.org>
 
 			      7 Aug 1998
 
@@ -75,7 +75,7 @@
 	...and so on
 
 Hats vary from one joystick type to another. Some can be moved in 8
-directions, some only in 4, however, the driver always reports a hat as two
+directions, some only in 4, The driver, however, always reports a hat as two
 independent axis, even if the hardware doesn't allow independent movement.
 
 
@@ -85,7 +85,7 @@
 For an axis, ``value'' is a signed integer between -32767 and +32767
 representing the position of the joystick along that axis. If you
 don't read a 0 when the joystick is `dead', or if it doesn't span the
-full range, you should recalibrate (with, for example, jscal).
+full range, you should recalibrate it (with, for example, jscal).
 
 For a button, ``value'' for a press button event is 1 and for a release
 button event is 0.
@@ -93,16 +93,16 @@
 Though this
 
 	if (js_event.type == JS_EVENT_BUTTON) {
-	   buttons_state ^= (1 << js_event.number);
+		buttons_state ^= (1 << js_event.number);
 	}
 
 may work well if you handle JS_EVENT_INIT events separately,
 
 	if ((js_event.type & ~JS_EVENT_INIT) == JS_EVENT_BUTTON) {
-	   if (js_event.value)
-	      buttons_state |= (1 << js_event.number);
-	   else
-	      buttons_state &= ~(1 << js_event.number);
+		if (js_event.value)
+	        	buttons_state |= (1 << js_event.number);
+	   	else
+	      		buttons_state &= ~(1 << js_event.number);
 	}
 
 is much safer since it can't lose sync with the driver. As you would
@@ -112,6 +112,7 @@
 
 2.4 js_event.time
 ~~~~~~~~~~~~~~~~~
+
 The time an event was generated is stored in ``js_event.time''. It's a time
 in miliseconds since ... well, since sometime in the past.  This eases the
 task of detecting double clicks, figuring out if movement of axis and button
@@ -144,14 +145,14 @@
 For example,
 
 	while (1) {
-	   while (read (fd, &e, sizeof(struct js_event)) > 0) {
-	      process_event (e);
-	   }
-	   /* EAGAIN is returned when the queue is empty */
-	   if (errno != EAGAIN) {
-	      /* error */
-	   }
-	   /* do something interesting with processed events */
+		while (read (fd, &e, sizeof(struct js_event)) > 0) {
+	        	process_event (e);
+	   	}
+	   	/* EAGAIN is returned when the queue is empty */
+	   	if (errno != EAGAIN) {
+	      		/* error */
+	   	}
+	   	/* do something interesting with processed events */
 	}
 
 One reason for emptying the queue is that if it gets full you'll start
@@ -219,6 +220,7 @@
 	#ifdef JS_VERSION
 	#if JS_VERSION > 0xsomething
 
+
 4.2 JSIOCGNAME
 ~~~~~~~~~~~~~~
 
@@ -232,6 +234,7 @@
 		strncpy(name, "Unknown", sizeof(name));
 	printf("Name: %s\n", name);
 
+
 4.3 JSIOC[SG]CORR
 ~~~~~~~~~~~~~~~~~
 
@@ -266,10 +269,10 @@
 
 	struct JS_DATA_TYPE js;
 	while (1) {
-	   if (read (fd, &js, JS_RETURN) != JS_RETURN) {
-	      /* error */
-	   }
-	   usleep (1000);
+		if (read (fd, &js, JS_RETURN) != JS_RETURN) {
+	      		/* error */
+	   	}
+	   	usleep (1000);
 	}
 
 As you can figure out from the example, the read returns immediately,
@@ -296,8 +299,9 @@
 center, and 255 maximum value.
 
 The v0.8.0.2 driver also had an interface for 'digital joysticks', (now
-called Multisystem joystick in this driver), under /dev/djsX. This driver
+called Multisystem joysticks in this driver), under /dev/djsX. This driver
 doesn't try to be compatible with that interface.
+
 
 6. Final Notes
 ~~~~~~~~~~~~~~
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/joystick-parport.txt linux.14p16/Documentation/joystick-parport.txt
--- linux.vanilla/Documentation/joystick-parport.txt	Wed Dec  2 03:05:05 1998
+++ linux.14p16/Documentation/joystick-parport.txt	Tue Dec 21 00:31:10 1999
@@ -1,6 +1,7 @@
 		  Linux Joystick parport drivers v1.2 BETA
-		  (c) 1998 Vojtech Pavlik <vojtech@ucw.cz>
+	       (c) 1998-1999 Vojtech Pavlik <vojtech@suse.cz>
 	       (c) 1998 Andree Borrmann <a.borrmann@tu-bs.de>
+			     Sponsored by SuSE
 ----------------------------------------------------------------------------
 
 0. Disclaimer
@@ -44,7 +45,8 @@
   The main problem with PC parallel ports is that they don't have +5V power
 source on any of their pins. So, if you want a reliable source of power
 for your pads, use either keyboard or joystick port, and make a pass-through
-cable.
+cable. You can also pull the power directly from the power supply (the red
+wire is +5V).
 
   If you want to use the parallel port only, you can take the power is from
 some data pin. For most gamepad and parport implementations only one pin is
@@ -298,27 +300,29 @@
 
   The PSX controller is supported by the joy-console.c.
 
-Pinout of the PSX controller:
+Pinout of the PSX controller (compatible with DirectPadPro):
 
   +---------+---------+---------+
 9 | o  o  o | o  o  o | o  o  o | 1               parallel
    \________|_________|________/                  port pins
     |  |      |  |  |   |
-    |  |      |  |  |   +-------->  Clock    ---  (1)
-    |  |      |  |  +------------>  Select   ---  (17)
-    |  |      |  +--------------->  Power    ---  (16)
+    |  |      |  |  |   +-------->  Clock    ---  (4)
+    |  |      |  |  +------------>  Select   ---  (3)
+    |  |      |  +--------------->  Power    ---  (5-9)
     |  |      +------------------>  Ground   ---  (18-25)
-    |  +------------------------->  Command  ---  (14)
+    |  +------------------------->  Command  ---  (2)
     +---------------------------->  Data     ---  (10,11,12,13,15) one only...
 
   You may have to add pull up/down resistors. Maybe your pad also won't like
 the 5V (PSX uses 3.7V).
 
-  Currently the driver supports only ONE psx pad and only one type of
-controller: The normal PSX controller. NEGCON support is planned for the
-next release. ANALOG controller may be too (I do not recommend to connect
-the "force feedback"/"rumble pack" version... it (may) use too much
-power...)
+  Currently the driver supports only one psx pad per parallel port, and these
+controllers:
+
+ * Standard PSX Pad
+ * NegCon PSX Pad
+ * Analog PSX Pad (red mode)
+ * Analog PSX Pad (green mode)
 
 2.4 Sega
 ~~~~~~~~
@@ -437,13 +441,15 @@
 	  4  | Multisystem 1-button joystick
 	  5  | Multisystem 2-button joystick
 	  6  | Sony PSX controller
+	  7  | N64 pad
+	  8  | N64 pad with direction pad as buttons (DirectPadPro style)
 
   The exact type of the PSX controller type is autoprobed, so you must have
 your controller plugged in before initializing.
 
   Should you want to use more than one of parallel ports at once, you can
-use js_console_2 and js_db9_3 as additional command line parameters for two
-more parallel ports.
+use js_console_2 and js_console_3 as additional command line parameters for
+two more parallel ports.
 
   Changes:
     v0.1  : First version (SNES only)
@@ -463,6 +469,9 @@
     v0.10 : Fixed PSX buttons 8 and 9
     v0.11V: Switched to EXCL mode
 	    Removed wakeup
+    v0.12V: Added N64 support
+    v0.13V: Updated N64 support
+    v0.14V: Fixed N64 axis/button counts
 
 3.2 joy-db9.c
 ~~~~~~~~~~~~~
@@ -475,6 +484,10 @@
 is connected to (eg. 0x378), or, if you are using the parport driver of 2.1+
 Linux kernels, the number of the parport interface (eg. 0 for parport0).
 
+  Caveat here: This driver only works on bidirectional parallel ports. If
+your parallel port is recent enough, you should have no trouble with this.
+Old parallel ports may not have this feature.
+
   'Type' is the type of joystick or pad attached:
 
 	Type | Joystick/Pad
@@ -484,9 +497,10 @@
 	  2  | Multisystem 2-button joystick
 	  3  | Genesis pad (3+1 buttons)
 	  5  | Genesis pad (5+1 buttons)
-	  6  | Genesis pad (6+1 buttons)
-	  7  | Saturn pad
+	  6  | Genesis pad (6+2 buttons)
+	  7  | Saturn pad (8 buttons)
 	  8  | Multisystem 1-button joystick (v0.8.0.2 pin-out)
+	  9  | Two Multiststem 1-button joysticks (v0.8.0.2 pin-out) 
 
   Should you want to use more than one of these joysticks/pads at once, you
 can use js_db9_2 and js_db9_3 as additional command line parameters for two
@@ -501,6 +515,8 @@
     v0.4V: Switched to EXCL mode
            Removed wakeup
     v0.5V: Added 0.8.0.2 HW compatibility for Multi sticks
+    v0.6V: Better timing for Genesis 6
+    v0.7V: Added 0.8.0.2 second joystick support
 
 3.3 joy-turbografx.c
 ~~~~~~~~~~~~~~~~~~~~
@@ -519,6 +535,27 @@
 use js_tg_2 and js_tg_3 as additional command line parameters for two more
 interfaces.
 
-3.4 End
+3.4 PC parallel port pinout
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		  .----------------------------------------.
+   At the PC:     \ 13 12 11 10  9  8  7  6  5  4  3  2  1 /
+                   \  25 24 23 22 21 20 19 18 17 16 15 14 /
+                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	  Pin | Name    | Description
+	~~~~~~|~~~~~~~~~|~~~~~~~~~~
+	    1 | /STROBE | Strobe
+	  2-9 | D0-D7   | Data Bit 0-7
+	   10 | /ACK    | Acknowledge
+	   11 | BUSY    | Busy
+	   12 | PE      | Paper End
+	   13 | SELIN   | Select In
+	   14 | /AUTOFD | Autofeed
+	   15 | /ERROR  | Error
+	   16 | /INIT   | Initialize
+	   17 | /SEL    | Select
+	18-25 | GND     | Signal Ground
+
+3.5 End
 ~~~~~~~
   That's all, folks! Have fun!
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/joystick.txt linux.14p16/Documentation/joystick.txt
--- linux.vanilla/Documentation/joystick.txt	Wed Dec  2 03:05:05 1998
+++ linux.14p16/Documentation/joystick.txt	Tue Dec 21 00:31:10 1999
@@ -1,5 +1,6 @@
-		     Linux Joystick driver v1.2.13
-	       (c) 1996-1998 Vojtech Pavlik <vojtech@ucw.cz>
+		       Linux Joystick driver v1.2.15
+	       (c) 1996-1999 Vojtech Pavlik <vojtech@suse.cz>
+			     Sponsored by SuSE
 ----------------------------------------------------------------------------
 
 0. Disclaimer
@@ -19,7 +20,7 @@
 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
   Should you need to contact me, the author, you can do so either by e-mail
-- mail your message to <vojtech@ucw.cz>, or by paper mail: Vojtech Pavlik,
+- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
 Ucitelska 1576, Prague 8, 182 00 Czech Republic
 
   For your convenience, the GNU General Public License version 2 is included
@@ -38,18 +39,18 @@
 
   In addition to these it also supports some of the new PC joysticks that
 use proprietary digital protocols to communicate over the gameport,
-currently by FPGaming, Genius, Gravis, Logitech, MadCatz, Microsoft and
-ThrustMaster. Creative Labs protocol support is still to be done.
+currently by FPGaming, Gravis, Logitech, MadCatz, Microsoft, Creative and
+ThrustMaster. Saitek protocol support is still to be done.
 
   The driver also includes support for many gamepads and joysticks that were
 used by various non-PC computers and game consoles. These include Multi
 system joysticks (Atari, Amiga, Commodore, Amstrad), Sega gamepads (Master
-System, Genesis, Saturn), Nintendo gamepads (NES, SNES), Sony gamepads (PSX).
-Support for N64, Atari Jaguar, Atari 2600, NES FourScore, SNES MultiTap,
-PSX NegCon and others might be added later.
+System, Genesis, Saturn), Nintendo gamepads (NES, SNES, N64), Sony gamepads
+(PSX).  Support for Atari Jaguar, Atari 2600, NES FourScore, SNES MultiTap
+and others might be added later.
 
   Last, but not least there is also native Amiga joystick support for the
-Amiga linux port.
+Amiga Linux port.
 
   Should you encounter any problems while using the driver, or joysticks
 this driver can't make complete use of, I'm very interested in hearing about
@@ -57,21 +58,16 @@
 
   The joystick package is available at the following FTP sites:
 
+	ftp://ftp.suse.cz/pub/development/joystick/
 	ftp://atrey.karlin.mff.cuni.cz/pub/linux/joystick/
-	ftp://artax.karlin.mff.cuni.cz/pub/linux/joystick/
-
-  The joystick driver is also included in the Linux 2.1 kernels:
-
-	ftp://linux.kernel.org/pub/linux/kernel/v2.1/
+	ftp://ftp.gts.cz/pub/linux/joystick/
 
   And a homepage of the driver is at:
 
+	http://www.suse.cz/development/joystick/
 	http://atrey.karlin.mff.cuni.cz/~vojtech/joystick/
-	http://artax.karlin.mff.cuni.cz/~vojtech/joystick/
-
-  A mirror of the homepage is at:
-
 	http://www.trylinux.com/projects/joystick/
+	http://www.linuxgames.com/joystick/
 
   There is also a mailing list for the driver at:
 
@@ -92,7 +88,21 @@
   To compile the utilities in the joystick package, and the driver itself,
 as a standalone module, you first unpack the package, and then edit the
 Makefile to meet your needs (namely whether are you using versioned
-modules). Then you compile it
+modules). You will also need an unpacked and configured
+
+	make config
+
+kernel in
+	
+	/usr/src/linux
+
+Furthermore, if you're using versioned modules, you'll also need
+
+	make dep
+
+done on the kernel, to create some needed files.
+
+After that, you compile the joystick driver
 
 	make
 
@@ -163,6 +173,14 @@
   where 'something' is the type of your joystick. See below for more precise
 explanation.
 
+  Alternately you can add the lines
+
+	alias char-major-15 joy-something
+	options joy-something js_xx=x,x,x,x,...
+
+  to the /etc/conf.modules file, so that the joystick module will be loaded
+automatically when the /dev/js devices are accessed.
+
 2.5 Verifying that it works
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
   For testing the joystick driver functionality, there is the jstest
@@ -197,14 +215,14 @@
 calibration using the jstest command, and if you do, you then can save the
 correction coefficients into a file
 
-	jscal -s /dev/js0 > /etc/joystick.cal
+	jscal -p /dev/js0 > /etc/joystick.cal
 
   And add a line to your rc script executing that file
 
 	source /etc/joystick.cal
 
   This way, after the next reboot your joystick will remain calibrated. You
-can also add the jscal -s line to your shutdown script.
+can also add the jscal -p line to your shutdown script.
 
 
 3. HW specific driver information
@@ -222,7 +240,7 @@
 
 * 2-axis, 4-button joystick
 * 3-axis, 4-button joystick
-* Two 2-axis, 2-button joysticks on an Y-cable
+* 4-axis, 4-button joystick
 
   For other joystick types (more/less axes, hats, and buttons) support
 you'll need to specify the types either on the kernel command line or on the
@@ -261,6 +279,8 @@
 
 	Joystick				| 'm' value
 	----------------------------------------------------
+	Simple 2-button 2-axis joystick		| 0x0033
+	Second simple joystick on Y-cable	| 0x00cc
 	Genius Flight2000 F-12			| 0x00f3
 	Genius Flight2000 F-21			| 0x08f7
 	Genius Flight2000 F-22			| 0x02ff
@@ -268,9 +288,11 @@
 	Genius MaxFire G-07			| 0xf0f3   
 	Genius PowerStation			| 0xf0f3
 	Laing #1 PC SuperPad			| 0xf0f3
+	Logitech Wingman			| 0x003b
 	Microsoft SideWinder Standard		| 0x003b
 	QuickShot QS-201 SuperWarrior		| 0x00fb
 	Saitek Megapad XII			| 0x30f3
+	PC Powerpad Pro				| 0x30f3
 
   In case you have one of the joystick in the table below, and it doesn't
 work with a specific driver in digital mode for some reason, you can use
@@ -280,8 +302,7 @@
 	Joystick				| 'm' value
 	----------------------------------------------------
 	Gravis GamePad Pro - analog mode	| 0x00f3
-	Genius Flight2000 F-23 - CHF mode	| 0x02ff
-	Genius Flight2000 F-23 - FCS mode	| 0x08f7
+	Genius Flight2000 F-23			| 0x02ff
 	Microsoft SideWinder 3D Pro - CHF mode	| 0x02ff
 	Microsoft SideWinder 3D Pro - FCS mode	| 0x08f7
 
@@ -302,70 +323,85 @@
   And it would do the same as the above explained command line. Use
 whichever way you like best.
 
-3.2 Microsoft SideWinder and Genius Digital joysticks
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  SideWinder and Genius Digital joysticks are supported by the
+3.2 Microsoft SideWinder joysticks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  Microsoft 'Digital Overdrive' protocol is supported by the
 joy-sidewinder.c module. All currently supported joysticks:
 
-* SideWinder 3d Pro
-* SideWinder Precision Pro 
+* SideWinder 3D Pro
 * SideWinder Force Feedback Pro
-* SideWinder Game Pad (up to four, chained together)
-* Genius Flight2000 Digital F-23
+* SideWinder Force Feedback Wheel
+* SideWinder FreeStyle Pro
+* SideWinder GamePad (up to four, chained together)
+* SideWinder Precision Pro 
 
   are autodetected, and thus no module parameters are needed.
 
+  There is one caveat with the 3D Pro. There are 9 buttons reported,
+although the joystick has only 8. The 9th button is the mode switch on the
+rear side of the joystick. However, moving it, you'll reset the joystick,
+and make it unresponsive for about a one third of a second. Furthermore, the
+joystick will also re-center itself, taking the position it was in during
+this time as a new center position. Use it if you want, but think first.
+
   The SideWinder Standard is not a digital joystick, and thus is supported
-by the analog driver described above. SideWinder FreeStyle Pro and
-SideWinder Force Feedback Wheel are not supported yet.
+by the analog driver described above. 
 
-3.3 Logitech Digital joysticks
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  Logitech Digital joysticks are supported by the joy-logitech.c module. It
-currently supports these devices:
+3.3 Logitech ADI devices
+~~~~~~~~~~~~~~~~~~~~~~~~
+  Logitech ADI protocol is supported by the joy-logitech.c module. It should
+support any Logitech device using this protocol. This includes, but is not
+limited to:
 
-* Logitech Wingman Extreme Digital
 * Logitech CyberMan 2
 * Logitech ThunderPad Digital
-
-  All three are autodetected, and thus no parameters to the module are
-needed.
-
-  Logitech Wingman is not a digital joystick and is handled by the analog
-driver described above. Logitech Wingman Warrior communicates through a
-serial port and is not supported yet. Logitech Wingman Force, Wingman
-Formula, Wingman Formula Force, Wingman Gamepad, Wingman Interceptor are USB
-joysticks, with optional serial port connection, and are not supported yet.
+* Logitech WingMan Extreme Digital
+* Logitech WingMan Formula
+* Logitech WingMan Interceptor
+* Logitech WingMan GamePad
+* Logitech WingMan GamePad USB
+* Logitech WingMan GamePad Extreme
+* Logitech WingMan Extreme Digital 3D
+
+  ADI devices are autodetected, and the driver supports up to two (any
+combination of) devices on a single gameport, using an Y-cable or chained
+together.
+
+  Logitech WingMan Joystick, Logitech WingMan Attack, Logitech WingMan
+Extreme and Logitech WingMan ThunderPad are not digital joysticks and are
+handled by the analog driver described above. Logitech WingMan Warrior and
+Logitech Magellan are supported by serial drivers described below. Logitech
+CyberMan, Logitech WingMan Force and Logitech WingMan Formula Force are not
+supported yet.
 
 3.4 Gravis GrIP
 ~~~~~~~~~~~~~~~
-  Gravis GrIP gamepads are supported by the joy-gravis.c module. It
+  Gravis GrIP protocol is supported by the joy-gravis.c module. It
 currently supports:
 
 * Gravis GamePad Pro
 * Gravis Xterminator
-* Gravis Blackhawk Digital
+* Gravis BlackHawk Digital
 
-  All these pads are autodetected, and you can even use any combination of
-up to two of these pads either chained together or using an Y-cable on a single
-gameport.
-
-GrIP MultiPort support is in the works. Gravis Xcalibur, ArcadeXtreme,
-GamePad Pro/M are joysticks/pads that probably never reached mass
-production. Gravis Stinger is a serial device and hopefully will be
-supported in the future.
+  All these devices are autodetected, and you can even use any combination
+of up to two of these pads either chained together or using an Y-cable on a
+single gameport.
+
+GrIP MultiPort and Gravis Xterminator DualControl aren't supported yet.
+Gravis Stinger is a serial device and hopefully will be supported in the
+future. Other Gravis joysticks are supported by the joy-analog driver.
 
 3.5 FPGaming A3D and MadCatz A3D
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  The Assasin 3D protocol created by FPGaming, is used both by FPGaming
+  The Assassin 3D protocol created by FPGaming, is used both by FPGaming
 themselves and is licensed to MadCatz. A3D devices are supported by the
-joy-assasin.c module. It currently supports:
+joy-assassin.c module. It currently supports:
 
-* FPGaming Assasin 3D
+* FPGaming Assassin 3D
 * MadCatz Panther
 * MadCatz Panther XL
 
-  All these devices are autodetected. Because the Assasin 3D and the Panther
+  All these devices are autodetected. Because the Assassin 3D and the Panther
 allow connecting analog joysticks to them, these are supported in this
 driver, too. The driver uses the js_as parameter for the analog joysticks,
 which has the same syntax as js_an for the analog driver.
@@ -376,20 +412,33 @@
 3.6 ThrustMaster DirectConnect (BSP)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   The TM DirectConnect (BSP) protocol is supported by the joy-thrustmaster.c
-module. It currently supports:
+module. This includes, but is not limited to:
 
 * ThrustMaster Millenium 3D Inceptor
 * ThrustMaster 3D Rage Pad
+* ThrustMaster Fusion Digital Game Pad
 
-  Both these drvices are autodetected, and thus no parameters to the module
+  Devices not directly supported, but hopefully working are:
+
+* ThrustMaster FragMaster
+* ThrustMaster Attack Throttle
+
+  If you have one of these, contact me.
+
+  BSP devices are autodetected, and thus no parameters to the module
 are needed.
 
-  The Millenium and Rage Pad should work fine now. TM WCS III won't work,
-because important parts of code for that are missing. I'm not sure if it was
-ever mass produced.
+3.7 Creative Labs Blaster
+~~~~~~~~~~~~~~~~~~~~~~~~~
+  The Blaster protocol is supported by the joy-creative.c module. It
+currently supports only the:
+
+* Creative Blaster GamePad Cobra
+
+  Up to two of these can be used on a single gameport, using an Y-cable.
 
-3.7 PDPI Lightning 4 gamecards
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+3.8 PDPI Lightning 4 gamecards
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   PDPI Lightning 4 gamecards are supported by the joy-lightning.c module.
 This driver is only for analog joysticks connected to the card - if you want
 to use some of the digital devices, you need to use its specific driver. The
@@ -420,8 +469,49 @@
   See the description of analog joystick driver for explanations of m0 and
 n0 values.
 
-3.8 Amiga
-~~~~~~~~~
+3.9 Trident 4DWave / Aureal Vortex
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  Soundcards with a Trident 4DWave DX/NX or Aureal Vortex chipset provide an
+"Enhanced Game Port" mode where the soundcard handles polling the joystick.
+This mode is supported by the joy-pci module.
+
+  If no module parameters are given, the joy-pci module will set all the
+soundcards it finds to "enhanced" mode, and will try to autodetect the type
+of attached joystick. It can only detect the same types of joysticks that
+the joy-analog module can.
+
+  This module accepts parameters in the form:
+
+	js_pci=t0,i0,m0,n0,t1,i1,m1,n1,....
+
+  The "t" value specifies the type of card, as follows:
+
+	  t  | Card Type
+	----------------------------
+	  0  | Trident 4DWave DX
+	  1  | Trident 4DWave NX
+	  2  | Aureal Vortex1 (Au8820 chipset)
+	  3  | Aureal Vortex2 (Au8830 chipset)
+
+  If you have more than one card of the same type, the "i" parameter lets
+you choose which card to apply the "m" and "n" values to. It counts from
+"0". (The driver detects cards in the order listed in the above table.)
+
+  The "m" and "n" values have the same meaning as for the analog module,
+with the exception that the value m=0, n=0 indicates that joy-pci should
+completely ignore that port. This can be useful to reserve a certain port
+for purely MIDI operation.
+
+  For example, let's say you have 3 sound cards - a 4Dwave DX, a 4DWave NX,
+and a Vortex 2. You have a three-axis, four-button, one-hat CHF- compatible
+joystick on the DX. You use the NX to interface to an external MIDI device.
+Finally, you have two two-axis, two-button joysticks on the Vortex. Your
+command line might look like:
+
+	js_pci=0,0,0x207,0,1,1,0,0,3,0,0x33,0xcc
+
+3.10 Amiga
+~~~~~~~~~~
   Amiga joysticks, connected to an Amiga, are supported by the joy-amiga.c
 driver. Since they can't be autodetected, the driver has a command line.
 
@@ -438,10 +528,75 @@
   No more joystick types are supported now, but that should change in the
 future if I get an Amiga in the reach of my fingers.
 
-3.9 Game console and 8-bit pads and joysticks
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+3.11 Game console and 8-bit pads and joysticks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 See joystick-parport.txt for more info.
 
+3.12 SpaceTec/LabTec devices
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  SpaceTec serial devices communicate using the SpaceWare protocol. It is
+supported by the joy-spaceorb and joy-spaceball drivers. The devices currently
+supported by joy-spaceorb are:
+
+* SpaceTec SpaceBall Avenger
+* SpaceTec SpaceOrb 360
+
+Devices currently supported by joy-spaceball are:
+
+* SpaceTec SpaceBall 4000 FLX
+
+  In addition to having the joy-spaceorb/spaceball module in the kernel, you
+also need to attach a serial port to it. to do that, run the jsattach
+program:
+
+	jsattach --spaceorb /dev/ttySx &
+or
+	jsattach --sball4 /dev/ttySx &
+
+where /dev/ttySx is the serial port which the device is connected to. After
+doing this, the device will be reported and will start working.
+
+  There is one caveat with the SpaceOrb. The button #6, the on the bottom
+side of the orb, although reported as an ordinary button, causes internal
+recentering of the spaceorb, moving the zero point to the position in which
+the ball is at the moment of pressing the button. So, think first before
+you bind it to some other function.
+
+SpaceTec SpaceBall 2003 FLX and 3003 FLX are not supported yet. 
+
+3.13 Logitech SWIFT devices
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  The SWIFT serial protocol is supported by the joy-warrior module. It
+currently supports only the:
+
+* Logitech WingMan Warrior
+
+but in the future, Logitech CyberMan (the original one, not CM2) could be
+supported as well. To use the module, you need to run jsattach after you
+insert/compile the module into your kernel:
+
+	jsattach --warrior /dev/ttySx &
+
+ttySx is the serial port your Warrior is attached to.
+
+3.14 Magellan / Space Mouse
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  The Magellan (or Space Mouse), manufactured by LogiCad3d (formerly Space
+Systems), for many other companies (Logitech, HP, ...) is supported by the
+joy-magellan module. It currently supports only the:
+
+* Magellan 3D
+* Space Mouse
+
+models, the additional buttons on the 'Plus' versions are not supported yet.
+
+  To use it, you need to attach the serial port to the driver using the
+
+	jsattach --magellan /dev/ttySx &
+
+command. After that the Magellan will be detected, initialized, will beep,
+and the /dev/jsX device should become useable.
+
 4. Troubleshooting
 ~~~~~~~~~~~~~~~~~~
   There is quite a high probability that you run into some problems. For
@@ -452,9 +607,10 @@
 	jstest --normal /dev/js0
 	jstest --old    /dev/js0
 
-  If your trouble stems from the fact the drivers can't detect the attached
-joystick, and/or you decide you need my help (which I will gladly provide),
-please use the joydump utility first. It's created just by typing
+  If your trouble stems from the fact the drivers can't detect the joystick
+attached to your gameport, and you decide you need my help (which I will
+gladly provide), please use the joydump utility first. It's created just by
+typing
 
 	make joydump.o
 
@@ -465,64 +621,73 @@
 
   in the same directory. It will return a 'device busy' or 'initialization
 failed' error. This is perfectly okay. It has already done it's job. The
-results can be found in the system log. Please send me the results along
-with your problem report.
+results can be found in the system log or in the output of the
+
+	dmesg
+
+command. Please send me the results along with your problem report.
 
   Oh, and read the FAQ! :)
 
 5. FAQ
 ~~~~~~
- Q: The driver doesn't find any joysticks connected to my soundcard with the
-message "joy-something: no joysticks found" and "joy-something.o:
-init_module: Device or resource busy." or "Initialization of joy-something
-failed"  What could be the cause?
-  A: The most common cause is that the joystick port on your soundcard is
-not enabled. If it is an ISA PnP card, you'll need isapnptools to configure
-the gameport. Non-PnP cards usually use some option to the sound driver -
-see the sound driver docs and source and enable the port.
-
-  Q: Any access to the joystick devices gives me "Operation not supported by
-device". What am I doing wrong?
-  A: You're running a 2.0 kernel and you forgot to insmod the hardware
-specific module. You not only need the joystick.o, but also one of the other
-joy-*.o files (most usually joy-analog.o), as described in this document,
-section 2. If you are not using modules, then you didn't say 'Y' to any of
-the hardware-specific questions. Again, see section 2. If you did select
-the specific support, and you still get this message, check that you
-selected the right one, and if it still doesn't work, go to the previous
-FAQ.
-
-  Q: Everything is fine, except I get "No such device" error when I try to
-do anything with /dev/js0. What's the cause?
-  A: You're running a 2.1 kernel and you want to read the previous FAQ.
-
-  Q: Upon 'insmod joystick.o' I get a LOT of unresolved symbols, including
-printk and others. Why?
-  A: You either don't have your kernel compiled with module support. If
-that's the cause, re-compile your kernel with module support switched on.
-Or, you use versioned symbols, and don't have -DMODVERSIONS in the joystick
-driver Makefile, or vice versa. Correct the situation by either removing or
-adding -DMODVERSIONS to the Makefile.
-
-  Q: Running 'jstest 1' or 'jscal 1' doesn't work, and returns with "File
-not found" error. What is the problem?
-  A: The command line interface for these tools is different from what
-version 0.8.0 used. You have to specify the whole device name, eg. 'jstest
-/dev/js0'.
-
-  Q: Running 'jstest /dev/js0' results in "File not found" error. What's the
-cause?
-  A: The device files don't exist. Run 'make devs'.
-
-  Q: Is it possible to connect my old Atari/Commodore/Amiga/console joystick
-or pad that uses a 9-pin D-type cannon connector to the serial port of my
-PC?
-  A: Yes, it is possible, but it'll burn your serial port or the pad. It
-won't work, of course.
-
-  Q: My joystick doesnt work with Quake / Quake 2. What's the cause?
-  A: Quake / Quake 2 don't support joystick. Use joy2key to simulate keypresses
-for them.
+Q: The driver doesn't find any joysticks connected to my soundcard with the
+   message "joy-something: no joysticks found" and "joy-something.o:
+   init_module: Device or resource busy." or "Initialization of joy-something
+   failed"  What could be the cause?
+A: The most common cause is that the joystick port on your soundcard is
+   not enabled. If it is an ISA PnP card, you'll need isapnptools to configure
+   the gameport. Non-PnP cards usually use some option to the sound driver -
+   see the sound driver docs and source and enable the port. Note that in case
+   of a PnP card you have to load the joystick driver as a module after running
+   the isapnp command, it will not work in the opposite order.
+
+Q: Any access to the joystick devices gives me "Operation not supported by
+   device". What am I doing wrong?
+A: You're running a 2.0 kernel and you forgot to insmod the hardware
+   specific module. You not only need the joystick.o, but also one of the other
+   joy-*.o files (most usually joy-analog.o), as described in this document,
+   section 2. If you are not using modules, then you didn't say 'Y' to any of
+   the hardware-specific questions. Again, see section 2. If you did select
+   the specific support, and you still get this message, check that you
+   selected the right one, and if it still doesn't work, go to the previous
+   FAQ.
+
+Q: Everything is fine, except I get "No such device" error when I try to
+   do anything with /dev/js0. What's the cause?
+A: You're running a 2.1 or 2.2. kernel and you want to read the previous FAQ.
+
+Q: Upon 'insmod joystick.o' I get a LOT of unresolved symbols, including
+   'printk' and others. Why?
+A: You either don't have your kernel compiled with module support. If
+   that's the cause, re-compile your kernel with module support switched on.
+   Or, you use versioned symbols, and don't have -DMODVERSIONS in the joystick
+   driver Makefile, or vice versa. Correct the situation by either removing or
+   adding -DMODVERSIONS to the Makefile.
+
+Q: Upon 'insmod joy-something' I get a bunch of unresolved symbols, like
+   'js_register_port, js_unregister device' and others. What's wrong?
+A: You need to 'insmod joystick.o' first.
+
+Q: Running 'jstest 1' or 'jscal 1' doesn't work, and returns with "File
+   not found" error. What is the problem?
+A: The command line interface for these tools is different from what
+   version 0.8.0 used. You have to specify the whole device name, eg. 'jstest
+   /dev/js0'.
+
+Q: Running 'jstest /dev/js0' results in "File not found" error. What's the
+   cause?
+A: The device files don't exist. Run 'make devs'.
+
+Q: Is it possible to connect my old Atari/Commodore/Amiga/console joystick
+   or pad that uses a 9-pin D-type cannon connector to the serial port of my
+   PC?
+A: Yes, it is possible, but it'll burn your serial port or the pad. It
+   won't work, of course.
+
+Q: My joystick doesn't work with Quake / Quake 2. What's the cause?
+A: Quake / Quake 2 don't support joystick. Use joy2key to simulate keypresses
+   for them.
 
 6. Programming Interface
 ~~~~~~~~~~~~~~~~~~~~~~~~
@@ -565,23 +730,31 @@
 	Brian Gerst		<bgerst@quark.vpplus.com>
 	Andree Borrmann		<a.borrmann@tu-bs.de>
 	Martin Giguere		<zefrench@hotmail.com>
+	David Thompson		<dcthomp@mail.utexas.edu>
+	Justin Wake		<spectre@telefragged.com>
+	Benoit Triquet		<benoit@adsl-216-100-248-201.dsl.pacbell.net>
+	John Dahlstrom		<jodaman@bradley.edu>
+	Dan Gohman		<gohmandj@mrs.umn.edu>
+	Joe Krahn		<krahn@niehs.nih.gov>
+	David Kuder		<alphagod@penguinpowered.com>
+	Raymond Ingles		<sorceror@tir.com>
 
   If you think you should be in this list and are not, it's possible that
 I forgot to include you - contact me and I'll correct the error. :)
 
   Thanks to KYE Systems Europe, who provided me with driver sources for the
-Genius Flight2000 Digital F-23, which happens to be compatible with
-Microsoft SideWinder 3d Pro.
+Genius Flight2000 Digital F-23, which happens to be identical (in software)
+to Microsoft SideWinder 3D Pro.
 
   Thanks to ThrustMaster Inc. who provided me with docs for their digital
-protocol, and to Trystan A Larey-williams <axe@mail.wsu.edu>, who wrote an
-attempt of a driver for them.
+protocol specifications, and to Trystan A Larey-Williams <axe@mail.wsu.edu>,
+who wrote an attempt of a driver for them.
 
   Thanks to Creative Labs Europe, and Ifor Powell <ipowell@cle.creaf.com>,
-who provided me with docs for their first generation gamepad.
+who provided me with docs for their first generation Blaster GamePad.
 
   Special thanks go to FP-Gaming, Inc. and James C Barnes <james@fpgaming.com>,
-who provided me with help and detailed information about the Assasin 3D
+who provided me with help and detailed information about the Assassin 3D
 protocol and devices, and even sent me a Panther and Panther XL for testing,
 along with cool T-shirts.
 
@@ -590,10 +763,20 @@
 code for their L4 gamecard, and sending me the card to test my driver with
 it.
 
+  Thanks to LogiCad3D for their support, for having the specifications
+online and for the nice music on their telephone.
+
+  Special thanks to Logitech, Jerry de Raad <Jerry_de_Raad@logitech.com>,
+Thomas Burgel <Thomas_Burgel@logitech.com>, Avinash Shinde
+<Avinash_Shinde@logitech.com> for providing me with a lot of documentation
+for their devices, and also for a big box, containing a CyberMan2, Wingman
+Extreme, Magellan, Wingman Warrior, two MouseMan mice, and a NewTouch
+keyboard.
+
   Thanks to everyone else who helped me develop this package of drivers!
 
-  No thanks to Microsoft, Logitech, and Gravis, who don't release a word
-about their hardware .... :(
+  No thanks to Microsoft and Gravis, who don't release a word about their
+hardware .... :(
 
 8. ChangeLog
 ~~~~~~~~~~~~
@@ -602,50 +785,3 @@
 9. To do
 ~~~~~~~~
   See the TODO file for the list of things planned.
-
-10. Current driver status
-~~~~~~~~~~~~~~~~~~~~~~~~~
-  OK means tested and not touched till this driver revision, unknown means
-that the driver was changed since last test, broken means doesn't work,
-incomplete means can't work, because vital parts of support are missing.
-
-joystick.c:		2.1.x kernel interface	- OK
-joy-amiga.c:		Multi1 stick		- unknown
-joy-analog.c:		standard joysticks	- OK
-			FCS hats		- OK
-			CHF hats & buttons	- OK
-			XY buttons		- OK
-			UV buttons		- OK
-joy-assasin.c:		MadCatz Panther XL	- OK
-			MadCatz PXL rudder	- OK
-			MadCatz Panther		- OK
-			FPG Assasin 3D		- OK
-joy-console.c:		NES pad			- OK
-			SNES pad		- OK
-			Multi1 stick		- OK
-			Multi2 stick		- OK
-			PSX			- SW OK, HW unreliable
-joy-db9.c:		Multi1 stick		- OK
-			Multi2 stick		- OK
-			Sega Genesis pad	- OK
-			Sega Genesis 5 pad	- OK
-			Sega Genesis 6 pad	- OK
-			Sega Saturn pad		- unknown
-joy-gravis.c		Gravis GamePad Pro	- OK
-			Gravis Xterminator	- OK
-			Gravis Blackhawk Digital- OK
-joy-lightning.c		PDPI Lightning 4	- OK
-joy-logitech.c		WingMan Extreme Digital	- OK
-			CyberMan 2		- OK
-			Thunder Pad Digital	- unknown
-joy-sidewinder.c	SW 3D Pro		- OK
-			Genius F-23		- OK
-			SW GP			- OK
-			SW PP			- OK
-			SW FFP			- OK
-joy-thrustmaster.c	Millenium 3D Inceptor	- OK
-			3D-Rage Pad		- OK
-joy-turbografx.c	Multi1 stick		- OK
-
-Please help me and send me success / failure reports for the drivers,
-I need to know what works, and what needs to be debugged. Thank you.
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/kernel-docs.txt linux.14p16/Documentation/kernel-docs.txt
--- linux.vanilla/Documentation/kernel-docs.txt	Sat Aug 14 02:26:08 1999
+++ linux.14p16/Documentation/kernel-docs.txt	Thu Dec  9 15:34:43 1999
@@ -1,15 +1,14 @@
 
-   
- INDEX OF DOCUMENTATION FOR PEOPLE INTERESTED IN WRITING AND/OR UNDERSTANDING
-                               THE LINUX KERNEL.
-                                       
-		Juan-Mariano de Goyeneche <jmseyas@dit.upm.es>
-   
-   
-   /*
-    * The latest version of this document may be found at: 
-    *   http://www.dit.upm.es/~jmseyas/linux/kernel/hackers-docs.html
-    */
+       Index of Documentation for People Interested in Writing and/or
+                                      
+                      Understanding the Linux Kernel.
+                                      
+              Juan-Mariano de Goyeneche < jmseyas@dit.upm.es>
+                                      
+/*
+ * The latest version of this document may be found at:
+ *   http://www.dit.upm.es/~jmseyas/linux/kernel/hackers-docs.html
+ */
 
    The need for a document like this one became apparent in the
    linux-kernel mailing list as the same questions, asking for pointers
@@ -31,301 +30,409 @@
    corrections, ideas or comments are also welcomed.
    
    The papers that follow are listed in no particular order. All are
-   catalogued with the following fields: the document's "Title", the
-   "Author"/s, the "URL" where they can be found, some "Keywords"
-   helpful when searching for specific topics, and a brief "Description"
-   of the Document.
+   cataloged with the following fields: the document's "Title", the
+   "Author"/s, the "URL" where they can be found, some "Keywords" helpful
+   when searching for specific topics, and a brief "Description" of the
+   Document.
    
    Enjoy!
    
-   
-   ON-LINE DOCS:
-   
-          + Title: "The Linux Kernel"
-            Author: David A. Rusling.
-            URL: http://sunsite.unc.edu/linux/LDP/tlk/tlk.html
-            Keywords: everything!, book.
-            Description: On line, 200 pages book describing most
-            aspects of the Linux Kernel. Probably, the first reference
-            for beginners. Lots of illustrations explaining data
-            structures use and relationships in the purest Richard W.
-            Stevens' style. Contents: "1.-Hardware Basics, 2.-Software
-            Basics, 3.-Memory Management, 4.-Processes, 5.-Interprocess
-            Communication Mechanisms, 6.-PCI, 7.-Interrupts and Interrupt
-            Handling, 8.-Device Drivers, 9.-The File system,
-            10.-Networks, 11.-Kernel Mechanisms, 12.-Modules, 13.-The
-            Linux Kernel Sources, A.-Linux Data Structures, B.-The Alpha
-            AXP Processor, C.-Useful Web and FTP Sites, D.-The GNU
-            General Public License, Glossary". In short: a must have.
-   
-          + Title: "The Linux Kernel Hackers' Guide"
-            Author: Michael K.Johnson and others.
-            URL: http://www.redhat.com:8080/HyperNews/get/khg.html
-            Keywords: everything!
-            Description: No more Postscript book-like version. Only
-            HTML now. Many people have contributed. The interface is
-            similar to web available mailing lists archives. You can find
-            some articles and then some mails asking questions about them
-            and/or complementing previous contributions. A little bit
-            anarchic in this aspect, but with some valuable information
-            in some cases.
-       
-          + Title: "Tour Of the Linux Kernel Source"
-            Author: Vijo Cherian.
-            URL: http://www.svrec.ernet.in/~vijo/tolks/tolks.html
-            Keywords:
-            Description: The name says it all. A tour of the sources,
-            describing directories, files, variables, data structures...
-            It covers general stuff, device drivers, filesystems, IPC and
-            Network Code.
-       
-          + Title: "Overview of the Virtual File System"
-            Author: Richard Gooch.
-            URL: http://www.atnf.csiro.au/~rgooch/linux/vfs.txt
-            Keywords: VFS, File System, mounting filesystems, opening
-            files, dentries,
-            dcache. Description: Brief introduction to the Linux
-            Virtual File System. What is it, how it works, operations
-            taken when opening a file or mounting a file system and
-            description of important data structures explaining the
-            purpose of each of their entries.
-   
-          + Title: "The Linux RAID-1, 4, 5 Code"
-            Author: Ingo Molnar, Gadi Oxman and Miguel de Icaza.
-            URL: http://www.ssc.com/lj/issue44/2391.html
-            Keywords: RAID, MD driver.
-            Description: Linux Journal Kernel Korner article. Here is
-            it's abstract: "A description of the implementation of the
-            RAID-1, RAID-4 and RAID-5 personalities of the MD device
-            driver in the Linux kernel, providing users with high
-            performance and reliable, secondary-storage capability using
-            software".
-   
-          + Title: "Dynamic Kernels: Modularized Device Drivers"
-            Author: Alessandro Rubini.
-            URL: http://www.ssc.com/lj/issue23/1219.html
-            Keywords: device driver, module, loading/unloading modules,
-            allocating
-            resources. Description: Linux Journal Kernel Korner
-            article. Here is it's abstract: "This is the first of a
-            series of four articles co-authored by Alessandro Rubini and
-            Georg Zezchwitz which present a practical approach to writing
-            Linux device drivers as kernel loadable modules. This
-            installment presents an introduction to the topic, preparing
-            the reader to understand next month's installment".
-   
-          + Title: "Dynamic Kernels: Discovery"
-            Author: Alessandro Rubini.
-            URL: http://www.ssc.com/lj/issue24/kk24.html
-            Keywords: character driver, init_module, clean_up module,
-            autodetection,
-            mayor number, minor number, file operations, open(), close().
-            Description: Linux Journal Kernel Korner article. Here is
-            it's abstract: "This article, the second of four, introduces
-            part of the actual code to create custom module implementing
-            a character device driver. It describes the code for module
-            initialization and cleanup, as well as the open() and close()
-            system calls".
-   
-          + Title: "The Devil's in the Details"
-            Author: Georg v. Zezschwitz and Alessandro Rubini.
-            URL: http://www.ssc.com/lj/issue25/kk25.html
-            Keywords: read(), write(), select(), ioctl(), blocking/non
-            blocking mode,
-            interrupt handler. Description: Linux Journal Kernel Korner
-            article. Here is it's abstract: "This article, the third of
-            four on writing character device drivers, introduces concepts
-            of reading, writing, and using ioctl-calls".
-   
-          + Title: "Dissecting Interrupts and Browsing DMA"
-            Author: Alessandro Rubini and Georg v. Zezschwitz.
-            URL: http://www.ssc.com/lj/issue26/interrupt.html
-            Keywords: interrupts, irqs, DMA, bottom halves, task
-            queues.
-            Description: Linux Journal Kernel Korner article. Here is
-            it's abstract: "This is the fourth in a series of articles
-            about writing character device drivers as loadable kernel
-            modules. This month, we further investigate the field of
-            interrupt handling. Though it is conceptually simple,
-            practical limitations and constraints make this an
-            ``interesting'' part of device driver writing, and several
-            different facilities have been provided for different
-            situations. We also investigate the complex topic of DMA".
-   
-          + Title: "Network Buffers And Memory Management"
-            Author: Alan Cox.
-            URL: http://www.ssc.com/lj/issue30/kk30.html
-            Keywords: sk_buffs, network devices, protocol/link layer
-            variables, network
-            devices flags, transmit, receive, configuration, multicast.
-            Description: Linux Journal Kernel Korner. Here is the
-            abstract: "Writing a network device driver for Linux is
-            fundamentally simple---most of the complexity (other than
-            talking to the hardware) involves managing network packets in
-            memory".
-       
-          + Title: "An Introduction to the Linux 1.3.x Networking Code"
-            Author: Vipul Gupta.
-            URL:
-            http://anchor.cs.binghamton.edu/courses/cs628/linux-net.html
-            Keywords: files, sk_buffs.
-            Description: A short description of files under the net/
-            directory. Each file has a one- or two-line paragraph to
-            describe it. Also, sk_buffs is explained with some
-            beautiful pictures. A little bit outdated.
-   
-          + Title: "Linux ioctl() Primer"
-            Author: Vipul Gupta.
-            URL:
-            http://anchor.cs.binghamton.edu/courses/cs628/ioctl.html
-            Keywords: ioctl, socket.
-            Description: Little description and examples on the use and
-            implementation of the ioctl() system call. A little bit
-            biased towards sockets.
-       
-          + Title: "Writing Linux Device Drivers"
-            Author: Michael K. Johnson.
-            URL: http://www.redhat.com/~johnsonm/devices.html
-            Keywords: files, VFS, file operations, kernel interface,
-            character vs
-            block devices, I/O access, hardware interrupts, DMA, access
-            to user memory, memory allocation, timers. Description:
-            Introductory 50-minutes (sic) tutorial on writing device
-            drivers. 12 pages written by the same author of the "Kernel
-            Hackers' Guide" which give a very good overview of the topic.
-   
-          + Title: "The Venus kernel interface"
-            Author: Peter J. Braam.
-            URL:
-            http://www.coda.cs.cmu.edu/doc/html/kernel-venus-protocol.html
-            Keywords: coda, filesystem, venus, cache manager.
-            Description: "This document describes the communication
-            between Venus and kernel level file system code needed for
-            the operation of the Coda filesystem. This version document
-            is meant to describe the current interface (version 1.0) as
-            well as improvements we envisage".
-       
-          + Title: "Programming PCI-Devices under Linux"
-            Author: Claus Schroeter.
-            URL:
-            ftp://ftp.llp.fu-berlin.de/pub/linux/LINUX-LAB/whitepapers/pc
-            ip.ps.gz
-            Keywords: PCI, device, busmastering.
-            Description: 6 pages tutorial on PCI programming under
-            Linux. Gives the basic concepts on the architecture of the
-            PCI subsystem, as long as basic functions and macros to
-            read/write the devices and perform busmastering.
-       
-          + Title: "Writing Character Device Driver for Linux"
-            Author: R. Baruch and C. Schroeter.
-            URL:
-            ftp://ftp.llp.fu-berlin.de/pub/linux/LINUX-LAB/whitepapers/dr
-            ivers.ps.gz
-            Keywords: character device drivers, I/O, signals, DMA,
-            accessing ports in user space, kernel environment.
-            Description: 68 pages paper on writing character drivers. A
-            little bit old (1.993, 1.994) although still useful.
-       
-       
-       
-     * BOOKS: (Not on-line)
-       
-          + Title: "Linux Device Drivers"
-            Author: Alessandro Rubini.
-            Publisher: O'Reilly &Associates.
-            Date: 1998.
-            ISBN: 1-56592-292-1
-       
-          + Title: "Linux Kernel Internals"
-            Author: Michael Beck.
-            Publisher: Addison-Wesley.
-            Date: 1997.
-            ISBN: 0-201-33143-8 (second edition)
-       
-          + Title: "The Design of the UNIX Operating System"
-            Author: Maurice J. Bach.
-            Publisher: Prentice Hall.
-            Date: 1986.
-            ISBN: ???
-   
-          + Title: "The Design and Implementation of the 4.3 BSD UNIX
-            Operating System"
-            Author: Samuel J. Leffler, Marshall Kirk McKusick, Michael
-            J. Karels, John S. Quarterman.
-            Publisher: Addison-Wesley.
-            Date: 1989 (reprinted with corrections on October, 1990).
-            ISBN: 0-201-06196-1
-       
-          + Title: "The Design and Implementation of the 4.4 BSD UNIX
-            Operating System"
-            Author: Marshall Kirk McKusick, Keith Bostic, Michael J.
-            Karels, John S. Quarterman.
-            Publisher: Addison-Wesley.
-            Date: 1996.
-            ISBN: 0-201-54979-4
-   
-          + Title: "Programmation Linux 2.0 API systeme et
-            fonctionnement du noyau"
-            Author: Remy Card, Eric Dumas, Franck Mevel.
-            Publisher: Eyrolles.
-            Date: 1997.
-            Pages: 520. ISBN: 2-212-08932-5
-       
-          + Title: "Unix internals -- the new frontiers"
-            Author: Uresh Vahalia.
-            Publisher: Prentice Hall.
-            Date: 1996.
-            Pages: 600. ISBN: 0-13-101908-2
-   
-       
-     * MISCELLANEOUS:
+     ON-LINE DOCS:
        
-          + Name: Linux Source Driver.
-            URL: http://lsd.linux.cz
-            Keywords: Browsing.
-            Description: "Linux Source Driver (LSD) is an application,
-            which can make browsing source codes of Linux kernel easier
-            than you can imagine. You can select between multiple
-            versions of kernel (e.g. 0.01, 1.0.0, 2.0.33, 2.0.34pre13,
-            2.0.0, 2.1.101 etc.). With LSD you can search Linux kernel
-            (fulltext, macros, types, functions and variables) and LSD
-            can generate patches for you on the fly (files, directories
-            or kernel)".
-       
-          + Name: Linux Weekly News.
-            URL: http://lwn.net
-            Keywords: last kernel news.
-            Description: The title says it all. There's a fixed kernel
-            section summarizing developers' work, bug fixes, new features
-            and versions produced during the week. Published every
-            Thursday.
-       
-          + Name: CuTTiNG.eDGe.LiNuX.
-            URL: http://edge.linuxhq.com
-            Keywords: changelist.
-            Description: Site which provides the changelist for every
-            kernel release. What's new, what's better, what's changed.
-            Myrdraal reads the patchs and describes them. Pointers to the
-            patches are there, too.
+     * Title: "The Linux Kernel"
+       Author: David A. Rusling.
+       URL: http://sunsite.unc.edu/linux/LDP/tlk/tlk.html
+       Keywords: everything!, book.
+       Description: On line, 200 pages book describing most aspects of
+       the Linux Kernel. Probably, the first reference for beginners.
+       Lots of illustrations explaining data structures use and
+       relationships in the purest Richard W. Stevens' style. Contents:
+       "1.-Hardware Basics, 2.-Software Basics, 3.-Memory Management,
+       4.-Processes, 5.-Interprocess Communication Mechanisms, 6.-PCI,
+       7.-Interrupts and Interrupt Handling, 8.-Device Drivers, 9.-The
+       File system, 10.-Networks, 11.-Kernel Mechanisms, 12.-Modules,
+       13.-The Linux Kernel Sources, A.-Linux Data Structures, B.-The
+       Alpha AXP Processor, C.-Useful Web and FTP Sites, D.-The GNU
+       General Public License, Glossary". In short: a must have.
+       
+     * Title: "The Linux Kernel Hackers' Guide"
+       Author: Michael K.Johnson and others.
+       URL: http://khg.redhat.com/HyperNews/get/khg.html
+       Keywords: everything!
+       Description: No more Postscript book-like version. Only HTML now.
+       Many people have contributed. The interface is similar to web
+       available mailing lists archives. You can find some articles and
+       then some mails asking questions about them and/or complementing
+       previous contributions. A little bit anarchic in this aspect, but
+       with some valuable information in some cases.
+       
+     * Title: "Conceptual Architecture of the Linux Kernel"
+       Author: Ivan T. Bowman.
+       URL: http://plg.uwaterloo.ca/~itbowman/papers/CS746G-a1.html
+       Keywords: conceptual software arquitecture, extracted design,
+       reverse engineering, system structure.
+       Description: Conceptual software arquitecture of the Linux kernel,
+       automatically extracted from the source code. Very detailed. Good
+       figures. Gives good overall kernel understanding.
+       
+     * Title: "Concrete Architecture of the Linux Kernel"
+       Author: Ivan T. Bowman, Saheem Siddiqi, and Meyer C. Tanuan.
+       URL: http://plg.uwaterloo.ca/~itbowman/papers/CS746G-a2.html
+       Keywords: concrete arquitecture, extracted design, reverse
+       engineering, system structure, dependencies.
+       Description: Concrete arquitecture of the Linux kernel,
+       automatically extracted from the source code. Very detailed. Good
+       figures. Gives good overall kernel understanding. This papers
+       focus on lower details than its predecessor (files, variables...).
+       
+     * Title: "Linux as a Case Study: Its Extracted Software
+       Architecture"
+       Author: Ivan T. Bowman, Richard C. Holt and Neil V. Brewster.
+       URL: http://plg.uwaterloo.ca/~itbowman/papers/linuxcase.html
+       Keywords: software architecture, architecture recovery,
+       redocumentation.
+       Description: Paper appeared at ICSE'99, Los Angeles, May 16-22,
+       1999. A mixture of the previous two documents from the same
+       author.
+       
+     * Title: "Overview of the Virtual File System"
+       Author: Richard Gooch.
+       URL: http://www.atnf.csiro.au/~rgooch/linux/vfs.txt
+       Keywords: VFS, File System, mounting filesystems, opening files,
+       dentries,
+       dcache. Description: Brief introduction to the Linux Virtual File
+       System. What is it, how it works, operations taken when opening a
+       file or mounting a file system and description of important data
+       structures explaining the purpose of each of their entries.
+       
+     * Title: "The Linux RAID-1, 4, 5 Code"
+       Author: Ingo Molnar, Gadi Oxman and Miguel de Icaza.
+       URL: http://www.ssc.com/lj/issue44/2391.html
+       Keywords: RAID, MD driver.
+       Description: Linux Journal Kernel Korner article. Here is it's
+       abstract: "A description of the implementation of the RAID-1,
+       RAID-4 and RAID-5 personalities of the MD device driver in the
+       Linux kernel, providing users with high performance and reliable,
+       secondary-storage capability using software".
+       
+     * Title: "Dynamic Kernels: Modularized Device Drivers"
+       Author: Alessandro Rubini.
+       URL: http://www.ssc.com/lj/issue23/1219.html
+       Keywords: device driver, module, loading/unloading modules,
+       allocating resources.
+       Description: Linux Journal Kernel Korner article. Here is it's
+       abstract: "This is the first of a series of four articles
+       co-authored by Alessandro Rubini and Georg Zezchwitz which present
+       a practical approach to writing Linux device drivers as kernel
+       loadable modules. This installment presents an introduction to the
+       topic, preparing the reader to understand next month's
+       installment".
+       
+     * Title: "Dynamic Kernels: Discovery"
+       Author: Alessandro Rubini.
+       URL: http://www.ssc.com/lj/issue24/kk24.html
+       Keywords: character driver, init_module, clean_up module,
+       autodetection,
+       mayor number, minor number, file operations, open(), close().
+       Description: Linux Journal Kernel Korner article. Here is it's
+       abstract: "This article, the second of four, introduces part of
+       the actual code to create custom module implementing a character
+       device driver. It describes the code for module initialization and
+       cleanup, as well as the open() and close() system calls".
+       
+     * Title: "The Devil's in the Details"
+       Author: Georg v. Zezschwitz and Alessandro Rubini.
+       URL: http://www.ssc.com/lj/issue25/kk25.html
+       Keywords: read(), write(), select(), ioctl(), blocking/non
+       blocking mode, interrupt handler.
+       Description: Linux Journal Kernel Korner article. Here is it's
+       abstract: "This article, the third of four on writing character
+       device drivers, introduces concepts of reading, writing, and using
+       ioctl-calls".
+       
+     * Title: "Dissecting Interrupts and Browsing DMA"
+       Author: Alessandro Rubini and Georg v. Zezschwitz.
+       URL: http://www.ssc.com/lj/issue26/interrupt.html
+       Keywords: interrupts, irqs, DMA, bottom halves, task queues.
+       Description: Linux Journal Kernel Korner article. Here is it's
+       abstract: "This is the fourth in a series of articles about
+       writing character device drivers as loadable kernel modules. This
+       month, we further investigate the field of interrupt handling.
+       Though it is conceptually simple, practical limitations and
+       constraints make this an ``interesting'' part of device driver
+       writing, and several different facilities have been provided for
+       different situations. We also investigate the complex topic of
+       DMA".
+       
+     * Title: "Network Buffers And Memory Management"
+       Author: Alan Cox.
+       URL: http://www.ssc.com/lj/issue30/kk30.html
+       Keywords: sk_buffs, network devices, protocol/link layer
+       variables, network devices flags, transmit, receive,
+       configuration, multicast.
+       Description: Linux Journal Kernel Korner. Here is the abstract:
+       "Writing a network device driver for Linux is fundamentally
+       simple---most of the complexity (other than talking to the
+       hardware) involves managing network packets in memory".
+       
+     * Title: "An Introduction to the Linux 1.3.x Networking Code"
+       Author: Vipul Gupta.
+       URL: http://anchor.cs.binghamton.edu/courses/cs628/linux-net.html
+       Keywords: files, sk_buffs.
+       Description: A short description of files under the net/
+       directory. Each file has a one or two lines paragraph description.
+       sk_buffs explained, too, with some beautiful pictures. A little
+       bit outdated.
+       
+     * Title: "Linux ioctl() Primer"
+       Author: Vipul Gupta.
+       URL: http://anchor.cs.binghamton.edu/courses/cs628/ioctl.html
+       Keywords: ioctl, socket.
+       Description: Little description and examples on the use and
+       implementation of the ioctl() system call. A little bit biased
+       towards sockets.
+       
+     * Title: "Writing Linux Device Drivers"
+       Author: Michael K. Johnson.
+       URL: http://www.redhat.com/~johnsonm/devices.html
+       Keywords: files, VFS, file operations, kernel interface, character
+       vs block devices, I/O access, hardware interrupts, DMA, access to
+       user memory, memory allocation, timers.
+       Description: Introductory 50-minutes (sic) tutorial on writing
+       device drivers. 12 pages written by the same author of the "Kernel
+       Hackers' Guide" which give a very good overview of the topic.
+       
+     * Title: "The Venus kernel interface"
+       Author: Peter J. Braam.
+       URL:
+       http://www.coda.cs.cmu.edu/doc/html/kernel-venus-protocol.html
+       Keywords: coda, filesystem, venus, cache manager.
+       Description: "This document describes the communication between
+       Venus and kernel level file system code needed for the operation
+       of the Coda filesystem. This version document is meant to describe
+       the current interface (version 1.0) as well as improvements we
+       envisage".
+       
+     * Title: "Programming PCI-Devices under Linux"
+       Author: Claus Schroeter.
+       URL:
+       ftp://ftp.llp.fu-berlin.de/pub/linux/LINUX-LAB/whitepapers/pcip.ps
+       .gz
+       Keywords: PCI, device, busmastering.
+       Description: 6 pages tutorial on PCI programming under Linux.
+       Gives the basic concepts on the architecture of the PCI subsystem,
+       as long as basic functions and macros to read/write the devices
+       and perform busmastering.
+       
+     * Title: "Writing Character Device Driver for Linux"
+       Author: R. Baruch and C. Schroeter.
+       URL:
+       ftp://ftp.llp.fu-berlin.de/pub/linux/LINUX-LAB/whitepapers/drivers
+       .ps.gz
+       Keywords: character device drivers, I/O, signals, DMA, accesing
+       ports in user space, kernel environment.
+       Description: 68 pages paper on writing character drivers. A little
+       bit old (1.993, 1.994) although still useful.
+       
+     * Title: "The Second Extended Filesystem"
+       Author: Matthew Wilcox.
+       URL: http://pocket.fluff.org/~mrw/linux/ext2.txt
+       Keywords: ext2, filesystem.
+       Description: Description of ext2's blocks, directories, inodes ...
+       
+     * Title: "Analysis of the Ext2fs structure"
+       Author: Louis-Dominique Dubeau.
+       URL: http://step.polymtl.ca/~ldd/ext2fs/ext2fs_toc.html
+       Keywords: ext2, filesystem, ext2fs.
+       Description: Description of ext2's blocks, directories, inodes,
+       bitmaps, invariants ...
+       
+     * Title: "Kernel API changes from 2.0 to 2.2"
+       Author: Richard Gooch.
+       URL:
+       http://www.atnf.csiro.au/~rgooch/linux/docs/porting-to-2.2.html
+       Keywords: 2.2, changes.
+       Description: Kernel functions/structures/variables which changed
+       from 2.0.x to 2.2.x.
+       
+     * Title: "Kernel API changes from 2.2 to 2.3"
+       Author: Richard Gooch.
+       URL:
+       http://www.atnf.csiro.au/~rgooch/linux/docs/porting-to-2.2.html
+       Keywords: 2.3, changes.
+       Description: Kernel functions/structures/variables which changed
+       from 2.2.x to 2.3.x.
+       
+     * Title: "Linux Kernel Module Programming Guide"
+       Author: Ori Pomerantz.
+       URL: http://www.linuxdoc.org/LDP/lkmpg/mpg.html
+       Keywords: modules, GPL book, /proc, ioctls, system calls,
+       interrupt handlers .
+       Description: Very nice 92 pages GPL book on the topic of modules
+       programming. Lots of examples.
+       
+     * Title: "Device File System (devfs) Overview"
+       Author: Richard Gooch.
+       URL: http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.txt
+       Keywords: filesystem, /dev, devfs, dynamic devices, major/minor
+       allocation, device management.
+       Description: Document describing Richard Gooch's controversial
+       devfs, which allows for dynamic devices, only shows present
+       devices in /dev, gets rid of major/minor numbers allocation
+       problems, and allows for hundreds of identical devices (which some
+       USB systems might demand soon).
+       
+     * Title: "I/O Event Handling Under Linux"
+       Author: Richard Gooch.
+       URL: http://www.atnf.csiro.au/~rgooch/linux/docs/io-events.html
+       Keywords: IO, I/O, select(2), poll(2), FDs, aio_read(2), readiness
+       event queues.
+       Description: From the Introduction: "I/O Event handling is about
+       how your Operating System allows you to manage a large number of
+       open files (file descriptors in UNIX/POSIX, or FDs) in your
+       application. You want the OS to notify you when FDs become active
+       (have data ready to be read or are ready for writing). Ideally you
+       want a mechanism that is scalable. This means a large number of
+       inactive FDs cost very little in memory and CPU time to manage".
+       
+     BOOKS: (Not on-line)
+   
+     * Title: "Linux Device Drivers"
+       Author: Alessandro Rubini.
+       Publisher: O'Reilly &Associates.
+       Date: 1998.
+       ISBN: 1-56592-292-1
+       
+     * Title: "Linux Kernel Internals"
+       Author: Michael Beck.
+       Publisher: Addison-Wesley.
+       Date: 1997.
+       ISBN: 0-201-33143-8 (second edition)
+       
+     * Title: "The Design of the UNIX Operating System"
+       Author: Maurice J. Bach.
+       Publisher: Prentice Hall.
+       Date: 1986.
+       Pages: 471.
+       ISBN: 0-13-201757-1
+       
+     * Title: "The Design and Implementation of the 4.3 BSD UNIX
+       Operating System"
+       Author: Samuel J. Leffler, Marshall Kirk McKusick, Michael J.
+       Karels, John S. Quarterman.
+       Publisher: Addison-Wesley.
+       Date: 1989 (reprinted with corrections on October, 1990).
+       ISBN: 0-201-06196-1
+       
+     * Title: "The Design and Implementation of the 4.4 BSD UNIX
+       Operating System"
+       Author: Marshall Kirk McKusick, Keith Bostic, Michael J. Karels,
+       John S. Quarterman.
+       Publisher: Addison-Wesley.
+       Date: 1996.
+       ISBN: 0-201-54979-4
+       
+     * Title: "Programmation Linux 2.0 API systeme et fonctionnement du
+       noyau"
+       Author: Remy Card, Eric Dumas, Franck Mevel.
+       Publisher: Eyrolles.
+       Date: 1997.
+       Pages: 520.
+       ISBN: 2-212-08932-5
+       Notes: French.
+       
+     * Title: "The Linux Kernel Book"
+       Author: Remy Card, Eric Dumas, Franck Mevel.
+       Publisher: John Wiley & Sons.
+       Date: 1998.
+       ISBN: 0-471-98141-9
+       Notes: English translation.
+       
+     * Title: "Linux 2.0"
+       Author: Remy Card, Eric Dumas, Franck Mevel.
+       Publisher: Gestión 2000.
+       Date: 1997.
+       Pages: 501.
+       ISBN: 8-480-88208-5
+       Notes: Spanish translation.
+       
+     * Title: "Unix internals -- the new frontiers"
+       Author: Uresh Vahalia.
+       Publisher: Prentice Hall.
+       Date: 1996.
+       Pages: 600.
+       ISBN: 0-13-101908-2
+       
+     * Title: "Linux Core Kernel Commentary. Guide to Insider's Knowledge
+       on the Core Kernel od the Linux Code"
+       Author: Scott Maxwell.
+       Publisher: ???.
+       Date: 1999.
+       Pages: 592.
+       ISBN: 1-57610-469-9
+       Notes: CD-ROM included.
+       
+     MISCELLANEOUS:
+   
+     * Name: Linux Source Driver.
+       URL: http://lsd.linux.cz
+       Keywords: Browsing source code.
+       Description: "Linux Source Driver (LSD) is an application, which
+       can make browsing source codes of Linux kernel easier than you can
+       imagine. You can select between multiple versions of kernel (e.g.
+       0.01, 1.0.0, 2.0.33, 2.0.34pre13, 2.0.0, 2.1.101 etc.). With LSD
+       you can search Linux kernel (fulltext, macros, types, functions
+       and variables) and LSD can generate patches for you on the fly
+       (files, directories or kernel)".
+       
+     * Name: Cross-Referencing Linux.
+       URL: http://lxr.linux.no/source/
+       Keywords: Browsing source code.
+       Description: Another web-based Linux kernel source code browser.
+       Lots of cross references to variables and functions. You can see
+       where they are defined and where they are used.
+       
+     * Name: Linux Weekly News.
+       URL: http://lwn.net
+       Keywords: latest kernel news.
+       Description: The title says it all. There's a fixed kernel section
+       summarizing developers' work, bug fixes, new features and versions
+       produced during the week. Published every Thursday.
+       
+     * Name: Kernel Traffic.
+       URL: http://kt.linuxcare.com
+       Keywords: linux-kernel mailing list, weekly kernel news.
+       Description: Weekly newsletter covering the most relevant
+       discussions of the linux-kernel mailing list.
+       
+     * Name: CuTTiNG.eDGe.LiNuX.
+       URL: http://edge.kernelnotes.org
+       Keywords: changelist.
+       Description: Site which provides the changelist for every kernel
+       release. What's new, what's better, what's changed. Myrdraal reads
+       the patches and describes them. Pointers to the patches are there,
+       too.
+       
+     * Name: New linux-kernel Mailing List FAQ.
+       URL: Original site:
+       http://www.altern.org/andrebalsa/doc/lkml-faq.html
+       URL: U.S. mirror site:
+       http://www.ececs.uc.edu/~rreilova/linux/lkml-faq.html
+       Keywords: linux-kernel mailing list FAQ.
+       Description: linux-kernel is a mailing list for developers to
+       communicate. This FAQ builds on the previous linux-kernel mailing
+       list FAQ maintained by Frohwalt Egerer, who no longer maintains
+       it. Read it to see how to join the mailing list. Dozens of
+       interesting questions regarding the list, Linux, developers (who
+       is ...?), terms (what is...?) are answered here too. Just read it.
+       
+     * Name: "Linux Virtual File System"
+       Author: Peter J. Braam.
+       URL: http://www.coda.cs.cmu.edu/doc/talks/linuxvfs
+       Keywords: slides, VFS, inode, superblock, dentry, dcache.
+       Description: Set of slides, presumably from a presentation on the
+       Linux VFS layer. Covers version 2.1.x, with dentries and the
+       dcache.
+     _________________________________________________________________
    
-          + Name: New linux-kernel Mailing List FAQ.
-            URL: Original site:
-            http://www.altern.org/andrebalsa/doc/lkml-faq.html
-            URL: U.S. mirror site:
-            http://www.ececs.uc.edu/~rreilova/linux/lkml-faq.html
-            Keywords: linux-kernel mailing list FAQ.
-            Description: linux-kernel is a mailing list for developers
-            to communicate. This FAQ builds on the previous linux-kernel
-            mailing list FAQ maintained by Frohwalt Egerer, who no longer
-            maintains it. Read it to see how to join the mailing list.
-            Dozens of interesting questions regarding the list, Linux,
-            developers (who is ...?), terms (what is...?) are answered
-            here too. Just read it.
-       
-          + Name: "Linux Virtual File System"
-            Author: Peter J. Braam.
-            URL: http://www.coda.cs.cmu.edu/doc/talks/linuxvfs
-            Keywords: slides, VFS, inode, superblock, dentry, dcache.
-            Description: Set of slides, presumably from a presentation
-            on the Linux VFS layer. Covers version 2.1.x, with dentries
-            and the dcache.
+   Document last updated on Tue Nov 30 11:20:00 CET 1999
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/kernel-parameters.txt linux.14p16/Documentation/kernel-parameters.txt
--- linux.vanilla/Documentation/kernel-parameters.txt	Sat Aug 14 02:26:45 1999
+++ linux.14p16/Documentation/kernel-parameters.txt	Thu Dec  9 15:34:43 1999
@@ -11,7 +11,7 @@
 restrictions referred to are that the relevant option is valid if:
 
     APIC	APIC support is enabled.
-    APM 	Automatic Power Management support is enabled.
+    APM 	Advanced Power Management support is enabled.
     AX25	Appropriate AX.25 support is enabled.
     CD		Appropriate CD support is enabled.
     EIDE	EIDE/ATAPI support is enabled.
@@ -50,7 +50,7 @@
 it will appear as a kernel argument readable via /proc/cmdline by programs
 running once the system is up.
 
-    53c7xx=		[HW,SCSI]
+    53c7xx=		[HW,SCSI] Amiga SCSI controllers
 
     adb_buttons=	[HW,MOUSE]
 
@@ -64,10 +64,12 @@
 
     AM53C974=		[HW,SCSI]
 
-    apm=		[APM] Automatic Power Management.
+    apm=		[APM] Advanced Power Management.
 
     arcrimi=		[HW,NET]
 
+	ataflop=		[HW, M68k]
+
     atamouse=		[HW,MOUSE] Atari Mouse.
 
     atascsi=		[HW,SCSI] Atari SCSI.
@@ -96,22 +98,22 @@
 
     com90xx=		[HW,NET]
 
-    console=		
+    console=		[KNL] output console + comm spec (speed, control, parity)
 
     cyclades=		[HW,SERIAL] Cyclades multi-serial port adapter.
 
-    debug		[KNL] Enable kernel debugging.
+    debug		[KNL] Enable kernel debugging (events log level).
 
     decnet=		[HW,NET]
 
-    digi=		[HW,SERIAL]
+    digi=		[HW,SERIAL] io parameters + enable/disable command
 
     digiepca=		[HW,SERIAL]
 
     dmascc=		[HW,AX25,SERIAL] AX.25 Z80SCC driver with DMA
 			support available.
 
-    dmasound=		[HW,SOUND]
+    dmasound=		[HW,SOUND] (sound subsystem buffers)
 
     dtc3181e=		[HW,SCSI]
 
@@ -121,7 +123,7 @@
 
     edb=		[HW,PS2]
 
-    ether=		[HW,NET] Ethernet.
+    ether=		[HW,NET] Ethernet cards parameters (iomem,irq,dev_name).
 
     fd_mcs=		[HW,SCSI]
 
@@ -129,7 +131,7 @@
 
     floppy=		[HW]
 
-    ftape=		[HW] Floppy Tape subsystem.
+    ftape=		[HW] Floppy Tape subsystem debugging options.
 
     gdth=		[HW,SCSI]
 
@@ -137,7 +139,8 @@
 
     gvp11=		[HW,SCSI]
 
-    hd= 		[EIDE] IDE and EIDE hard drive subsystem.
+    hd= 		[EIDE] (E)IDE hard drive subsystem
+                geometry (Cyl/heads/sectors) or tune parameters.
 
     hfmodem=		[HW,AX25]
 
@@ -149,10 +152,18 @@
 
     icn=		[HW,ISDN]
 
+	ide?=		[HW] (E)IDE subsystem : config (iomem/irq), tuning or
+                     debugging (serialize,reset,no{dma,tune,probe}) or
+					chipset specific parameters
+
+	idebus=		[HW] (E)IDE subsystem : VLB/PCI bus speed
+
     in2000=		[HW,SCSI]
 
     init=		[KNL]
 
+	initrd=		[KNL] initial ramdisk path
+
     ip= 		[PNP]
 
     isp16=		[HW,CD]
@@ -185,7 +196,7 @@
 
     kbd-reset		[VT]
 
-    load_ramdisk=	[RAM]
+    load_ramdisk=	[RAM] initrd loading boolean
 
     lp= 		[LPT] Parallel Printer.
 
@@ -204,7 +215,7 @@
 
     mcdx=		[HW,CD]
 
-    md= 		[HW]
+    md= 		[HW] RAID subsystems devices and level
 
     mdacon=		[MDA]
 
@@ -224,6 +235,8 @@
 
     nfsroot=		[NFS]
 
+	nmi_watchdog=	[KNL, BUGS=ix86] debugging features for SMP kernels
+
     no387		[BUGS=ix86] Tells the kernel to use the 387 maths
 			emulation library even if a 387 maths coprocessor
 			is present.
@@ -231,6 +244,10 @@
     noapic		[SMP,APIC] Tells the kernel not to make use of any
 			APIC that may be present on the system.
 
+    noasync		[HW, M68K] Disables async and sync negotiation for all devices.
+
+    nodisconnect	[HW,SCSI, M68K] Disables SCSI disconnects.
+
     no-halt		[BUGS=ix86]
 
     noinitrd		[RAM] Tells the kernel not to load any configured
@@ -240,6 +257,8 @@
 
     nosmp		[SMP] Tells an SMP kernel to act as a UP kernel.
 
+    nosync		[HW, M68K] Disables sync negotiation for all devices.
+
     optcd=		[HW,CD]
 
     panic=		
@@ -260,7 +279,7 @@
 
     pg. 		[PARIDE]
 
-    pirq=		[SMP,APIC]
+    pirq=		[SMP,APIC] mp-table
 
     plip=		[LP,NET] Parallel port network link.
 
@@ -275,13 +294,14 @@
 
     ramdisk_size=	[RAM]
 
-    ramdisk_start=	[RAM]
+    ramdisk_start=	[RAM] offset of the initrd image when cohabiting with
+					a kernel image on a floppy
 
     reboot=		[BUGS=ix86]
 
     reserve=
 
-    riscom8=		[HW,SERIAL]
+    riscom8=		[HW,SERIAL] multi-port serial driver (io parameters)
 
     ro			[KNL] Mount root device read-only on boot.
 
@@ -303,12 +323,14 @@
 
     specialix=		[HW,SERIAL] Specialix multi-serial port adapter.
 
-    st= 		[HW]
+    st= 		[HW] SCSI tape parameters (buffers, ..)
 
     st0x=		[HW,SCSI]
 
     stram_swap= 	[HW]
 
+    switches=		[HW, M68K]
+
     sym53c416=		[HW,SCSI]
 
     sym53c8xx=		[HW,SCSI]
@@ -331,6 +353,6 @@
 
     wdt=		[HW]
 
-    xd= 		[HW,XT]
+    xd= 		[HW,XT] Original XT 8bit disk controllers
 
     xd_geo=		[HW,XT]
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/comx.txt linux.14p16/Documentation/networking/comx.txt
--- linux.vanilla/Documentation/networking/comx.txt	Thu Jan  1 01:00:00 1970
+++ linux.14p16/Documentation/networking/comx.txt	Thu Dec  9 15:34:40 1999
@@ -0,0 +1,248 @@
+
+		COMX drivers for the 2.2 kernel
+
+Originally written by: Tivadar Szemethy, <tiv@itc.hu>
+Currently maintained by: Gergely Madarasz <gorgo@itc.hu>
+
+Last change: 21/06/1999.
+
+INTRODUCTION
+
+This document describes the software drivers and their use for the 
+COMX line of synchronous serial adapters for Linux version 2.2.0 and
+above.
+The cards are produced and sold by ITC-Pro Ltd. Budapest, Hungary
+For further info contact <info@itc.hu> 
+or http://www.itc.hu (mostly in Hungarian).
+The firmware files and software are available from ftp://ftp.itc.hu
+
+Currently, the drivers support the following cards and protocols:
+
+COMX (2x64 kbps intelligent board)
+CMX (1x256 + 1x128 kbps intelligent board)
+HiCOMX (2x2Mbps intelligent board)
+LoCOMX (1x512 kbps passive board)
+MixCOM (1x512 or 2x512kbps passive board with a hardware watchdog an
+	optional BRI interface and optional flashROM (1-32M))
+
+At the moment of writing this document, the (Cisco)-HDLC, LAPB, SyncPPP and
+Frame Relay (DTE, rfc1294 IP encapsulation with partially implemented Q933a 
+LMI) protocols are available as link-level protocol. 
+X.25 support is being worked on.
+
+USAGE
+
+Load the comx.o module and the hardware-specific and protocol-specific 
+modules you'll need into the running kernel using the insmod utility.
+This creates the /proc/comx directory.
+See the example scripts in the 'etc' directory.
+
+/proc INTERFACE INTRO
+
+The COMX driver set has a new type of user interface based on the /proc 
+filesystem which eliminates the need for external user-land software doing 
+IOCTL calls. 
+Each network interface or device (i.e. those ones you configure with 'ifconfig'
+and 'route' etc.) has a corresponding directory under /proc/comx. You can
+dynamically create a new interface by saying 'mkdir /proc/comx/comx0' (or you
+can name it whatever you want up to 8 characters long, comx[n] is just a 
+convention).
+Generally the files contained in these directories are text files, which can
+be viewed by 'cat filename' and you can write a string to such a file by
+saying 'echo _string_ >filename'. This is very similar to the sysctl interface.
+Don't use a text editor to edit these files, always use 'echo' (or 'cat'
+where appropriate).
+When you've created the comx[n] directory, two files are created automagically
+in it: 'boardtype' and 'protocol'. You have to fill in these files correctly
+for your board and protocol you intend to use (see the board and protocol 
+descriptions in this file below or the example scripts in the 'etc' directory).
+After filling in these files, other files will appear in the directory for 
+setting the various hardware- and protocol-related informations (for example
+irq and io addresses, keepalive values etc.) These files are set to default 
+values upon creation, so you don't necessarily have to change all of them.
+
+When you're ready with filling in the files in the comx[n] directory, you can
+configure the corresponding network interface with the standard network 
+configuration utilites. If you're unble to bring the interfaces up, look up
+the various kernel log files on your system, and consult the messages for
+a probable reason.
+
+EXAMPLE
+
+To create the interface 'comx0' which is the first channel of a COMX card:
+
+insmod comx 
+# insmod comx-hw-comx ; insmod comx-proto-hdlc  (these are usually
+autoloaded if you use the kernel module loader)
+
+mkdir /proc/comx/comx0
+echo comx >/proc/comx/comx0/boardtype
+echo 0x360 >/proc/comx/comx0/io		<- jumper-selectable I/O port 
+echo 0x0a >/proc/comx/comx0/irq		<- jumper-selectable IRQ line
+echo 0xd000 >/proc/comx/comx0/memaddr	<- software-configurable memory
+					   address. COMX uses 64 KB, and this
+					   can be: 0xa000, 0xb000, 0xc000, 
+					   0xd000, 0xe000. Avoid conflicts
+					   with other hardware.
+cat </etc/siol1.rom >/proc/comx/comx0/firmware <- the firmware for the card
+echo HDLC >/proc/comx/comx0/protocol	<- the data-link protocol
+echo 10 >/proc/comx/comx0/keepalive	<- the keepalive for the protocol
+ifconfig comx0 1.2.3.4 pointopoint 5.6.7.8 netmask 255.255.255.255 <-
+					   finally configure it with ifconfig
+Check its status:
+cat /proc/comx/comx0/status
+
+If you want to use the second channel of this board:
+
+mkdir /proc/comx/comx1
+echo comx >/proc/comx/comx1/boardtype
+echo 0x360 >/proc/comx/comx1/io	
+echo 10 >/proc/comx/comx1/irq		
+echo 0xd000 >/proc/comx/comx1/memaddr
+echo 1 >/proc/comx/comx1/channel	<- channels are numbered 
+					   as 0 (default) and 1
+
+Now, check if the driver recognized that you're going to use the other
+channel of the same adapter:
+
+cat /proc/comx/comx0/twin
+comx1
+cat /proc/comx/comx1/twin
+comx0
+
+You don't have to load the firmware twice, if you use both channels of
+an adapter, just write it into the channel 0's /proc firmware file.
+
+Default values: io 0x360 for COMX, 0x320 (HICOMX), irq 10, memaddr 0xd0000
+
+THE LOCOMX HARDWARE DRIVER
+
+The LoCOMX driver doesn't require firmware, and it doesn't use memory either,
+but it uses DMA channels 1 and 3. You can set the clock rate (if enabled by
+jumpers on the board) by writing the kbps value into the file named 'clock'.
+Set it to 'external' (it is the default) if you have external clock source.
+
+(Note: currently the LoCOMX driver does not support the internal clock)
+
+THE COMX, CMX AND HICOMX DRIVERS
+
+On the HICOMX, COMX and CMX, you have to load the firmware (it is different for
+the three cards!). All these adapters can share the same memory
+address (we usually use 0xd0000). On the CMX you can set the internal
+clock rate (if enabled by jumpers on the small adapter boards) by writing
+the kbps value into the 'clock' file. You have to do this before initializing
+the card. If you use both HICOMX and CMX/COMX cards, initialize the HICOMX
+first. The I/O address of the HICOMX board is not configurable by any
+method available to the user: it is hardwired to 0x320, and if you have to 
+change it, consult ITC-Pro Ltd.
+
+THE MIXCOM DRIVER
+
+The MixCOM board doesn't require firmware, the driver communicates with
+it through I/O ports. You can have three of these cards in one machine.
+
+THE HDLC LINE PROTOCOL DRIVER
+
+There's only one configurable parameter with this protocol: the 'keepalive'
+value. You can set this in seconds or set to 'off'. Agree with the administrator
+of your peer router on this setting. The default is 10 (seconds).
+
+EXAMPLE
+
+(setting up hw parameters, see above)
+echo hdlc >/proc/comx/comx0/protocol
+echo 10 >/proc/comx/comx0/keepalive	<- not necessary, 10 is the default
+ifconfig comx0 1.2.3.4 pointopoint 5.6.7.8 netmask 255.255.255.255
+
+
+THE PPP LINE PROTOCOL DRIVER
+
+To use this driver, you have to have ppp-2.3.4, and have a modified version of
+pppd (this pppd will work as async pppd to, the modifiactions merely relax 
+some restricions in order to be able to use non-async lines too.
+If configured, this driver can use Van Jacobson TCP header compression (you'll
+need the slhc.o module for this).
+Additionaly to use this protocol, enable async ppp in your kernel config, and
+create the comx device special files in /dev. They're character special files
+with major 88, and their names must be the same as their network interface
+counterparts (i.e /dev/comx0 with minor 0 corresponds interface comx0 and so
+on).
+
+EXAMPLE
+
+(setting up hw parameters, see above)
+echo ppp >/proc/comx/comx0/protocol
+ifconfig comx0 up
+pppd comx0 1.2.3.4:5.6.7.8 persist	<- with this option pppd won't exit
+					   when the line goes down
+
+THE LAPB LINE PROTOCOL DRIVER
+
+For this, you'll need to configure LAPB support (See 'LAPB Data Link Driver' in
+'Network options' section) into your kernel (thanks to Jonathan Naylor for his 
+excellent implementation). 
+comxlapb.o provides the following files in the appropriate directory
+(the default values in parens): t1 (5), t2 (1), n2 (20), mode (DTE, STD) and
+window (7). Agree with the administrator of your peer router on these
+settings (most people use defaults, but you have to know if you are DTE or
+DCE).
+
+EXAMPLE
+
+(setting up hw parameters, see above)
+echo lapb >/proc/comx/comx0/protocol
+echo dce >/proc/comx/comx0/mode		<- DCE interface in this example
+ifconfig comx0 1.2.3.4 pointopoint 5.6.7.8 netmask 255.255.255.255
+
+
+THE FRAME RELAY PROTOCOL DRIVER
+
+You DON'T need any other frame relay related modules from the kernel to use
+COMX-Frame Relay. This protocol is a bit more complicated than the others, 
+because it allows to use 'subinterfaces' or DLCIs within one physical device.
+First you have to create the 'master' device (the actual physical interface)
+as you would do for other protocols. Specify 'frad' as protocol type.
+Now you can bring this interface up by saying 'ifconfig comx0 up' (or whatever
+you've named the interface). Do not assign any IP address to this interface
+and do not set any routes through it.
+Then, set up your DLCIs the following way: create a comx interface for each
+DLCI you intend to use (with mkdir), and write 'dlci' to the 'boardtype' file, 
+and 'ietf-ip' to the 'protocol' file. Currently, the only supported 
+encapsulation type is this (also called as RFC1294/1490 IP encapsulation).
+Write the DLCI number to the 'dlci' file, and write the name of the physical
+COMX device to the file called 'master'. 
+Now you can assign an IP address to this interface and set routes using it.
+See the example file for further info and example config script.
+Notes: this driver implements a DTE interface with partially implemented
+Q933a LMI.
+You can find an extensively commented example in the 'etc' directory.
+
+FURTHER /proc FILES
+
+boardtype:
+Type of the hardware. Valid values are:
+ 'comx', 'hicomx', 'locomx', 'cmx'.
+
+protocol:
+Data-link protocol on this channel. Can be: HDLC, LAPB, PPP, FRAD
+
+status:
+You can read the channel's actual status from the 'status' file, for example
+'cat /proc/comx/comx3/status'.
+
+lineup_delay:
+Interpreted in seconds (default is 1). Used to avoid line jitter: the system
+will consider the line status 'UP' only if it is up for at least this number
+of seconds.
+
+debug: 
+You can set various debug options through this file. Valid options are:
+'comx_events', 'comx_tx', 'comx_rx', 'hw_events', 'hw_tx', 'hw_rx'.
+You can enable a debug options by writing its name prepended by a '+' into
+the debug file, for example 'echo +comx_rx >comx0/debug'. 
+Disabling an option happens similarly, use the '-' prefix 
+(e.g. 'echo -hw_rx >debug').
+Debug results can be read from the debug file, for example: 
+tail -f /proc/comx/comx2/debug
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/ip-sysctl.txt linux.14p16/Documentation/networking/ip-sysctl.txt
--- linux.vanilla/Documentation/networking/ip-sysctl.txt	Sat Aug 14 02:26:08 1999
+++ linux.14p16/Documentation/networking/ip-sysctl.txt	Mon Dec 13 18:50:28 1999
@@ -156,6 +156,14 @@
 proxy_arp - BOOLEAN
 	Do proxy arp.
 
+hidden - BOOLEAN
+	Hide addresses attached to this device from another devices.
+	Such addresses will never be selected by source address autoselection
+	mechanism, host does not answer broadcast ARP requests for them,
+	does not announce it as source address of ARP requests,	but they
+	are still reachable via IP. This flag is activated only if it is
+	enabled both in specific device section and in "all" section.
+
 shared_media - BOOLEAN
 	undocumented.
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/sis900.txt linux.14p16/Documentation/networking/sis900.txt
--- linux.vanilla/Documentation/networking/sis900.txt	Thu Jan  1 01:00:00 1970
+++ linux.14p16/Documentation/networking/sis900.txt	Thu Dec  9 15:34:40 1999
@@ -0,0 +1,460 @@
+  SiS 900/7016 Fast Ethernet Device Driver
+  by Ollie Lho (ollie@sis.com.tw)
+  November 4, 1999. Document Revision: 0.1
+
+  This document gives some information on installation and usage of SiS
+  900/7016 device driver under Linux.
+  ______________________________________________________________________
+
+  Table of Contents
+
+
+  1. Introduction
+
+  2. License
+
+  3. Changes
+
+  4. Tested Environment
+
+  5. Files in This Rackage
+
+  6. Installation
+
+     6.1 Kernel version later than 2.2.11 and 2.3.15
+        6.1.1 Building the driver as loadable module
+        6.1.2 Building the driver into kernel
+     6.2 Earlier Kernel Version in 2.2.x and 2.3.x Series
+
+  7. Known Problems and Bugs
+
+  8. Revision History
+
+  9. Acknowledgements
+
+
+
+  ______________________________________________________________________
+
+  1.  Introduction
+
+  This document describes the revision 1.06 of SiS 900/7016 Fast
+  Ethernet device driver under Linux. The driver is developed by Silicon
+  Integrated System Corp. and distributed freely under the GNU General
+  Public License (GPL). The driver can be compiled as a loadable module
+  and used under Linux kernel version 2.2.x. With minimal changes, the
+  driver can also be used under 2.3.x kernel, please see section
+  ``Installation''. If you are intended to use the driver for earlier
+  kernels, you are on your own.
+
+  The driver is tested with usual TCP/IP applications including FTP,
+  Telnet, Netscape etc. and is used constantly by the developers.
+
+  Please send all comments/fixes/questions to Ollie Lho.
+
+
+  2.  License
+
+
+
+
+
+
+
+
+
+
+          Copyright (C) 1999 Silicon Integrated System Corp.
+
+          This program is free software; you can redistribute it and/or modify
+          it under the terms of the GNU General Public License as published by
+          the Free Software Foundation; either version 2 of the License, or
+          (at your option) any later version.
+
+          This program is 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+
+
+
+  3.  Changes
+
+  Changes made in Revision 1.06
+
+  1. Separation of sis900.c and sis900.h in order to move most constant
+     definition to sis900.h (many of those constants were corrected)
+
+  2. Clean up PCI detection, the pci-scan from Donald Becker were not
+     used, just simple pci_find_*.
+
+  3. MII detection is modified to support multiple mii transceiver.
+
+  4. Bugs in read_eeprom, mdio_* were removed.
+
+  5. Lot of sis900 irrelevant comments were removed/changed and more
+     comments were added to reflect the real situation.
+
+  6. Clean up of physical/virtual address space mess in buffer
+     descriptors.
+
+  7. Better transmit/receive error handling.
+
+  8. The driver now uses zero-copy single buffer management scheme to
+     improve performance.
+
+  9. Names of variables were changed to be more consistent.
+
+ 10. Clean up of auo-negotiation and timer code.
+
+ 11. Automatic detection and change of PHY on the fly.
+
+
+  4.  Tested Environment
+
+  This driver is developed on the following hardware
+
+  o  Intel Celeron 336 with SiS 620 (rev 02) chipset
+
+  o  SiS 900 (rev 01) and SiS 7016/7014 Fast Ethernet Card
+
+     and tested with these software environments
+
+  o  Red Hat Linux version 6.0
+
+  o  Linux kernel version 2.2.13
+
+  o  Netscape version 4.6
+
+  o  NcFTP 3.0.0 beta 18
+
+  o  Samba version 2.0.3
+
+
+  5.  Files in This Rackage
+
+  In the package you can find these files:
+
+
+     sis900-2.2.x.c
+        Driver source for kernel 2.2.x
+
+     sis900-2.3.x.c
+        Driver source for kernel 2.3.x
+
+     sis900.h
+        Header file for both 2.2.x and 2.3.x kernel
+
+     sis900.sgml
+        Linux-Doc SGML source of the document
+
+
+  6.  Installation
+
+  Before trying to install the driver, be sure to get the latest
+  revision from SiS' Home Page.  If you have no prior experience in
+  networking under Linux, please read Ethernet HOWTO and Networking
+  HOWTO available from Linux Documentation Project (LDP).
+
+  The installation procedure are different according to your kernel
+  versions.
+
+
+  6.1.  Kernel version later than 2.2.11 and 2.3.15
+
+  The driver is bundled in release later than 2.2.11 and 2.3.15 so this
+  is the most easy case.  Be sure you have the appropriate packages for
+  compiling kernel source.  Those packages are listed in
+  Document/Changes in kernel source distribution. There are two
+  alternative ways to install the driver
+
+
+  6.1.1.  Building the driver as loadable module
+
+  To build the driver as a loadable kernel module you have to
+  reconfigure the kernel to activate network support by
+
+
+
+       make config
+
+
+
+
+  Choose "Network Device Support" to "Y" and "Ethernet Support" to "Y".
+  Then you have to choose "SiS 900 Fast Ethernet Adapter Support" to
+  "M".
+
+  After reconfiguring the kernel, you can make the driver module by
+
+
+       make modules
+
+
+
+
+  The driver should be compiled with no errors. After compiling the
+  driver, the driver can be installed to proper place by
+
+
+
+       make modules_install
+
+
+
+
+  Load the driver into kernel by
+
+
+
+       insmod sis900
+
+
+
+
+  When loading the driver into memory, some information message can be
+  view by
+
+
+
+       dmesg
+
+
+
+
+  or
+
+
+       cat /var/log/message
+
+
+
+
+  If the driver is loaded properly you will have messages similar to
+  this:
+
+
+
+       sis900.c: v1.06  11/04/99
+       eth0: SiS 900 PCI Fast Ethernet at 0xd000, IRQ 10, 00:00:e8:83:7f:a4.
+       eth0: SiS 900 Internal MII PHY transceiver found at address 1.
+
+
+
+
+  showing the version of the driver and the results of probing routine.
+
+  Once the driver is loaded, network can be brought up by
+
+
+
+       /sbin/ifconfig eth0 IPADDR broadcast BROADCAST netmask NETMASK
+
+
+
+
+
+  where IPADDR, BROADCAST, NETMASK are your IP address, broadcast
+  address and netmask respectively. For more information on how to
+  configure network interface, please refer to Networking HOWTO.
+
+  The link status is also shown by kernel messages. For example, after
+  the network interface is activated, you may have the message:
+
+
+
+       eth0: Using SiS 900 Internal MII PHY as default
+       eth0: Media Link On 100mbps full-duplex
+
+
+
+
+  If you try to unplug the twist pair (TP) cable you will get
+
+
+
+       eth0: Media Link Off
+
+
+
+
+  indicating that the link is failed.
+
+
+  6.1.2.  Building the driver into kernel
+
+  If you want to make the driver into kernel, choose "Y" rather than "M"
+  on "SiS 900 Fast Ethernet Adapter Support" when configuring the
+  kernel.  Build the kernel image in the usual way
+
+
+
+       make dep
+
+       make clean
+
+       make bzlilo
+
+
+
+
+  Next time the system reboot, you have the driver in memory.
+
+
+  6.2.  Earlier Kernel Version in 2.2.x and 2.3.x Series
+
+  Installing the driver for earlier kernels in 2.2.x and 2.3.x series
+  requires a little bit more work. First you have to copy sis900-2.x.x.c
+  to /usr/src/linux/drivers/net/ and you have to modify some files
+  manually (sorry !! no patch available !!)
+
+  in Space.c, add
+
+
+       extern int sis900_probe(struct device *dev);
+
+       ...
+
+       #ifdef CONFIG_SIS900
+               {sis900_probe,0},
+       #endif
+
+
+  in Config.in add
+
+
+       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+               ... //other adapter drivers
+               tristate 'SiS 900 PCI Fast Ethernet Adapter Support' CONFIG_SIS900
+               ... //other adapter drivers
+       fi
+
+
+
+
+  in Makefile add
+
+
+       ifeq ($(CONFIG_SIS900),y)
+               L_OBJS += sis900.o
+       else
+               ifeq ($(CONFIG_SIS900),m)
+                       M_OBJS += sis900.o
+               endif
+       endif
+
+
+
+
+  After modifying these files, the driver can be build as described in
+  the previous section.
+
+
+  7.  Known Problems and Bugs
+
+  There are some known problems and bugs. If you find any other bugs
+  please mail to ollie@sis.com.tw
+
+  1. AM79C901 HomePNA PHY is not thoroughly tested, there may be some
+     bugs in the "on the fly" change of transceiver.
+
+  2. A bug is hidden somewhere in the receive buffer management code,
+     the bug causes NULL pointer reference in the kernel. This fault is
+     caught before bad things happen and reported with the message:
+
+
+       eth0: NULL pointer encountered in Rx ring, skipping
+
+
+
+
+  which can be viewed with dmesg or cat /var/log/message.
+
+
+  8.  Revision History
+
+
+  o  November 4, 1999, Revision 1.06, Second release, lots of clean up
+     and optimization.
+
+  o  August 8, 1999, Revision 1.05, Initial Public Release
+
+
+  9.  Acknowledgements
+
+  This driver was originally derived form Donald Becker's pci-skeleton
+  and rtl8139 drivers. Donald also provided various suggestion regarded
+  with improvements made in revision 1.06.
+
+  The 1.05 revision was created by Jim Huang, AMD 79c901 support was
+  added by Chin-Shan Li.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/sk98lin.txt linux.14p16/Documentation/networking/sk98lin.txt
--- linux.vanilla/Documentation/networking/sk98lin.txt	Thu Jan  1 01:00:00 1970
+++ linux.14p16/Documentation/networking/sk98lin.txt	Thu Dec  9 15:34:40 1999
@@ -0,0 +1,480 @@
+(C)Copyright 1999 SysKonnect.
+===========================================================================
+
+sk98lin.txt created 11-Nov-1999
+
+Readme File for sk98lin.o v3.02
+SK-NET Gigabit Ethernet Adapter SK-98xx Driver for Linux
+
+This file contains
+(1) OVERVIEW
+(2) REQUIRED FILES
+(3) INSTALLATION
+(4) INCLUSION OF THE ADAPTER AT SYSTEM START
+(5) DRIVER PARAMETERS
+(6) LARGE FRAME SUPPORT
+(7) TROUBLESHOOTING
+(8) HISTORY
+
+===========================================================================
+
+
+
+(1) OVERVIEW
+============
+
+The sk98lin driver supports the SysKonnect SK-NET Gigabit Ethernet
+Adapter SK-98xx family on Linux 2.2.x.
+It has been tested with Linux on Intel/x86 and ALPHA machines.
+From v3.02 on, the driver is integrated in the linux kernel source.
+***
+
+
+(2) REQUIRED FILES
+==================
+
+The linux kernel source.
+No additional files required.
+***
+
+
+(3) INSTALLATION
+================
+
+The following steps describe the actions that are required to install
+the driver and to start it manually. These steps should be carried
+out for the initial driver setup. Once confirmed to be ok, they can
+be included in the system start which is described in the next
+chapter.
+
+NOTE 1: You must have 'root' access to the system to perform
+        the following tasks.
+NOTE 2:	IMPORTANT: In case of problems, please read the section
+	"Troubleshooting" below.
+
+1) The driver can either be integrated into the kernel or it can
+   be compiled as a module.
+   Select the appropriate option during the kernel configuration.
+   For use as a module, your kernel must have
+   'loadable module support' enabled.
+   For automatic driver start, you also need 'Kernel module loader'
+   enabled.
+   Configure those options, build and install the new kernel. If you
+   choose to use the driver as a module, do "make modules" and
+   "make modules_install".
+   Reboot your system.
+
+4) Load the module manually by entering:
+       insmod sk98lin.o
+   If the SysKonnect SK-98xx adapter is installed in your
+   computer and you have a /proc filesystem, running the command
+   'more /proc/net/dev' should produce an output containing a
+   line with the following format:
+       eth0:    0    0 ...
+   which means that your adapter has been found and initialized.
+   
+   NOTE 1: If you have more than one SysKonnect SK-98xx adapter, the
+           adapters will be listed as 'eth0', 'eth1', 'eth2', etc.
+           For each adapter, repeat the steps 5) and 6).
+   NOTE 2: If you have other Ethernet adapters installed,
+           your SysKonnect SK-98xx adapter can be mapped to 'eth1' or
+	   'eth2' ...
+	   The module installation message (in system logfile or
+	   on console, depending on /etc/syslog.conf) prints a line
+	   for each adapter that is found, containing the
+	   corresponding 'ethX'.
+
+5) Select an IP address and assign it to the respective adapter by
+   entering:
+       ifconfig eth0 <ip-address>
+   This causes the adapter to connect to the ethernet. The solitary
+   yellow LED at the adapter is now active, the link status LED of
+   the primary port is on and the link status LED of the secondary
+   port (on dual port adapters) is blinking (only if the laters are
+   connected to a switch or hub).
+   You will also get a status message on the console saying
+   "ethX: network connection up using port Y" and indicating
+   the selected connection parameters.
+   
+   NOTE: If you are in doubt about IP addresses, ask your network
+         administrator for assistance.
+
+6) Your adapter should now be fully operational.
+   Use 'ping <otherstation>' to verify the connection to other
+   computers on your network.
+   By entering 'ifconfig', you can check the number of packets sent
+   and received by your adapter and additional some other information
+   regarding the adapter configuration.
+
+7) The driver module can be stopped and unloaded using the following
+   commands:
+       ifconfig eth0 down
+       rmmod sk98lin
+***
+
+
+(4) INCLUSION OF THE ADAPTER AT SYSTEM START
+============================================
+
+Since a large number of different Linux distributions are 
+available, we are unable to describe a general installation procedure
+for the driver module.
+Because the driver is now integrated in the kernel, installation should
+be easy, using the standard mechanism of your distribution.
+Refer to the distribution's manual for installation of ethernet adapters.
+***
+
+
+(5) DRIVER PARAMETERS
+=====================
+
+Parameters can be set at the command line while loading the
+module with 'insmod'. The configuration tools of some distributions
+can also give parameters to the driver module.
+If you use the kernel module loader, you can set driver parameters
+in the file /etc/conf.modules. Insert a line of the form:
+
+options sk98lin ...
+
+For "...", use the same syntax as described below for the command
+line paramaters of insmod.
+You either have to reboot your computer or unload and reload
+the driver to activate the new parameters.
+The syntax of the driver parameters is:
+
+insmod sk98lin parameter=value1[,value2[,value3...]]
+
+value1 is for the first adapter, value2 for the second one etc.
+All Parameters are case sensitive, so write them exactly as
+shown below.
+
+Sample: Suppose you have two adapters. You want to set AutoNegotiation
+	on Port A of the first adapter to ON and on Port A of the
+	second adapter to OFF.
+	You also want to set DuplexCapabilities on Port A of the first
+	adapter to FULL and on Port A of the second adapter to HALF.
+	You must enter:
+
+	insmod sk98lin.o AutoNeg_A=On,Off DupCap_A=Full,Half
+
+NOTE: The number of adapters that can be configured this way is
+      limited in the driver (file skge.c, constant SK_MAX_CARD_PARAM).
+      The current limit is 16. If you happen to install
+      more adapters, adjust this and recompile.
+
+
+5.1 Per-Port Parameters
+-----------------------
+Those setting are available for each port on the adapter.
+In the following description, '?' stands for the port for
+which you set the parameter (A or B).
+
+- Auto Negotiation
+  Parameter:	AutoNeg_?
+  Values:	On, Off, Sense
+  Default:	Sense
+  
+  The "Sense"-mode finds out automatically whether the link
+  partner supports autonegotiation or not.
+
+- Duplex Capabilities
+  Parameter:	DupCap_?
+  Values:	Half, Full, Both
+  Default:	Both
+
+  This parameters is relevant only if autonegotiation for
+  this port is not "Sense". If autonegotiation is "On", all
+  three values are possible. If it is "Off", only "Full" and
+  "Half" are allowed.
+  It is usefull if your link partner does not support all
+  possible combinations.
+
+- Flow Control
+  Parameter:	FlowCtrl_?
+  Values:	Sym, SymOrRem, LocSend, None
+  Default:	SymOrRem
+
+  This parameter can be used to set the flow control capabilities
+  that the port reports during autonegotiation.
+  The meaning of the different modes is:
+-- Sym = Symetric: both link partners are allowed to send PAUSE frames
+-- SymOrRem = SymetricOrRemote: both or only remote partner are allowed
+   to send PAUSE frames
+-- LocSend = LocalSend: only local link partner is allowed to send
+   PAUSE frames
+-- None: no link partner is allowed to send PAUSE frames
+  
+  NOTE: This parameter is ignored if autonegotiation is set to "Off".
+
+- Role in Master-Slave-Negotiation (1000Base-T only).
+  Parameter:    Role_?
+  Values:       Auto, Master, Slave
+  Default:      Auto
+  
+  This parameter is only valid for the SK-9821 and SK-9822 adapters.
+  For two 1000Base-T ports to communicate, one must take the role as
+  master (providing timing information), while the other must be slave.
+  Normally, this is negotiated between the two ports during link 
+  establishment. If this should ever fail, you can force a port to a
+  specific setting with this parameter.
+  
+
+5.2 Per-Adapter Parameters
+--------------------------
+
+- Preferred Port
+  Parameter:	PrefPort
+  Values:	A, B
+  Default:	A
+
+  This is used to force the preferred port to A or B (on two-port NICs).
+  The preferred port is the one that is used if both are detected as
+  fully functional.
+
+- RLMT (Redundant Link Management Technology) Mode
+  Parameter:	RlmtMode
+  Values:	CheckLinkState,CheckLocalPort, CheckSeg
+  Default:	CheckLinkState
+
+  RLMT (the driver part that decides which port to use) knows three
+  ways of checking if a port is available for use:
+
+-- CheckLinkState = Check link state only: RLMT uses the link state
+   reported by the adapter hardware for each individual port to determine
+   whether a port can be used for all network traffic or not.
+
+-- CheckLocalPort - Check other port on adapter: RLMT sends test frames
+   from each port to each other port and checks if they are received by
+   the other port, respectively. Thus, the ports must be connected to the
+   network such that LLC test frames can be exchanged between them
+   (i.e. there must be no routers between the ports).
+
+-- CheckSeg - Check other port and segmentation: RLMT checks the other port
+   and in addition requests information from the Gigabit Ethernet
+   switch next to each port to see if the network is segmented between
+   the ports. Thus, this mode is only to be used if you have Gigabit
+   Ethernet switches installed in your network that have been configured
+   to use the Spanning Tree protocol.
+
+  NOTE: The modes CheckLocalPort and CheckSeg are meant to operate in
+        configurations where a network path between the ports on one
+        adapter exists. Especially, they are not designed to work where
+        adapters are connected back-to-back.
+***
+
+
+(6) LARGE FRAME SUPPORT
+=======================
+
+Large frames (also called jumbo frames) are now supported by the
+driver. This can result in a greatly improved throughput if
+transfering large amounts of data.
+To enable large frames, set the MTU (maximum transfer unit)
+of the interface to the value you wish (up to 9000). The command
+for this is:
+  ifconfig eth0 mtu 9000
+This will only work if you have two adapters connected back-to-back
+or if you use a switch that supports large frames. When using a
+switch, it should be configured to allow large frames, without
+autonegotiating for them.
+The setting must be done on all adapters that can be reached by
+the large frames. If one adapter is not set to receive large frames,
+it will simply drop them.
+
+NOTE: If you look at the statistics (with netstat) in large frame
+      mode while there is traffic on the net, you will see the
+      RX error counter go up. This is because the adapter hardware
+      counts received large frames as errors, although they are
+      received correctly. So ignore this counter in that case.
+
+You can switch back to the standard ethernet frame size with:
+  ifconfig eth0 mtu 1500
+***
+
+
+(7) TROUBLESHOOTING
+===================
+
+If you run into problems during installation, check those items:
+
+Problem:  The SK-98xx adapter can not be found by the driver.
+Reason:   Look in /proc/pci for the following entry:
+             'Ethernet controller: SysKonnect SK-98xx ...'
+	  If this entry exists, then the SK-98xx adapter has been
+	  found by the system and should be able to be used.
+	  If this entry does not exist or if the file '/proc/pci'
+	  is not there, then you may have a hardware problem or PCI
+	  support may not be enabled in your kernel.
+	  The adapter can be checked using the diagnostic program
+	  which is available from the SysKonnect web site:
+	      www.syskonnect.de
+	  Some COMPAQ machines have a problem with PCI under
+	  Linux. This is described in the 'PCI howto' document
+	  (included in some distributions or available from the
+	  www, e.g. at 'www.linux.org'). This might be fixed in the
+	  2.2.x kernel series (I've not tested it).
+
+Problem:  Programs such as 'ifconfig' or 'route' can not be found or
+          you get an error message 'Operation not permitted'.
+Reason:   You are not logged in as user 'root'. Logout and 
+          login as root or change to root via 'su'.
+
+Problem:  Using the command 'ping <address>', you get a message
+          "ping: sendto: Network is unreachable".
+Reason:   Your route is not set up correct.
+	  If you are using RedHat, you probably forgot
+	  to set up the route in 'network configuration'.
+	  Check the existing routes with the 'route' command
+	  and check if there is an entry for 'eth0' and if
+	  it is correct.
+
+Problem:  The driver can be started, the adapter is connected
+          to the network, but you can not receive or transmit
+          any packet; e.g. 'ping' does not work.
+Reason:   You have an incorrect route in your routing table.
+          Check the routing table with the command 'route' and
+	  read the manual pages about route ('man route').
+NOTE:	  Although the 2.2.x kernel versions generate the routing
+	  entry automatically, you may have problems of this kind
+	  here, too. We found a case where the driver started correct
+	  at system boot, but after removing and reloading the driver,
+	  the route of the adapter's network pointed to the 'dummy0'
+	  device and had to be corrected manually.
+	  
+Problem:  You want to use your computer as a router between
+          multiple IP subnetworks (using multiple adapters), but
+	  you can not reach computers in other subnetworks.
+Reason:   Either the router's kernel is not configured for IP
+	  forwarding or there is a problem with the routing table
+	  and gateway configuration in at least one of the
+	  computers.
+
+Problem:  At the start of the driver, you get an error message:
+	  "eth0: -- ERROR --
+	   Class: internal Software error
+	   Nr: 0xcc
+	   Msg: SkGeInitPort() cannot init running ports"
+Reason:	  You are using a driver compiled for single processor
+	  machines on an multiprocessor machine with SMP (Symetric
+	  MultiProcessor) kernel.
+	  Configure your kernel appropriate and recompile the kernel or
+	  the modules.
+
+If your problem is not listed here, please contact SysKonnect's technical
+support for help (linux@syskonnect.de).
+When contacting our technical support, please ensure that the
+following information is available:
+- System Manufacturer and Model
+- Boards in your system
+- Distribution
+- Kernel version
+***
+
+
+(8) HISTORY
+===========
+
+VERSION 3.02
+Problems fixed:
+- None
+New Features:
+- Integration in linux kernel source.
+Known limitations:
+- None
+
+VERSION 3.02
+Problems fixed:
+- None
+New Features:
+- Full source release
+Known limitations:
+- None
+
+VERSION 3.00
+Problems fixed:
+- None
+New Features:
+- Support for 1000Base-T adapters (SK-9821 and SK-9822)
+Known limitations:
+- None
+
+VERSION 1.07
+Problems fixed:
+- RlmtMode parameter value strings were wrong (#10437)
+- Driver sent too many RLMT frames (#10439)
+- Driver did not recognize network segmentation (#10440)
+- RLMT switched too often on segmented network (#10441)
+Known limitations:
+- None
+
+VERSION 1.06
+Problems fixed:
+- System panic'ed after some time when running with 
+  RlmtMode=CheckOtherLink or RlmtMode=CheckSeg (#10421)
+  Panic message: "Kernel panic: skput: over ... dev: eth0"
+- Driver did not switch back to default port when connected
+  back-to-back (#10422).
+Changes:
+- RlmtMode parameter names have changed
+New features:
+- There is now a version for ALPHA processors
+Known limitations:
+- None
+
+VERSION 1.05
+Problems fixed:
+- Driver failed to load on kernels with version information
+  for module symbols enabled
+Known limitations:
+- None
+
+VERSION 1.04
+Problems fixed:
+- Large frame support does work now (no autonegotiation
+  support for large frames, just manually selectable)
+New Features:
+- Receive checksumming in hardware
+- Performance optimizations
+  Some numbers (on two PII-400 machines, back-to-back):
+  netpipe: 300 MBit/sec, with large frames: 470 MBit/sec
+  ttcp:  38 MByte/sec, with large frames: 60 MByte/sec
+  ttcp (UDP send): 66 MByte/sec, with large frames: 106 MByte/sec
+Known limitations:
+- None
+
+VERSION 1.03
+Problems fixed:
+- Unloading with "rmmod" caused segmentation fault (#10415)
+- The link LED flickered from time to time, if no link was
+  established (#10402)
+- Installation problems with RedHat 6.0 (#10409)
+New Features:
+- Connection state ouput at "network connection up"
+Known limitations:
+- None
+
+VERSION 1.02
+Problems fixed:
+- Failed with multiple adapters
+- Failed with Single Port adapters
+- Startup string was only displayed if adapter found
+- No link could be established on certain switches when the switches were
+  rebooted. (#10377)
+Known limitations:
+- Segmentation fault at "rmmod" with kernel 2.2.3 on some machines
+
+VERSION 1.01
+Problems fixed:
+- Sensor status was not set back to 'ok' after 'warning/error'. (#10386)
+Changes:
+- improved parallelism in driver
+
+VERSION 1.00
+Known limitations:
+- not tested with all kernel versions (I don't have that much time :-)
+- only x86 version available (if you need others, ask for it)
+- source code not completely available
+
+***End of Readme File***
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/tlan.txt linux.14p16/Documentation/networking/tlan.txt
--- linux.vanilla/Documentation/networking/tlan.txt	Fri Jul 24 19:15:05 1998
+++ linux.14p16/Documentation/networking/tlan.txt	Thu Dec  9 15:34:40 1999
@@ -1,15 +1,26 @@
-TLAN driver for Linux, version 1.0
-README
 
-Well, I'm back.  The TLAN driver seems pretty stable, so I'm
-declaring this cycle of development finished, and calling the
-driver 1.0.  I will, of course continue to work on improving
-the driver, and work towards a 2.0 release.
 
+I haven't had any time to do anything for a long time, and this isn't
+likely to change.  So there's a driver here for anyone looking to
+carry forward a project :)
+
+For those who are looking for help, I can't.  I haven't looked at
+a kernel since the early 2.0 series, so I won't know what's going on.
+Your best chance at help would be joining the TLAN mailing list and
+posting your question there.
+
+You can join by sending "subscribe tlan" in the body of an email to
+majordomo@vuser.vu.union.edu.
+
+Thanks to those who have (and who will ;) put work in to keep the TLAN
+driver working as the kernel moves on.
 
 James
 james@sovereign.org
 
+
+TLAN driver for Linux, version 1.0
+README
 
 
 I.  Supported Devices.
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/wan-router.txt linux.14p16/Documentation/networking/wan-router.txt
--- linux.vanilla/Documentation/networking/wan-router.txt	Thu May 21 02:54:34 1998
+++ linux.14p16/Documentation/networking/wan-router.txt	Wed Dec 15 16:09:50 1999
@@ -1,19 +1,26 @@
 ------------------------------------------------------------------------------
 WAN Router for Linux Operating System
 ------------------------------------------------------------------------------
+Version 2.1.1 - Nov 08, 1999
+Version 2.0.8 - Nov 02, 1999
+Version 2.0.7 - Aug 26, 1999
+Version 2.0.6 - Aug 17, 1999
+Version 2.0.5 - Aug 12, 1999
+Version 2.0.4 - Nov 26, 1998
+Version 2.0.3 - Aug 25, 1998
+Version 2.0.2 - Dec 09, 1997
 Version 2.0.1 - Nov 28, 1997
 Version 2.0.0 - Nov 06, 1997
 Version 1.0.3 - June 3, 1997
 Version 1.0.1 - January 30, 1997
-Author: Jaspreet Singh <jaspreet@sangoma.com>
-	Gene Kozin <genek@compuserve.com>
-Copyright (c) 1995-1997 Sangoma Technologies Inc.
+Author: Nenad Corbic <ncorbic@sangoma.com>
+Copyright (c) 1995-1999 Sangoma Technologies Inc.
 ------------------------------------------------------------------------------
 
 
 WARNING:  This Version of WANPIPE supports only the S508 and S508/FT1 cards.  
 IF YOU OWN A S502E OR A S508 CARD THEN PLEASE CONTACT SANGOMA TECHNOLOGIES FOR 
-AN UPGRADE.
+AN UPGRADE.  ONLY THE BiSYNC STREAMING CODE IS SUPPORTED ON S502E/S503 cards. 
 
 INTRODUCTION
 
@@ -129,11 +136,55 @@
 
 REVISION HISTORY
 
+2.1.1   Nov 09, 1999 		- New code for S514PCI card
+                                - Completely redesigned drivers
+                                  fully tested and optimized.
+
+2.0.8   Nov 02, 1999            - Fixed up the X25API code.
+                                - Clear call bug fixed.i
+                                - Eanbled driver for multi-card
+                                  operation.                                
+
+2.0.7   Aug 26, 1999		- Merged X25API code into WANPIPE.
+				- Fixed a memeory leak for X25API
+				- Updated the X25API code for 2.2.X kernels.
+				- Improved NEM handling.
+
+2.0.6   Aug 17, 1999            - Kernel patch works for both 2.2.10 and 2.2.11 kernels
+                                - Fixed up 2.0.5 installation bugs
+                                - No functional difference between 2.0.6 and 2.0.5         
+
+2.0.5   Aug 12, 1999            - NEW PPP, interrupt drive code
+				- NEW X25 Xpipmon debugger
+				- Comments added to setup scripts
+				- Numerous bug fixes
+
+2.0.4	Nov 26, 1998		- NEW Cisco Dual Port support. 
+				- NEW support for BiSync Streaming API.
+				- NEW support for HDLC (LAPB) API.
+				- WANPIPE provides an API for application 
+				  development using the BSD socket interface.
+
+2.0.3 	Aug 25, 1998		- NEW support for Cisco HDLC, with cpipemon 
+				  utility for monitoring
+				- CIR support for Frame-relay
+				- Support for PAP and CHAP for ppp has been 
+				  implemented
+				- Dynamic IP assignment for PPP
+				- Multiple channel IPX support for Frame-relay 
+				  and X25
+				- Inverse Arp support for Frame-relay
+				- FT1 Configuration utility for linux
+				- Man Pages for router.conf, router, sdladump,
+				  cfgft1, fpipemon, ppipemon and cpipemon
+
+2.0.2	Dev 09, 1997	      - Implemented PAP and CHAP for ppp.
+
 2.0.1	Nov 28, 1997	      -	Protection of "enable_irq()" while
                                 "disable_irq()" has been enabled from any other
                                 routine (for Frame Relay, PPP and X25).
-			      - Added additional Stats for Fpipemon and Ppipemon                              - Improved Load Sharing for multiple boards.
-
+			      - Added additional Stats for Fpipemon and Ppipemon
+                              - Improved Load Sharing for multiple boards.
 
 2.0.0   Nov 07, 1997          - Implemented protection of RACE conditions by
                                 critical flags for FRAME RELAY and PPP.
@@ -173,7 +224,7 @@
 1.0.1	January 30, 1997
 
 			      -	Implemented user-readable status and statistics
-				via /proc file system
+				via /proc filesystem
 
 1.0.0	December 31, 1996
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/wanpipe.txt linux.14p16/Documentation/networking/wanpipe.txt
--- linux.vanilla/Documentation/networking/wanpipe.txt	Tue Apr 28 22:22:04 1998
+++ linux.14p16/Documentation/networking/wanpipe.txt	Wed Dec 15 16:09:50 1999
@@ -1,36 +1,23 @@
 ------------------------------------------------------------------------------
-WANPIPE(tm) Multiprotocol WAN Driver for Linux WAN Router
+Linux WAN Router Utilities Package
 ------------------------------------------------------------------------------
-Release 4.1
-November 17, 1997
-Author: Jaspreet Singh <jaspreet@sangoma.com>
-Copyright (c) 1995-1997 Sangoma Technologies Inc.
+Version 2.1.1
+Nov 08, 1999
+Author: Nenad Corbic <ncorbic@sangoma.com>
+Copyright (c) 1995-1999 Sangoma Technologies Inc.
 ------------------------------------------------------------------------------
 
 INTRODUCTION
 
-WANPIPE(tm) is a family of intelligent multiprotocol 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 a 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 a
-relatively inexpensive, yet high-performance multiprotocol WAN router.  For
-more information about the Linux WAN Router please read the file
-Documentation/networking/wan-router.txt.  You must also obtain the WAN Tools
-package to be able to use the 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
-			or
-	ftp.sangoma.com/pub/linux/wanpipe-X.Y.Z.tgz
-
-The names of the packages differ only due to naming convention.  The 
-functionality of wantools and wanpipe packages are the same.  The latest 
-version of the WAN Drivers is wanpipe-2.0.0.
+This is a set of utilities and shell scripts you need in order to be able to
+use Linux kernel-level WAN Router.  Please read WAN Router User's manual
+(router.txt) and WANPIPE driver documentation found in /usr/lib/router/doc
+directory for installation and configuration instructions.
 
-For technical questions and/or comments please e-mail to jaspreet@sangoma.com.
+You can find the latest version of this software in /pub/linux directory on
+Sangoma Technologies' anonymous FTP server (ftp.sangoma.com). 
+
+For technical questions and/or comments please e-mail to ncorbic@sangoma.com.
 For general inquiries please contact Sangoma Technologies Inc. by
 
 	Hotline:	1-800-388-2475	(USA and Canada, toll free)
@@ -57,117 +44,214 @@
 
 
 
-NEW IN THIS RELEASE
-
- o This Version of WANPIPE supports only the S508 and S508/FT1 cards.  IF YOU
-   OWN A S502E OR A S508 CARD THEN PLEASE CONTACT SANGOMA TECHNOLOGIES FOR AN
-   UPGRADE.
- o Protection of "enable_irq()" while "disable_irq()" has been enabled from 
-   any other routine (for Frame Relay, PPP and X25).
- o Added additional Stats for Fpipemon and Ppipemon.
- o Improved Load Sharing for multiple boards
-
-
-FILE LIST
-
-drivers/net:
-	README.wanpipe	This file
-	sdladrv.c	SDLA support module source code
-	sdla_fr.c	SDLA Frame Relay source code
-	sdla_ppp.c	SDLA PPP source code
-	sdla_x25.c	SDLA X.25 source code
-	sdlamain.c	SDLA support source code
-
-include/linux:
-	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
-	wanpipe.h	WANPIPE API definitions
-	sdladrv.h	SDLA support module API definitions
-	sdlasfm.h	SDLA firmware module definitions
-	router.h	
-
-
-REVISION HISTORY
-
-4.1	November 28, 1997
-        o Protection of "enable_irq()" while "disable_irq()" has been enabled 
-	  from any other routine (for Frame Relay, PPP and X25).
-        o Added additional Stats for Fpipemon and Ppipemon
-	o Improved Load Sharing for multiple boards
-
-
-4.0	November 06, 1997
- 	o Implemented better protection of RACE conditions by critical flags for
- 	  FRAME RELAY, PPP and X25.
- 	o DLCI List interrupt mode implemented for DLCI specific CIR.
- 	o IPX support for FRAME RELAY, PPP and X25.
- 	o IPX Server Support (MARS) for FRAME RELAY, PPP and X25.
- 	o More driver specific stats included. 
-	o MULTICAST for FRAME RELAY and PPP.
-
-3.1.0	January 30, 1997
-
-	o Implemented IOCTL for executing adapter commands.
-	o Fixed a bug in frame relay code causing driver configured as a FR
-	  switch to be stuck in WAN_DISCONNECTED mode.
-
-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
+ACKNOWLEDGEMENTS
 
-	o Added support for LMI and Q.933 frame relay link management
+This product is based on the WANPIPE(tm) Multiprotocol WAN Router developed
+by Sangoma Technologies Inc. for Linux 2.2.x.  Success of the WANPIPE
+together with the next major release of Linux kernel in summer 1996 commanded
+adequate changes to the WANPIPE code to take full advantage of new Linux
+features.
+
+Instead of continuing developing proprietary interface tied to Sangoma WAN
+cards, we decided to separate all hardware-independent code into a separate
+module and defined two levels of interfaces - one for user-level applications
+and another for kernel-level WAN drivers.  WANPIPE is now implemented as a
+WAN driver compliant with the WAN Link Driver interface.  Also a general
+purpose WAN configuration utility and a set of shell scripts was developed to 
+support WAN router at the user level.
+
+Many useful 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).
+
+With the new implementation of the APIs being incorporated into the WANPIPE,
+a special thank goes to Alan Cox in providing insight into BSD sockets.
+
+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.
 
-2.3.0	October 17, 1996
 
-	o All shell scripts use meta-configuration file
-	o Miscellaneous bug fixes
 
-2.2.0	July 16, 1996
+NEW IN THIS RELEASE
 
-	o Compatible with Linux 2.0
-	o Added uninstall script
-	o User's Manual is available in HTML format
+o Renamed startup script to wanrouter
+o Option to turn off/on each router 
+  separately
+o New source directory /usr/lib/wanrouter
+o New PPP driver 
+o X25 is not supported in this release 
+
+	
+PRODUCT COMPONENTS AND RELATED FILES
+
+/etc:
+	wanpipe1.conf	default router configuration file
+	wanrouter.rc	meta-configuration file (used by the Setup script)
+
+/lib/modules/X.Y.Z/misc:
+	wanrouter.o	router kernel loadable module
+
+/lib/modules/X.Y.Z/net:
+	sdladrv.o	Sangoma SDLA support module
+	wanpipe.o	Sangoma WANPIPE(tm) driver module
+
+/proc/net/wanrouter
+	Config		reads current router configuration
+	Status		reads current router status
+	{name}		reads WAN driver statistics
+
+/usr/sbin:
+	wanrouter	router start-up script
+	wanconfig	router configuration utility
+	sdladump	WANPIPE adapter memory dump utility
+        fpipemon        Monitor for Frame Relay
+        cpipemon        Monitor for Cisco HDLC
+
+/usr/lib/wanrouter:
+	README		this file
+	COPYING		GNU General Public License
+	Setup		installation script
+	Configure	configuration script
+	Filelist	distribution definition file
+
+/usr/lib/wanrouter/doc:
+	WANPIPE_USER_MANUAL.txt WAN Router User's Manual
+	WANPIPE_CONFIG.txt	WAN Configuration Manual
+
+/usr/lib/wanrouter/interfaces:
+	*		interface configuration files (TCP/IP configuration)
+
+/usr/lib/wanrouter/patches:
+	wanrouter-22.gz	patch for Linux kernel 2.2.10 and 2.2.11 
+			(compatible for all 2.2.X kernels)
+	wanrouter-20.gz patch for Linux kernel 2.0.36 
+
+	Fix_2.2.11.gz   patch to fix the 2.2.11 kernel so other patches
+                        can be applied properly.
+
+/usr/lib/wanrouter/samples:
+	interface	sample interface configuration file
+	wanpipe1.cpri 	CHDLC primary port
+     	wanpipe2.csec 	CHDLC secondary port
+     	wanpipe1.fr   	Frame Relay protocol
+     	wanpipe1.ppp  	PPP protocol ) 
+	wanrouter.rc	sample meta-configuration file
 
-2.1.0	June 20, 1996
+/usr/lib/wanrouter/src:
+	*		wan-tools source code
 
-	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 relay driver
-	o Changed interface between SDLA driver and protocol support modules
-	o Updated frame relay firmware
+/usr/include/linux:
+	wanrouter.h	router API definitions
+	wanpipe.h	WANPIPE API definitions
+	sdladrv.h	SDLA support module API definitions
+	sdlasfm.h	SDLA firmware module definitions
 
-2.0.0	May 1, 1996
+/usr/src/linux/net/router:
+	*		router source code
 
-	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
+/var/log:
+	wanrouter	router start-up log (created by the Setup script)
 
-1.0.0	February 12, 1996
+/var/lock:
+	wanrouter	router lock file (created by the Setup script)
 
-	o Final release
-	o Added support for Linux 1.3
-	o Updated S508 frame relay firmware
+/usr/lib/wanrouter/wanpipe:
+	fr514.sfm	Frame relay firmware for Sangoma S508/S514 card
+	cdual514.sfm	Dual Port Cisco HDLC firmware for Sangoma S508/S514 card
+	ppp514.sfm      PPP Firmware for Sangoma S508 and S514 cards
 
-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
+REVISION HISTORY
 
-0.1.0	October 12, 1995
+1.0.0	December 31, 1996	Initial version
 
-	o Initial version
+1.0.1	January 30, 1997	Status and statistics can be read via /proc
+				filesystem entries.
 
->>>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+1.0.2   April 30, 1997          Added UDP management via monitors.
 
+1.0.3	June 3, 1997		UDP management for multiple boards using Frame
+				Relay and PPP
+				Enabled continuous transmission of Configure 
+				Request Packet for PPP (for 508 only)
+				Connection Timeout for PPP changed from 900 to 0
+				Flow Control Problem fixed for Frame Relay
+
+1.0.4	July 10, 1997		S508/FT1 monitoring capability in fpipemon and
+				ppipemon utilities.
+				Configurable TTL for UDP packets.
+				Multicast and Broadcast IP source addresses are
+				silently discarded.
+
+1.0.5	July 28, 1997		Configurable T391,T392,N391,N392,N393 for Frame
+				Relay in router.conf.
+				Configurable Memory Address through router.conf 
+				for Frame Relay, PPP and X.25. (commenting this
+ 				out enables auto-detection).
+				Fixed freeing up received buffers using kfree()
+ 				for Frame Relay and X.25.
+				Protect sdla_peek() by calling save_flags(),
+				cli() and restore_flags().
+				Changed number of Trace elements from 32 to 20
+				Added DLCI specific data monitoring in FPIPEMON. 
+2.0.0	Nov 07, 1997		Implemented protection of RACE conditions by 
+				critical flags for FRAME RELAY and PPP.
+				DLCI List interrupt mode implemented.
+				IPX support in FRAME RELAY and PPP.
+				IPX Server Support (MARS)
+				More driver specific stats included in FPIPEMON
+				and PIPEMON.
+
+2.0.1	Nov 28, 1997		Bug Fixes for version 2.0.0.
+				Protection of "enable_irq()" while 
+				"disable_irq()" has been enabled from any other
+				routine (for Frame Relay, PPP and X25).
+				Added additional Stats for Fpipemon and Ppipemon
+				Improved Load Sharing for multiple boards
+
+2.0.2	Dec 09, 1997		Support for PAP and CHAP for ppp has been
+				implemented.
+
+2.0.3	Aug 15, 1998		New release supporting Cisco HDLC, CIR for Frame
+				relay, Dynamic IP assignment for PPP and Inverse
+				Arp support for Frame-relay.  Man Pages are 
+				included for better support and a new utility
+				for configuring FT1 cards.
+
+2.0.4	Dec 09, 1998	        Dual Port support for Cisco HDLC.
+				Support for HDLC (LAPB) API.
+				Supports BiSync Streaming code for S502E 
+				and S503 cards.
+				Support for Streaming HDLC API.
+				Provides a BSD socket interface for 
+				creating applications using BiSync
+   				streaming.        
+
+2.0.5   Aug 04, 1999 		CHDLC initializatin bug fix.
+				PPP interrupt driven driver: 
+  				Fix to the PPP line hangup problem.
+				New PPP firmware
+				Added comments to the startup SYSTEM ERROR messages
+				Xpipemon debugging application for the X25 protocol
+				New USER_MANUAL.txt
+				Fixed the odd boundary 4byte writes to the board.
+				BiSync Streaming code has been taken out.  
+				 Available as a patch.
+				Streaming HDLC API has been taken out.  
+				 Available as a patch.                 
+
+2.0.6   Aug 17, 1999		Increased debugging in statup scripts
+				Fixed insallation bugs from 2.0.5
+				Kernel patch works for both 2.2.10 and 2.2.11 kernels.
+				There is no functional difference between the two packages         
+
+2.0.7   Aug 26, 1999		o  Merged X25API code into WANPIPE.
+				o  Fixed a memeory leak for X25API
+				o  Updated the X25API code for 2.2.X kernels.
+				o  Improved NEM handling.   
+
+2.1.0	Oct 25, 1999		o New code for S514 PCI Card
+				o New CHDLC and Frame Relay drivers
+				o PPP and X25 are not supported in this release    
+>>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/oops-tracing.txt linux.14p16/Documentation/oops-tracing.txt
--- linux.vanilla/Documentation/oops-tracing.txt	Tue Jan  5 19:14:24 1999
+++ linux.14p16/Documentation/oops-tracing.txt	Thu Dec  9 15:34:41 1999
@@ -15,6 +15,37 @@
 linux-kernel@vger.rutgers.edu. Thanks for your help in making Linux as
 stable as humanly possible.
 
+Where is the_oops.txt?
+----------------------
+
+Normally the Oops text is read from the kernel buffers by klogd and
+handed to syslogd which writes it to a syslog file, typically
+/var/log/messages (depends on /etc/syslog.conf).  Sometimes klogd dies,
+in which case you can run dmesg > file to read the data from the kernel
+buffers and save it.  Or you can cat /proc/kmsg > file, however you
+have to break in to stop the transfer, kmsg is a "never ending file".
+If the machine has crashed so badly that you cannot enter commands or
+the disk is not available then you have three options :-
+
+(1) Hand copy the text from the screen and type it in after the machine
+    has restarted.  Messy but it is the only option if you have not
+    planned for a crash.
+
+(2) Boot with a serial console (see Documentation/serial-console.txt),
+    run a null modem to a second machine and capture the output there
+    using your favourite communication program.  Minicom works well.
+
+(3) Patch the kernel with one of the crash dump patches.  These save
+    data to a floppy disk or video rom or a swap partition.  None of
+    these are standard kernel patches so you have to find and apply
+    them yourself.  Search kernel archives for kmsgdump, lkcd and
+    oops+smram.
+
+No matter how you capture the log output, feed the resulting file to
+ksymoops along with /proc/ksyms and /proc/modules that applied at the
+time of the crash.  /var/log/ksymoops can be useful to capture the
+latter, man ksymoops for details.
+
 
 Full Information
 ----------------
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/pci.txt linux.14p16/Documentation/pci.txt
--- linux.vanilla/Documentation/pci.txt	Tue Apr 28 22:22:04 1998
+++ linux.14p16/Documentation/pci.txt	Thu Dec  9 15:34:43 1999
@@ -51,6 +51,30 @@
 config space. You should use the values in the pci_dev structure as they might
 have been remapped by the kernel.
 
+   If your PCI device uses PCI I/O space, you need to use the check_region(),
+request_region() and release_region() routines. These prevent devices from 
+having conflicting I/O regions. You access your registers using the inb(),
+inw(), inl(), outb(), outw(), or outl() routines passing the value of
+(struct pci_dev *) dev->base_address[] masked by PCI_BASE_ADDRESS_IO_MASK
+as the base address of your registers.
+
+   If your PCI device uses PCI memory space, use ioremap() to create a cookie 
+mapping to your PCI device. The mask (struct pci_dev *) dev->base_address[] 
+with PCI_BASE_ADDRESS_MEM_MASK before passing it into ioremap(). This cookie 
+is passed to the readb(), readw(), readl(), writeb(), writew(), and writel() 
+routines when accessing PCI space. You must always use these routines when 
+accessing PCI space from the kernel. Not all architectures allow direct access
+to PCI memory space from the kernel.
+
+   The IO-mapping.txt file has information about converting between the
+various address spaces. People writing DMA device drivers should pay special
+attention to this information.
+
+   PCI interrupt routines are always SA_SHIRQ and should use the value from
+(struct pci_dev *) dev->irq field for the interrupt number passed into 
+request_irq(). Since it is a shared interrupt, you must also always pass a 
+unique dev_id to request_irq().
+
 4. Obsolete functions
 ~~~~~~~~~~~~~~~~~~~~~
 <linux/bios32.h> is obsolete and should not be included in new code.
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/proc.txt linux.14p16/Documentation/proc.txt
--- linux.vanilla/Documentation/proc.txt	Sat Feb  6 20:46:20 1999
+++ linux.14p16/Documentation/proc.txt	Mon Dec 13 18:50:28 1999
@@ -1041,6 +1041,21 @@
 
 IP fragmentation settings
 
+ip_always_defrag
+   Replaces the former Kernel-Configuration option:
+	CONFIG_IP_ALWAYS_DEFRAG
+   All incoming fragments (parts of IP packets
+   that arose when some host between origin and destination decided
+   that the packets were too large and cut them into pieces) will be
+   reassembled (defragmented) before being processed, even if they are
+   about to be forwarded.
+
+   Only say Y here if running either a firewall that is the sole link
+   to your network or a transparent proxy; never ever say Y here for a
+   normal router or host.
+
+   This is automagically enabled when enabling masquerading.
+
 ipfrag_high_trash and ipfrag_low_trash
    Maximum memory used to reassemble IP fragments. When
    ipfrag_high_thresh bytes of memory is allocated for this purpose,
@@ -1176,6 +1191,14 @@
 secure_redirects
    Accept ICMP redirect messages only for gateways, listed in
    default gateway list. Enabled by default.
+
+hidden
+   Hide addresses attached to this device from another devices.
+   Such addresses will never be selected by source address autoselection
+   mechanism, host does not answer broadcast ARP requests for them,
+   does not announce it as source address of ARP requests,	but they
+   are still reachable via IP. This flag is activated only if it is
+   enabled both in specific device section and in "all" section.
 
 shared_media
    If it is not set the kernel does not assume that different subnets
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/s390/DASD linux.14p16/Documentation/s390/DASD
--- linux.vanilla/Documentation/s390/DASD	Thu Jan  1 01:00:00 1970
+++ linux.14p16/Documentation/s390/DASD	Wed Dec 15 22:40:19 1999
@@ -0,0 +1,73 @@
+DASD device driver
+
+S/390's disk devices (DASDs) are managed by Linux via the DASD device
+driver. It is valid for all types of DASDs and represents them to
+Linux as block devices, namely "dasd". Currently the DASD driver uses a
+single major number (94) and 4 minor numbers per volume (1 for the
+physical volume and 3 for partitions). With respect to partitions see
+below. Thus you may have up to 64 DASD devices in your system.
+
+The kernel parameter 'dasd=from-to,...' may be issued arbitrary times
+in the kernel's parameter line or not at all. The 'from' and 'to'
+parameters are to be given in hexadecimal notation without a leading
+0x.
+If you supply kernel parameters the different instances are processed
+in order of appearance and a minor number is reserved for any device
+covered by the supplied range up to 64 volumes. Additional DASDs are
+ignored. If you do not supply the 'dasd=' kernel parameter at all, the 
+DASD driver registers all supported DASDs of your system to a minor
+number in ascending order of the subchannel number.
+
+The driver currently supports ECKD-devices and there are stubs for
+support of the FBA and CKD architectures. For the FBA architecture
+only some smart data structures are missing to make the support
+complete. 
+We performed our testing on 3380 and 3390 type disks of different
+sizes, under VM and on the bare hardware (LPAR), using internal disks
+of the multiprise as well as a RAMAC virtual array. Disks exported by
+an Enterprise Storage Server (Seascape) should work fine as well.
+
+We currently implement one partition per volume, which is the whole
+volume, skipping the first blocks up to the volume label. These are
+reserved for IPL records and IBM's volume label to assure
+accessability of the DASD from other OSs. In a later stage we will
+provide support of partitions, maybe VTOC oriented or using a kind of
+partition table in the label record.
+
+USAGE
+
+-Low-level format (?CKD only)
+For using an ECKD-DASD as a Linux harddisk you have to low-level
+format the tracks by issueing the BLKDASDFORMAT-ioctl on that
+device. This will erase any data on that volume including IBM volume
+labels, VTOCs etc. The ioctl may take a 'struct format_data *' or
+'NULL' as an argument.  
+typedef struct {
+	int start_unit;
+	int stop_unit;
+	int blksize;
+} format_data_t;
+When a NULL argument is passed to the BLKDASDFORMAT ioctl the whole
+disk is formatted to a blocksize of 1024 bytes. Otherwise start_unit
+and stop_unit are the first and last track to be formatted. If
+stop_unit is -1 it implies that the DASD is formatted from start_unit
+up to the last track. blksize can be any power of two between 512 and
+4096. We recommend no blksize lower than 1024 because the ext2fs uses
+1kB blocks anyway and you gain approx. 50% of capacity increasing your
+blksize from 512 byte to 1kB.
+
+-Make a filesystem
+Then you can mk??fs the filesystem of your choice on that volume or
+partition. For reasons of sanity you should build your filesystem on
+the partition /dev/dd?1 instead of the whole volume. You only lose 3kB	
+but may be sure that you can reuse your data after introduction of a
+real partition table.
+
+BUGS:
+- Performance sometimes is rather low because we don't fully exploit clustering
+
+TODO-List:
+- Add IBM'S Disk layout to genhd
+- Enhance driver to use more than one major number
+- Enable usage as a module
+- Support Cache fast write and DASD fast write (ECKD)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/s390/cds.txt linux.14p16/Documentation/s390/cds.txt
--- linux.vanilla/Documentation/s390/cds.txt	Thu Jan  1 01:00:00 1970
+++ linux.14p16/Documentation/s390/cds.txt	Fri Dec 17 17:46:43 1999
@@ -0,0 +1,912 @@
+Linux/390
+
+Common Device Support (CDS)
+Device Driver I/O Support Routines
+
+Author : Ingo Adlung
+
+Copyright, IBM Corp. 1999
+
+Introduction
+
+This document describes the common device support routines for Linux/390.
+Different than other hardware architectures, ESA/390 has defined a unified
+I/O access method. This gives relief to the device drivers as they don't
+have to deal with different bus types, polling versus interrupt
+processing, shared versus non-shared interrupt processing, DMA versus port
+I/O (PIO), and other hardware features more. However, this implies that
+either every single device driver needs to implement the hardware I/O
+attachment functionality itself, or the operating system provides for a
+unified method to access the hardware, providing all the functionality that
+every single device driver would have to provide itself.
+
+The document does not intend to explain the ESA/390 hardware architecture in
+every detail.This information can be obtained from the ESA/390 Principles of
+Operation manual (IBM Form. No. SA22-7201).
+
+In order to build common device support for ESA/390 I/O interfaces, a
+functional layer was introduced that provides generic I/O access methods to
+the hardware. The following figure shows the usage of the common device support
+of Linux/390 using a TbCP/IP driven device access an example. Similar figures
+could be drawn for other access methods, e.g. file system access to disk
+devices.
+
+The common device support layer shown above comprises the I/O support routines
+defined below. Some of them implement common Linux device driver interfaces,
+while some of them are ESA/390 platform specific.
+
+get_dev_info_by_irq() / get_dev_info_by_devno()	
+   allow a device driver to determine the devices attached (visible) to the
+   system and their current status.
+
+get_irq_by_devno() / get_devno_by_irq()	
+   get irq (subchannel) from device number and vice versa.
+
+read_dev_chars()	
+   read device characteristics
+
+request_irq()	
+   obtain ownership for a specific device.
+
+free_irq()	
+   release ownership for a specific device.
+
+disable_irq()	
+   disable a device from presenting interrupts.
+
+enable_irq()	
+   enable a device, allowing for I/O interrupts.
+
+do_IO()	
+   initiate an I/O request.
+
+halt_IO()	
+   terminate the current I/O request processed on the device.
+
+do_IRQ()	
+   generic interrupt routine. This function is called by the interrupt entry
+   routine whenever an I/O interrupt is presented to the system. The do_IRQ()
+   routine determines the interrupt status and calls the device specific
+   interrupt handler according to the rules (flags) defined during I/O request
+   initiation with do_IO().
+
+The next chapters describe the functions, other than do_IRQ() in more details.
+The do_IRQ() interface is not described, as it is called from the Linux/390
+first level interrupt handler only and does not comprise a device driver
+callable interface. Instead, the functional description of do_IO() also
+describes the input to the device specific interrupt handler.
+
+
+Common Device Support (CDS) for Linux/390 Device Drivers
+
+General Information
+
+The following chapters describe the I/O related interface routines the
+Linux/390 common device support (CDS) provides to allow for device specific
+driver implementations on the IBM ESA/390 hardware platform. Those interfaces
+intend to provide the functionality required by every device driver
+implementaion to allow to drive a specific hardware device on the ESA/390
+platform. Some of the interface routines are specific to Linux/390 and some
+of them can be found on other Linux platforms implementations too.
+Miscellaneous function prototypes, data declarations, and macro definitions
+can be found in the architecture specific C header file
+linux/arch/s390/kernel/irq.h.
+
+Overview of CDS interface concepts
+
+Different to other hardware platforms, the ESA/390 architecture doesn't define
+interrupt lines managed by a specific interrupt controller and bus systems
+that may or may not allow for shared interrupts, DMA processing, etc.. Instead,
+the ESA/390 architecture has implemented a so called channel subsystem, that
+provides a unified view of the devices physically attached to the systems.
+Though the ESA/390 hardware platform knows about a huge variety of different
+peripheral attachments like disk devices (aka. DASDs), tapes, communication
+controllers, etc. they can all by accessed by a well defined access method and
+they are presenting I/O completion a unified way : I/O interruptions. Every
+single device is uniquely identified to the system by a so called subchannel,
+where the ESA/390 architecture allows for 64k devices be attached.
+
+Linux, however was first built on the Intel PC architecture, with its two
+cascaded 8259 programmable interrupt controllers (PICs), that allow for a
+maximum of 15 different interrupt lines. All devices attached to such a system
+share those 15 interrupt levels. Devices attached to the ISA bus system must
+not share interrupt levels (aka. IRQs), as the ISA bus bases on edge triggered
+interrupts. MCA, EISA, PCI and other bus systems base on level triggered
+interrupts, and therewith allow for shared IRQs. However, if multiple devices
+present their hardware status by the same (shared) IRQ, the operating system
+has to call every single device driver registered on this IRQ in order to
+determine the device driver owning the device that raised the interrupt.
+
+In order to not introduce a new I/O concept to the common Linux code,
+Linux/390 preserves the IRQ concept and semantically maps the ESA/390
+subchannels to Linux as IRQs. This allows Linux/390 to support up to 64k
+different IRQs, uniquely representig a single device each.
+
+During its startup the Linux/390 system checks for peripheral devices. Each
+of those devices is uniquely defined by a so called subchannel by the ESA/390
+channel subsystem. While the subchannel numbers are system generated, each
+subchannel also takes a user defined attribute, the so called device number.
+Both, subchannel number and device number can not exceed 65535. The
+init_IRQ() routine gathers the information about control unit type and device
+types that imply specific I/O commands (channel command words - CCWs) in
+order to operate the device. Device drivers can retrieve this set of hardware
+information during their initialization step to recognize the devices they
+support using get_dev_info_by_irq() or get_dev_info_by_devno() respectively.
+This methods implies that Linux/390 doesn't require to probe for free (not
+armed) interrupt request lines (IRQs) to drive its devices with. Where
+applicable, the device drivers can use the read_dev_chars() to retrieve device
+characteristics. This can be done without having to request device ownership
+previously.
+
+When a device driver has recognized a device it wants to claim ownership for,
+it calls request_irq() with the device's subchannel id serving as pseudo irq
+line. One of the required parameters it has to specify is dev_id, defining a
+device status block, the CDS layer will use to notify the device driver's
+interrupt handler about interrupt information observed. It depends on the
+device driver to properly handle those interrupts.
+
+In order to allow for easy I/O initiation the CDS layer provides a do_IO()
+interface that takes a device specific channel program (one or more CCWs) as
+input sets up the required architecture specific control blocks and initiates
+an I/O request on behalf of the device driver. The do_IO() routine allows for
+different I/O methods, synchronous and asynchronous, and allows to specify
+whether it expects the CDS layer to notify the device driver for every
+interrupt it observes, or with final status only. It also provides a scheme
+to allow for overlapped I/O processing. See do_IO() for more details. A device
+driver must never issue ESA/390 I/O commands itself, but must use the
+Linux/390 CDS interfaces instead.
+
+For long running I/O request to be canceled, the CDS layer provides the
+halt_IO() function. Some devices require to initially issue a HALT SUBCHANNEL
+(HSCH) command without having pending I/O requests. This function is also
+covered by halt_IO().
+
+When done with a device, the device driver calls free_irq() to release its
+ownership for the device. During free_irq() processing the CDS layer also
+disables the device from presenting further interrupts - the device driver
+doesn't need to assure it. The device will be reenabled for interrupts with
+the next call to request_irq().
+
+
+
+get_dev_info_by_irq() / get_dev_info_by_devno() - Retrieve Device Information
+
+During system startup - init_IRQ() processing - the generic I/O device support
+checks for the devices available. For all devices found it collects the
+SenseID information. For those devices supporting the command it also obtains
+extended SenseID information.
+
+int get_dev_info_by_irq( int         irq,
+                         dev_info_t *devinfo);
+
+int get_dev_info_by_devno( unsigned int  irq,
+                           dev_info_t   *devinfo);
+
+irq     - defines the subchannel, status information is to be
+          returned for.
+devno   - device number.
+devinfo - pointer to a user buffer of type dev_info_t that should
+          be filled with device specific information.
+
+typedef struct {
+     unsigned int devno;     /* device number */
+     unsigned int status;    /* device status */
+     senseid_t    sid_data;  /* senseID data  */
+} dev_info_t;
+
+devno     - device number as configured in the IOCDS.
+status    - device status
+sid_data  - data obtained by a SenseID call
+
+Possible status values are :
+
+DEVSTAT_NOT_OPER - device was found not-operational. In this case
+                   the caller should disregard the sid_data
+                   buffer content.
+
+//
+// SenseID response buffer layout
+//
+typedef struct {
+  /* common part */
+      unsigned char  reserved;     /* always 0x'FF' */
+      unsigned short cu_type;      /* control unit type */
+      unsigned char  cu_model;     /* control unit model */
+      unsigned short dev_type;     /* device type */
+      unsigned char  dev_model;    /* device model */
+      unsigned char  unused;       /* padding byte */
+  /* extended part */
+      ciw_t    ciw[62];            /* variable # of CIWs */
+} senseid_t;
+
+The ESA/390 I/O architecture defines certain device specific I/O functions.
+The device returns the device specific command code together with the SenseID
+data in so called Command Information Words (CIW) :
+
+typedef struct _ciw {
+   unsigned int et       :  2;    // entry type
+   unsigned int reserved :  2;    // reserved
+   unsigned int ct       :  4;    // command type
+   unsigned int cmd      :  8;    // command
+   unsigned int count    : 16;    // count
+} ciw_t;
+
+Possible CIW entry types are :
+
+#define CIW_TYPE_RDC    0x0;      // read configuration data
+#define CIW_TYPE_SII    0x1;      // set interface identifier
+#define CIW_TYPE_RNI    0x2;      // read node identifier
+
+The device driver may use these commands as appropriate.
+
+The get_dev_info_by_irq() / get_dev_info_by_devno() functions return:
+
+      0 - sucessful completion
+-ENODEV - irq or devno don't specify a known subchannel or device
+          number.
+-EINVAL - invalid devinfo value.
+
+Usage Notes :
+
+In order to scan for known devices a device driver should scan all irqs by
+calling     get_dev_info() until it returns -ENODEV as there aren't any more
+available devices.
+
+If a device driver wants to request ownership for a specific device it must
+call request_irq() prior to be able to issue any I/O request for it, including
+above mentioned   device dependent commands.
+
+Please see the "ESA/390 Common I/O-Commandss and Self Description" manual,
+with IBM form number SA22-7204 for more details on how to read the Sense-ID
+output, CIWs and device independent commands.
+
+
+
+get_irq_by_devno() / get_devno_by_irq() - Convert device identifiers
+
+While some device drivers act on the irq (subchannel) only, others take user
+defined device configurations on device number base, according to the device
+numbers configured in the IOCDS. The following routines serve the purpose to
+convert irq values into device numbers and vice versa.
+
+int get_irq_by_devno( unsigned int devno );
+
+unsigned int get_devno_by_irq( int irq );
+
+The functions return :
+
+the requested irq/devno values
+-1 if the requested conversion can't be accomplished.
+
+This could either be caused by irq/devno be outside the valid range
+( value > 0xffff or value < 0 ) or not identifying a known device.
+
+
+read_dev_chars() - Read Device Characteristics
+
+This routine returns the characteristics for the device specified.
+
+The function is meant to be called without an irq handler be in place.
+However, the irq for the requested device must not be locked or this will
+cause a deadlock situation ! Further, the driver must assure that nobody
+else has claimed ownership for the requested irq yet or the owning device
+driver's internal accounting may be affected.
+
+In case of a registered interrupt handler, the interrupt handler must be
+able to properly react on interrupts related to the read_dev_chars() I/O
+commands. While the request is procesed synchronously, the device interrupt
+handler is called for final ending status. In case of error situations the
+interrupt handler may recover appropriately. The device irq handler can
+recognize the corresponding interrupts by the interruption parameter be
+0x00524443. If using the function with an existing device interrupt handler
+in place, the irq must be locked prior to call read_dev_chars().
+
+The function may be called enabled or disabled.
+
+int read_dev_chars( int irq, void **buffer, int length );
+
+irq    - specifies the subchannel the device characteristic
+         retrieval is requested for
+buffer - pointer to a buffer pointer. The buffer pointer itself
+         may be NULL to have the function allocate a buffer or
+         must contain a valid buffer area.
+length - length of the buffer provided or to be allocated.
+
+The read_dev_chars() function returns :
+
+      0 - successful completion
+-ENODEV - irq doesn't specify a valid subchannel number
+-EINVAL - an invalid parameter was detected
+-EBUSY  - an irrecoverable I/O error occured or the device is not
+          operational.
+
+Usage Notes :
+
+The function can be used in two ways :
+
+If the caller doesn't provide a data buffer, read_dev_chars() allocates a
+data buffer and provides the device characteristics together. It's the
+caller's responsability to release the kernel memory if not longer needed.
+This behaviour is triggered by specifying a NULL buffer area (*buffer == NULL).
+
+Alternatively, if the user specifies a buffer area himself, nothing is
+allocated.
+
+In either case the caller must provide the data area length - for the buffer
+he specifies, or the buffer he wants to be allocated.
+
+
+request_irq() - Request Device Ownership
+
+As previously discussed a device driver will scan for the devices its supports
+by calling get_dev_info(). Once it has found a device it will call
+request_irq() to request ownership for it. This call causes the subchannel to
+be enabled for interrupts if it was found operational.
+
+int request_irq( unsigned int   irq,
+                 int          (*handler)( int,
+                                          void *,
+                                          struct pt_regs *),
+                 unsigned long  irqflags,
+                 const char    *devname,
+                 void          *dev_id);
+
+irq      : specifies the subchannel the ownership is requested for
+handler  : specifies the device driver's interrupt handler to be
+           called for interrupt processing
+irqflags : IRQ flags, must be 0 (zero) or SA_SAMPLE_RANDOM
+devname  : device name
+dev_id   : required pointer to a device specific buffer of type
+           devstat_t
+
+typedef struct {
+     unsigned int  devno;   /* device number from irb */
+     unsigned int  intparm; /* interrupt parameter */
+     unsigned char cstat;   /* channel status - accumulated */
+     unsigned char dstat;   /* device status - accumulated */
+     unsigned char lpum;    /* last path used mask from irb */
+     unsigned char unused;  /* not used - reserved */
+     unsigned int  flag;    /* flag : see below */
+     unsigned long cpa;     /* CCW addr from irb at prim. status */
+     unsigned int  rescnt;  /* count from irb at primary status */
+     unsigned int  scnt;    /* sense count, if available */
+     union {
+        irb_t   irb;        /* interruption response block */
+        sense_t sense;      /* sense information */
+        } ii;               /* interrupt information */
+  } devstat_t;
+
+During request_irq() processing, the devstat_t layout does not matter as it
+won't be used during request_irq() processing. See do_IO() for a functional
+description of its usage.
+
+The request_irq() function returns :
+
+      0 - successful completion
+-EINVAL - an invalid parameter was detected
+-EBUSY  - device (subchannel) already owned
+-ENODEV - the device is not-operational
+-ENOMEM - not enough kernel memory to process request
+
+Usage Notes :
+
+While Linux for Intel defines dev_id as a unique identifier for shared
+interrupt lines it has a totally different purpose on Linux/390. Here it
+serves as a shared interrupt status area between the generic device support
+layer, and the device specific driver. The value passed to request_irq()
+must therefore point to a valid devstat_t type buffer area the device driver
+must preserve for later usage. I.e. it must not be released prior to a call
+to free_irq()
+
+The only value parameter irqflags supports is SA_SAMPLE_RANDOM if appropriate.
+The Linux/390 kernel does neither know about "fast" interrupt handlers, nor
+does it allow for interrupt sharing. Remember, the term interrupt level (irq),
+device, and subchannel are used interchangeably in Linux/390.
+
+If request_irq() was called in enabled state, or if multiple CPUs are present,
+the device may present an interrupt to the specified handler prior to
+request_irq() return to the caller  already ! This includes the possibility
+of unsolicited interrupts or a pending interrupt status from an earlier
+solicited I/O request. The device driver must be able to handle this situation
+properly or the device may become unoperational otherwise !
+
+Although the interrupt handler is defined to be called with a pointer to a
+struct pt_regs buffer area, this is not implemented by the Linux/390 generic
+I/O device driver support layer. The device driver's interrupt handler must
+therefore not rely on this parameter on function entry.
+
+
+free_irq() - Release Device Ownership
+
+A device driver may call free_irq() to release ownership of a previously
+aquired device.
+
+void free_irq( unsigned int  irq,
+               void         *dev_id);
+
+irq      : specifies the subchannel the ownership is requested for
+dev_id   : required pointer to a device specific buffer of type
+           devstat_t. This must be the same as the one specified
+           during a previous call to request_irq().
+
+Usage Notes :
+
+Unfortunately the free_irq() is defined not to return error codes. I.e. if
+called with wrong  parameters a device may still be operational although there
+is no device driver available to handle its interrupts. Further, during
+free_irq() processing we may possibly find pending interrupt conditions. As
+those need to be processed, we have to delay free_irq() returning until a
+clean device status is found by synchronously handling them.
+
+The call to free_irq() will also cause the device (subchannel) be disabled for
+interrupts. The device driver must not release any data areas required for
+interrupt processing prior to free_irq() return to the caller as interrupts
+can occur prior to free_irq() returning. This is also true when called in
+disabled state if either multiple CPUs are presents or a pending interrupt
+status was found during free_irq() processing.
+
+
+disable_irq() - Disable Interrupts for a given Device
+
+This function may be called at any time to disable interrupt processing for
+the specified irq. However, as Linux/390 maps irqs to the device (subchannel)
+one-to-one, this may require more extensive I/O processing than anticipated,
+especially if an interrupt status is found pending on the subchannel that
+requires synchronous error processing.
+
+int disable_irq( unsigned int irq );
+
+irq : specifies the subchannel to be disabled
+
+The disable-irq() routine may return :
+
+      0 - successful completion
+-EBUSY  - device (subchannel) is currently processing an I/O
+          request
+-ENODEV - the device is not-operational or irq doesn't specify a
+          valid subchannel
+
+Usage Notes :
+
+Unlike the Intel based hardware architecture the ESA/390 architecture does
+not have a programmable interrupt controller (PIC) where a specific interrupt
+line can be disabled. Instead the subchannel logically representing the device
+in the channel subsystem must be disabled for interrupts. However, if there
+are still inetrrupt conditions pending they must   be processed first in order
+to allow for proper processing after reenabling the device at a later time.
+This may lead to delayed disable processing.
+
+As described above the disable processing may require extensive processing.
+Therefore    disabling and re-enabling the device using disable_irq() /
+enable_irq() should be avoided and is not suitable for high frequency
+operations.
+
+Linux for Intel defines this function
+
+void disable_irq( int irq);
+
+This is suitable for the Intel PC architecture as this only causes to mask
+the requested irq line in the PIC which is not applicable for the ESA/390
+architecture. Therefore we allow   for returning error codes.
+
+
+enable_irq() - Enable Interrupts for a given Device
+
+This function is used to enable a previously disabled device (subchannel).
+See disable_irq() for more details.
+
+int enable_irq( unsigned int irq );
+
+irq : specifies the subchannel to be enabled
+
+The enable-irq() routine may return :
+
+      0 - successful completion
+-EBUSY  - device (subchannel) is currently processing an I/O
+          request. This implies the device is already in enabled
+          state
+-ENODEV - the device is not-operational or irq doesn't specify a
+          valid subchannel
+
+
+
+do_IO() - Initiate I/O Request
+
+The do_IO() routines is the I/O request front-end processor. All device driver
+I/O requests must be issued using this routine. A device driver must not issue
+ESA/390 I/O commands itself. Instead the do_IO() routine provides all
+interfaces required to drive arbitrary devices.
+
+This description also covers the status information passed to the device
+driver's interrupt handler as this is related to the rules (flags) defined
+with the associated I/O request when calling do_IO().
+
+int do_IO( int            irq,
+           ccw1_t        *cpa,
+           unsigned long  intparm,
+           unsigned int   lpm,
+           unsigned long  flag);
+
+irq     : irq (subchannel) the I/O request is destined for
+cpa     : logical start address of channel program
+intparm : user specific interrupt information; will be presented
+          back to the device driver's interrupt handler. Allows a
+          device driver to associate the interrupt with a
+          particular I/O request.
+lpm     : defines the channel path to be used for a specific I/O
+          request. Valid with flag value DOIO_VALID_LPM only.
+flag    : defines the action to e parformed for I/O processing
+
+Possible flag values are :
+
+DOIO_EARLY_NOTIFICATION  - allow for early interupt notification
+DOIO_VALID_LPM           - LPM input parameter is valid (see usage
+                           notes below for details)
+DOIO_WAIT_FOR_INTERRUPT  - wait synchronously for final status
+DOIO_REPORT_ALL          - report all interrupt conditions
+
+The cpa parameter points to the first format 1 CCW of a channel program :
+
+typedef struct {
+   char            cmd_code; /* command code */
+   char            flags;    /* flags, like IDA adressing, etc. */
+   unsigned short  count;    /* byte count */
+   void           *cda;      /* data address */
+} ccw1_t __attribute__ ((aligned(8)));
+
+with the following CCW flags values defined :
+
+CCW_FLAG_DC        - data chaining
+CCW_FLAG_CC        - command chaining
+CCW_FLAG_SLI       - suppress incorrct length
+CCW_FLAG_SKIP      - skip
+CCW_FLAG_PCI       - PCI
+CCW_FLAG_IDA       - indirect addressing
+CCW_FLAG_SUSPEND   - suspend
+
+
+
+The do_IO() function returns :
+
+      0 - successful completion or request successfuly initiated
+-EBUSY  - the do_io() function was caled out of sequence. The
+          device is currently processing a previous I/O request
+-ENODEV - irq doesn't specify a valid subchannel, the device is
+          not operational (check dev_id.flags) or the irq is not
+          owned.
+-EINVAL - both, DOIO_EARLY_NOTIFICATION and DOIO_REORT_ALL flags
+          have been specified. The usage of those flags is mutual
+          exclusive.
+
+When the I/O request completes, the CDS first level interrupt handler will
+setup the dev_id buffer of type devstat_t defined during request_irq()
+processing. See request_irq() for the devstat_t data layout. The
+dev_id->intparm field in the device status area will contain the value the
+device driver has associated with a particular I/O request. If a pending
+device status was recognized dev_id->intparm will be set to 0 (zero). This
+may happen during I/O initiation or delayed by an alert status notification.
+In any case this status is not related to the current (last) I/O request. In
+case of a delayed status notification no special interrupt will be presented
+to indicate I/O completion as the I/O request was never started, even though
+do_IO() returned with successful completion.
+
+Possible dev_id->flag values are :
+
+DEVSTAT_FLAG_SENSE_AVAIL - sense data is available
+DEVSTAT_NOT_OPER         - device is not-operational
+DEVSTAT_START_FUNCTION   - interrupt is presented as result of a
+                           call to do_IO()
+DEVSTAT_HALT_FUNCTION    - interrupt is presented as result of a
+                           call to halt_IO()
+DEVSTAT_STATUS_PENDING   - a pending status was found. The I/O
+                           resquest (if any) was not initiated.
+                           This status might have been presented
+                           delayed, after do_IO() or halt_IO() have
+                           successfully be started previously.
+DEVSTAT_FINAL_STATUS     - This is a final interrupt status for the
+                           I/O requst identified by intparm.
+
+If device status DEVSTAT_FLAG_SENSE_AVAIL is indicated in field dev_id->flag,
+field dev_id->scnt describes the numer of device specific sense bytes
+available in the sense area dev_id->ii.sense. No device sensing by the device
+driver itself is required.
+
+typedef struct {
+   unsigned char res[32];       /* reserved   */
+   unsigned char data[32];      /* sense data */
+} sense_t;
+
+The device interrupt handler can use the following definitions to investigate
+the primary unit check source coded in sense byte 0 :
+
+SNS0_CMD_REJECT         0x80
+SNS0_INTERVENTION_REQ   0x40
+SNS0_BUS_OUT_CHECK      0x20
+SNS0_EQUIPMENT_CHECK    0x10
+SNS0_DATA_CHECK         0x08
+SNS0_OVERRUN            0x04
+
+Depending on the device status, multiple of those values may be set together.
+Please refer to the device specific documentation for details.
+
+The devi_id->cstat field provides the (accumulated) subchannel status :
+
+SCHN_STAT_PCI            - program controlled interrupt
+SCHN_STAT_INCORR_LEN     - incorrect length
+SCHN_STAT_PROG_CHECK     - program check
+SCHN_STAT_PROT_CHECK     - protection check
+SCHN_STAT_CHN_DATA_CHK   - channel data check
+SCHN_STAT_CHN_CTRL_CHK   - channel control check
+SCHN_STAT_INTF_CTRL_CHK  - interface control check
+SCHN_STAT_CHAIN_CHECK    - chaining check
+
+The dev_id->dstat field provides the (accumulated) device status :
+
+DEV_STAT_ATTENTION   - attention
+DEV_STAT_STAT_MOD    - status modifier
+DEV_STAT_CU_END      - control unit end
+DEV_STAT_BUSY        - busy
+DEV_STAT_CHN_END     - channel end
+DEV_STAT_DEV_END     - device end
+DEV_STAT_UNIT_CHECK  - unit check
+DEV_STAT_UNIT_EXCEP  - unit exception
+
+Please see the ESA/390 Principles of Operation manual for details on the
+individual flag meanings.
+
+In rare error situations the device driver may require access to the original
+hardware interrupt data beyond the scope of above mentioned infromation. For
+those situations the Linux/390 common device support provides the interrupt
+response block (IRB) as part of the device status block in dev_id->ii.irb.
+
+Usage Notes :
+
+Prior to call do_IO() the device driver must
+
+assure disabled state, i.e. the I/O mask value in the PSW must be disabled.
+This can be accomplished by calling __save_flags( flags). The current PSW
+flags are preserved and can be restored by __restore_flags( flags) at a
+later time.
+
+If the device driver violates this rule while running in a uni-processor
+environment an interrupt might be presented prior to the do_IO() routine
+returning to the device driver main path. In this case we will end in a
+deadlock situation as the interrupt handler will try to obtain the irq
+lock the device driver still owns (see below) !
+
+the driver must assure to hold the device specific lock. This can be
+accomplished by
+
+(i)  s390irq_spin_lock( irq), or
+(ii) s390irq_spin_lock_irqsave(irq, flags)
+
+Option (i) should be used if the calling routine is running disabled for
+I/O interrupts (see above) already. Option (ii) obtains the device gate und
+puts the CPU into I/O disabled state by preserving the current PSW flags.
+See the descriptions of s390irq_spin_lock() or s390irq_spin_lock_irqsave()
+for more details.
+
+The device driver is allowed to issue the next do_IO() call from within its
+interrupt handler already. It is not required to schedule a bottom-half,
+unless an non deterministicly long running error recovery procedure or
+similar needs to be scheduled. During I/O processing the Linux/390 generic
+I/O device driver support has already obtained the IRQ lock, i.e. the handler
+must not try to obtain it again when calling do_IO() or we end in a deadlock
+situation ! Anyway, the device driver's interrupt handler must only call
+do_IO() if the handler itself can be entered recursively if do_IO() e.g. finds
+a status pending and needs to all the interrupt handler itself.
+
+Device drivers shouldn't heavily rely on DOIO_WAIT_FOR_INTERRUPT synchronous
+I/O request processing. All I/O devices, but the console device are driven
+using a single shared interrupt subclass (ISC). For sync. processing the
+device is temporarily mapped to a special ISC while the calling CPU waits for
+I/O completion. As this special ISC is gated, all sync. requests in a SMP
+environment are serialized which may cause other CPUs to spin. This service
+is therewith primarily meant to be used during device driver initialization
+for ease of device setup.
+
+The lpm input parameter might be used for multipath devices shared among
+multiple systems as the Linux/390 CDS isn't grouping channel paths. Therefore
+its use might be required if multiple access paths to a device are available
+and the device was reserved by means of a reserve device command (for devices
+supporting this technique). When issuing this command the device driver needs
+needs to extract the dev_id->lpum value and restrict all subsequent channel
+programs to this channel path until the device is released by a device release
+command. Otherwise a deadlock may occur.
+
+If a device driver relies on an I/O request to be completed prior to start the
+next it can reduce I/O processing overhead by chaining a NoOp I/O command
+CCW_CMD_NOOP to the end of the submitted CCW chain. This will force Channel-End
+and Device-End status to be presented together, with a single interrupt.
+However, this should be used with care as it implies the channel will remain
+busy, not being able to process I/O requests for other devices on the same
+channel. Therefore e.g. read commands should never use this technique, as the
+result will be presented by a single interrupt anyway.
+
+In order to minimize I/O overhead, a device driver should use the
+DOIO_REPORT_ALL  only if the device can report intermediate interrupt
+information prior to device-end the device driver urgently relies on. In this
+case all I/O interruptions are presented to the device driver until final
+status is recognized.
+
+If a device is able to recover from asynchronosly presented I/O errors, it can
+perform overlapping I/O using the DOIO_EARLY_NOTIFICATION flag. While some
+devices always report channel-end and device-end together, with a single
+interrupt, others present primary status (channel-end) when the channel is
+ready for the next I/O request and secondary status (device-end) when the data
+transmission has been completed at the device.
+
+Above flag allows to exploit this feature, e.g. for communication devices that
+can handle lost data on the network to allow for enhanced I/O processing.
+
+Unless the channel subsystem at any time presents a secondary status interrupt,
+exploiting this feature will cause only primary status interrups to be
+presented to the device driver while overlapping I/O is performed. When a
+secondary status without error (alert status) is presented, this indicates
+successful completion for all overlapping do_IO() requests that have been
+issued since the last secondary (final) status.
+
+During interrupt processing the device specific interrupt handler should avoid
+basing its processing decisions on the interruption response block (IRB) that
+is part of the dev_id buffer area. The IRB area represents the interruption
+parameters from the last interrupt received. Unless the device driver has
+specified DOIO_REPORT_ALL or is called with a pending status
+(DEVSTAT_STATUS_PENDING), the IRB information may or may not show the complete
+interruption status, but the last interrupt only. Therefore the device driver
+should usually base its processing decisions on the values of dev_id->cstat
+and dev_id->dstat that represent the accumulated subchannel and device status
+information gathered since do_IO() request initiation.
+
+
+halt_IO() - Halt I/O Request Processing
+
+Sometimes a device driver might need a possibility to stop the processing of
+a long-running channel program or the device might require to initially issue
+a halt subchannel (HSCH) I/O command. For those purposes the halt_IO() command
+is provided.
+
+int halt_IO( int          irq,     /* subchannel number */
+             int          intparm, /* dummy intparm */
+             unsigned int flag);   /* operation mode */
+
+irq     : irq (subchannel) the halt operation is requested for
+intparm : interruption parameter; value is only used if no I/O
+          is outstanding, otherwise the intparm associated with
+          the I/O request is returned
+flag    : 0 (zero) or DOIO_WAIT_FOR_INTERRUPT
+
+The halt_IO() function returns :
+
+      0 - successful completion or request successfuly initiated
+-EBUSY  - the device is currently performing a sysnchonous I/O
+          operation : do_IO() with flag DOIO_WAIT_FOR_INTERRUPT
+          or an error was encountered and the device is currently
+          be sensed
+-ENODEV - the irq specified doesn't specify a valid subchannel, the
+          device is not operational (check dev_id.flags) or the irq
+          is not owned.
+
+Usage Notes :
+
+A device driver may write a never-ending channel program by writing a channel
+program that at its end loops back to its beginning by means of a transfer in
+channel (TIC)   command (CCW_CMD_TIC). Usually this is performed by network
+device drivers by setting the PCI CCW flag (CCW_FLAG_PCI). Once this CCW is
+executed a program controlled interrupt (PCI) is generated. The device driver
+can then perform an appropriate action. Prior to interrupt of an outstanding
+read to a network device (with or   without PCI flag) a halt_IO() is required
+to end the pending operation.
+
+We don't allow to stop sync. I/O requests by means of a halt_IO() call. The
+function will return -EBUSY instead.
+
+
+Miscellaneous Support Routines
+
+This chapter describes various routines to be used in a Linux/390 device
+driver programming environment.
+
+s390irq_spin_lock() / s390irq_spin_unlock()
+
+Those two macro definitions are required to obtain the device specific IRQ
+lock. The lock needs to be obtained if the device driver intends to call
+do_IO() or halt_IO() from anywhere but the device interrupt handler (where
+the lock is already owned). Those routines must only be used if running
+disabled for interrupts already. Otherwise use s390irq_spin_lock_irqsave()
+and the corresponding unlock routine instead (see below).
+
+s390irq_spin_lock( int irq);
+s390irq_spin_unlock( int irq);
+
+
+s390irq_spin_lock_irqsave() / s390_irq_spin_unlock_irqrestore()
+
+Those two macro definitions are required to obtain the device specific IRQ
+lock. The lock needs to be obtained if the device driver intends to call
+do_IO() or halt_IO() from anywhere but the device interrupt handler (where
+the lock is already owned). Those routines should only be used if running
+enabled for interrupts. If running disabled already, the driver should use
+s390irq_spin_lock() and the corresponding unlock routine instead (see above).
+
+s390irq_spin_lock_irqsave( int irq, unsigned long flags);
+s390irq_spin_unlock_irqrestore( int irq, unsigned long flags);
+
+
+
+
+Special Console Interface Routines
+
+This chapter describes the special interface routines required for system
+console processing. Though they are an extension to the Linux/390 device
+driver interface concept, they base on the same principles. It was necessary
+to build those extensions to assure a deterministic behaviour in critical
+situations e.g. printk() messages by other device drivers running disabled
+for interrupts during I/O interrupt handling or in case of a panic() message
+being raised.
+
+set_cons_dev - Set Console Device
+
+This routine allows to specify the system console device. This is necessary
+as the console isn't driven by the same ESA/390 interrupt subclass as are
+other devices, but it is assigned ist own interrupt subclass. Only one device
+can act as system console. See wait_cons_dev() for details.
+
+int set_cons_dev( int irq);
+
+irq : subchannel identifying the system console device
+
+The set_cons_dev() function returns
+
+      0 - successful completion
+-EIO    - an unhandled interrupt condition is pending for the
+          specified subchannel (irq) - status pending
+-ENODEV - irq doesn't specify a valid subchannel or the devive is
+          not operational
+-EBUSY  - the console device is already defined
+
+reset_cons_dev - Reset Console Device
+
+This routine allows for resetting the console device specification. See
+set_cons_dev() for details.
+
+int reset_cons_dev( int irq);
+
+irq : subchannel identifying the system console device
+
+The reset_cons_dev() function returns
+
+      0 - successful completion
+-EIO    - an unhandled interrupt condition is pending for the
+          specified subchannel (irq) - status pending
+-ENODEV - irq doesn't specify a valid subchannel or the devive is
+          not operational
+
+wait_cons_dev - Synchronously Wait for Console Processing
+
+The wait_cons_dev() routine is used by the console device driver when its
+buffer pool for intermediate request queuing is exhausted and a new output
+request is received. In this case the console driver uses the wait_cons_dev()
+routine to synchronously wait until enough buffer space is gained to enqueue
+the current request. Any pending interrupt condition for the console device
+found during wait_cons_dev() processing causes its interrupt handler to be
+called.
+
+int wait_cons_dev( int irq);
+
+irq : subchannel identifying the system console device
+
+The wait_cons_dev() function  returns :
+
+      0 - successful completion
+-EINVAL - the irq specified doesn't match the irq configured for
+          the console device by set_cons_dev()
+
+Usage Notes :
+
+The function should be used carefully. Especially in a SMP environment the
+wait_cons_dev() processing requires that all but the special console ISC are
+disabled. In a SMP system this requires the other CPUs to be signaled to
+disable/enable those ISCs.
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/sound/Introduction linux.14p16/Documentation/sound/Introduction
--- linux.vanilla/Documentation/sound/Introduction	Sat Aug 14 02:27:12 1999
+++ linux.14p16/Documentation/sound/Introduction	Thu Dec  9 15:34:42 1999
@@ -25,7 +25,8 @@
                    added info on multiple sound cards of similar types,]
                    added more diagnostics info, added info about esd.
                    added info on OSS and ALSA.
-
+1.1.1  19991031	   Added notes on sound-slot- and sound-service.
+			(Alan Cox)
 
 Modular Sound Drivers:
 ======================
@@ -321,6 +322,12 @@
 
 7)  Turn on debug in drivers/sound/sound_config.h (DEB, DDB, MDB).
 
+8)  If the system reports insuffcient DMA memory then you may want to
+    load sound with the "dmabufs=1" option. Or in /etc/conf.modules add
+	
+	preinstall sound dmabufs=1
+
+    This makes the sound system allocate its buffers and hang onto them.
 
 Configuring Sound:
 ==================
@@ -335,7 +342,7 @@
 
 3)  In /etc/conf.modules when using modprobe.
 
-4)  Via Red Hat's /usr/sbin/sndconfig program (text based).
+4)  Via Red Hat's GPL'd /usr/sbin/sndconfig program (text based).
 
 5)  Via the OSS soundconf program (with the commercial version
     of the OSS driver.
@@ -344,6 +351,28 @@
 
 Anyone want to write a linuxconf module for configuring sound?
 
+Module Loading:
+===============
+
+When a sound card is first referenced and sound is modular the sound system
+will ask for the sound devices to be loaded. Initially it requests that
+the driver for the sound system is loaded. It then wwill ask for 
+sound-slot-0, where 0 is the first sound card. (sound-slot-1 the second and
+so on). Thus you can do
+
+alias sound-slot-0 sb
+
+To load a soundblaster at this point. If the slot loading does not provide
+the desired device - for example a soundblaster does not directly provide
+a midi synth in all cases then it will request "sound-service-0-n" where n
+is
+
+0	Mixer
+
+2  	MIDI
+
+3, 4	DSP audio
+
 
 For More Information (RTFM):
 ============================
@@ -373,6 +402,3 @@
 Contact Information:
 ====================
 Wade Hampton:  (whampton@staffnet.com)
-
-
-
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/sound/NM256 linux.14p16/Documentation/sound/NM256
--- linux.vanilla/Documentation/sound/NM256	Wed Oct 20 01:12:33 1999
+++ linux.14p16/Documentation/sound/NM256	Mon Dec 13 19:29:11 1999
@@ -2,10 +2,10 @@
 Documentation for the NeoMagic 256AV/256ZX sound driver
 =======================================================
 
-You're looking at version 1.0 of the driver.  (Woohoo!) It has been
+You're looking at version 1.11 of the driver.  (Woohoo!) It has been
 successfully tested against the following laptop models:
 
-	Sony Z505S/Z505SX/Z505DX
+	Sony Z505S/Z505SX/Z505DX/Z505RX
 	Sony F150, F160, F180, F250, F270, F280, PCG-F26
 	Dell Latitude CPi, CPt (various submodels)
 
@@ -16,9 +16,13 @@
 NeoMagic.  There is no warranty, expressed, implied, or otherwise.  It
 is free software in the public domain; feel free to use it, sell it,
 give it to your best friends, even claim that you wrote it (but why?!)
-but don't come whining to me, NeoMagic, Sony, Dell, or anyone else
+but don't go whining to me, NeoMagic, Sony, Dell, or anyone else
 when it blows up your computer.
 
+Version 1.11 fixes a bug uncovered by Timidity--the sound would start clicking
+after the first MIDI file was finished playing.  There are no other changes
+over 1.1.
+
 ============
 Installation
 ============
@@ -42,16 +46,19 @@
 another device (it normally shares IRQ 9 with the builtin eepro100
 ethernet on the Sony Z505 laptops). 
 
-It does not run the card in any sort of compatibility mode. Thus it
-almost certainly will not work on laptops that have the
-SB16-compatible codec/mixer; you will want to use the standard SB16
-OSS driver with these chipsets.  I cannot provide any assistance with
-machines using the SB-16 compatible version.
+It does not run the card in any sort of compatibility mode. It will
+not work on laptops that have the SB16-compatible, AD1848-compatible
+or CS4232-compatible codec/mixer; you will want to use the appropriate
+compatible OSS driver with these chipsets.  I cannot provide any
+assistance with machines using the SB16, AD1848 or CS4232 compatible
+versions.  (The driver now attempts to detect the mixer version, and
+will refuse to load if it believes the hardware is not not
+AC97-compatible.)
 
 The sound support is very basic, but it does include simultaneous
 playback and record capability.  The mixer support is also quite
 simple, although this is in keeping with the rather limited
-functionality of the chipset.  
+functionality of the chipset.
 
 There is no hardware synthesizer available, as the Losedows OPL-3 and
 MIDI support is done via hardware emulation.
@@ -63,8 +70,6 @@
 so of course the CD-ROM input doesn't work.  It does work on laptops
 with a builtin CD-ROM drive.
 
-Recording is mono 8-bit only.
-
 The mixer device does not appear to have any tone controls, at least
 on the Z505 series.  The mixer module checks for tone controls in the
 AC97 mixer, and will enable them if they are available.
@@ -93,10 +98,11 @@
     limitation.  It may be possible to support other speeds in the future.
 
   * There is no support for the telephone mixer/codec.  There is support
-    for a phonein/phoneout device if your mixer program supports it;
-    whether or not it does anything is anyone's guess.  (Reports on this
-    would be appreciated.)
-  
+    for a phonein/phoneout device in the mixer driver;  whether or not 
+    it does anything is anyone's guess.  (Reports on this would be
+    appreciated.  You'll have to figure out how to get the phone to
+    go off-hook before it'll work, tho.)
+
   * This driver was not written with any cooperation or support from
     NeoMagic.  If you have any questions about this, see their website
     for their official stance on supporting open source drivers.
@@ -118,8 +124,8 @@
 
   * Sometimes the NM256 driver has to guess at where the buffer 
     should be placed, especially if the module is loaded after the
-    X server is started.  It's usually correct, but it will fail on
-    the Sony F250.
+    X server is started.  It's usually correct, but it will consistently
+    fail on the Sony F250.
 
   * Virtual screens greater than 1024x768x16 under XFree86 are
     problematic on laptops with only 2.5MB of screen RAM. This
@@ -139,10 +145,16 @@
 On the F250, it is possible to force the driver to load properly even
 after the XFree86 server is started by doing:
 
-	insmod nm256.o buffertop=0x25a800
+	insmod nm256 buffertop=0x25a800
 
 This forces the audio buffers to the correct offset in screen RAM.
 
+One user has reported a similar problem on the Sony F270, although
+others apparently aren't seeing any problems.  His suggested command
+is
+
+	insmod nm256 buffertop=0x272800
+
 =================
 Official WWW site
 =================
@@ -154,6 +166,17 @@
 You should always be able to get the latest version of the driver there,
 and the driver will be supported for the foreseeable future.
 
+==============
+Z505RX and IDE
+==============
+
+There appears to be a problem with the IDE chipset on the Z505RX; one
+of the symptoms is that sound playback periodically hangs (when the
+disk is accessed).  The user reporting the problem also reported that
+enabling all of the IDE chipset workarounds in the kernel solved the
+problem, tho obviously only one of them should be needed--if someone
+can give me more details I would appreciate it.
+
 ==============================
 Z505S/Z505SX on-board Ethernet
 ==============================
@@ -176,11 +199,30 @@
 ==================================
 
 There is also a known problem with the Sony Z505S and Z505SX hanging
-if a PCMCIA card is inserted while the ethernet driver is loaded.
-This is caused by tons of spurious IRQ 9s, probably generated from the
-PCMCIA or ACPI bridges.  There is currently no fix for the problem,
-and the only known workaround is to disable the ethernet interface
-before inserting or removing a PCMCIA card.
+if a PCMCIA card is inserted while the ethernet driver is loaded, or
+in some cases if the laptop is suspended.  This is caused by tons of
+spurious IRQ 9s, probably generated from the PCMCIA or ACPI bridges.
+
+There is currently no fix for the problem that works in every case.
+The only known workarounds are to disable the ethernet interface
+before inserting or removing a PCMCIA card, or with some cards
+disabling the PCMCIA card before ejecting it will also help the
+problem with the laptop hanging when the card is ejected.
+
+One user has reported that setting the tcic's cs_irq to some value
+other than 9 (like 11) fixed the problem.  This doesn't work on my
+Z505S, however--changing the value causes the cardmgr to stop seeing
+card insertions and removals, cards don't seem to work correctly, and
+I still get hangs if a card is inserted when the kernel is booted.
+
+Using the latest ethernet driver and pcmcia package allows me to
+insert an Adaptec 1480A SlimScsi card without the laptop hanging,
+although I still have to shut down the card before ejecting or
+powering down the laptop.  However, similar experiments with a DE-660
+ethernet card still result in hangs when the card is inserted.  I am
+beginning to think that the interrupts are CardBus-related, since the
+Adaptec card is a CardBus card, and the DE-660 is not; however, I
+don't have any other CardBus cards to test with.
 
 ======
 Thanks
@@ -208,6 +250,11 @@
 	Jeff Garzik, for various helpful suggestions on the AC97
 	interface
 
+	"Mr. Bumpy" for feedback on the Z505RX
+
+	Bill Nottingham, for generous assistance in getting the mixer ID
+	code working
+
 =================
 Previous versions
 =================
@@ -227,3 +274,11 @@
 
 Version 0.75 renamed all the functions and files with slightly more
 generic names.
+
+Version 1.1 contains a change to try and detect non-AC97 versions of
+the hardware, and not install itself appropriately.  It should also
+reinitialize the hardware on an APM resume event, assuming that APM
+was configured into your kernel.
+
+Note that previous versions of this document claimed that recording was
+8-bit only; it actually has been working for 16-bits all along.
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/sound/PSS linux.14p16/Documentation/sound/PSS
--- linux.vanilla/Documentation/sound/PSS	Thu Jan  1 01:00:00 1970
+++ linux.14p16/Documentation/sound/PSS	Thu Dec  9 15:34:42 1999
@@ -0,0 +1,41 @@
+The PSS cards and other ECHO based cards provide an onboard DSP with 
+downloadable programs and also has an AD1848 "Microsoft Sound System" 
+device. The PSS driver enables MSS and MPU401 modes of the card. SB 
+is not enabled since it doesn't work concurrently with MSS. 
+
+If you build this driver as a module then the driver takes the folowing
+parameters
+
+pss_io. 	The I/O base the PSS card is configured at (normally 0x220
+		or 0x240)
+
+mss_io		The base address of the Microsoft Sound System interface.
+		This is normally 0x530, but may be 0x604 or other addresses.
+
+mss_irq		The interrupt assigned to the Microsoft Sound System
+		emulation. IRQ's 3,5,7,9,10,11 and 12 are available. If you
+		get IRQ errors be sure to check the interrupt is set to 
+		"ISA/Legacy" in the BIOS on modern machines.
+
+mss_dma		The DMA channel used by the Microsoft Sound System.
+		This can be 0, 1, or 3. DMA 0 is not available on older 
+		machines and will cause a crash on them.
+
+mpu_io		The MPU emulation base address. This sets the base of the
+		synthesizer. It is typically 0x330 but can be altered.
+
+mpu_irq		The interrupt to use for the synthesizer. It must differ
+		from the IRQ used by the Microsoft Sound System port.
+
+
+The mpu_io/mpu_irq fields are optional. If they are not specified the 
+synthesizer parts are not configured.
+
+When the module is loaded it looks for a file called 
+/etc/sound/pss_synth. This is the firmware file from the DOS install disks.
+This fil holds a general MIDI emulation. The file expected is called
+genmidi.ld on newer DOS driver install disks and synth.ld on older ones.
+
+You can also load alternative DSP algorithms into the card if you wish. One
+alternative driver can be found at http://www.mpg123.de/
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/telephony/ixj.txt linux.14p16/Documentation/telephony/ixj.txt
--- linux.vanilla/Documentation/telephony/ixj.txt	Thu Jan  1 01:00:00 1970
+++ linux.14p16/Documentation/telephony/ixj.txt	Fri Dec 17 23:12:23 1999
@@ -0,0 +1,406 @@
+Linux Quicknet-Drivers-Howto
+Quicknet Technologies, Inc. (www.quicknet.net)
+Version 0.3.4  December 18, 1999
+
+1.0  Introduction
+
+This document describes the first GPL release version of the Linux
+driver for the Quicknet Internet PhoneJACK and Internet LineJACK
+cards.  More information about these cards is available at
+www.quicknet.net.  The driver version discussed in this document is
+0.3.4.
+
+These cards offer nice telco style interfaces to use your standard
+telephone/key system/PBX as the user interface for VoIP applications.
+The Internet LineJACK also offers PSTN connectivity for a single line
+Internet to PSTN gateway.  Of course, you can add more than one card
+to a system to obtain multi-line functionality.  At this time, the
+driver supports the POTS port on both the Internet PhoneJACK and the
+Internet LineJACK, but the PSTN port on the latter card is not yet
+supported.
+
+This document, and the drivers for the cards, are intended for a
+limited audience that includes technically capable programmers who
+would like to experiment with Quicknet cards.  The drivers are
+considered in ALPHA status and are not yet considered stable enough
+for general, widespread use in an unlimited audience.
+
+That's worth saying again:
+
+THE LINUX DRIVERS FOR QUICKNET CARDS ARE PRESENTLY IN A ALPHA STATE
+AND SHOULD NOT BE CONSIDERED AS READY FOR NORMAL WIDESPREAD USE.
+
+They are released early in the spirit of Internet development and to
+make this technology available to innovators who would benefit from
+early exposure.
+
+When we promote the device driver to "beta" level it will be
+considered ready for non-programmer, non-technical users.  Until then,
+please be aware that these drivers may not be stable and may affect
+the performance of your system.
+
+
+1.1 Latest Additions/Improvements
+
+The 0.3.4 version of the driver is the first GPL release.  Several
+features had to be removed from the prior binary only module, mostly
+for reasons of Intellectual Property rights.  We can't release
+information that is not ours - so certain aspects of the driver had to
+be removed to protect the rights of others.  
+
+Specifically, very old Internet PhoneJACK cards have non-standard
+G.723.1 codecs (due to the early nature of the DSPs in those days).
+The auto-conversion code to bring those cards into compliance with
+todays standards is available as a binary only module to those people
+needing it.  If you bought your card after 1997 or so, you are OK -
+it's only the very old cards that are affected.
+
+Also, the code to download G.728/G.729/G.729a codecs to the DSP is
+available as a binary only module as well.  This IP is not ours to
+release.  
+
+Hooks are built into the GPL driver to allow it to work with other
+companion modules that are completely separate from this module.
+
+1.2 Copyright, Trademarks, Disclaimer, & Credits 
+
+Copyright
+
+Copyright (c) 1999 Quicknet Technologies, Inc.  Permission is granted
+to freely copy and distribute this document provided you preserve it
+in its original form. For corrections and minor changes contact the
+maintainer at linux@quicknet.net.
+
+Trademarks
+
+Internet PhoneJACK and Internet LineJACK are registered trademarks of
+Quicknet Technologies, Inc.
+
+Disclaimer
+
+Much of the info in this HOWTO is early information released by
+Quicknet Technologies, Inc. for the express purpose of allowing early
+testing and use of the Linux drivers developed for their products.
+While every attempt has been made to be thorough, complete and
+accurate, the information contained here may be unreliable and there
+are likely a number of errors in this document. Please let the
+maintainer know about them. Since this is free documentation, it
+should be obvious that neither I nor previous authors can be held
+legally responsible for any errors.
+
+Credits
+
+This HOWTO was written by:
+
+	Greg Herlein <gherlein@quicknet.net>
+	Ed Okerson <eokerson@quicknet.net> 
+
+1.3  Future Plans: You Can Help 
+
+Please let the maintainer know of any errors in facts, opinions,
+logic, spelling, grammar, clarity, links, etc.  But first, if the date
+is over a month old, check to see that you have the latest
+version. Please send any info that you think belongs in this document.
+
+You can also contribute code and/or bug-fixes for the sample
+applications.
+
+
+1.4  Where to get things
+
+You can download the latest versions of the driver from:
+
+http://www.quicknet.net/develop.htm
+
+You can download the latest version of this document from:
+
+http://www.quicknet.net/develop.htm
+
+
+1.5  Mailing List
+
+Quicknet operates a mailing list to provide a public forum on using
+these drivers.
+
+To subscribe to the linux-sdk mailing list, send an email to:
+
+   majordomo@linux.quicknet.net
+
+In the body of the email, type:
+
+   subscribe linux-sdk <your-email-address>
+
+Please delete any signature block that you would normally add to the
+bottom of your email - it tends to confuse majordomo.
+
+To send mail to the list, address your mail to 
+
+   linux-sdk@linux.quicknet.net
+
+Your message will go out to everyone on the list.
+
+To unsubscribe to the linux-sdk mailing list, send an email to:
+
+   majordomo@linux.quicknet.net
+
+In the body of the email, type:
+
+   unsubscribe linux-sdk <your-email-address>
+
+
+
+2.0  Requirements
+
+2.1  Quicknet Card(s)
+
+You will need at least one Internet PhoneJACK or Internet LineJACK
+cards.  These are ISA or PCI bus devices that use Plug-n-Play for
+configuration, and use no IRQs.  The driver will support up to 16
+cards in any one system, of any mix between the two types.
+
+Note that you will need two cards to do any useful testing alone, since
+you will need a card on both ends of the connection.  Of course, if
+you are doing collaborative work, perhaps your friends or coworkers
+have cards too.  If not, we'll gladly sell them some!
+
+
+2.2  ISAPNP
+
+Since the Quicknet cards are Plug-n-Play devices, you will need the
+isapnp tools package to configure the cards, or you can use the isapnp
+module to autoconfigure them.  The former package probably came with
+your Linux distribution.  Documentation on this package is available
+online at:
+
+http://mailer.wiwi.uni-marburg.de/linux/LDP/HOWTO/Plug-and-Play-HOWTO.html
+
+The isapnp autoconfiguration is available on the Quicknet website at:
+
+    http://www.quicknet.net/develop.htm
+
+though it may be in the kernel by the time you read this.
+
+
+3.0  Card Configuration 
+
+If you did not get your drivers as part of the linux kernel, do the
+following to install them:
+
+   a.  untar the distribution file.  We use the following command:
+        tar -xvzf ixj-0.x.x.tgz
+
+This creates a subdirectory holding all the necessary files.  Go to that
+subdirectory.
+
+   b.  run the "ixj_dev_create" script to remove any stray device
+files left in the /dev directory, and to create the new officially
+designated device files.  Note that the old devices were called 
+/dev/ixj, and the new method uses /dev/phone.  
+
+   c.  type "make;make install" - this will compile and install the
+module.
+
+   d.  type "depmod -av" to rebuild all your kernel version dependencies.
+
+   e.  if you are using the isapnp module to configure the cards
+       automatically, then skip to step f.  Otherwise, ensure that you
+       have run the isapnp configuration utility to properly configure
+       the cards.
+
+       e1. The Internet PhoneJACK has one configuration register that
+           requires 16 IO ports.  The Internet LineJACK card has two
+           configuration registers and isapnp reports that IO 0
+           requires 16 IO ports and IO 1 requires 8.  The Quicknet
+           driver assumes that these registers are configured to be
+           contiguous, i.e. if IO 0 is set to 0x340 then IO 1 should
+           be set to 0x350.
+
+           Make sure that none of the cards overlap if you have
+           multiple cards in the system.
+
+           If you are new to the isapnp tools, you can jumpstart
+           yourself by doing the following:
+
+      e2.  go to the /etc directory and run pnpdump to get a blank
+           isapnp.conf file.
+
+	   	pnpdump > /etc/isapnp.conf
+
+      e3.  edit the /etc/isapnp.conf file to set the IO warnings and
+           the register IO addresses. The IO warnings means that you
+           should find the line in the file that looks like this:
+
+	   (CONFLICT (IO FATAL)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # or WARNING
+
+	   and you should edit the line to look like this:
+
+	   (CONFLICT (IO WARNING)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) #
+	   or WARNING
+
+           The next step is to set the IO port addresses.  The issue
+           here is that isapnp does not identify all of the ports out
+           there.  Specifically any device that does not have a driver
+           or module loaded by Linux will not be registered.  This
+           includes older sound cards and network cards.  We have
+           found that the IO port 0x300 is often used even though
+           isapnp claims that no-one is using those ports.  We
+           recommend that for a single card installation that port
+           0x340 (and 0x350) be used.  The IO port line should change
+           from this:
+
+	   (IO 0 (SIZE 16) (BASE 0x0300) (CHECK))
+
+	   to this:
+
+	   (IO 0 (SIZE 16) (BASE 0x0340) )
+
+       e4.  if you have multiple Quicknet cards, make sure that you do
+            not have any overlaps.  Be especially careful if you are
+            mixing Internet PhoneJACK and Internet LineJACK cards in
+            the same system.  In these cases we recommend moving the
+            IO port addresses to the 0x400 block.  Please note that on
+            a few machines the 0x400 series are used.  Feel free to
+            experiment with other addresses.  Our cards have been
+            proven to work using IO addresses of up to 0xFF0.
+
+       e5.  the last step is to uncomment the activation line so the
+            drivers will be associated with the port.  This means the
+            line (immediately below) the IO line should go from this:
+
+            # (ACT Y)
+
+            to this:
+
+	    (ACT Y)
+
+            Once you have finished editing the isapnp.conf file you
+            must submit it into the pnp driverconfigure the cards.
+            This is done using the following command:
+
+	    isapnp isapnp.conf
+
+	    If this works you should see a line that identifies the
+            Quicknet device, the IO port(s) chosen, and a message
+            "Enabled OK".
+
+   f.  if you are loading the module by hand, use insmod.  An example
+of this would look like this:
+
+	insmod phonedev
+	insmod ixj dspio=0x320,0x310 xio=0,0x330
+
+Then verify the module loaded by running lsmod. If you are not using a
+module that matches your kernel version, you may need to "force" the
+load using the -f option in the insmod command.
+
+	insmod phonedev
+	insmod -f ixj dspio=0x320,0x310 xio=0,0x330
+
+
+If you are using isapnp to autoconfigure your card, then you do NOT
+need any of the above, though you need to use depmod to load the
+driver, like this:
+
+	depmod ixj
+
+which will result in the needed drivers getting loaded automatically.
+
+   g.  if you are planning on using kerneld to automatically load the 
+module for you, then you need to edit /etc/conf.modules and add the 
+following lines:
+
+	options ixj dspio=0x340 xio=0x330 ixjdebug=0
+
+If you do this, then when you execute an application that uses the
+module kerneld will load the module for you.  Note that to do this,
+you need to have your kernel set to support kerneld.  You can check
+for this by looking at /usr/src/linux/.config and you should see this:
+
+	# Loadable module support
+	#
+	<snip>
+	CONFIG_KMOD=y
+
+  h.  if you want non-root users to be able to read and write to the 
+ixj devices (this is a good idea!) you should do the following:
+
+     - decide upon a group name to use and create that group if 
+       needed.  Add the user names to that group that you wish to 
+       have access to the device.  For example, we typically will
+       create a group named "ixj" in /etc/group and add all users
+       to that group that we want to run software that can use the 
+       ixjX devices.
+
+     - change the permissions on the device files, like this:
+	
+       chgrp ixj /dev/ixj*	
+       chmod 660 /dev/ixj*
+	
+Once this is done, then non-root users should be able to use the
+devices.  If you have enabled autoloading of modules, then the user
+should be able to open the device and have the module loaded
+automatically for them.
+
+
+4.0 Driver Installation problems.
+
+We have tested these drivers on the 2.2.9, 2.2.10, 2.2.12, and 2.2.13 kernels
+and in all cases have eventually been able to get the drivers to load and 
+run.  We have found four types of problems that prevent this from happening.
+The problems and solutions are:
+
+  a. A step was missed in the installation.  Go back and use section 3
+as a checklist.  Many people miss running the ixj_dev_create script and thus
+never load the device names into the filesystem.
+
+  b. The kernel is inconsistently linked.  We have found this problem in
+the Out Of the Box installation of several distributions.  The symptoms 
+are that neither driver will load, and that the unknown symbols include "jiffy"
+and "kmalloc".  The solution is to recompile both the kernel and the
+modules.  The command string for the final compile looks like this:
+
+    In the kernel directory:
+    1.  cp .config /tmp
+    2.  make mrproper
+    3.  cp /tmp/.config .
+    4.	make dep;make clean;make bzImage;make modules;make modules_install
+
+This rebuilds both the kernel and all the modules and makes sure they all 
+have the same linkages.  This generally solves the problem once the new 
+kernel is installed and the system rebooted.
+
+  c. The kernel has been patched, then unpatched.  This happens when
+someone decides to use an earlier kernel after they load a later kernel.
+The symptoms are proceeding through all three above steps and still not
+being able to load the driver.  What has happened is that the generated
+header files are out of sync with the kernel itself.  The solution is
+to recompile (again) using "make mrproper".  This will remove and then
+regenerate all the necessary header files.  Once this is done, then you 
+need to install and reboot the kernel.  We have not seen any problem
+loading one of our drivers after this treatment.
+
+5.0  Known Limitations
+
+We cannot currently play "dial-tone" and listen for DTMF digits at the
+same time using the ISA PhoneJACK.  This is a bug in the 8020 DSP chip
+used on that product.  All other Quicknet products function normally
+in this regard.  We have a work-around, but it's not done yet.  Until
+then, if you want dial-tone, you can always play a recorded dial-tone
+sound into the audio until you have gathered the DTMF digits.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/MAINTAINERS linux.14p16/MAINTAINERS
--- linux.vanilla/MAINTAINERS	Wed Oct 20 01:12:33 1999
+++ linux.14p16/MAINTAINERS	Tue Dec 21 00:31:11 1999
@@ -103,7 +103,7 @@
 
 ADVANSYS SCSI DRIVER
 P:	Bob Frey
-M:	Bob Frey <bobf@advansys.com>
+M:	linux@advansys.com
 W:	http://www.advansys.com/linux.html
 L:	linux-scsi@vger.rutgers.edu
 S:	Maintained
@@ -121,9 +121,10 @@
 
 APM DRIVER
 P:	Stephen Rothwell
-M:	Stephen.Rothwell@canb.auug.org.au
+M:	apm@linuxcare.com.au
 L:	linux-laptop@vger.rutgers.edu
-S:	Maintained
+W:	http://linuxcare.com.au/apm/
+S:	Supported
 
 APPLETALK NETWORK LAYER
 P:	Jay Schulist
@@ -203,6 +204,11 @@
 W:	http://www.fi.muni.cz/~kas/cosa/
 S:	Maintained
 
+COMX/MULTIGATE SYNC SERIAL DRIVERS
+P:	Gergely Madarasz
+M:	Gergely Madarasz <gorgo@itc.hu>
+S:	Supported
+
 CREDITS FILE
 P:	John A. Martin
 M:	jam@acm.org
@@ -233,7 +239,7 @@
 M:	SteveW@ACM.org
 W:	http://www.sucs.swan.ac.uk/~rohan/
 W:	http://www-sigproc.eng.cam.ac.uk/~sjw44/
-L:	netdev@roxanne.nuclecu.unam.mx
+L:	netdev@oss.sgi.com
 S:	Maintained
 
 DEVICE NUMBER REGISTRY
@@ -452,9 +458,9 @@
 
 JOYSTICK DRIVER
 P:	Vojtech Pavlik
-M:	vojtech@ucw.cz
+M:	vojtech@suse.cz
 L:	linux-joystick@atrey.karlin.mff.cuni.cz
-W:	http://atrey.karlin.mff.cuni.cz/~vojtech/joystick/
+W:	http://www.suse.cz/development/joystick/
 S:	Maintained
 
 KERNEL AUTOMOUNTER (AUTOFS)
@@ -484,8 +490,9 @@
 
 LINUX FOR POWER MACINTOSH
 P:	Paul Mackerras
-M:	paulus@cs.anu.edu.au
-L:	linux-pmac@samba.anu.edu.au
+M:	paulus@linuxcare.com
+W:	http://www.linuxppc.org/
+L:	linuxppc-dev@lists.linuxppc.org
 S:	Maintained
 
 LOGICAL VOLUME MANAGER
@@ -573,7 +580,7 @@
 
 NETWORKING [GENERAL]
 P:	Networking Teak
-M:	netdev@nuclecu.unam.mx
+M:	netdev@oss.sgi.com
 L:	linux-net@vger.rutgers.edu
 W:	http://www.uk.linux.org/NetNews.html (2.0 only)
 S:	Maintained
@@ -585,7 +592,7 @@
 M:	ak@muc.de
 P:	Alexey Kuznetsov
 M:	kuznet@ms2.inr.ac.ru
-L:	netdev@roxanne.nuclecu.unam.mx
+L:	netdev@oss.sgi.com
 S:	Maintained
 
 NFS CLIENT
@@ -804,8 +811,8 @@
 S:	Maintained
 
 TLAN NETWORK DRIVER
-P:	James Banks
-M:	james@sovereign.org
+P:	Torben Mathiasen
+M:	torben.mathiasen@compaq.com
 L:	tlan@vuser.vu.union.edu
 S:	Maintained
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Makefile linux.14p16/Makefile
--- linux.vanilla/Makefile	Wed Oct 20 01:12:33 1999
+++ linux.14p16/Makefile	Tue Dec 21 00:42:32 1999
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
-SUBLEVEL = 13
-EXTRAVERSION =
+SUBLEVEL = 14
+EXTRAVERSION = pre16
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
@@ -202,6 +202,10 @@
 DRIVERS := $(DRIVERS) drivers/net/irda/irda_drivers.a
 endif
 
+ifeq ($(CONFIG_PHONE),y)
+DRIVERS := $(DRIVERS) drivers/telephony/telephony.a
+endif
+
 include arch/$(ARCH)/Makefile
 
 .S.s:
@@ -338,8 +342,9 @@
 	if [ -f VIDEO_MODULES ]; then inst_mod VIDEO_MODULES video; fi; \
 	if [ -f FC4_MODULES   ]; then inst_mod FC4_MODULES   fc4;   fi; \
 	if [ -f IRDA_MODULES  ]; then inst_mod IRDA_MODULES  net;   fi; \
+	if [ -f SK98LIN_MODULES ]; then inst_mod SK98LIN_MODULES  net;   fi; \
 	\
-	for f in *.o; do [ -r $$f ] && echo $$f; done > $$MODLIB/.allmods; \
+	for f in *.o; do [ -r $$f ] && echo $$f; done | sort > $$MODLIB/.allmods; \
 	echo $$MODULES | tr ' ' '\n' | sort | comm -23 $$MODLIB/.allmods - > $$MODLIB/.misc; \
 	if [ -s $$MODLIB/.misc ]; then inst_mod $$MODLIB/.misc misc; fi; \
 	rm -f $$MODLIB/.misc $$MODLIB/.allmods; \
@@ -381,6 +386,10 @@
 	rm -f drivers/net/hamradio/soundmodem/gentbl
 	rm -f drivers/char/hfmodem/gentbl drivers/char/hfmodem/tables.h
 	rm -f drivers/sound/*_boot.h drivers/sound/.*.boot
+	rm -f drivers/sound/msndinit.c
+	rm -f drivers/sound/msndperm.c
+	rm -f drivers/sound/pndsperm.c
+	rm -f drivers/sound/pndspini.c
 	rm -f .version .config* config.in config.old
 	rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp
 	rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/Makefile linux.14p16/arch/alpha/Makefile
--- linux.vanilla/arch/alpha/Makefile	Sat Aug 14 02:27:12 1999
+++ linux.14p16/arch/alpha/Makefile	Thu Dec  9 15:34:20 1999
@@ -60,9 +60,10 @@
 
 # For TSUNAMI, we must have the assembler not emulate our instructions.
 # The same is true for POLARIS.
+# The same is true for IRONGATE.
 # BWX is most important, but we don't really want any emulation ever.
 ifeq ($(old_gas),y)
- ifneq ($(CONFIG_ALPHA_GENERIC)$(CONFIG_ALPHA_TSUNAMI)$(CONFIG_ALPHA_POLARIS),)
+ ifneq ($(CONFIG_ALPHA_GENERIC)$(CONFIG_ALPHA_TSUNAMI)$(CONFIG_ALPHA_POLARIS)$(CONFIG_ALPHA_IRONGATE),)
    # How do we do #error in make?
    CFLAGS := --error-please-upgrade-your-assembler
  endif
@@ -79,6 +80,9 @@
  ifeq ($(CONFIG_ALPHA_TSUNAMI),y)
    CFLAGS := $(CFLAGS) -Wa,-mev6
  endif
+ ifeq ($(CONFIG_ALPHA_IRONGATE),y)
+   CFLAGS := $(CFLAGS) -Wa,-mev6
+ endif
 endif
 
 HEAD := arch/alpha/kernel/head.o
@@ -116,11 +120,9 @@
 	@$(MAKEBOOT) clean
 
 archmrproper:
-	-$(MAKE) -C arch/alpha/math-emu cleansymlinks
 
 archdep:
 	@$(MAKEBOOT) dep
-	-$(MAKE) -C arch/alpha/math-emu symlinks
 
 bootpfile:
 	@$(MAKEBOOT) bootpfile
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/config.in linux.14p16/arch/alpha/config.in
--- linux.vanilla/arch/alpha/config.in	Sat Aug 14 02:26:46 1999
+++ linux.14p16/arch/alpha/config.in	Thu Dec  9 15:34:20 1999
@@ -33,10 +33,12 @@
 	 EB64+			CONFIG_ALPHA_EB64P		\
 	 EB66			CONFIG_ALPHA_EB66		\
 	 EB66+			CONFIG_ALPHA_EB66P		\
+	 Eiger			CONFIG_ALPHA_EIGER		\
 	 Jensen			CONFIG_ALPHA_JENSEN		\
 	 LX164			CONFIG_ALPHA_LX164		\
 	 Miata			CONFIG_ALPHA_MIATA		\
 	 Mikasa			CONFIG_ALPHA_MIKASA		\
+	 Nautilus		CONFIG_ALPHA_NAUTILUS		\
 	 Noname			CONFIG_ALPHA_NONAME		\
 	 Noritake		CONFIG_ALPHA_NORITAKE		\
 	 PC164			CONFIG_ALPHA_PC164		\
@@ -54,6 +56,7 @@
 unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA
 unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS
 unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA
+unset CONFIG_ALPHA_IRONGATE
 
 if [ "$CONFIG_ALPHA_GENERIC" = "y" ]
 then
@@ -117,7 +120,7 @@
 	define_bool CONFIG_ALPHA_EV5 y
 	define_bool CONFIG_ALPHA_PYXIS y
 fi
-if [ "$CONFIG_ALPHA_DP264" = "y" ]
+if [ "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_EIGER" = "y" ]
 then
 	define_bool CONFIG_PCI y
 	define_bool CONFIG_ALPHA_EV6 y
@@ -139,6 +142,12 @@
 then
 	define_bool CONFIG_ALPHA_EV4 y
 fi
+if [ "$CONFIG_ALPHA_NAUTILUS" = "y" ]
+then
+	define_bool CONFIG_PCI y
+	define_bool CONFIG_ALPHA_EV6 y
+	define_bool CONFIG_ALPHA_IRONGATE y
+fi
 
 if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
 	-o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \
@@ -147,7 +156,8 @@
 	-o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \
 	-o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \
 	-o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" \
-	-o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" ]
+	-o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \
+	-o "$CONFIG_ALPHA_EIGER" = "y" ]
 then
   bool 'Use SRM as bootloader' CONFIG_ALPHA_SRM
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/defconfig linux.14p16/arch/alpha/defconfig
--- linux.vanilla/arch/alpha/defconfig	Sat Aug 14 02:26:46 1999
+++ linux.14p16/arch/alpha/defconfig	Thu Dec  9 15:34:21 1999
@@ -32,6 +32,7 @@
 # CONFIG_ALPHA_LX164 is not set
 # CONFIG_ALPHA_MIATA is not set
 # CONFIG_ALPHA_MIKASA is not set
+# CONFIG_ALPHA_NAUTILUS is not set
 # CONFIG_ALPHA_NONAME is not set
 # CONFIG_ALPHA_NORITAKE is not set
 # CONFIG_ALPHA_PC164 is not set
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/Makefile linux.14p16/arch/alpha/kernel/Makefile
--- linux.vanilla/arch/alpha/kernel/Makefile	Sat Aug 14 02:27:12 1999
+++ linux.14p16/arch/alpha/kernel/Makefile	Thu Dec  9 15:34:20 1999
@@ -12,8 +12,6 @@
 .S.o:
 	$(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $<
 
-all: kernel.o head.o
-
 O_TARGET := kernel.o
 O_OBJS   := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
 	    bios32.o ptrace.o time.o fpreg.o
@@ -22,12 +20,12 @@
 
 ifdef CONFIG_ALPHA_GENERIC
 
-O_OBJS	 += core_apecs.o core_cia.o core_lca.o core_mcpcia.o core_pyxis.o \
-	    core_t2.o core_tsunami.o core_polaris.o \
-	    sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eb64p.o \
-	    sys_jensen.o sys_miata.o sys_mikasa.o sys_noritake.o \
-	    sys_rawhide.o sys_ruffian.o sys_sable.o sys_sio.o \
-	    sys_sx164.o sys_takara.o sys_rx164.o \
+O_OBJS	 += core_apecs.o core_cia.o core_irongate.o core_lca.o core_mcpcia.o \
+	    core_pyxis.o core_t2.o core_tsunami.o core_polaris.o \
+	    sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eb64p.o sys_eiger.o \
+	    sys_jensen.o sys_miata.o sys_mikasa.o sys_nautilus.o \
+	    sys_noritake.o sys_rawhide.o sys_ruffian.o sys_rx164.o \
+	    sys_sable.o sys_sio.o sys_sx164.o sys_takara.o \
 	    es1888.o smc37c669.o smc37c93x.o
 else
 
@@ -38,6 +36,9 @@
 ifdef CONFIG_ALPHA_CIA
 O_OBJS   += core_cia.o
 endif
+ifdef CONFIG_ALPHA_IRONGATE
+O_OBJS   += core_irongate.o
+endif
 ifdef CONFIG_ALPHA_LCA
 O_OBJS   += core_lca.o
 endif
@@ -70,6 +71,9 @@
 ifneq ($(CONFIG_ALPHA_EB64P)$(CONFIG_ALPHA_EB66),)
 O_OBJS   += sys_eb64p.o
 endif
+ifdef CONFIG_ALPHA_EIGER
+O_OBJS   += sys_eiger.o
+endif
 ifdef CONFIG_ALPHA_JENSEN
 O_OBJS   += sys_jensen.o
 endif
@@ -79,6 +83,9 @@
 ifdef CONFIG_ALPHA_MIKASA
 O_OBJS   += sys_mikasa.o
 endif
+ifdef CONFIG_ALPHA_NAUTILUS
+O_OBJS   += sys_nautilus.o
+endif
 ifdef CONFIG_ALPHA_NORITAKE
 O_OBJS   += sys_noritake.o
 endif
@@ -121,7 +128,7 @@
 O_OBJS   += smp.o
 endif
 
-all: kernel.o head.o
+all: kernel.o head.o asm_offsets
 
 asm_offsets: check_asm
 	./check_asm > $(TOPDIR)/include/asm-alpha/asm_offsets.h
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/alpha_ksyms.c linux.14p16/arch/alpha/kernel/alpha_ksyms.c
--- linux.vanilla/arch/alpha/kernel/alpha_ksyms.c	Wed Oct 20 01:12:33 1999
+++ linux.14p16/arch/alpha/kernel/alpha_ksyms.c	Thu Dec  9 15:34:20 1999
@@ -49,8 +49,6 @@
 extern void __remqu (void);
 
 EXPORT_SYMBOL(alpha_mv);
-EXPORT_SYMBOL(local_bh_count);
-EXPORT_SYMBOL(local_irq_count);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(disable_irq_nosync);
@@ -182,6 +180,9 @@
 EXPORT_SYMBOL(read_lock);
 #endif
 EXPORT_SYMBOL_NOVERS(kernel_flag);
+#else /* __SMP__ */
+EXPORT_SYMBOL(local_bh_count);
+EXPORT_SYMBOL(local_irq_count);
 #endif /* __SMP__ */
 
 /*
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/bios32.c linux.14p16/arch/alpha/kernel/bios32.c
--- linux.vanilla/arch/alpha/kernel/bios32.c	Tue Dec  1 17:33:59 1998
+++ linux.14p16/arch/alpha/kernel/bios32.c	Thu Dec  9 15:34:20 1999
@@ -78,6 +78,7 @@
 
 struct linux_hose_info *bus2hose[256];
 struct linux_hose_info *hose_head, **hose_tail = &hose_head;
+struct linux_hose_info default_hose;
 int hose_count;
 int pci_probe_enabled;
 
@@ -639,11 +640,11 @@
 				/* Bypass hi reg in the loop.  */
 				dev->base_address[++idx] = 0;
 
-				printk("bios32 WARNING: "
-				       "handling 64-bit device in "
-				       "slot %d, function %d: \n",
-				       PCI_SLOT(dev->devfn),
-				       PCI_FUNC(dev->devfn));
+				DBG_DEVS(("bios32 WARNING: "
+					  "handling 64-bit device in "
+					  "slot %d, function %d: \n",
+					  PCI_SLOT(dev->devfn),
+					  PCI_FUNC(dev->devfn)));
 			}
 
 			DBG_DEVS(("layout_dev: dev 0x%x MEM @ 0x%lx (0x%x)\n",
@@ -1345,8 +1346,7 @@
 		/* For the benefit of single-bus machines, emulate a
 		   multi-bus machine to the (limited) extent necessary. 
 		   Init all bus2hose entries to point to a dummy.  */
-		hose = kmalloc(sizeof(*hose), GFP_KERNEL);
-		memset(hose, 0, sizeof(*hose));
+		hose = &default_hose;
 		for (i = 0; i < 256; ++i)
 			bus2hose[i] = hose;
 	}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/core_irongate.c linux.14p16/arch/alpha/kernel/core_irongate.c
--- linux.vanilla/arch/alpha/kernel/core_irongate.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/alpha/kernel/core_irongate.c	Tue Dec 14 16:16:13 1999
@@ -0,0 +1,368 @@
+/*
+ *	linux/arch/alpha/kernel/core_irongate.c
+ *
+ * Code common to all IRONGATE core logic chips.
+ *
+ * Based on code written by David A. Rusling (david.rusling@reo.mts.dec.com).
+ *	Copyright (C) 1999 Alpha Processor, Inc., (David Daniel, Stig Telfer, Soohoon Lee)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/pci.h>
+#include <asm/hwrpb.h>
+
+#define __EXTERN_INLINE inline
+#include <asm/io.h>
+#include <asm/core_irongate.h>
+#undef __EXTERN_INLINE
+
+#include "proto.h"
+#include "bios32.h"
+
+/*
+ * NOTE: Herein lie back-to-back mb instructions.  They are magic.
+ * One plausible explanation is that the I/O controller does not properly
+ * handle the system transaction.  Another involves timing.  Ho hum.
+ */
+
+/*
+ * BIOS32-style PCI interface:
+ */
+
+/* #define DEBUG_CONFIG */
+#define DEBUG_MCHECK
+
+#ifdef DEBUG_CONFIG
+# define DBG_CFG(args)	printk args
+#else
+# define DBG_CFG(args)
+#endif
+
+#ifdef DEBUG_MCHECK
+# define DBG_MCK(args)	printk args
+#define DEBUG_MCHECK_DUMP
+#else
+# define DBG_MCK(args)
+#endif
+
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address accordingly.  It is therefore not safe
+ * to have concurrent invocations to configuration space access
+ * routines, but there really shouldn't be any need for this.
+ *
+ *	addr[31:24]		reserved
+ *	addr[23:16]		bus number (8 bits = 128 possible buses)
+ *	addr[15:11]		Device number (5 bits)
+ *	addr[10: 8]		function number
+ *	addr[ 7: 2]		register number
+
+ * For IRONGATE:
+ *    if (bus = addr[23:16]) == 0
+ *    then
+ *	  type 0 config cycle:
+ *	      addr_on_pci[31:11] = id selection for device = addr[15:11]
+ *	      addr_on_pci[10: 2] = addr[10: 2] ???
+ *	      addr_on_pci[ 1: 0] = 00
+ *    else
+ *	  type 1 config cycle (pass on with no decoding):
+ *	      addr_on_pci[31:24] = 0
+ *	      addr_on_pci[23: 2] = addr[23: 2]
+ *	      addr_on_pci[ 1: 0] = 01
+ *    fi
+ *
+ * Notes:
+ *	The function number selects which function of a multi-function device
+ *	(e.g., SCSI and Ethernet).
+ *
+ *	The register selects a DWORD (32 bit) register offset.	Hence it
+ *	doesn't get shifted by 2 bits as we want to "drop" the bottom two
+ *	bits.
+ */
+
+static int
+mk_conf_addr(u8 bus, u8 device_fn, u8 where, struct linux_hose_info *hose,
+	     unsigned long *pci_addr, unsigned char *type1)
+{
+	unsigned long addr;
+
+	DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, "
+		 "pci_addr=0x%p, type1=0x%p)\n",
+		 bus, device_fn, where, pci_addr, type1));
+
+	addr = (bus << 16) | (device_fn << 8) | where;
+	addr |= IRONGATE_CONF;
+
+	*pci_addr = addr;
+	DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+	return 0;
+}
+
+int
+irongate_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value,
+			       struct linux_hose_info *hose)
+{
+	unsigned long addr;
+	unsigned char type1;
+
+	if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*value = __kernel_ldbu(*(vucp)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+irongate_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value,
+			       struct linux_hose_info *hose)
+{
+	unsigned long addr;
+	unsigned char type1;
+
+	if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*value = __kernel_ldwu(*(vusp)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+irongate_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value,
+				struct linux_hose_info *hose)
+{
+	unsigned long addr;
+	unsigned char type1;
+
+	if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*value = *(vuip)addr;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+irongate_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value,
+				struct linux_hose_info *hose)
+{
+	unsigned long addr;
+	unsigned char type1;
+
+	if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	__kernel_stb(value, *(vucp)addr);
+	mb();
+	__kernel_ldbu(*(vucp)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+irongate_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value,
+				struct linux_hose_info *hose)
+{
+	unsigned long addr;
+	unsigned char type1;
+
+	if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	__kernel_stw(value, *(vusp)addr);
+	mb();
+	__kernel_ldwu(*(vusp)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+irongate_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value,
+				 struct linux_hose_info *hose)
+{
+	unsigned long addr;
+	unsigned char type1;
+
+	if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*(vuip)addr = value;
+	mb();
+	*(vuip)addr;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+#if 0
+static void
+irongate_register_dump(const char *function_name)
+{
+	printk("%s: Irongate registers:\n"
+	       "\tdev_vendor\t0x%08x\n"
+	       "\tstat_cmd\t0x%08x\n"
+	       "\tclass\t\t0x%08x\n"
+	       "\tlatency\t\t0x%08x\n"
+	       "\tbar0\t\t0x%08x\n"
+	       "\tbar1\t\t0x%08x\n"
+	       "\tbar2\t\t0x%08x\n"
+	       "\trsrvd0[0]\t0x%08x\n"
+	       "\trsrvd0[1]\t0x%08x\n"
+	       "\trsrvd0[2]\t0x%08x\n"
+	       "\trsrvd0[3]\t0x%08x\n"
+	       "\trsrvd0[4]\t0x%08x\n"
+	       "\trsrvd0[5]\t0x%08x\n"
+	       "\tcapptr\t\t0x%08x\n"
+	       "\trsrvd1[0]\t0x%08x\n"
+	       "\trsrvd1[1]\t0x%08x\n"
+	       "\tbacsr10\t\t0x%08x\n"
+	       "\tbacsr32\t\t0x%08x\n"
+	       "\tbacsr54\t\t0x%08x\n"
+	       "\trsrvd2[0]\t0x%08x\n"
+	       "\tdrammap\t\t0x%08x\n"
+	       "\tdramtm\t\t0x%08x\n"
+	       "\tdramms\t\t0x%08x\n"
+	       "\trsrvd3[0]\t0x%08x\n"
+	       "\tbiu0\t\t0x%08x\n"
+	       "\tbiusip\t\t0x%08x\n"
+	       "\trsrvd4[0]\t0x%08x\n"
+	       "\trsrvd4[1]\t0x%08x\n"
+	       "\tmro\t\t0x%08x\n"
+	       "\trsrvd5[0]\t0x%08x\n"
+	       "\trsrvd5[1]\t0x%08x\n"
+	       "\trsrvd5[2]\t0x%08x\n"
+	       "\twhami\t\t0x%08x\n"
+	       "\tpciarb\t\t0x%08x\n"
+	       "\tpcicfg\t\t0x%08x\n"
+	       "\trsrvd6[0]\t0x%08x\n"
+	       "\trsrvd6[1]\t0x%08x\n"
+	       "\trsrvd6[2]\t0x%08x\n"
+	       "\trsrvd6[3]\t0x%08x\n"
+	       "\trsrvd6[4]\t0x%08x\n"
+	       "\tagpcap\t\t0x%08x\n"
+	       "\tagpstat\t\t0x%08x\n"
+	       "\tagpcmd\t\t0x%08x\n"
+	       "\tagpva\t\t0x%08x\n"
+	       "\tagpmode\t\t0x%08x\n",
+	       function_name,
+	       IRONGATE0->dev_vendor,
+	       IRONGATE0->stat_cmd,
+	       IRONGATE0->class,
+	       IRONGATE0->latency,
+	       IRONGATE0->bar0,
+	       IRONGATE0->bar1,
+	       IRONGATE0->bar2,
+	       IRONGATE0->rsrvd0[0],
+	       IRONGATE0->rsrvd0[1],
+	       IRONGATE0->rsrvd0[2],
+	       IRONGATE0->rsrvd0[3],
+	       IRONGATE0->rsrvd0[4],
+	       IRONGATE0->rsrvd0[5],
+	       IRONGATE0->capptr,
+	       IRONGATE0->rsrvd1[0],
+	       IRONGATE0->rsrvd1[1],
+	       IRONGATE0->bacsr10,
+	       IRONGATE0->bacsr32,
+	       IRONGATE0->bacsr54,
+	       IRONGATE0->rsrvd2[0],
+	       IRONGATE0->drammap,
+	       IRONGATE0->dramtm,
+	       IRONGATE0->dramms,
+	       IRONGATE0->rsrvd3[0],
+	       IRONGATE0->biu0,
+	       IRONGATE0->biusip,
+	       IRONGATE0->rsrvd4[0],
+	       IRONGATE0->rsrvd4[1],
+	       IRONGATE0->mro,
+	       IRONGATE0->rsrvd5[0],
+	       IRONGATE0->rsrvd5[1],
+	       IRONGATE0->rsrvd5[2],
+	       IRONGATE0->whami,
+	       IRONGATE0->pciarb,
+	       IRONGATE0->pcicfg,
+	       IRONGATE0->rsrvd6[0],
+	       IRONGATE0->rsrvd6[1],
+	       IRONGATE0->rsrvd6[2],
+	       IRONGATE0->rsrvd6[3],
+	       IRONGATE0->rsrvd6[4],
+	       IRONGATE0->agpcap,
+	       IRONGATE0->agpstat,
+	       IRONGATE0->agpcmd,
+	       IRONGATE0->agpva,
+	       IRONGATE0->agpmode);
+}
+#else
+#define irongate_register_dump(x)	1
+#endif
+
+void __init
+irongate_init_arch(unsigned long *mem_start, unsigned long *mem_end)
+{
+	struct linux_hose_info *hose;
+
+	irongate_register_dump(__FUNCTION__);
+
+	/* Align memory to cache line; we'll be allocating from it. */
+
+	*mem_start = (*mem_start | 31) + 1;
+
+	/*
+	 * Irongate only supports one PCI bus but do the hose thing anyway.
+	 * Anything to do for AGP???
+	 */
+
+	hose = (struct linux_hose_info *) *mem_start;
+	*mem_start = (unsigned long)(hose + 1);
+	memset(hose, 0, sizeof(*hose));
+	hose->pci_io_space = IRONGATE_IO;
+	hose->pci_mem_space = IRONGATE_MEM;
+	hose->pci_config_space = IRONGATE_CONF;
+	hose->pci_sparse_space = 0;
+	hose->pci_hose_index = 0;
+
+	/* add it to the hose list for bios32.[ch] */
+
+	*hose_tail = hose;
+	hose_tail = &hose->next;
+
+	IRONGATE0->stat_cmd = IRONGATE0->stat_cmd & ~0x100;
+	irongate_pci_clr_err();
+}
+
+int
+irongate_pci_clr_err(void)
+{
+	
+	unsigned int nmi_ctl=0;
+	unsigned int IRONGATE_jd;
+
+again:
+
+	IRONGATE_jd = IRONGATE0->stat_cmd;
+	printk("Iron stat_cmd %x\n", IRONGATE_jd);
+	IRONGATE0->stat_cmd = IRONGATE_jd; /* write again clears error bits */
+	mb();
+	IRONGATE_jd = IRONGATE0->stat_cmd;  /* re-read to force write */
+
+	IRONGATE_jd = IRONGATE0->dramms;
+	printk("Iron dramms %x\n", IRONGATE_jd);
+	IRONGATE0->dramms = IRONGATE_jd; /* write again clears error bits */
+	mb();
+	IRONGATE_jd = IRONGATE0->dramms;  /* re-read to force write */
+
+	/* Clear ALI NMI */
+        nmi_ctl = inb(0x61);
+        nmi_ctl |= 0x0c;
+        outb(nmi_ctl, 0x61);
+        nmi_ctl &= ~0x0c;
+        outb(nmi_ctl, 0x61);
+	
+	IRONGATE_jd = IRONGATE0->dramms;
+	if (IRONGATE_jd & 0x300) goto again;
+	
+	return 0;
+}
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/core_mcpcia.c linux.14p16/arch/alpha/kernel/core_mcpcia.c
--- linux.vanilla/arch/alpha/kernel/core_mcpcia.c	Sat Aug 28 20:00:53 1999
+++ linux.14p16/arch/alpha/kernel/core_mcpcia.c	Thu Dec  9 15:34:21 1999
@@ -24,6 +24,7 @@
 #include <asm/core_mcpcia.h>
 #undef __EXTERN_INLINE
 
+#include "machvec.h"
 #include "proto.h"
 #include "bios32.h"
 
@@ -51,9 +52,12 @@
 static volatile unsigned int MCPCIA_mcheck_taken[NR_CPUS];
 static volatile unsigned int MCPCIA_mcheck_hose[NR_CPUS];
 static unsigned int MCPCIA_jd[NR_CPUS];
+static unsigned int MCPCIA_mcheck_enable_print = 1;
+static unsigned int MCPCIA_mcheck_probing_hose = 0;
 
-#define MCPCIA_MAX_HOSES 2
+#define MCPCIA_MAX_HOSES	4
 
+static struct linux_hose_info *mcpcia_hoses[MCPCIA_MAX_HOSES];
 
 /*
  * Given a bus, device, and function number, compute resulting
@@ -297,24 +301,65 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
+static void
+mcpcia_pci_clr_err(int cpu, int hose)
+{
+	MCPCIA_jd[cpu] = *(vuip)MCPCIA_CAP_ERR(hose);
+	*(vuip)MCPCIA_CAP_ERR(hose) = 0xffffffff; mb(); /* clear them all */
+	MCPCIA_jd[cpu] = *(vuip)MCPCIA_CAP_ERR(hose); /* read to force write */
+}
+
 void __init
 mcpcia_init_arch(unsigned long *mem_start, unsigned long *mem_end)
 {
-	extern asmlinkage void entInt(void);
 	struct linux_hose_info *hose;
-	unsigned int mcpcia_err;
-	unsigned int pci_rev;
-	int h, cpu;
-
-	/* Ho hum.. init_arch is called before init_IRQ, but we need to be
-	   able to handle machine checks.  So install the handler now.  */
-	wrent(entInt, 0);
+	int h;
 
 	/* Align memory to cache line; we'll be allocating from it.  */
 	*mem_start = (*mem_start | 31) + 1;
 
+	/* First, allocate for the maximum number of hoses we might have.  */
+	for (h = 0; h < MCPCIA_MAX_HOSES; h++) {
+
+		hose = (struct linux_hose_info *)*mem_start;
+		*mem_start = (unsigned long)(hose + 1);
+
+		memset(hose, 0, sizeof(*hose));
+
+		mcpcia_hoses[h] = hose;
+
+		hose->pci_io_space = MCPCIA_IO(h);
+		hose->pci_mem_space = MCPCIA_DENSE(h);
+		hose->pci_config_space = MCPCIA_CONF(h);
+		hose->pci_sparse_space = MCPCIA_SPARSE(h);
+		hose->pci_hose_index = h;
+		hose->pci_first_busno = 255;
+		hose->pci_last_busno = 0;
+	}
+
+#if 1
+	printk("mcpcia_init_arch: allocating for %d hoses\n",
+	       MCPCIA_MAX_HOSES);
+#endif
+}
+
+/*
+ * This is called from init_IRQ, since we cannot take interrupts
+ * before then, so we cannot do this in init_arch.
+ */
+void __init
+mcpcia_init_hoses(void)
+{
+	struct linux_hose_info *hose;
+	unsigned int mcpcia_err;
+	unsigned int pci_rev;
+	int h, cpu;
+
 	cpu = smp_processor_id();
 
+	MCPCIA_mcheck_enable_print = 0;
+	MCPCIA_mcheck_probing_hose = 1;
+
 	/* First, find how many hoses we have.  */
 	for (h = 0; h < MCPCIA_MAX_HOSES; h++) {
 
@@ -324,50 +369,49 @@
 		mb();
 		mb();
 		draina();
+		wrmces(7);
 		MCPCIA_mcheck_expected[cpu] = 1;
 		MCPCIA_mcheck_taken[cpu]    = 0;
+		MCPCIA_mcheck_hose[cpu] = h;
+		pci_rev = 0xffffffff;
 		mb();
 
 		/* Access the bus revision word. */
 		pci_rev = *(vuip)MCPCIA_REV(h);
 
+#if 0
+		draina(); /* huh? */
+#endif
+
 		mb();
 		mb();  /* magic */
 		if (MCPCIA_mcheck_taken[cpu]) {
 			MCPCIA_mcheck_taken[cpu] = 0;
 			pci_rev = 0xffffffff;
 			mb();
+			break;
 		}
 		MCPCIA_mcheck_expected[cpu] = 0;
 		mb();
 
-#if 0
-		printk("mcpcia_init_arch: got 0x%x for PCI_REV for hose %d\n",
-		       pci_rev, h);
-#endif
 		if ((pci_rev >> 16) == PCI_CLASS_BRIDGE_HOST) {
+
 			hose_count++;
 
-			hose = (struct linux_hose_info *)*mem_start;
-			*mem_start = (unsigned long)(hose + 1);
+			mcpcia_pci_clr_err(cpu, h);
 
-			memset(hose, 0, sizeof(*hose));
+			hose = mcpcia_hoses[h];
 
 			*hose_tail = hose;
 			hose_tail = &hose->next;
-
-			hose->pci_io_space = MCPCIA_IO(h);
-			hose->pci_mem_space = MCPCIA_DENSE(h);
-			hose->pci_config_space = MCPCIA_CONF(h);
-			hose->pci_sparse_space = MCPCIA_SPARSE(h);
-			hose->pci_hose_index = h;
-			hose->pci_first_busno = 255;
-			hose->pci_last_busno = 0;
 		}
 	}
 
+	MCPCIA_mcheck_enable_print = 1;
+	MCPCIA_mcheck_probing_hose = 0;
+
 #if 1
-	printk("mcpcia_init_arch: found %d hoses\n", hose_count);
+	printk("mcpcia_init_hoses: found %d hoses\n", hose_count);
 #endif
 
 	/* Now do init for each hose.  */
@@ -390,22 +434,16 @@
 		printk("MCPCIA_HBASE 0x%x\n", *(vuip)MCPCIA_HBASE(h));
 #endif
 
+#if 1
 		/* 
-		 * Set up error reporting. Make sure CPU_PE is OFF in the mask.
+		 * Set up error reporting.
 		 */
-#if 0
-		mcpcia_err = *(vuip)MCPCIA_ERR_MASK(h);
-		mcpcia_err &= ~4;   
-		*(vuip)MCPCIA_ERR_MASK(h) = mcpcia_err;
-		mb();
-		mcpcia_err = *(vuip)MCPCIA_ERR_MASK;
-#endif
-
 		mcpcia_err = *(vuip)MCPCIA_CAP_ERR(h);
 		mcpcia_err |= 0x0006;   /* master/target abort */
 		*(vuip)MCPCIA_CAP_ERR(h) = mcpcia_err;
 		mb() ;
 		mcpcia_err = *(vuip)MCPCIA_CAP_ERR(h);
+#endif
 
 		switch (alpha_use_srm_setup)
 		{
@@ -486,11 +524,10 @@
 		case 0:
 			/*
 			 * Set up the PCI->physical memory translation windows.
-			 * For now, windows 1,2 and 3 are disabled.  In the
-			 * future, we may want to use them to do scatter/
-			 * gather DMA.
+			 * For now, windows 2 and 3 are disabled. 
 			 *
 			 * Window 0 goes at 2 GB and is 2 GB large.
+			 * Window 1 goes at ? MB and is ? MB large, S/G.
 			 */
 
 			*(vuip)MCPCIA_W0_BASE(h) = 1U | (MCPCIA_DMA_WIN_BASE_DEFAULT & 0xfff00000U);
@@ -551,14 +588,6 @@
 }
 
 static void
-mcpcia_pci_clr_err(int cpu, int hose)
-{
-	MCPCIA_jd[cpu] = *(vuip)MCPCIA_CAP_ERR(hose);
-	*(vuip)MCPCIA_CAP_ERR(hose) = 0xffffffff; mb(); /* clear them all */
-	MCPCIA_jd[cpu] = *(vuip)MCPCIA_CAP_ERR(hose); /* read to force write */
-}
-
-static void
 mcpcia_print_uncorrectable(struct el_MCPCIA_uncorrected_frame_mcheck *logout)
 {
 	struct el_common_EV5_uncorrectable_mcheck *frame;
@@ -568,65 +597,64 @@
 
 	/* Print PAL fields */
 	for (i = 0; i < 24; i += 2) {
-		printk("\tpal temp[%d-%d]\t\t= %16lx %16lx\n",
+		printk("  paltmp[%2d-%2d]    = %16lx %16lx\n",
 		       i, i+1, frame->paltemp[i], frame->paltemp[i+1]);
 	}
 	for (i = 0; i < 8; i += 2) {
-		printk("\tshadow[%d-%d]\t\t= %16lx %16lx\n",
+		printk("  shadow[%2d-%2d]     = %16lx %16lx\n",
 		       i, i+1, frame->shadow[i], 
 		       frame->shadow[i+1]);
 	}
-	printk("\tAddr of excepting instruction\t= %16lx\n",
+	printk("  Addr of excepting instruction  = %16lx\n",
 	       frame->exc_addr);
-	printk("\tSummary of arithmetic traps\t= %16lx\n",
+	printk("  Summary of arithmetic traps    = %16lx\n",
 	       frame->exc_sum);
-	printk("\tException mask\t\t\t= %16lx\n",
+	printk("  Exception mask                 = %16lx\n",
 	       frame->exc_mask);
-	printk("\tBase address for PALcode\t= %16lx\n",
+	printk("  Base address for PALcode       = %16lx\n",
 	       frame->pal_base);
-	printk("\tInterrupt Status Reg\t\t= %16lx\n",
+	printk("  Interrupt Status Reg           = %16lx\n",
 	       frame->isr);
-	printk("\tCURRENT SETUP OF EV5 IBOX\t= %16lx\n",
+	printk("  CURRENT SETUP OF EV5 IBOX      = %16lx\n",
 	       frame->icsr);
-	printk("\tI-CACHE Reg %s parity error\t= %16lx\n",
-	       (frame->ic_perr_stat & 0x800L) ? 
-	       "Data" : "Tag", 
+	printk("  I-CACHE Reg %s parity error    = %16lx\n",
+	       (frame->ic_perr_stat & 0x800L) ? "Data" : "Tag", 
 	       frame->ic_perr_stat); 
-	printk("\tD-CACHE error Reg\t\t= %16lx\n",
+	printk("  D-CACHE error Reg              = %16lx\n",
 	       frame->dc_perr_stat);
 	if (frame->dc_perr_stat & 0x2) {
 		switch (frame->dc_perr_stat & 0x03c) {
 		case 8:
-			printk("\t\tData error in bank 1\n");
+			printk("    Data error in bank 1\n");
 			break;
 		case 4:
-			printk("\t\tData error in bank 0\n");
+			printk("    Data error in bank 0\n");
 			break;
 		case 20:
-			printk("\t\tTag error in bank 1\n");
+			printk("    Tag error in bank 1\n");
 			break;
 		case 10:
-			printk("\t\tTag error in bank 0\n");
+			printk("    Tag error in bank 0\n");
 			break;
 		}
 	}
-	printk("\tEffective VA\t\t\t= %16lx\n",
+	printk("  Effective VA                   = %16lx\n",
 	       frame->va);
-	printk("\tReason for D-stream\t\t= %16lx\n",
+	printk("  Reason for D-stream            = %16lx\n",
 	       frame->mm_stat);
-	printk("\tEV5 SCache address\t\t= %16lx\n",
+	printk("  EV5 SCache address             = %16lx\n",
 	       frame->sc_addr);
-	printk("\tEV5 SCache TAG/Data parity\t= %16lx\n",
+	printk("  EV5 SCache TAG/Data parity     = %16lx\n",
 	       frame->sc_stat);
-	printk("\tEV5 BC_TAG_ADDR\t\t\t= %16lx\n",
+	printk("  EV5 BC_TAG_ADDR                = %16lx\n",
 	       frame->bc_tag_addr);
-	printk("\tEV5 EI_ADDR: Phys addr of Xfer\t= %16lx\n",
+	printk("  EV5 EI_ADDR: Phys addr of Xfer = %16lx\n",
 	       frame->ei_addr);
-	printk("\tFill Syndrome\t\t\t= %16lx\n",
+	printk("  Fill Syndrome                  = %16lx\n",
 	       frame->fill_syndrome);
-	printk("\tEI_STAT reg\t\t\t= %16lx\n",
+	printk("  EI_STAT reg                    = %16lx\n",
 	       frame->ei_stat);
-	printk("\tLD_LOCK\t\t\t\t= %16lx\n",
+	printk("  LD_LOCK                        = %16lx\n",
 	       frame->ld_lock);
 }
 
@@ -636,32 +664,53 @@
 {
 	struct el_common *mchk_header;
 	struct el_MCPCIA_uncorrected_frame_mcheck *mchk_logout;
-	unsigned int cpu = smp_processor_id();
+	unsigned int cpu;
+#if 0
+halt();
+#endif
+	mb();
+	mb();  /* magic */
+#if 0
+	draina();
+#endif
 
 	mchk_header = (struct el_common *)la_ptr;
 	mchk_logout = (struct el_MCPCIA_uncorrected_frame_mcheck *)la_ptr;
 
-	mb();
-	mb();  /* magic */
-	draina();
-	if (MCPCIA_mcheck_expected[cpu])
+	cpu = smp_processor_id();
+
+	if (!MCPCIA_mcheck_probing_hose) {
+
+	    if (MCPCIA_mcheck_expected[cpu])
 		mcpcia_pci_clr_err(cpu, MCPCIA_mcheck_hose[cpu]);
-	else {
+	    else {
 		/* FIXME: how do we figure out which hose the error was on? */
 		mcpcia_pci_clr_err(cpu, 0);
 		mcpcia_pci_clr_err(cpu, 1);
+	    }
+
+	} else {
+		/* FIXME: clear out known always good hoses */
+		mcpcia_pci_clr_err(cpu, 0);
+		mcpcia_pci_clr_err(cpu, 1);
 	}
+
 	wrmces(0x7);
 	mb();
 
-	process_mcheck_info(vector, la_ptr, regs, "MCPCIA",
-			    DEBUG_MCHECK, MCPCIA_mcheck_expected[cpu]);
+	if (MCPCIA_mcheck_enable_print) {
+
+	    process_mcheck_info(vector, la_ptr, regs, "MCPCIA",
+				DEBUG_MCHECK, MCPCIA_mcheck_expected[cpu]);
 
-	if (vector != 0x620 && vector != 0x630
-	    && ! MCPCIA_mcheck_expected[cpu]) {
+	    if (vector != 0x620 && vector != 0x630
+		&& ! MCPCIA_mcheck_expected[cpu]) {
 		mcpcia_print_uncorrectable(mchk_logout);
+	    }
 	}
 
+#if 0
 	MCPCIA_mcheck_expected[cpu] = 0;
+#endif
 	MCPCIA_mcheck_taken[cpu] = 1;
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/core_pyxis.c linux.14p16/arch/alpha/kernel/core_pyxis.c
--- linux.vanilla/arch/alpha/kernel/core_pyxis.c	Sat Aug 14 02:27:12 1999
+++ linux.14p16/arch/alpha/kernel/core_pyxis.c	Thu Dec  9 15:34:20 1999
@@ -43,8 +43,6 @@
 
 static volatile unsigned int PYXIS_mcheck_expected = 0;
 static volatile unsigned int PYXIS_mcheck_taken = 0;
-static unsigned int PYXIS_jd;
-
 
 /*
  * Given a bus, device, and function number, compute resulting
@@ -526,23 +524,17 @@
 pyxis_machine_check(unsigned long vector, unsigned long la_ptr,
 		    struct pt_regs * regs)
 {
-	struct el_common *mchk_header;
-	struct el_PYXIS_sysdata_mcheck *mchk_sysdata;
-
-	mchk_header = (struct el_common *)la_ptr;
-
-	mchk_sysdata = (struct el_PYXIS_sysdata_mcheck *)
-		(la_ptr + mchk_header->sys_offset);
+	unsigned int tmp;
 
 	/* Clear the error before reporting anything. */
 	mb();
 	mb();  /* magic */
 	draina();
 
-	PYXIS_jd = *(vuip)PYXIS_ERR;
-	*(vuip)PYXIS_ERR = PYXIS_jd;
+	tmp = *(vuip)PYXIS_ERR;
+	*(vuip)PYXIS_ERR = tmp;
 	mb();
-	PYXIS_jd = *(vuip)PYXIS_ERR;  /* re-read to force write */
+	*(vuip)PYXIS_ERR;  /* re-read to force write */
 
 	wrmces(0x7);
 	mb();
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/core_tsunami.c linux.14p16/arch/alpha/kernel/core_tsunami.c
--- linux.vanilla/arch/alpha/kernel/core_tsunami.c	Sat Aug 14 02:27:12 1999
+++ linux.14p16/arch/alpha/kernel/core_tsunami.c	Thu Dec  9 15:34:21 1999
@@ -164,6 +164,8 @@
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
 	__kernel_stb(value, *(vucp)addr);
+	mb();
+	__kernel_ldbu(*(vucp)addr);
 	return PCIBIOS_SUCCESSFUL;
 }
 
@@ -178,6 +180,8 @@
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
 	__kernel_stw(value, *(vusp)addr);
+	mb();
+	__kernel_ldwu(*(vusp)addr);
 	return PCIBIOS_SUCCESSFUL;
 }
 
@@ -192,6 +196,8 @@
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
 	*(vuip)addr = value;
+	mb();
+	*(vuip)addr;
 	return PCIBIOS_SUCCESSFUL;
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/entry.S linux.14p16/arch/alpha/kernel/entry.S
--- linux.vanilla/arch/alpha/kernel/entry.S	Sat Aug 14 02:26:09 1999
+++ linux.14p16/arch/alpha/kernel/entry.S	Wed Dec 15 18:43:01 1999
@@ -82,8 +82,8 @@
 	ldq	$1,8($30);		\
 	ldq	$2,16($30);		\
 	ldq	$3,24($30);		\
-	ldq	$20,152($30);		\
-	ldq	$21,HAE_CACHE($19);	\
+	ldq	$20,HAE_CACHE($19);	\
+	ldq	$21,152($30);		\
 	ldq	$4,32($30);		\
 	ldq	$5,40($30);		\
 	ldq	$6,48($30);		\
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/irq.c linux.14p16/arch/alpha/kernel/irq.c
--- linux.vanilla/arch/alpha/kernel/irq.c	Sat Aug 14 02:27:12 1999
+++ linux.14p16/arch/alpha/kernel/irq.c	Thu Dec  9 15:34:20 1999
@@ -35,12 +35,16 @@
 #define vulp	volatile unsigned long *
 #define vuip	volatile unsigned int *
 
-unsigned int local_irq_count[NR_CPUS];
-unsigned int local_bh_count[NR_CPUS];
-unsigned long hardirq_no[NR_CPUS];
+/* Only uniprocessor needs this IRQ/BH locking depth, on SMP it
+ * lives in the per-cpu structure for cache reasons.
+ */
+#ifndef __SMP__
+unsigned long local_bh_count;
+unsigned long local_irq_count;
+#endif
 
-#if NR_IRQS > 64
-#  error Unable to handle more than 64 irq levels.
+#if NR_IRQS > 128
+#  error Unable to handle more than 128 irq levels.
 #endif
 
 #ifdef CONFIG_ALPHA_GENERIC
@@ -57,7 +61,7 @@
 /*
  * Shadow-copy of masked interrupts.
  */
-unsigned long alpha_irq_mask = ~0UL;
+unsigned long _alpha_irq_masks[2] = {~0UL, ~0UL };
 
 /*
  * The ack_irq routine used by 80% of the systems.
@@ -107,6 +111,8 @@
 # define IACK_SC	TSUNAMI_IACK_SC
 #elif defined(CONFIG_ALPHA_POLARIS)
 # define IACK_SC	POLARIS_IACK_SC
+#elif defined(CONFIG_ALPHA_IRONGATE)
+# define IACK_SC        IRONGATE_IACK_SC
 #else
   /* This is bogus but necessary to get it to compile on all platforms. */
 # define IACK_SC	1L
@@ -182,13 +188,15 @@
 static inline void
 mask_irq(unsigned long irq)
 {
-	alpha_mv.update_irq_hw(irq, alpha_irq_mask |= 1UL << irq, 0);
+	set_bit(irq, _alpha_irq_masks);
+	alpha_mv.update_irq_hw(irq, alpha_irq_mask, 0);
 }
 
 static inline void
 unmask_irq(unsigned long irq)
 {
-	alpha_mv.update_irq_hw(irq, alpha_irq_mask &= ~(1UL << irq), 1);
+	clear_bit(irq, _alpha_irq_masks);
+	alpha_mv.update_irq_hw(irq, alpha_irq_mask, 1);
 }
 
 void
@@ -205,7 +213,7 @@
 disable_irq(unsigned int irq_nr)
 {
 	/* This works non-SMP, and SMP until we write code to distribute
-	   interrupts to more that cpu 0.  */
+	   interrupts to more than CPU 0.  */
 	disable_irq_nosync(irq_nr);
 }
 
@@ -384,6 +392,8 @@
 
 static void show(char * str, void *where);
 
+#define SYNC_OTHER_CPUS(x)	udelay((x)+1)
+
 static inline void
 wait_on_irq(int cpu, void *where)
 {
@@ -397,8 +407,7 @@
 		 * already executing in one..
 		 */
 		if (!atomic_read(&global_irq_count)) {
-			if (local_bh_count[cpu] ||
-			    !atomic_read(&global_bh_count))
+			if (local_bh_count || !atomic_read(&global_bh_count))
 				break;
 		}
 
@@ -412,18 +421,14 @@
 				count = MAXCOUNT;
 			}
 			__sti();
-#if 0
-			SYNC_OTHER_CORES(cpu);
-#else
-			udelay(cpu+1);
-#endif
+			SYNC_OTHER_CPUS(cpu);
 			__cli();
 
 			if (atomic_read(&global_irq_count))
 				continue;
-			if (global_irq_lock.lock)
+			if (spin_is_locked(&global_irq_lock))
 				continue;
-			if (!local_bh_count[cpu] &&
+			if (!local_bh_count &&
 			    atomic_read(&global_bh_count))
 				continue;
 			if (spin_trylock(&global_irq_lock))
@@ -437,13 +442,8 @@
 {
 	if (!spin_trylock(&global_irq_lock)) {
 		/* do we already hold the lock? */
-		if (cpu == global_irq_holder) {
-#if 0
-			printk("get_irqlock: already held at %08lx\n",
-			       previous_irqholder);
-#endif
+		if (cpu == global_irq_holder)
 			return;
-		}
 		/* Uhhuh.. Somebody else got it. Wait.. */
 		spin_lock(&global_irq_lock);
 	}
@@ -469,25 +469,19 @@
 void
 __global_cli(void)
 {
-	int cpu;
-	void *where = __builtin_return_address(0);
-
 	/*
 	 * Maximize ipl.  If ipl was previously 0 and if this thread
 	 * is not in an irq, then take global_irq_lock.
 	 */
-	if ((swpipl(7) == 0) && !local_irq_count[cpu = smp_processor_id()])
-		get_irqlock(cpu, where);
+	if ((swpipl(7) == 0) && !local_irq_count)
+		get_irqlock(smp_processor_id(), __builtin_return_address(0));
 }
 
 void
 __global_sti(void)
 {
-        int cpu = smp_processor_id();
-
-        if (!local_irq_count[cpu]) {
-		release_irqlock(cpu);
-	}
+        if (!local_irq_count)
+		release_irqlock(smp_processor_id());
 	__sti();
 }
 
@@ -512,7 +506,7 @@
         retval = 2 + local_enabled;
 
         /* Check for global flags if we're not in an interrupt.  */
-        if (!local_irq_count[cpu]) {
+        if (!local_irq_count) {
                 if (local_enabled)
                         retval = 1;
                 if (global_irq_holder == cpu)
@@ -566,11 +560,10 @@
 
 	hardirq_enter(cpu, irq);
 	barrier();
-	while (global_irq_lock.lock) {
+	while (spin_is_locked(&global_irq_lock)) {
 		if (cpu == global_irq_holder) {
-			int globl_locked = global_irq_lock.lock;
+			int globl_locked = spin_is_locked(&global_irq_lock);
 			int globl_icount = atomic_read(&global_irq_count);
-			int local_count = local_irq_count[cpu];
 
 			/* It is very important that we load the state
 			   variables before we do the first call to
@@ -578,9 +571,9 @@
 			   them...  */
 
 			printk("CPU[%d]: where [%p] glocked[%d] gicnt[%d]"
-			       " licnt[%d]\n",
+			       " licnt[%ld]\n",
 			       cpu, previous_irqholder, globl_locked,
-			       globl_icount, local_count);
+			       globl_icount, local_irq_count);
 #ifdef VERBOSE_IRQLOCK_DEBUGGING
 			printk("Performing backtrace on all CPUs,"
 			       " write this down!\n");
@@ -609,19 +602,17 @@
 #endif
         int cpu = smp_processor_id();
 
-	int global_count = atomic_read(&global_irq_count);
-        int local_count0 = local_irq_count[0];
-        int local_count1 = local_irq_count[1];
-        long hardirq_no0 = hardirq_no[0];
-        long hardirq_no1 = hardirq_no[1];
-
         printk("\n%s, CPU %d: %p\n", str, cpu, where);
-        printk("irq:  %d [%d(0x%016lx) %d(0x%016lx)]\n", global_count,
-               local_count0, hardirq_no0, local_count1, hardirq_no1);
+	printk("irq:  %d [%ld %ld]\n",
+	       atomic_read(&global_irq_count),
+	       cpu_data[0].irq_count,
+	       cpu_data[1].irq_count);
+
+	printk("bh:   %d [%ld %ld]\n",
+	       atomic_read(&global_bh_count),
+	       cpu_data[0].bh_count,
+	       cpu_data[1].bh_count);
 
-        printk("bh:   %d [%d %d]\n",
-	       atomic_read(&global_bh_count), local_bh_count[0],
-	       local_bh_count[1]);
 #if 0
         stack = (unsigned long *) &str;
         for (i = 40; i ; i--) {
@@ -644,6 +635,7 @@
                         count = ~0;
                 }
                 /* nothing .. wait for the other bh's to go away */
+		barrier();
         } while (atomic_read(&global_bh_count) != 0);
 }
 
@@ -658,12 +650,8 @@
 void
 synchronize_bh(void)
 {
-	if (atomic_read(&global_bh_count)) {
-		int cpu = smp_processor_id();
-                if (!local_irq_count[cpu] && !local_bh_count[cpu]) {
+	if (atomic_read(&global_bh_count) && !in_interrupt())
 			wait_on_bh();
-		}
-        }
 }
 
 /*
@@ -680,6 +668,7 @@
 void
 synchronize_irq(void)
 {
+#ifdef JOES_ORIGINAL_VERSION
 	int cpu = smp_processor_id();
 	int local_count;
 	int global_count;
@@ -688,7 +677,7 @@
 
 	mb();
 	do {
-		local_count = local_irq_count[cpu];
+		local_count = local_irq_count;
 		global_count = atomic_read(&global_irq_count);
 		if (DEBUG_SYNCHRONIZE_IRQ && (--countdown == 0)) {
 			printk("%d:%d/%d\n", cpu, local_count, global_count);
@@ -696,12 +685,19 @@
 			break;
 		}
 	} while (global_count != local_count);
+#else
+	if (atomic_read(&global_irq_count)) {
+		/* Stupid approach */
+		cli();
+		sti();
+	}
+#endif
 }
 
 #else /* !__SMP__ */
 
-#define irq_enter(cpu, irq)	(++local_irq_count[cpu])
-#define irq_exit(cpu, irq)	(--local_irq_count[cpu])
+#define irq_enter(cpu, irq)	(++local_irq_count)
+#define irq_exit(cpu, irq)	(--local_irq_count)
 
 #endif /* __SMP__ */
 
@@ -816,7 +812,8 @@
 	unsigned long delay;
 	unsigned int i;
 
-	for (i = ACTUAL_NR_IRQS - 1; i > 0; i--) {
+	/* Handle only the first 64 IRQs here. */
+	for (i = (ACTUAL_NR_IRQS - 1) & 63; i > 0; i--) {
 		if (!(PROBE_MASK & (1UL << i))) {
 			continue;
 		}
@@ -849,6 +846,7 @@
 {
 	int i;
 	
+	/* Handle only the first 64 IRQs here. */
         irqs &= alpha_irq_mask;
 	if (!irqs)
 		return 0;
@@ -933,6 +931,19 @@
 		       (expected?"expected.":"NOT expected!!!"));
 	if (expected)
 		return;
+
+	/* Just in case we get some incomplete arguments... */
+	if (!la_ptr) {
+	    if (!regs)
+		printk(KERN_CRIT "%s machine check: vector=0x%lx\n",
+		       machine, vector);
+	    else
+		printk(KERN_CRIT "%s machine check: vector=0x%lx"
+		       " pc=0x%lx ra=0x%lx args=0x%lx/0x%lx/0x%lx\n",
+		       machine, vector, regs->pc, regs->r26,
+		       regs->r16, regs->r17, regs->r18);
+	    return;
+	}
 
 	mchk_header = (struct el_common *)la_ptr;
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/irq.h linux.14p16/arch/alpha/kernel/irq.h
--- linux.vanilla/arch/alpha/kernel/irq.h	Sat Aug 14 02:27:12 1999
+++ linux.14p16/arch/alpha/kernel/irq.h	Thu Dec  9 15:34:20 1999
@@ -9,6 +9,7 @@
  */
 
 #include <linux/config.h>
+#include <asm/irq.h>
 
 #define STANDARD_INIT_IRQ_PROLOG	\
 	outb(0, DMA1_RESET_REG);	\
@@ -16,7 +17,8 @@
 	outb(0, DMA1_CLR_MASK_REG);	\
 	outb(0, DMA2_CLR_MASK_REG)
 
-extern unsigned long alpha_irq_mask;
+extern unsigned long _alpha_irq_masks[2];
+#define alpha_irq_mask _alpha_irq_masks[0]
 
 extern void generic_ack_irq(unsigned long irq);
 extern void isa_device_interrupt(unsigned long vector, struct pt_regs * regs);
@@ -47,4 +49,41 @@
 #else
 #define TIMER_IRQ  RTC_IRQ		 /* timer is the rtc */
 #endif
+
+/*
+ * PROBE_MASK is the bitset of irqs that we consider for autoprobing.
+ */
+
+/* NOTE: we only handle the first 64 IRQs in this code. */
+
+/* The normal mask includes all the IRQs except timer IRQ 0.  */
+#define _PROBE_MASK(nr_irqs)	\
+	(((nr_irqs > 63) ? ~0UL : ((1UL << (nr_irqs & 63)) - 1)) & ~1UL)
+
+/* Mask out unused timer irq 0 and RTC irq 8. */
+#define P2K_PROBE_MASK		(_PROBE_MASK(16) & ~0x101UL)
+
+/* Mask out unused timer irq 0, "irqs" 20-30, and the EISA cascade. */
+#define ALCOR_PROBE_MASK	(_PROBE_MASK(48) & ~0xfff000000001UL)
+
+/* Leave timer IRQ 0 in the mask.  */
+#define RUFFIAN_PROBE_MASK	(_PROBE_MASK(48) | 1UL)
+
+/* Do not probe/enable beyond the PCI devices. */
+#define TSUNAMI_PROBE_MASK	_PROBE_MASK(48)
+
+#if defined(CONFIG_ALPHA_GENERIC)
+# define PROBE_MASK	alpha_mv.irq_probe_mask
+#elif defined(CONFIG_ALPHA_P2K)
+# define PROBE_MASK	P2K_PROBE_MASK
+#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
+# define PROBE_MASK	ALCOR_PROBE_MASK
+#elif defined(CONFIG_ALPHA_RUFFIAN)
+# define PROBE_MASK	RUFFIAN_PROBE_MASK
+#elif defined(CONFIG_ALPHA_DP264)
+# define PROBE_MASK	TSUNAMI_PROBE_MASK
+#else
+# define PROBE_MASK	_PROBE_MASK(NR_IRQS)
+#endif
+
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/machvec.h linux.14p16/arch/alpha/kernel/machvec.h
--- linux.vanilla/arch/alpha/kernel/machvec.h	Sat Aug 14 02:27:12 1999
+++ linux.14p16/arch/alpha/kernel/machvec.h	Thu Dec  9 15:34:21 1999
@@ -18,6 +18,11 @@
    we can read and write it as we like.  ;-)  */
 #define POLARIS_HAE_ADDRESS	(&alpha_mv.hae_cache)
 
+/* Whee.  IRONGATE doesn't have an HAE.  Fix things up for the GENERIC
+   kernel by defining the HAE address to be that of the cache.  Now
+   we can read and write it as we like.  ;-)  */
+#define IRONGATE_HAE_ADDRESS	(&alpha_mv.hae_cache)
+
 /* Only a few systems don't define IACK_SC, handling all interrupts through
    the SRM console.  But splitting out that one case from IO() below
    seems like such a pain.  Define this to get things to compile.  */
@@ -90,6 +95,7 @@
 
 #define DO_APECS_IO	IO(APECS,apecs,apecs)
 #define DO_CIA_IO	IO(CIA,cia,cia)
+#define DO_IRONGATE_IO	IO(IRONGATE,irongate,irongate)
 #define DO_LCA_IO	IO(LCA,lca,lca)
 #define DO_MCPCIA_IO	IO(MCPCIA,mcpcia,mcpcia)
 #define DO_PYXIS_IO	IO(PYXIS,pyxis_bw,pyxis)
@@ -103,6 +109,7 @@
 
 #define DO_APECS_BUS	BUS(apecs)
 #define DO_CIA_BUS	BUS(cia)
+#define DO_IRONGATE_BUS	BUS(irongate)
 #define DO_LCA_BUS	BUS(lca)
 #define DO_MCPCIA_BUS	BUS(mcpcia)
 #define DO_PYXIS_BUS	BUS(pyxis)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/process.c linux.14p16/arch/alpha/kernel/process.c
--- linux.vanilla/arch/alpha/kernel/process.c	Sat Aug 28 20:00:53 1999
+++ linux.14p16/arch/alpha/kernel/process.c	Thu Dec  9 15:34:20 1999
@@ -117,58 +117,44 @@
 	}
 }
 
-void
-generic_kill_arch (int mode, char *restart_cmd)
-{
-	/* The following currently only has any effect on SRM.  We should
-	   fix MILO to understand it.  Should be pretty easy.  Also we can
-	   support RESTART2 via the ipc_buffer machinations pictured below,
-	   which SRM ignores.  */
-
-	if (alpha_using_srm) {
-		struct percpu_struct *cpup;
-		unsigned long flags;
-	
-		cpup = (struct percpu_struct *)
-		  ((unsigned long)hwrpb + hwrpb->processor_offset);
-
-		flags = cpup->flags;
-
-		/* Clear reason to "default"; clear "bootstrap in progress". */
-		flags &= ~0x00ff0001UL;
-
-		if (mode == LINUX_REBOOT_CMD_RESTART) {
-			if (!restart_cmd) {
-				flags |= 0x00020000UL; /* "cold bootstrap" */
-				cpup->ipc_buffer[0] = 0;
-			} else {
-				flags |=  0x00030000UL; /* "warm bootstrap" */
-				strncpy((char *)cpup->ipc_buffer, restart_cmd,
-					sizeof(cpup->ipc_buffer));
-			}
-		} else {
-			flags |=  0x00040000UL; /* "remain halted" */
-		}
-			
-		cpup->flags = flags;					       
-		mb();						
-
-		reset_for_srm();
-		set_hae(srm_hae);
+struct halt_info {
+	int	mode;
+	char *	restart_cmd;
+};
 
-#ifdef CONFIG_DUMMY_CONSOLE
-		/* This has the effect of reseting the VGA video origin.  */
-		take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1);
-#endif
+static void
+halt_processor(void * generic_ptr)
+{
+	struct percpu_struct * cpup;
+	struct halt_info * how = (struct halt_info *)generic_ptr;
+	unsigned long *flags;
+	int cpuid = smp_processor_id();
+
+	/* No point in taking interrupts anymore. */
+	__cli();
+
+	cpup = (struct percpu_struct *)
+			((unsigned long)hwrpb + hwrpb->processor_offset
+			 + hwrpb->processor_size * cpuid);
+	flags = &cpup->flags;
+
+	/* Clear reason to "default"; clear "bootstrap in progress". */
+	*flags &= ~0x00ff0001UL;
+
+#ifdef __SMP__
+	/* Secondaries halt here. */
+	if (cpuid != smp_boot_cpuid) {
+		*flags |= 0x00040000UL; /* "remain halted" */
+		clear_bit(cpuid, &cpu_present_mask);
+		halt();
 	}
+#endif /* __SMP__ */
 
 #ifdef CONFIG_RTC
 	/* Reset rtc to defaults.  */
 	{
 		unsigned char control;
 
-		cli();
-
 		/* Reset periodic interrupt frequency.  */
 		CMOS_WRITE(0x26, RTC_FREQ_SELECT);
 
@@ -177,22 +163,73 @@
 		control |= RTC_PIE;
 		CMOS_WRITE(control, RTC_CONTROL);	
 		CMOS_READ(RTC_INTR_FLAGS);
-
-		sti();
 	}
-#endif
+#endif /* CONFIG_RTC */
 
-	if (!alpha_using_srm && mode != LINUX_REBOOT_CMD_RESTART) {
+	if (how->mode == LINUX_REBOOT_CMD_RESTART) {
+		if (!how->restart_cmd) {
+			*flags |= 0x00020000UL; /* "cold bootstrap" */
+			cpup->ipc_buffer[0] = 0;
+		} else {
+		  /* NOTE: this could really only work when returning
+		     into MILO, rather than SRM console. The latter
+		     does NOT look at the ipc_buffer to get a new
+		     boot command. It could be done by using callbacks
+		     to change some of the SRM environment variables,
+		     but that is beyond our capabilities at this time.
+		     At the moment, SRM will use the last boot device,
+		     but the file and flags will be the defaults, when
+		     doing a "warm" bootstrap.
+		  */
+			*flags |=  0x00030000UL; /* "warm bootstrap" */
+			strncpy((char *)cpup->ipc_buffer,
+				how->restart_cmd,
+				sizeof(cpup->ipc_buffer));
+		}
+	} else
+		*flags |=  0x00040000UL; /* "remain halted" */
+
+#ifdef __SMP__
+	/* Wait for the secondaries to halt. */
+	clear_bit(smp_boot_cpuid, &cpu_present_mask);
+	while (cpu_present_mask)
+		/* Make sure we sample memory and not a register. */
+		barrier();
+#endif /* __SMP__ */
+
+        /* If booted from SRM, reset some of the original environment. */
+	if (alpha_using_srm) {
+#ifdef CONFIG_DUMMY_CONSOLE
+		/* This has the effect of resetting the VGA video origin.  */
+		take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1);
+#endif
+		reset_for_srm();
+		set_hae(srm_hae);
+	}
+	else if (how->mode != LINUX_REBOOT_CMD_RESTART &&
+		 how->mode != LINUX_REBOOT_CMD_RESTART2) {
 		/* Unfortunately, since MILO doesn't currently understand
 		   the hwrpb bits above, we can't reliably halt the 
 		   processor and keep it halted.  So just loop.  */
 		return;
 	}
 
-	if (alpha_using_srm)
-		srm_paging_stop();
-
+	/* PRIMARY */
 	halt();
+}
+
+void
+generic_kill_arch(int mode, char * restart_cmd)
+{
+	struct halt_info copy_of_args;
+
+	copy_of_args.mode = mode;
+	copy_of_args.restart_cmd = restart_cmd;
+#ifdef __SMP__
+	/* A secondary can't wait here for the primary to finish, can it now? */
+	smp_call_function(halt_processor, (void *)&copy_of_args, 1, 0);
+#endif /* __SMP__ */
+	halt_processor(&copy_of_args);
 }
 
 void
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/proto.h linux.14p16/arch/alpha/kernel/proto.h
--- linux.vanilla/arch/alpha/kernel/proto.h	Sat Aug 14 02:27:12 1999
+++ linux.14p16/arch/alpha/kernel/proto.h	Thu Dec  9 15:34:20 1999
@@ -1,4 +1,5 @@
 /* Prototypes of functions used across modules here in this directory.  */
+#include <linux/pci.h>
 
 #define vucp	volatile unsigned char  *
 #define vusp	volatile unsigned short *
@@ -44,6 +45,22 @@
 extern void cia_init_arch(unsigned long *, unsigned long *);
 extern void cia_machine_check(u64, u64, struct pt_regs *);
 
+/* core_irongate.c */
+extern int irongate_hose_read_config_byte (u8, u8, u8, u8 *value,
+					  struct linux_hose_info *hose);
+extern int irongate_hose_read_config_word (u8, u8, u8, u16 *value,
+					  struct linux_hose_info *hose);
+extern int irongate_hose_read_config_dword (u8, u8, u8, u32 *value,
+					   struct linux_hose_info *hose);
+extern int irongate_hose_write_config_byte (u8, u8, u8, u8 value,
+					   struct linux_hose_info *hose);
+extern int irongate_hose_write_config_word (u8, u8, u8, u16 value,
+					   struct linux_hose_info *hose);
+extern int irongate_hose_write_config_dword (u8, u8, u8, u32 value,
+					    struct linux_hose_info *hose);
+extern void irongate_init_arch(unsigned long *, unsigned long *);
+extern void irongate_machine_check(u64, u64, struct pt_regs *);
+
 /* core_lca.c */
 extern int lca_hose_read_config_byte (u8, u8, u8, u8 *value,
 				      struct linux_hose_info *hose);
@@ -74,6 +91,7 @@
 extern int mcpcia_hose_write_config_dword (u8, u8, u8, u32 value,
 					   struct linux_hose_info *hose);
 extern void mcpcia_init_arch(unsigned long *, unsigned long *);
+extern void mcpcia_init_hoses(void);
 extern void mcpcia_machine_check(u64, u64, struct pt_regs *);
 
 /* core_polaris.c */
@@ -153,6 +171,7 @@
 extern void handle_ipi(struct pt_regs *);
 extern void smp_percpu_timer_interrupt(struct pt_regs *);
 extern int smp_boot_cpuid;
+extern unsigned long cpu_present_mask;
 
 /* bios32.c */
 extern void reset_for_srm(void);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/ptrace.c linux.14p16/arch/alpha/kernel/ptrace.c
--- linux.vanilla/arch/alpha/kernel/ptrace.c	Wed Dec 30 00:17:00 1998
+++ linux.14p16/arch/alpha/kernel/ptrace.c	Thu Dec  9 15:34:20 1999
@@ -149,13 +149,18 @@
 	pmd_t * pgmiddle;
 	pte_t * pgtable;
 	unsigned long page;
+	int fault;
 
 	DBG(DBG_MEM_ALL, ("getting long at 0x%lx\n", addr));
  repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (pgd_none(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 0);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return 0;
 	}
 	if (pgd_bad(*pgdir)) {
 		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
@@ -164,8 +169,12 @@
 	}
 	pgmiddle = pmd_offset(pgdir, addr);
 	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 0);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return 0;
 	}
 	if (pmd_bad(*pgmiddle)) {
 		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
@@ -174,8 +183,12 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 0);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return 0;
 	}
 	page = pte_page(*pgtable);
 	/* this is a hack for non-kernel-mapped video buffers and similar */
@@ -202,12 +215,17 @@
 	pmd_t *pgmiddle;
 	pte_t *pgtable;
 	unsigned long page;
+	int fault;
 
  repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (!pgd_present(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 1);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return;
 	}
 	if (pgd_bad(*pgdir)) {
 		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
@@ -216,8 +234,12 @@
 	}
 	pgmiddle = pmd_offset(pgdir, addr);
 	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 1);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return;
 	}
 	if (pmd_bad(*pgmiddle)) {
 		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
@@ -226,13 +248,21 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 1);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return;
 	}
 	page = pte_page(*pgtable);
 	if (!pte_write(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 1);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return;
 	}
 
 	/* This is a hack for non-kernel-mapped video buffers and similar.  */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/setup.c linux.14p16/arch/alpha/kernel/setup.c
--- linux.vanilla/arch/alpha/kernel/setup.c	Sat Aug 28 20:00:53 1999
+++ linux.14p16/arch/alpha/kernel/setup.c	Thu Dec  9 15:34:20 1999
@@ -37,6 +37,7 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/hwrpb.h>
+#include <asm/page.h>
 #include <asm/dma.h>
 #include <asm/io.h>
 
@@ -56,6 +57,7 @@
 #define N(a) (sizeof(a)/sizeof(a[0]))
 
 static unsigned long find_end_memory(void);
+static unsigned long get_memory_end_override(char *);
 static struct alpha_machine_vector *get_sysvec(long, long, long);
 static struct alpha_machine_vector *get_sysvec_byname(const char *);
 static void get_sysnames(long, long, char **, char **);
@@ -112,12 +114,14 @@
 WEAK(eb64p_mv);
 WEAK(eb66_mv);
 WEAK(eb66p_mv);
+WEAK(eiger_mv);
 WEAK(jensen_mv);
 WEAK(lx164_mv);
 WEAK(miata_mv);
 WEAK(mikasa_mv);
 WEAK(mikasa_primo_mv);
 WEAK(monet_mv);
+WEAK(nautilus_mv);
 WEAK(noname_mv);
 WEAK(noritake_mv);
 WEAK(noritake_primo_mv);
@@ -136,7 +140,6 @@
 
 #undef WEAK
 
-
 void __init
 setup_arch(char **cmdline_p, unsigned long * memory_start_p,
 	   unsigned long * memory_end_p)
@@ -146,8 +149,9 @@
 	struct alpha_machine_vector *vec = NULL;
 	struct percpu_struct *cpu;
 	char *type_name, *var_name, *p;
+	unsigned long memory_end_override = 0;
 
-	hwrpb = (struct hwrpb_struct*)(IDENT_ADDR + INIT_HWRPB->phys_addr);
+	hwrpb = (struct hwrpb_struct*) __va(INIT_HWRPB->phys_addr);
 
 	/* 
 	 * Locate the command line.
@@ -189,6 +193,11 @@
 			est_cycle_freq = simple_strtol(p+6, NULL, 0);
 			continue;
 		}
+
+		if (strncmp(p, "mem=", 4) == 0) {
+			memory_end_override = get_memory_end_override(p+4);
+			continue;
+		}
 	}
 
 	/* Replace the command line, not that we've killed it with strtok.  */
@@ -215,9 +224,10 @@
 		      type_name, (*var_name ? " variation " : ""), var_name,
 		      hwrpb->sys_type, hwrpb->sys_variation);
 	}
-	if (vec != &alpha_mv)
+	if (vec != &alpha_mv) {
 		alpha_mv = *vec;
-
+	}
+	
 #ifdef CONFIG_ALPHA_GENERIC
 	/* Assume that we've booted from SRM if we havn't booted from MILO.
 	   Detect the later by looking for "MILO" in the system serial nr.  */
@@ -248,8 +258,14 @@
 	wrmces(0x7);
 
 	/* Find our memory.  */
-	*memory_end_p = find_end_memory();
 	*memory_start_p = (unsigned long) _end;
+	*memory_end_p = find_end_memory();
+	if (memory_end_override && memory_end_override < *memory_end_p) {
+		printk("Overriding memory size from %luMB to %luMB\n",
+		       __pa(*memory_end_p) >> 20,
+		       __pa(memory_end_override) >> 20);
+		*memory_end_p = memory_end_override;
+	}
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	initrd_start = INITRD_START;
@@ -339,13 +355,35 @@
 	/* Round it up to an even number of pages. */
 	high = (high + PAGE_SIZE) & (PAGE_MASK*2);
 
-	/* Enforce maximum of 2GB even if there is more.  Blah.  */
+	/* Enforce maximum of 2GB even if there is more,
+	 * but only if the platform (support) cannot handle it.
+	 */
 	if (high > 0x80000000UL) {
-		printk("Cropping memory from %luMB to 2048MB\n", high);
+		printk("Cropping memory from %luMB to 2048MB\n", high >> 20);
 		high = 0x80000000UL;
 	}
 
-	return PAGE_OFFSET + high;
+	return (unsigned long) __va(high);
+}
+
+static unsigned long __init
+get_memory_end_override(char *s)
+{
+	unsigned long end = 0;
+	char *from = s;
+
+	end = simple_strtoul(from, &from, 0);
+	if ( *from == 'K' || *from == 'k' ) {
+		end = end << 10;
+		from++;
+	} else if ( *from == 'M' || *from == 'm' ) {
+		end = end << 20;
+		from++;
+	} else if ( *from == 'G' || *from == 'g' ) {
+		end = end << 30;
+		from++;
+	}
+	return (unsigned long) __va(end);
 }
 
 
@@ -358,11 +396,13 @@
 	"Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1",
 	"Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake",
 	"Cortex", "29", "Miata", "XXM", "Takara", "Yukon",
-	"Tsunami", "Wildfire", "CUSCO"
+	"Tsunami", "Wildfire", "CUSCO", "Eiger"
 };
 
 static char unofficial_names[][8] = {"100", "Ruffian"};
 
+static char api_names[][16] = {"200", "Nautilus"};
+
 static char eb164_names[][8] = {"EB164", "PC164", "LX164", "SX164", "RX164"};
 static int eb164_indices[] = {0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3,4};
 
@@ -386,7 +426,6 @@
 };
 static int tsunami_indices[] = {0,1,2,3,4,5,6,7,8};
 
-
 static struct alpha_machine_vector * __init
 get_sysvec(long type, long variation, long cpu)
 {
@@ -429,6 +468,7 @@
 		NULL,		/* Tsunami -- see variation.  */
 		NULL,		/* Wildfire */
 		NULL,		/* CUSCO */
+		&eiger_mv,	/* Eiger */
 	};
 
 	static struct alpha_machine_vector *unofficial_vecs[] __initlocaldata =
@@ -437,6 +477,12 @@
 		&ruffian_mv,
 	};
 
+	static struct alpha_machine_vector *api_vecs[] __initlocaldata =
+	{
+		NULL,		/* 200 */
+		&nautilus_mv,
+	};
+
 	static struct alpha_machine_vector *alcor_vecs[] __initlocaldata = 
 	{
 		&alcor_mv, &xlt_mv, &xlt_mv
@@ -485,6 +531,9 @@
 	vec = NULL;
 	if (type < N(systype_vecs)) {
 		vec = systype_vecs[type];
+	} else if ((type > ST_API_BIAS) &&
+		   (type - ST_API_BIAS) < N(api_vecs)) {
+		vec = api_vecs[type - ST_API_BIAS];
 	} else if ((type > ST_UNOFFICIAL_BIAS) &&
 		   (type - ST_UNOFFICIAL_BIAS) < N(unofficial_vecs)) {
 		vec = unofficial_vecs[type - ST_UNOFFICIAL_BIAS];
@@ -558,12 +607,14 @@
 		&eb64p_mv,
 		&eb66_mv,
 		&eb66p_mv,
+		&eiger_mv,
 		&jensen_mv,
 		&lx164_mv,
 		&miata_mv,
 		&mikasa_mv,
 		&mikasa_primo_mv,
 		&monet_mv,
+		&nautilus_mv,
 		&noname_mv,
 		&noritake_mv,
 		&noritake_primo_mv,
@@ -604,6 +655,9 @@
 	   else set type name to family */
 	if (type < N(systype_names)) {
 		*type_name = systype_names[type];
+	} else if ((type > ST_API_BIAS) &&
+		   (type - ST_API_BIAS) < N(api_names)) {
+		*type_name = api_names[type - ST_API_BIAS];
 	} else if ((type > ST_UNOFFICIAL_BIAS) &&
 		   (type - ST_UNOFFICIAL_BIAS) < N(unofficial_names)) {
 		*type_name = unofficial_names[type - ST_UNOFFICIAL_BIAS];
@@ -689,6 +743,21 @@
 	}
 }
 
+static int
+get_nr_processors(struct percpu_struct *cpubase, unsigned long num)
+{
+	struct percpu_struct *cpu;
+	int i, count = 0;
+
+	for (i = 0; i < num; i++) {
+		cpu = (struct percpu_struct *)
+			((char *)cpubase + i*hwrpb->processor_size);
+		if ((cpu->flags & 0x1cc) == 0x1cc)
+			count++;
+	}
+	return count;
+}
+
 /*
  * BUFFER is PAGE_SIZE bytes long.
  */
@@ -708,7 +777,7 @@
 	char *cpu_name;
 	char *systype_name;
 	char *sysvariation_name;
-	int len;
+	int len, nr_processors;
 
 	cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset);
 	cpu_index = (unsigned) (cpu->type - 1);
@@ -719,6 +788,8 @@
 	get_sysnames(hwrpb->sys_type, hwrpb->sys_variation,
 		     &systype_name, &sysvariation_name);
 
+	nr_processors = get_nr_processors(cpu, hwrpb->nr_processors);
+
 	len = sprintf(buffer,
 		      "cpu\t\t\t: Alpha\n"
 		      "cpu model\t\t: %s\n"
@@ -738,7 +809,7 @@
 		      "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
 		      "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
 		      "platform string\t\t: %s\n"
-		      "cpus detected\t\t: %ld\n",
+		      "cpus detected\t\t: %d\n",
 		       cpu_name, cpu->variation, cpu->revision,
 		       (char*)cpu->serial_no,
 		       systype_name, sysvariation_name, hwrpb->sys_revision,
@@ -753,7 +824,7 @@
 		       loops_per_sec / 500000, (loops_per_sec / 5000) % 100,
 		       unaligned[0].count, unaligned[0].pc, unaligned[0].va,
 		       unaligned[1].count, unaligned[1].pc, unaligned[1].va,
-		       platform_string(), hwrpb->nr_processors);
+		       platform_string(), nr_processors);
 
 #ifdef __SMP__
 	len += smp_info(buffer+len);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/signal.c linux.14p16/arch/alpha/kernel/signal.c
--- linux.vanilla/arch/alpha/kernel/signal.c	Sat Aug 14 02:27:12 1999
+++ linux.14p16/arch/alpha/kernel/signal.c	Thu Dec  9 15:34:20 1999
@@ -437,6 +437,8 @@
 		err |= __copy_to_user(frame->extramask, &set->sig[1], 
 				      sizeof(frame->extramask));
 	}
+	if (err)
+		goto give_sigsegv;
 
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
@@ -499,6 +501,8 @@
 	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, sw,
 				set->sig[0], oldsp);
 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+	if (err)
+		goto give_sigsegv;
 
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/smp.c linux.14p16/arch/alpha/kernel/smp.c
--- linux.vanilla/arch/alpha/kernel/smp.c	Sat Aug 14 02:27:12 1999
+++ linux.14p16/arch/alpha/kernel/smp.c	Thu Dec  9 15:34:20 1999
@@ -97,6 +97,9 @@
 	cpu_data[cpuid].loops_per_sec = loops_per_sec;
 	cpu_data[cpuid].last_asn
 	  = (cpuid << WIDTH_HARDWARE_ASN) + ASN_FIRST_VERSION;
+
+        cpu_data[cpuid].irq_count = 0;
+        cpu_data[cpuid].bh_count = 0;
 }
 
 /*
@@ -580,7 +583,7 @@
 smp_percpu_timer_interrupt(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
-	int user = user_mode(regs);
+	unsigned long user = user_mode(regs);
 	struct cpuinfo_alpha *data = &cpu_data[cpu];
 
 	/* Record kernel PC */
@@ -902,7 +905,7 @@
 			return;
 	} else
 		flush_tlb_other(mm);
-	
+       
 	data.vma = vma;
 	data.mm = mm;
 	data.addr = addr;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/sys_dp264.c linux.14p16/arch/alpha/kernel/sys_dp264.c
--- linux.vanilla/arch/alpha/kernel/sys_dp264.c	Sat Aug 14 02:27:12 1999
+++ linux.14p16/arch/alpha/kernel/sys_dp264.c	Thu Dec  9 15:34:21 1999
@@ -203,7 +203,6 @@
 	enable_irq(2);
 }
 
-
 /*
  * PCI Fixup configuration.
  *
@@ -402,7 +401,6 @@
 {
 	layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE);
 	common_pci_fixup(webbrick_map_irq, common_swizzle);
-	SMC669_Init(0);
 }
 
 static void __init
@@ -412,7 +410,6 @@
 	common_pci_fixup(clipper_map_irq, common_swizzle);
 }
 
-
 /*
  * The System Vectors
  */
@@ -427,7 +424,7 @@
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 
 	nr_irqs:		64,
-	irq_probe_mask:		_PROBE_MASK(64),
+	irq_probe_mask:		TSUNAMI_PROBE_MASK,
 	update_irq_hw:		dp264_update_irq_hw,
 	ack_irq:		generic_ack_irq,
 	device_interrupt:	dp264_device_interrupt,
@@ -450,7 +447,7 @@
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 
 	nr_irqs:		64,
-	irq_probe_mask:		_PROBE_MASK(64),
+	irq_probe_mask:		TSUNAMI_PROBE_MASK,
 	update_irq_hw:		dp264_update_irq_hw,
 	ack_irq:		generic_ack_irq,
 	device_interrupt:	dp264_device_interrupt,
@@ -472,7 +469,7 @@
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 
 	nr_irqs:		64,
-	irq_probe_mask:		_PROBE_MASK(64),
+	irq_probe_mask:		TSUNAMI_PROBE_MASK,
 	update_irq_hw:		dp264_update_irq_hw,
 	ack_irq:		generic_ack_irq,
 	device_interrupt:	dp264_device_interrupt,
@@ -494,7 +491,7 @@
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 
 	nr_irqs:		64,
-	irq_probe_mask:		_PROBE_MASK(64),
+	irq_probe_mask:		TSUNAMI_PROBE_MASK,
 	update_irq_hw:		clipper_update_irq_hw,
 	ack_irq:		generic_ack_irq,
 	device_interrupt:	dp264_device_interrupt,
@@ -505,6 +502,6 @@
 	pci_fixup:		clipper_pci_fixup,
 	kill_arch:		generic_kill_arch,
 };
-
 /* No alpha_mv alias for webbrick/monet/clipper, since we compile them
    in unconditionally with DP264; setup_arch knows how to cope.  */
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/sys_eiger.c linux.14p16/arch/alpha/kernel/sys_eiger.c
--- linux.vanilla/arch/alpha/kernel/sys_eiger.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/alpha/kernel/sys_eiger.c	Thu Dec  9 15:34:21 1999
@@ -0,0 +1,237 @@
+/*
+ *	linux/arch/alpha/kernel/sys_eiger.c
+ *
+ *	Copyright (C) 1995 David A Rusling
+ *	Copyright (C) 1996, 1999 Jay A Estabrook
+ *	Copyright (C) 1998, 1999 Richard Henderson
+ *	Copyright (C) 1999 Iain Grant
+ *
+ * Code supporting the EIGER (EV6+TSUNAMI).
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/mmu_context.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <asm/pgtable.h>
+#include <asm/core_tsunami.h>
+#include <asm/hwrpb.h>
+
+#include "proto.h"
+#include "irq.h"
+#include "bios32.h"
+#include "machvec.h"
+
+#define dev2hose(d) (bus2hose[(d)->bus->number]->pci_hose_index)
+
+/*
+ * HACK ALERT! only the boot cpu is used for interrupts.
+ */
+
+static void
+eiger_update_irq_hw(unsigned long irq, unsigned long unused, int unmask_p)
+{
+
+	unsigned int regaddr;
+	unsigned long mask;
+
+	if (irq <= 15) {
+		if (irq <= 7)
+			outb(alpha_irq_mask, 0x21);		/* ISA PIC1 */
+	else
+			outb(alpha_irq_mask >> 8, 0xA1);	/* ISA PIC2 */
+	} else {
+		if (irq > 63)
+			mask = _alpha_irq_masks[1] << 16;
+		else
+			mask = _alpha_irq_masks[0] >> ((irq - 16) & 0x30);
+
+		regaddr = 0x510 + (((irq - 16) >> 2) & 0x0c);
+
+		outl(mask & 0xffff0000UL, regaddr);
+	}
+
+}
+
+static void
+eiger_device_interrupt(unsigned long vector, struct pt_regs * regs)
+{
+	unsigned intstatus;
+
+	/*
+	 * The PALcode will have passed us vectors 0x800 or 0x810,
+	 * which are fairly arbitrary values and serve only to tell
+	 * us whether an interrupt has come in on IRQ0 or IRQ1. If
+	 * it's IRQ1 it's a PCI interrupt; if it's IRQ0, it's
+	 * probably ISA, but PCI interrupts can come through IRQ0
+	 * as well if the interrupt controller isn't in accelerated
+	 * mode.
+	 *
+	 * OTOH, the accelerator thing doesn't seem to be working
+	 * overly well, so what we'll do instead is try directly
+	 * examining the Master Interrupt Register to see if it's a
+	 * PCI interrupt, and if _not_ then we'll pass it on to the
+	 * ISA handler.
+	 */
+
+	intstatus = inw(0x500) & 15;
+	if (intstatus) {
+		/*
+		 * This is a PCI interrupt. Check each bit and
+		 * despatch an interrupt if it's set.
+		 */
+
+		if (intstatus & 8) handle_irq(16+3, 16+3, regs);
+		if (intstatus & 4) handle_irq(16+2, 16+2, regs);
+		if (intstatus & 2) handle_irq(16+1, 16+1, regs);
+		if (intstatus & 1) handle_irq(16+0, 16+0, regs);
+	} else
+		isa_device_interrupt (vector, regs);
+}
+
+
+static void
+eiger_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+{
+   int irq = (vector - 0x800) >> 4;
+
+   handle_irq(irq, irq, regs);
+
+}
+
+static void __init
+eiger_init_irq(void)
+{
+	outb(0, DMA1_RESET_REG);
+	outb(0, DMA2_RESET_REG);
+	outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
+	outb(0, DMA2_MASK_REG);
+
+	if (alpha_using_srm)
+		alpha_mv.device_interrupt = eiger_srm_device_interrupt;
+
+	eiger_update_irq_hw(16, alpha_irq_mask, 0);
+
+	enable_irq(2);
+}
+
+static int __init
+eiger_map_irq(struct pci_dev *dev, int slot, int pin)
+{
+	u8 irq_orig;
+	int irq;
+
+	/* The SRM console has already calculated out the IRQ value's for
+	   option cards. As this works lets just read in the value already
+	   set and change it to a useable value by Linux.
+
+	   All the IRQ values generated by the console are greater than 90,
+	   so we calculate a value for Linux by the following:
+
+	   irq = (card Irq - 80);
+
+	   We subtract 80 because it is (90 - allocated ISA IRQ's ).
+	*/
+	pcibios_read_config_byte(dev->bus->number,
+				 dev->devfn,
+				 PCI_INTERRUPT_LINE,
+				 &irq_orig);
+
+	irq = ( irq_orig - 0x80);
+
+	return irq;
+}
+
+/* New swizzle routine with code for card based bridges */
+static int __init
+eiger_swizzle(struct pci_dev *dev, int *pinp)
+{
+	int slot, pin = *pinp;
+	int bridge_count = 0;
+
+	/* Find the number of backplane bridges */
+	int backplane = ( inw(0x502) & 0x0f);
+
+	switch (backplane)
+	{
+	   case 0x00: bridge_count = 0; break; /* No bridges */
+	   case 0x01: bridge_count = 1; break; /* 1 */
+	   case 0x03: bridge_count = 2; break; /* 2 */
+	   case 0x07: bridge_count = 3; break; /* 3 */
+	   case 0x0f: bridge_count = 4; break; /* 4 */
+	};
+
+
+	/*  Check first for the built-in bridges on hose 0. */
+	if ( dev2hose(dev) == 0 &&
+            ( (PCI_SLOT(dev->bus->self->devfn) > (20-bridge_count))))
+	{
+		slot = PCI_SLOT(dev->devfn);
+	} else {
+		/*  Must be a card-based bridge.  */
+		do {
+			/* Check for built-in bridges on hose 0. */
+			if ( dev2hose(dev) == 0 &&
+			     (PCI_SLOT(dev->bus->self->devfn) >
+				(20 - bridge_count)))
+			{
+                  		slot = PCI_SLOT(dev->devfn);
+				break;
+			}
+			pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)) ;
+
+			/* Move up the chain of bridges.  */
+			dev = dev->bus->self;
+			/* Slot of the next bridge.  */
+			slot = PCI_SLOT(dev->devfn);
+		} while (dev->bus->self);
+	}
+	*pinp = pin;
+
+	return slot;
+}
+
+static void __init
+eiger_pci_fixup(void)
+{
+	layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE);
+	common_pci_fixup(eiger_map_irq, eiger_swizzle);
+}
+
+/*
+ * The System Vectors
+ */
+
+struct alpha_machine_vector eiger_mv __initmv = {
+	vector_name:		"Eiger",
+	DO_EV6_MMU,
+	DO_DEFAULT_RTC,
+	DO_TSUNAMI_IO,
+	DO_TSUNAMI_BUS,
+	machine_check:		tsunami_machine_check,
+	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+
+	nr_irqs:		128,
+	irq_probe_mask:		TSUNAMI_PROBE_MASK,
+	update_irq_hw:		eiger_update_irq_hw,
+	ack_irq:		generic_ack_irq,
+	device_interrupt:	eiger_device_interrupt,
+
+	init_arch:		tsunami_init_arch,
+	init_irq:		eiger_init_irq,
+	init_pit:		generic_init_pit,
+	pci_fixup:		eiger_pci_fixup,
+	kill_arch:		generic_kill_arch,
+};
+ALIAS_MV(eiger)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/sys_nautilus.c linux.14p16/arch/alpha/kernel/sys_nautilus.c
--- linux.vanilla/arch/alpha/kernel/sys_nautilus.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/alpha/kernel/sys_nautilus.c	Tue Dec 14 16:16:13 1999
@@ -0,0 +1,544 @@
+/*
+ *	linux/arch/alpha/kernel/sys_nautilus.c
+ *
+ *	Copyright (C) 1995 David A Rusling
+ *	Copyright (C) 1998 Richard Henderson
+ *	Copyright (C) 1999 Alpha Processor, Inc., (David Daniel, Stig Telfer, Soohoon Lee)
+ *
+ * Code supporting NAUTILUS systems.
+ *
+ *
+ * NAUTILUS has the following I/O features:
+ *
+ * a) Driven by AMD 751 aka IRONGATE (northbridge):
+ *     4 PCI slots
+ *     1 AGP slot
+ *
+ * b) Driven by ALI M1543C (southbridge)
+ *     2 ISA slots
+ *     2 IDE connectors
+ *     1 dual drive capable FDD controller
+ *     2 serial ports
+ *     1 ECP/EPP/SP parallel port
+ *     2 USB ports
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/mmu_context.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <asm/pgtable.h>
+#include <asm/core_irongate.h>
+#include <asm/hwrpb.h>
+
+#include "proto.h"
+#include "irq.h"
+#include "bios32.h"
+#include "machvec.h"
+
+#define dev2hose(d) (bus2hose[(d)->bus->number]->pci_hose_index)
+
+static void
+nautilus_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+{
+	mask |= 0x100;	/*Timer is connected to PIC int. line also on Nautilus*/
+		      	/*And the timer int. handler enables PIC line */
+			/*So not to get multiple timer int. sources*/
+			/*Mask it all the times*/
+	if (irq >= 8)
+		outb(mask >> 8, 0xA1);
+	else
+		outb(mask, 0x21);
+}
+
+static void __init
+nautilus_init_irq(void)
+{
+	STANDARD_INIT_IRQ_PROLOG;
+
+	enable_irq(2);			/* enable cascade */
+	disable_irq(8);
+}
+
+
+static void __init
+nautilus_pci_fixup(void)
+{
+/* All BIOS setups are preserved */
+}
+
+void
+nautilus_kill_arch (int mode, char *restart_cmd)
+{
+
+#ifdef CONFIG_RTC
+	/* Reset rtc to defaults.  */
+	{
+		unsigned char control;
+
+		cli();
+
+		/* Reset periodic interrupt frequency.  */
+		CMOS_WRITE(0x26, RTC_FREQ_SELECT);
+
+		/* Turn on periodic interrupts.  */
+		control = CMOS_READ(RTC_CONTROL);
+		control |= RTC_PIE;
+		CMOS_WRITE(control, RTC_CONTROL);	
+		CMOS_READ(RTC_INTR_FLAGS);
+
+		sti();
+	}
+#endif
+
+	switch(mode) {
+        case LINUX_REBOOT_CMD_HALT:
+		printk("Press Reset bottun");
+		break;
+	case LINUX_REBOOT_CMD_RESTART:
+		{
+			int v;
+			irongate_hose_write_config_byte(0, 0x07<<3, 0x43, &v, 0);
+			irongate_hose_write_config_byte(0, 0x07<<3, 0x43, v | 0x80, 0);
+			outb(1, 0x92);
+			outb(0, 0x92);
+			printk("Press Reset button");
+		}
+		break;
+        case LINUX_REBOOT_CMD_POWER_OFF:
+                {
+                        int pmuport;
+                        irongate_hose_read_config_dword(0, 0x11<<3, 0x10, &pmuport, 0);
+                        pmuport &= 0xfffe;
+                        outl(0xffff, pmuport); /* clear pending events */
+                        outw(0x2000, pmuport+4); /* power off */
+                        printk("Press power button");
+                }
+	}
+
+	while (1)
+		;
+	halt();
+}
+
+/*----------------------------------------------------------------------*/
+/* Machine check handler code 
+ *
+ * Perform analysis of a machine check that was triggered by the EV6 CPU's
+ * fault-detection mechanism. */
+
+/* IPR structures for EV6, containing the necessary data for the
+ * machine check handler to unpick the logout frame
+ */
+
+
+/* I_STAT */
+
+#define EV6__I_STAT__PAR                ( 1 << 29 )
+
+
+/* MM_STAT */
+
+#define EV6__MM_STAT__DC_TAG_PERR       ( 1 << 10 )
+
+
+/* DC_STAT */
+
+#define EV6__DC_STAT__SEO               ( 1 << 4 )
+#define EV6__DC_STAT__ECC_ERR_LD        ( 1 << 3 )
+#define EV6__DC_STAT__ECC_ERR_ST        ( 1 << 2 )
+#define EV6__DC_STAT__TPERR_P1          ( 1 << 1 )
+#define EV6__DC_STAT__TPERR_P0          ( 1      )
+
+
+/* C_STAT */
+
+#define EV6__C_STAT__BC_PERR            ( 0x01 )
+#define EV6__C_STAT__DC_PERR            ( 0x02 )
+#define EV6__C_STAT__DSTREAM_MEM_ERR    ( 0x03 )
+#define EV6__C_STAT__DSTREAM_BC_ERR     ( 0x04 )
+#define EV6__C_STAT__DSTREAM_DC_ERR     ( 0x05 )
+#define EV6__C_STAT__PROBE_BC_ERR0      ( 0x06 )
+#define EV6__C_STAT__PROBE_BC_ERR1      ( 0x07 )
+#define EV6__C_STAT__ISTREAM_MEM_ERR    ( 0x0B )
+#define EV6__C_STAT__ISTREAM_BC_ERR     ( 0x0C )
+#define EV6__C_STAT__DSTREAM_MEM_DBL    ( 0x13 )
+#define EV6__C_STAT__DSTREAM_BC_DBL     ( 0x14 )
+#define EV6__C_STAT__ISTREAM_MEM_DBL    ( 0x1B )
+#define EV6__C_STAT__ISTREAM_BC_DBL     ( 0x1C )
+
+
+/* take the two syndromes from the CBOX error chain and convert them
+ * into a bit number */
+
+/* NOTE - since I don't know of any difference between C0 and C1
+ * I just ignore C1, since in all cases I've seen so far they are identical */
+
+static const unsigned char ev6_bit_to_syndrome[72] =
+{
+    0xce, 0xcb, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc,     /* 0 */
+    0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34,     /* 8 */
+    0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c,     /* 16 */
+    0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xf1, 0xf4,     /* 24 */
+    0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d,     /* 32 */
+    0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xb0, 0xb5,     /* 40 */
+    0x8f, 0x8a, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d,     /* 48 */
+    0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75,     /* 56 */
+    0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80      /* 64 */
+};
+
+
+static int ev6_syn2bit(unsigned long c0, unsigned long c1)
+{
+    int bit;
+
+    for (bit = 0; bit < 72; bit++)
+        if (ev6_bit_to_syndrome[bit] == c0)	return bit;
+    for (bit = 0; bit < 72; bit++)
+        if (ev6_bit_to_syndrome[bit] == c1)	return bit + 64;
+
+    return -1;                  /* not found */
+}
+
+
+/* single bit ECC errors are categorised here */
+
+#if 0
+static const char *interr = "CPU internal error";
+static const char *slotb= "Slot-B error";
+static const char *membus= "Memory/EV6-bus error";
+#else
+static const char *interr = "";
+static const char *slotb = "";
+static const char *membus = "";
+#endif
+
+static void ev6_crd_interp(char *interp, struct el_common_EV6_mcheck * L)
+{
+
+    /* Icache data or tag parity error */
+    if (L->I_STAT & EV6__I_STAT__PAR) {
+	sprintf(interp, "%s: I_STAT[PAR]\n Icache data or tag parity error", interr);
+	return;
+    }
+
+    /* Dcache tag parity error (on issue) (DFAULT) */
+    if (L->MM_STAT & EV6__MM_STAT__DC_TAG_PERR) {
+	sprintf(interp, "%s: MM_STAT[DC_TAG_PERR]\n Dcache tag parity error(on issue)", interr);
+	return;
+    }
+
+    /* Errors relating to D-stream set non-zero DC_STAT - mask CRD bits */
+    switch (L->DC_STAT & (EV6__DC_STAT__ECC_ERR_ST | EV6__DC_STAT__ECC_ERR_LD)) 
+    {
+
+    case EV6__DC_STAT__ECC_ERR_ST:
+	/* Dcache single-bit ECC error on small store */
+	sprintf(interp, "%s: DC_STAT[ECC_ERR_ST]\n Dcache single-bit ECC error on small store", interr);
+	return;
+
+    case EV6__DC_STAT__ECC_ERR_LD:
+	switch (L->C_STAT) {
+	case 0:
+	    /* Dcache single-bit error on speculative load */
+	    /* Bcache victim read on Dcache/Bcache miss */
+	    sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT=0\n Dcache single-bit ECC error on speculative load", slotb);
+	    return;
+
+	case EV6__C_STAT__DSTREAM_DC_ERR:
+	    /* Dcache single bit error on load */
+	    sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT[DSTREAM_DC_ERR]\n Dcache single-bit ECC error on speculative load, bit %d", interr, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
+	    return;
+
+
+	case EV6__C_STAT__DSTREAM_BC_ERR:
+	    /* Bcache single-bit error on Dcache fill */
+	    sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT[DSTREAM_BC_ERR]\n Bcache single-bit error on Dcache fill, bit %d", slotb, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
+	    return;
+
+	case EV6__C_STAT__DSTREAM_MEM_ERR:
+	    /* Memory single-bit error on Dcache fill */
+	    sprintf(interp, "%s (to Dcache): DC_STAT[ECC_ERR_LD] C_STAT[DSTREAM_MEM_ERR]\n Memory single-bit error on Dcache fill, Address 0x%lX, bit %d", membus, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
+	    return;
+
+	default:			/* not one of these */
+	}
+    default:				/* not one of these */
+    }
+
+    /* I-stream, other misc errors go on C_STAT alone */
+    switch (L->C_STAT) {
+
+    case EV6__C_STAT__ISTREAM_BC_ERR:
+	/* Bcache single-bit error on Icache fill (also MCHK) */
+	sprintf(interp, "%s: C_STAT[ISTREAM_BC_ERR]\n Bcache single-bit error on Icache fill, bit %d", slotb, 
+		    ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
+	return;
+
+    case EV6__C_STAT__ISTREAM_MEM_ERR:
+	/* Memory single-bit error on Icache fill (also MCHK) */
+	sprintf(interp, "%s : C_STATISTREAM_MEM_ERR]\n Memory single-bit error on Icache fill addr 0x%lX, bit %d", membus, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
+	return;
+
+    case EV6__C_STAT__PROBE_BC_ERR0:
+    case EV6__C_STAT__PROBE_BC_ERR1:
+	/* Bcache single-bit error on a probe hit */
+	sprintf(interp, "%s: C_STAT[PROBE_BC_ERR]\n Bcache single-bit error on a probe hit, addr 0x$lX, bit %d", slotb, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
+	return;
+
+    default:				/* not one of these */
+    }
+}
+
+
+/* these are the really nasty ones... */
+
+static void ev6_mchk_interp(char *interp, struct el_common_EV6_mcheck * L)
+{
+    /* Machine check errors described by DC_STAT */
+    switch (L->DC_STAT) {
+    case EV6__DC_STAT__TPERR_P0:
+    case EV6__DC_STAT__TPERR_P1:
+	/* Dcache tag parity error (on retry) */
+	sprintf(interp, "%s: DC_STAT[TPERR_P0|TPERR_P1]\n Dcache tag parity error(on retry)", interr);
+	return;
+
+    case EV6__DC_STAT__SEO:
+	/* Dcache second error on store */
+	sprintf(interp, "%s: DC_STAT[SEO]\n Dcache second error during mcheck", interr);
+	return;
+
+    default:				/* some other kind of error */
+    }
+
+    /* Machine check errors described by C_STAT */
+    switch (L->C_STAT) {
+    case EV6__C_STAT__DC_PERR:		/* Dcache duplicate tag parity error */
+	sprintf(interp, "%s: C_STAT[DC_PERR]\n Dcache duplicate tag parity error at 0x%lX",
+			interr, L->C_ADDR);
+	return;
+
+    case EV6__C_STAT__BC_PERR:		/* Bcache tag parity error */
+	sprintf(interp, "%s: C_STAT[BC_PERR]\n Bcache tag parity error at 0x%lX", slotb, L->C_ADDR);
+	return;
+
+    case EV6__C_STAT__ISTREAM_BC_ERR:
+	/* Bcache single-bit error on Icache fill (also CRD) */
+	sprintf(interp, "%s: C_STAT[ISTREAM_BC_ERR]\n Bcache single-bit error on Icache fill 0x%lX bit %d",
+		    slotb, L->C_ADDR,
+		    ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
+	return;
+
+
+    case EV6__C_STAT__ISTREAM_MEM_ERR:
+	/* Memory single-bit error on Icache fill (also CRD) */
+	sprintf(interp, "%s: C_STAT[ISTREAM_MEM_ERR]\n Memory single-bit error on Icache fill 0x%lX, bit %d",
+		    membus, L->C_ADDR,
+		    ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
+	return;
+
+
+    case EV6__C_STAT__ISTREAM_BC_DBL:
+	/* Bcache double-bit error on Icache fill */
+	sprintf(interp, "%s: C_STAT[ISTREAM_BC_DBL]\n Bcache double-bit error on Icache fill at 0x%lX",
+			slotb, L->C_ADDR);
+	return;
+    case EV6__C_STAT__DSTREAM_BC_DBL:
+	/* Bcache double-bit error on Dcache fill */
+	sprintf(interp, "%s: C_STAT[DSTREAM_BC_DBL]\n Bcache double-bit error on Dcache fill at 0x%lX",
+			slotb, L->C_ADDR);
+	return;
+
+    case EV6__C_STAT__ISTREAM_MEM_DBL:
+	/* Memory double-bit error on Icache fill */
+	sprintf(interp, "%s: C_STAT[ISTREAM_MEM_DBL]\n Memory double-bit error on Icache fill at 0x%lX", 
+			membus, L->C_ADDR);
+	return;
+    case EV6__C_STAT__DSTREAM_MEM_DBL:
+	/* Memory double-bit error on Dcache fill */
+	sprintf(interp, "%s: C_STAT[DSTREAM_MEM_DBL]\n Memory double-bit error on Dcache fill at 0x%lX", 
+			membus, L->C_ADDR);
+	return;
+
+    default:			/* something else */
+    }
+}
+
+
+static void ev6_cpu_machine_check( unsigned long vector,
+		 struct el_common_EV6_mcheck *L, struct pt_regs *regs)
+{
+    char interp[80];			/* buffer for interpretation details */
+
+    /* this is verbose and looks intimidating.  Should it be printed for
+     * corrected (CRD) machine checks? */
+
+    printk(KERN_CRIT "PALcode logout frame:  "
+           "MCHK_Code       %d  "
+           "MCHK_Frame_Rev  %d\n"
+           "I_STAT  %016lx  "
+           "DC_STAT %016lx  "
+           "C_ADDR  %016lx\n"
+           "SYND1   %016lx  "
+           "SYND0   %016lx  "
+           "C_STAT  %016lx\n"
+           "C_STS   %016lx  "
+           "RES     %016lx  "
+           "EXC_ADDR%016lx\n"
+           "IER_CM  %016lx  "
+           "ISUM    %016lx  "
+           "MM_STAT %016lx\n"
+           "PALBASE %016lx  "
+           "I_CTL   %016lx  "
+           "PCTX    %016lx\n"
+           "CPU registers: "
+           "PC      %016lx  "
+           "Return  %016lx\n",
+           L->MCHK_Code, L->MCHK_Frame_Rev, L->I_STAT, L->DC_STAT,
+           L->C_ADDR, L->DC1_SYNDROME, L->DC0_SYNDROME, L->C_STAT,
+           L->C_STS, L->RESERVED0, L->EXC_ADDR, L->IER_CM, L->ISUM,
+           L->MM_STAT, L->PAL_BASE, L->I_CTL, L->PCTX,
+           regs->pc, regs->r26 );
+
+    /* Attempt an interpretation on the meanings of the fields above */
+    sprintf(interp, "No interpretation available!" );
+    if ( vector == SCB_Q_PROCERR )		ev6_crd_interp( interp, L );
+    else if ( vector == SCB_Q_PROCMCHK )	ev6_mchk_interp( interp, L );
+
+    printk( KERN_CRIT "interpretation: %s\n\n", interp );
+}
+
+
+/* Perform analysis of a machine check that arrived from the system (NMI) */
+
+static void naut_sys_machine_check( unsigned long vector, unsigned long la_ptr,
+			     struct pt_regs *regs )
+{
+    printk("xtime %lx\n", CURRENT_TIME);
+    printk("PC %lx RA %lx\n", regs->pc, regs->r26);
+    irongate_pci_clr_err();
+}
+
+
+
+/* Machine checks can come from two sources - those on the CPU and those
+ * in the system.  They are analysed separately but all starts here */
+
+void nautilus_machine_check(unsigned long vector, unsigned long la_ptr,
+			    struct pt_regs *regs)
+{
+    char *mchk_class;
+    unsigned cpu_analysis=0, sys_analysis=0;	/* interpretation flags */
+
+    /* now for some analysis.  Machine checks fall into two classes -
+     * those picked up by the system, and those picked up by the CPU.
+     * add to that the two levels of severity - correctable or not
+     */
+
+    if (vector == SCB_Q_SYSMCHK && ((IRONGATE0->dramms & 0x300) == 0x300)) {
+	unsigned long nmi_ctl, temp;
+
+	/* Clear ALI NMI */
+        nmi_ctl = inb(0x61);
+        nmi_ctl |= 0x0c;
+        outb(nmi_ctl, 0x61);
+        nmi_ctl &= ~0x0c;
+        outb(nmi_ctl, 0x61);
+	
+	temp = IRONGATE0->stat_cmd;
+	temp &= ~0x100;
+	IRONGATE0->stat_cmd = temp; /* write again clears error bits */
+	mb();
+	temp = IRONGATE0->stat_cmd;  /* re-read to force write */
+
+	temp = IRONGATE0->dramms;
+	IRONGATE0->dramms = temp; /* write again clears error bits */
+	mb();
+	temp = IRONGATE0->dramms;  /* re-read to force write */
+
+	draina();
+	wrmces(0x7);
+	mb();
+	return;
+    }
+
+    switch (vector) {
+    case SCB_Q_SYSERR:
+	mchk_class = "Correctable System Machine Check (NMI)";
+	sys_analysis = 1;
+	break;
+    case SCB_Q_SYSMCHK:
+	mchk_class = "Fatal System Machine Check (NMI)";
+	sys_analysis = 1;
+	break;
+
+    case SCB_Q_PROCERR:
+	mchk_class = "Correctable Processor Machine Check";
+	cpu_analysis = 1;
+	break;
+    case SCB_Q_PROCMCHK:
+	mchk_class = "Fatal Processor Machine Check";
+	cpu_analysis = 1;
+	break;
+
+    default:
+	mchk_class = "Unknown vector!";
+	break;
+    }
+
+    printk(KERN_CRIT "> NAUTILUS Machine check 0x%x [%s]\n", vector, mchk_class);
+
+    if ( cpu_analysis )	
+	ev6_cpu_machine_check(  vector,
+				(struct el_common_EV6_mcheck *)la_ptr,
+				regs );
+    if ( sys_analysis )
+	naut_sys_machine_check( vector, la_ptr, regs );
+
+    /* Tell the PALcode to clear the machine check */
+    draina();
+    wrmces(0x7);
+    mb();
+}
+
+
+
+/*
+ * The System Vectors
+ */
+
+struct alpha_machine_vector nautilus_mv __initmv = {
+	vector_name:		"NAUTILUS",
+	DO_EV6_MMU,
+	DO_DEFAULT_RTC,
+	DO_IRONGATE_IO,
+	DO_IRONGATE_BUS,
+	machine_check:		nautilus_machine_check,
+	max_dma_address:	ALPHA_NAUTILUS_MAX_DMA_ADDRESS,
+
+	nr_irqs:		16,
+	irq_probe_mask:		(_PROBE_MASK(16) & ~0x101UL),
+
+	update_irq_hw:		nautilus_update_irq_hw,
+	ack_irq:		generic_ack_irq,
+	device_interrupt:	isa_device_interrupt,
+
+	init_arch:		irongate_init_arch,
+	init_irq:		nautilus_init_irq,
+	init_pit:		generic_init_pit,
+	pci_fixup:		nautilus_pci_fixup,
+	kill_arch:		nautilus_kill_arch,
+};
+ALIAS_MV(nautilus)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/sys_rawhide.c linux.14p16/arch/alpha/kernel/sys_rawhide.c
--- linux.vanilla/arch/alpha/kernel/sys_rawhide.c	Sun Jan 10 17:59:59 1999
+++ linux.14p16/arch/alpha/kernel/sys_rawhide.c	Thu Dec  9 15:34:21 1999
@@ -30,38 +30,53 @@
 #include "bios32.h"
 #include "machvec.h"
 
+static unsigned int hose_irq_masks[4] = { 0xff0000, 0xfe0000,
+					  0xff0000, 0xff0000 };
 
 static void
-rawhide_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+rawhide_update_irq_hw(unsigned long irq, unsigned long unused, int unmask_p)
 {
-	if (irq >= 40) {
-		/* PCI bus 1 with builtin NCR810 SCSI */
-		*(vuip)MCPCIA_INT_MASK0(1) =
-			(~((mask) >> 40) & 0x00ffffffU) | 0x00fe0000U;
-		mb();
-		/* ... and read it back to make sure it got written.  */
-	  	*(vuip)MCPCIA_INT_MASK0(1);
+	unsigned int saddle, hose, new_irq;
+	unsigned long mask;
+
+	saddle = (irq > 63); /* Which saddle are we on? */
+	mask = _alpha_irq_masks[saddle]; /* Use the correct mask. */
+
+	if (irq < 16) {
+		if (irq < 8)
+			outb(mask, 0x21);	/* ISA PIC1 */
+		else
+			outb(mask >> 8, 0xA1);	/* ISA PIC2 */
+		return;
 	}
-	else if (irq >= 16) {
-		/* PCI bus 0 with EISA bridge */
-		*(vuip)MCPCIA_INT_MASK0(0) =
-			(~((mask) >> 16) & 0x00ffffffU) | 0x00ff0000U;
-		mb();
-		/* ... and read it back to make sure it got written.  */
-	  	*(vuip)MCPCIA_INT_MASK0(0);
+
+	if (!saddle) {
+		mask >>= 16; /* Saddle 0 includes EISA interrupts. */
+		new_irq = irq - 16;
+	} else {
+		new_irq = irq - 64;
 	}
-	else if (irq >= 8)
-		outb(mask >> 8, 0xA1);	/* ISA PIC2 */
-	else
-		outb(mask, 0x21);	/* ISA PIC1 */
+
+	hose = (saddle << 1);
+
+	if (new_irq >= 24) {
+		mask >>= 24;
+		hose++;
+	}
+
+	*(vuip)MCPCIA_INT_MASK0(hose) =
+		(~(mask) & 0x00ffffffU) | hose_irq_masks[hose];
+	mb();
+	/* ... and read it back to make sure it got written.  */
+	*(vuip)MCPCIA_INT_MASK0(hose);
 }
 
 static void 
 rawhide_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
-	int irq, ack;
+	int irq;
 
-	ack = irq = (vector - 0x800) >> 4;
+	irq = (vector - 0x800) >> 4;
 
         /*
          * The RAWHIDE SRM console reports PCI interrupts with a vector
@@ -73,34 +88,31 @@
 	 * also, PCI #1 interrupts are offset some more... :-(
          */
 	if (irq == 52)
-		ack = irq = 56; /* SCSI on PCI 1 is special */
-	else {
-		if (irq >= 24) /* adjust all PCI interrupts down 8 */
-			ack = irq = irq - 8;
-		if (irq >= 48) /* adjust PCI bus 1 interrupts down another 8 */
-			ack = irq = irq - 8;
-	}
+		irq = 72; /* SCSI on PCI 1 is special */
+
+	/* Adjust by which hose it is from. */
+	irq -= (((irq + 16) >> 2) & 0x38);
 
-	handle_irq(irq, ack, regs);
+	handle_irq(irq, irq, regs);
 }
 
 static void __init
 rawhide_init_irq(void)
 {
-	STANDARD_INIT_IRQ_PROLOG;
+	unsigned int hose;
 
-	/* HACK ALERT! only PCI busses 0 and 1 are used currently,
-	   and routing is only to CPU #1*/
+	mcpcia_init_hoses();
 
-	*(vuip)MCPCIA_INT_MASK0(0) =
-		(~((alpha_irq_mask) >> 16) & 0x00ffffffU) | 0x00ff0000U; mb();
-	/* ... and read it back to make sure it got written.  */
-	*(vuip)MCPCIA_INT_MASK0(0);
+	STANDARD_INIT_IRQ_PROLOG;
 
-	*(vuip)MCPCIA_INT_MASK0(1) =
-		(~((alpha_irq_mask) >> 40) & 0x00ffffffU) | 0x00fe0000U; mb();
-	/* ... and read it back to make sure it got written.  */
-	*(vuip)MCPCIA_INT_MASK0(1);
+	/* HACK ALERT! routing is only to CPU #0. */
+
+	for (hose = 0; hose < hose_count; hose++) {
+		*(vuip)MCPCIA_INT_MASK0(hose) = hose_irq_masks[hose];
+		mb();
+		/* ... and read it back to make sure it got written.  */
+		*(vuip)MCPCIA_INT_MASK0(hose);
+	}
 
 	enable_irq(2);
 }
@@ -177,8 +189,8 @@
 	machine_check:		mcpcia_machine_check,
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 
-	nr_irqs:		64,
-	irq_probe_mask:		_PROBE_MASK(64),
+	nr_irqs:		128,
+	irq_probe_mask:		_PROBE_MASK(128),
 	update_irq_hw:		rawhide_update_irq_hw,
 	ack_irq:		generic_ack_irq,
 	device_interrupt:	rawhide_srm_device_interrupt,
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/sys_takara.c linux.14p16/arch/alpha/kernel/sys_takara.c
--- linux.vanilla/arch/alpha/kernel/sys_takara.c	Sat Aug 14 02:26:46 1999
+++ linux.14p16/arch/alpha/kernel/sys_takara.c	Thu Dec  9 15:34:21 1999
@@ -31,18 +31,25 @@
 
 
 static void 
-takara_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+takara_update_irq_hw(unsigned long irq, unsigned long unused, int unmask_p)
 {
 	unsigned int regaddr;
+	unsigned long mask;
 
 	if (irq <= 15) {
 		if (irq <= 7)
-			outb(mask, 0x21);	/* ISA PIC1 */
+			outb(alpha_irq_mask, 0x21);		/* ISA PIC1 */
 		else
-			outb(mask >> 8, 0xA1);	/* ISA PIC2 */
-	} else if (irq <= 31) {
-		regaddr = 0x510 + ((irq - 16) & 0x0c);
-		outl((mask >> ((irq - 16) & 0x0c)) & 0xf0000Ul, regaddr);
+			outb(alpha_irq_mask >> 8, 0xA1);	/* ISA PIC2 */
+	} else {
+		if (irq > 63)
+			mask = _alpha_irq_masks[1] << 16;
+		else
+			mask = _alpha_irq_masks[0] >> ((irq - 16) & 0x30);
+
+		regaddr = 0x510 + (((irq - 16) >> 2) & 0x0c);
+
+		outl(mask & 0xffff0000UL, regaddr);
 	}
 }
 
@@ -88,9 +95,6 @@
 {
 	int irq = (vector - 0x800) >> 4;
 
-	if (irq > 15)
-		irq = ((vector - 0x800) >> 6) + 12;
-	
 	handle_irq(irq, irq, regs);
 }
 
@@ -101,8 +105,7 @@
 
 	if (alpha_using_srm)
 		alpha_mv.device_interrupt = takara_srm_device_interrupt;
-
-	if (!alpha_using_srm) {
+	else {
 		unsigned int ctlreg = inl(0x500);
 
 		/* Return to non-accelerated mode.  */
@@ -127,6 +130,43 @@
  */
 
 static int __init
+takara_map_irq_srm(struct pci_dev *dev, int slot, int pin)
+{
+	static char irq_tab[15][5] __initlocaldata = {
+		{ 16+3, 16+3, 16+3, 16+3, 16+3},   /* slot  6 == device 3 */
+		{ 16+2, 16+2, 16+2, 16+2, 16+2},   /* slot  7 == device 2 */
+		{ 16+1, 16+1, 16+1, 16+1, 16+1},   /* slot  8 == device 1 */
+		{   -1,   -1,   -1,   -1,   -1},   /* slot  9 == nothing */
+		{   -1,   -1,   -1,   -1,   -1},   /* slot 10 == nothing */
+		{   -1,   -1,   -1,   -1,   -1},   /* slot 11 == nothing */
+#if 0
+		{   -1,   -1,   -1,   -1,   -1},   /* slot 12 == nothing */
+		{   -1,   -1,   -1,   -1,   -1},   /* slot 13 == nothing */
+		{   -1,   -1,   -1,   -1,   -1},   /* slot 14 == nothing */
+		{   -1,   -1,   -1,   -1,   -1},   /* slot 15 == nothing */
+#else
+		/* these are behind the bridges */
+		{   12,   12,   13,   14,   15},   /* slot 12 == nothing */
+		{    8,    8,    9,   19,   11},   /* slot 13 == nothing */
+		{    4,    4,    5,    6,    7},   /* slot 14 == nothing */
+		{    0,    0,    1,    2,    3},   /* slot 15 == nothing */
+#endif
+		{   -1,   -1,   -1,   -1,   -1},   /* slot 16 == nothing */
+		{64+ 0, 64+0, 64+1, 64+2, 64+3},   /* slot 17= device 4 */
+		{48+ 0, 48+0, 48+1, 48+2, 48+3},   /* slot 18= device 3 */
+		{32+ 0, 32+0, 32+1, 32+2, 32+3},   /* slot 19= device 2 */
+		{16+ 0, 16+0, 16+1, 16+2, 16+3},   /* slot 20= device 1 */
+	};
+	const long min_idsel = 6, max_idsel = 20, irqs_per_slot = 5;
+        int irq = COMMON_TABLE_LOOKUP;
+	if (irq >= 0 && irq < 16) { /* guess that we are behind a bridge */
+	    unsigned int busslot = PCI_SLOT(dev->bus->self->devfn);
+	    irq += irq_tab[busslot-min_idsel][0];
+	}
+	return irq;
+}
+
+static int __init
 takara_map_irq(struct pci_dev *dev, int slot, int pin)
 {
 	static char irq_tab[15][5] __initlocaldata = {
@@ -147,7 +187,7 @@
 		{ 16+1, 16+1, 16+1, 16+1, 16+1},   /* slot 20 == device 1 */
 	};
 	const long min_idsel = 6, max_idsel = 20, irqs_per_slot = 5;
-	return COMMON_TABLE_LOOKUP;
+        return COMMON_TABLE_LOOKUP;
 }
 
 static int __init
@@ -159,14 +199,21 @@
 	unsigned int busslot = PCI_SLOT(dev->bus->self->devfn);
 
 	/* Check first for built-in bridges.  */
-	if (busslot > 16 && ((1<<(36-busslot)) & ctlreg)) {
+	if (busslot > 16 && ((1U << (36 - busslot)) & ctlreg)) {
+#if 0
 		if (pin == 1)
 			pin += (20 - busslot);
 		else {
-			/* Must be a card-based bridge.  */
-			printk(KERN_WARNING "takara_swizzle: cannot handle "
-			       "card-bridge behind builtin bridge yet.\n");
+			/* Can only handle INTA pins currently.  */
+			printk(KERN_WARNING "takara_swizzle: cannot only "
+			       "handle cards with INTA IRQ pin now.\n");
 		}
+#else
+#endif
+	} else {
+		/* Must be a card-based bridge.  */
+		printk(KERN_WARNING "takara_swizzle: cannot handle "
+		       "card-bridge behind builtin bridge yet.\n");
 	}
 
 	*pinp = pin;
@@ -177,8 +224,11 @@
 takara_pci_fixup(void)
 {
 	layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE);
-	common_pci_fixup(takara_map_irq, takara_swizzle);
-	/* enable_ide(0x26e); */
+	if (alpha_using_srm)
+		common_pci_fixup(takara_map_irq_srm, takara_swizzle);
+	else
+		common_pci_fixup(takara_map_irq, takara_swizzle);
+	enable_ide(0x26e);
 }
 
 
@@ -195,8 +245,8 @@
 	machine_check:		cia_machine_check,
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 
-	nr_irqs:		20,
-	irq_probe_mask:		_PROBE_MASK(20),
+	nr_irqs:		128,
+	irq_probe_mask:		_PROBE_MASK(48),
 	update_irq_hw:		takara_update_irq_hw,
 	ack_irq:		generic_ack_irq,
 	device_interrupt:	takara_device_interrupt,
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/traps.c linux.14p16/arch/alpha/kernel/traps.c
--- linux.vanilla/arch/alpha/kernel/traps.c	Sat Aug 14 02:26:46 1999
+++ linux.14p16/arch/alpha/kernel/traps.c	Thu Dec  9 15:34:20 1999
@@ -27,66 +27,270 @@
 {
 	printk("pc = [<%016lx>]  ra = [<%016lx>]  ps = %04lx\n",
 	       regs->pc, regs->r26, regs->ps);
-	printk("r0 = %016lx  r1 = %016lx  r2 = %016lx\n",
+	printk("v0 = %016lx  t0 = %016lx  t1 = %016lx\n",
 	       regs->r0, regs->r1, regs->r2);
-	printk("r3 = %016lx  r4 = %016lx  r5 = %016lx\n",
+	printk("t2 = %016lx  t3 = %016lx  t4 = %016lx\n",
  	       regs->r3, regs->r4, regs->r5);
-	printk("r6 = %016lx  r7 = %016lx  r8 = %016lx\n",
+	printk("t5 = %016lx  t6 = %016lx  t7 = %016lx\n",
 	       regs->r6, regs->r7, regs->r8);
 
 	if (r9_15) {
-		printk("r9 = %016lx  r10= %016lx  r11= %016lx\n",
+		printk("s0 = %016lx  s1 = %016lx  s2 = %016lx\n",
 		       r9_15[9], r9_15[10], r9_15[11]);
-		printk("r12= %016lx  r13= %016lx  r14= %016lx\n",
+		printk("s3 = %016lx  s4 = %016lx  s5 = %016lx\n",
 		       r9_15[12], r9_15[13], r9_15[14]);
-		printk("r15= %016lx\n", r9_15[15]);
+		printk("s6 = %016lx", r9_15[15]);
 	}
 
-	printk("r16= %016lx  r17= %016lx  r18= %016lx\n",
+	printk("  a0 = %016lx  a1 = %016lx\na2 = %016lx",
 	       regs->r16, regs->r17, regs->r18);
-	printk("r19= %016lx  r20= %016lx  r21= %016lx\n",
+	printk("  a3 = %016lx  a4 = %016lx\na5 = %016lx",
  	       regs->r19, regs->r20, regs->r21);
- 	printk("r22= %016lx  r23= %016lx  r24= %016lx\n",
+ 	printk("  t8 = %016lx  t9 = %016lx\nt10= %016lx",
 	       regs->r22, regs->r23, regs->r24);
-	printk("r25= %016lx  r27= %016lx  r28= %016lx\n",
+	printk("  t11= %016lx  pv = %016lx\nat = %016lx",
 	       regs->r25, regs->r27, regs->r28);
-	printk("gp = %016lx  sp = %p\n", regs->gp, regs+1);
+	printk("  gp = %016lx  sp = %p\n", regs->gp, regs+1);
+}
+
+static char * ireg_name[] = {"v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
+			   "t7", "s0", "s1", "s2", "s3", "s4", "s5", "s6",
+			   "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
+			   "t10", "t11", "ra", "pv", "at", "gp", "sp", "zero"};
+
+static char * inst_name[] = {"call_pal", "", "", "", "", "", "", "",
+	"lda", "ldah", "ldbu", "ldq_u", "ldwu", "stw", "stb", "stq_u",
+	"ALU", "ALU", "ALU", "ALU", "SQRT", "FVAX", "FIEEE", "FLOAT",
+	"MISC", "PAL19", "JMP", "PAL1B", "GRAPH", "PAL1D", "PAL1E", "PAL1F",
+	"ldf", "ldg", "lds", "ldt", "stf", "stg", "sts", "stt",
+	"ldl", "ldq", "ldl_l", "ldq_l", "stl", "stq", "stl_c", "stq_c",
+	"br", "fbeq", "fblt", "fble", "bsr", "fbne", "fbge", "fbgt"
+	"blbc", "beq", "blt", "ble", "blbs", "bne", "bge", "bgt"
+};
+
+static char * jump_name[] = {"jmp", "jsr", "ret", "jsr_coroutine"};
+
+typedef struct {int func; char * text;} alist;
+
+static alist inta_name[] = {{0, "addl"}, {2, "s4addl"}, {9, "subl"},
+	{0xb, "s4subl"}, {0xf, "cmpbge"}, {0x12, "s8addl"}, {0x1b, "s8subl"},
+	{0x1d, "cmpult"}, {0x20, "addq"}, {0x22, "s4addq"}, {0x29, "subq"},
+	{0x2b, "s4subq"}, {0x2d, "cmpeq"}, {0x32, "s8addq"}, {0x3b, "s8subq"},
+	{0x3d, "cmpule"}, {0x40, "addl/v"}, {0x49, "subl/v"}, {0x4d, "cmplt"},
+	{0x60, "addq/v"}, {0x69, "subq/v"}, {0x6d, "cmple"}, {-1, 0}};
+
+static alist intl_name[] = {{0, "and"}, {8, "andnot"}, {0x14, "cmovlbs"},
+	{0x16, "cmovlbc"}, {0x20, "or"}, {0x24, "cmoveq"}, {0x26, "cmovne"},
+	{0x28, "ornot"}, {0x40, "xor"}, {0x44, "cmovlt"}, {0x46, "cmovge"},
+	{0x48, "eqv"}, {0x61, "amask"}, {0x64, "cmovle"}, {0x66, "cmovgt"},
+	{0x6c, "implver"}, {-1, 0}};
+
+static alist ints_name[] = {{2, "mskbl"}, {6, "extbl"}, {0xb, "insbl"},
+	{0x12, "mskwl"}, {0x16, "extwl"}, {0x1b, "inswl"}, {0x22, "mskll"},
+	{0x26, "extll"}, {0x2b, "insll"}, {0x30, "zap"}, {0x31, "zapnot"},
+	{0x32, "mskql"}, {0x34, "srl"}, {0x36, "extql"}, {0x39, "sll"},
+	{0x3b, "insql"}, {0x3c, "sra"}, {0x52, "mskwh"}, {0x57, "inswh"},
+	{0x5a, "extwh"}, {0x62, "msklh"}, {0x67, "inslh"}, {0x6a, "extlh"},
+	{0x72, "mskqh"}, {0x77, "insqh"}, {0x7a, "extqh"}, {-1, 0}};
+
+static alist intm_name[] = {{0, "mull"}, {0x20, "mulq"}, {0x30, "umulh"},
+	{0x40, "mull/v"}, {0x60, "mulq/v"}, {-1, 0}};
+
+static alist * int_name[] = {inta_name, intl_name, ints_name, intm_name};
+
+static char *
+assoc(int fcode, alist * a)
+{
+	while ((fcode != a->func) && (a->func != -1))
+		++a;
+	return a->text;
+}
+
+static char *
+iname(unsigned int instr)
+{
+	int opcode = instr >> 26;
+	char * name = inst_name[opcode];
+
+	switch (opcode) {
+		default:
+			break;
+
+		case 0x10:
+		case 0x11:
+		case 0x12:
+		case 0x13: {
+			char * specific_name
+			  = assoc((instr >> 5) & 0x3f, int_name[opcode - 0x10]);
+			if (specific_name)
+				name = specific_name;
+			break;
+		}
+
+		case 0x1a:
+			name = jump_name[(instr >> 14) & 3];
+			break;
+	}
+	
+	return name;
+}
+
+static enum {NOT_INST, PAL, BRANCH, MEMORY, JUMP, OPERATE, FOPERATE, MISC}
+iformat(int opcode)
+{
+	if (opcode >= 0x30)
+		return BRANCH;
+	if (opcode >= 0x20)
+		return MEMORY;
+	if (opcode == 0)
+		return PAL;
+	if (opcode < 8)
+		return NOT_INST;
+	if (opcode < 0x10)
+		return MEMORY;
+	if (opcode < 0x14)
+		return OPERATE;
+	if (opcode < 0x18)
+		return FOPERATE;
+	switch (opcode) {
+		case 0x18:
+			return MISC;
+		case 0x1A:
+			return JUMP;
+		case 0x1C:
+			return OPERATE;
+		default:
+			return NOT_INST;
+	}
+}
+
+/*
+ * The purpose here is to provide useful clues about a kernel crash, so
+ * less likely instructions, e.g. floating point, aren't fully decoded.
+ */
+static void
+disassemble(unsigned int instr)
+{
+	int optype = instr >> 26;
+	char buf[40], *s = buf;
+
+	s += sprintf(buf, "%08x  %s ", instr, iname(instr));
+	switch (iformat(optype)) {
+		default:
+		case NOT_INST:
+		case MISC:
+			break;
+
+		case PAL:
+			s += sprintf(s, "%d", instr);
+			break;
+
+		case BRANCH: {
+			int reg = (instr >> 21) & 0x1f;
+			int offset = instr & 0x1fffff;
+
+			if (offset >= 0x100000)
+				offset -= 0x200000;
+			if (((optype & 3) == 0) || (optype >= 0x38)) {
+				if ((optype != 0x30) || (reg != 0x1f))
+					s += sprintf(s, "%s,", ireg_name[reg]);
+			} else
+				s += sprintf(s, "f%d,", reg);
+			s += sprintf(s, ".%+d", (offset + 1) << 2);
+			break;
+		}
+
+		case MEMORY: {
+			int addr_reg = (instr >> 16) & 0x1f;
+			int value_reg = (instr >> 21) & 0x1f;
+			int offset = instr & 0xffff;
+
+			if (offset >= 0x8000)
+				offset -= 0x10000;
+			if ((optype >= 0x20) && (optype < 0x28))
+				s += sprintf(s, "f%d", value_reg);
+			else
+				s += sprintf(s, "%s", ireg_name[value_reg]);
+
+			s += sprintf(s, ",%d(%s)", offset, ireg_name[addr_reg]);
+			break;
+		}
+
+		case JUMP: {
+			int target_reg = (instr >> 16) & 0x1f;
+			int return_reg = (instr >> 21) & 0x1f;
+
+			s += sprintf(s, "%s,", ireg_name[return_reg]);
+			s += sprintf(s, "(%s)", ireg_name[target_reg]);
+			break;
+		}
+
+		case OPERATE: {
+			int areg = (instr >> 21) & 0x1f;
+			int breg = (instr >> 16) & 0x1f;
+			int creg = instr & 0x1f;
+			int litflag = instr & (1<<12);
+			int lit = (instr >> 13) & 0xff;
+
+			s += sprintf(s, "%s,", ireg_name[areg]);
+			if (litflag)
+				s += sprintf(s, "%d", lit);
+			else
+				s += sprintf(s, "%s", ireg_name[breg]);
+			s += sprintf(s, ",%s", ireg_name[creg]);
+			break;
+		}
+
+		case FOPERATE: {
+			int areg = (instr >> 21) & 0x1f;
+			int breg = (instr >> 16) & 0x1f;
+			int creg = instr & 0x1f;
+
+			s += sprintf(s, "f%d,f%d,f%d", areg, breg, creg);
+			break;
+		}
+	}
+	buf[s-buf] = 0;
+	printk("%s\n", buf);
 }
 
 static void
 dik_show_code(unsigned int *pc)
 {
-	long i;
+	int i;
 
-	printk("Code:");
-	for (i = -3; i < 6; i++) {
+	printk("Code:\n");
+	for (i = -6; i < 2; i++) {
 		unsigned int insn;
 		if (__get_user(insn, pc+i))
 			break;
-		printk("%c%08x%c",i?' ':'<',insn,i?' ':'>');
+		printk("%c", i ? ' ' : '*');
+		disassemble(insn);
 	}
-	printk("\n");
 }
 
 static void
 dik_show_trace(unsigned long *sp)
 {
-	long i = 0;
-	printk("Trace:");
-	while (0x1ff8 & (unsigned long) sp) {
+	int i = 1;
+
+	printk("Trace: ");
+	do {
 		extern unsigned long _stext, _etext;
-		unsigned long tmp = *sp;
-		sp++;
-		if (tmp < (unsigned long) &_stext)
+		unsigned long kpc = *sp;
+
+		if (kpc < (unsigned long) &_stext)
 			continue;
-		if (tmp >= (unsigned long) &_etext)
+		if (kpc >= (unsigned long) &_etext)
 			continue;
-		printk(" [<%lx>]", tmp);
-		if (++i > 40) {
-			printk(" ...");
-			break;
-		}
-	}
+		/*
+		 * Assume that only the low 24-bits of a kernel text address
+		 * is interesting.
+		 */
+		printk("%6x%c", (int)kpc & 0xffffff, (++i % 11) ? ' ' : '\n');
+	} while (((unsigned long)++sp & 0x1ff8) && (i < 33));
+	if (i >= 33)
+		printk(" ...");
 	printk("\n");
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/math-emu/Makefile linux.14p16/arch/alpha/math-emu/Makefile
--- linux.vanilla/arch/alpha/math-emu/Makefile	Sat Aug 28 20:00:53 1999
+++ linux.14p16/arch/alpha/math-emu/Makefile	Thu Dec  9 15:34:21 1999
@@ -1,21 +1,18 @@
 #
-# Makefile for math-emulator files...
+# Makefile for the FPU instruction emulation.
 #
+# 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 :=	math-emu.o
-O_OBJS   :=	fp-emul.o udivmodti4.o
-
-LINKS	:=	double.h op-common.h op-1.h op-2.h op-4.h single.h \
-		soft-fp.h udivmodti4.c
+O_TARGET := math-emu.o
+O_OBJS   := math.o
+CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w
 
 ifeq ($(CONFIG_MATHEMU),m)
 M_OBJS   := $(O_TARGET)
 endif
 
 include $(TOPDIR)/Rules.make
-
-symlinks:
-	ln -sf $(patsubst %,../../sparc64/math-emu/%,$(LINKS)) .
-
-cleansymlinks:
-	rm -f $(LINKS)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/math-emu/fp-emul.c linux.14p16/arch/alpha/math-emu/fp-emul.c
--- linux.vanilla/arch/alpha/math-emu/fp-emul.c	Sat Aug 28 20:00:53 1999
+++ linux.14p16/arch/alpha/math-emu/fp-emul.c	Thu Dec  9 15:34:21 1999
@@ -1,451 +0,0 @@
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-
-#include <asm/uaccess.h>
-
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
-
-#define	OPC_PAL		0x00
-#define OPC_INTA	0x10
-#define OPC_INTL	0x11
-#define OPC_INTS	0x12
-#define OPC_INTM	0x13
-#define OPC_FLTC	0x14
-#define OPC_FLTV	0x15
-#define OPC_FLTI	0x16
-#define OPC_FLTL	0x17
-#define OPC_MISC	0x18
-#define	OPC_JSR		0x1a
-
-#define FOP_SRC_S	0
-#define FOP_SRC_T	2
-#define FOP_SRC_Q	3
-
-#define FOP_FNC_ADDx	0
-#define FOP_FNC_CVTQL	0
-#define FOP_FNC_SUBx	1
-#define FOP_FNC_MULx	2
-#define FOP_FNC_DIVx	3
-#define FOP_FNC_CMPxUN	4
-#define FOP_FNC_CMPxEQ	5
-#define FOP_FNC_CMPxLT	6
-#define FOP_FNC_CMPxLE	7
-#define FOP_FNC_SQRTx	11
-#define FOP_FNC_CVTxS	12
-#define FOP_FNC_CVTxT	14
-#define FOP_FNC_CVTxQ	15
-
-#define MISC_TRAPB	0x0000
-#define MISC_EXCB	0x0400
-
-extern unsigned long alpha_read_fp_reg (unsigned long reg);
-extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
-extern unsigned long alpha_read_fp_reg_s (unsigned long reg);
-extern void alpha_write_fp_reg_s (unsigned long reg, unsigned long val);
-
-
-#ifdef MODULE
-
-MODULE_DESCRIPTION("FP Software completion module");
-
-extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long);
-extern long (*alpha_fp_emul) (unsigned long pc);
-
-static long (*save_emul_imprecise)(struct pt_regs *, unsigned long);
-static long (*save_emul) (unsigned long pc);
-
-long do_alpha_fp_emul_imprecise(struct pt_regs *, unsigned long);
-long do_alpha_fp_emul(unsigned long);
-
-int init_module(void)
-{
-	save_emul_imprecise = alpha_fp_emul_imprecise;
-	save_emul = alpha_fp_emul;
-	alpha_fp_emul_imprecise = do_alpha_fp_emul_imprecise;
-	alpha_fp_emul = do_alpha_fp_emul;
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	alpha_fp_emul_imprecise = save_emul_imprecise;
-	alpha_fp_emul = save_emul;
-}
-
-#undef  alpha_fp_emul_imprecise
-#define alpha_fp_emul_imprecise		do_alpha_fp_emul_imprecise
-#undef  alpha_fp_emul
-#define alpha_fp_emul			do_alpha_fp_emul
-
-#endif /* MODULE */
-
-/* For 128-bit division.  */
-
-__complex__ unsigned long
-udiv128(unsigned long divisor_f0, unsigned long divisor_f1,
-	unsigned long dividend_f0, unsigned long dividend_f1)
-{
-	_FP_FRAC_DECL_2(quo);
-	_FP_FRAC_DECL_2(rem);
-	_FP_FRAC_DECL_2(tmp);
-	unsigned long i, num_bits, bit;
-	__complex__ unsigned long ret;
-
-	_FP_FRAC_SET_2(rem, _FP_ZEROFRAC_2);
-	_FP_FRAC_SET_2(quo, _FP_ZEROFRAC_2);
-
-	if (_FP_FRAC_ZEROP_2(divisor))
-		goto out;
-
-	if (_FP_FRAC_GT_2(divisor, dividend)) {
-		_FP_FRAC_COPY_2(rem, dividend);
-		goto out;
-	}
-
-	if (_FP_FRAC_EQ_2(divisor, dividend)) {
-		__FP_FRAC_SET_2(quo, 0, 1);
-		goto out;
-	}
-
-	num_bits = 128;
-	while (1) {
-		bit = _FP_FRAC_NEGP_2(dividend);
-		_FP_FRAC_COPY_2(tmp, rem);
-		_FP_FRAC_SLL_2(tmp, 1);
-		_FP_FRAC_LOW_2(tmp) |= bit;
-		if (! _FP_FRAC_GE_2(tmp, divisor))
-			break;
-		_FP_FRAC_COPY_2(rem, tmp);
-		_FP_FRAC_SLL_2(dividend, 1);
-		num_bits--;
-	}
-
-	for (i = 0; i < num_bits; i++) {
-		bit = _FP_FRAC_NEGP_2(dividend);
-		_FP_FRAC_SLL_2(rem, 1);
-		_FP_FRAC_LOW_2(rem) |= bit;
-		_FP_FRAC_SUB_2(tmp, rem, divisor);
-		bit = _FP_FRAC_NEGP_2(tmp);
-		_FP_FRAC_SLL_2(dividend, 1);
-		_FP_FRAC_SLL_2(quo, 1);
-		if (!bit) {
-			_FP_FRAC_LOW_2(quo) |= 1;
-			_FP_FRAC_COPY_2(rem, tmp);
-		}
-	}
-
-out:
-	__real__ ret = quo_f1;
-	__imag__ ret = rem_f1;
-	return ret;
-}
-
-/*
- * Emulate the floating point instruction at address PC.  Returns 0 if
- * emulation fails.  Notice that the kernel does not and cannot use FP
- * regs.  This is good because it means that instead of
- * saving/restoring all fp regs, we simply stick the result of the
- * operation into the appropriate register.
- */
-long
-alpha_fp_emul (unsigned long pc)
-{
-	FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
-	FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
-
-	unsigned long fa, fb, fc, func, mode, src;
-	unsigned long fpcw = current->tss.flags;
-	unsigned long res, cmptype, va, vb, vc, fpcr;
-	__u32 insn;
-
-	MOD_INC_USE_COUNT;
-
-	get_user(insn, (__u32*)pc);
-	fc     = (insn >>  0) & 0x1f;	/* destination register */
-	fb     = (insn >> 16) & 0x1f;
-	fa     = (insn >> 21) & 0x1f;
-	func   = (insn >>  5) & 0xf;
-	src    = (insn >>  9) & 0x3;
-	mode   = (insn >> 11) & 0x3;
-	
-	fpcr = rdfpcr();
-
-	if (mode == 3) {
-	    /* Dynamic -- get rounding mode from fpcr.  */
-	    mode = (fpcr >> FPCR_DYN_SHIFT) & 3;
-	}
-
-	res = 0;
-
-	switch (src) {
-	case FOP_SRC_S:
-		va = alpha_read_fp_reg_s(fa);
-		vb = alpha_read_fp_reg_s(fb);
-		
-		__FP_UNPACK_S(SA, &va);
-		__FP_UNPACK_S(SB, &vb);
-
-		switch (func) {
-		case FOP_FNC_SUBx:
-			if (SB_c != FP_CLS_NAN)
-				SB_s ^= 1;
-			/* FALLTHRU */
-		case FOP_FNC_ADDx:
-			FP_ADD_S(SR, SA, SB);
-			goto pack_s;
-
-		case FOP_FNC_MULx:
-			FP_MUL_S(SR, SA, SB);
-			goto pack_s;
-
-		case FOP_FNC_DIVx:
-			if (SB_c == FP_CLS_ZERO && SA_c != FP_CLS_ZERO) {
-				res |= EFLAG_DIVZERO;
-				if (__FPU_TRAP_P(EFLAG_DIVZERO))
-					goto done;
-			}
-			FP_DIV_S(SR, SA, SB);
-			goto pack_s;
-
-		case FOP_FNC_SQRTx:
-			FP_SQRT_S(SR, SA);
-			goto pack_s;
-		}
-		goto bad_insn;
-
-	case FOP_SRC_T:
-		va = alpha_read_fp_reg(fa);
-		vb = alpha_read_fp_reg(fb);
-		
-		__FP_UNPACK_D(DA, &va);
-		__FP_UNPACK_D(DB, &vb);
-
-		switch (func) {
-		case FOP_FNC_SUBx:
-			if (DB_c != FP_CLS_NAN)
-				DB_s ^= 1;
-			/* FALLTHRU */
-		case FOP_FNC_ADDx:
-			FP_ADD_D(DR, DA, DB);
-			goto pack_d;
-
-		case FOP_FNC_MULx:
-			FP_MUL_D(DR, DA, DB);
-			goto pack_d;
-
-		case FOP_FNC_DIVx:
-			if (DB_c == FP_CLS_ZERO && DA_c != FP_CLS_ZERO) {
-				res |= EFLAG_DIVZERO;
-				if (__FPU_TRAP_P(EFLAG_DIVZERO))
-					goto done;
-			}
-			FP_DIV_D(DR, DA, DB);
-			goto pack_d;
-
-		case FOP_FNC_CMPxUN:
-			cmptype = CMPTXX_UN;
-			goto compare;
-		case FOP_FNC_CMPxEQ:
-			cmptype = CMPTXX_EQ;
-			goto compare;
-		case FOP_FNC_CMPxLT:
-			cmptype = CMPTXX_LT;
-			goto compare;
-		case FOP_FNC_CMPxLE:
-			cmptype = CMPTXX_LE;
-			goto compare;
-		compare:
-			FP_CMP_D(res, DA, DB, 3);
-			vc = 0;
-        		if (res == cmptype
-			    || (cmptype == CMPTXX_LE
-				&& (res == CMPTXX_LT || res == CMPTXX_EQ))) {
-				vc = 0x4000000000000000;  
-			}
-			goto done_d;
-
-		case FOP_FNC_SQRTx:
-			FP_SQRT_D(DR, DA);
-			goto pack_d;
-
-		case FOP_FNC_CVTxS:
-			/* It is irritating that DEC encoded CVTST with
-			   SRC == T_floating.  It is also interesting that
-			   the bit used to tell the two apart is /U... */
-			if (insn & 0x2000) {
-				FP_CONV(S,D,1,1,SR,DA);
-				goto pack_s;
-			} else {
-				/* CVTST need do nothing else but copy the
-				   bits and repack.  */
-				DR_c = DA_c;
-				DR_s = DA_s;
-				DR_e = DA_e;
-				DR_r = DA_r;
-				DR_f = DA_f;
-				goto pack_d;
-			}
-
-		case FOP_FNC_CVTxQ:
-			FP_TO_INT_D(vc, DA, 64, 1);
-			res = _FTOI_RESULT(DA);
-			goto done_d;
-		}
-		goto bad_insn;
-
-	case FOP_SRC_Q:
-		vb = alpha_read_fp_reg(fb);
-
-		switch (func) {
-		case FOP_FNC_CVTQL:
-			/* Notice: We can get here only due to an integer
-			   overflow.  Such overflows are reported as invalid
-			   ops.  We return the result the hw would have
-			   computed.  */
-			vc = ((vb & 0xc0000000) << 32 |	/* sign and msb */
-			      (vb & 0x3fffffff) << 29);	/* rest of the int */
-			res = EFLAG_INVALID;
-			goto done_d;
-
-		case FOP_FNC_CVTxS:
-			FP_FROM_INT_S(SR, ((long)vb), 64, long);
-			goto pack_s;
-
-		case FOP_FNC_CVTxT:
-			FP_FROM_INT_D(DR, ((long)vb), 64, long);
-			goto pack_d;
-		}
-		goto bad_insn;
-	}
-	goto bad_insn;
-
-pack_s:
-	res |= __FP_PACK_S(&vc, SR);
-	alpha_write_fp_reg_s(fc, vc);
-	goto done;
-
-pack_d:
-	res |= __FP_PACK_D(&vc, DR);
-done_d:
-	alpha_write_fp_reg(fc, vc);
-	goto done;
-
-	/*
-	 * Take the appropriate action for each possible
-	 * floating-point result:
-	 *
-	 *	- Set the appropriate bits in the FPCR
-	 *	- If the specified exception is enabled in the FPCR,
-	 *	  return.  The caller (entArith) will dispatch
-	 *	  the appropriate signal to the translated program.
-	 *
-	 * In addition, properly track the exception state in software
-	 * as described in the Alpha Architectre Handbook section 4.7.7.3.
-	 */
-done:
-	if (res) {
-		/* Record exceptions in software control word.  */
-		current->tss.flags
-		  = fpcw |= (res << IEEE_STATUS_TO_EXCSUM_SHIFT);
-
-		/* Update hardware control register */
-		fpcr &= (~FPCR_MASK | FPCR_DYN_MASK);
-		fpcr |= ieee_swcr_to_fpcr(fpcw);
-		wrfpcr(fpcr);
-
-		/* Do we generate a signal?  */
-		if (res & fpcw & IEEE_TRAP_ENABLE_MASK) {
-			MOD_DEC_USE_COUNT;
-			return 0;
-		}
-	}
-
-	/* We used to write the destination register here, but DEC FORTRAN
-	   requires that the result *always* be written... so we do the write
-	   immediately after the operations above.  */
-
-	MOD_DEC_USE_COUNT;
-	return 1;
-
-bad_insn:
-	printk(KERN_ERR "alpha_fp_emul: Invalid FP insn %#x at %#lx\n",
-	       insn, pc);
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-long
-alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
-{
-	unsigned long trigger_pc = regs->pc - 4;
-	unsigned long insn, opcode, rc;
-
-	MOD_INC_USE_COUNT;
-
-	/*
-	 * Turn off the bits corresponding to registers that are the
-	 * target of instructions that set bits in the exception
-	 * summary register.  We have some slack doing this because a
-	 * register that is the target of a trapping instruction can
-	 * be written at most once in the trap shadow.
-	 *
-	 * Branches, jumps, TRAPBs, EXCBs and calls to PALcode all
-	 * bound the trap shadow, so we need not look any further than
-	 * up to the first occurrence of such an instruction.
-	 */
-	while (write_mask) {
-		get_user(insn, (__u32*)(trigger_pc));
-		opcode = insn >> 26;
-		rc = insn & 0x1f;
-
-		switch (opcode) {
-		      case OPC_PAL:
-		      case OPC_JSR:
-		      case 0x30 ... 0x3f:	/* branches */
-			MOD_DEC_USE_COUNT;
-			return 0;
-
-		      case OPC_MISC:
-			switch (insn & 0xffff) {
-			      case MISC_TRAPB:
-			      case MISC_EXCB:
-				MOD_DEC_USE_COUNT;
-				return 0;
-
-			      default:
-				break;
-			}
-			break;
-
-		      case OPC_INTA:
-		      case OPC_INTL:
-		      case OPC_INTS:
-		      case OPC_INTM:
-			write_mask &= ~(1UL << rc);
-			break;
-
-		      case OPC_FLTC:
-		      case OPC_FLTV:
-		      case OPC_FLTI:
-		      case OPC_FLTL:
-			write_mask &= ~(1UL << (rc + 32));
-			break;
-		}
-		if (!write_mask) {
-			if (alpha_fp_emul(trigger_pc)) {
-				/* re-execute insns in trap-shadow: */
-				regs->pc = trigger_pc + 4;
-				MOD_DEC_USE_COUNT;
-				return 1;
-			}
-			break;
-		}
-		trigger_pc -= 4;
-	}
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/math-emu/fp-emul.h linux.14p16/arch/alpha/math-emu/fp-emul.h
--- linux.vanilla/arch/alpha/math-emu/fp-emul.h	Fri Apr 12 07:49:30 1996
+++ linux.14p16/arch/alpha/math-emu/fp-emul.h	Thu Dec  9 15:34:21 1999
@@ -1,10 +0,0 @@
-/*
- * These defines correspond to the dynamic rounding mode bits in the
- * Floating Point Control Register.  They also happen to correspond to
- * the instruction encodings except that 0x03 signifies dynamic
- * rounding mode in that case.
- */
-#define ROUND_CHOP	0x00	/* chopped (aka round towards zero) */
-#define ROUND_NINF	0x01	/* round towards negative infinity */
-#define ROUND_NEAR	0x02	/* round towards nearest number */
-#define ROUND_PINF	0x03	/* round towards positive infinity */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/math-emu/math.c linux.14p16/arch/alpha/math-emu/math.c
--- linux.vanilla/arch/alpha/math-emu/math.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/alpha/math-emu/math.c	Thu Dec  9 15:34:21 1999
@@ -0,0 +1,447 @@
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/uaccess.h>
+
+#include "sfp-util.h"
+#include "soft-fp.h"
+#include "single.h"
+#include "double.h"
+
+#define	OPC_PAL		0x00
+#define OPC_INTA	0x10
+#define OPC_INTL	0x11
+#define OPC_INTS	0x12
+#define OPC_INTM	0x13
+#define OPC_FLTC	0x14
+#define OPC_FLTV	0x15
+#define OPC_FLTI	0x16
+#define OPC_FLTL	0x17
+#define OPC_MISC	0x18
+#define	OPC_JSR		0x1a
+
+#define FOP_SRC_S	0
+#define FOP_SRC_T	2
+#define FOP_SRC_Q	3
+
+#define FOP_FNC_ADDx	0
+#define FOP_FNC_CVTQL	0
+#define FOP_FNC_SUBx	1
+#define FOP_FNC_MULx	2
+#define FOP_FNC_DIVx	3
+#define FOP_FNC_CMPxUN	4
+#define FOP_FNC_CMPxEQ	5
+#define FOP_FNC_CMPxLT	6
+#define FOP_FNC_CMPxLE	7
+#define FOP_FNC_SQRTx	11
+#define FOP_FNC_CVTxS	12
+#define FOP_FNC_CVTxT	14
+#define FOP_FNC_CVTxQ	15
+
+#define MISC_TRAPB	0x0000
+#define MISC_EXCB	0x0400
+
+extern unsigned long alpha_read_fp_reg (unsigned long reg);
+extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
+extern unsigned long alpha_read_fp_reg_s (unsigned long reg);
+extern void alpha_write_fp_reg_s (unsigned long reg, unsigned long val);
+
+
+#ifdef MODULE
+
+MODULE_DESCRIPTION("FP Software completion module");
+
+extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long);
+extern long (*alpha_fp_emul) (unsigned long pc);
+
+static long (*save_emul_imprecise)(struct pt_regs *, unsigned long);
+static long (*save_emul) (unsigned long pc);
+
+long do_alpha_fp_emul_imprecise(struct pt_regs *, unsigned long);
+long do_alpha_fp_emul(unsigned long);
+
+int init_module(void)
+{
+	save_emul_imprecise = alpha_fp_emul_imprecise;
+	save_emul = alpha_fp_emul;
+	alpha_fp_emul_imprecise = do_alpha_fp_emul_imprecise;
+	alpha_fp_emul = do_alpha_fp_emul;
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	alpha_fp_emul_imprecise = save_emul_imprecise;
+	alpha_fp_emul = save_emul;
+}
+
+#undef  alpha_fp_emul_imprecise
+#define alpha_fp_emul_imprecise		do_alpha_fp_emul_imprecise
+#undef  alpha_fp_emul
+#define alpha_fp_emul			do_alpha_fp_emul
+
+#endif /* MODULE */
+
+/* For 128-bit division.  */
+
+void
+udiv128(unsigned long divisor_f0, unsigned long divisor_f1,
+	unsigned long dividend_f0, unsigned long dividend_f1,
+	unsigned long *quot, unsigned long *remd)
+{
+	_FP_FRAC_DECL_2(quo);
+	_FP_FRAC_DECL_2(rem);
+	_FP_FRAC_DECL_2(tmp);
+	unsigned long i, num_bits, bit;
+
+	_FP_FRAC_SET_2(rem, _FP_ZEROFRAC_2);
+	_FP_FRAC_SET_2(quo, _FP_ZEROFRAC_2);
+
+	if (_FP_FRAC_ZEROP_2(divisor))
+		goto out;
+
+	if (_FP_FRAC_GT_2(divisor, dividend)) {
+		_FP_FRAC_COPY_2(rem, dividend);
+		goto out;
+	}
+
+	if (_FP_FRAC_EQ_2(divisor, dividend)) {
+		__FP_FRAC_SET_2(quo, 0, 1);
+		goto out;
+	}
+
+	num_bits = 128;
+	while (1) {
+		bit = _FP_FRAC_NEGP_2(dividend);
+		_FP_FRAC_COPY_2(tmp, rem);
+		_FP_FRAC_SLL_2(tmp, 1);
+		_FP_FRAC_LOW_2(tmp) |= bit;
+		if (! _FP_FRAC_GE_2(tmp, divisor))
+			break;
+		_FP_FRAC_COPY_2(rem, tmp);
+		_FP_FRAC_SLL_2(dividend, 1);
+		num_bits--;
+	}
+
+	for (i = 0; i < num_bits; i++) {
+		bit = _FP_FRAC_NEGP_2(dividend);
+		_FP_FRAC_SLL_2(rem, 1);
+		_FP_FRAC_LOW_2(rem) |= bit;
+		_FP_FRAC_SUB_2(tmp, rem, divisor);
+		bit = _FP_FRAC_NEGP_2(tmp);
+		_FP_FRAC_SLL_2(dividend, 1);
+		_FP_FRAC_SLL_2(quo, 1);
+		if (!bit) {
+			_FP_FRAC_LOW_2(quo) |= 1;
+			_FP_FRAC_COPY_2(rem, tmp);
+		}
+	}
+
+out:
+	*quot = quo_f1;
+	*remd = rem_f1;
+	return;
+}
+
+/*
+ * Emulate the floating point instruction at address PC.  Returns 0 if
+ * emulation fails.  Notice that the kernel does not and cannot use FP
+ * regs.  This is good because it means that instead of
+ * saving/restoring all fp regs, we simply stick the result of the
+ * operation into the appropriate register.
+ */
+long
+alpha_fp_emul (unsigned long pc)
+{
+	FP_DECL_EX;
+	FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+	FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+
+	unsigned long fa, fb, fc, func, mode, src;
+	unsigned long fpcw = current->tss.flags;
+	unsigned long res, va, vb, vc, fpcr;
+	__u32 insn;
+
+	MOD_INC_USE_COUNT;
+
+	get_user(insn, (__u32*)pc);
+	fc     = (insn >>  0) & 0x1f;	/* destination register */
+	fb     = (insn >> 16) & 0x1f;
+	fa     = (insn >> 21) & 0x1f;
+	func   = (insn >>  5) & 0xf;
+	src    = (insn >>  9) & 0x3;
+	mode   = (insn >> 11) & 0x3;
+	
+	fpcr = rdfpcr();
+
+	if (mode == 3) {
+	    /* Dynamic -- get rounding mode from fpcr.  */
+	    mode = (fpcr >> FPCR_DYN_SHIFT) & 3;
+	}
+
+	switch (src) {
+	case FOP_SRC_S:
+		va = alpha_read_fp_reg_s(fa);
+		vb = alpha_read_fp_reg_s(fb);
+		
+		FP_UNPACK_SP(SA, &va);
+		FP_UNPACK_SP(SB, &vb);
+
+		switch (func) {
+		case FOP_FNC_SUBx:
+			FP_SUB_S(SR, SA, SB);
+			goto pack_s;
+
+		case FOP_FNC_ADDx:
+			FP_ADD_S(SR, SA, SB);
+			goto pack_s;
+
+		case FOP_FNC_MULx:
+			FP_MUL_S(SR, SA, SB);
+			goto pack_s;
+
+		case FOP_FNC_DIVx:
+			FP_DIV_S(SR, SA, SB);
+			goto pack_s;
+
+		case FOP_FNC_SQRTx:
+			FP_SQRT_S(SR, SB);
+			goto pack_s;
+		}
+		goto bad_insn;
+
+	case FOP_SRC_T:
+		va = alpha_read_fp_reg(fa);
+		vb = alpha_read_fp_reg(fb);
+
+		if ((func & ~3) == FOP_FNC_CMPxUN) {
+			FP_UNPACK_RAW_DP(DA, &va);
+			FP_UNPACK_RAW_DP(DB, &vb);
+			if (!DA_e && !_FP_FRAC_ZEROP_1(DA)) {
+				FP_SET_EXCEPTION(FP_EX_DENORM);
+				if (FP_DENORM_ZERO)
+					_FP_FRAC_SET_1(DA, _FP_ZEROFRAC_1);
+			}
+			if (!DB_e && !_FP_FRAC_ZEROP_1(DB)) {
+				FP_SET_EXCEPTION(FP_EX_DENORM);
+				if (FP_DENORM_ZERO)
+					_FP_FRAC_SET_1(DB, _FP_ZEROFRAC_1);
+			}
+			FP_CMP_D(res, DA, DB, 3);
+			vc = 0x4000000000000000;
+			/* CMPTEQ, CMPTUN don't trap on QNaN, while CMPTLT and CMPTLE do */
+			if (res == 3 && ((func & 3) >= 2 || FP_ISSIGNAN_D(DA) || FP_ISSIGNAN_D(DB)))
+				FP_SET_EXCEPTION(FP_EX_INVALID);
+			switch (func) {
+			case FOP_FNC_CMPxUN: if (res != 3) vc = 0; break;
+			case FOP_FNC_CMPxEQ: if (res) vc = 0; break;
+			case FOP_FNC_CMPxLT: if (res != -1) vc = 0; break;
+			case FOP_FNC_CMPxLE: if ((long)res > 0) vc = 0; break;
+			}
+			goto done_d;
+		}
+
+		FP_UNPACK_DP(DA, &va);
+		FP_UNPACK_DP(DB, &vb);
+
+		switch (func) {
+		case FOP_FNC_SUBx:
+			FP_SUB_D(DR, DA, DB);
+			goto pack_d;
+
+		case FOP_FNC_ADDx:
+			FP_ADD_D(DR, DA, DB);
+			goto pack_d;
+
+		case FOP_FNC_MULx:
+			FP_MUL_D(DR, DA, DB);
+			goto pack_d;
+
+		case FOP_FNC_DIVx:
+			FP_DIV_D(DR, DA, DB);
+			goto pack_d;
+
+		case FOP_FNC_SQRTx:
+			FP_SQRT_D(DR, DB);
+			goto pack_d;
+
+		case FOP_FNC_CVTxS:
+			/* It is irritating that DEC encoded CVTST with
+			   SRC == T_floating.  It is also interesting that
+			   the bit used to tell the two apart is /U... */
+			if (insn & 0x2000) {
+				FP_CONV(S,D,1,1,SR,DB);
+				goto pack_s;
+			} else {
+				/* CVTST need do nothing else but copy the
+				   bits and repack.  */
+				DR_c = DB_c;
+				DR_s = DB_s;
+				DR_e = DB_e;
+				DR_f = DB_f;
+				goto pack_d;
+			}
+
+		case FOP_FNC_CVTxQ:
+			if (DB_c == FP_CLS_NAN && (_FP_FRAC_HIGH_RAW_D(DB) & _FP_QNANBIT_D))
+				vc = 0; /* AAHB Table B-2 sais QNaN should not trigger INV */
+			else
+				FP_TO_INT_ROUND_D(vc, DB, 64, 2);
+			goto done_d;
+		}
+		goto bad_insn;
+
+	case FOP_SRC_Q:
+		vb = alpha_read_fp_reg(fb);
+
+		switch (func) {
+		case FOP_FNC_CVTQL:
+			/* Notice: We can get here only due to an integer
+			   overflow.  Such overflows are reported as invalid
+			   ops.  We return the result the hw would have
+			   computed.  */
+			vc = ((vb & 0xc0000000) << 32 |	/* sign and msb */
+			      (vb & 0x3fffffff) << 29);	/* rest of the int */
+			FP_SET_EXCEPTION (FP_EX_INVALID);
+			goto done_d;
+
+		case FOP_FNC_CVTxS:
+			FP_FROM_INT_S(SR, ((long)vb), 64, long);
+			goto pack_s;
+
+		case FOP_FNC_CVTxT:
+			FP_FROM_INT_D(DR, ((long)vb), 64, long);
+			goto pack_d;
+		}
+		goto bad_insn;
+	}
+	goto bad_insn;
+
+pack_s:
+	FP_PACK_SP(&vc, SR);
+	alpha_write_fp_reg_s(fc, vc);
+	goto done;
+
+pack_d:
+	FP_PACK_DP(&vc, DR);
+done_d:
+	alpha_write_fp_reg(fc, vc);
+	goto done;
+
+	/*
+	 * Take the appropriate action for each possible
+	 * floating-point result:
+	 *
+	 *	- Set the appropriate bits in the FPCR
+	 *	- If the specified exception is enabled in the FPCR,
+	 *	  return.  The caller (entArith) will dispatch
+	 *	  the appropriate signal to the translated program.
+	 *
+	 * In addition, properly track the exception state in software
+	 * as described in the Alpha Architectre Handbook section 4.7.7.3.
+	 */
+done:
+	if (_fex) {
+		/* Record exceptions in software control word.  */
+		current->tss.flags
+		  = fpcw |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT);
+
+		/* Update hardware control register */
+		fpcr &= (~FPCR_MASK | FPCR_DYN_MASK);
+		fpcr |= ieee_swcr_to_fpcr(fpcw);
+		wrfpcr(fpcr);
+
+		/* Do we generate a signal?  */
+		if (_fex & fpcw & IEEE_TRAP_ENABLE_MASK) {
+			MOD_DEC_USE_COUNT;
+			return 0;
+		}
+	}
+
+	/* We used to write the destination register here, but DEC FORTRAN
+	   requires that the result *always* be written... so we do the write
+	   immediately after the operations above.  */
+
+	MOD_DEC_USE_COUNT;
+	return 1;
+
+bad_insn:
+	printk(KERN_ERR "alpha_fp_emul: Invalid FP insn %#x at %#lx\n",
+	       insn, pc);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+long
+alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
+{
+	unsigned long trigger_pc = regs->pc - 4;
+	unsigned long insn, opcode, rc;
+
+	MOD_INC_USE_COUNT;
+
+	/*
+	 * Turn off the bits corresponding to registers that are the
+	 * target of instructions that set bits in the exception
+	 * summary register.  We have some slack doing this because a
+	 * register that is the target of a trapping instruction can
+	 * be written at most once in the trap shadow.
+	 *
+	 * Branches, jumps, TRAPBs, EXCBs and calls to PALcode all
+	 * bound the trap shadow, so we need not look any further than
+	 * up to the first occurrence of such an instruction.
+	 */
+	while (write_mask) {
+		get_user(insn, (__u32*)(trigger_pc));
+		opcode = insn >> 26;
+		rc = insn & 0x1f;
+
+		switch (opcode) {
+		      case OPC_PAL:
+		      case OPC_JSR:
+		      case 0x30 ... 0x3f:	/* branches */
+			MOD_DEC_USE_COUNT;
+			return 0;
+
+		      case OPC_MISC:
+			switch (insn & 0xffff) {
+			      case MISC_TRAPB:
+			      case MISC_EXCB:
+				MOD_DEC_USE_COUNT;
+				return 0;
+
+			      default:
+				break;
+			}
+			break;
+
+		      case OPC_INTA:
+		      case OPC_INTL:
+		      case OPC_INTS:
+		      case OPC_INTM:
+			write_mask &= ~(1UL << rc);
+			break;
+
+		      case OPC_FLTC:
+		      case OPC_FLTV:
+		      case OPC_FLTI:
+		      case OPC_FLTL:
+			write_mask &= ~(1UL << (rc + 32));
+			break;
+		}
+		if (!write_mask) {
+			if (alpha_fp_emul(trigger_pc)) {
+				/* re-execute insns in trap-shadow: */
+				regs->pc = trigger_pc + 4;
+				MOD_DEC_USE_COUNT;
+				return 1;
+			}
+			break;
+		}
+		trigger_pc -= 4;
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/math-emu/sfp-machine.h linux.14p16/arch/alpha/math-emu/sfp-machine.h
--- linux.vanilla/arch/alpha/math-emu/sfp-machine.h	Sat Aug 28 20:00:53 1999
+++ linux.14p16/arch/alpha/math-emu/sfp-machine.h	Thu Dec  9 15:34:21 1999
@@ -1,6 +1,10 @@
-/* Machine-dependent software floating-point definitions.  Sparc64 version.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+/* Machine-dependent software floating-point definitions.
+   Alpha kernel version.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+		  Jakub Jelinek (jakub@redhat.com) and
+		  David S. Miller (davem@redhat.com).
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public License as
@@ -17,575 +21,64 @@
    not, write to the Free Software Foundation, Inc.,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
-#include <linux/sched.h>
-#include <asm/fpu.h>
-
+#ifndef _SFP_MACHINE_H
+#define _SFP_MACHINE_H
+   
 #define _FP_W_TYPE_SIZE		64
 #define _FP_W_TYPE		unsigned long
 #define _FP_WS_TYPE		signed long
 #define _FP_I_TYPE		long
 
-#define _FP_MUL_MEAT_S(R,X,Y)	_FP_MUL_MEAT_1_imm(S,R,X,Y)
-#define _FP_MUL_MEAT_D(R,X,Y)	_FP_MUL_MEAT_1_wide(D,R,X,Y,umul_ppmm)
-#define _FP_MUL_MEAT_Q(R,X,Y)	_FP_MUL_MEAT_2_wide(Q,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_S(R,X,Y)					\
+  _FP_MUL_MEAT_1_imm(_FP_WFRACBITS_S,R,X,Y)
+#define _FP_MUL_MEAT_D(R,X,Y)					\
+  _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y)					\
+  _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
 
 #define _FP_DIV_MEAT_S(R,X,Y)	_FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm)
 #define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_1_udiv(D,R,X,Y)
-#define _FP_DIV_MEAT_Q(R,X,Y)	_FP_DIV_MEAT_2_udiv_64(Q,R,X,Y)
+#define _FP_DIV_MEAT_Q(R,X,Y)	_FP_DIV_MEAT_2_udiv(Q,R,X,Y)
 
 #define _FP_NANFRAC_S		_FP_QNANBIT_S
 #define _FP_NANFRAC_D		_FP_QNANBIT_D
-#define _FP_NANFRAC_Q		_FP_QNANBIT_Q, 0
-
-/* On some architectures float-to-int conversions return a result
-   code.  On others (e.g. Sparc) they return 0.  */
-#define _FTOI_RESULT(X)		X##_r
-
-#define _FP_KEEPNANFRACP	1
-
-/*
- * Alpha Architecture Manual Section 4.7.10.4: Propagating NaN Values,
- * summary:
- *
- * The first of the following rules that is applicable governs the
- * value returned:
- *	1: If X is a quiet NaN, copy X to the result.
- *	2: If X is a signaling NaN, the result is the canonical quiet NaN
- *	   with the same sign as X
- *	3: If Y is a quiet NaN, copy Y to the result.
- *	4: If Y is a signaling NaN, the result is the canonical quiet NaN
- *	   with the same sign as Y
- *	5: The result is the canonical quiet NaN with a sign bit of 1
- *
- * In addition, in cases (2) and (4) above we set EFLAG_INVALID.
- */
+#define _FP_NANFRAC_Q		_FP_QNANBIT_Q
+#define _FP_NANSIGN_S		1
+#define _FP_NANSIGN_D		1
+#define _FP_NANSIGN_Q		1
 
-#define _FP_IS_NAN(fs, Z)	(Z##_c == FP_CLS_NAN)
-#define _FP_IS_QNAN(fs, Z)	(Z##_f & _FP_QNANBIT_##fs)
+#define _FP_KEEPNANFRACP 1
 
-#define _FP_CHOOSENAN(fs, wc, R, X, Y)				\
-  do {								\
-    R##_r |= (X##_r | Y##_r);					\
-    if (_FP_IS_NAN(fs, Y)) {					\
-	R##_s = Y##_s;						\
-	R##_c = FP_CLS_NAN;					\
-	if (_FP_IS_QNAN(fs, Y)) {	/* Rule 1 */		\
-	    _FP_FRAC_COPY_##wc(R,Y);				\
-	} else {			/* Rule 2 */		\
-	    _FP_FRAC_SET_##wc(R,Y##_f | _FP_QNANBIT_##fs); 	\
-	    R##_r = EFLAG_INVALID;				\
-	}							\
-    } else if (_FP_IS_NAN(fs, X)) {				\
-	R##_s = X##_s;						\
-	R##_c = FP_CLS_NAN;					\
-	if (_FP_IS_QNAN(fs, X)) {	/* Rule 3 */		\
-	    _FP_FRAC_COPY_##wc(R,X);				\
-	} else {			/* Rule 4 */		\
-	    _FP_FRAC_SET_##wc(R,X##_f | _FP_QNANBIT_##fs); 	\
-	    R##_r |= EFLAG_INVALID;				\
-	}							\
-    } else {				/* Rule 5 */		\
-	R##_s = 1;						\
-	R##_c = FP_CLS_NAN;					\
-	_FP_FRAC_SET_##wc(R,_FP_QNANBIT_##fs | EFLAG_MASK); 	\
-    }								\
-  } while(0)
-
-/* Rules 3 and 4 don't apply to functions of only one argument */
-#define _FP_CHOOSENAN_1(fs, wc, R, X)				\
+/* Alpha Architecture Handbook, 4.7.10.4 sais that
+ * we should prefer any type of NaN in Fb, then Fa.
+ */
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)			\
   do {								\
-    if (_FP_IS_NAN(fs, X)) {					\
-	R##_s = X##_s;						\
-	R##_c = FP_CLS_NAN;					\
-	if (_FP_IS_QNAN(fs, X)) {	/* Rule 1 */		\
-	    _FP_FRAC_COPY_##wc(R,X);				\
-	} else {			/* Rule 2 */		\
-	    _FP_FRAC_SET_##wc(R,X##_f | _FP_QNANBIT_##fs); 	\
-	    R##_r |= EFLAG_INVALID;				\
-	}							\
-    } else {				/* Rule 5 */		\
-	R##_s = 1;						\
-	R##_c = FP_CLS_NAN;					\
-	_FP_FRAC_SET_##wc(R,_FP_QNANBIT_##fs | EFLAG_MASK); 	\
-    }								\
-  } while(0)
-
-#define _FP_CHOOSENAN_SQRT	_FP_CHOOSENAN_1
-
-
-#define __FP_UNPACK_DENORM(fs, wc, X)					\
-  do {									\
-	_FP_I_TYPE _shift;						\
-	X##_r |= EFLAG_DENORM;						\
-	if (_FP_DENORM_TO_ZERO) {					\
-	    /* Crunching a nonzero denorm to zero necessarily makes */  \
-	    /* the result inexact */					\
-	    X##_r |= EFLAG_INEXACT;					\
-	    _FP_FRAC_SET_##wc(X, 0);					\
-	    X##_c = FP_CLS_ZERO;					\
-	} else {							\
-	    _FP_FRAC_CLZ_##wc(_shift, X);				\
-	    _shift -= _FP_FRACXBITS_##fs;				\
-	    _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS));		\
-	    X##_e -= _FP_EXPBIAS_##fs - 1 + _shift;			\
-	    X##_c = FP_CLS_NORMAL;					\
-	}								\
-  } while (0)
-
-#define __FP_UNPACK_RAW_1(fs, X, val)	\
-  do {					\
-    union _FP_UNION_##fs *_flo =	\
-    	(union _FP_UNION_##fs *)val;	\
-					\
-    X##_f = _flo->bits.frac;		\
-    X##_e = _flo->bits.exp;		\
-    X##_s = _flo->bits.sign;		\
-  } while (0)
-
-#define __FP_UNPACK_RAW_2(fs, X, val)	\
-  do {					\
-    union _FP_UNION_##fs *_flo =	\
-    	(union _FP_UNION_##fs *)val;	\
-					\
-    X##_f0 = _flo->bits.frac0;		\
-    X##_f1 = _flo->bits.frac1;		\
-    X##_e  = _flo->bits.exp;		\
-    X##_s  = _flo->bits.sign;		\
-  } while (0)
-
-#define __FP_UNPACK_S(X,val)		\
-  do {					\
-    __FP_UNPACK_RAW_1(S,X,val);		\
-    _FP_UNPACK_CANONICAL(S,1,X);	\
-  } while (0)
-
-#define __FP_UNPACK_D(X,val)		\
-  do {					\
-    __FP_UNPACK_RAW_1(D,X,val);		\
-    _FP_UNPACK_CANONICAL(D,1,X);	\
+    R##_s = Y##_s;						\
+    _FP_FRAC_COPY_##wc(R,X);					\
+    R##_c = FP_CLS_NAN;						\
   } while (0)
 
-#define __FP_UNPACK_Q(X,val)		\
-  do {					\
-    __FP_UNPACK_RAW_2(Q,X,val);		\
-    _FP_UNPACK_CANONICAL(Q,2,X);	\
-  } while (0)
-
-#define __FP_PACK_RAW_1(fs, val, X)	\
-  do {					\
-    union _FP_UNION_##fs *_flo =	\
-    	(union _FP_UNION_##fs *)val;	\
-					\
-    _flo->bits.frac = X##_f;		\
-    _flo->bits.exp  = X##_e;		\
-    _flo->bits.sign = X##_s;		\
-  } while (0)
-  
-#define __FP_PACK_RAW_2(fs, val, X)	\
-  do {					\
-    union _FP_UNION_##fs *_flo =	\
-    	(union _FP_UNION_##fs *)val;	\
-					\
-    _flo->bits.frac0 = X##_f0;		\
-    _flo->bits.frac1 = X##_f1;		\
-    _flo->bits.exp   = X##_e;		\
-    _flo->bits.sign  = X##_s;		\
-  } while (0)
-
-
-/* Alpha rules for handling certain exceptional cases are different
- * enough that we simply define our own versions here to override
- * the ones in op-common.h
- */
+/* Obtain the current rounding mode. */
+#define FP_ROUNDMODE	mode
+#define FP_RND_NEAREST	(FPCR_DYN_NORMAL >> FPCR_DYN_SHIFT)
+#define FP_RND_ZERO	(FPCR_DYN_CHOPPED >> FPCR_DYN_SHIFT)
+#define FP_RND_PINF	(FPCR_DYN_PLUS >> FPCR_DYN_SHIFT)
+#define FP_RND_MINF	(FPCR_DYN_MINUS >> FPCR_DYN_SHIFT)
 
-#define _FP_ADD(fs, wc, R, X, Y)					     \
-do {									     \
-  /* Propagate any flags that may have been set during unpacking */	     \
-  R##_r |= (X##_r | Y##_r);						     \
-  switch (_FP_CLS_COMBINE(X##_c, Y##_c))				     \
-  {									     \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):			     \
-    {									     \
-      /* shift the smaller number so that its exponent matches the larger */ \
-      _FP_I_TYPE diff = X##_e - Y##_e;					     \
-									     \
-      if (diff < 0)							     \
-	{								     \
-	  diff = -diff;							     \
-	  if (diff <= _FP_WFRACBITS_##fs)				     \
-	    _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs);		     \
-	  else if (!_FP_FRAC_ZEROP_##wc(X)) {				     \
-	    _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);			     \
-	    R##_r |= EFLAG_INEXACT;					     \
-	  }								     \
-	  else								     \
-	    _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);			     \
-	  R##_e = Y##_e;						     \
-	}								     \
-      else								     \
-	{								     \
-	  if (diff > 0)							     \
-	    {								     \
-	      if (diff <= _FP_WFRACBITS_##fs)				     \
-	        _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs);		     \
-	      else if (!_FP_FRAC_ZEROP_##wc(Y))	{			     \
-	        _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc);			     \
-	         R##_r |= EFLAG_INEXACT;				     \
-	      }								     \
-	      else							     \
-	        _FP_FRAC_SET_##wc(Y, _FP_ZEROFRAC_##wc);		     \
-	    }								     \
-	  R##_e = X##_e;						     \
-	}								     \
-									     \
-      R##_c = FP_CLS_NORMAL;						     \
-									     \
-      if (X##_s == Y##_s)						     \
-	{								     \
-	  R##_s = X##_s;						     \
-	  _FP_FRAC_ADD_##wc(R, X, Y);					     \
-	  if (_FP_FRAC_OVERP_##wc(fs, R))				     \
-	    {								     \
-	      _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs);		     \
-	      R##_e++;							     \
-	    }								     \
-	}								     \
-      else								     \
-	{								     \
-	  R##_s = X##_s;						     \
-	  _FP_FRAC_SUB_##wc(R, X, Y);					     \
-	  if (_FP_FRAC_ZEROP_##wc(R))					     \
-	    {								     \
-	      /* return an exact zero */				     \
-	      if (FP_ROUNDMODE == FP_RND_MINF)				     \
-		R##_s |= Y##_s;						     \
-	      else							     \
-		R##_s &= Y##_s;						     \
-	      R##_c = FP_CLS_ZERO;					     \
-	    }								     \
-	  else								     \
-	    {								     \
-	      if (_FP_FRAC_NEGP_##wc(R))				     \
-		{							     \
-		  _FP_FRAC_SUB_##wc(R, Y, X);				     \
-		  R##_s = Y##_s;					     \
-		}							     \
-									     \
-	      /* renormalize after subtraction */			     \
-	      _FP_FRAC_CLZ_##wc(diff, R);				     \
-	      diff -= _FP_WFRACXBITS_##fs;				     \
-	      if (diff)							     \
-		{							     \
-		  R##_e -= diff;					     \
-		  _FP_FRAC_SLL_##wc(R, diff);				     \
-		}							     \
-	    }								     \
-	}								     \
-      break;								     \
-    }									     \
-									     \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):				     \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):			     \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):				     \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):				     \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):			     \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):				     \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):				     \
-    _FP_CHOOSENAN(fs, wc, R, X, Y);					     \
-    break;								     \
-									     \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):			     \
-    R##_e = X##_e;							     \
-    _FP_FRAC_COPY_##wc(R, X);						     \
-    R##_s = X##_s;							     \
-    R##_c = X##_c;							     \
-    break;								     \
-									     \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):			     \
-    R##_e = Y##_e;							     \
-    _FP_FRAC_COPY_##wc(R, Y);						     \
-    R##_s = Y##_s;							     \
-    R##_c = Y##_c;							     \
-    break;								     \
-									     \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):				     \
-    if (X##_s != Y##_s)							     \
-      {									     \
-	/* +INF + -INF => NAN */					     \
-	_FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);				     \
-	R##_s = X##_s ^ Y##_s;						     \
-	R##_c = FP_CLS_NAN;						     \
-	R##_r |= EFLAG_INVALID;						     \
-	break;								     \
-      }									     \
-    /* FALLTHRU */							     \
-									     \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):			     \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):				     \
-    R##_s = X##_s;							     \
-    R##_c = FP_CLS_INF;							     \
-    break;								     \
-									     \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):			     \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):				     \
-    R##_s = Y##_s;							     \
-    R##_c = FP_CLS_INF;							     \
-    break;								     \
-									     \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):			     \
-    /* make sure the sign is correct */					     \
-    if (FP_ROUNDMODE == FP_RND_MINF)					     \
-      R##_s = X##_s | Y##_s;						     \
-    else								     \
-      R##_s = X##_s & Y##_s;						     \
-    R##_c = FP_CLS_ZERO;						     \
-    break;								     \
-									     \
-  default:								     \
-    abort();								     \
-  }									     \
-} while (0)
-
-
-#define _FP_MUL(fs, wc, R, X, Y)			\
-do {							\
-  /* Propagate any flags that may have been set during unpacking */	     \
-  R##_r |= (X##_r | Y##_r);						     \
-  R##_s = X##_s ^ Y##_s;				\
-  switch (_FP_CLS_COMBINE(X##_c, Y##_c))		\
-  {							\
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):	\
-    R##_c = FP_CLS_NORMAL;				\
-    R##_e = X##_e + Y##_e + 1;				\
-							\
-    _FP_MUL_MEAT_##fs(R,X,Y);				\
-							\
-    if (_FP_FRAC_OVERP_##wc(fs, R))			\
-      _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs);	\
-    else						\
-      R##_e--;						\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):	\
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):		\
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):		\
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):		\
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):	\
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):		\
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):		\
-    _FP_CHOOSENAN(fs, wc, R, X, Y);			\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):		\
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):	\
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):	\
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):	\
-    _FP_FRAC_COPY_##wc(R, X);				\
-    R##_c = X##_c;					\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):	\
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):	\
-    _FP_FRAC_COPY_##wc(R, Y);				\
-    R##_c = Y##_c;					\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):		\
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):		\
-    R##_c = FP_CLS_NAN;					\
-    _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);		\
-    R##_s = 1; /* Alpha SRM rule */			\
-    break;						\
-							\
-  default:						\
-    abort();						\
-  }							\
-} while (0)
-
-
-#define _FP_DIV(fs, wc, R, X, Y)			\
-do {							\
-  /* Propagate any flags that may have been set during unpacking */ \
-  R##_r |= (X##_r | Y##_r);				\
-  R##_s = X##_s ^ Y##_s;				\
-  switch (_FP_CLS_COMBINE(X##_c, Y##_c))		\
-  {							\
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):	\
-    R##_c = FP_CLS_NORMAL;				\
-    R##_e = X##_e - Y##_e;				\
-							\
-    _FP_DIV_MEAT_##fs(R,X,Y);				\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):	\
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):		\
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):		\
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):		\
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):	\
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):		\
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):		\
-    _FP_CHOOSENAN(fs, wc, R, X, Y);			\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):	\
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):		\
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):	\
-    R##_c = FP_CLS_ZERO;				\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):	\
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):		\
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):	\
-    R##_c = FP_CLS_INF;					\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):		\
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):	\
-    R##_c = FP_CLS_NAN;					\
-    _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);		\
-    R##_s = 1;	/* Alpha SRM rule */			\
-    break;						\
-							\
-  default:						\
-    abort();						\
-  }							\
-} while (0)
-
-
-#define _FP_TO_INT(fs, wc, r, X, rsize, rsigned)			\
-  ({									\
-    switch (X##_c)							\
-      {									\
-      case FP_CLS_ZERO:							\
-	r = 0;								\
-	break;								\
-      case FP_CLS_NAN:                                              	\
-	r = 0;								\
-	X##_r |= EFLAG_INVALID;						\
-	break;								\
-      case FP_CLS_INF:							\
-	r = 0;								\
-	X##_r |= (EFLAG_INVALID | EFLAG_INEXACT);			\
-	break;								\
-      case FP_CLS_NORMAL:						\
-	if (X##_e < 0)							\
-	  {								\
-	    r = 0;							\
-	    X##_r |= EFLAG_INEXACT;					\
-	  }								\
-	else								\
-	  {								\
-	    if (X##_e >= rsize - (rsigned != 0)) {			\
-		/* Overflow.  On alpha, set the INV bit and proceed */	\
-		/* JRP - I *believe* the proper behavior is to set */   \
-		/*       INV and write a true zero... need to check */  \
-		X##_r |= EFLAG_INVALID;					\
-		r = 0;							\
-		break;							\
-	    }								\
-	    if (_FP_W_TYPE_SIZE*wc < rsize)				\
-	      {								\
-		_FP_FRAC_ASSEMBLE_##wc(r, X, rsize);			\
-		r <<= X##_e - _FP_WFRACBITS_##fs;			\
-	      }								\
-	    else							\
-	      {								\
-		if (X##_e >= _FP_WFRACBITS_##fs)			\
-		  _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1)); \
-		else							\
-		  _FP_FRAC_SRL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1)); \
-		_FP_FRAC_ASSEMBLE_##wc(r, X, rsize);			\
-	      }								\
-	    if (rsigned && X##_s)					\
-	      r = -r;							\
-	  }								\
-	break;								\
-      }									\
-      X##_r;								\
-  })
-
-
-/* We only actually write to the destination register if exceptions
-   signalled (if any) will not trap.  */
-#define __FPU_TEM		(current->tss.flags & IEEE_TRAP_ENABLE_MASK)
-#define __FPU_TRAP_P(bits)	((__FPU_TEM & (bits)) != 0)
-
-#define __FP_PACK_S(val,X)			\
-({  int __exc = _FP_PACK_CANONICAL(S,1,X);	\
-    if (!__exc || !__FPU_TRAP_P(__exc))		\
-        __FP_PACK_RAW_1(S,val,X);		\
-    __exc;					\
-})
-
-#define __FP_PACK_D(val,X)			\
-({  int __exc = _FP_PACK_CANONICAL(D,1,X);	\
-    if(!__exc || !__FPU_TRAP_P(__exc))		\
-        __FP_PACK_RAW_1(D,val,X);		\
-    __exc;					\
-})
-
-#define __FP_PACK_Q(val,X)			\
-({  int __exc = _FP_PACK_CANONICAL(Q,2,X);	\
-    if(!__exc || !__FPU_TRAP_P(__exc))		\
-        __FP_PACK_RAW_2(Q,val,X);		\
-    __exc;					\
-})
+/* Exception flags. */
+#define FP_EX_INVALID		IEEE_TRAP_ENABLE_INV
+#define FP_EX_OVERFLOW		IEEE_TRAP_ENABLE_OVF
+#define FP_EX_UNDERFLOW		IEEE_TRAP_ENABLE_UNF
+#define FP_EX_DIVZERO		IEEE_TRAP_ENABLE_DZE
+#define FP_EX_INEXACT		IEEE_TRAP_ENABLE_INE
+#define FP_EX_DENORM		IEEE_TRAP_ENABLE_DNO
 
-/* Obtain the current rounding mode. */
-#define FP_ROUNDMODE		mode
-#define FP_RND_NEAREST		(FPCR_DYN_NORMAL >> FPCR_DYN_SHIFT)
-#define FP_RND_ZERO		(FPCR_DYN_CHOPPED >> FPCR_DYN_SHIFT)
-#define FP_RND_PINF		(FPCR_DYN_PLUS >> FPCR_DYN_SHIFT)
-#define FP_RND_MINF		(FPCR_DYN_MINUS >> FPCR_DYN_SHIFT)
-
-
-#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
-  ((sl) = (al) + (bl), (sh) = (ah) + (bh) + ((sl) < (al)))
-
-#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
-  ((sl) = (al) - (bl), (sh) = (ah) - (bh) - ((al) < (bl)))
-
-#define umul_ppmm(wh, wl, u, v)			\
-  __asm__ ("mulq %2,%3,%1; umulh %2,%3,%0"	\
-	   : "=r" ((UDItype)(wh)),		\
-	     "=&r" ((UDItype)(wl))		\
-	   : "r" ((UDItype)(u)),		\
-	     "r" ((UDItype)(v)))
-
-extern __complex__ unsigned long udiv128(unsigned long, unsigned long,
-					 unsigned long, unsigned long);
-
-#define udiv_qrnnd(q, r, n1, n0, d)	\
-  do {					\
-    __complex__ unsigned long x_;	\
-    x_ = udiv128((n0), (n1), 0, (d));	\
-    (q) = __real__ x_;			\
-    (r) = __imag__ x_;			\
-  } while (0)
+#define FP_DENORM_ZERO		(fpcw & IEEE_MAP_DMZ)
 
-#define UDIV_NEEDS_NORMALIZATION 1  
+#define FP_HANDLE_EXCEPTIONS return _fex
 
-#define abort()			goto bad_insn
+/* We write the results always */
+#define FP_INHIBIT_RESULTS 0
 
-#ifndef __LITTLE_ENDIAN
-#define __LITTLE_ENDIAN -1
 #endif
-#define __BYTE_ORDER __LITTLE_ENDIAN
-
-/* Exception flags. */
-#define EFLAG_INVALID		IEEE_TRAP_ENABLE_INV
-#define EFLAG_OVERFLOW		IEEE_TRAP_ENABLE_OVF
-#define EFLAG_UNDERFLOW		IEEE_TRAP_ENABLE_UNF
-#define EFLAG_DIVZERO		IEEE_TRAP_ENABLE_DZE
-#define EFLAG_INEXACT		IEEE_TRAP_ENABLE_INE
-#define EFLAG_DENORM		IEEE_TRAP_ENABLE_DNO
-#define EFLAG_MASK		IEEE_TRAP_ENABLE_MASK
-
-#define _FP_DENORM_TO_ZERO	((current->tss.flags) & IEEE_MAP_DMZ)
-
-/* Comparison operations */
-#define CMPTXX_EQ		0
-#define CMPTXX_LT		-1
-#define CMPTXX_GT		1
-#define CMPTXX_LE		2
-#define CMPTXX_UN		3
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/math-emu/sfp-util.h linux.14p16/arch/alpha/math-emu/sfp-util.h
--- linux.vanilla/arch/alpha/math-emu/sfp-util.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/alpha/math-emu/sfp-util.h	Thu Dec  9 15:34:21 1999
@@ -0,0 +1,40 @@
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <asm/fpu.h>
+
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  ((sl) = (al) + (bl), (sh) = (ah) + (bh) + ((sl) < (al)))
+
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  ((sl) = (al) - (bl), (sh) = (ah) - (bh) - ((al) < (bl)))
+
+#define umul_ppmm(wh, wl, u, v)			\
+  __asm__ ("mulq %2,%3,%1; umulh %2,%3,%0"	\
+	   : "=r" ((UDItype)(wh)),		\
+	     "=&r" ((UDItype)(wl))		\
+	   : "r" ((UDItype)(u)),		\
+	     "r" ((UDItype)(v)))
+
+extern void udiv128(unsigned long, unsigned long,
+		    unsigned long, unsigned long,
+		    unsigned long *,
+		    unsigned long *);
+
+#define udiv_qrnnd(q, r, n1, n0, d)		\
+  do {						\
+    unsigned long xr, xi;			\
+    udiv128((n0), (n1), 0, (d), &xr, &xi);	\
+    (q) = xr; 					\
+    (r) = xi;					\
+  } while (0)
+
+#define UDIV_NEEDS_NORMALIZATION 1  
+
+#define abort()			goto bad_insn
+
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN -1
+#endif
+#define __BYTE_ORDER __LITTLE_ENDIAN
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/mm/fault.c linux.14p16/arch/alpha/mm/fault.c
--- linux.vanilla/arch/alpha/mm/fault.c	Sat Aug 14 02:27:13 1999
+++ linux.14p16/arch/alpha/mm/fault.c	Thu Dec  9 15:34:20 1999
@@ -120,9 +120,18 @@
 		if (!(vma->vm_flags & VM_WRITE))
 			goto bad_area;
 	}
-	handle_mm_fault(current, vma, address, cause > 0);
+survive:
+	{
+		int fault = handle_mm_fault(current, vma, address, cause > 0);
+		if (!fault)
+			goto do_sigbus;
+		if (fault < 0)
+			goto out_of_memory;
+	}
 	up(&mm->mmap_sem);
-	goto out;
+ out_unlock:
+	unlock_kernel();
+	return;
 
 /*
  * Something tried to access memory that isn't in our memory map..
@@ -133,9 +142,10 @@
 
 	if (user_mode(regs)) {
 		force_sig(SIGSEGV, current);
-		goto out;
+		goto out_unlock;
 	}
 
+no_context:
 	/* Are we prepared to handle this fault as an exception?  */
 	if ((fixup = search_exception_table(regs->pc)) != 0) {
 		unsigned long newpc;
@@ -143,7 +153,7 @@
 		printk("%s: Exception at [<%lx>] (%lx)\n",
 		       current->comm, regs->pc, newpc);
 		regs->pc = newpc;
-		goto out;
+		goto out_unlock;
 	}
 
 /*
@@ -154,7 +164,37 @@
 	       "virtual address %016lx\n", address);
 	die_if_kernel("Oops", regs, cause, (unsigned long*)regs - 16);
 	do_exit(SIGKILL);
- out:
-	unlock_kernel();
-}
 
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+out_of_memory:
+	if (current->pid == 1)
+	{
+		current->policy |= SCHED_YIELD;
+		schedule();
+		goto survive;
+	}
+	up(&mm->mmap_sem);
+	if (user_mode(regs))
+	{
+		printk("VM: killing process %s\n", current->comm);
+		do_exit(SIGKILL);
+	}
+	goto no_context;
+
+do_sigbus:
+	up(&mm->mmap_sem);
+
+	/*
+	 * Send a sigbus, regardless of whether we were in kernel
+	 * or user mode.
+	 */
+	force_sig(SIGBUS, current);
+
+	/* Kernel mode? Handle exceptions or die */
+	if (!user_mode(regs))
+		goto no_context;
+	goto out_unlock;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/mm/init.c linux.14p16/arch/alpha/mm/init.c
--- linux.vanilla/arch/alpha/mm/init.c	Sat Aug 14 02:27:13 1999
+++ linux.14p16/arch/alpha/mm/init.c	Mon Dec 13 18:45:50 1999
@@ -179,7 +179,7 @@
 {
 	register unsigned long sp __asm__("$30");
 	pcb->ksp = sp;
-	return __reload_tss(pcb);
+	return (struct thread_struct *) __reload_tss(pcb);
 }
 
 /*
@@ -211,7 +211,11 @@
 		if (cluster->usage & 3)
 			continue;
 		pfn = cluster->start_pfn;
+		if (pfn >= MAP_NR(end_mem)) /* if we overrode mem size */
+			continue;
 		nr = cluster->numpages;
+		if ((pfn + nr) > MAP_NR(end_mem)) /* if override in cluster */
+			nr = MAP_NR(end_mem) - pfn;
 
 		while (nr--)
 			clear_bit(PG_reserved, &mem_map[pfn++].flags);
@@ -221,7 +225,7 @@
 	   the last slot of the L1 page table.  */
 	memset((void *) ZERO_PAGE(0), 0, PAGE_SIZE);
 	memset(swapper_pg_dir, 0, PAGE_SIZE);
-	newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT;
+	newptbr = MAP_NR(swapper_pg_dir);
 	pgd_val(swapper_pg_dir[1023]) =
 		(newptbr << 32) | pgprot_val(PAGE_KERNEL);
 
@@ -328,8 +332,8 @@
 		kill_page(tmp);
 		free_page(tmp);
 	}
-	tmp = nr_free_pages << PAGE_SHIFT;
-	printk("Memory: %luk available\n", tmp >> 10);
+	tmp = nr_free_pages << (PAGE_SHIFT - 10);
+	printk("Memory: %luk available\n", tmp);
 	return;
 }
 
@@ -358,7 +362,7 @@
 	i = max_mapnr;
 	val->totalram = 0;
 	val->sharedram = 0;
-	val->freeram = nr_free_pages << PAGE_SHIFT;
+	val->freeram = ((unsigned long)nr_free_pages) << PAGE_SHIFT;
 	val->bufferram = buffermem;
 	while (i-- > 0)  {
 		if (PageReserved(mem_map+i))
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/boot/compressed/Makefile linux.14p16/arch/i386/boot/compressed/Makefile
--- linux.vanilla/arch/i386/boot/compressed/Makefile	Wed Oct 20 01:12:33 1999
+++ linux.14p16/arch/i386/boot/compressed/Makefile	Thu Dec  9 15:34:18 1999
@@ -37,7 +37,7 @@
 	tmppiggy=_tmp_$$$$piggy; \
 	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
 	$(OBJCOPY) $(SYSTEM) $$tmppiggy; \
-	gzip -f -3 < $$tmppiggy > $$tmppiggy.gz; \
+	gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
 	echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
 	$(LD) -m elf_i386 -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \
 	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/boot/compressed/misc.c linux.14p16/arch/i386/boot/compressed/misc.c
--- linux.vanilla/arch/i386/boot/compressed/misc.c	Wed Jun 24 22:30:08 1998
+++ linux.14p16/arch/i386/boot/compressed/misc.c	Thu Dec  9 15:34:18 1999
@@ -104,7 +104,7 @@
 #define LOW_BUFFER_START      0x2000
 #define LOW_BUFFER_END       0x90000
 #define LOW_BUFFER_SIZE      ( LOW_BUFFER_END - LOW_BUFFER_START )
-#define HEAP_SIZE             0x2000
+#define HEAP_SIZE             0x2400
 static int high_loaded =0;
 static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/config.in linux.14p16/arch/i386/config.in
--- linux.vanilla/arch/i386/config.in	Sat Aug 14 02:27:13 1999
+++ linux.14p16/arch/i386/config.in	Fri Dec 17 18:58:45 1999
@@ -126,6 +126,8 @@
   source net/Config.in
 fi
 
+source drivers/telephony/Config.in
+
 mainmenu_option next_comment
 comment 'SCSI support'
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/apm.c linux.14p16/arch/i386/kernel/apm.c
--- linux.vanilla/arch/i386/kernel/apm.c	Wed Oct 20 01:12:33 1999
+++ linux.14p16/arch/i386/kernel/apm.c	Thu Dec  9 15:34:20 1999
@@ -1,8 +1,8 @@
 /* -*- linux-c -*-
  * APM BIOS driver for Linux
- * Copyright 1994-1998 Stephen Rothwell
- *                     (Stephen.Rothwell@canb.auug.org.au)
- * Development of this driver was funded by NEC Australia P/L
+ * Copyright 1994-1999 Stephen Rothwell (sfr@linuxcare.com)
+ *
+ * Initial development of this driver was funded by NEC Australia P/L
  *	and NEC Corporation
  *
  * This program is free software; you can redistribute it and/or modify it
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/bios32.c linux.14p16/arch/i386/kernel/bios32.c
--- linux.vanilla/arch/i386/kernel/bios32.c	Sat Aug 14 02:25:55 1999
+++ linux.14p16/arch/i386/kernel/bios32.c	Thu Dec  9 15:34:19 1999
@@ -1095,7 +1095,7 @@
  * for buggy PCI BIOS'es :-[).
  */
 
-extern int skip_ioapic_setup;
+extern int skip_ioapic_setup;	/* defined in arch/i386/kernel/smp.c */
 
 static void __init pcibios_fixup_devices(void)
 {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/io_apic.c linux.14p16/arch/i386/kernel/io_apic.c
--- linux.vanilla/arch/i386/kernel/io_apic.c	Wed Oct 20 01:12:33 1999
+++ linux.14p16/arch/i386/kernel/io_apic.c	Thu Dec  9 15:34:20 1999
@@ -19,7 +19,7 @@
  * volatile is justified in this case, IO-APIC register contents
  * might change spontaneously, GCC should not cache it
  */
-#define IO_APIC_BASE ((volatile int *)fix_to_virt(FIX_IO_APIC_BASE))
+#define IO_APIC_BASE(idx) ((volatile int *)__fix_to_virt(FIX_IO_APIC_BASE_0 + idx))
 
 /*
  * The structure of the IO-APIC:
@@ -47,7 +47,7 @@
 /*
  * # of IRQ routing registers
  */
-int nr_ioapic_registers = 0;
+int nr_ioapic_registers[MAX_IO_APICS];
 
 enum ioapic_irq_destination_types {
 	dest_Fixed = 0,
@@ -94,6 +94,8 @@
 	mp_ExtINT = 3
 };
 
+int mp_apic_entries = 0;			/* # of I/O APIC entries */
+struct mpc_config_ioapic mp_apics[MAX_IO_APICS];/* I/O APIC entries */
 int mp_irq_entries = 0;				/* # of MP IRQ source entries */
 struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
 						/* MP IRQ source entries */
@@ -108,34 +110,34 @@
  * between pins and IRQs.
  */
 
-static inline unsigned int io_apic_read(unsigned int reg)
+static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
 {
-	*IO_APIC_BASE = reg;
-	return *(IO_APIC_BASE+4);
+	*IO_APIC_BASE(apic) = reg;
+	return *(IO_APIC_BASE(apic)+4);
 }
 
-static inline void io_apic_write(unsigned int reg, unsigned int value)
+static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
 {
-	*IO_APIC_BASE = reg;
-	*(IO_APIC_BASE+4) = value;
+	*IO_APIC_BASE(apic) = reg;
+	*(IO_APIC_BASE(apic)+4) = value;
 }
 
 /*
  * Re-write a value: to be used for read-modify-write
  * cycles where the read already set up the index register.
  */
-static inline void io_apic_modify(unsigned int value)
+static inline void io_apic_modify(unsigned int apic, unsigned int value)
 {
-	*(IO_APIC_BASE+4) = value;
+	*(IO_APIC_BASE(apic)+4) = value;
 }
 
 /*
  * Synchronize the IO-APIC and the CPU by doing
  * a dummy read from the IO-APIC
  */
-static inline void io_apic_sync(void)
+static inline void io_apic_sync(unsigned int apic)
 {
-	(void) *(IO_APIC_BASE+4);
+	(void) *(IO_APIC_BASE(apic)+4);
 }
 
 /*
@@ -146,7 +148,7 @@
 #define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
 
 static struct irq_pin_list {
-	int pin, next;
+	int apic, pin, next;
 } irq_2_pin[PIN_MAP_SIZE];
 
 /*
@@ -154,7 +156,7 @@
  * shared ISA-space IRQs, so we have to support them. We are super
  * fast in the common case, and fast for shared ISA-space IRQs.
  */
-static void add_pin_to_irq(unsigned int irq, int pin)
+static void add_pin_to_irq(unsigned int irq, int apic, int pin)
 {
 	static int first_free_entry = NR_IRQS;
 	struct irq_pin_list *entry = irq_2_pin + irq;
@@ -168,6 +170,7 @@
 		if (++first_free_entry >= PIN_MAP_SIZE)
 			panic("io_apic.c: whoops");
 	}
+	entry->apic = apic;
 	entry->pin = pin;
 }
 
@@ -183,9 +186,9 @@
 		pin = entry->pin;					\
 		if (pin == -1)						\
 			break;						\
-		reg = io_apic_read(0x10 + R + pin*2);			\
+		reg = io_apic_read(entry->apic, 0x10 + R + pin*2);	\
 		reg ACTION;						\
-		io_apic_modify(reg);					\
+		io_apic_modify(entry->apic, reg);			\
 		if (!entry->next)					\
 			break;						\
 		entry = irq_2_pin + entry->next;			\
@@ -197,12 +200,12 @@
  * We disable IO-APIC IRQs by setting their 'destination CPU mask' to
  * zero. Trick by Ramesh Nalluri.
  */
-DO_ACTION( disable, 1, &= 0x00ffffff, io_apic_sync())		/* destination = 0x00 */
+DO_ACTION( disable, 1, &= 0x00ffffff, io_apic_sync(entry->apic))/* destination = 0x00 */
 DO_ACTION( enable,  1, |= 0xff000000, )				/* destination = 0xff */
-DO_ACTION( mask,    0, |= 0x00010000, io_apic_sync())		/* mask = 1 */
+DO_ACTION( mask,    0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */
 DO_ACTION( unmask,  0, &= 0xfffeffff, )				/* mask = 0 */
 
-static void clear_IO_APIC_pin(unsigned int pin)
+static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
 {
 	struct IO_APIC_route_entry entry;
 
@@ -211,16 +214,17 @@
 	 */
 	memset(&entry, 0, sizeof(entry));
 	entry.mask = 1;
-	io_apic_write(0x10 + 2 * pin, *(((int *)&entry) + 0));
-	io_apic_write(0x11 + 2 * pin, *(((int *)&entry) + 1));
+	io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
+	io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
 }
 
 static void clear_IO_APIC (void)
 {
-	int pin;
+	int apic, pin;
 
-	for (pin = 0; pin < nr_ioapic_registers; pin++)
-		clear_IO_APIC_pin(pin);
+	for (apic = 0; apic < mp_apic_entries; apic++)
+		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
+			clear_IO_APIC_pin(apic, pin);
 }
 
 /*
@@ -270,12 +274,13 @@
 /*
  * Find the IRQ entry number of a certain pin.
  */
-static int __init find_irq_entry(int pin, int type)
+static int __init find_irq_entry(int apic, int pin, int type)
 {
 	int i;
 
 	for (i = 0; i < mp_irq_entries; i++)
 		if ( (mp_irqs[i].mpc_irqtype == type) &&
+			(mp_irqs[i].mpc_dstapic == mp_apics[apic].mpc_apicid) &&
 			(mp_irqs[i].mpc_dstirq == pin))
 
 			return i;
@@ -307,21 +312,26 @@
  * Find a specific PCI IRQ entry.
  * Not an initfunc, possibly needed by modules
  */
+static int __init pin_2_irq(int idx, int apic, int pin);
 int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pci_pin)
 {
-	int i;
+	int apic, i;
 
 	for (i = 0; i < mp_irq_entries; i++) {
 		int lbus = mp_irqs[i].mpc_srcbus;
 
-		if (IO_APIC_IRQ(mp_irqs[i].mpc_dstirq) &&
+		for (apic = 0; apic < mp_apic_entries; apic++)
+			if (mp_apics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic)
+				break;
+
+		if ((apic || IO_APIC_IRQ(mp_irqs[i].mpc_dstirq)) &&
 		    (mp_bus_id_to_type[lbus] == MP_BUS_PCI) &&
 		    !mp_irqs[i].mpc_irqtype &&
 		    (bus == mp_bus_id_to_pci_bus[mp_irqs[i].mpc_srcbus]) &&
 		    (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f)) &&
 		    (pci_pin == (mp_irqs[i].mpc_srcbusirq & 3)))
 
-			return mp_irqs[i].mpc_dstirq;
+			return pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq);
 	}
 	return -1;
 }
@@ -491,9 +501,9 @@
 	return MPBIOS_trigger(idx);
 }
 
-static int __init pin_2_irq(int idx, int pin)
+static int __init pin_2_irq(int idx, int apic, int pin)
 {
-	int irq;
+	int irq, i;
 	int bus = mp_irqs[idx].mpc_srcbus;
 
 	/*
@@ -513,9 +523,12 @@
 		case MP_BUS_PCI: /* PCI pin */
 		{
 			/*
-			 * PCI IRQs are 'directly mapped'
+			 * PCI IRQs are mapped in order
 			 */
-			irq = pin;
+			i = irq = 0;
+			while (i < apic)
+				irq += nr_ioapic_registers[i++];
+			irq += pin;
 			break;
 		}
 		default:
@@ -545,12 +558,14 @@
 
 static inline int IO_APIC_irq_trigger(int irq)
 {
-	int idx, pin;
+	int apic, idx, pin;
 
-	for (pin = 0; pin < nr_ioapic_registers; pin++) {
-		idx = find_irq_entry(pin,mp_INT);
-		if ((idx != -1) && (irq == pin_2_irq(idx,pin)))
-			return irq_trigger(idx);
+	for (apic = 0; apic < mp_apic_entries; apic++) {
+		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+			idx = find_irq_entry(apic,pin,mp_INT);
+			if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin)))
+				return irq_trigger(idx);
+		}
 	}
 	/*
 	 * nonexistent IRQs are edge default
@@ -582,11 +597,12 @@
 void __init setup_IO_APIC_irqs(void)
 {
 	struct IO_APIC_route_entry entry;
-	int pin, idx, bus, irq, first_notcon = 1;
+	int apic, pin, idx, irq, first_notcon = 1;
 
 	printk("init IO_APIC IRQs\n");
 
-	for (pin = 0; pin < nr_ioapic_registers; pin++) {
+	for (apic = 0; apic < mp_apic_entries; apic++) {
+	for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
 
 		/*
 		 * add it to the IO-APIC irq-routing table:
@@ -598,13 +614,13 @@
 		entry.mask = 0;				/* enable IRQ */
 		entry.dest.logical.logical_dest = 0;	/* but no route */
 
-		idx = find_irq_entry(pin,mp_INT);
+		idx = find_irq_entry(apic,pin,mp_INT);
 		if (idx == -1) {
 			if (first_notcon) {
-				printk(" IO-APIC pin %d", pin);
+				printk(" IO-APIC (apicid-pin) %d-%d", mp_apics[apic].mpc_apicid, pin);
 				first_notcon = 0;
 			} else
-				printk(", %d", pin);
+				printk(", %d-%d", mp_apics[apic].mpc_apicid, pin);
 			continue;
 		}
 
@@ -617,18 +633,17 @@
 			entry.dest.logical.logical_dest = 0xff;
 		}
 
-		irq = pin_2_irq(idx,pin);
-		add_pin_to_irq(irq, pin);
+		irq = pin_2_irq(idx,apic,pin);
+		add_pin_to_irq(irq, apic, pin);
 
-		if (!IO_APIC_IRQ(irq))
+		if (!apic && !IO_APIC_IRQ(irq))
 			continue;
 
 		entry.vector = assign_irq_vector(irq);
 
-		bus = mp_irqs[idx].mpc_srcbus;
-
-		io_apic_write(0x11+2*pin, *(((int *)&entry)+1));
-		io_apic_write(0x10+2*pin, *(((int *)&entry)+0));
+		io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
+		io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
+	}
 	}
 
 	if (!first_notcon)
@@ -638,7 +653,7 @@
 /*
  * Set up a certain pin as ExtINT delivered interrupt
  */
-void __init setup_ExtINT_pin(unsigned int pin, int irq)
+void __init setup_ExtINT_pin(unsigned int apic, unsigned int pin, int irq)
 {
 	struct IO_APIC_route_entry entry;
 
@@ -662,8 +677,8 @@
 	entry.polarity = 0;
 	entry.trigger = 0;
 
-	io_apic_write(0x10+2*pin, *(((int *)&entry)+0));
-	io_apic_write(0x11+2*pin, *(((int *)&entry)+1));
+	io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
+	io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
 }
 
 void __init UNEXPECTED_IO_APIC(void)
@@ -674,17 +689,14 @@
 
 void __init print_IO_APIC(void)
 {
-	int i;
+	int apic, i;
 	struct IO_APIC_reg_00 reg_00;
 	struct IO_APIC_reg_01 reg_01;
 	struct IO_APIC_reg_02 reg_02;
 
  	printk("number of MP IRQ sources: %d.\n", mp_irq_entries);
- 	printk("number of IO-APIC registers: %d.\n", nr_ioapic_registers);
-
-	*(int *)&reg_00 = io_apic_read(0);
-	*(int *)&reg_01 = io_apic_read(1);
-	*(int *)&reg_02 = io_apic_read(2);
+	for (i = 0; i < mp_apic_entries; i++)
+		printk("number of IO-APIC #%d registers: %d.\n", mp_apics[i].mpc_apicid, nr_ioapic_registers[i]);
 
 	/*
 	 * We are a bit conservative about what we expect.  We have to
@@ -692,6 +704,12 @@
 	 */
 	printk("testing the IO APIC.......................\n");
 
+	for (apic = 0; apic < mp_apic_entries; apic++) {
+
+	*(int *)&reg_00 = io_apic_read(apic, 0);
+	*(int *)&reg_01 = io_apic_read(apic, 1);
+	*(int *)&reg_02 = io_apic_read(apic, 2);
+	printk("\nIO APIC #%d......\n", mp_apics[apic].mpc_apicid);
 	printk(".... register #00: %08X\n", *(int *)&reg_00);
 	printk(".......    : physical APIC id: %02X\n", reg_00.ID);
 	if (reg_00.__reserved_1 || reg_00.__reserved_2)
@@ -731,8 +749,8 @@
 	for (i = 0; i <= reg_01.entries; i++) {
 		struct IO_APIC_route_entry entry;
 
-		*(((int *)&entry)+0) = io_apic_read(0x10+i*2);
-		*(((int *)&entry)+1) = io_apic_read(0x11+i*2);
+		*(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2);
+		*(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2);
 
 		printk(" %02x %03X %02X  ",
 			i,
@@ -751,7 +769,7 @@
 			entry.vector
 		);
 	}
-
+	}
 	printk(KERN_DEBUG "IRQ to pin mappings:\n");
 	for (i = 0; i < NR_IRQS; i++) {
 		struct irq_pin_list *entry = irq_2_pin + i;
@@ -796,9 +814,12 @@
 	 */
 	{
 		struct IO_APIC_reg_01 reg_01;
+		int i;
 
-		*(int *)&reg_01 = io_apic_read(1);
-		nr_ioapic_registers = reg_01.entries+1;
+		for (i = 0; i < mp_apic_entries; i++) {
+			*(int *)&reg_01 = io_apic_read(i, 1);
+			nr_ioapic_registers[i] = reg_01.entries+1;
+		}
 	}
 
 	/*
@@ -897,15 +918,15 @@
 	/*
 	 * Set the ID
 	 */
-	*(int *)&reg_00 = io_apic_read(0);
+	*(int *)&reg_00 = io_apic_read(0, 0);
 	printk("...changing IO-APIC physical APIC ID to 2...\n");
 	reg_00.ID = 0x2;
-	io_apic_write(0, *(int *)&reg_00);
+	io_apic_write(0, 0, *(int *)&reg_00);
 
 	/*
 	 * Sanity check
 	 */
-	*(int *)&reg_00 = io_apic_read(0);
+	*(int *)&reg_00 = io_apic_read(0, 0);
 	if (reg_00.ID != 0x2)
 		panic("could not set ID");
 }
@@ -1227,7 +1248,10 @@
 
 		if (pin2 != -1) {
 			printk(".. (found pin %d) ...", pin2);
-			setup_ExtINT_pin(pin2, 0);
+			/*
+			 * legacy devices should be connected to IO APIC #0
+			 */
+			setup_ExtINT_pin(0, pin2, 0);
 			make_8259A_irq(0);
 		}
 
@@ -1238,9 +1262,9 @@
 			 * Just in case ...
 			 */
 			if (pin1 != -1)
-				clear_IO_APIC_pin(pin1);
+				clear_IO_APIC_pin(0, pin1);
 			if (pin2 != -1)
-				clear_IO_APIC_pin(pin2);
+				clear_IO_APIC_pin(0, pin2);
 
 			make_8259A_irq(0);
 
@@ -1282,7 +1306,8 @@
 	 * - those for which the user has specified a pirq= parameter
 	 */
 	if (	ioapic_whitelisted() ||
-		(nr_ioapic_registers == 16) ||
+		(mp_apic_entries == 1 && nr_ioapic_registers[0] == 16) ||
+		(mp_apic_entries > 1) ||
 		pirqs_enabled)
 	{
 		printk("ENABLING IO-APIC IRQs\n");
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/irq.h linux.14p16/arch/i386/kernel/irq.h
--- linux.vanilla/arch/i386/kernel/irq.h	Sat Aug 14 02:27:13 1999
+++ linux.14p16/arch/i386/kernel/irq.h	Mon Dec 13 19:41:55 1999
@@ -112,6 +112,11 @@
 
 extern char _stext, _etext;
 
+/*
+ * IF YOU CHANGE THIS, PLEASE ALSO CHANGE
+ * FIX_IO_APIC_BASE_* in fixmap.h
+ */
+#define MAX_IO_APICS 4
 #define MAX_IRQ_SOURCES 128
 #define MAX_MP_BUSSES 32
 enum mp_bustype {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/ptrace.c linux.14p16/arch/i386/kernel/ptrace.c
--- linux.vanilla/arch/i386/kernel/ptrace.c	Wed Mar 24 21:18:46 1999
+++ linux.14p16/arch/i386/kernel/ptrace.c	Thu Dec  9 15:34:19 1999
@@ -80,12 +80,17 @@
 	pmd_t * pgmiddle;
 	pte_t * pgtable;
 	unsigned long page;
+	int fault;
 
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (pgd_none(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 0);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return 0;
 	}
 	if (pgd_bad(*pgdir)) {
 		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
@@ -94,8 +99,12 @@
 	}
 	pgmiddle = pmd_offset(pgdir, addr);
 	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 0);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return 0;
 	}
 	if (pmd_bad(*pgmiddle)) {
 		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
@@ -104,8 +113,12 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 0);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return 0;
 	}
 	page = pte_page(*pgtable);
 /* this is a hack for non-kernel-mapped video buffers and similar */
@@ -131,12 +144,17 @@
 	pmd_t *pgmiddle;
 	pte_t *pgtable;
 	unsigned long page;
+	int fault;
 
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (!pgd_present(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 1);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return;
 	}
 	if (pgd_bad(*pgdir)) {
 		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
@@ -145,8 +163,12 @@
 	}
 	pgmiddle = pmd_offset(pgdir, addr);
 	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 1);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return;
 	}
 	if (pmd_bad(*pgmiddle)) {
 		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
@@ -155,13 +177,21 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 1);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return;
 	}
 	page = pte_page(*pgtable);
 	if (!pte_write(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 1);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return;
 	}
 /* this is a hack for non-kernel-mapped video buffers and similar */
 	if (MAP_NR(page) < max_mapnr)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/setup.c linux.14p16/arch/i386/kernel/setup.c
--- linux.vanilla/arch/i386/kernel/setup.c	Wed Oct 20 01:12:33 1999
+++ linux.14p16/arch/i386/kernel/setup.c	Thu Dec  9 15:34:19 1999
@@ -17,6 +17,12 @@
  *
  *  IDT Winchip tweaks, misc clean ups.
  *	Dave Jones <dave@powertweak.com>, August 1999
+ *
+ *	Added proper L2 cache detection for Coppermine
+ *	Dragan Stancevic <visitor@valinux.com>, October 1999
+ *
+ *	Improved Intel cache detection.
+ *	Dave Jones <dave@powertweak.com>, October 1999
  */
 
 /*
@@ -366,7 +372,7 @@
 			/* Zero is valid according to the BIOS weenies */
 			if(i386_endbase)
 			{
-				printk(KERN_NOTICE "Ignoring bogus EBDA pointer %X\n", 
+				printk(KERN_NOTICE "Ignoring bogus EBDA pointer %lX\n", 
 					i386_endbase);
 			}
 			i386_endbase = BIOS_ENDBASE;
@@ -755,8 +761,8 @@
 	{ X86_VENDOR_INTEL,	6,
 	  { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", 
 	    NULL, "Pentium II (Deschutes)", "Mobile Pentium II", 
-            "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL, NULL, 
-            NULL, NULL, NULL, NULL }},
+	    "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL, NULL, 
+	    NULL, NULL, NULL, NULL, NULL }},
 	{ X86_VENDOR_AMD,	4,
 	  { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB",
 	    "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT",
@@ -818,49 +824,48 @@
 		}
 	}
 
-	for (i = 0; i < sizeof(cpu_models)/sizeof(struct cpu_model_info); i++) {
-		if (c->cpuid_level > 1) {
-			/* supports eax=2  call */
-			int edx, cache_size, dummy;
+	if (c->cpuid_level > 1) {
+		/* supports eax=2  call */
+		int edx, dummy;
 			
-			cpuid(2, &dummy, &dummy, &dummy, &edx);
+		cpuid(2, &dummy, &dummy, &dummy, &edx);
 
-			/* We need only the LSB */
-			edx &= 0xff;
+		/* We need only the LSB */
+		edx &= 0xff;
 
-			switch (edx) {
-				case 0x40:
-					cache_size = 0;
-					break;
-
-				case 0x41:
-					cache_size = 128;
-					break;
-
-				case 0x42:
-					cache_size = 256;
-					break;
-
-				case 0x43:
-					cache_size = 512;
-					break;
-
-				case 0x44:
-					cache_size = 1024;
-					break;
-
-				case 0x45:
-					cache_size = 2048;
-					break;
-
-				default:
-					cache_size = 0;
-					break;
-			}
+		switch (edx) {
+			case 0x40:
+				c->x86_cache_size = 0;
+				break;
 
-			c->x86_cache_size = cache_size; 
+			case 0x41:
+				c->x86_cache_size = 128;
+				break;
+
+			case 0x42:
+			case 0x82: /*Detect 256-Kbyte cache on Coppermine*/ 
+				c->x86_cache_size = 256;
+				break;
+
+			case 0x43:
+				c->x86_cache_size = 512;
+				break;
+
+			case 0x44:
+				c->x86_cache_size = 1024;
+				break;
+
+			case 0x45:
+				c->x86_cache_size = 2048;
+				break;
+
+			default:
+				c->x86_cache_size = 0;
+				break;
 		}
+	}
 
+	for (i = 0; i < sizeof(cpu_models)/sizeof(struct cpu_model_info); i++) {
 		if (cpu_models[i].vendor == c->x86_vendor &&
 		    cpu_models[i].x86 == c->x86) {
 			if (c->x86_model <= 16)
@@ -1019,8 +1024,9 @@
 			x86_cap_flags[14] = "mca";
 			x86_cap_flags[16] = "pat";
 			x86_cap_flags[17] = "pse36";
-			x86_cap_flags[18] = "psn";
-			x86_cap_flags[24] = "osfxsr";
+			x86_cap_flags[18] = "pn";
+			x86_cap_flags[24] = "fxsr";
+			x86_cap_flags[25] = "xmm";
 			break;
 
 		    case X86_VENDOR_CENTAUR:
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/signal.c linux.14p16/arch/i386/kernel/signal.c
--- linux.vanilla/arch/i386/kernel/signal.c	Sat Aug 14 02:26:46 1999
+++ linux.14p16/arch/i386/kernel/signal.c	Thu Dec  9 15:34:19 1999
@@ -419,13 +419,19 @@
 		           ? current->exec_domain->signal_invmap[sig]
 		           : sig),
 		          &frame->sig);
+	if (err)
+		goto give_sigsegv;
 
 	err |= setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]);
+	if (err)
+		goto give_sigsegv;
 
 	if (_NSIG_WORDS > 1) {
 		err |= __copy_to_user(frame->extramask, &set->sig[1],
 				      sizeof(frame->extramask));
 	}
+	if (err)
+		goto give_sigsegv;
 
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
@@ -486,6 +492,8 @@
 	err |= __put_user(&frame->info, &frame->pinfo);
 	err |= __put_user(&frame->uc, &frame->puc);
 	err |= __copy_to_user(&frame->info, info, sizeof(*info));
+	if (err)
+		goto give_sigsegv;
 
 	/* Create the ucontext.  */
 	err |= __put_user(0, &frame->uc.uc_flags);
@@ -497,6 +505,8 @@
 	err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
 			        regs, set->sig[0]);
 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+	if (err)
+		goto give_sigsegv;
 
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/smp.c linux.14p16/arch/i386/kernel/smp.c
--- linux.vanilla/arch/i386/kernel/smp.c	Wed Oct 20 01:12:33 1999
+++ linux.14p16/arch/i386/kernel/smp.c	Mon Dec 13 18:27:44 1999
@@ -114,7 +114,6 @@
 volatile unsigned long kstack_ptr;			/* Stack vector for booting CPUs			*/
 struct cpuinfo_x86 cpu_data[NR_CPUS];			/* Per CPU bogomips and other parameters 		*/
 static unsigned int num_processors = 1;			/* Internal processor count				*/
-unsigned long mp_ioapic_addr = 0xFEC00000;		/* Address of the I/O apic (not yet used) 		*/
 unsigned char boot_cpu_id = 0;				/* Processor that is doing the boot up 			*/
 static int smp_activated = 0;				/* Tripped once we need to start cross invalidating 	*/
 int apic_version[NR_CPUS];				/* APIC version number					*/
@@ -128,6 +127,8 @@
 const char lk_lockmsg[] = "lock from interrupt context at %p\n"; 
 
 int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, };
+extern int mp_apic_entries;
+extern struct mpc_config_ioapic mp_apics [MAX_IO_APICS];
 extern int mp_irq_entries;
 extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
 extern int mpc_default_type;
@@ -367,11 +368,9 @@
 					printk("I/O APIC #%d Version %d at 0x%lX.\n",
 						m->mpc_apicid,m->mpc_apicver,
 						m->mpc_apicaddr);
-					/*
-					 * we use the first one only currently
-					 */
-					if (ioapics == 1)
-						mp_ioapic_addr = m->mpc_apicaddr;
+					mp_apics [mp_apic_entries] = *m;
+					if (++mp_apic_entries > MAX_IO_APICS)
+						--mp_apic_entries;
 				}
 				mpt+=sizeof(*m);
 				count+=sizeof(*m);
@@ -403,9 +402,9 @@
 			}
 		}
 	}
-	if (ioapics > 1)
+	if (ioapics > MAX_IO_APICS)
 	{
-		printk("Warning: Multiple IO-APICs not yet supported.\n");
+		printk("Warning: Max I/O APICs exceeded (max %d, found %d).\n", MAX_IO_APICS, ioapics);
 		printk("Warning: switching to non APIC mode.\n");
 		skip_ioapic_setup=1;
 	}
@@ -493,6 +492,8 @@
 					cpu_present_map=3;
 					num_processors=2;
 					printk("I/O APIC at 0xFEC00000.\n");
+					mp_apics[0].mpc_apicaddr = 0xFEC00000;
+					mp_apic_entries = 1;
 
 					/*
 					 * Save the default type number, we
@@ -772,18 +773,22 @@
 
 #ifdef CONFIG_X86_IO_APIC
 	{
-		unsigned long ioapic_phys;
+		unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
+		int i;
 
-		if (smp_found_config) {
-			ioapic_phys = mp_ioapic_addr;
-		} else {
-			ioapic_phys = __pa(memory_start);
-			memset((void *)memory_start, 0, PAGE_SIZE);
-			memory_start += PAGE_SIZE;
+		for (i = 0; i < mp_apic_entries; i++) {
+			if (smp_found_config) {
+				ioapic_phys = mp_apics[i].mpc_apicaddr;
+			} else {
+				ioapic_phys = __pa(memory_start);
+				memset((void *)memory_start, 0, PAGE_SIZE);
+				memory_start += PAGE_SIZE;
+			}
+			set_fixmap(idx,ioapic_phys);
+			printk("mapped IOAPIC to %08lx (%08lx)\n",
+					__fix_to_virt(idx), ioapic_phys);
+			idx++;
 		}
-		set_fixmap(FIX_IO_APIC_BASE,ioapic_phys);
-		printk("mapped IOAPIC to %08lx (%08lx)\n",
-				fix_to_virt(FIX_IO_APIC_BASE), ioapic_phys);
 	}
 #endif
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/math-emu/README linux.14p16/arch/i386/math-emu/README
--- linux.vanilla/arch/i386/math-emu/README	Wed Jun 24 22:30:08 1998
+++ linux.14p16/arch/i386/math-emu/README	Thu Dec  9 15:34:19 1999
@@ -1,9 +1,9 @@
  +---------------------------------------------------------------------------+
  |  wm-FPU-emu   an FPU emulator for 80386 and 80486SX microprocessors.      |
  |                                                                           |
- | Copyright (C) 1992,1993,1994,1995,1996,1997                               |
+ | Copyright (C) 1992,1993,1994,1995,1996,1997,1999                          |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail billm@suburbia.net               |
+ |                       Australia.  E-mail billm@melbpc.org.au              |
  |                                                                           |
  |    This program is free software; you can redistribute it and/or modify   |
  |    it under the terms of the GNU General Public License version 2 as      |
@@ -42,14 +42,15 @@
 some differences.
 
 Please report bugs, etc to me at:
-       billm@suburbia.net
+       billm@melbpc.org.au
+or     b.metzenthen@medoto.unimelb.edu.au
 
 For more information on the emulator and on floating point topics, see
 my web pages, currently at  http://www.suburbia.net/~billm/
 
 
 --Bill Metzenthen
-  December 1997
+  December 1999
 
 
 ----------------------- Internals of wm-FPU-emu -----------------------
@@ -98,7 +99,7 @@
 ----------------------- Limitations of wm-FPU-emu -----------------------
 
 There are a number of differences between the current wm-FPU-emu
-(version 2.00) and the 80486 FPU (apart from bugs).  The differences
+(version 2.01) and the 80486 FPU (apart from bugs).  The differences
 are fewer than those which applied to the 1.xx series of the emulator.
 Some of the more important differences are listed below:
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/math-emu/fpu_trig.c linux.14p16/arch/i386/math-emu/fpu_trig.c
--- linux.vanilla/arch/i386/math-emu/fpu_trig.c	Wed Dec 10 01:57:09 1997
+++ linux.14p16/arch/i386/math-emu/fpu_trig.c	Thu Dec  9 15:34:19 1999
@@ -3,9 +3,9 @@
  |                                                                           |
  | Implementation of the FPU "transcendental" functions.                     |
  |                                                                           |
- | Copyright (C) 1992,1993,1994,1997                                         |
+ | Copyright (C) 1992,1993,1994,1997,1999                                    |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@suburbia.net             |
+ |                       Australia.  E-mail   billm@melbpc.org.au            |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -85,7 +85,8 @@
 	  FPU_normalize(&tmp);
 	  tmptag =
 	    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION, SIGN_POS,
-		      exponent16(&CONST_PI2extra) + exponent16(&tmp));
+		      exponent(&CONST_PI2extra) + exponent(&tmp));
+	  setsign(&tmp, getsign(&CONST_PI2extra));
 	  st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION);
 	  if ( signnegative(st0_ptr) )
 	    {
@@ -117,7 +118,8 @@
 	  FPU_normalize(&tmp);         /* This must return TAG_Valid */
 	  tmptag = FPU_u_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION,
 			     SIGN_POS,
-			     exponent16(&CONST_PI2extra) + exponent16(&tmp));
+			     exponent(&CONST_PI2extra) + exponent(&tmp));
+	  setsign(&tmp, getsign(&CONST_PI2extra));
 	  st0_tag = FPU_sub(LOADED|(tmptag & 0x0f), (int)&tmp,
 			    FULL_PRECISION);
 	  if ( (exponent(st0_ptr) == exponent(&CONST_PI2)) &&
@@ -827,18 +829,29 @@
 		       unsigned long long st1,
 		       unsigned long long q, int n)
 {
+  int dummy;
   unsigned long long x;
 
   x = st0 << n;
 
   /* Do the required multiplication and subtraction in the one operation */
-  asm volatile ("movl %2,%%eax; mull %4; subl %%eax,%0; sbbl %%edx,%1;
-                 movl %3,%%eax; mull %4; subl %%eax,%1;
-                 movl %2,%%eax; mull %5; subl %%eax,%1;"
-		:"=m" (x), "=m" (((unsigned *)&x)[1])
-		:"m" (st1),"m" (((unsigned *)&st1)[1]),
-		 "m" (q),"m" (((unsigned *)&q)[1])
-		:"%ax","%dx");
+
+  /* lsw x -= lsw st1 * lsw q */
+  asm volatile ("mull %4; subl %%eax,%0; sbbl %%edx,%1"
+		:"=m" (((unsigned *)&x)[0]), "=m" (((unsigned *)&x)[1]),
+		"=a" (dummy)
+		:"2" (((unsigned *)&st1)[0]), "m" (((unsigned *)&q)[0])
+		:"%dx");
+  /* msw x -= msw st1 * lsw q */
+  asm volatile ("mull %3; subl %%eax,%0"
+		:"=m" (((unsigned *)&x)[1]), "=a" (dummy)
+		:"1" (((unsigned *)&st1)[1]), "m" (((unsigned *)&q)[0])
+		:"%dx");
+  /* msw x -= lsw st1 * msw q */
+  asm volatile ("mull %3; subl %%eax,%0"
+		:"=m" (((unsigned *)&x)[1]), "=a" (dummy)
+		:"1" (((unsigned *)&st1)[0]), "m" (((unsigned *)&q)[1])
+		:"%dx");
 
   *y = x;
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/math-emu/poly.h linux.14p16/arch/i386/math-emu/poly.h
--- linux.vanilla/arch/i386/math-emu/poly.h	Tue Apr  7 15:48:54 1998
+++ linux.14p16/arch/i386/math-emu/poly.h	Thu Dec  9 15:34:19 1999
@@ -3,9 +3,9 @@
  |                                                                           |
  |  Header file for the FPU-emu poly*.c source files.                        |
  |                                                                           |
- | Copyright (C) 1994                                                        |
+ | Copyright (C) 1994,1999                                                   |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ |                       Australia.  E-mail   billm@melbpc.org.au            |
  |                                                                           |
  | Declarations and definitions for functions operating on Xsig (12-byte     |
  | extended-significand) quantities.                                         |
@@ -55,15 +55,20 @@
    actually be in-line.
    */
 
-/* Multiply two fixed-point 32 bit numbers. */
-extern inline void mul_32_32(const unsigned long arg1,
-			     const unsigned long arg2,
-			     unsigned long *out)
+/* Multiply two fixed-point 32 bit numbers, producing a 32 bit result.
+   The answer is the ms word of the product. */
+/* Some versions of gcc make it difficult to stop eax from being clobbered.
+   Merely specifying that it is used doesn't work...
+ */
+extern inline unsigned long mul_32_32(const unsigned long arg1,
+				      const unsigned long arg2)
 {
-  asm volatile ("movl %1,%%eax; mull %2; movl %%edx,%0" \
-		:"=g" (*out) \
-		:"g" (arg1), "g" (arg2) \
-		:"ax","dx");
+  int retval;
+  asm volatile ("mull %2; movl %%edx,%%eax" \
+		:"=a" (retval) \
+		:"0" (arg1), "g" (arg2) \
+		:"dx");
+  return retval;
 }
 
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/math-emu/poly_sin.c linux.14p16/arch/i386/math-emu/poly_sin.c
--- linux.vanilla/arch/i386/math-emu/poly_sin.c	Wed Dec 10 01:57:09 1997
+++ linux.14p16/arch/i386/math-emu/poly_sin.c	Thu Dec  9 15:34:19 1999
@@ -4,9 +4,9 @@
  |  Computation of an approximation of the sin function and the cosine       |
  |  function by a polynomial.                                                |
  |                                                                           |
- | Copyright (C) 1992,1993,1994,1997                                         |
+ | Copyright (C) 1992,1993,1994,1997,1999                                    |
  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
- |                  E-mail   billm@suburbia.net                              |
+ |                  E-mail   billm@melbpc.org.au                             |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -132,6 +132,9 @@
 	}
       /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
       fixed_arg = 0x921fb54442d18469LL - fixed_arg;
+      /* There is a special case which arises due to rounding, to fix here. */
+      if ( fixed_arg == 0xffffffffffffffffLL )
+	fixed_arg = 0;
 
       XSIG_LL(argSqrd) = fixed_arg; argSqrd.lsw = 0;
       mul64_Xsig(&argSqrd, &fixed_arg);
@@ -172,10 +175,9 @@
       if ( argSqrd.msw & 0xffc00000 )
 	{
 	  /* Get about 32 bit precision in these: */
-	  mul_32_32(0x898cc517, argSqrd.msw, &adj);
-	  fix_up -= adj/6;
+	  fix_up -= mul_32_32(0x898cc517, argSqrd.msw) / 6;
 	}
-      mul_32_32(fix_up, LL_MSW(fixed_arg), &fix_up);
+      fix_up = mul_32_32(fix_up, LL_MSW(fixed_arg));
 
       adj = accumulator.lsw;    /* temp save */
       accumulator.lsw -= fix_up;
@@ -211,7 +213,6 @@
   FPU_REG	      result;
   long int            exponent, exp2, echange;
   Xsig                accumulator, argSqrd, fix_up, argTo4;
-  unsigned long       adj;
   unsigned long long  fixed_arg;
 
 #ifdef PARANOID
@@ -300,6 +301,9 @@
 	}
       /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
       fixed_arg = 0x921fb54442d18469LL - fixed_arg;
+      /* There is a special case which arises due to rounding, to fix here. */
+      if ( fixed_arg == 0xffffffffffffffffLL )
+	fixed_arg = 0;
 
       exponent = -1;
       exp2 = -1;
@@ -363,10 +367,8 @@
       if ( argSqrd.msw & 0xffc00000 )
 	{
 	  /* Get about 32 bit precision in these: */
-	  mul_32_32(0x898cc517, argSqrd.msw, &adj);
-	  fix_up.msw -= adj/2;
-	  mul_32_32(0x898cc517, argTo4.msw, &adj);
-	  fix_up.msw += adj/24;
+	  fix_up.msw -= mul_32_32(0x898cc517, argSqrd.msw) / 2;
+	  fix_up.msw += mul_32_32(0x898cc517, argTo4.msw) / 24;
 	}
 
       exp2 += norm_Xsig(&accumulator);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/math-emu/poly_tan.c linux.14p16/arch/i386/math-emu/poly_tan.c
--- linux.vanilla/arch/i386/math-emu/poly_tan.c	Wed Dec 10 01:57:09 1997
+++ linux.14p16/arch/i386/math-emu/poly_tan.c	Thu Dec  9 15:34:19 1999
@@ -3,9 +3,9 @@
  |                                                                           |
  | Compute the tan of a FPU_REG, using a polynomial approximation.           |
  |                                                                           |
- | Copyright (C) 1992,1993,1994,1997                                         |
+ | Copyright (C) 1992,1993,1994,1997,1999                                    |
  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@suburbia.net             |
+ |                       Australia.  E-mail   billm@melbpc.org.au            |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -84,6 +84,14 @@
 	}
       /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
       XSIG_LL(accum) = 0x921fb54442d18469LL - XSIG_LL(accum);
+      /* This is a special case which arises due to rounding. */
+      if ( XSIG_LL(accum) == 0xffffffffffffffffLL )
+	{
+	  FPU_settag0(TAG_Valid);
+	  significand(st0_ptr) = 0x8a51e04daabda360LL;
+	  setexponent16(st0_ptr, 0x41 + EXTENDED_Ebias | SIGN_Negative);
+	  return;
+	}
 
       argSignif.lsw = accum.lsw;
       XSIG_LL(argSignif) = XSIG_LL(accum);
@@ -177,11 +185,11 @@
       else if ( exponent > -30 )
 	{
 	  adj = accum.msw >> -(exponent+1);      /* tan */
-	  mul_32_32(adj, adj, &adj);           /* tan^2 */
+	  adj = mul_32_32(adj, adj);             /* tan^2 */
 	}
       else
 	adj = 0;
-      mul_32_32(0x898cc517, adj, &adj);        /* delta * tan^2 */
+      adj = mul_32_32(0x898cc517, adj);          /* delta * tan^2 */
 
       fix_up.msw += adj;
       if ( !(fix_up.msw & 0x80000000) )   /* did fix_up overflow ? */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/math-emu/reg_round.S linux.14p16/arch/i386/math-emu/reg_round.S
--- linux.vanilla/arch/i386/math-emu/reg_round.S	Wed Dec 10 01:57:09 1997
+++ linux.14p16/arch/i386/math-emu/reg_round.S	Thu Dec  9 15:34:19 1999
@@ -365,7 +365,7 @@
 	jne	LDo_64_round_up
 
 	/* Now test for round-to-even */
-	testb	$1,%ebx
+	testb	$1,%bl
 	jz	LCheck_truncate_64
 
 LDo_64_round_up:
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/mm/fault.c linux.14p16/arch/i386/mm/fault.c
--- linux.vanilla/arch/i386/mm/fault.c	Sun Nov 22 17:38:19 1998
+++ linux.14p16/arch/i386/mm/fault.c	Thu Dec  9 15:34:19 1999
@@ -50,7 +50,14 @@
 	start &= PAGE_MASK;
 
 	for (;;) {
-		handle_mm_fault(current,vma, start, 1);
+	survive:
+		{
+			int fault = handle_mm_fault(current,vma, start, 1);
+			if (!fault)
+				goto do_sigbus;
+			if (fault < 0)
+				goto out_of_memory;
+		}
 		if (!size)
 			break;
 		size--;
@@ -73,6 +80,19 @@
 
 bad_area:
 	return 0;
+
+do_sigbus:
+	force_sig(SIGBUS, current);
+	goto bad_area;
+
+out_of_memory:
+	if (current->pid == 1)
+	{
+		current->policy |= SCHED_YIELD;
+		schedule();
+		goto survive;
+	}
+	goto bad_area;
 }
 
 asmlinkage void do_invalid_op(struct pt_regs *, unsigned long);
@@ -162,8 +182,14 @@
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	if (!handle_mm_fault(tsk, vma, address, write))
-		goto do_sigbus;
+survive:
+	{
+		int fault = handle_mm_fault(tsk, vma, address, write);
+		if (!fault)
+			goto do_sigbus;
+		if (fault < 0)
+			goto out_of_memory;
+	}
 
 	/*
 	 * Did it hit the DOS screen memory VA from vm86 mode?
@@ -255,6 +281,34 @@
  * We ran out of memory, or some other thing happened to us that made
  * us unable to handle the page fault gracefully.
  */
+out_of_memory:
+	if (tsk->pid == 1)
+	{
+		tsk->policy |= SCHED_YIELD;
+		schedule();
+		goto survive;
+	}
+	up(&mm->mmap_sem);
+	if (error_code & 4)
+	{
+		if (!((regs->eflags >> 12) & 3))
+		{
+			printk("VM: killing process %s\n", tsk->comm);
+			do_exit(SIGKILL);
+		}
+		else
+		{
+			/*
+			 * The task is running with privilegies and so we
+			 * trust it and we give it a chance to die gracefully.
+			 */
+			printk("VM: terminating process %s\n", tsk->comm);
+			force_sig(SIGTERM, current);
+			return;
+		}
+	}
+	goto no_context;
+
 do_sigbus:
 	up(&mm->mmap_sem);
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/Makefile linux.14p16/arch/ppc/Makefile
--- linux.vanilla/arch/ppc/Makefile	Sat Aug 14 02:27:15 1999
+++ linux.14p16/arch/ppc/Makefile	Thu Dec  9 15:34:29 1999
@@ -112,6 +112,10 @@
 	rm -f .config arch/ppc/defconfig
 	ln -s apus_defconfig arch/ppc/defconfig
 
+gemini_config:
+	rm -f .config arch/ppc/defconfig
+	ln -s gemini_defconfig arch/ppc/defconfig
+
 tags:
 	etags */*.c include/{asm,linux}/*.h arch/ppc/kernel/*.{c,h}
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/boot/Makefile linux.14p16/arch/ppc/boot/Makefile
--- linux.vanilla/arch/ppc/boot/Makefile	Sat Aug 28 20:00:53 1999
+++ linux.14p16/arch/ppc/boot/Makefile	Thu Dec  9 15:34:32 1999
@@ -25,12 +25,22 @@
 IOFF = 0
 ISZ = 0
 
+ifeq ($(CONFIG_ALL_PPC),y)
+CONFIG_PREP=y
+endif
+
 ifeq ($(CONFIG_SMP),y)
 TFTPIMAGE=/tftpboot/zImage.prep.smp$(MSIZE)
 else
 TFTPIMAGE=/tftpboot/zImage.prep$(MSIZE)
 endif
 
+ifeq ($(CONFIG_SMP),y)
+TFTPSIMAGE=/tftpboot/sImage.smp
+else
+TFTPSIMAGE=/tftpboot/sImage
+endif
+
 ifeq ($(CONFIG_PPC64),y)
 MSIZE=.64
 else
@@ -46,14 +56,10 @@
 OBJCOPY = $(CROSS_COMPILE)objcopy
 OBJCOPY_ARGS = -O elf32-powerpc
 
-ifeq ($(CONFIG_SMP),y)
-CFLAGS += -D__SMP__
-endif
-
 OBJECTS += vreset.o kbd.o of1275.o
- ifeq ($(CONFIG_SERIAL_CONSOLE),y)
-  OBJECTS += ns16550.o
- endif
+ifeq ($(CONFIG_SERIAL_CONSOLE),y)
+OBJECTS += ns16550.o
+endif
 
 all:	zImage
 
@@ -75,11 +81,20 @@
 		zvmlinux.initrd.tmp $@
 	rm zvmlinux.initrd.tmp
 
-zImage: zvmlinux mkprep
+zImage: zvmlinux mkprep sImage
+ifdef CONFIG_PREP
 	./mkprep -pbp zvmlinux zImage
+endif
+
+sImage: ../../../vmlinux
+ifdef CONFIG_GEMINI
+	$(OBJCOPY) -I elf32-powerpc -O binary ../../../vmlinux sImage
+endif
 
 zImage.initrd: zvmlinux.initrd mkprep
+ifdef CONFIG_PREP
 	./mkprep -pbp zvmlinux.initrd zImage.initrd
+endif
 
 zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz
 #
@@ -108,13 +123,18 @@
 	$(HOSTCC) -o mkprep mkprep.c
 
 znetboot : zImage
+ifdef CONFIG_PREP
 	cp zImage $(TFTPIMAGE)
+endif
+ifdef CONFIG_GEMINI
+	cp sImage $(TFTPSIMAGE)
+endif
 
 znetboot.initrd : zImage.initrd
 	cp zImage.initrd $(TFTPIMAGE)
 
 clean:
-	rm -f vmlinux* zvmlinux* mkprep zImage*
+	rm -f vmlinux* zvmlinux* mkprep zImage* sImage*
 
 fastdep:
 	$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/boot/head.S linux.14p16/arch/ppc/boot/head.S
--- linux.vanilla/arch/ppc/boot/head.S	Sat Aug 14 02:26:11 1999
+++ linux.14p16/arch/ppc/boot/head.S	Thu Dec  9 15:34:32 1999
@@ -6,7 +6,7 @@
 	.text
 
 /*
- * $Id: head.S,v 1.31 1999/04/22 06:32:00 davem Exp $
+ * $Id: head.S,v 1.33 1999/09/08 01:06:58 cort Exp $
  *	
  * Boot loader philosophy:
  *      ROM loads us to some arbitrary location
@@ -125,12 +125,11 @@
 	 * get start address of kernel code which is stored as a coff
 	 * entry.  see boot/head.S -- Cort 
 	 */
-	li	r9,0x0
-	lwz	r9,0(r9)
+	li	r9,0x4
 	mtlr	r9
-	li	r9,0
 	lis	r10,0xdeadc0de@h
 	ori	r10,r10,0xdeadc0de@l
+	li	r9,0
 	stw	r10,0(r9)
 /*
  * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/chrpboot/main.c linux.14p16/arch/ppc/chrpboot/main.c
--- linux.vanilla/arch/ppc/chrpboot/main.c	Sat Aug 14 02:27:15 1999
+++ linux.14p16/arch/ppc/chrpboot/main.c	Thu Dec  9 15:34:32 1999
@@ -68,7 +68,7 @@
 
     flush_cache(dst, len);
     
-    sa = *(unsigned long *)PROG_START+PROG_START;
+    sa = (unsigned long)PROG_START;
     printf("start address = 0x%x\n\r", sa);
 
     (*(void (*)())sa)(0, 0, prom, a1, a2);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/chrpboot/string.S linux.14p16/arch/ppc/chrpboot/string.S
--- linux.vanilla/arch/ppc/chrpboot/string.S	Mon Jan 12 23:18:13 1998
+++ linux.14p16/arch/ppc/chrpboot/string.S	Thu Jan  1 01:00:00 1970
@@ -1,206 +0,0 @@
-/*
- * String handling functions for PowerPC.
- *
- * Copyright (C) 1996 Paul Mackerras.
- *
- * 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.
- */
-#define r0	0
-#define r3	3
-#define r4	4
-#define r5	5
-#define r6	6
-#define r7	7
-#define r8	8
-
-	.globl	strcpy
-strcpy:
-	addi	r5,r3,-1
-	addi	r4,r4,-1
-1:	lbzu	r0,1(r4)
-	cmpwi	0,r0,0
-	stbu	r0,1(r5)
-	bne	1b
-	blr
-
-	.globl	strncpy
-strncpy:
-	cmpwi	0,r5,0
-	beqlr
-	mtctr	r5
-	addi	r6,r3,-1
-	addi	r4,r4,-1
-1:	lbzu	r0,1(r4)
-	cmpwi	0,r0,0
-	stbu	r0,1(r6)
-	bdnzf	2,1b		/* dec ctr, branch if ctr != 0 && !cr0.eq */
-	blr
-
-	.globl	strcat
-strcat:
-	addi	r5,r3,-1
-	addi	r4,r4,-1
-1:	lbzu	r0,1(r5)
-	cmpwi	0,r0,0
-	bne	1b
-	addi	r5,r5,-1
-1:	lbzu	r0,1(r4)
-	cmpwi	0,r0,0
-	stbu	r0,1(r5)
-	bne	1b
-	blr
-
-	.globl	strcmp
-strcmp:
-	addi	r5,r3,-1
-	addi	r4,r4,-1
-1:	lbzu	r3,1(r5)
-	cmpwi	1,r3,0
-	lbzu	r0,1(r4)
-	subf.	r3,r0,r3
-	beqlr	1
-	beq	1b
-	blr
-
-	.globl	strlen
-strlen:
-	addi	r4,r3,-1
-1:	lbzu	r0,1(r4)
-	cmpwi	0,r0,0
-	bne	1b
-	subf	r3,r3,r4
-	blr
-
-	.globl	memset
-memset:
-	rlwimi	r4,r4,8,16,23
-	rlwimi	r4,r4,16,0,15
-	addi	r6,r3,-4
-	cmplwi	0,r5,4
-	blt	7f
-	stwu	r4,4(r6)
-	beqlr
-	andi.	r0,r6,3
-	add	r5,r0,r5
-	subf	r6,r0,r6
-	rlwinm	r0,r5,32-2,2,31
-	mtctr	r0
-	bdz	6f
-1:	stwu	r4,4(r6)
-	bdnz	1b
-6:	andi.	r5,r5,3
-7:	cmpwi	0,r5,0
-	beqlr
-	mtctr	r5
-	addi	r6,r6,3
-8:	stbu	r4,1(r6)
-	bdnz	8b
-	blr
-
-	.globl	bcopy
-bcopy:
-	mr	r6,r3
-	mr	r3,r4
-	mr	r4,r6
-	b	memcpy
-
-	.globl	memmove
-memmove:
-	cmplw	0,r3,r4
-	bgt	backwards_memcpy
-	/* fall through */
-
-	.globl	memcpy
-memcpy:
-	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
-	addi	r6,r3,-4
-	addi	r4,r4,-4
-	beq	2f			/* if less than 8 bytes to do */
-	andi.	r0,r6,3			/* get dest word aligned */
-	mtctr	r7
-	bne	5f
-1:	lwz	r7,4(r4)
-	lwzu	r8,8(r4)
-	stw	r7,4(r6)
-	stwu	r8,8(r6)
-	bdnz	1b
-	andi.	r5,r5,7
-2:	cmplwi	0,r5,4
-	blt	3f
-	lwzu	r0,4(r4)
-	addi	r5,r5,-4
-	stwu	r0,4(r6)
-3:	cmpwi	0,r5,0
-	beqlr
-	mtctr	r5
-	addi	r4,r4,3
-	addi	r6,r6,3
-4:	lbzu	r0,1(r4)
-	stbu	r0,1(r6)
-	bdnz	4b
-	blr
-5:	subfic	r0,r0,4
-	mtctr	r0
-6:	lbz	r7,4(r4)
-	addi	r4,r4,1
-	stb	r7,4(r6)
-	addi	r6,r6,1
-	bdnz	6b
-	subf	r5,r0,r5
-	rlwinm.	r7,r5,32-3,3,31
-	beq	2b
-	mtctr	r7
-	b	1b
-
-	.globl	backwards_memcpy
-backwards_memcpy:
-	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
-	add	r6,r3,r5
-	add	r4,r4,r5
-	beq	2f
-	andi.	r0,r6,3
-	mtctr	r7
-	bne	5f
-1:	lwz	r7,-4(r4)
-	lwzu	r8,-8(r4)
-	stw	r7,-4(r6)
-	stwu	r8,-8(r6)
-	bdnz	1b
-	andi.	r5,r5,7
-2:	cmplwi	0,r5,4
-	blt	3f
-	lwzu	r0,-4(r4)
-	subi	r5,r5,4
-	stwu	r0,-4(r6)
-3:	cmpwi	0,r5,0
-	beqlr
-	mtctr	r5
-4:	lbzu	r0,-1(r4)
-	stbu	r0,-1(r6)
-	bdnz	4b
-	blr
-5:	mtctr	r0
-6:	lbzu	r7,-1(r4)
-	stbu	r7,-1(r6)
-	bdnz	6b
-	subf	r5,r0,r5
-	rlwinm.	r7,r5,32-3,3,31
-	beq	2b
-	mtctr	r7
-	b	1b
-
-	.globl	memcmp
-memcmp:
-	cmpwi	0,r5,0
-	blelr
-	mtctr	r5
-	addi	r6,r3,-1
-	addi	r4,r4,-1
-1:	lbzu	r3,1(r6)
-	lbzu	r0,1(r4)
-	subf.	r3,r0,r3
-	bdnzt	2,1b
-	blr
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/coffboot/main.c linux.14p16/arch/ppc/coffboot/main.c
--- linux.vanilla/arch/ppc/coffboot/main.c	Wed Aug  5 00:06:36 1998
+++ linux.14p16/arch/ppc/coffboot/main.c	Thu Dec  9 15:34:32 1999
@@ -100,7 +100,7 @@
 
     flush_cache(dst, len);
 
-    sa = *(unsigned *)dst + PROG_START;
+    sa = (unsigned long)dst;
     printf("start address = 0x%x\n", sa);
 
 #if 0
@@ -165,7 +165,6 @@
 	printf("gunzip: ran out of data in header\n");
 	exit();
     }
-
     s.zalloc = zalloc;
     s.zfree = zfree;
     r = inflateInit2(&s, -MAX_WBITS);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/common_defconfig linux.14p16/arch/ppc/common_defconfig
--- linux.vanilla/arch/ppc/common_defconfig	Sat Aug 14 02:27:15 1999
+++ linux.14p16/arch/ppc/common_defconfig	Thu Dec  9 15:34:33 1999
@@ -1,5 +1,5 @@
 #
-# Automatically generated make config: don't edit
+# Automatically generated by make menuconfig: don't edit
 #
 
 #
@@ -7,13 +7,13 @@
 #
 CONFIG_PPC=y
 CONFIG_6xx=y
-# CONFIG_PPC64 is not set
 # CONFIG_8xx is not set
 # CONFIG_PMAC is not set
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
+# CONFIG_GEMINI is not set
 # CONFIG_MBX is not set
 # CONFIG_SMP is not set
 CONFIG_6xx=y
@@ -62,10 +62,6 @@
 #
 CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_BLK_DEV_IDECD=y
@@ -81,18 +77,16 @@
 CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_PMAC_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
-
-#
-# Additional Block Devices
-#
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_PARIDE_PARPORT=y
 # CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -115,17 +109,9 @@
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
 CONFIG_SYN_COOKIES=y
-
-#
-# (it is safe to leave these untouched)
-#
 CONFIG_INET_RARP=y
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
-
-#
-#  
-#
 # CONFIG_IPX is not set
 CONFIG_ATALK=m
 # CONFIG_X25 is not set
@@ -147,19 +133,11 @@
 # SCSI support
 #
 CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
+CONFIG_CHR_DEV_SG=y
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
@@ -177,6 +155,7 @@
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=15
+# CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
@@ -189,12 +168,11 @@
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_G_NCR5380_PORT is not set
-# CONFIG_SCSI_G_NCR5380_MEM is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_NCR53C8XX is not set
 CONFIG_SCSI_SYM53C8XX=y
@@ -226,26 +204,37 @@
 # Network device support
 #
 CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
 # CONFIG_ARCNET is not set
 # CONFIG_DUMMY is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
 CONFIG_NET_ETHERNET=y
 CONFIG_MACE=y
 CONFIG_BMAC=y
+# CONFIG_NCR885E is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_RTL8139 is not set
 # CONFIG_YELLOWFIN is not set
-# CONFIG_ACENIC is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
 CONFIG_PCNET32=y
+# CONFIG_ACENIC is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
+# CONFIG_DM9102 is not set
 CONFIG_DE4X5=y
 # CONFIG_DEC_ELCP is not set
 # CONFIG_DGRS is not set
@@ -255,28 +244,41 @@
 # CONFIG_NE2K_PCI is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
+# CONFIG_SIS900 is not set
 # CONFIG_ES3210 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_ZNET is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
-# CONFIG_DLCI is not set
+
+#
+# Appletalk devices
+#
 # CONFIG_LTPC is not set
 # CONFIG_COPS is not set
 # CONFIG_IPDDP is not set
 CONFIG_PPP=y
+# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
 
 #
-# CCP compressors for PPP are only built as modules.
+# Token ring devices
 #
-# CONFIG_SLIP is not set
-# CONFIG_NET_RADIO is not set
 # CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
 # CONFIG_HOSTESS_SV11 is not set
 # CONFIG_COSA is not set
-# CONFIG_RCPCI is not set
+# CONFIG_SEALEVEL_4021 is not set
+# CONFIG_COMX is not set
+# CONFIG_DLCI is not set
+# CONFIG_SBNI is not set
 
 #
 # Amateur Radio support
@@ -302,7 +304,6 @@
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
-# CONFIG_FB_ATY is not set
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
@@ -311,7 +312,7 @@
 CONFIG_FB_MATROX_MYSTIQUE=y
 CONFIG_FB_MATROX_G100=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
-# CONFIG_FB_ATY is not set
+CONFIG_FB_ATY=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -369,14 +370,6 @@
 # Ftape, the floppy tape device driver
 #
 # CONFIG_FTAPE is not set
-# CONFIG_FT_NORMAL_DEBUG is not set
-# CONFIG_FT_FULL_DEBUG is not set
-# CONFIG_FT_NO_TRACE is not set
-# CONFIG_FT_NO_TRACE_AT_ALL is not set
-# CONFIG_FT_STD_FDC is not set
-# CONFIG_FT_MACH2 is not set
-# CONFIG_FT_PROBE_FC10 is not set
-# CONFIG_FT_ALT_FDC is not set
 
 #
 # USB drivers - not for the faint of heart
@@ -407,6 +400,7 @@
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_EFS_FS is not set
 
 #
 # Network File Systems
@@ -458,6 +452,7 @@
 # CONFIG_NLS_ISO8859_7 is not set
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_14 is not set
 # CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 
@@ -466,8 +461,11 @@
 #
 CONFIG_SOUND=y
 CONFIG_DMASOUND=y
+# CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
@@ -475,13 +473,13 @@
 # CONFIG_SOUND_DMAP is not set
 # CONFIG_SOUND_PAS is not set
 # CONFIG_SOUND_SB is not set
-# CONFIG_SOUND_ADLIB is not set
 # CONFIG_SOUND_GUS is not set
 # CONFIG_SOUND_MPU401 is not set
 # CONFIG_SOUND_PSS is not set
 # CONFIG_SOUND_MSS is not set
 # CONFIG_SOUND_SSCAPE is not set
 # CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_VIA82CXXX is not set
 # CONFIG_SOUND_MAD16 is not set
 # CONFIG_SOUND_WAVEFRONT is not set
 CONFIG_SOUND_CS4232=m
@@ -494,6 +492,7 @@
 # CONFIG_SOUND_YM3812 is not set
 # CONFIG_SOUND_VMIDI is not set
 # CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_NM256 is not set
 
 #
 # Additional low level sound drivers
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/config.in linux.14p16/arch/ppc/config.in
--- linux.vanilla/arch/ppc/config.in	Wed Oct 20 01:12:33 1999
+++ linux.14p16/arch/ppc/config.in	Thu Dec  9 15:34:32 1999
@@ -9,7 +9,6 @@
 define_bool CONFIG_PPC y
 choice 'Processor type' \
 	"6xx/7xx		CONFIG_6xx \
-	 630/Power3(64-Bit) 	CONFIG_PPC64 \
 	 860/821		CONFIG_8xx" 6xx/7xx
 
 choice 'Machine Type' \
@@ -18,6 +17,7 @@
 	 CHRP		CONFIG_CHRP \
 	 PowerMac/PReP/CHRP	CONFIG_ALL_PPC \
   	 APUS           CONFIG_APUS \
+	 Gemini		CONFIG_GEMINI \
 	 MBX		CONFIG_MBX" PowerMac
 
 bool 'Symmetric multi-processing support' CONFIG_SMP
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/defconfig linux.14p16/arch/ppc/defconfig
--- linux.vanilla/arch/ppc/defconfig	Wed Oct 20 01:12:33 1999
+++ linux.14p16/arch/ppc/defconfig	Thu Dec  9 15:34:32 1999
@@ -1,5 +1,5 @@
 #
-# Automatically generated make config: don't edit
+# Automatically generated by make menuconfig: don't edit
 #
 
 #
@@ -7,16 +7,15 @@
 #
 CONFIG_PPC=y
 CONFIG_6xx=y
-# CONFIG_PPC64 is not set
 # CONFIG_8xx is not set
-CONFIG_PMAC=y
+# CONFIG_PMAC is not set
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
-# CONFIG_ALL_PPC is not set
+CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
+# CONFIG_GEMINI is not set
 # CONFIG_MBX is not set
 # CONFIG_SMP is not set
-CONFIG_MACH_SPECIFIC=y
 CONFIG_6xx=y
 
 #
@@ -24,7 +23,7 @@
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
+CONFIG_MODVERSIONS=y
 CONFIG_KMOD=y
 CONFIG_PCI=y
 # CONFIG_PCI_QUIRKS is not set
@@ -35,11 +34,10 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_MISC=m
+# CONFIG_BINFMT_MISC is not set
 # CONFIG_BINFMT_JAVA is not set
-CONFIG_PARPORT=m
-# CONFIG_PARPORT_PC is not set
-# CONFIG_VGA_CONSOLE is not set
+# CONFIG_PARPORT is not set
+CONFIG_VGA_CONSOLE=y
 CONFIG_FB=y
 CONFIG_FB_COMPAT_XPMAC=y
 CONFIG_PMAC_PBOOK=y
@@ -52,6 +50,7 @@
 # CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
 # CONFIG_MOTOROLA_HOTSWAP is not set
+# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Plug and Play support
@@ -61,12 +60,8 @@
 #
 # Block devices
 #
-# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_BLK_DEV_IDECD=y
@@ -75,25 +70,13 @@
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
-CONFIG_IDEDMA_AUTO=y
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_VIA82C586 is not set
-CONFIG_BLK_DEV_CMD646=y
-# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+CONFIG_BLK_DEV_SL82C105=y
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
 CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_PMAC_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
-
-#
-# Additional Block Devices
-#
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
@@ -101,7 +84,7 @@
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_PARIDE_PARPORT=m
+CONFIG_PARIDE_PARPORT=y
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -125,18 +108,10 @@
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
-# CONFIG_SYN_COOKIES is not set
-
-#
-# (it is safe to leave these untouched)
-#
+CONFIG_SYN_COOKIES=y
 CONFIG_INET_RARP=y
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
-
-#
-#  
-#
 # CONFIG_IPX is not set
 CONFIG_ATALK=m
 # CONFIG_X25 is not set
@@ -158,19 +133,11 @@
 # SCSI support
 #
 CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
+CONFIG_CHR_DEV_SG=y
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
@@ -188,6 +155,7 @@
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=15
+# CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
@@ -202,12 +170,11 @@
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_PPA is not set
-# CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
-CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_NCR53C8XX is not set
 CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
@@ -215,7 +182,7 @@
 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 # CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
@@ -253,20 +220,21 @@
 CONFIG_NET_ETHERNET=y
 CONFIG_MACE=y
 CONFIG_BMAC=y
+# CONFIG_NCR885E is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_RTL8139 is not set
-# CONFIG_SIS900 is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
-# CONFIG_PCNET32 is not set
+CONFIG_PCNET32=y
 # CONFIG_ACENIC is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
+# CONFIG_DM9102 is not set
 CONFIG_DE4X5=y
 # CONFIG_DEC_ELCP is not set
 # CONFIG_DGRS is not set
@@ -276,6 +244,7 @@
 # CONFIG_NE2K_PCI is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
+# CONFIG_SIS900 is not set
 # CONFIG_ES3210 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_ZNET is not set
@@ -289,12 +258,7 @@
 # CONFIG_LTPC is not set
 # CONFIG_COPS is not set
 # CONFIG_IPDDP is not set
-# CONFIG_PLIP is not set
 CONFIG_PPP=y
-
-#
-# CCP compressors for PPP are only built as modules.
-#
 # CONFIG_SLIP is not set
 # CONFIG_NET_RADIO is not set
 
@@ -312,7 +276,9 @@
 # CONFIG_HOSTESS_SV11 is not set
 # CONFIG_COSA is not set
 # CONFIG_SEALEVEL_4021 is not set
+# CONFIG_COMX is not set
 # CONFIG_DLCI is not set
+# CONFIG_SBNI is not set
 
 #
 # Amateur Radio support
@@ -338,11 +304,14 @@
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
-CONFIG_FB_ATY=y
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_MATROX is not set
+CONFIG_FB_MATROX=y
+# CONFIG_FB_MATROX_MILLENIUM is not set
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_MULTIHEAD is not set
 CONFIG_FB_ATY=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
@@ -365,13 +334,22 @@
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
+CONFIG_SERIAL=m
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_PRINTER is not set
-# CONFIG_MOUSE is not set
+CONFIG_MOUSE=y
+
+#
+# Mice
+#
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
 CONFIG_NVRAM=y
@@ -406,10 +384,10 @@
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 CONFIG_HFS_FS=y
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
 # CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=m
+CONFIG_VFAT_FS=y
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
@@ -475,7 +453,7 @@
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_9 is not set
 # CONFIG_NLS_ISO8859_14 is not set
-CONFIG_NLS_ISO8859_15=y
+# CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 
 #
@@ -483,13 +461,43 @@
 #
 CONFIG_SOUND=y
 CONFIG_DMASOUND=y
+# CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_OSS is not set
+CONFIG_SOUND_OSS=y
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+CONFIG_SOUND_CS4232=m
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_SOFTOSS is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_NM256 is not set
+
+#
+# Additional low level sound drivers
+#
+# CONFIG_LOWLEVEL_SOUND is not set
 
 #
 # Kernel hacking
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/gemini_defconfig linux.14p16/arch/ppc/gemini_defconfig
--- linux.vanilla/arch/ppc/gemini_defconfig	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/ppc/gemini_defconfig	Thu Dec  9 15:34:33 1999
@@ -0,0 +1,379 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_6xx=y
+# CONFIG_8xx is not set
+# CONFIG_PMAC is not set
+# CONFIG_PREP is not set
+# CONFIG_CHRP is not set
+# CONFIG_ALL_PPC is not set
+# CONFIG_APUS is not set
+CONFIG_GEMINI=y
+# CONFIG_MBX is not set
+# CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
+CONFIG_6xx=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+CONFIG_PCI=y
+# CONFIG_PCI_QUIRKS is not set
+# CONFIG_PCI_OLD_PROC is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
+# CONFIG_PARPORT is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_FB is not set
+# CONFIG_PMAC_PBOOK is not set
+# CONFIG_MAC_KEYBOARD is not set
+# CONFIG_MAC_FLOPPY is not set
+# CONFIG_MAC_SERIAL is not set
+# CONFIG_ADBMOUSE is not set
+# CONFIG_PROC_DEVICETREE is not set
+# CONFIG_TOTALMP is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_MOTOROLA_HOTSWAP is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_IDE is not set
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_ONLY is not set
+
+#
+# Additional Block Devices
+#
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+CONFIG_IP_ALIAS=y
+CONFIG_SYN_COOKIES=y
+
+#
+# (it is safe to leave these untouched)
+#
+# CONFIG_INET_RARP is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_G_NCR5380_PORT is not set
+# CONFIG_SCSI_G_NCR5380_MEM is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_SYM53C8XX=y
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+CONFIG_NCR885E=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_EISA is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
+
+#
+# Token ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
+# CONFIG_SEALEVEL_4021 is not set
+# CONFIG_COMX is not set
+# CONFIG_DLCI is not set
+# CONFIG_SBNI is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_MOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Joystick support
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_FT_NORMAL_DEBUG is not set
+# CONFIG_FT_FULL_DEBUG is not set
+# CONFIG_FT_NO_TRACE is not set
+# CONFIG_FT_NO_TRACE_AT_ALL is not set
+# CONFIG_FT_STD_FDC is not set
+# CONFIG_FT_MACH2 is not set
+# CONFIG_FT_PROBE_FC10 is not set
+# CONFIG_FT_ALT_FDC is not set
+
+#
+# USB drivers - not for the faint of heart
+#
+# CONFIG_USB is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_FAT_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_EFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_BSD_DISKLABEL is not set
+CONFIG_MAC_PARTITION=y
+# CONFIG_SMD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/Makefile linux.14p16/arch/ppc/kernel/Makefile
--- linux.vanilla/arch/ppc/kernel/Makefile	Sat Aug 28 20:00:53 1999
+++ linux.14p16/arch/ppc/kernel/Makefile	Thu Dec  9 15:34:29 1999
@@ -40,7 +40,8 @@
 	  pmac_setup.o pmac_support.o \
 	  prep_pci.o pmac_pci.o chrp_pci.o \
 	  residual.o prom.o openpic.o feature.o \
-	  prep_nvram.o open_pic.o i8259.o pmac_pic.o indirect_pci.o
+	  prep_nvram.o open_pic.o i8259.o pmac_pic.o indirect_pci.o \
+	  gemini_pci.o gemini_prom.o gemini_setup.o
 OX_OBJS += chrp_setup.o prep_setup.o
 endif
 endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/chrp_pci.c linux.14p16/arch/ppc/kernel/chrp_pci.c
--- linux.vanilla/arch/ppc/kernel/chrp_pci.c	Wed Oct 20 01:12:33 1999
+++ linux.14p16/arch/ppc/kernel/chrp_pci.c	Thu Dec  9 15:34:29 1999
@@ -287,9 +287,6 @@
 	{
 		if ( dev->irq )
 			dev->irq = openpic_to_irq( dev->irq );
-		/* adjust the io_port for the NCR cards for busses other than 0 -- Cort */
-		if ( (dev->bus->number > 0) && (dev->vendor == PCI_VENDOR_ID_NCR) )
-			dev->base_address[0] += (dev->bus->number*0x08000000);
 		/* these need to be absolute addrs for OF and Matrox FB -- Cort */
 		if ( dev->vendor == PCI_VENDOR_ID_MATROX )
 		{
@@ -306,6 +303,10 @@
 			pcibios_write_config_word(dev->bus->number,
 			  dev->devfn, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD);
 		}
+		if ( (dev->bus->number > 0) &&
+		     ((dev->vendor == PCI_VENDOR_ID_NCR) ||
+		      (dev->vendor == PCI_VENDOR_ID_AMD)))
+			dev->base_address[0] += (dev->bus->number*0x08000000);
 	}
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/chrp_setup.c linux.14p16/arch/ppc/kernel/chrp_setup.c
--- linux.vanilla/arch/ppc/kernel/chrp_setup.c	Sat Aug 28 20:00:53 1999
+++ linux.14p16/arch/ppc/kernel/chrp_setup.c	Thu Dec  9 15:34:29 1999
@@ -386,8 +386,8 @@
                 }
         }
 #endif /* __SMP__ */
-
-        irq = openpic_irq(0);
+	
+        irq = openpic_irq(smp_processor_id());
         if (irq == IRQ_8259_CASCADE)
         {
                 /*
@@ -402,7 +402,7 @@
                 /*
                  * Acknowledge as soon as possible to allow i8259
                  * interrupt nesting                         */
-                openpic_eoi(0);
+                openpic_eoi(smp_processor_id());
                 openpic_eoi_done = 1;
         }
         if (irq == OPENPIC_VEC_SPURIOUS)
@@ -429,7 +429,7 @@
 	}
 out:
         if (!openpic_eoi_done)
-                openpic_eoi(0);
+                openpic_eoi(smp_processor_id());
 }
 
 __initfunc(void
@@ -446,12 +446,9 @@
 			(*(unsigned long *)get_property(np,
 							"8259-interrupt-acknowledge", NULL));
 	}
+	open_pic.irq_offset = 16;
 	for ( i = 16 ; i < NR_IRQS ; i++ )
 		irq_desc[i].ctl = &open_pic;
-	/* openpic knows that it's at irq 16 offset
-	 * so we don't need to set it in the pic structure
-	 * -- Cort
-	 */
 	openpic_init(1);
 	for ( i = 0 ; i < 16  ; i++ )
 		irq_desc[i].ctl = &i8259_pic;
@@ -461,8 +458,14 @@
 		    xmon_irq, 0, "NMI", 0);
 #endif	/* CONFIG_XMON */
 #ifdef __SMP__
-	request_irq(openpic_to_irq(OPENPIC_VEC_IPI),
-		    openpic_ipi_action, 0, "IPI0", 0);
+	request_irq(OPENPIC_VEC_IPI, openpic_ipi_action,
+		    0, "IPI0", 0);
+	request_irq(OPENPIC_VEC_IPI+1, openpic_ipi_action,
+		    0, "IPI1 (invalidate TLB)", 0);
+	request_irq(OPENPIC_VEC_IPI+2, openpic_ipi_action,
+		    0, "IPI2 (stop CPU)", 0);
+	request_irq(OPENPIC_VEC_IPI+3, openpic_ipi_action,
+		    0, "IPI3 (reschedule)", 0);
 #endif	/* __SMP__ */
 }
 
@@ -471,7 +474,6 @@
 {
 	adb_init();
 
-	/* Should this be here? - Corey */
 	pmac_nvram_init();
 
 #ifdef CONFIG_VT
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/gemini_pci.c linux.14p16/arch/ppc/kernel/gemini_pci.c
--- linux.vanilla/arch/ppc/kernel/gemini_pci.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/ppc/kernel/gemini_pci.c	Thu Dec  9 15:34:30 1999
@@ -0,0 +1,273 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+
+#include <asm/machdep.h>
+#include <asm/gemini.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include "pci.h"
+
+#define pci_config_addr(bus,dev,offset) \
+        (0x80000000 | (bus<<16) | (dev<<8) | offset)
+
+
+int
+gemini_pcibios_read_config_byte(unsigned char bus, unsigned char dev,
+                                unsigned char offset, unsigned char *val)
+{
+	unsigned long reg;
+	reg = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3))));
+	*val = ((reg >> ((offset & 0x3) << 3)) & 0xff);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_read_config_word(unsigned char bus, unsigned char dev,
+                                unsigned char offset, unsigned short *val)
+{
+	unsigned long reg;
+	reg = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3))));
+	*val = ((reg >> ((offset & 0x3) << 3)) & 0xffff);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_read_config_dword(unsigned char bus, unsigned char dev,
+                                 unsigned char offset, unsigned int *val)
+{
+	*val = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3))));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_write_config_byte(unsigned char bus, unsigned char dev,
+                                 unsigned char offset, unsigned char val)
+{
+	unsigned long reg;
+	int shifts = offset & 0x3;
+
+	reg = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3))));
+	reg = (reg & ~(0xff << (shifts << 3))) | (val << (shifts << 3));
+	grackle_write( pci_config_addr( bus, dev, (offset & ~(0x3))), reg );
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_write_config_word(unsigned char bus, unsigned char dev,
+                                 unsigned char offset, unsigned short val)
+{
+	unsigned long reg;
+	int shifts = offset & 0x3;
+
+	reg = grackle_read( pci_config_addr( bus, dev, (offset & ~(0x3))));
+	reg = (reg & ~(0xffff << (shifts << 3))) | (val << (shifts << 3));
+	grackle_write( pci_config_addr( bus, dev, (offset & ~(0x3))), reg );
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_write_config_dword(unsigned char bus, unsigned char dev,
+                                  unsigned char offset, unsigned int val)
+{
+	grackle_write( pci_config_addr( bus, dev, (offset & ~(0x3))), val );
+	return PCIBIOS_SUCCESSFUL;
+}
+
+struct gemini_device {
+	unsigned short vendor, device;
+	unsigned char irq;
+	unsigned short cmd;
+	unsigned char cache_line, latency;
+	void (*init)(struct pci_dev *dev);
+};
+
+static struct gemini_device gemini_map[] = {
+	{ PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C885, 11, 0x15, 32, 248, NULL },
+	{ PCI_VENDOR_ID_NCR, 0x701, 10, 0, 0, 0, NULL },
+	{ PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_CA91C042, 3, 0, 0, 0, NULL },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_MPIC, 0xff, 0, 0, 0, NULL },
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_670, 0xff, 0, 0, 0, NULL },
+	{ PCI_VENDOR_ID_MOTOROLA, PCI_DEVICE_ID_MOTOROLA_MPC106, 0xff, 0, 0, 0, NULL },
+};
+
+static int gemini_map_count = (sizeof( gemini_map ) /
+                               sizeof( gemini_map[0] ));
+
+ 
+
+/*  This just sets up the known devices on the board. */
+__initfunc(static void mapin_device( struct pci_dev *dev ))
+{
+	struct gemini_device *p;
+	unsigned short cmd;
+	int i;
+  
+
+	for( i=0; i < gemini_map_count; i++ ) {
+		p = &(gemini_map[i]);
+    
+		if ( p->vendor == dev->vendor && 
+		     p->device == dev->device ) {
+     
+			if (p->irq != 0xff) {
+				pci_write_config_byte( dev, PCI_INTERRUPT_LINE, p->irq );
+				dev->irq = p->irq;
+			}
+
+			if (p->cmd) {
+				pci_read_config_word( dev, PCI_COMMAND, &cmd );
+				pci_write_config_word( dev, PCI_COMMAND, (p->cmd|cmd));
+			}
+
+			if (p->cache_line)
+				pci_write_config_byte( dev, PCI_CACHE_LINE_SIZE, p->cache_line );
+ 
+			if (p->latency)
+				pci_write_config_byte( dev, PCI_LATENCY_TIMER, p->latency );
+		}
+	}
+}
+
+#define KB 1024
+#define MB (KB*KB)
+
+#define ALIGN(val,align) (((val) + ((align) -1))&(~((align) -1)))
+#define MAX(a,b)   (((a) > (b)) ? (a) : (b))
+
+#define FIRST_IO_ADDR 0x10000
+#define FIRST_MEM_ADDR 0x02000000
+
+#define GEMINI_PCI_MEM_BASE (0xf0000000)
+#define GEMINI_PCI_IO_BASE  (0xfe800000)
+
+static unsigned long pci_mem_base = GEMINI_PCI_MEM_BASE;
+static unsigned long pci_io_base = GEMINI_PCI_IO_BASE;
+
+static unsigned int io_base = FIRST_IO_ADDR;
+static unsigned int mem_base = FIRST_MEM_ADDR;
+
+
+
+__initfunc(static void layout_dev( struct pci_dev *dev ))
+{
+	int i;
+	struct pci_bus *bus;
+	unsigned short cmd;
+	unsigned int reg, base, mask, size, alignto, type;
+
+	bus = dev->bus;
+
+	/* make any known settings happen */
+	mapin_device( dev );
+
+	gemini_pcibios_read_config_word( bus->number, dev->devfn, PCI_COMMAND, &cmd );
+
+	for( reg = PCI_BASE_ADDRESS_0, i=0; reg <= PCI_BASE_ADDRESS_5; reg += 4, i++ ) {
+    
+		/* MPIC already done */
+		if (dev->vendor == PCI_VENDOR_ID_IBM &&
+		    dev->device == PCI_DEVICE_ID_IBM_MPIC)
+			return;
+
+		gemini_pcibios_write_config_dword( bus->number, dev->devfn, reg, 0xffffffff );
+		gemini_pcibios_read_config_dword( bus->number, dev->devfn, reg, &base );
+		if (!base) {
+			dev->base_address[i] = 0;
+			continue;
+		}
+
+		if (base & PCI_BASE_ADDRESS_SPACE_IO) {
+			cmd |= PCI_COMMAND_IO;
+			base &= PCI_BASE_ADDRESS_IO_MASK;
+			mask = (~base << 1) | 0x1;
+			size = (mask & base) & 0xffffffff;
+			alignto = MAX(0x400, size);
+			base = ALIGN(io_base, alignto);
+			io_base = base + size;
+			gemini_pcibios_write_config_dword( bus->number, dev->devfn, reg, 
+							   ((pci_io_base + base) & 0x00ffffff) | 0x1);
+			dev->base_address[i] = (pci_io_base + base) | 0x1;
+		}
+
+		else {
+			cmd |= PCI_COMMAND_MEMORY;
+			type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+			mask = (~base << 1) | 0x1;
+			size = (mask & base) & 0xffffffff;
+			switch( type ) {
+
+			case PCI_BASE_ADDRESS_MEM_TYPE_32:
+				break;
+			case PCI_BASE_ADDRESS_MEM_TYPE_64:
+				printk("Warning: Ignoring 64-bit device; slot %d, function %d.\n",
+				       PCI_SLOT( dev->devfn ), PCI_FUNC( dev->devfn ));
+				reg += 4;
+				continue;
+			}
+
+			alignto = MAX(0x1000, size);
+			base = ALIGN(mem_base, alignto);
+			mem_base = base + size;
+			gemini_pcibios_write_config_dword( bus->number, dev->devfn,
+							   reg, (pci_mem_base + base));
+			dev->base_address[i] = pci_mem_base + base;
+		}
+	}
+
+	if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+		cmd |= PCI_COMMAND_IO;
+
+	gemini_pcibios_write_config_word( bus->number, dev->devfn, PCI_COMMAND,
+					  (cmd|PCI_COMMAND_MASTER));
+
+}
+
+__initfunc(static void layout_bus( struct pci_bus *bus ))
+{
+	struct pci_dev *dev;
+
+	if (!bus->devices && !bus->children)
+		return;
+
+	io_base = ALIGN(io_base, 4*KB);
+	mem_base = ALIGN(mem_base, 4*KB);
+
+	for( dev = bus->devices; dev; dev = dev->sibling ) {
+		if (((dev->class >> 16) != PCI_BASE_CLASS_BRIDGE) ||
+		    ((dev->class >> 8) == PCI_CLASS_BRIDGE_OTHER))
+			layout_dev( dev );
+	}
+}
+
+
+__initfunc(void gemini_pcibios_fixup(void))
+{
+	struct pci_bus *bus;
+	unsigned long orig_mem_base, orig_io_base;
+
+	orig_mem_base = pci_mem_base;
+	orig_io_base = pci_io_base;
+
+	for( bus = &pci_root; bus; bus = bus->children )
+		layout_bus( bus );
+
+	pci_mem_base = orig_mem_base;
+	pci_io_base = orig_io_base;
+
+
+}
+
+decl_config_access_method(gemini);
+
+/* The "bootloader" for Synergy boards does none of this for us, so we need to
+   lay it all out ourselves... --Dan */
+__initfunc(void gemini_setup_pci_ptrs(void))
+{
+
+	set_config_access_method(gemini);
+	ppc_md.pcibios_fixup = gemini_pcibios_fixup;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/gemini_prom.S linux.14p16/arch/ppc/kernel/gemini_prom.S
--- linux.vanilla/arch/ppc/kernel/gemini_prom.S	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/ppc/kernel/gemini_prom.S	Thu Dec  9 15:34:30 1999
@@ -0,0 +1,94 @@
+/*
+ *  arch/ppc/kernel/gemini_prom.S
+ *
+ *  Not really prom support code (yet), but sort of anti-prom code.  The current
+ *  bootloader does a number of things it shouldn't and doesn't do things that it
+ *  should.  The stuff in here is mainly a hodge-podge collection of setup code
+ *  to get the board up and running.
+ *    ---Dan
+ */
+
+#include "ppc_asm.tmpl"
+#include "ppc_defs.h"
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/gemini.h>
+
+#define HID0_ABE (1<<3)
+
+/*
+ *  On 750's the MMU is on when Linux is booted, so we need to clear out the
+ *  bootloader's BAT settings, make sure we're in supervisor state (gotcha!),
+ *  and turn off the MMU.
+ *
+ */
+
+_GLOBAL(gemini_prom_init)
+#ifdef __SMP__
+	/* Since the MMU's on, get stuff in rom space that we'll need */
+	lis	r4,GEMINI_CPUSTAT@h
+	ori	r4,r4,GEMINI_CPUSTAT@l
+	lbz	r5,0(r4)
+	andi.	r5,r5,3
+	mr	r24,r5		/* cpu # used later on */
+#endif
+	mfmsr	r4
+	li	r3,MSR_PR	/* ensure supervisor! */
+	ori	r3,r3,MSR_IR|MSR_DR
+	andc	r4,r4,r3
+	mtmsr	r4
+#if 0
+	/* zero out the bats now that the MMU is off */
+prom_no_mmu:	
+	li	r3,0
+        mtspr   IBAT0U,r3
+        mtspr   IBAT0L,r3
+        mtspr   IBAT1U,r3
+        mtspr   IBAT1L,r3
+        mtspr   IBAT2U,r3
+        mtspr   IBAT2L,r3
+        mtspr   IBAT3U,r3
+        mtspr   IBAT3L,r3
+
+        mtspr   DBAT0U,r3
+        mtspr   DBAT0L,r3
+        mtspr   DBAT1U,r3
+        mtspr   DBAT1L,r3
+        mtspr   DBAT2U,r3
+	mtspr   DBAT2L,r3
+        mtspr   DBAT3U,r3
+        mtspr   DBAT3L,r3
+#endif
+
+	/* the bootloader (as far as I'm currently aware) doesn't mess with page
+	   tables, but since we're already here, might as well zap these, too */
+	li	r4,0
+	mtspr	SDR1,r4
+
+	li	r4,16
+	mtctr	r4
+	li	r3,0
+	li	r4,0
+3:	mtsrin	r3,r4
+	addi	r3,r3,1
+	bdnz	3b
+
+#ifdef __SMP__
+	/* The 750 book (and Mot/IBM support) says that this will "assist" snooping
+	   when in SMP.  Not sure yet whether this should stay or leave... */
+	mfspr	r4,HID0
+	ori	r4,r4,HID0_ABE
+	mtspr	HID0,r4
+	sync
+#endif /* __SMP__ */
+	blr
+
+/*  apparently, SMon doesn't pay attention to HID0[SRST].  Disable the MMU and
+    branch to 0xfff00100 */
+_GLOBAL(_gemini_reboot)
+	lis	r5,GEMINI_BOOT_INIT@h
+	ori	r5,r5,GEMINI_BOOT_INIT@l
+	li	r6,MSR_IP
+	mtspr	SRR0,r5
+	mtspr	SRR1,r6
+	rfi
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/gemini_setup.c linux.14p16/arch/ppc/kernel/gemini_setup.c
--- linux.vanilla/arch/ppc/kernel/gemini_setup.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/ppc/kernel/gemini_setup.c	Thu Dec  9 15:34:30 1999
@@ -0,0 +1,576 @@
+/*
+ *  linux/arch/ppc/kernel/setup.c
+ *
+ *  Copyright (C) 1995 Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  Synergy Microsystems board support by Dan Cox (dan@synergymicro.com)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h> 
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/console.h>
+#include <linux/openpic.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/m48t35.h>
+#include <asm/gemini.h>
+
+#include "time.h"
+#include "local_irq.h"
+#include "open_pic.h"
+
+void gemini_setup_pci_ptrs(void);
+
+static int l2_printed = 0;
+static unsigned char gemini_switch_map = 0;
+static char *gemini_board_families[] = {
+	"VGM", "VSS", "KGM", "VGR", "KSS"
+};
+
+static char *gemini_memtypes[] = {
+	"EDO DRAM, 60nS", "SDRAM, 15nS, CL=2", "SDRAM, 15nS, CL=2 with ECC"
+};
+
+static unsigned int cpu_7xx[16] = {
+	0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
+};
+static unsigned int cpu_6xx[16] = {
+	0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0
+};
+
+void
+gemini_do_IRQ(struct pt_regs *regs, int cpu, int isfake)
+{
+	int irq, openpic_eoi_done = 0;
+#ifdef __SMP__
+	{
+		unsigned int loops = 1000000;
+		while(test_bit(0, &global_irq_lock)) {
+			if (smp_processor_id() == global_irq_holder) {
+				printk("uh oh, it chokes!!! interrupt while we hold irq lock\n");
+				break;
+			}
+			if (loops-- == 0) {
+				printk("do_IRQ waiting for irq lock (holder=%d)\n", 
+				       global_irq_holder);
+			}
+		}
+	}
+#endif
+
+	irq = openpic_irq(cpu);
+	
+	if (irq == OPENPIC_VEC_SPURIOUS ) {
+		ppc_spurious_interrupts++;
+		openpic_eoi_done = 1;
+		goto out;
+	}
+
+	if (irq < 0) {
+		printk(KERN_DEBUG "Bogus interrupt %d from pc=%lx\n", irq,
+		       regs->nip);
+		ppc_spurious_interrupts++;
+	}
+	
+	else
+		ppc_irq_dispatch_handler(regs, irq);
+ out:
+	if (!openpic_eoi_done)
+		openpic_eoi(smp_processor_id());
+}
+
+static inline unsigned long _get_HID1(void)
+{
+	unsigned long val;
+
+	__asm__ __volatile__("mfspr %0,1009" : "=r" (val));
+	return val;
+}
+
+int
+gemini_get_cpuinfo(char *buffer)
+{
+	int i, len;
+	unsigned char reg, rev;
+	char *family;
+	unsigned int type;
+
+	reg = readb(GEMINI_FEAT);
+	family = gemini_board_families[((reg>>4) & 0xf)];
+	if (((reg>>4) & 0xf) > 2)
+		printk(KERN_ERR "cpuinfo(): unable to determine board family\n");
+
+	reg = readb(GEMINI_BREV);
+	type = (reg>>4) & 0xf;
+	rev = reg & 0xf;
+
+	reg = readb(GEMINI_BECO);
+
+	len = sprintf( buffer, "machine\t\t: Gemini %s%d, rev %c, eco %d\n", 
+		       family, type, (rev + 'A'), (reg & 0xf));
+
+	len += sprintf( buffer+len, "vendor\t\t: %s\n", 
+			(_get_PVR() & (1<<15)) ? "IBM" : "Motorola");
+
+	reg = readb(GEMINI_MEMCFG);
+	len += sprintf( buffer+len, "memory type\t: %s\n", 
+			gemini_memtypes[(reg & 0xc0)>>6]);
+	len += sprintf( buffer+len, "switches on\t: ");
+	for( i=0; i < 8; i++ ) {
+		if ( gemini_switch_map & (1<<i))
+			len += sprintf(buffer+len, "%d ", i);
+	}
+	len += sprintf(buffer+len, "\n");
+
+	return len;
+}
+
+static u_char gemini_openpic_initsenses[] = {
+	1,
+	1,
+	1,
+	1,
+	0,
+	0,
+	1, /* remainder are level-triggered */
+};
+
+#define GEMINI_MPIC_ADDR (0xfcfc0000)
+#define GEMINI_MPIC_PCI_CFG (0x80005800)
+
+void __init gemini_openpic_init(void)
+{
+	grackle_write(GEMINI_MPIC_PCI_CFG + PCI_BASE_ADDRESS_0, 
+		      GEMINI_MPIC_ADDR);
+	grackle_write(GEMINI_MPIC_PCI_CFG + PCI_COMMAND, PCI_COMMAND_MEMORY);
+
+	OpenPIC = (volatile struct OpenPIC *) GEMINI_MPIC_ADDR;
+	OpenPIC_InitSenses = gemini_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses );
+
+	ioremap( GEMINI_MPIC_ADDR, sizeof( struct OpenPIC ));
+}
+
+
+extern unsigned long loops_per_sec;
+extern int root_mountflags;
+extern char cmd_line[];
+
+
+void __init
+gemini_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)
+{
+	unsigned int cpu;
+	extern char cmd_line[];
+
+
+	loops_per_sec = 50000000;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* bootable off CDROM */
+	if (initrd_start)
+		ROOT_DEV = MKDEV(SCSI_CDROM_MAJOR, 0);
+	else
+#endif
+		ROOT_DEV = to_kdev_t(0x0801);
+
+	/* nothing but serial consoles... */  
+	sprintf(cmd_line, "%s console=ttyS0", cmd_line);
+
+
+	/* The user switches on the front panel can be used as follows:
+
+	   Switch 0 - adds "debug" to the command line for verbose boot info,
+	   Switch 7 - boots in single-user mode 
+
+	*/
+
+	gemini_switch_map = readb( GEMINI_USWITCH );
+  
+	if ( gemini_switch_map & (1<<GEMINI_SWITCH_VERBOSE))
+		sprintf(cmd_line, "%s debug", cmd_line);
+
+	if ( gemini_switch_map & (1<<GEMINI_SWITCH_SINGLE_USER))
+		sprintf(cmd_line, "%s single", cmd_line);
+
+	printk("Boot arguments: %s\n", cmd_line);
+
+	/* mutter some kind words about who made the CPU */
+	cpu = _get_PVR();
+	printk("CPU manufacturer: %s [rev=%04x]\n", (cpu & (1<<15)) ? "IBM" :
+	       "Motorola", (cpu & 0xffff));
+
+	/* take special pains to map the MPIC, since it isn't mapped yet */
+	gemini_openpic_init();
+
+	/* start the L2 */
+	gemini_init_l2();
+
+}
+
+
+int
+gemini_get_clock_speed(void)
+{
+	unsigned long hid1;
+	int clock;
+	unsigned char reg;
+  
+	hid1 = _get_HID1();
+	if ((_get_PVR()>>16) == 8)
+		hid1 = cpu_7xx[hid1];
+	else
+		hid1 = cpu_6xx[hid1];
+
+	reg = readb(GEMINI_BSTAT) & 0xc0;
+
+	switch( reg >> 2 ) {
+
+	case 0:
+	default:
+		clock = (hid1*100)/3;
+		break;
+  
+	case 1:
+		clock = (hid1*125)/3;
+		break;
+  
+	case 2:
+		clock = (hid1*50)/3;
+		break;
+	}
+
+	return clock;
+}
+
+
+#define L2CR_PIPE_LATEWR   (0x01800000)   /* late-write SRAM */
+#define L2CR_L2CTL         (0x00100000)   /* RAM control */
+#define L2CR_INST_DISABLE  (0x00400000)   /* disable for insn's */
+#define L2CR_L2I           (0x00200000)   /* global invalidate */
+#define L2CR_L2E           (0x80000000)   /* enable */
+#define L2CR_L2WT          (0x00080000)   /* write-through */
+
+void __init gemini_init_l2(void)
+{
+	unsigned char reg;
+	unsigned long cache;
+	int speed;
+
+	reg = readb(GEMINI_L2CFG);
+
+	/* 750's L2 initializes differently from a 604's.  Also note that a Grackle
+	   bug will hang a dual-604 board, so make sure that doesn't happen by not
+	   turning on the L2 */
+	if ( _get_PVR() >> 16 != 8 ) {
+     
+		/* check for dual cpus and cry sadly about the loss of an L2... */
+		if ((( readb(GEMINI_CPUSTAT) & 0x0c ) >> 2) != 1) 
+			printk("Sorry. Your dual-604 does not allow the L2 to be enabled due "
+			       "to a Grackle bug.\n");
+		else if ( reg & GEMINI_L2_SIZE_MASK ) {
+			printk("Enabling 604 L2 cache: %dKb\n", 
+			       (128<<((reg & GEMINI_L2_SIZE_MASK)>>6)));
+			writeb( 1, GEMINI_L2CFG );
+		}
+	}
+
+	/* do a 750 */
+	else {
+		/* Synergy's first round of 750 boards had the L2 size stuff into the
+		   board register above.  If it's there, it's used; if not, the
+		   standard default is 1Mb.  The L2 type, I'm told, is "most likely
+		   probably always going to be late-write".  --Dan */
+
+		if (reg & 0xc0) {
+			if (!l2_printed) {
+				printk("Enabling 750 L2 cache: %dKb\n", 
+				       (128 << ((reg & 0xc0)>>6)));
+				l2_printed=1;
+			}
+    
+			/* take the size given */
+			cache = (((reg>>6) & 0x3)<<28);
+		}
+		else
+			/* default of 1Mb */
+			cache = 0x3<<28;
+ 
+		reg &= 0x3;
+
+		/* a cache ratio of 1:1 and CPU clock speeds in excess of 300Mhz are bad
+		   things.  If found, tune it down to 1:1.5.  -- Dan */
+		if (!reg) {
+
+			speed = gemini_get_clock_speed();
+   
+			if (speed >= 300) {
+				printk("Warning:  L2 ratio is 1:1 on a %dMhz processor.  Dropping to 1:1.5.\n",
+				       speed );
+				printk("Contact Synergy Microsystems for an ECO to fix this problem\n");
+				reg = 0x1;
+			}
+		}
+
+		/* standard stuff */
+		cache |= ((1<<reg)<<25);
+#ifdef __SMP__
+		/* A couple errata for the 750's (both IBM and Motorola silicon)
+		   note that you can get missed cache lines on MP implementations.
+		   The workaround - if you call it that - is to make the L2
+		   write-through.  This is fixed in IBM's 3.1 rev (I'm told), but
+		   for now, always make 2.x versions use L2 write-through. --Dan */
+		if (((_get_PVR()>>8) & 0xf) <= 2)
+			cache |= L2CR_L2WT;
+#endif
+		cache |= L2CR_PIPE_LATEWR|L2CR_L2CTL|L2CR_INST_DISABLE;
+		_set_L2CR(0);
+		_set_L2CR(cache|L2CR_L2I|L2CR_L2E);
+	}
+}
+
+void
+gemini_restart(char *cmd)
+{
+	__cli();
+	/* make a clean restart, not via the MPIC */
+	_gemini_reboot();
+	for(;;);
+}
+
+void
+gemini_power_off(void)
+{
+	for(;;);
+}
+
+void
+gemini_halt(void)
+{
+	gemini_restart(NULL);
+}
+
+void __init gemini_init_IRQ(void)
+{
+	int i;
+
+	/* gemini has no 8259 */
+	open_pic.irq_offset = 0;
+	for( i=0; i < NR_IRQS; i++ ) 
+		irq_desc[i].ctl = &open_pic;
+	openpic_init(1);
+#ifdef __SMP__
+	request_irq(OPENPIC_VEC_IPI, openpic_ipi_action,
+		    0, "IPI0", 0);
+	request_irq(OPENPIC_VEC_IPI+1, openpic_ipi_action,
+		    0, "IPI1 (invalidate TLB)", 0);
+	request_irq(OPENPIC_VEC_IPI+2, openpic_ipi_action,
+		    0, "IPI2 (stop CPU)", 0);
+	request_irq(OPENPIC_VEC_IPI+3, openpic_ipi_action,
+		    0, "IPI3 (reschedule)", 0);
+#endif	/* __SMP__ */
+}
+
+#define gemini_rtc_read(x)       (readb(GEMINI_RTC+(x)))
+#define gemini_rtc_write(val,x)  (writeb((val),(GEMINI_RTC+(x))))
+
+/* ensure that the RTC is up and running */
+void __init gemini_time_init(void)
+{
+	unsigned char reg;
+
+	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
+
+	if ( reg & M48T35_RTC_STOPPED ) {
+		printk(KERN_INFO "M48T35 real-time-clock was stopped. Now starting...\n");
+		gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL);
+		gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL);
+	}
+}
+
+#undef DEBUG_RTC
+
+unsigned long
+gemini_get_rtc_time(void)
+{
+	unsigned int year, mon, day, hour, min, sec;
+	unsigned char reg;
+
+	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
+	gemini_rtc_write((reg|M48T35_RTC_READ), M48T35_RTC_CONTROL);
+#ifdef DEBUG_RTC
+	printk("get rtc: reg = %x\n", reg);
+#endif
+  
+	do {
+		sec = gemini_rtc_read(M48T35_RTC_SECONDS);
+		min = gemini_rtc_read(M48T35_RTC_MINUTES);
+		hour = gemini_rtc_read(M48T35_RTC_HOURS);
+		day = gemini_rtc_read(M48T35_RTC_DOM);
+		mon = gemini_rtc_read(M48T35_RTC_MONTH);
+		year = gemini_rtc_read(M48T35_RTC_YEAR);
+	} while( sec != gemini_rtc_read(M48T35_RTC_SECONDS));
+#ifdef DEBUG_RTC
+	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", 
+	       sec, min, hour, day, mon, year);
+#endif
+
+	gemini_rtc_write(reg, M48T35_RTC_CONTROL);
+
+	BCD_TO_BIN(sec);
+	BCD_TO_BIN(min);
+	BCD_TO_BIN(hour);
+	BCD_TO_BIN(day);
+	BCD_TO_BIN(mon);
+	BCD_TO_BIN(year);
+
+	if ((year += 1900) < 1970)
+		year += 100;
+#ifdef DEBUG_RTC
+	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", 
+	       sec, min, hour, day, mon, year);
+#endif
+
+	return mktime( year, mon, day, hour, min, sec );
+}
+
+
+int
+gemini_set_rtc_time( unsigned long now )
+{
+	unsigned char reg;
+	struct rtc_time tm;
+
+	to_tm( now, &tm );
+
+	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
+#if DEBUG_RTC
+	printk("set rtc: reg = %x\n", reg);
+#endif
+  
+	gemini_rtc_write((reg|M48T35_RTC_SET), M48T35_RTC_CONTROL);
+#if DEBUG_RTC
+	printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
+	       tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
+#endif
+  
+	tm.tm_year -= 1900;
+	BIN_TO_BCD(tm.tm_sec);
+	BIN_TO_BCD(tm.tm_min);
+	BIN_TO_BCD(tm.tm_hour);
+	BIN_TO_BCD(tm.tm_mon);
+	BIN_TO_BCD(tm.tm_mday);
+	BIN_TO_BCD(tm.tm_year);
+#ifdef DEBUG_RTC
+	printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
+	       tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
+#endif
+
+	gemini_rtc_write(tm.tm_sec, M48T35_RTC_SECONDS);
+	gemini_rtc_write(tm.tm_min, M48T35_RTC_MINUTES);
+	gemini_rtc_write(tm.tm_hour, M48T35_RTC_HOURS);
+	gemini_rtc_write(tm.tm_mday, M48T35_RTC_DOM);
+	gemini_rtc_write(tm.tm_mon, M48T35_RTC_MONTH);
+	gemini_rtc_write(tm.tm_year, M48T35_RTC_YEAR);
+
+	/* done writing */
+	gemini_rtc_write(reg, M48T35_RTC_CONTROL);
+
+	if ((time_state == TIME_ERROR) || (time_state == TIME_BAD))
+		time_state = TIME_OK;
+  
+	return 0;
+}
+
+/*  use the RTC to determine the decrementer count */
+void __init gemini_calibrate_decr(void)
+{
+	int freq, divisor;
+	unsigned char reg;
+
+	/* determine processor bus speed */
+	reg = readb(GEMINI_BSTAT);
+
+	switch(((reg & 0x0c)>>2)&0x3) {
+	case 0:
+	default:
+		freq = 66;
+		break;
+	case 1:
+		freq = 83;
+		break;
+	case 2:
+		freq = 100;
+		break;
+	}
+
+	freq *= 1000000;
+	divisor = 4;
+	decrementer_count = freq / HZ / divisor;
+	count_period_num = divisor;
+	count_period_den = freq / 1000000;
+}
+
+
+void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5,
+			unsigned long r6, unsigned long r7)
+{
+	void layout_bus( struct pci_bus * );
+
+	gemini_setup_pci_ptrs();
+
+	ISA_DMA_THRESHOLD = 0;
+	DMA_MODE_READ = 0;
+	DMA_MODE_WRITE = 0;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if ( r4 )
+	{
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif
+
+	ppc_md.setup_arch = gemini_setup_arch;
+	ppc_md.setup_residual = NULL;
+	ppc_md.get_cpuinfo = gemini_get_cpuinfo;
+	ppc_md.irq_cannonicalize = NULL;
+	ppc_md.init_IRQ = gemini_init_IRQ;
+	ppc_md.do_IRQ = gemini_do_IRQ;
+	ppc_md.init = NULL;
+
+	ppc_md.restart = gemini_restart;
+	ppc_md.power_off = gemini_power_off;
+	ppc_md.halt = gemini_halt;
+
+	ppc_md.time_init = gemini_time_init;
+	ppc_md.set_rtc_time = gemini_set_rtc_time;
+	ppc_md.get_rtc_time = gemini_get_rtc_time;
+	ppc_md.calibrate_decr = gemini_calibrate_decr;
+
+	/* no keyboard/mouse/video stuff yet.. */
+	ppc_md.kbd_setkeycode = NULL;
+	ppc_md.kbd_getkeycode = NULL;
+	ppc_md.kbd_translate = NULL;
+	ppc_md.kbd_unexpected_up = NULL;
+	ppc_md.kbd_leds = NULL;
+	ppc_md.kbd_init_hw = NULL;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.ppc_kbd_sysrq_xlate = NULL;
+#endif
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/head.S linux.14p16/arch/ppc/kernel/head.S
--- linux.vanilla/arch/ppc/kernel/head.S	Sat Aug 28 20:00:53 1999
+++ linux.14p16/arch/ppc/kernel/head.S	Thu Dec  9 15:34:29 1999
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/head.S
  *
- *  $Id: head.S,v 1.130.2.3 1999/08/10 21:36:48 cort Exp $
+ *  $Id: head.S,v 1.130.2.6 1999/10/12 01:03:34 cort Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -97,21 +97,12 @@
 	bdnz	0b
 #endif
 
-#ifdef CONFIG_PPC64
+/* 601 only have IBAT cr0.eq is set on 601 when using this macro */ 
 #define LOAD_BAT(n, offset, reg, RA, RB) \
-	ld	RA,offset+0(reg);	\
-	ld	RB,offset+8(reg);	\
+	/* see the comment for clear_bats() -- Cort */ \
+	li	RA,0;			\
 	mtspr	IBAT##n##U,RA;		\
-	mtspr	IBAT##n##L,RB;		\
-	ld	RA,offset+16(reg);	\
-	ld	RB,offset+24(reg);	\
 	mtspr	DBAT##n##U,RA;		\
-	mtspr	DBAT##n##L,RB;		\
-	
-#else /* CONFIG_PPC64 */
-	
-/* 601 only have IBAT cr0.eq is set on 601 when using this macro */ 
-#define LOAD_BAT(n, offset, reg, RA, RB) \
 	lwz	RA,offset+0(reg);	\
 	lwz	RB,offset+4(reg);	\
 	mtspr	IBAT##n##U,RA;		\
@@ -122,7 +113,6 @@
 	mtspr	DBAT##n##U,RA;		\
 	mtspr	DBAT##n##L,RB;		\
 1:	
-#endif /* CONFIG_PPC64 */	 
 
 #ifndef CONFIG_APUS
 #define tophys(rd,rs,rt)	addis	rd,rs,-KERNELBASE@h
@@ -149,7 +139,15 @@
 	.text
 	.globl	_start
 _start:
-	.long	TOPHYS(__start),0,0
+	/* 
+	 * These are here for legacy reasons, the kernel used to
+	 * need to look like a coff function entry for the pmac
+	 * but we're always started by some kind of bootloader now.
+	 *  -- Cort
+	 */
+	nop
+	nop
+	nop
 
 /* PMAC
  * Enter here with the kernel text, data and bss loaded starting at
@@ -220,16 +218,6 @@
 	
 	.globl	__start
 __start:
-#ifdef CONFIG_PPC64
-/* 
- * Go into 32-bit mode to boot.  OF should do this for
- * us already but just in case...
- * -- Cort 
- */
-	mfmsr	r10
-	clrldi	r10,r10,3
-	mtmsr	r10
-#endif	
 /*
  * We have to do any OF calls before we map ourselves to KERNELBASE,
  * because OF may have I/O devices mapped in in that area
@@ -245,13 +233,16 @@
 	bl	prom_init
 	.globl	__secondary_start
 __secondary_start:
-/*
- * Use the first pair of BAT registers to map the 1st 16MB
+/* Switch MMU off, clear BATs and flush TLB */
+ 	bl	mmu_off
+	bl	clear_bats
+	bl	flush_tlbs
+
+/* Use the first pair of BAT registers to map the 1st 16MB
  * of RAM to KERNELBASE.  From this point on we can't safely
  * call OF any more.
  */
 	lis	r11,KERNELBASE@h
-#ifndef CONFIG_PPC64
 	mfspr	r9,PVR
 	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
 	cmpi	0,r9,1
@@ -265,7 +256,6 @@
 	mtspr	IBAT1U,r9
 	mtspr	IBAT1L,r10
 	b	5f
-#endif /* CONFIG_PPC64 */
 4:
 #ifdef CONFIG_APUS
 	ori	r11,r11,BL_8M<<2|0x2	/* set up an 8MB mapping */
@@ -277,14 +267,10 @@
 #else	
 	ori	r11,r11,BL_256M<<2|0x2	/* set up BAT registers for 604 */
 	li	r8,2			/* R/W access */
-#ifdef CONFIG_PPC64
-	/* clear out the high 32 bits in the BAT */
-	clrldi	r11,r11,32
-	clrldi	r8,r8,32
-	/* turn off the pagetable mappings just in case */
-	clrldi	r16,r16,63
-	mtsdr1	r16
-#else /* CONFIG_PPC64 */
+	/*
+	 * If the MMU is off clear the bats.  See clear_bat() -- Cort
+	 */
+#ifndef CONFIG_GEMINI	
 	/* 
 	 * allow secondary cpus to get at all of ram in early bootup
 	 * since their init_task may be up there -- Cort
@@ -302,14 +288,13 @@
 	mtspr	DBAT2U,r21		/* bit in upper BAT register */
 	mtspr	IBAT2L,r18
 	mtspr	IBAT2U,r21
-#endif /* CONFIG_PPC64 */
+#endif /* ndef CONFIG_GEMINI */	
 #endif
 	mtspr	DBAT0L,r8		/* N.B. 6xx (not 601) have valid */
 	mtspr	DBAT0U,r11		/* bit in upper BAT register */
 	mtspr	IBAT0L,r8
 	mtspr	IBAT0U,r11
 5:	isync
-
 #ifdef CONFIG_APUS
 	/* Unfortunately the APUS specific instructions bloat the
 	 * code so it cannot fit in the 0x100 bytes available. We have
@@ -499,7 +484,12 @@
 
 /* System reset */
 #ifdef CONFIG_SMP /* MVME/MTX start the secondary here */
+#ifdef CONFIG_GEMINI
+	. = 0x100
+	b	__secondary_start_gemini
+#else /* CONFIG_GEMINI */
 	STD_EXCEPTION(0x100, Reset, __secondary_start_psurge)
+#endif /* CONFIG_GEMINI */
 #else
 	STD_EXCEPTION(0x100, Reset, UnknownException)
 #endif	
@@ -1269,6 +1259,7 @@
 	.globl	hash_page
 hash_page:
 #ifdef __SMP__
+	SAVE_2GPRS(7,r21)
 	eieio
 	lis	r2,hash_table_lock@h
 	ori	r2,r2,hash_table_lock@l
@@ -1282,10 +1273,18 @@
 	bne-	12f
 	stwcx.	r0,0,r2
 	beq+	11f
-12:	cmpw	r6,r0
+	/* spin here a bit */
+12:	mfctr	r7
+	li	r8,1000
+	mtctr	r8
+13:
+	bdnz	13b
+	mtctr	r7
+	cmpw	r6,r0
 	bdnzf	2,10b
 	tw	31,31,31
 11:	eieio
+	REST_2GPRS(7, r21)
 #endif
 	/* Get PTE (linux-style) and check access */
 	lwz	r5,PG_TABLES(r5)		
@@ -1312,7 +1311,6 @@
 #else
 	bnelr-
 #endif
-
 	ori	r6,r6,0x100		/* set _PAGE_ACCESSED in pte */
 	rlwinm	r5,r4,5,24,24		/* _PAGE_RW access -> _PAGE_DIRTY */
 	rlwimi	r5,r4,7,22,22		/* _PAGE_RW -> _PAGE_HWWRITE */
@@ -1320,11 +1318,6 @@
 	stw	r6,0(r2)		/* update PTE (accessed/dirty bits) */
 
 	/* Convert linux-style PTE to low word of PPC-style PTE */
-#ifdef CONFIG_PPC64
-	/* clear the high 32 bits just in case */
-	clrldi	r6,r6,32
-	clrldi	r4,r4,32
-#endif /* CONFIG_PPC64 */
 	rlwinm	r4,r6,32-9,31,31	/* _PAGE_HWWRITE -> PP lsb */
 	rlwimi	r6,r6,32-1,31,31	/* _PAGE_USER -> PP (both bits now) */
 	ori	r4,r4,0xe04		/* clear out reserved bits */
@@ -1332,34 +1325,17 @@
 
 	/* Construct the high word of the PPC-style PTE */
 	mfsrin	r5,r3			/* get segment reg for segment */
-#ifdef CONFIG_PPC64
-	sldi	r5,r5,12
-#else /* CONFIG_PPC64 */
 	rlwinm	r5,r5,7,1,24		/* put VSID in 0x7fffff80 bits */
-#endif /* CONFIG_PPC64 */
 	
 #ifndef __SMP__				/* do this later for SMP */
-#ifdef CONFIG_PPC64
-	ori	r5,r5,1			/* set V (valid) bit */
-#else /* CONFIG_PPC64 */
 	oris	r5,r5,0x8000		/* set V (valid) bit */
-#endif /* CONFIG_PPC64 */
 #endif
 	
-#ifdef CONFIG_PPC64
-/* XXX:	 does this insert the api correctly? -- Cort */
-	rlwimi	r5,r3,17,21,25		/* put in API (abbrev page index) */
-#else /* CONFIG_PPC64 */
 	rlwimi	r5,r3,10,26,31		/* put in API (abbrev page index) */
-#endif /* CONFIG_PPC64 */
 	/* Get the address of the primary PTE group in the hash table */
 	.globl	hash_page_patch_A
 hash_page_patch_A:
 	lis	r4,Hash_base@h		/* base address of hash table */
-#ifdef CONFIG_PPC64
-	/* just in case */
-	clrldi	r4,r4,32
-#endif	
 	rlwimi	r4,r5,32-1,26-Hash_bits,25	/* (VSID & hash_mask) << 6 */
 	rlwinm	r0,r3,32-6,26-Hash_bits,25	/* (PI & hash_mask) << 6 */
 	xor	r4,r4,r0		/* make primary hash */
@@ -1662,6 +1638,19 @@
 	blr
 #endif /* CONFIG_8xx */
 
+mmu_off:
+ 	addi	r4, r3, __secondary_start - _start
+	mfmsr	r3
+	andi.	r0,r3,MSR_DR|MSR_IR		/* MMU enabled? */
+	beq	1f
+	ori	r3,r3,MSR_DR|MSR_IR
+	xori	r3,r3,MSR_DR|MSR_IR
+	mtspr	SRR0,r4
+	mtspr	SRR1,r3
+	sync
+	rfi
+1:	blr
+
 /*
  * This code is jumped to from the startup code to copy
  * the kernel image to physical address 0.
@@ -1671,8 +1660,10 @@
 	addi	r9,r9,0x6f58		/* translate source addr */
 	cmpw	r31,r9			/* (we have to on chrp) */
 	beq	7f
+#if 0 // still needed ? breaks on me if I don't disable this
 	rlwinm	r4,r4,0,8,31		/* translate source address */
 	add	r4,r4,r3		/* to region mapped with BATs */
+#endif	
 7:	addis	r9,r26,klimit@ha	/* fetch klimit */
 	lwz	r25,klimit@l(r9)
 	addis	r25,r25,-KERNELBASE@h
@@ -1724,33 +1715,26 @@
 	mfmsr	r0
 	ori	r1,r0,MSR_DR|MSR_IR
 	mtspr	SRR1,r1
-#ifdef CONFIG_SMP
-	/* see the function start_here_ibm_hack for explanation -- Cort */
-	andi.	0,r1,MSR_DR	/* check if the MMU is already on */
-	bne	10f
-	lis	r5,smp_ibm_chrp_hack@h
-	ori	r5,r5,smp_ibm_chrp_hack@l
-	tophys(r5,r5,r6)
-	lwz	r5,0(r5)
-	cmpi	0,r5,0
-	beq	10f
-	lis	r5,first_cpu_booted@h
-	ori	r5,r5,first_cpu_booted@l
-	tophys(r5,r5,r6)
-	lwz	r5,0(r5)
-	cmpi	0,r5,0
-	beq	10f
-	lis	r0,start_here_ibm_hack@h
-	ori	r0,r0,start_here_ibm_hack@l
-	b	1010f
-10:	
-#endif /* CONFIG_SMP */
 	lis	r0,start_here@h
 	ori	r0,r0,start_here@l
-1010:	mtspr	SRR0,r0
+	mtspr	SRR0,r0
 	SYNC
 	rfi				/* enables MMU */
 
+#ifdef CONFIG_GEMINI
+	.globl	__secondary_start_gemini
+__secondary_start_gemini:
+        mfspr   r4,HID0
+        ori     r4,r4,HID0_ICFI
+        li      r3,0
+        ori     r3,r3,HID0_ICE
+        andc    r4,r4,r3
+        mtspr   HID0,r4
+        sync
+        bl      prom_init
+        b       __secondary_start
+#endif /* CONFIG_GEMINI */
+
 #ifdef CONFIG_SMP
 	.globl	__secondary_start_psurge
 __secondary_start_psurge:
@@ -1780,25 +1764,6 @@
 	blr
 #endif /* CONFIG_SMP */
 	
-/* 
- * We get _strange_ behavior on the new IBM chrp firmware.
- * We end up here with the MMU disabled, even though we enable
- * it with the rfi that takes us here.  Somehow, a physical address
- * access fixes this by enabling the MMU.
- *
- * The IBM engineers can't explain this behavior and AIX doesn't 
- * seem to find it.  This hack gets around it for now.
- *          -- Cort
- */
-start_here_ibm_hack:
-	mfmsr	r1
-	lis	r5,smp_ibm_chrp_hack@h
-	ori	r5,r5,smp_ibm_chrp_hack@l
-	tophys(r5,r5,r6)
-	mfmsr	r1
-	stw	r1,_MSR-16(r5)
-	addi	r5,r5,_MSR-16
-	dcbf	0,r5
 #ifndef CONFIG_8xx
 start_here:
 	/*
@@ -1895,11 +1860,7 @@
  */
 #ifndef CONFIG_8xx
 	lis	r6,_SDR1@ha
-#ifdef CONFIG_PPC64	
-	ld	r6,_SDR1@l(r6)
-#else
 	lwz	r6,_SDR1@l(r6)
-#endif		
 #else
 	/* The right way to do this would be to track it down through
 	 * init's TSS like the context switch code does, but this is
@@ -1928,14 +1889,6 @@
 #endif
 #ifndef CONFIG_8xx
 	mtspr	SDR1,r6
-#ifdef CONFIG_PPC64
-	/* clear the v bit in the ASR so we can
-	 * behave as if we have segment registers 
-	 * -- Cort
-	 */
-	clrldi	r6,r6,63
-	mtasr	r6
-#endif /* CONFIG_PPC64 */
 	li	r0,16		/* load up segment register values */
 	mtctr	r0		/* for context 0 */
 	lis	r3,0x2000	/* Ku = 1, VSID = 0 */
@@ -1952,17 +1905,10 @@
 	lis	r3,BATS@ha
 	addi	r3,r3,BATS@l
 	tophys(r3,r3,r4)
-#ifdef CONFIG_PPC64
-	LOAD_BAT(0,0,r3,r4,r5)
-	LOAD_BAT(1,32,r3,r4,r5)
-	LOAD_BAT(2,64,r3,r4,r5)
-	LOAD_BAT(3,96,r3,r4,r5)
-#else /* CONFIG_PPC64 */
 	LOAD_BAT(0,0,r3,r4,r5)
 	LOAD_BAT(1,16,r3,r4,r5)
 	LOAD_BAT(2,32,r3,r4,r5)
 	LOAD_BAT(3,48,r3,r4,r5)
-#endif /* CONFIG_PPC64 */
 #endif /* CONFIG_8xx */
 /* Set up for using our exception vectors */
 	/* ptr to phys current tss */
@@ -2733,3 +2679,48 @@
 	.globl	cmd_line
 cmd_line:
 	.space	512
+
+/* 
+ * An undocumented "feature" of 604e requires that the v bit
+ * be cleared before changing BAT values.
+ *
+ * Also, newer IBM firmware does not clear bat3 and 4 so
+ * this makes sure it's done.
+ *  -- Cort 
+ */
+clear_bats:
+#if !defined(CONFIG_GEMINI)
+	li	r20,0
+	mfspr	r9,PVR
+	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
+	cmpwi	r9, 1
+	beq	1f
+	
+	mtspr	DBAT0U,r20
+	mtspr	DBAT0L,r20	
+	mtspr	DBAT1U,r20
+	mtspr	DBAT1L,r20
+	mtspr	DBAT2U,r20
+	mtspr	DBAT2L,r20	
+	mtspr	DBAT3U,r20
+	mtspr	DBAT3L,r20
+1:	
+	mtspr	IBAT0U,r20
+	mtspr	IBAT0L,r20
+	mtspr	IBAT1U,r20
+	mtspr	IBAT1L,r20
+	mtspr	IBAT2U,r20
+	mtspr	IBAT2L,r20
+	mtspr	IBAT3U,r20
+	mtspr	IBAT3L,r20
+#endif /* !defined(CONFIG_GEMINI) */
+	blr
+
+flush_tlbs:
+	lis	r20, 0x1000
+1:	addic.	r20, r20, -0x1000
+	tlbie	r20
+	blt	1b
+	sync
+	blr
+	
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/irq.c linux.14p16/arch/ppc/kernel/irq.c
--- linux.vanilla/arch/ppc/kernel/irq.c	Sat Aug 28 20:00:53 1999
+++ linux.14p16/arch/ppc/kernel/irq.c	Thu Dec  9 15:34:29 1999
@@ -94,8 +94,8 @@
  * this needs to be removed.
  * -- Cort
  */
-static char cache_bitmask = 0;
-static struct irqaction malloc_cache[8];
+static unsigned long cache_bitmask[1];
+static struct irqaction malloc_cache[32];
 extern int mem_init_done;
 
 void *irq_kmalloc(size_t size, int pri)
@@ -103,10 +103,10 @@
 	unsigned int i;
 	if ( mem_init_done )
 		return kmalloc(size,pri);
-	for ( i = 0; i <= 3 ; i++ )
-		if ( ! ( cache_bitmask & (1<<i) ) )
+	for ( i = 0; i < 32 ; i++ )
+		if ( ! (test_bit(i, (void *)cache_bitmask)) )
 		{
-			cache_bitmask |= (1<<i);
+			set_bit(i,(void *)cache_bitmask);
 			return (void *)(&malloc_cache[i]);
 		}
 	return 0;
@@ -115,10 +115,10 @@
 void irq_kfree(void *ptr)
 {
 	unsigned int i;
-	for ( i = 0 ; i <= 3 ; i++ )
+	for ( i = 0 ; i < 32 ; i++ )
 		if ( ptr == &malloc_cache[i] )
 		{
-			cache_bitmask &= ~(1<<i);
+			clear_bit( i, (void *)cache_bitmask );
 			return;
 		}
 	kfree(ptr);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/open_pic.c linux.14p16/arch/ppc/kernel/open_pic.c
--- linux.vanilla/arch/ppc/kernel/open_pic.c	Sat Aug 14 02:26:13 1999
+++ linux.14p16/arch/ppc/kernel/open_pic.c	Thu Dec  9 15:34:30 1999
@@ -10,30 +10,30 @@
 #ifdef __SMP__
 void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
 {
-	smp_message_recv();
+	smp_message_recv(cpl-OPENPIC_VEC_IPI);
 }
 #endif /* __SMP__ */
 
 void chrp_mask_and_ack_irq(unsigned int irq_nr)
 {
-	if (is_8259_irq(irq_nr))
-	    i8259_pic.mask_and_ack(irq_nr);
+	if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr))
+		i8259_pic.mask_and_ack(irq_nr);
 }
 
 static void chrp_mask_irq(unsigned int irq_nr)
 {
-	if (is_8259_irq(irq_nr))
+	if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr))
 		i8259_pic.disable(irq_nr);
 	else
-		openpic_disable_irq(irq_to_openpic(irq_nr));
+		openpic_disable_irq(irq_nr-open_pic.irq_offset);
 }
 
 static void chrp_unmask_irq(unsigned int irq_nr)
 {
-	if (is_8259_irq(irq_nr))
+	if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr))
 		i8259_pic.enable(irq_nr);
 	else
-		openpic_enable_irq(irq_to_openpic(irq_nr));
+		openpic_enable_irq(irq_nr-open_pic.irq_offset);
 }
 
 struct hw_interrupt_type open_pic = {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/open_pic.h linux.14p16/arch/ppc/kernel/open_pic.h
--- linux.vanilla/arch/ppc/kernel/open_pic.h	Sat Aug 14 02:26:13 1999
+++ linux.14p16/arch/ppc/kernel/open_pic.h	Thu Dec  9 15:34:30 1999
@@ -7,5 +7,7 @@
 extern struct hw_interrupt_type open_pic;
 
 void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
+void openpic_enable_IPI(u_int ipi);
+void do_openpic_setup_cpu(void);
 
 #endif /* _PPC_KERNEL_OPEN_PIC_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/openpic.c linux.14p16/arch/ppc/kernel/openpic.c
--- linux.vanilla/arch/ppc/kernel/openpic.c	Sat Aug 14 02:26:13 1999
+++ linux.14p16/arch/ppc/kernel/openpic.c	Thu Dec  9 15:34:29 1999
@@ -3,17 +3,14 @@
  *
  *  Copyright (C) 1997 Geert Uytterhoeven
  *
+ *  Fixed up IPI and restructured a bit
+ *    Cort Dougan <cort@ppc.kernel.org>
+ * 
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License.  See the file COPYING in the main directory of this archive
  *  for more details.
  */
 
-
-/*
- *  Note: Interprocessor Interrupt (IPI) and Timer support is incomplete
- */
-
-
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -23,12 +20,11 @@
 #include <asm/signal.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-
+#include "open_pic.h"
 
 #define REGISTER_DEBUG
 #undef REGISTER_DEBUG
 
-
 volatile struct OpenPIC *OpenPIC = NULL;
 u_int OpenPIC_NumInitSenses __initdata = 0;
 u_char *OpenPIC_InitSenses __initdata = NULL;
@@ -36,11 +32,6 @@
 static u_int NumProcessors;
 static u_int NumSources;
 
-
-    /*
-     *  Accesses to the current processor's registers
-     */
-
 #ifndef __powerpc__
 #define THIS_CPU		Private
 #define CHECK_THIS_CPU		do {} while (0)
@@ -49,11 +40,6 @@
 #define CHECK_THIS_CPU		check_arg_cpu(cpu)
 #endif
 
-
-    /*
-     *  Sanity checks
-     */
-
 #if 1
 #define check_arg_ipi(ipi) \
     if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
@@ -67,9 +53,14 @@
 #define check_arg_pri(pri) \
     if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
 	printk("openpic.c:%d: illegal priority %d\n", __LINE__, pri);
+/*
+ * I changed this to return to keep us from from trying to use irq #'s
+ * that we're using for IPI's.
+ *   -- Cort
+ */ 
 #define check_arg_irq(irq) \
     if (irq < 0 || irq >= NumSources) \
-	printk("openpic.c:%d: illegal irq %d\n", __LINE__, irq);
+	/*printk("openpic.c:%d: illegal irq %d\n", __LINE__, irq);*/return;
 #define check_arg_cpu(cpu) \
     if (cpu < 0 || cpu >= NumProcessors) \
 	printk("openpic.c:%d: illegal cpu %d\n", __LINE__, cpu);
@@ -82,252 +73,229 @@
 #define check_arg_cpu(cpu)	do {} while (0)
 #endif
 
-
-    /*
-     *  Dummy interrupt handler
-     */
-
 static void no_action(int ir1, void *dev, struct pt_regs *regs)
 {}
 
-
-    /*
-     *  I/O functions
-     */
-
+/*
+ *  I/O functions
+ */
 #ifdef __i386__
 static inline u_int ld_le32(volatile u_int *addr)
 {
-    return *addr;
+	return *addr;
 }
 
 static inline void out_le32(volatile u_int *addr, u_int val)
 {
-    *addr = val;
+	*addr = val;
 }
 #endif
 
 u_int openpic_read(volatile u_int *addr)
 {
-    u_int val;
+	u_int val;
 
-    val = ld_le32(addr);
+	val = ld_le32(addr);
 #ifdef REGISTER_DEBUG
-    printk("openpic_read(0x%08x) = 0x%08x\n", (u_int)addr, val);
+	printk("openpic_read(0x%08x) = 0x%08x\n", (u_int)addr, val);
 #endif
-    return val;
+	return val;
 }
 
 static inline void openpic_write(volatile u_int *addr, u_int val)
 {
 #ifdef REGISTER_DEBUG
-    printk("openpic_write(0x%08x, 0x%08x)\n", (u_int)addr, val);
+	printk("openpic_write(0x%08x, 0x%08x)\n", (u_int)addr, val);
 #endif
-    out_le32(addr, val);
+	out_le32(addr, val);
 }
 
-
 static inline u_int openpic_readfield(volatile u_int *addr, u_int mask)
 {
-    u_int val = openpic_read(addr);
-    return val & mask;
+	u_int val = openpic_read(addr);
+	return val & mask;
 }
 
 inline void openpic_writefield(volatile u_int *addr, u_int mask,
-				      u_int field)
+			       u_int field)
 {
-    u_int val = openpic_read(addr);
-    openpic_write(addr, (val & ~mask) | (field & mask));
+	u_int val = openpic_read(addr);
+	openpic_write(addr, (val & ~mask) | (field & mask));
 }
 
 static inline void openpic_clearfield(volatile u_int *addr, u_int mask)
 {
-    openpic_writefield(addr, mask, 0);
+	openpic_writefield(addr, mask, 0);
 }
 
 static inline void openpic_setfield(volatile u_int *addr, u_int mask)
 {
-    openpic_writefield(addr, mask, mask);
+	openpic_writefield(addr, mask, mask);
 }
 
-
-    /*
-     *  Update a Vector/Priority register in a safe manner. The interrupt will
-     *  be disabled.
-     */
-
+/*
+ *  Update a Vector/Priority register in a safe manner. The interrupt will
+ *  be disabled.
+ */
 static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
 				    u_int field)
 {
-    openpic_setfield(addr, OPENPIC_MASK);
-    /* wait until it's not in use */
-    while (openpic_read(addr) & OPENPIC_ACTIVITY);
-    openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
+	openpic_setfield(addr, OPENPIC_MASK);
+	/* wait until it's not in use */
+	while (openpic_read(addr) & OPENPIC_ACTIVITY);
+	openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
 }
 
-
-/* -------- Global Operations ---------------------------------------------- */
-
-
-    /*
-     *  Initialize the OpenPIC
-     */
-
+/*
+ *  Initialize the OpenPIC
+ */
 __initfunc(void openpic_init(int main_pic))
 {
-    u_int t, i;
-    u_int timerfreq;
-    const char *version;
+	u_int t, i;
+	u_int timerfreq;
+	const char *version;
 
-    if (!OpenPIC)
-	panic("No OpenPIC found");
+	if (!OpenPIC)
+		panic("No OpenPIC found");
 
-    t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
-    switch (t & OPENPIC_FEATURE_VERSION_MASK) {
+	t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
+	switch (t & OPENPIC_FEATURE_VERSION_MASK) {
 	case 1:
-	    version = "1.0";
-	    break;
+		version = "1.0";
+		break;
 	case 2:
-	    version = "1.2";
-	    break;
+		version = "1.2";
+		break;
 	case 3:
-	    version = "1.3";
-	    break;
+		version = "1.3";
+		break;
 	default:
-	    version = "?";
-	    break;
-    }
-    NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
-		     OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
-    NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
-		  OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
-    printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version,
-	   NumProcessors, NumSources, OpenPIC);
-    timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
-    printk("OpenPIC timer frequency is ");
-    if (timerfreq)
-	printk("%d Hz\n", timerfreq);
-    else
-	printk("not set\n");
-
-    if ( main_pic )
-    {
-	    /* Initialize timer interrupts */
-	    for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
-		    /* Disabled, Priority 0 */
-		    openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i);
-		    /* No processor */
-		    openpic_maptimer(i, 0);
-	    }
-	    
-	    /* Initialize IPI interrupts */
-	    for (i = 0; i < OPENPIC_NUM_IPI; i++) {
-		    /* Disabled, Priority 0 */
-		    openpic_initipi(i, 0, OPENPIC_VEC_IPI+i);
-	    }
+		version = "?";
+		break;
+	}
+	NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
+			 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
+	NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
+		      OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
+	printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version,
+	       NumProcessors, NumSources, OpenPIC);
+	timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
+	printk("OpenPIC timer frequency is ");
+	if (timerfreq)
+		printk("%d Hz\n", timerfreq);
+	else
+		printk("not set\n");
+
+	if ( main_pic )
+	{
+		/* Initialize timer interrupts */
+		for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
+			/* Disabled, Priority 0 */
+			openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i);
+			/* No processor */
+			openpic_maptimer(i, 0);
+		}
 	    
-	    /* Initialize external interrupts */
-	    /* SIOint (8259 cascade) is special */
-	    openpic_initirq(0, 8, OPENPIC_VEC_SOURCE, 1, 1);
-	    /* Processor 0 */
-	    openpic_mapirq(0, 1<<0);
-	    for (i = 1; i < NumSources; i++) {
-		    /* Enabled, Priority 8 */
-		    openpic_initirq(i, 8, OPENPIC_VEC_SOURCE+i, 0,
-				    i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1);
-		    /* Processor 0 */
-		    openpic_mapirq(i, 1<<0);
-	    }
+		/* Initialize IPI interrupts */
+		for (i = 0; i < OPENPIC_NUM_IPI; i++) {
+			openpic_initipi(i, 10, OPENPIC_VEC_IPI+i);
+		}
 	    
-	    /* Initialize the spurious interrupt */
-	    openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
+		/* Initialize external interrupts */
+		for (i = 0; i < NumSources; i++) {
+			/* Enabled, Priority 8 */
+			openpic_initirq(i, 8, open_pic.irq_offset+i, 0,
+					i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1);
+			/* Processor 0 */
+			openpic_mapirq(i, 1<<0);
+		}
 	    
-	    if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT,
-			    "82c59 cascade", NULL))
-		    printk("Unable to get OpenPIC IRQ 0 for cascade\n");
-	    openpic_set_priority(0, 0);
-	    openpic_disable_8259_pass_through();
-    }
-}
+		/* Initialize the spurious interrupt */
+		openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
 
+		/* Gemini has no i8259 */
+		if ( _machine != _MACH_gemini )
+		{
+			/* SIOint (8259 cascade) is special */
+			openpic_initirq(0, 8, open_pic.irq_offset, 1, 1);
+			openpic_mapirq(0, 1<<0);
+			if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT,
+					"82c59 cascade", NULL))
+				printk("Unable to get OpenPIC IRQ 0 for cascade\n");
+		}
+		openpic_set_priority(0, 0);
+		openpic_disable_8259_pass_through();
+	}
+}
 
-    /*
-     *  Reset the OpenPIC
-     */
 
+/*
+ *  Reset the OpenPIC
+ */
 void openpic_reset(void)
 {
-    openpic_setfield(&OpenPIC->Global.Global_Configuration0,
-    		       OPENPIC_CONFIG_RESET);
+	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
+			 OPENPIC_CONFIG_RESET);
 }
 
 
-    /*
-     *  Enable/disable 8259 Pass Through Mode
-     */
-
+/*
+ *  Enable/disable 8259 Pass Through Mode
+ */
 void openpic_enable_8259_pass_through(void)
 {
-    openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
-    		       OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
+	openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
+			   OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
 }
 
 void openpic_disable_8259_pass_through(void)
 {
-    openpic_setfield(&OpenPIC->Global.Global_Configuration0,
-    		     OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
+	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
+			 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
 }
 
-
 #ifndef __i386__
-    /*
-     *  Find out the current interrupt
-     */
-
+/*
+ *  Find out the current interrupt
+ */
 u_int openpic_irq(u_int cpu)
 {
-    u_int vec;
+	u_int vec;
 
-    check_arg_cpu(cpu);
-    vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
-			    OPENPIC_VECTOR_MASK);
-#if 0
-if (vec != 22 /* SCSI */)
-printk("++openpic_irq: %d\n", vec);
-#endif
-    return vec;
+	check_arg_cpu(cpu);
+	vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
+				OPENPIC_VECTOR_MASK);
+	return vec;
 }
 #endif
 
 
-    /*
-     *  Signal end of interrupt (EOI) processing
-     */
-
+/*
+ *  Signal end of interrupt (EOI) processing
+ */
 #ifndef __powerpc__
 void openpic_eoi(void)
 #else
 void openpic_eoi(u_int cpu)
 #endif
 {
-    check_arg_cpu(cpu);
-    openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
+	check_arg_cpu(cpu);
+	openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
 }
 
 
-    /*
-     *  Get/set the current task priority
-     */
-
+/*
+ *  Get/set the current task priority
+ */
 #ifndef __powerpc__
 u_int openpic_get_priority(void)
 #else
 u_int openpic_get_priority(u_int cpu)
 #endif
 {
-    CHECK_THIS_CPU;
-    return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
-			     OPENPIC_CURRENT_TASK_PRIORITY_MASK);
+	CHECK_THIS_CPU;
+	return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
+				 OPENPIC_CURRENT_TASK_PRIORITY_MASK);
 }
 
 #ifndef __powerpc__
@@ -336,176 +304,178 @@
 void openpic_set_priority(u_int cpu, u_int pri)
 #endif
 {
-    CHECK_THIS_CPU;
-    check_arg_pri(pri);
-    openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
-    		       OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
+	CHECK_THIS_CPU;
+	check_arg_pri(pri);
+	openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
+			   OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
 }
 
-    /*
-     *  Get/set the spurious vector
-     */
-
+/*
+ *  Get/set the spurious vector
+ */
 u_int openpic_get_spurious(void)
 {
-    return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
-    			     OPENPIC_VECTOR_MASK);
+	return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
+				 OPENPIC_VECTOR_MASK);
 }
 
 void openpic_set_spurious(u_int vec)
 {
-    check_arg_vec(vec);
-    openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
-    		       vec);
+	check_arg_vec(vec);
+	openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
+			   vec);
 }
 
-
-    /*
-     *  Initialize one or more CPUs
-     */
-
+/*
+ *  Initialize one or more CPUs
+ */
 void openpic_init_processor(u_int cpumask)
 {
-    openpic_write(&OpenPIC->Global.Processor_Initialization, cpumask);
+	openpic_write(&OpenPIC->Global.Processor_Initialization, cpumask);
 }
 
 
-/* -------- Interprocessor Interrupts -------------------------------------- */
-
-
-    /*
-     *  Initialize an interprocessor interrupt (and disable it)
-     *
-     *  ipi: OpenPIC interprocessor interrupt number
-     *  pri: interrupt source priority
-     *  vec: the vector it will produce
-     */
-
+/*
+ *  Initialize an interprocessor interrupt (and disable it)
+ *
+ *  ipi: OpenPIC interprocessor interrupt number
+ *  pri: interrupt source priority
+ *  vec: the vector it will produce
+ */
 void openpic_initipi(u_int ipi, u_int pri, u_int vec)
 {
-    check_arg_timer(ipi);
-    check_arg_pri(pri);
-    check_arg_vec(vec);
-    openpic_safe_writefield(&OpenPIC->Global.IPI_Vector_Priority(ipi),
-    			    OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
-    			    (pri << OPENPIC_PRIORITY_SHIFT) | vec);
+	check_arg_timer(ipi);
+	check_arg_pri(pri);
+	check_arg_vec(vec);
+	openpic_safe_writefield(&OpenPIC->Global.IPI_Vector_Priority(ipi),
+				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
+				(pri << OPENPIC_PRIORITY_SHIFT) | vec);
 }
 
-
-    /*
-     *  Send an IPI to one or more CPUs
-     */
-
+/*
+ *  Send an IPI to one or more CPUs
+ */
 #ifndef __powerpc__
 void openpic_cause_IPI(u_int ipi, u_int cpumask)
 #else
 void openpic_cause_IPI(u_int cpu, u_int ipi, u_int cpumask)
 #endif
 {
-    CHECK_THIS_CPU;
-    check_arg_ipi(ipi);
-    openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpumask);
+	CHECK_THIS_CPU;
+	check_arg_ipi(ipi);
+	openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpumask);
 }
 
+void openpic_enable_IPI(u_int ipi)
+{
+	check_arg_ipi(ipi);
+	openpic_clearfield(&OpenPIC->Global.IPI_Vector_Priority(ipi),
+			   OPENPIC_MASK);
+}
 
-/* -------- Timer Interrupts ----------------------------------------------- */
-
-
-    /*
-     *  Initialize a timer interrupt (and disable it)
-     *
-     *  timer: OpenPIC timer number
-     *  pri: interrupt source priority
-     *  vec: the vector it will produce
-     */
+/*
+ * Do per-cpu setup for SMP systems.
+ *
+ * Get IPI's working and start taking interrupts.
+ *   -- Cort
+ */
+void do_openpic_setup_cpu(void)
+{
+	int i;
+	
+	for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
+		  openpic_enable_IPI(i);
+#if 0	
+	/* let the openpic know we want intrs */
+	for ( i = 0; i < NumSources ; i++ )
+		openpic_mapirq(i, openpic_read(&OpenPIC->Source[i].Destination)
+			       | (1<<smp_processor_id()) );
+#endif	
+	openpic_set_priority(smp_processor_id(), 0);
+}    
 
+/*
+ *  Initialize a timer interrupt (and disable it)
+ *
+ *  timer: OpenPIC timer number
+ *  pri: interrupt source priority
+ *  vec: the vector it will produce
+ */
 void openpic_inittimer(u_int timer, u_int pri, u_int vec)
 {
-    check_arg_timer(timer);
-    check_arg_pri(pri);
-    check_arg_vec(vec);
-    openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
-    			    OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
-    			    (pri << OPENPIC_PRIORITY_SHIFT) | vec);
+	check_arg_timer(timer);
+	check_arg_pri(pri);
+	check_arg_vec(vec);
+	openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
+				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
+				(pri << OPENPIC_PRIORITY_SHIFT) | vec);
 }
 
 
-    /*
-     *  Map a timer interrupt to one or more CPUs
-     */
-
+/*
+ *  Map a timer interrupt to one or more CPUs
+ */
 void openpic_maptimer(u_int timer, u_int cpumask)
 {
-    check_arg_timer(timer);
-    openpic_write(&OpenPIC->Global.Timer[timer].Destination, cpumask);
+	check_arg_timer(timer);
+	openpic_write(&OpenPIC->Global.Timer[timer].Destination, cpumask);
 }
 
-
-/* -------- Interrupt Sources ---------------------------------------------- */
-
-
-    /*
-     *  Enable/disable an interrupt source
-     */
-
+/*
+ *  Enable/disable an interrupt source
+ */
 void openpic_enable_irq(u_int irq)
 {
-    check_arg_irq(irq);
-    openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
+	check_arg_irq(irq);
+	openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
 }
 
 void openpic_disable_irq(u_int irq)
 {
-    check_arg_irq(irq);
-    openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
+	check_arg_irq(irq);
+	openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
 }
 
-
-    /*
-     *  Initialize an interrupt source (and disable it!)
-     *
-     *  irq: OpenPIC interrupt number
-     *  pri: interrupt source priority
-     *  vec: the vector it will produce
-     *  pol: polarity (1 for positive, 0 for negative)
-     *  sense: 1 for level, 0 for edge
-     */
-
+/*
+ *  Initialize an interrupt source (and disable it!)
+ *
+ *  irq: OpenPIC interrupt number
+ *  pri: interrupt source priority
+ *  vec: the vector it will produce
+ *  pol: polarity (1 for positive, 0 for negative)
+ *  sense: 1 for level, 0 for edge
+ */
 void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
 {
-    check_arg_irq(irq);
-    check_arg_pri(pri);
-    check_arg_vec(vec);
-    openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
-    			    OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
-    			    OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL,
-    			    (pri << OPENPIC_PRIORITY_SHIFT) | vec |
-			    (pol ? OPENPIC_SENSE_POLARITY : 0) |
-			    (sense ? OPENPIC_SENSE_LEVEL : 0));
+	check_arg_irq(irq);
+	check_arg_pri(pri);
+	check_arg_vec(vec);
+	openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
+				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
+				OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL,
+				(pri << OPENPIC_PRIORITY_SHIFT) | vec |
+				(pol ? OPENPIC_SENSE_POLARITY : 0) |
+				(sense ? OPENPIC_SENSE_LEVEL : 0));
 }
 
-
-    /*
-     *  Map an interrupt source to one or more CPUs
-     */
-
+/*
+ *  Map an interrupt source to one or more CPUs
+ */
 void openpic_mapirq(u_int irq, u_int cpumask)
 {
-    check_arg_irq(irq);
-    openpic_write(&OpenPIC->Source[irq].Destination, cpumask);
+	check_arg_irq(irq);
+	openpic_write(&OpenPIC->Source[irq].Destination, cpumask);
 }
 
-
-    /*
-     *  Set the sense for an interrupt source (and disable it!)
-     *
-     *  sense: 1 for level, 0 for edge
-     */
-
+/*
+ *  Set the sense for an interrupt source (and disable it!)
+ *
+ *  sense: 1 for level, 0 for edge
+ */
 void openpic_set_sense(u_int irq, int sense)
 {
-    check_arg_irq(irq);
-    openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
-    			    OPENPIC_SENSE_LEVEL,
-			    (sense ? OPENPIC_SENSE_LEVEL : 0));
+	check_arg_irq(irq);
+	openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
+				OPENPIC_SENSE_LEVEL,
+				(sense ? OPENPIC_SENSE_LEVEL : 0));
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/pmac_pic.c linux.14p16/arch/ppc/kernel/pmac_pic.c
--- linux.vanilla/arch/ppc/kernel/pmac_pic.c	Sat Aug 28 20:00:53 1999
+++ linux.14p16/arch/ppc/kernel/pmac_pic.c	Thu Dec  9 15:34:30 1999
@@ -3,12 +3,14 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
+#include <linux/pci.h>
+#include <asm/pci-bridge.h>
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/prom.h>
 #include "pmac_pic.h"
 
-/* pmac */struct pmac_irq_hw {
+struct pmac_irq_hw {
         unsigned int    flag;
         unsigned int    enable;
         unsigned int    ack;
@@ -31,6 +33,12 @@
 #define GATWICK_IRQ_POOL_SIZE        10
 static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
 
+extern int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+                                      unsigned char offset, unsigned short *val);
+extern int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+                                      unsigned char offset, unsigned short val);
+
+
 static void __pmac pmac_mask_and_ack_irq(unsigned int irq_nr)
 {
         unsigned long bit = 1UL << (irq_nr & 0x1f);
@@ -108,7 +116,7 @@
 };
 
 struct hw_interrupt_type gatwick_pic = {
-	" GATWICK  ",
+        " PMAC-PI2 ",
 	NULL,
 	NULL,
 	NULL,
@@ -160,7 +168,7 @@
                         if (xmon_2nd)
                                 xmon(regs);
 #endif
-                        smp_message_recv();
+                        pmac_smp_message_recv();
                         goto out;
                 }
                 /* could be here due to a do_fake_interrupt call but we don't
@@ -290,17 +298,67 @@
 	}
 }
 
+/*
+ * The PowerBook 3400/2400/3500 can have a combo ethernet/modem
+ * card which includes an ohare chip that acts as a second interrupt
+ * controller.  If we find this second ohare, set it up and fix the
+ * interrupt value in the device tree for the ethernet chip.
+ */
+static void __init enable_second_ohare(void)
+{
+	unsigned char bus, devfn;
+	unsigned short cmd;
+        unsigned long addr;
+	int second_irq;
+	struct device_node *irqctrler = find_devices("pci106b,7");
+	struct device_node *ether;
+
+	if (irqctrler == NULL || irqctrler->n_addrs <= 0)
+		return;
+	addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40);
+	pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20);
+	max_irqs = 64;
+	if (pci_device_loc(irqctrler, &bus, &devfn) == 0) {
+		pmac_pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+		cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+		cmd &= ~PCI_COMMAND_IO;
+		pmac_pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+	}
+
+	second_irq = irqctrler->intrs[0].line;
+	printk(KERN_INFO "irq: secondary controller on irq %d\n", second_irq);
+	request_irq(second_irq, gatwick_action, SA_INTERRUPT,
+		    "interrupt cascade", 0 );
+
+	/* Fix interrupt for the modem/ethernet combo controller. The number
+	   in the device tree (27) is bogus (correct for the ethernet-only
+	   board but not the combo ethernet/modem board).
+	   The real interrupt is 28 on the second controller -> 28+32 = 60.
+	*/
+	ether = find_devices("pci1011,14");
+	if (ether && ether->n_intrs > 0) {
+		ether->intrs[0].line = 60;
+		printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n",
+		       ether->intrs[0].line);
+	}
+}
+
 __initfunc(void
 pmac_pic_init(void))
 {
         int i;
         struct device_node *irqctrler;
-        unsigned long addr;
-	int second_irq = -999;
+        volatile struct pmac_irq_hw *addr;
+	int second_irq;
 
-
-	/* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128, 
-	   others have 32 */
+	/*
+	 * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
+	 * 1998 G3 Series PowerBooks have 128, 
+	 * other powermacs have 32.
+	 * The combo ethernet/modem card for the Powerstar powerbooks
+	 * (2400/3400/3500, ohare based) has a second ohare chip
+	 * effectively making a total of 64.
+	 */
 	max_irqs = max_real_irqs = 32;
 	irqctrler = find_devices("mac-io");
 	if (irqctrler)
@@ -317,24 +375,28 @@
 	/* get addresses of first controller */
 	if (irqctrler) {
 		if  (irqctrler->n_addrs > 0) {
-			addr = (unsigned long) 
-				ioremap(irqctrler->addrs[0].address, 0x40);
-			for (i = 0; i < 2; ++i)
-				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-					(addr + (2 - i) * 0x10);
+			addr = ioremap(irqctrler->addrs[0].address, 0x40);
+			addr += 2;
+			for (i = 0; i < 2; ++i, --addr)
+				pmac_irq_hw[i] = addr;
 		}
 		
 		/* get addresses of second controller */
-		irqctrler = (irqctrler->next) ? irqctrler->next : NULL;
+		irqctrler = irqctrler->next;
 		if (irqctrler && irqctrler->n_addrs > 0) {
-			addr = (unsigned long) 
-				ioremap(irqctrler->addrs[0].address, 0x40);
-			for (i = 2; i < 4; ++i)
-				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-					(addr + (4 - i) * 0x10);
+			addr = ioremap(irqctrler->addrs[0].address, 0x40);
+			addr += 2;
+			for (i = 2; i < 4; ++i, --addr)
+				pmac_irq_hw[i] = addr;
 		}
 	}
 
+	/* PowerBooks 3400 and 3500 can have a second controller in a second
+	   ohare chip, on the combo ethernet/modem card */
+	if (machine_is_compatible("AAPL,3400/2400")
+	     || machine_is_compatible("AAPL,3500"))
+		enable_second_ohare();
+
 	/* disable all interrupts in all controllers */
 	for (i = 0; i * 32 < max_irqs; ++i)
 		out_le32(&pmac_irq_hw[i]->enable, 0);
@@ -346,11 +408,11 @@
 			(int)second_irq);
 		if (device_is_compatible(irqctrler, "gatwick"))
 			pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
-		for ( i = max_real_irqs ; i < max_irqs ; i++ )
-			irq_desc[i].ctl = &gatwick_pic;
 		request_irq( second_irq, gatwick_action, SA_INTERRUPT,
-			     "gatwick cascade", 0 );
+			     "interrupt cascade", 0 );
 	}
+	for (i = max_real_irqs; i < max_irqs; i++)
+		irq_desc[i].ctl = &gatwick_pic;
 	printk("System has %d possible interrupts\n", max_irqs);
 	if (max_irqs != max_real_irqs)
 		printk(KERN_DEBUG "%d interrupts on main controller\n",
@@ -381,6 +443,7 @@
 	out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]);
 	if (max_real_irqs > 32)
 		out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);
+	(void)in_le32(&pmac_irq_hw[0]->flag);
 	mb();
 }
 
@@ -392,6 +455,7 @@
 	out_le32(&pmac_irq_hw[0]->enable, 0);
 	if (max_real_irqs > 32)
 		out_le32(&pmac_irq_hw[1]->enable, 0);
+	(void)in_le32(&pmac_irq_hw[0]->flag);
 	mb();
 	for (i = 0; i < max_real_irqs; ++i)
 		if (test_bit(i, sleep_save_mask))
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/pmac_setup.c linux.14p16/arch/ppc/kernel/pmac_setup.c
--- linux.vanilla/arch/ppc/kernel/pmac_setup.c	Sat Aug 28 20:00:53 1999
+++ linux.14p16/arch/ppc/kernel/pmac_setup.c	Thu Dec  9 15:34:29 1999
@@ -190,7 +190,7 @@
 	return len;
 }
 
-#ifdef CONFIG_SCSI
+#if defined(CONFIG_SCSI) && defined(CONFIG_BLK_DEV_SD)
 /* Find the device number for the disk (if any) at target tgt
    on host adaptor host.
    XXX this really really should be in drivers/scsi/sd.c. */
@@ -217,7 +217,7 @@
             return MKDEV_SD(i);
     return 0;
 }
-#endif
+#endif /* SCSI and BLK_DEV_SD */
 
 /*
  * Dummy mksound function that does nothing.
@@ -434,7 +434,7 @@
 
 __initfunc(void find_boot_device(void))
 {
-#ifdef CONFIG_SCSI
+#if defined(CONFIG_SCSI) && defined(CONFIG_BLK_DEV_SD)
 	if (boot_host != NULL) {
 		boot_dev = sd_find_target(boot_host, boot_target);
 		if (boot_dev != 0)
@@ -464,7 +464,7 @@
 		find_boot_device();
 		found_boot = 1;
 	}
-	if (dev == boot_dev) {
+	if (boot_dev == 0 || dev == boot_dev) {
 		ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part);
 		boot_dev = NODEV;
 		printk(" (root)");
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/ppc_ksyms.c linux.14p16/arch/ppc/kernel/ppc_ksyms.c
--- linux.vanilla/arch/ppc/kernel/ppc_ksyms.c	Wed Oct 20 01:12:33 1999
+++ linux.14p16/arch/ppc/kernel/ppc_ksyms.c	Thu Dec  9 15:34:29 1999
@@ -198,6 +198,8 @@
 EXPORT_SYMBOL(find_compatible_devices);
 EXPORT_SYMBOL(find_path_device);
 EXPORT_SYMBOL(find_phandle);
+EXPORT_SYMBOL(device_is_compatible);
+EXPORT_SYMBOL(machine_is_compatible);
 EXPORT_SYMBOL(get_property);
 EXPORT_SYMBOL(pci_io_base);
 EXPORT_SYMBOL(pci_device_loc);
@@ -214,7 +216,6 @@
 #endif /* CONFIG_PMAC */
 
 EXPORT_SYMBOL(abs);
-EXPORT_SYMBOL(device_is_compatible);
 
 EXPORT_SYMBOL_NOVERS(__ashrdi3);
 EXPORT_SYMBOL_NOVERS(__lshrdi3);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/prep_pci.c linux.14p16/arch/ppc/kernel/prep_pci.c
--- linux.vanilla/arch/ppc/kernel/prep_pci.c	Sat Aug 28 20:00:54 1999
+++ linux.14p16/arch/ppc/kernel/prep_pci.c	Thu Dec  9 15:34:29 1999
@@ -170,7 +170,7 @@
 	0,	/* Slot 8  - unused */
 	0,	/* Slot 9  - unused */
 	0,	/* Slot 10 - unxued */
-	0,	/* Slot 11 - unused */
+	0x1e,	/* Slot 11 - PCI-ISA/IDE/USB */
 	0,	/* Slot 12 - unused */
 	0,	/* Slot 13 - unused */
 	2,	/* Slot 14 - Ethernet */
@@ -198,7 +198,7 @@
 	0,      /* Slot 8  - unused */
 	0,      /* Slot 9  - unused */
 	0,      /* Slot 10 - unxued */
-	0,      /* Slot 11 - unused */
+	0x1e,   /* Slot 11 - PCI-ISA/IDE/USB */
 	0,      /* Slot 12 - unused */
 	0,      /* Slot 13 - unused */
 	2,      /* Slot 14 - Ethernet */
@@ -224,7 +224,7 @@
 	0,	/* Slot 8  - unused */
 	0,	/* Slot 9  - unused */
 	0,	/* Slot 10 - unused */
-	0,	/* Slot 11 - unused */
+	0x1e,	/* Slot 11 - PCI-ISA/IDE/USB */
 	3,	/* Slot 12 - SCSI */
 	0,	/* Slot 13 - unused */
 	2,	/* Slot 14 - Ethernet */
@@ -253,7 +253,7 @@
         0,      /* Slot 8  - unused */
         0,      /* Slot 9  - unused */
         0,      /* Slot 10 - unused */
-        0,      /* Slot 11 - unused */
+        0x1e,   /* Slot 11 - PCI-ISA/IDE/USB */
         3,      /* Slot 12 - SCSI */
         0,      /* Slot 13 - unused */
         2,      /* Slot 14 - Ethernet 1 */
@@ -1076,40 +1076,91 @@
 	return;
 }
 
+int motopenpic_to_irq(int n)
+{
+       if (n & 0xF0) {
+               return (n & 0x0F);
+       } else {
+               return(openpic_to_irq(n));
+       }
+}
+
+void prep_pib_init(void)
+{
+unsigned char   reg;
+unsigned short  short_reg;
+
+struct pci_dev *dev = NULL;
+
+	if (( _prep_type == _PREP_Motorola) && (OpenPIC)) {
+		/*
+		 * Perform specific configuration for the Via Tech or
+		 * or Winbond PCI-ISA-Bridge part.
+		 */
+		if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, 
+					PCI_DEVICE_ID_VIA_82C586_1, dev))) {
+			/*
+			 * PPCBUG does not set the enable bits
+			 * for the IDE device. Force them on here.
+			 */
+			pcibios_read_config_byte(dev->bus->number, 
+					dev->devfn, 0x40, &reg);
+
+			reg |= 0x03; /* IDE: Chip Enable Bits */
+			pcibios_write_config_byte(dev->bus->number, 
+					dev->devfn, 0x40, reg);
+
+		} else if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND, 
+					PCI_DEVICE_ID_WINBOND_83C553, dev))) {
+			/*
+			 * Clear the PCI Interrupt Routing Control Register.
+			 */
+			short_reg = 0x0000;
+			pcibios_write_config_word(dev->bus->number, 
+					dev->devfn, 0x44, short_reg);
+		}
+	}
+}
 __initfunc(
 void
 prep_pcibios_fixup(void))
 {
-        struct pci_dev *dev;
-        extern unsigned char *Motherboard_map;
-        extern unsigned char *Motherboard_routes;
-        unsigned char i;
-
-        if ( _prep_type == _PREP_Radstone )
-        {
-                printk("Radstone boards require no PCI fixups\n");
+extern unsigned char *Motherboard_map;
+extern unsigned char *Motherboard_routes;
+unsigned char	i;
+struct pci_dev  *dev;
+
+	if (_prep_type == _PREP_Radstone) {
+		printk("Radstone boards require no PCI fixups\n");
 		return;
-        }
+	}
 
 	prep_route_pci_interrupts();
 
+	prep_pib_init();
+
 	printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
+
 	if (OpenPIC) {
-		/* PCI interrupts are controlled by the OpenPIC */
-		for(dev=pci_devices; dev; dev=dev->next) {
-			if (dev->bus->number == 0) {
-                       		dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
-				pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_PIN, dev->irq);
-			} else {
-				if (Motherboard_non0 != NULL)
-					Motherboard_non0(dev);
-			}
+
+	    /* PCI interrupts are controlled by the OpenPIC */
+	    for(dev=pci_devices; dev; dev=dev->next) {
+		if (dev->bus->number == 0) {
+		    dev->irq = 
+		       motopenpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
+
+		    pcibios_write_config_byte(dev->bus->number, dev->devfn, 
+					      PCI_INTERRUPT_PIN, dev->irq);
+		} else {
+			if (Motherboard_non0 != NULL)
+				Motherboard_non0(dev);
 		}
-		return;
+
+	    }
+	return;
 	}
 
-	for(dev=pci_devices; dev; dev=dev->next)
-	{
+	for(dev=pci_devices; dev; dev=dev->next) {
 		/*
 		 * Use our old hard-coded kludge to figure out what
 		 * irq this device uses.  This is necessary on things
@@ -1118,29 +1169,26 @@
 		unsigned char d = PCI_SLOT(dev->devfn);
 		dev->irq = Motherboard_routes[Motherboard_map[d]];
 
-		for ( i = 0 ; i <= 5 ; i++ )
-		{
-		        if ( dev->base_address[i] > 0x10000000 )
-		        {
-		                printk("Relocating PCI address %lx -> %lx\n",
-		                       dev->base_address[i],
-		                       (dev->base_address[i] & 0x00FFFFFF)
-		                       | 0x01000000);
-		                dev->base_address[i] =
-		                  (dev->base_address[i] & 0x00FFFFFF) | 0x01000000;
-		                pci_write_config_dword(dev,
-		                        PCI_BASE_ADDRESS_0+(i*0x4),
-		                       dev->base_address[i] );
-		        }
+		for ( i = 0 ; i <= 5 ; i++ ) {
+			if ( dev->base_address[i] > 0x10000000 ) {
+				printk("Relocating PCI address %lx -> %lx\n",
+				dev->base_address[i],
+				(dev->base_address[i] & 0x00FFFFFF)|0x01000000);
+
+				dev->base_address[i] = (dev->base_address[i] & 
+							0x00FFFFFF)|0x01000000;
+				pci_write_config_dword(dev, 
+						PCI_BASE_ADDRESS_0+(i*0x4),
+						dev->base_address[i] );
+			}
 		}
 #if 0
-		/*
-		 * If we have residual data and if it knows about this
-		 * device ask it what the irq is.
-		 *  -- Cort
-		 */
-		ppcd = residual_find_device_id( ~0L, dev->device,
-		                                -1,-1,-1, 0);
+	/*
+	 * If we have residual data and if it knows about this
+	 * device ask it what the irq is.
+	 *  -- Cort
+	 */
+	ppcd = residual_find_device_id( ~0L, dev->device, -1,-1,-1, 0);
 #endif
 	}
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/prep_setup.c linux.14p16/arch/ppc/kernel/prep_setup.c
--- linux.vanilla/arch/ppc/kernel/prep_setup.c	Sat Aug 28 20:00:54 1999
+++ linux.14p16/arch/ppc/kernel/prep_setup.c	Thu Dec  9 15:34:29 1999
@@ -628,25 +628,36 @@
 void
 prep_ide_insw(ide_ioreg_t port, void *buf, int ns)
 {
-	_insw((unsigned short *)((port)+_IO_BASE), buf, ns);
+	ide_insw(((port)+(_IO_BASE)), buf, ns);
 }
 
 void
 prep_ide_outsw(ide_ioreg_t port, void *buf, int ns)
 {
-	_outsw((unsigned short *)((port)+_IO_BASE), buf, ns);
+	ide_outsw(((port)+_IO_BASE), buf, ns);
 }
 
 int
 prep_ide_default_irq(ide_ioreg_t base)
 {
-	switch (base) {
-		case 0x1f0: return 13;
-		case 0x170: return 13;
-		case 0x1e8: return 11;
-		case 0x168: return 10;
-		default:
-                        return 0;
+	if ( _prep_type == _PREP_IBM ) {
+		switch (base) {
+			case 0x1f0: return 13;
+			case 0x170: return 13;
+			case 0x1e8: return 11;
+			case 0x168: return 10;
+			default:
+				return 0;
+		}
+	} else {
+		switch (base) {
+			case 0x1f0: return 14;
+			case 0x170: return 14;
+			case 0x1e8: return 15;
+			case 0x168: return 15;
+			default:
+				return 0;
+		}
 	}
 }
 
@@ -687,6 +698,7 @@
 void
 prep_ide_fix_driveid(struct hd_driveid *id)
 {
+	ppc_generic_ide_fix_driveid(id);
 }
 
 __initfunc(void
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/process.c linux.14p16/arch/ppc/kernel/process.c
--- linux.vanilla/arch/ppc/kernel/process.c	Sat Aug 28 20:00:54 1999
+++ linux.14p16/arch/ppc/kernel/process.c	Thu Dec  9 15:34:29 1999
@@ -40,6 +40,7 @@
 #include <asm/processor.h>
 #include <asm/mmu.h>
 #include <asm/prom.h>
+#include <asm/mmu_context.h>
 
 int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
 extern unsigned long _get_SP(void);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/prom.c linux.14p16/arch/ppc/kernel/prom.c
--- linux.vanilla/arch/ppc/kernel/prom.c	Wed Oct 20 01:12:33 1999
+++ linux.14p16/arch/ppc/kernel/prom.c	Thu Dec  9 15:34:29 1999
@@ -25,6 +25,7 @@
 #include <asm/smp.h>
 #include <asm/bootx.h>
 #include <asm/system.h>
+#include <asm/gemini.h>
 
 /*
  * Properties whose value is longer than this get excluded from our
@@ -263,7 +264,7 @@
  * handling exceptions and the MMU hash table for us.
  */
 __init
-void
+unsigned long
 prom_init(int r3, int r4, prom_entry pp)
 {
 #ifdef CONFIG_SMP	
@@ -272,14 +273,23 @@
 	char type[16], *path;
 #endif	
 	unsigned long mem;
-	ihandle prom_rtas;
+	ihandle prom_rtas, prom_mmu;
 	unsigned long offset = reloc_offset();
 	int l;
 	char *p, *d;
+ 	unsigned long phys;
+ 	
+ 	/* Default */
+ 	phys = offset + KERNELBASE;
+	
+#ifdef CONFIG_GEMINI
+	gemini_prom_init();
+		return phys;
+#endif /* CONFIG_GEMINI */
 	
 	/* check if we're apus, return if we are */
 	if ( r3 == 0x61707573 )
-		return;
+ 		return phys;
 
 	/* If we came here from BootX, clear the screen,
 	 * set up some pointers and return. */
@@ -375,12 +385,12 @@
 		prom_print(RELOC("booting...\n"));
 		flushscreen();
 #endif
-		return;
+		return phys;
 	}
 	
 	/* check if we're prep, return if we are */
 	if ( *(unsigned long *)(0) == 0xdeadc0de )
-		return;
+		return phys;
 
 	/* First get a handle for the stdout device */
 	RELOC(prom) = pp;
@@ -472,6 +482,29 @@
 			prom_print(RELOC(" done\n"));
 	}
 
+	if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen),
+			    RELOC("mmu"), &prom_mmu, sizeof(prom_mmu)) <= 0) {	
+		prom_print(RELOC(" no MMU found\n"));
+	} else {
+		int nargs;
+		struct prom_args prom_args;
+		nargs = 4;
+		prom_args.service = RELOC("call-method");
+		prom_args.nargs = nargs;
+		prom_args.nret = 4;
+		prom_args.args[0] = RELOC("translate");
+		prom_args.args[1] = prom_mmu;
+		prom_args.args[2] = (void *)(offset + KERNELBASE);
+		prom_args.args[3] = (void *)1;
+		RELOC(prom)(&prom_args);
+
+		/* We assume the phys. address size is 3 cells */
+		if (prom_args.args[nargs] != 0)
+			prom_print(RELOC(" (translate failed) "));
+		else
+			phys = (unsigned long)prom_args.args[nargs+3];
+	}
+
 #ifdef CONFIG_SMP
 	/*
 	 * With CHRP SMP we need to use the OF to start the other
@@ -506,7 +539,7 @@
 		node = call_prom(RELOC("finddevice"), 1, 1, RELOC("/"));
 		if ( (int)call_prom(RELOC("getprop"), 4, 1, node,
 			    RELOC("device_type"),type, sizeof(type)) <= 0)
-			return;
+			return phys;
 		
 		/* copy the holding pattern code to someplace safe (8M) */
 		memcpy( (void *)(8<<20), RELOC(__secondary_hold), 0x100 );
@@ -548,6 +581,7 @@
 			prom_print(RELOC("...failed\n"));
 	}
 #endif	
+	return phys;
 }
 
 /*
@@ -1428,6 +1462,21 @@
 	}
 }
 
+/* Indicates whether the root node has a given value in its
+ * compatible property.
+ */
+__openfirmware
+int
+machine_is_compatible(const char *compat)
+{
+	struct device_node *root;
+	
+	root = find_path_device("/");
+	if (root == 0)
+		return 0;
+	return device_is_compatible(root, compat);
+}
+
 #ifdef CONFIG_BOOTX_TEXT
 
 __pmac
@@ -1986,20 +2035,5 @@
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 
 };
-
-/* Indicates whether the root node has a given value in its
- * compatible property.
- */
-__openfirmware
-int
-machine_is_compatible(const char *compat)
-{
-	struct device_node *root;
-	
-	root = find_path_device("/");
-	if (root == 0)
-		return 0;
-	return device_is_compatible(root, compat);
-}
 
 #endif /* CONFIG_BOOTX_TEXT */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/ptrace.c linux.14p16/arch/ppc/kernel/ptrace.c
--- linux.vanilla/arch/ppc/kernel/ptrace.c	Sat Aug 14 02:26:47 1999
+++ linux.14p16/arch/ppc/kernel/ptrace.c	Thu Dec  9 15:34:29 1999
@@ -26,7 +26,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 
-#include <asm/segment.h>
+#include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -86,7 +86,6 @@
  * tables. NOTE! You should check that the long isn't on a page boundary,
  * and that it is in the task area before calling this: this routine does
  * no checking.
- *
  */
 static unsigned long get_long(struct task_struct * tsk, 
 	struct vm_area_struct * vma, unsigned long addr)
@@ -95,22 +94,31 @@
 	pmd_t * pgmiddle;
 	pte_t * pgtable;
 	unsigned long page;
+	int fault;
 
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (pgd_none(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 0);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return 0;
 	}
 	if (pgd_bad(*pgdir)) {
 		printk("ptrace[1]: bad page directory %lx\n", pgd_val(*pgdir));
 		pgd_clear(pgdir);
 		return 0;
 	}
-	pgmiddle = pmd_offset(pgdir,addr);
+	pgmiddle = pmd_offset(pgdir, addr);
 	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 0);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return 0;
 	}
 	if (pmd_bad(*pgmiddle)) {
 		printk("ptrace[3]: bad pmd %lx\n", pmd_val(*pgmiddle));
@@ -119,8 +127,12 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 0);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return 0;
 	}
 	page = pte_page(*pgtable);
 /* this is a hack for non-kernel-mapped video buffers and similar */
@@ -146,22 +158,31 @@
 	pmd_t *pgmiddle;
 	pte_t *pgtable;
 	unsigned long page;
-		
+	int fault;
+
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (!pgd_present(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 1);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return;
 	}
 	if (pgd_bad(*pgdir)) {
 		printk("ptrace[2]: bad page directory %lx\n", pgd_val(*pgdir));
 		pgd_clear(pgdir);
 		return;
 	}
-	pgmiddle = pmd_offset(pgdir,addr);
+	pgmiddle = pmd_offset(pgdir, addr);
 	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 1);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return;
 	}
 	if (pmd_bad(*pgmiddle)) {
 		printk("ptrace[4]: bad pmd %lx\n", pmd_val(*pgmiddle));
@@ -170,13 +191,21 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 1);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return;
 	}
 	page = pte_page(*pgtable);
 	if (!pte_write(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 1);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return;
 	}
 /* this is a hack for non-kernel-mapped video buffers and similar */
 	if (MAP_NR(page) < max_mapnr) {
@@ -247,7 +276,7 @@
 		}
 		*result = low;
 	} else
-		*result = get_long(tsk, vma,addr);
+		*result = get_long(tsk, vma, addr);
 	return 0;
 }
 
@@ -299,7 +328,7 @@
 		put_long(tsk, vma,addr & ~(sizeof(long)-1),high);
 		put_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1),low);
 	} else
-		put_long(tsk, vma,addr,data);
+		put_long(tsk, vma, addr, data);
 	return 0;
 }
 
@@ -307,6 +336,7 @@
 {
 	struct task_struct *child;
 	int ret = -EPERM;
+	unsigned long flags;
 
 	lock_kernel();
 	if (request == PTRACE_TRACEME) {
@@ -318,34 +348,40 @@
 		ret = 0;
 		goto out;
 	}
-	if (pid == 1)		/* you may not mess with init */
-		goto out;
 	ret = -ESRCH;
-	if (!(child = find_task_by_pid(pid)))
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	read_unlock(&tasklist_lock);	/* FIXME!!! */
+	if (!child)
 		goto out;
 	ret = -EPERM;
+	if (pid == 1)		/* you may not mess with init */
+		goto out;
 	if (request == PTRACE_ATTACH) {
 		if (child == current)
 			goto out;
 		if ((!child->dumpable ||
 		    (current->uid != child->euid) ||
-		    (current->uid != child->uid) ||
 		    (current->uid != child->suid) ||
+		    (current->uid != child->uid) ||
 	 	    (current->gid != child->egid) ||
-	 	    (current->gid != child->gid) ||
-		    (current->gid != child->sgid) ||
-		    (!cap_issubset(child->cap_permitted, current->cap_permitted)))
-		    && !capable(CAP_SYS_PTRACE))
+	 	    (current->gid != child->sgid) ||
+	 	    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
+	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
 			goto out;
 		/* the same process cannot be attached many times */
 		if (child->flags & PF_PTRACED)
 			goto out;
 		child->flags |= PF_PTRACED;
+
+		write_lock_irqsave(&tasklist_lock, flags);
 		if (child->p_pptr != current) {
 			REMOVE_LINKS(child);
 			child->p_pptr = current;
 			SET_LINKS(child);
 		}
+		write_unlock_irqrestore(&tasklist_lock, flags);
+
 		send_sig(SIGSTOP, child, 1);
 		ret = 0;
 		goto out;
@@ -369,27 +405,19 @@
 			down(&child->mm->mmap_sem);
 			ret = read_long(child, addr, &tmp);
 			up(&child->mm->mmap_sem);
-			if (ret < 0)
-				goto out;
-			ret = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
-			if (!ret)
-				put_user(tmp, (unsigned long *) data);
+			if (ret >= 0)
+				ret = put_user(tmp,(unsigned long *) data);
 			goto out;
 		}
 
 	/* read the word at location addr in the USER area. */
 		case PTRACE_PEEKUSR: {
 			unsigned long tmp;
-			
-			if ((addr & 3) || addr < 0 || addr > (PT_FPSCR << 2)) {
-				ret = -EIO;
+
+			ret = -EIO;
+			if ((addr & 3) || addr < 0 || addr > (PT_FPSCR << 2))
 				goto out;
-			}
 			
-			ret = verify_area(VERIFY_WRITE, (void *) data,
-					  sizeof(long));
-			if (ret)
-				goto out;
 			tmp = 0;  /* Default return condition */
 			addr = addr >> 2; /* temporary hack. */
 			if (addr < PT_FPR0) {
@@ -401,9 +429,8 @@
 				tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
 			}
 			else
-				ret = -EIO;
-			if (!ret)
-				put_user(tmp,(unsigned long *) data);
+				goto out;
+			ret = put_user(tmp, (unsigned long *) data);
 			goto out;
 		}
 
@@ -442,16 +469,16 @@
 		case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 		case PTRACE_CONT: { /* restart after signal. */
 			ret = -EIO;
-			if ((unsigned long) data >= _NSIG)
+			if ((unsigned long) data > _NSIG)
 				goto out;
 			if (request == PTRACE_SYSCALL)
 				child->flags |= PF_TRACESYS;
 			else
 				child->flags &= ~PF_TRACESYS;
 			child->exit_code = data;
-			wake_up_process(child);
 			/* make sure the single step bit is not set. */
 			clear_single_step(child);
+			wake_up_process(child);
 			ret = 0;
 			goto out;
 		}
@@ -465,38 +492,40 @@
 			ret = 0;
 			if (child->state == TASK_ZOMBIE) /* already dead */
 				goto out;
-			wake_up_process(child);
 			child->exit_code = SIGKILL;
 			/* make sure the single step bit is not set. */
 			clear_single_step(child);
+			wake_up_process(child);
 			goto out;
 		}
 
 		case PTRACE_SINGLESTEP: {  /* set the trap flag. */
 			ret = -EIO;
-			if ((unsigned long) data >= _NSIG)
+			if ((unsigned long) data > _NSIG)
 				goto out;
 			child->flags &= ~PF_TRACESYS;
 			set_single_step(child);
-			wake_up_process(child);
 			child->exit_code = data;
 			/* give it a chance to run. */
+			wake_up_process(child);
 			ret = 0;
 			goto out;
 		}
 
 		case PTRACE_DETACH: { /* detach a process that was attached. */
 			ret = -EIO;
-			if ((unsigned long) data >= _NSIG)
+			if ((unsigned long) data > _NSIG)
 				goto out;
 			child->flags &= ~(PF_PTRACED|PF_TRACESYS);
-			wake_up_process(child);
 			child->exit_code = data;
+			write_lock_irqsave(&tasklist_lock, flags);
 			REMOVE_LINKS(child);
 			child->p_pptr = child->p_opptr;
 			SET_LINKS(child);
+			write_unlock_irqrestore(&tasklist_lock, flags);
 			/* make sure the single step bit is not set. */
 			clear_single_step(child);
+			wake_up_process(child);
 			ret = 0;
 			goto out;
 		}
@@ -512,10 +541,9 @@
 
 asmlinkage void syscall_trace(void)
 {
-	lock_kernel();
 	if ((current->flags & (PF_PTRACED|PF_TRACESYS))
 			!= (PF_PTRACED|PF_TRACESYS))
-		goto out;
+		return;
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
 	notify_parent(current, SIGCHLD);
@@ -529,6 +557,4 @@
 		send_sig(current->exit_code, current, 1);
 		current->exit_code = 0;
 	}
-out:
-	unlock_kernel();
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/setup.c linux.14p16/arch/ppc/kernel/setup.c
--- linux.vanilla/arch/ppc/kernel/setup.c	Wed Oct 20 01:12:33 1999
+++ linux.14p16/arch/ppc/kernel/setup.c	Thu Dec  9 15:34:29 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: setup.c,v 1.132.2.5 1999/09/11 03:32:50 paulus Exp $
+ * $Id: setup.c,v 1.132.2.6 1999/10/19 04:32:33 paulus Exp $
  * Common prep/pmac/chrp boot and setup code.
  */
 
@@ -62,6 +62,12 @@
                       unsigned long r6,
                       unsigned long r7);
 
+extern void gemini_init(unsigned long r3,
+                      unsigned long r4,
+                      unsigned long r5,
+                      unsigned long r6,
+                      unsigned long r7);
+
 extern boot_infos_t *boot_infos;
 extern char cmd_line[512];
 char saved_command_line[256];
@@ -342,7 +348,6 @@
 identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
 		 unsigned long r6, unsigned long r7)
 {
-	
 #ifdef __SMP__
 	if ( first_cpu_booted ) return 0;
 #endif /* __SMP__ */
@@ -403,6 +408,8 @@
 	_machine = _MACH_fads;
 #elif defined(CONFIG_APUS)
 	_machine = _MACH_apus;
+#elif defined(CONFIG_GEMINI)
+	_machine = _MACH_gemini;
 #else
 #error "Machine not defined correctly"
 #endif /* CONFIG_APUS */
@@ -488,6 +495,11 @@
                 mbx_init(r3, r4, r5, r6, r7);
                 break;
 #endif
+#ifdef CONFIG_GEMINI
+	case _MACH_gemini:
+                gemini_init(r3, r4, r5, r6, r7);
+		break;
+#endif
 	default:
 		printk("Unknown machine type in identify_machine!\n");
 	}
@@ -497,6 +509,28 @@
 		extern int __map_without_bats;
 		__map_without_bats = 1;
 	}
+
+	/* Look for mem= option on command line */
+	if (strstr(cmd_line, "mem=")) {
+		char *p, *q;
+		unsigned long maxmem = 0;
+		extern unsigned long __max_memory;
+
+		for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) {
+			q = p + 4;
+			if (p > cmd_line && p[-1] != ' ')
+				continue;
+			maxmem = simple_strtoul(q, &q, 0);
+			if (*q == 'k' || *q == 'K') {
+				maxmem <<= 10;
+				++q;
+			} else if (*q == 'm' || *q == 'M') {
+				maxmem <<= 20;
+				++q;
+			}
+		}
+		__max_memory = maxmem;
+	}
 	
 	return 0;
 }
@@ -522,7 +556,7 @@
 }
 
 __initfunc(void setup_arch(char **cmdline_p,
-			   unsigned long * memory_start_p, unsigned long * memory_end_p))
+		unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
 	extern int panic_timeout;
 	extern char _etext[], _edata[];
@@ -532,8 +566,11 @@
 
 #ifdef CONFIG_XMON
 	extern void xmon_map_scc(void);
+	char *p;
+
 	xmon_map_scc();
-	if (strstr(cmd_line, "xmon"))
+	p = strstr(cmd_line, "xmon");
+	if (p != NULL && (p == cmd_line || p[-1] == ' '))
 		xmon(0);
 #endif /* CONFIG_XMON */
  
@@ -547,6 +584,7 @@
 
 	/* Save unparsed command line copy for /proc/cmdline */
 	strcpy(saved_command_line, cmd_line);
+
 	*cmdline_p = cmd_line;
 
 	*memory_start_p = find_available_memory();
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/signal.c linux.14p16/arch/ppc/kernel/signal.c
--- linux.vanilla/arch/ppc/kernel/signal.c	Sat Aug 14 02:27:15 1999
+++ linux.14p16/arch/ppc/kernel/signal.c	Thu Dec  9 15:34:29 1999
@@ -266,8 +266,8 @@
 
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
-		if (regs->msr & MSR_FP)
-			giveup_fpu(current);
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
 	if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
 	    || __copy_to_user(&frame->fp_regs, current->tss.fpr,
 			      ELF_NFPREG * sizeof(double))
@@ -471,6 +471,7 @@
 
 		/* Whee!  Actually deliver the signal.  */
 		handle_signal(signr, ka, &info, oldset, regs, &newsp, frame);
+		break;
 	}
 
 	if (regs->trap == 0x0C00 /* System Call! */ &&
@@ -487,5 +488,6 @@
 
 	setup_frame(regs, (struct sigregs *) frame, newsp);
 	return 1;
+
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/sleep.S linux.14p16/arch/ppc/kernel/sleep.S
--- linux.vanilla/arch/ppc/kernel/sleep.S	Sat Aug 28 20:00:54 1999
+++ linux.14p16/arch/ppc/kernel/sleep.S	Thu Dec  9 15:34:30 1999
@@ -171,6 +171,11 @@
  */
 	
 wake_up:
+	/* Flash inval the instruction cache */
+	mfspr	r3,HID0
+	ori	r3,r3, HID0_ICFI
+	mtspr	HID0,r3
+	isync
 	/* Restore the HID0 register.  This turns on the L1 caches. */
 	subi	r1,r1,SL_PC
 	lwz	r3,SL_HID0(r1)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/smp.c linux.14p16/arch/ppc/kernel/smp.c
--- linux.vanilla/arch/ppc/kernel/smp.c	Sat Aug 28 20:00:54 1999
+++ linux.14p16/arch/ppc/kernel/smp.c	Thu Dec  9 15:34:29 1999
@@ -34,8 +34,11 @@
 #include <asm/init.h>
 #include <asm/io.h>
 #include <asm/prom.h>
+#include <asm/gemini.h>
 
 #include "time.h"
+#include "open_pic.h"
+
 int first_cpu_booted = 0;
 int smp_threads_ready = 0;
 volatile int smp_commenced = 0;
@@ -109,34 +112,8 @@
 	}
 }
 
-/*
- * Dirty hack to get smp message passing working.
- *
- * As it is now, if we're sending two message at the same time
- * we have race conditions.  The PowerSurge doesn't easily
- * allow us to send IPI messages so we put the messages in
- * smp_message[].
- *
- * This is because don't have several IPI's on the PowerSurge even though
- * we do on the chrp.  It would be nice to use the actual IPI's on the chrp
- * rather than this but having two methods of doing IPI isn't a good idea
- * right now.
- *  -- Cort
- */
-int smp_message[NR_CPUS];
-void smp_message_recv(void)
+void smp_message_recv(int msg)
 {
-	int msg = smp_message[smp_processor_id()];
-
-	if ( _machine == _MACH_Pmac )
-	{
-		/* clear interrupt */
-		out_be32(PSURGE_INTR, ~0);
-	}
-	
-	/* make sure msg is for us */
-	if ( msg == -1 ) return;
-
 	ipi_count++;
 	
 	switch( msg )
@@ -145,25 +122,72 @@
 		__cli();
 		while (1) ;
 		break;
-	case MSG_RESCHEDULE: 
+	case MSG_RESCHEDULE:
 		current->need_resched = 1;
 		break;
-	case 0xf0f0: /* syncing time bases - just return */
+	case MSG_INVALIDATE_TLB:
+		_tlbia();
+	case 0xf0f0: /* pmac syncing time bases - just return */
 		break;
 	default:
 		printk("SMP %d: smp_message_recv(): unknown msg %d\n",
 		       smp_processor_id(), msg);
 		break;
 	}
+}
+
+/*
+ * As it is now, if we're sending two message at the same time
+ * we have race conditions on Pmac.  The PowerSurge doesn't easily
+ * allow us to send IPI messages so we put the messages in
+ * smp_message[].
+ *
+ * This is because don't have several IPI's on the PowerSurge even though
+ * we do on the chrp.  It would be nice to use actual IPI's such as with openpic
+ * rather than this.
+ *  -- Cort
+ */
+int pmac_smp_message[NR_CPUS];
+void pmac_smp_message_recv(void)
+{
+	int msg = pmac_smp_message[smp_processor_id()];
+
+	/* clear interrupt */
+	out_be32(PSURGE_INTR, ~0);
+	
+	/* make sure msg is for us */
+	if ( msg == -1 ) return;
+
+	smp_message_recv(msg);
+
 	/* reset message */
-	smp_message[smp_processor_id()] = -1;
+	pmac_smp_message[smp_processor_id()] = -1;
+}
+
+
+/*
+ * 750's don't broadcast tlb invalidates so
+ * we have to emulate that behavior.
+ *   -- Cort
+ */
+void smp_send_tlb_invalidate(int cpu)
+{
+	if ( (_get_PVR()>>16) == 8 )
+		smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0, 0);
 }
 
 void smp_send_reschedule(int cpu)
 {
-	/* This is only used if `cpu' is running an idle task,
-	   so it will reschedule itself anyway... */
-	/*smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0);*/
+	/*
+	 * This is only used if `cpu' is running an idle task,
+	 * so it will reschedule itself anyway...
+	 *
+	 * This isn't the case anymore since the other CPU could be
+	 * sleeping and won't reschedule until the next interrupt (such
+	 * as the timer).
+	 *  -- Cort
+	 */
+	smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0);
 }
 
 void smp_send_stop(void)
@@ -171,38 +195,39 @@
 	smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0);
 }
 
-spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED;
 void smp_message_pass(int target, int msg, unsigned long data, int wait)
 {
 	int i;
-	if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep)) )
+	
+	if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep|_MACH_gemini)) )
 		return;
 
-	spin_lock(&mesg_pass_lock);
-
-	/*
-	 * We assume here that the msg is not -1.  If it is,
-	 * the recipient won't know the message was destined
-	 * for it. -- Cort
-	 */
-	
-	switch( target )
-	{
-	case MSG_ALL:
-		smp_message[smp_processor_id()] = msg;
-		/* fall through */
-	case MSG_ALL_BUT_SELF:
-		for ( i = 0 ; i < smp_num_cpus ; i++ )
-			if ( i != smp_processor_id () )
-				smp_message[i] = msg;
-		break;
-	default:
-		smp_message[target] = msg;
-		break;
-	}
-	
 	switch (_machine) {
 	case _MACH_Pmac:
+		/*
+		 * IPI's on the Pmac are a hack but without reasonable
+		 * IPI hardware SMP on Pmac is a hack.
+		 *
+		 * We assume here that the msg is not -1.  If it is,
+		 * the recipient won't know the message was destined
+		 * for it. -- Cort
+		 */
+		for ( i = 0; i <= smp_num_cpus ; i++ )
+			pmac_smp_message[i] = -1;
+		switch( target )
+		{
+		case MSG_ALL:
+			pmac_smp_message[smp_processor_id()] = msg;
+			/* fall through */
+		case MSG_ALL_BUT_SELF:
+			for ( i = 0 ; i < smp_num_cpus ; i++ )
+				if ( i != smp_processor_id () )
+					pmac_smp_message[i] = msg;
+			break;
+		default:
+			pmac_smp_message[target] = msg;
+			break;
+		}
 		/* interrupt secondary processor */
 		out_be32(PSURGE_INTR, ~0);
 		out_be32(PSURGE_INTR, 0);
@@ -213,35 +238,27 @@
 		/* interrupt primary */
 		/**(volatile unsigned long *)(0xf3019000);*/
 		break;
-	
 	case _MACH_chrp:
 	case _MACH_prep:
-		/*
-		 * There has to be some way of doing this better -
-		 * perhaps a sent-to-all or send-to-all-but-self
-		 * in the openpic.  This gets us going for now, though.
-		 * -- Cort
-		 */
+	case _MACH_gemini:
+		/* make sure we're sending something that translates to an IPI */
+		if ( msg > 0x3 )
+			break;
 		switch ( target )
 		{
 		case MSG_ALL:
-			for ( i = 0 ; i < smp_num_cpus ; i++ )
-				openpic_cause_IPI(i, 0, 0xffffffff );
+			openpic_cause_IPI(smp_processor_id(), msg, 0xffffffff);
 			break;
 		case MSG_ALL_BUT_SELF:
-			for ( i = 0 ; i < smp_num_cpus ; i++ )
-				if ( i != smp_processor_id () )
-					openpic_cause_IPI(i, 0,
-			  0xffffffff & ~(1 << smp_processor_id()));
+			openpic_cause_IPI(smp_processor_id(), msg,
+					  0xffffffff & ~(1 << smp_processor_id()));
 			break;
 		default:
-			openpic_cause_IPI(target, 0, 1U << target);
+			openpic_cause_IPI(smp_processor_id(), msg, 1<<target);
 			break;
 		}
 		break;
 	}
-	
-	spin_unlock(&mesg_pass_lock);
 }
 
 void __init smp_boot_cpus(void)
@@ -296,6 +313,10 @@
 			cpu_nr = 2;
 			break;
 		}
+	case _MACH_gemini:
+                cpu_nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK)>>2;
+                cpu_nr = (cpu_nr == 0) ? 4 : cpu_nr;
+		break;
 	default:
 		printk("SMP not supported on this machine.\n");
 		return;
@@ -338,25 +359,16 @@
 		case _MACH_chrp:
 			*(unsigned long *)KERNELBASE = i;
 			asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
-#if 0
-			device = find_type_devices("cpu");
-			/* assume cpu device list is in order, find the ith cpu */
-			for ( a = i; device && a; device = device->next, a-- )
-				;
-			if ( !device )
-				break;
-			printk( "Starting %s (%lu): ", device->full_name,
-				*(ulong *)get_property(device, "reg", NULL) );
-			call_rtas( "start-cpu", 3, 1, NULL,
-				   *(ulong *)get_property(device, "reg", NULL),
-				   __pa(__secondary_start_chrp), i);
-#endif			
 			break;
 		case _MACH_prep:
 			*MotSave_SmpIar = (unsigned long)__secondary_start_psurge - KERNELBASE;
 			*MotSave_CpusState[1] = CPU_GOOD;
 			printk("CPU1 reset, waiting\n");
 			break;
+		case _MACH_gemini:
+			openpic_init_processor( 1<<i );
+			openpic_init_processor( 0 );
+			break;
 		}
 		
 		/*
@@ -379,6 +391,8 @@
 		}
 	}
 	
+	if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) )
+		do_openpic_setup_cpu();
 	if ( _machine == _MACH_Pmac )
 	{
 		/* reset the entry point so if we get another intr we won't
@@ -420,6 +434,13 @@
 #endif
 	init_idle();
 	cpu_callin_map[current->processor] = 1;
+	/*
+	 * Each processor has to do this and this is the best
+	 * place to stick it for now.
+	 *  -- Cort
+	 */
+	if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) )
+		do_openpic_setup_cpu();
 	while(!smp_commenced)
 		barrier();
 	__sti();
@@ -437,8 +458,8 @@
 void __init smp_store_cpu_info(int id)
 {
         struct cpuinfo_PPC *c = &cpu_data[id];
-
 	/* assume bogomips are same for everything */
         c->loops_per_sec = loops_per_sec;
         c->pvr = _get_PVR();
 }
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/mm/init.c linux.14p16/arch/ppc/mm/init.c
--- linux.vanilla/arch/ppc/mm/init.c	Wed Oct 20 01:12:33 1999
+++ linux.14p16/arch/ppc/mm/init.c	Thu Dec  9 15:34:29 1999
@@ -1,5 +1,5 @@
 /*
- *  $Id: init.c,v 1.164.2.5 1999/09/07 00:59:22 paulus Exp $
+ *  $Id: init.c,v 1.164.2.7 1999/10/19 04:32:39 paulus Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -54,6 +54,7 @@
 #include <asm/setup.h>
 #include <asm/amigahw.h>
 /* END APUS includes */
+#include <asm/gemini.h>
 
 int prom_trashed;
 atomic_t next_mmu_context;
@@ -83,6 +84,7 @@
 unsigned long *prep_find_end_of_memory(void);
 unsigned long *pmac_find_end_of_memory(void);
 unsigned long *apus_find_end_of_memory(void);
+unsigned long *gemini_find_end_of_memory(void);
 extern unsigned long *find_end_of_memory(void);
 #ifdef CONFIG_MBX
 unsigned long *mbx_find_end_of_memory(void);
@@ -114,6 +116,7 @@
 static void append_mem_piece(struct mem_pieces *, unsigned, unsigned);
 
 extern struct task_struct *current_set[NR_CPUS];
+unsigned long cpu_invalidate_tlb[NR_CPUS];
 
 PTE *Hash, *Hash_end;
 unsigned long Hash_size, Hash_mask;
@@ -149,6 +152,9 @@
  */
 int __map_without_bats = 0;
 
+/* max amount of RAM to use */
+unsigned long __max_memory;
+
 /* optimization for 603 to load the tlb directly from the linux table -- Cort */
 #define NO_RELOAD_HTAB 1 /* change in kernel/head.S too! */
 
@@ -492,6 +498,9 @@
 #ifndef CONFIG_8xx
 	__clear_user(Hash, Hash_size);
 	_tlbia();
+#ifdef __SMP__
+	smp_send_tlb_invalidate(0);
+#endif	
 #else
 	asm volatile ("tlbia" : : );
 #endif
@@ -509,6 +518,9 @@
 	mm->context = NO_CONTEXT;
 	if (mm == current->mm)
 		activate_context(current);
+#ifdef __SMP__
+	smp_send_tlb_invalidate(0);
+#endif	
 #else
 	asm volatile ("tlbia" : : );
 #endif
@@ -522,6 +534,9 @@
 		flush_hash_page(vma->vm_mm->context, vmaddr);
 	else
 		flush_hash_page(0, vmaddr);
+#ifdef __SMP__
+	smp_send_tlb_invalidate(0);
+#endif	
 #else
 	asm volatile ("tlbia" : : );
 #endif
@@ -551,6 +566,9 @@
 	{
 		flush_hash_page(mm->context, start);
 	}
+#ifdef __SMP__
+	smp_send_tlb_invalidate(0);
+#endif	
 #else
 	asm volatile ("tlbia" : : );
 #endif
@@ -576,6 +594,9 @@
 	}
 	read_unlock(&tasklist_lock);
 	flush_hash_segments(0x10, 0xffffff);
+#ifdef __SMP__
+	smp_send_tlb_invalidate(0);
+#endif	
 	atomic_set(&next_mmu_context, 0);
 	/* make sure current always has a context */
 	current->mm->context = MUNGE_CONTEXT(atomic_inc_return(&next_mmu_context));
@@ -984,6 +1005,10 @@
 		FREESEC(__pmac_begin,__pmac_end,num_pmac_pages);
 		FREESEC(__prep_begin,__prep_end,num_prep_pages);
 		break;
+	case _MACH_gemini:
+		FREESEC(__pmac_begin,__pmac_end,num_pmac_pages);
+		FREESEC(__prep_begin,__prep_end,num_prep_pages);
+		break;
 	}
 
 	if ( !have_of )
@@ -1021,9 +1046,13 @@
 	else if (_machine == _MACH_apus )
 		end_of_DRAM = apus_find_end_of_memory();
 #endif
+#ifdef CONFIG_GEMINI	
+	else if ( _machine == _MACH_gemini )
+		end_of_DRAM = gemini_find_end_of_memory();
+#endif /* CONFIG_GEMINI	*/
 	else /* prep */
 		end_of_DRAM = prep_find_end_of_memory();
-
+*(unsigned long *)(KERNELBASE) = 0xdeadbeef;	
         hash_init();
         _SDR1 = __pa(Hash) | (Hash_mask >> 10);
 	ioremap_base = 0xf8000000;
@@ -1066,6 +1095,10 @@
 		   (kernel_map) remaps individual IO regions to
 		   0x90000000. */
 		break;
+	case _MACH_gemini:
+		setbat(0, 0xf0000000, 0xf0000000, 0x10000000, IO_PAGE);
+		setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
+		break;
 	}
 	ioremap_bot = ioremap_base;
 #else /* CONFIG_8xx */
@@ -1296,7 +1329,7 @@
 	int i;
 	
 	/* max amount of RAM we allow -- Cort */
-#define RAM_LIMIT (256<<20)
+#define RAM_LIMIT (768<<20)
 
 	memory_node = find_devices("memory");
 	if (memory_node == NULL) {
@@ -1329,8 +1362,12 @@
 	 * to our nearest IO area.
 	 * -- Cort
 	 */
-	if ( phys_mem.regions[0].size >= RAM_LIMIT )
-		phys_mem.regions[0].size = RAM_LIMIT;
+	if (__max_memory == 0 || __max_memory > RAM_LIMIT)
+		__max_memory = RAM_LIMIT;
+	if (phys_mem.regions[0].size >= __max_memory) {
+		phys_mem.regions[0].size = __max_memory;
+		phys_mem.n_regions = 1;
+	}
 	total = phys_mem.regions[0].size;
 	
 	if (phys_mem.n_regions > 1) {
@@ -1343,20 +1380,15 @@
 	if (boot_infos == 0) {
 		/* record which bits the prom is using */
 		get_mem_prop("available", &phys_avail);
+		prom_mem = phys_mem;
+		for (i = 0; i < phys_avail.n_regions; ++i)
+			remove_mem_piece(&prom_mem,
+					 phys_avail.regions[i].address,
+					 phys_avail.regions[i].size, 0);
 	} else {
 		/* booted from BootX - it's all available (after klimit) */
 		phys_avail = phys_mem;
-	}
-	prom_mem = phys_mem;
-	for (i = 0; i < phys_avail.n_regions; ++i)
-	{
-		if ( phys_avail.regions[i].address >= RAM_LIMIT )
-			continue;
-		if ( (phys_avail.regions[i].address+phys_avail.regions[i].size)
-		     >= RAM_LIMIT )
-			phys_avail.regions[i].size = RAM_LIMIT - phys_avail.regions[i].address;
-		remove_mem_piece(&prom_mem, phys_avail.regions[i].address,
-				 phys_avail.regions[i].size, 1);
+		prom_mem.n_regions = 0;
 	}
 
 	/*
@@ -1406,6 +1438,32 @@
 
 	return (__va(total));
 }
+
+#if defined(CONFIG_GEMINI)
+unsigned long __init *gemini_find_end_of_memory(void)
+{
+	unsigned long total, kstart, ksize, *ret;
+	unsigned char reg;
+*(unsigned long *)(KERNELBASE) = 0x1;
+	reg = readb(GEMINI_MEMCFG);
+*(unsigned long *)(KERNELBASE) = 0x2;
+	total = ((1<<((reg & 0x7) - 1)) *
+		 (8<<((reg >> 3) & 0x7)));
+	total *= (1024*1024);
+	phys_mem.regions[0].address = 0;
+	phys_mem.regions[0].size = total;
+	phys_mem.n_regions = 1;
+	
+	ret = __va(phys_mem.regions[0].size);
+	phys_avail = phys_mem;
+	kstart = __pa(_stext);
+	ksize = PAGE_ALIGN( _end - _stext );
+*(unsigned long *)(KERNELBASE) = 0x3;
+	remove_mem_piece( &phys_avail, kstart, ksize, 0 );
+*(unsigned long *)(KERNELBASE) = 0x4;
+	return ret;
+}
+#endif /* defined(CONFIG_GEMINI) */
 
 #ifdef CONFIG_APUS
 #define HARDWARE_MAPPED_SIZE (512*1024)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/xmon/xmon.c linux.14p16/arch/ppc/xmon/xmon.c
--- linux.vanilla/arch/ppc/xmon/xmon.c	Sat Aug 28 20:00:54 1999
+++ linux.14p16/arch/ppc/xmon/xmon.c	Thu Dec  9 15:34:33 1999
@@ -115,9 +115,13 @@
 {
 	struct pt_regs regs;
 	int msr, cmd;
+	static int entered = 0;
+
+	if (!entered) {
+		entered = 1;
+		printk("Entering xmon kernel debugger.\n");
+	}
 
-	printk("Entering xmon kernel debugger.\n");
-	
 	if (excp == NULL) {
 		asm volatile ("stw	0,0(%0)\n\
 			lwz	0,0(1)\n\
@@ -230,7 +234,7 @@
 
 	if (dabr.enabled && pc == dabr.instr)
 		return &dabr;
-	if (iabr.enabled && pc == iabr.address)
+	if (iabr.enabled && ((pc ^ iabr.address) & ~3) == 0)
 		return &iabr;
 	bp = bpts;
 	for (i = 0; i < NBPTS; ++i, ++bp)
@@ -254,7 +258,9 @@
 			printf("Couldn't insert breakpoint at %x, disabling\n",
 			       bp->address);
 			bp->enabled = 0;
+			continue;
 		}
+		store_inst((void *) bp->address);
 	}
 	if (dabr.enabled)
 		set_dabr(dabr.address);
@@ -277,9 +283,12 @@
 			continue;
 		if (mread(bp->address, &instr, 4) == 4
 		    && instr == bpinstr
-		    && mwrite(bp->address, &bp->instr, 4) != 4)
+		    && mwrite(bp->address, &bp->instr, 4) != 4) {
 			printf("Couldn't remove breakpoint at %x\n",
 			       bp->address);
+			continue;
+		}
+		store_inst((void *) bp->address);
 	}
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/Makefile linux.14p16/arch/s390/Makefile
--- linux.vanilla/arch/s390/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/Makefile	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,70 @@
+
+# i386/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1994 by Linus Torvalds
+#
+
+LD=$(CROSS_COMPILE)ld -m elf_s390
+CPP=$(CC) -E
+OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
+LDFLAGS=-e start
+LINKFLAGS =-T $(TOPDIR)/arch/s390/vmlinux.lds $(LDFLAGS)
+
+CFLAGS_PIPE := -pipe
+CFLAGS_NSR  := -fno-strength-reduce
+CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) $(CFLAGS_NSR)
+
+
+ifdef SMP
+CFLAGS := $(CFLAGS) -D__SMP__
+endif
+
+HEAD := arch/s390/kernel/head.o arch/s390/kernel/init_task.o
+
+SUBDIRS := $(SUBDIRS) arch/s390/mm arch/s390/kernel arch/s390/lib \
+           drivers/s390
+CORE_FILES := arch/s390/mm/mm.o arch/s390/kernel/kernel.o $(CORE_FILES) \
+           drivers/s390/io.o
+LIBS := $(TOPDIR)/arch/s390/lib/lib.a $(LIBS) $(TOPDIR)/arch/s390/lib/lib.a
+
+all: image listing
+
+listing: vmlinux
+	@$(MAKEBOOT) listing
+
+arch/s390/kernel: dummy
+	$(MAKE) linuxsubdirs SUBDIRS=arch/s390/kernel
+
+arch/s390/mm: dummy
+	$(MAKE) linuxsubdirs SUBDIRS=arch/s390/mm
+
+drivers/s390: dummy
+	$(MAKE) linuxsubdirs SUBDIRS=drivers/s390
+
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+
+silo:
+	@$(MAKEBOOT) silo
+
+dasdfmt:
+	@$(MAKEBOOT) dasdfmt
+
+image: vmlinux 
+	@$(MAKEBOOT) image
+
+archclean:
+	@$(MAKEBOOT) clean
+
+archmrproper:
+
+archdep:
+	@$(MAKEBOOT) dep
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/boot/Makefile linux.14p16/arch/s390/boot/Makefile
--- linux.vanilla/arch/s390/boot/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/boot/Makefile	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,40 @@
+#
+# Makefile for the linux i386-specific parts of the memory manager.
+#
+# 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...
+
+OBJCOPY = $(CROSS_COMPILE)objcopy
+
+O_TARGET := 
+O_OBJS	 := 
+
+include $(TOPDIR)/Rules.make
+
+%.lnk: %.o
+	$(LD) -Ttext 0x0 -o $@ $<
+
+%.boot: %.lnk
+	$(OBJCOPY) -O binary $< $@
+
+silo: silo.c
+	$(CROSS_COMPILE)gcc $< -o $@
+
+dasdfmt: dasdfmt.c
+	$(CROSS_COMPILE)gcc $< -o $@
+
+image: $(CONFIGURE) $(TOPDIR)/vmlinux \
+	iplfba.boot ipleckd.boot 
+	$(OBJCOPY) -O binary $(TOPDIR)/vmlinux image
+
+listing: ../../../vmlinux
+	$(OBJDUMP) --disassemble --disassemble-all --disassemble-zeroes --reloc $(TOPDIR)/vmlinux > listing
+
+dep:
+
+clean:
+	rm -f image listing silo dasdfmt iplfba.boot ipleckd.boot
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/boot/dasdfmt.c linux.14p16/arch/s390/boot/dasdfmt.c
--- linux.vanilla/arch/s390/boot/dasdfmt.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/boot/dasdfmt.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,559 @@
+/*
+ *
+ * dasdfmt.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Corporation
+ *    Author(s): Utz Bacher (utz.bacher@de.ibm.com)
+ *
+ * Still to do:
+ *   detect non-switch parameters and complain about them
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+
+#define EXIT_MISUSE 1
+#define TEMPFILENAME "/tmp/ddfXXXXXX"
+#define TEMPFILENAMECHARS 8  /* 8 characters are fixed in all temp filenames */
+#define IOCTL_COMMAND 'D' << 8
+#define SLASHDEV "/dev/"
+#define PROC_DASD_DEVICES "/proc/dasd/devices"
+#define DASD_DRIVER_NAME "dasd"
+#define PROC_LINE_LENGTH 80
+#define ERR_LENGTH 80
+
+#define MAX_FILELEN NAME_MAX+PATH_MAX
+
+#define GIVEN_DEVNO 1
+#define GIVEN_MAJOR 2
+#define GIVEN_MINOR 4
+
+#define CHECK_START 1
+#define CHECK_END 2
+#define CHECK_BLKSIZE 4
+#define CHECK_ALL ~0
+
+#define ERRMSG(x...) {fflush(stdout);fprintf(stderr,x);}
+#define ERRMSG_EXIT(ec,x...) {fflush(stdout);fprintf(stderr,x);exit(ec);}
+
+#define CHECK_SPEC_MAX_ONCE(i,str) \
+	{if (i>1) \
+		ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
+			"can only be specified once\n",prog_name);}
+
+#define PARSE_PARAM_INTO(x,param,base,str) \
+	{x=(int)strtol(param,&endptr,base); \
+	if (*endptr) \
+		ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
+			"is in invalid format\n",prog_name);}
+
+typedef struct {
+	int start_unit;
+	int stop_unit;
+	int blksize;
+} format_data_t;
+
+char prog_name[]="dasd_format";
+char tempfilename[]=TEMPFILENAME;
+
+void
+exit_usage(int exitcode)
+{
+	printf("Usage: %s [-tvV] [-s start_track] [-e end_track] \n",prog_name);
+	printf("       [-b blocksize] -f dev_filename | -n 390_devno\n");
+	exit(exitcode);
+}
+
+void
+get_xno_from_xno(int *devno,int *major_no,int *minor_no,int mode)
+{
+	FILE *file;
+	int d,mi,ma,rc;
+	char line[PROC_LINE_LENGTH];
+
+	file=fopen(PROC_DASD_DEVICES,"r");
+	if (file==NULL)
+		ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to open " \
+			PROC_DASD_DEVICES ": %s (do you have the /proc " \
+			"filesystem enabled?)\n",prog_name,strerror(errno));
+
+	fgets(line,sizeof(line),file); /* omit first line */
+	while (fgets(line,sizeof(line),file)!=NULL) {
+		rc=sscanf(line,"%X%d%d",&d,&ma,&mi);
+		if ( (rc==3) &&
+			!((d!=*devno)&&(mode&GIVEN_DEVNO)) &&
+			!((ma!=*major_no)&&(mode&GIVEN_MAJOR)) &&
+			!((mi!=*minor_no)&&(mode&GIVEN_MINOR)) ) {
+			*devno=d;
+			*major_no=ma;
+			*minor_no=mi;
+			/* yes, this is a quick exit, but the easiest way */
+			fclose(file);
+			return;
+			break;
+		}
+	}
+	fclose(file);
+
+	ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to find device in the /proc " \
+		"filesystem (are you sure to have the right param line?)\n",
+		prog_name);
+}
+
+char *
+get_devname_from_devno(int devno,int verbosity)
+{
+	int major_no,minor_no;
+	int file_major,file_minor;
+	struct stat stat_buf;
+	int rc;
+	int found;
+	char *devname;
+	char tmpname[MAX_FILELEN];
+
+	DIR *dp;
+	struct dirent *direntp;
+
+	/**** get minor number ****/
+	get_xno_from_xno(&devno,&major_no,&minor_no,GIVEN_DEVNO);
+
+	/**** get device file ****/
+	if ((dp=opendir(SLASHDEV)) == NULL)
+		ERRMSG_EXIT(EXIT_FAILURE,"%s: unable to read " SLASHDEV \
+			"\n",prog_name);
+	found=0;
+	while ((direntp=readdir(dp)) != NULL) {
+		strcpy(tmpname,SLASHDEV);
+		strcat(tmpname,direntp->d_name);
+		rc=stat(tmpname,&stat_buf);
+		if (!rc) {
+			file_major=(stat_buf.st_rdev>>8)&0xff;
+			file_minor=stat_buf.st_rdev&0xff;
+			if ((file_major==major_no) && (file_minor==minor_no)) {
+				found=1;
+				break;
+			}
+		}
+	}
+	if (found) {
+		devname=malloc(strlen(direntp->d_name));
+		strcpy(devname,tmpname);
+	}
+	rc=closedir(dp);
+	if (rc<0) ERRMSG("%s: unable to close directory " SLASHDEV \
+		"; continuing\n",prog_name);
+	if (found)
+		return devname;
+
+	if (verbosity>=1)
+		printf("I didn't find device node in " SLASHDEV \
+			"; trying to create a temporary node\n");
+
+	/**** get temp file and create device node *****/
+	rc=mkstemp(tempfilename);
+	if (rc==-1)
+		ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to get temporary " \
+			"filename: %s\n",prog_name,strerror(errno));
+	close(rc);
+	rc=unlink(tempfilename);
+	
+	rc=mknod(tempfilename,S_IFBLK|0600,(major_no<<8)+minor_no);
+	if (rc)
+		ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to create temporary " \
+			"device node %s: %s\n",prog_name,tempfilename,
+			strerror(errno));
+	return tempfilename;
+}
+
+char *
+check_param(int mode,format_data_t data)
+{
+	char *s;
+
+	if (NULL==(s=malloc(ERR_LENGTH)))
+		ERRMSG_EXIT(EXIT_FAILURE,"%s: not enough memory.\n",prog_name);
+
+	if ((mode&CHECK_START)&&(data.start_unit<0)) {
+		strcpy(s,"start track must be greater than zero");
+		goto exit;
+	}
+	if ((mode&CHECK_END)&&(data.stop_unit<-1)) {
+		strcpy(s,"end track must be -1 or greater than zero");
+		goto exit;
+	}
+	if ((mode&CHECK_END)&&(data.start_unit>data.stop_unit)&&
+		(data.stop_unit!=-1)) {
+		strcpy(s,"end track must be higher than start track");
+		goto exit;
+	}
+
+	if ((mode&CHECK_BLKSIZE)&&(data.blksize<1)) {
+		strcpy(s,"blocksize must be a positive integer");
+		goto exit;
+	}
+	if (mode&CHECK_BLKSIZE) while (data.blksize>0) {
+		if ((data.blksize%2)&&(data.blksize!=1)) {
+			strcpy(s,"blocksize must be a power of 2");
+			goto exit;
+		}
+		data.blksize/=2;
+	}
+
+	free(s);
+	return NULL;
+exit:
+	return s;
+}
+
+#define ASK_PRINTOUT printf("Please enter %s",output)
+#define ASK_GETBUFFER fgets(buffer,sizeof(buffer),stdin)
+#define ASK_SCANFORNUMBER(var) rc=sscanf(buffer,"%d%c",&var,&c)
+#define ASK_COMPLAIN_FORMAT if ((rc==2)&&(c=='\n')) rc=1; \
+	if (rc==-1) rc=1; /* this happens, if enter is pressed */ \
+	if (rc!=1) printf(" -- wrong input, try again.\n")
+#define ASK_CHECK_PARAM(mode) str=check_param(mode,params); \
+		if (str!=NULL) { printf(" -- %s\n",str); rc=0; free(str); }
+
+format_data_t
+ask_user_for_data(format_data_t params)
+{
+	char buffer[20]; /* should be enough for inputing track numbers */
+	char c;
+	int i,rc;
+	char *str;
+	char output[60],o2[12];
+
+	i=params.start_unit;
+	do {
+		params.start_unit=i;
+		sprintf(output,"the start track of the range to format " \
+			"[%d]: ",i);
+		ASK_PRINTOUT;
+		ASK_GETBUFFER;
+		ASK_SCANFORNUMBER(params.start_unit);
+		ASK_COMPLAIN_FORMAT;
+		ASK_CHECK_PARAM(CHECK_START);
+	} while (rc!=1);
+
+	i=params.stop_unit;
+	do {
+		params.stop_unit=i;
+		sprintf(output,"the end track of the range to format [");
+		if (i==-1) sprintf(o2,"END]: "); else
+			sprintf(o2,"%d]: ",i);
+		strcat(output,o2);
+		ASK_PRINTOUT;
+		ASK_GETBUFFER;
+		if ( (!strcasecmp(buffer,"end")) ||
+			(!strcasecmp(buffer,"end\n")) ) {
+			rc=1;
+			params.stop_unit=-1;
+		} else {
+			ASK_SCANFORNUMBER(params.stop_unit);
+			ASK_COMPLAIN_FORMAT;
+			ASK_CHECK_PARAM(CHECK_END);
+		}
+	} while (rc!=1);
+
+	i=params.blksize;
+	do {
+		params.blksize=i;
+		sprintf(output,"the blocksize of the formatting [%d]: ",i);
+		ASK_PRINTOUT;
+		ASK_GETBUFFER;
+		ASK_SCANFORNUMBER(params.blksize);
+		ASK_COMPLAIN_FORMAT;
+		ASK_CHECK_PARAM(CHECK_BLKSIZE);
+	} while (rc!=1);
+
+	return params;
+}
+
+void
+do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
+	int verbosity,int withoutprompt)
+{
+	int fd,rc;
+	struct stat stat_buf;
+	int minor_no,major_no,devno;
+	char inp_buffer[5]; /* to contain yes */
+
+	fd=open(dev_name,O_RDWR);
+	if (fd==-1)
+		ERRMSG_EXIT(EXIT_FAILURE,"%s: error opening device %s: " \
+			"%s\n",prog_name,dev_name,strerror(errno));
+
+	if (verbosity>=1) {
+	}
+
+	rc=stat(dev_name,&stat_buf);
+	if (rc) {
+		ERRMSG_EXIT(EXIT_FAILURE,"%s: error occured during stat: " \
+			"%s\n",prog_name,strerror(errno));
+	} else {
+		if (!S_ISBLK(stat_buf.st_mode))
+			ERRMSG_EXIT(EXIT_FAILURE,"%s: file is not a " \
+				"blockdevice.\n",prog_name);
+		major_no=(stat_buf.st_rdev>>8)&0xff;
+		minor_no=stat_buf.st_rdev&0xff;
+	}
+	
+	if ( ((withoutprompt)&&(verbosity>=1)) ||
+		(!withoutprompt) ) {
+		get_xno_from_xno(&devno,&major_no,&minor_no,
+			GIVEN_MAJOR|GIVEN_MINOR);
+		printf("\nI am going to format the device %s in the " \
+			"following way:\n",dev_name);
+		printf("   Device number of device : 0x%x\n",devno);
+		printf("   Major number of device  : %u\n",major_no);
+		printf("   Minor number of device  : %u\n",minor_no);
+		printf("   Start track             : %d\n" \
+			,format_params.start_unit);
+		printf("   End track               : ");
+		if (format_params.stop_unit==-1)
+			printf("last track of disk\n");
+		else
+			printf("%d\n",format_params.stop_unit);
+		printf("   Blocksize               : %d\n" \
+			,format_params.blksize);
+		if (testmode) printf("Test mode active, omitting ioctl.\n");
+	}
+
+	while (!testmode) {
+		if (!withoutprompt) {
+			printf("\n--->> ATTENTION! <<---\n");
+			printf("All data in the specified range of that " \
+				"device will be lost.\nType yes to continue" \
+				", no will leave the disk untouched: ");
+			fgets(inp_buffer,sizeof(inp_buffer),stdin);
+			if (strcasecmp(inp_buffer,"yes") &&
+				strcasecmp(inp_buffer,"yes\n")) {
+				printf("Omitting ioctl call (disk will " \
+					"NOT be formatted).\n");
+				break;
+			}
+		}
+
+		if ( !(  (withoutprompt)&&(verbosity<1) ))
+			printf("Formatting the device. This may take a " \
+				"while (get yourself a coffee).\n");
+		rc=ioctl(fd,IOCTL_COMMAND,format_params);
+		if (rc)
+			ERRMSG_EXIT(EXIT_FAILURE,"%s: the dasd driver " \
+				"returned with the following error " \
+				"message:\n%s\n",prog_name,strerror(errno));
+		printf("Finished formatting the device.\n");
+
+		break;
+	}
+
+	rc=close(fd);
+	if (rc)
+		ERRMSG("%s: error during close: " \
+			"%s; continuing.\n",prog_name,strerror(errno));
+}
+
+
+
+int main(int argc,char *argv[]) {
+	int verbosity;
+	int testmode;
+	int withoutprompt;
+
+	char *dev_name;
+	int devno;
+	char *dev_filename,*devno_param_str,*range_param_str;
+	char *start_param_str,*end_param_str,*blksize_param_str;
+	
+	format_data_t format_params;
+
+	int rc;
+	int oc;
+	char *endptr;
+
+	char c1,c2,cbuffer[6]; /* should be able to contain -end plus 1 char */
+	int i1,i2;
+	char *str;
+
+	int start_specified,end_specified,blksize_specified;
+	int devfile_specified,devno_specified,range_specified;
+
+	/******************* initialization ********************/
+
+	endptr=NULL;
+
+	/* set default values */
+	format_params.start_unit=0;
+	format_params.stop_unit=-1;
+	format_params.blksize=1024;
+	testmode=0;
+	verbosity=0;
+	withoutprompt=0;
+	start_specified=end_specified=blksize_specified=0;
+	devfile_specified=devno_specified=range_specified=0;
+
+	/*************** parse parameters **********************/
+
+	/* avoid error message generated by getopt */
+	opterr=0;
+
+	while ( (oc=getopt(argc,argv,"r:s:e:b:n:f:hty?vV")) !=EOF) {
+		switch (oc) {
+		case 'y':
+			withoutprompt=1;
+			break;
+
+		case 't':
+			testmode=1;
+			break;
+
+		case 'v':
+			verbosity++;
+			break;
+
+		case '?': /* fall-through */
+		case ':':
+			exit_usage(EXIT_MISUSE);
+
+		case 'h':
+			exit_usage(0);
+
+		case 'V':
+			printf("%s version 0.99\n",prog_name);
+			exit(0);
+
+		case 's' :
+			start_param_str=optarg;
+			start_specified++;
+			break;
+			
+		case 'e' :
+			end_param_str=optarg;
+			end_specified++;
+			break;
+
+		case 'b' :
+			blksize_param_str=optarg;
+			blksize_specified++;
+			break;
+			
+		case 'n' :
+			devno_param_str=optarg;
+			devno_specified++;
+			break;
+		
+		case 'f' :
+			dev_filename=optarg;
+			devfile_specified++;
+			break;
+		case 'r' :
+			range_param_str=optarg;
+			range_specified++;
+			break;
+		}
+	}
+
+	/* set default values */
+
+	/******************** checking of parameters **************/
+
+	/* convert range into -s and -e */
+	CHECK_SPEC_MAX_ONCE(range_specified,"formatting range");
+
+	while (range_specified) {
+		start_specified++;
+		end_specified++;
+
+		/* scan for 1 or 2 integers, separated by a dash */
+		rc=sscanf(range_param_str,"%d%c%d%c",&i1,&c1,&i2,&c2);
+		if ((rc==3)&&(c1=='-')) {
+			format_params.start_unit=i1;
+			format_params.stop_unit=i2;
+			break;
+		}
+		if (rc==1) {
+			format_params.start_unit=i1;
+			break;
+		}
+
+		/* scan for integer and -END */
+		rc=sscanf(range_param_str,"%d%s",&i1,cbuffer);
+		if ((rc==2)&&(!strcasecmp(cbuffer,"-END"))) {
+			format_params.start_unit=i1;
+			format_params.stop_unit=-1;
+			break;
+		}
+		ERRMSG_EXIT(EXIT_MISUSE,"%s: specified range " \
+			"is in invalid format\n",prog_name);
+	}
+
+	if ((!devfile_specified)&&(!devno_specified))
+		ERRMSG_EXIT(EXIT_MISUSE,"%s: device to format " \
+			"not specified\n",prog_name);
+
+	if ((devfile_specified+devno_specified)>1)
+		ERRMSG_EXIT(EXIT_MISUSE,"%s: device to format " \
+			"can only be specified once\n",prog_name);
+
+	if ((!start_specified)&&(!end_specified)&&(!range_specified)&&
+		(!blksize_specified)) {
+		format_params=ask_user_for_data(format_params);
+	}
+
+	CHECK_SPEC_MAX_ONCE(start_specified,"start track");
+	CHECK_SPEC_MAX_ONCE(end_specified,"end track");
+	CHECK_SPEC_MAX_ONCE(blksize_specified,"blocksize");
+
+	if (devno_specified)
+		PARSE_PARAM_INTO(devno,devno_param_str,16,"device number");
+	if (start_specified&&!range_specified)
+		PARSE_PARAM_INTO(format_params.start_unit,start_param_str,10,
+			"start track");
+	if (end_specified&&!range_specified)
+		PARSE_PARAM_INTO(format_params.stop_unit,end_param_str,10,
+			"end track");
+	if (blksize_specified)
+		PARSE_PARAM_INTO(format_params.blksize,blksize_param_str,10,
+			"blocksize");
+
+	/***********get dev_name *********************/
+	dev_name=(devno_specified)?
+		get_devname_from_devno(devno,verbosity):
+		dev_filename;
+
+	/*** range checking *********/
+	str=check_param(CHECK_ALL,format_params);
+	if (str!=NULL) ERRMSG_EXIT(EXIT_MISUSE,"%s: %s\n",prog_name,str);
+
+	/*************** issue the real command *****************/
+	do_format_dasd(dev_name,format_params,testmode,verbosity,
+		withoutprompt);
+
+	/*************** cleanup ********************************/
+	if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) {
+		rc=unlink(dev_name);
+		if ((rc)&&(verbosity>=1))
+			ERRMSG("%s: temporary device node %s could not be " \
+				"removed: %s\n",prog_name,dev_name,
+				strerror(errno));
+	} else {
+		if (devno_specified) {
+			/* so we have allocated space for the filename */
+			free(dev_name);
+		}
+	}
+
+	return 0;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/boot/ipleckd.S linux.14p16/arch/s390/boot/ipleckd.S
--- linux.vanilla/arch/s390/boot/ipleckd.S	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/boot/ipleckd.S	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,289 @@
+#
+#  arch/s390/boot/ipleckd.S
+#    IPL record for 3380/3390 DASD
+#
+#  S390 version
+#    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+#    Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>
+#
+#
+# FIXME:	 should use the countarea to determine the blocksize
+# FIXME:	 should insert zeroes into memory when filling holes
+# FIXME:	 calculate blkpertrack from rdc data and blksize
+
+# Usage of registers
+# r1:	ipl subchannel ( general use, dont overload without save/restore !)
+# r10:
+# r13:	base register 	index to 0x0000
+# r14:	callers address
+# r15:	temporary save register (we have no stack!)
+	.org 0
+.psw:	.long 0x00080000,0x80000000+_start
+.ccw1:	.long 0x06000000,0x00001000     # Re-Read enough of bootsector to start
+.ccw2:	.long 0x00000000,0x00000000	# read countarea of record 1 to s/w.
+
+	.org 0x58
+.Lextn:	.long	0x000a0000,0x00000000+.Lextn
+.Lsvcn:	.long	0x000a0000,0x00000000+.Lsvcn
+.Lprgn:	.long	0x000a0000,0x00000000+.Lprgn
+.Lmcn:	.long	0x000a0000,0x00000000+.Lmcn
+.Lion:	.long   0x00080000,0x80000000+.Lionewaddr
+
+	.org 0xd0	
+.Lnull:	
+	.long 0x00000000,0x00000000
+	.org 0xe0
+.Llstad:.long 	0x00000000,0x00000000	# sectorno + ct of bootlist
+
+	.org 0xf0			# Lets start now...
+_start: .globl _start
+	l  	%r1,0xb8		# get IPL-subchannel from lowcore
+	stsch	.Lrdcdata
+	oi      .Lrdcdata+5,0x80        # enable ssch
+	oi	.Lrdcdata+27,0x01	# enalbe concurrent sense
+	msch	.Lrdcdata
+	l	%r2,.Lparm
+	mvc     0x0(8,%r2),.Lnull      # set parmarea to null
+	lctl	%c6,%c6,.Lc6     	# enable all interrupts
+.Lrdc:					# read device characteristics
+	la	%r6,.Lrdcccw     
+	st      %r6,.Lorb+8		# store cp-address to orb
+	bras    %r15,.Lssch		# start I/O
+	oi	.Llodata+1,0x80
+	lh	%r5,.Lcountarea+6	# init r5 from countarea
+	stcm	%r5,3,.Lrdccw+2		# and store into rd template *FIXME*
+	stcm	%r5,3,.Llodata+14	# and store into lodata *FIXME*
+.Lbootlist:	
+	l	%r2,.Llstad	
+	l	%r3,.Lblklst     
+	lhi	%r4,1
+	bras	%r14,.Lreadblks
+.Lloader:	
+	l	%r10,.Lblklst     	# r10 is index to bootlist
+	lhi	%r5,4			# r5:	skip 4 blocks = firstpage....
+.Lkloop:
+	clc	.Lnull(8),0(%r10)	# test blocklist	
+	jz	.Lchkparm		# end of list?
+	l	%r2,0(%r10)		# get startblock to r2
+	slr	%r4,%r4			# erase r4
+	icm	%r4,1,7(%r10)		# get blockcount
+	slr	%r3,%r3			# get address to r3
+	icm 	%r3,0xe,4(%r10)
+	chi	%r5,0			# still blocks to skip?
+	jz	.Ldoread		# no: start reading
+	cr	%r5,%r4			# #skipblocks >= blockct?
+	jm	.L007			# no: skip the blocks one by one
+.L006:	
+	sr	%r5,%r4			# decrease number of blocks to skip
+	j	.Lkcont			# advance to next entry
+.L007:	
+	ahi	%r2,1			# skip 1 block...
+	bctr    %r4,0                   # update blockct
+	ah	%r3,.Lcountarea+6       # increment address
+	bct	%r5,.L007		# 4 blocks skipped?
+.Ldoread:
+	ltr	%r2,%r2			# test startblock
+	jz	.Lzeroes		# startblocks is zero (hole)
+.Ldiskread:	
+	bras	%r14,.Lreadblks
+	j	.Lkcont
+.Lzeroes:
+	lr	%r2,%r3
+	slr	%r3,%r3
+	icm	%r3,3,.Lcountarea+6      # get blocksize
+.L008:	slr	%r5,%r5			# no bytes to move
+	mvcle	%r2,%r4,0(%r10)		# fill zeroes to storage
+	jo	.L008			# until block is filled
+	bctr	%r4,0			# skip to next block
+	a  	%r2,.Lcountarea+6       # proceed loadaddress
+	jnz	.Lzeroes		# proceed for additional blocks
+.Lkcont:	
+	ahi	%r10,8
+	j	.Lkloop
+.Lchkparm:
+	lm	%r3,%r4,.Lstart         # load .Lstart and .Lparm
+	clc	0x0(4,%r4),.Lnull     
+	je	.Lrunkern
+	mvc	0x480(128,%r3),0(%r4)	# move 1k-0x80 to parmarea
+	mvc	0x500(256,%r3),0x80(%r4)
+	mvc	0x600(256,%r3),0x180(%r4)
+	mvc	0x700(256,%r3),0x280(%r4)
+.Lrunkern:
+	lhi	%r2,17
+	sll	%r2,12
+	st	%r1,0xc6c(%r2)		# store iplsubchannel to lowcore
+	st	%r1,0xc6c		# store iplsubchannel to lowcore
+	br	%r3
+# This function does the start IO
+# r2:	number of first block to read ( input by caller )
+# r3:	address to read data to ( input by caller )
+# r4:	number of blocks to read ( input by caller )
+# r5:	destroyed
+# r6:	blocks per track ( input by caller )
+# r7:	number of heads 
+# r8:	
+# r9:	
+# r10:	
+# r11:	temporary register
+# r12:	local use for base address
+# r13:	base address for module
+# r14:	address of caller for subroutine
+# r15:	temporary save register (since we have no stack)
+.Lreadblks:
+	la	%r12,.Ldeccw     
+	st	%r12,8+.Lorb		# store cpaddr to orb
+	ahi	%r12,0x10		# increment r12 to point to rdccw
+	oi	1(%r12),0x40		# set CC in rd template
+	# first setup the read CCWs
+	lr	%r15,%r4		# save number or blocks
+	slr	%r7,%r7
+	icm	%r7,3,.Lrdcdata+14      # load heads to r7
+	clc	.Lrdcdata+3(2),.L3390     
+	jne	.L010			# 3380 or 3390 ?
+	lhi	%r6,12			# setup r6 correct!
+	j	.L011
+.L010:	
+	lhi	%r6,10	
+.L011:	
+	# loop for nbl times
+.Lrdloop:	
+	mvc	0(8,%r12),.Lrdccw     	# copy template to this ccw
+	st	%r3,4(%r12)		# store target address to this ccw
+	bct	%r4,.L005		# decrement no of blks still to do
+	ni	1(%r12),0x3f		# delete CC from last ccw
+	lr	%r4,%r15		# restore number of blocks
+	# read CCWs are setup now		
+	stcm	%r4,3,.Llodata+2     	# store blockno to lodata clears r4
+	ar	%r4,%r2			# r4 (clear): ebl = blk + nbl
+	bctr    %r4,0			# decrement r4 ( last blk touched 
+	srda	%r2,32			# trk = blk / bpt, bot = blk % bpt 
+	dr	%r2,%r6			# r3: trk, r2: bot
+	ahi	%r2,1			# bot++ ( we start counting at 1 )
+	stcm	%r2,1,.Llodata+12     	# store bot to lodata
+	xr 	%r2,%r2			# cy  = trk / heads, hd  = trk % heads
+	dr	%r2,%r7			# r3: cy, r2: hd
+	sll	%r3,16			# combine to CCHH in r3
+	or	%r3,%r2
+	st	%r3,.Ldedata+8     	# store cchh to dedata	
+	st	%r3,.Llodata+4     	# store cchh to lodata	
+	st	%r3,.Llodata+8     	# store cchh to lodata	
+	lr	%r15,%r5		# save r5
+	srda	%r4,32			# tr2 = ebl / bpt
+	dr	%r4,%r6			# r5: tr2, r4: bot2
+	xr 	%r4,%r4			# cy2 = tr2 / heads, hd2 = hd2 % heads
+	dr	%r4,%r7			# r5: cy2, r4: hd2 
+	stcm	%r5,3,.Ldedata+12     	# store cy2,hd2 to dedata
+	stcm	%r4,3,.Ldedata+14     	# store cy2,hd2 to dedata
+	lr	%r5,%r15		# restore r5
+	# CCWs are setup now, arent they?
+	bras	%r15,.Lssch		# start I/O
+	br	%r14			# return to caller
+.L005:	
+	ah 	%r3,.Lcountarea+6     	# add blocksize to target address
+	ahi	%r12,8			# add sizeof(ccw) to base address
+	j	.Lrdloop
+# end of function
+# This function does the start IO
+# r1:	Subchannel number
+# r8:	ORB address
+# r9:	IRB address
+.Lssch:
+	lhi     %r13,10			# initialize retries
+.L012:	
+	ssch	.Lorb			# start I/O
+	jz	.Ltpi			# ok?
+	bras	%r14,.Ldisab		# error
+.Ltpi:	
+	lpsw	.Lwaitpsw     		# load wait-PSW
+.Lionewaddr:	
+	c	%r1,0xb8     		# compare to ipl subhchannel
+	jnz	.Ltpi			# not equal: loop
+	clc	0xbc(4),.Lorb 		# cross check the intparm
+	jnz	.Ltpi               	# not equal:	loop 
+	tsch    .Lirb			# get status
+	tm	.Lirb+9,0xff		# channel status ?
+	jz	.L003			# CS == 0x00
+	bras	%r14,.Ldisab		# error
+.L003:
+	tm	.Lirb+8,0xf3		# DS different from CE/DE
+	jz	.L004			# ok ?
+	bct	%r13,.L012		# retries <= 5 ?
+	bras	%r14,.Ldisab		# error
+.L004:
+	tm	.Lirb+8,0x04		# DE set?
+	jz	.Ltpi			# DE not set, loop
+.Lsschend:
+	br	%r15			# return to caller
+# end of function
+# In case of error goto disabled wait with %r14 containing the caller
+.Ldisab:
+	st	%r14,.Ldisabpsw+4     
+	lpsw	.Ldisabpsw     
+
+# FIXME pre-initialized data should be listed first
+# NULLed storage can be taken from anywhere ;) 
+.L3390:	
+	.word	0x3390
+.Lblklst:	
+	.long   0x00002000     
+	.align 8
+.Ldisabpsw: 
+	.long 0x000a0000,0x00000000
+.Lwaitpsw:
+	.long 0x020a0000,0x00000000+.Ltpi
+.Lorb:	
+	.long 0x0049504c,0x0080ff00	# intparm is " IPL"
+	.long 0x00000000		# CCW address
+.Lc6:	.long 0xff000000
+.Lstart:
+	.long	0x00010000              # do not separate .Lstart and .Lparm
+.Lparm:	
+	.long	0x00008000              # they are loaded with a LM
+.Lrdcdata:
+	.long 0x00000000,0x00000000
+	.long 0x00000000,0x00000000
+	.long 0x00000000,0x00000000
+	.long 0x00000000,0x00000000
+	.long 0x00000000,0x00000000
+	.long 0x00000000,0x00000000
+	.long 0x00000000,0x00000000
+	.long 0x00000000,0x00000000
+.Lirb:
+	.long 0x00000000,0x00000000
+	.long 0x00000000,0x00000000
+	.long 0x00000000,0x00000000
+	.long 0x00000000,0x00000000
+	.long 0x00000000,0x00000000
+	.long 0x00000000,0x00000000
+	.long 0x00000000,0x00000000
+	.long 0x00000000,0x00000000
+.Lcountarea:	
+	.word 0x0000			# cyl;
+	.word 0x0000			# head;
+	.byte 0x00			# record;
+	.byte 0x00			# key length;
+	.word 0x0000			# data length == blocksize;
+.Ldedata:
+	.long 0x40c00000,0x00000000
+	.long 0x00000000,0x00000000
+.Llodata:
+	.long 0x06000001,0x00000000
+	.long 0x00000000,0x01000000
+	.long 0x12345678
+	.org 0x3c8
+.Lrdcccw:				# CCW read device characteristics
+	.long 0x64400040,0x00000000+.Lrdcdata
+	.long 0x63400010,0x00000000+.Ldedata
+	.long 0x47400010,0x00000000+.Llodata
+	.long 0x12000008,0x00000000+.Lcountarea
+.Ldeccw:
+	.long 0x63400010,0x00000000+.Ldedata
+.Lloccw:
+	.long 0x47400010,0x00000000+.Llodata
+.Lrdccw:	
+	.long 0x86400000,0x00000000
+	.org 0x400
+# end of pre initialized data is here CCWarea follows
+# from here we load 1k blocklist 
+# end of function
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/boot/iplfba.S linux.14p16/arch/s390/boot/iplfba.S
--- linux.vanilla/arch/s390/boot/iplfba.S	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/boot/iplfba.S	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,131 @@
+#
+#  Ipl block for fba devices
+#    Copyright (C) 1998 IBM Corporation
+#    Author(s): Martin Schwidefsky
+#
+#  startup for ipl at address 0
+#  start with restart
+
+# The first 24 byes are loaded by ipl to addresses 0-23 (a PSW and two CCWs).
+# The CCWs on 8-23 are used as a continuation of the implicit ipl channel
+# program. The fba ipl loader only uses the CCW on 8-15 to load the first 512
+# byte block to location 0-511 (the reading starts again at block 0, byte 0).
+# The second CCW is used to store the location of the load list.
+        .org   0
+        .long  0x00080000,0x80000000+_start    # The first 24 byte are loaded
+        .long  0x02000000,0x20000200           # by ipl to addresses 0-23.
+        .long  0x00000001,0x00000001           # (PSW, one CCW & loadlist info).
+
+        .globl _start
+_start:
+	basr  %r13,0
+.LPG0:	
+	l     %r1,0xb8                         # load ipl subchannel number
+        lhi   %r2,0x200                        # location for the loadlist
+        lm    %r3,%r4,0x10                     # blocknr and length of loadlist
+        bras  %r14,.Lloader                    # load loadlist
+
+        lhi   %r11,0x400
+        lhi   %r12,0x200                       # load address of loadlist
+        l     %r3,0(%r12)                      # get first block number
+        l     %r4,4(%r12)                      # get first block count
+        la    %r12,8(%r12)
+        j     .Llistloop
+        .org  0x50
+.Llistloop:
+        lr    %r2,%r11                         # load address
+        lr    %r5,%r4                          # block count
+        mhi   %r5,512
+        la    %r11,0(%r5,%r11)                 # update load address
+        bras  %r14,.Lloader                    # load chunk of the image
+        l     %r3,0(%r12)                      # get next block number
+        icm   %r4,15,4(%r12)                   # get next block count
+        la    %r12,8(%r12)
+        jnz   .Llistloop
+
+#
+# everything loaded, go for it
+#
+        l     %r1,.Lstart-.LPG0(%r13)
+	br    %r1
+
+#
+# subroutine for loading a sequence of block from fba
+# %r2: load address (24 bit address)
+# %r3: number of first block (unsigned long)
+# %r4: number of blocks to load (unsigned short)
+#
+        .org  0xC0
+.Lloader:
+        la    %r5,.Llo-.LPG0(%r13)
+        sth   %r4,2(%r5)                       # initialize block count
+        st    %r3,4(%r5)                       # initialize block number
+        la    %r5,.Lccws-.LPG0(%r13)
+        mhi   %r4,512
+        sth   %r4,22(%r5)                      # initialize byte count
+	icm   %r2,8,16(%r5)
+        st    %r2,16(%r5)                      # initialize CCW data address
+
+        slr   %r2,%r2
+        la    %r3,.Lorb-.LPG0(%r13)            # r2 = address of orb into r2
+        la    %r4,.Ltinfo-.LPG0(%r13)          # r3 = address of tpi info block
+        la    %r5,.Lirb-.LPG0(%r13)            # r4 = address of irb
+
+        lctl  %c6,%c6,.Lc6-.LPG0(%r13)
+.Lldlp:
+        ssch  0(%r3)                           # read blocks
+.Ltpi:
+        tpi   0(%r4)                           # test pending interrupt
+        jz    .Ltpi
+        c     %r1,0(%r4)                       # compare subchannel number
+        jne   .Ltpi
+        tsch  0(%r5)
+        slr   %r0,%r0
+        tm    8(%r5),0x82                      # do we have a problem ?
+        jnz   .Ldwpsw
+        tm    8(%r5),0x04                      # got device end ?
+        jz    .Ltpi
+.Lexit:
+        br    %r14
+
+        .align 8
+.Ldwpsw:.long  0x000a0000,0x00000000
+.Lorb:	.long  0x00000000,0x0000ff00,.Lccws
+.Ltinfo:.long  0
+.Lirb:	.long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+.Lc6:   .long  0xff000000
+.Lloadp:.long  0,0
+.Lparm:	.long  0x10400
+.Lstart:.long  0x10000
+        .align 8
+.Lccws: .long  0x63000000+.Lde,0x60000010      # define extent
+        .long  0x43000000+.Llo,0x60000008      # locate
+# offset 1 in read CCW: data address (24 bit)
+# offset 6 in read CCW: number of bytes (16 bit)
+        .long  0x42000000,0x20000000           # read
+.Lde:   .long  0x40000200,0x00000000
+        .long  0x00000000,0x00001000
+# offset 2 in .Llo: block count (unsigned short)
+# offset 4 in .Llo: block number (unsigned long)
+.Llo:   .long  0x06000000,0x00000000
+
+        .org   0x200
+        .long  0x00000002,0x0000007f
+        .long  0x00000081,0x0000007f
+        .long  0x00000100,0x0000007f
+        .long  0x0000017f,0x0000007f
+        .long  0x000001fe,0x0000007f
+        .long  0x0000027d,0x0000007f
+        .long  0x000002fc,0x0000007f
+        .long  0x0000037b,0x0000007f
+        .long  0x000003fa,0x0000007f
+        .long  0x00000479,0x0000007f
+        .long  0x000004f8,0x0000007f
+        .long  0x00000577,0x0000007f
+        .long  0x000005f6,0x0000007f
+        .long  0x00000675,0x0000007f
+        .long  0x000006f4,0x0000007f
+        .long  0x00000773,0x0000003f
+        .long  0x00000000,0x00000000
+        .org   0x400
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/boot/silo.c linux.14p16/arch/s390/boot/silo.c
--- linux.vanilla/arch/s390/boot/silo.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/boot/silo.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,408 @@
+/*
+ *  arch/s390/boot/silo.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Holger Smolinski <linux390@de.ibm.com>
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <dirent.h>
+#include <linux/fs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <asm/ioctl.h>
+
+/* from dasd.h */
+#define DASD_PARTN_BITS 2
+#define BIODASDRWTB _IOWR('D',5,int)
+/* end */
+
+#define PRINT_LEVEL(x,y...) if ( silo_options.verbosity >= x ) printf(y)
+#define ERROR_LEVEL(x,y...) if ( silo_options.verbosity >= x ) fprintf(stderr,y)
+#define TOGGLE(x) ((x)=((x)?(0):(1)))
+#define GETARG(x) {int len=strlen(optarg);x=malloc(len);strncpy(x,optarg,len);PRINT_LEVEL(1,"%s set to %s\n",#x,optarg);}
+
+#define ITRY(x) if ( (x) == -1 ) { ERROR_LEVEL(0,"%s (line:%d) '%s' returned %d='%s'\n", __FILE__,__LINE__,#x,errno,strerror(errno)); usage(); exit(1); }
+#define NTRY(x) if ( (x) == 0 ) { ERROR_LEVEL(0,"%s (line:%d) '%s' returned %d='%s'\n", __FILE__,__LINE__,#x,errno,strerror(errno)); usage(); exit(1); }
+
+#define MAX_CLUSTERS 256
+#define PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
+
+struct silo_options
+  {
+    short int verbosity;
+    struct
+      {
+	unsigned char testonly;
+      }
+    flags;
+    char *image;
+    char *ipldevice;
+    char *parmfile;
+    char *ramdisk;
+    char *bootsect;
+  }
+silo_options =
+{
+  1,				/* verbosity */
+  {
+    0,				/* testonly */
+  }
+  ,
+    "./image",			/* image */
+    NULL,			/* ipldevice */
+    NULL,			/* parmfile */
+    NULL,			/* initrd */
+    "ipleckd.boot",		/* bootsector */
+};
+
+struct blockdesc
+  {
+    unsigned long off;
+    unsigned short ct;
+    unsigned long addr;
+  };
+
+struct blocklist
+  {
+    struct blockdesc blk[MAX_CLUSTERS];
+    unsigned short ix;
+  };
+
+void
+usage (void)
+{
+  printf ("Usage:\n");
+  printf ("silo -d ipldevice [additional options]\n");
+  printf ("-d /dev/node : set ipldevice to /dev/node\n");
+  printf ("-f image : set image to image\n");
+  printf ("-p parmfile : set parameter file to parmfile\n");
+  printf ("-b bootsect : set bootsector to bootsect\n");
+  printf ("Additional options\n");
+  printf ("-v: increase verbosity level\n");
+  printf ("-v#: set verbosity level to #\n");
+  printf ("-t: toggle testonly flag\n");
+  printf ("-h: print this message\n");
+  printf ("-?: print this message\n");
+}
+
+int
+parse_options (struct silo_options *o, int argc, char *argv[])
+{
+  int rc = 0;
+  int oc;
+  if (argc == 1)
+    {
+      usage ();
+      exit (0);
+    }
+  while ((oc = getopt (argc, argv, "f:d:p:r:b:B:h?v::t")) != -1)
+    {
+      switch (oc)
+	{
+	case 't':
+	  TOGGLE (o->flags.testonly);
+	  PRINT_LEVEL (1, "Testonly flag is now %sactive\n", o->flags.testonly ? "" : "in");
+	  break;
+	case 'v':
+	  {
+	    unsigned short v;
+	    if (optarg && sscanf (optarg, "%hu", &v))
+	      o->verbosity = v;
+	    else
+	      o->verbosity++;
+	    PRINT_LEVEL (1, "Verbosity value is now %hu\n", o->verbosity);
+	    break;
+	  }
+	case 'h':
+	case '?':
+	  usage ();
+	  break;
+	case 'd':
+	  GETARG (o->ipldevice);
+	  break;
+	case 'f':
+	  GETARG (o->image);
+	  break;
+	case 'p':
+	  GETARG (o->parmfile);
+	  break;
+	case 'r':
+	  GETARG (o->ramdisk);
+	  break;
+	case 'b':
+	  GETARG (o->bootsect);
+	  break;
+	default:
+	  rc = EINVAL;
+	  break;
+	}
+    }
+  return rc;
+}
+
+int
+verify_device (char *name)
+{
+  int rc = 0;
+  struct stat dst;
+  struct stat st;
+  ITRY (stat (name, &dst));
+  if (S_ISBLK (dst.st_mode))
+    {
+      if (!(MINOR (dst.st_rdev) & PARTN_MASK))
+	{
+	  rc = dst.st_rdev;
+	}
+      else
+	/* invalid MINOR & PARTN_MASK */
+	{
+	  ERROR_LEVEL (1, "Cannot boot from partition %d %d %d",
+		       (int) PARTN_MASK, (int) MINOR (dst.st_rdev), (int) (PARTN_MASK & MINOR (dst.st_rdev)));
+	  rc = -1;
+	  errno = EINVAL;
+	}
+    }
+  else
+    /* error S_ISBLK */
+    {
+      ERROR_LEVEL (1, "%s is no block device\n", name);
+      rc = -1;
+      errno = EINVAL;
+    }
+  return rc;
+}
+
+int
+verify_file (char *name, int dev)
+{
+  int rc = 0;
+  struct stat dst;
+  struct stat st;
+  int bs = 1024;
+  int l;
+  ITRY (stat (name, &dst));
+  if (S_ISREG (dst.st_mode))
+    {
+      if ((unsigned) MAJOR (dev) == (unsigned) MAJOR (dst.st_dev) && (unsigned) MINOR (dev) == (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK))
+	{
+	  /* whatever to do if all is ok... */
+	}
+      else
+	/* devicenumber doesn't match */
+	{
+	  ERROR_LEVEL (1, "%s is not on device (%d/%d) but on (%d/%d)\n", name, (unsigned) MAJOR (dev), (unsigned) MINOR (dev), (unsigned) MAJOR (dst.st_dev), (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK));
+	  rc = -1;
+	  errno = EINVAL;
+	}
+    }
+  else
+    /* error S_ISREG */
+    {
+      ERROR_LEVEL (1, "%s is neither regular file nor linkto one\n", name);
+      rc = -1;
+      errno = EINVAL;
+    }
+  return rc;
+}
+
+int
+verify_options (struct silo_options *o)
+{
+  int rc = 0;
+  int dev = 0;
+  int crc = 0;
+  if (!o->ipldevice || !o->image || !o->bootsect)
+    {
+      usage ();
+      exit (1);
+    }
+  PRINT_LEVEL (1, "IPL device is: '%s'", o->ipldevice);
+
+  ITRY (dev = verify_device (o->ipldevice));
+  PRINT_LEVEL (2, "...ok...(%d/%d)", (unsigned short) MAJOR (dev), (unsigned short) MINOR (dev));
+  PRINT_LEVEL (1, "\n");
+
+  PRINT_LEVEL (0, "bootsector is: '%s'", o->bootsect);
+  ITRY (verify_file (o->bootsect, dev));
+  PRINT_LEVEL (1, "...ok...");
+  PRINT_LEVEL (0, "\n");
+
+  PRINT_LEVEL (0, "Kernel image is: '%s'", o->image);
+  ITRY (verify_file (o->image, dev));
+  PRINT_LEVEL (1, "...ok...");
+  PRINT_LEVEL (0, "\n");
+
+  if (o->parmfile)
+    {
+      PRINT_LEVEL (0, "parameterfile is: '%s'", o->parmfile);
+      ITRY (verify_file (o->parmfile, dev));
+      PRINT_LEVEL (1, "...ok...");
+      PRINT_LEVEL (0, "\n");
+    }
+
+  if (o->ramdisk)
+    {
+      PRINT_LEVEL (0, "initialramdisk is: '%s'", o->ramdisk);
+      ITRY (verify_file (o->ramdisk, dev));
+      PRINT_LEVEL (1, "...ok...");
+      PRINT_LEVEL (0, "\n");
+    }
+
+  return crc;
+}
+
+
+int
+add_file_to_blocklist (char *name, struct blocklist *lst, long addr)
+{
+  int fd;
+  int devfd;
+  struct stat fst;
+  int i;
+  int blk;
+  int bs;
+  int blocks;
+
+  int rc = 0;
+
+  ITRY (fd = open (name, O_RDONLY));
+  ITRY (fstat (fd, &fst));
+  ITRY (mknod ("/tmp/silodev", S_IFBLK | S_IRUSR | S_IWUSR, fst.st_dev));
+  ITRY (devfd = open ("/tmp/silodev", O_RDONLY));
+  ITRY (ioctl (fd, FIGETBSZ, &bs));
+  blocks = (fst.st_size + bs - 1) / bs;
+  for (i = 0; i < blocks; i++)
+    {
+      blk = i;
+      ITRY (ioctl (fd, FIBMAP, &blk));
+      if (blk)
+	{
+	  int oldblk = blk;
+	  ITRY (ioctl (devfd, BIODASDRWTB, &blk));
+	  if (blk <= 0)
+	    {
+	      ERROR_LEVEL (0, "BIODASDRWTB on blk %d returned %d\n", oldblk, blk);
+	      break;
+	    }
+	}
+      else
+	{
+	  PRINT_LEVEL (1, "Filled hole on blk %d\n", i);
+	}
+      if (lst->ix == 0 || i == 0  || 
+	  lst->blk[lst->ix - 1].ct >= 128 ||
+	  (lst->blk[lst->ix - 1].off + lst->blk[lst->ix - 1].ct != blk &&
+	   !(lst->blk[lst->ix - 1].off == 0 && blk == 0)))
+	{
+	  if (lst->ix >= MAX_CLUSTERS)
+	    {
+	      rc = 1;
+	      errno = ENOMEM;
+	      break;
+	    }
+	  lst->blk[lst->ix].off = blk;
+	  lst->blk[lst->ix].ct = 1;
+	  lst->blk[lst->ix].addr = addr + i * bs;
+	  lst->ix++;
+	}
+      else
+	{
+	  lst->blk[lst->ix - 1].ct++;
+	}
+    }
+  ITRY(unlink("/tmp/silodev"));
+  return rc;
+}
+
+int
+write_bootsect (char *ipldevice, char *bootsect, struct blocklist *blklst)
+{
+  int i;
+  int s_fd, d_fd, b_fd, bd_fd;
+  struct stat s_st, d_st, b_st;
+  int rc=0;
+  int bs, boots;
+  char buffer[4096];
+  ITRY (d_fd = open (ipldevice, O_RDWR | O_SYNC));
+  ITRY (fstat (d_fd, &d_st));
+  ITRY (s_fd = open ("boot.map", O_RDWR | O_TRUNC | O_CREAT | O_SYNC));
+  ITRY (verify_file (bootsect, d_st.st_rdev));
+  for (i = 0; i < blklst->ix; i++)
+    {
+      int offset = blklst->blk[i].off;
+      int addrct = blklst->blk[i].addr | (blklst->blk[i].ct & 0xff);
+      PRINT_LEVEL (1, "ix %i: offset: %06x count: %02x address: 0x%08x\n", i, offset, blklst->blk[i].ct & 0xff, blklst->blk[i].addr);
+      NTRY (write (s_fd, &offset, sizeof (int)));
+      NTRY (write (s_fd, &addrct, sizeof (int)));
+    }
+  ITRY (ioctl (s_fd,FIGETBSZ, &bs));
+  ITRY (stat ("boot.map", &s_st));
+  if (s_st.st_size > bs )
+    {
+      ERROR_LEVEL (0,"boot.map is larger than one block\n");
+      rc = -1;
+      errno = EINVAL;
+    }
+  boots=0;
+  ITRY (mknod ("/tmp/silodev", S_IFBLK | S_IRUSR | S_IWUSR, s_st.st_dev));
+  ITRY (bd_fd = open ("/tmp/silodev", O_RDONLY));
+  ITRY ( ioctl(s_fd,FIBMAP,&boots));
+  ITRY (ioctl (bd_fd, BIODASDRWTB, &boots));
+  PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots);
+  close (bd_fd);
+  close(s_fd);
+  ITRY (unlink("/tmp/silodev"));
+  /* Now patch the bootsector */
+  ITRY (b_fd = open (bootsect, O_RDONLY));
+  NTRY (read (b_fd, buffer, 4096));
+  memset (buffer + 0xe0, 0, 8);
+  *(int *) (buffer + 0xe0) = boots;
+  NTRY (write (d_fd, buffer, 4096));
+  NTRY (write (d_fd, buffer, 4096));
+  close (b_fd);
+  close (d_fd);
+  return rc;
+}
+
+int
+do_silo (struct silo_options *o)
+{
+  int rc = 0;
+
+  int device_fd;
+  int image_fd;
+  struct blocklist blklist;
+  memset (&blklist, 0, sizeof (struct blocklist));
+  ITRY (add_file_to_blocklist (o->image, &blklist, 0x00000000));
+  if (o->parmfile)
+    {
+      ITRY (add_file_to_blocklist (o->parmfile, &blklist, 0x00008000));
+    }
+  if (o->ramdisk)
+    {
+      ITRY (add_file_to_blocklist (o->ramdisk, &blklist, 0x00800000));
+    }
+  ITRY (write_bootsect (o->ipldevice, o->bootsect, &blklist));
+
+  return rc;
+}
+
+int
+main (int argct, char *argv[])
+{
+  int rc = 0;
+  ITRY (parse_options (&silo_options, argct, argv));
+  ITRY (verify_options (&silo_options));
+  ITRY (do_silo (&silo_options));
+  return rc;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/config.in linux.14p16/arch/s390/config.in
--- linux.vanilla/arch/s390/config.in	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/config.in	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,68 @@
+
+# For a description of the syntax of this configuration file,
+# see the Configure script.
+#
+mainmenu_name "Linux Kernel Configuration"
+define_bool CONFIG_ARCH_S390 y
+
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
+mainmenu_option next_comment
+comment 'Processor type and features'
+bool 'Symmetric multi-processing support' CONFIG_SMP
+bool 'IEEE FPU emulation' CONFIG_IEEEFPU_EMULATION
+endmenu
+
+mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+  bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
+  bool 'Kernel module loader' CONFIG_KMOD
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'General setup'
+bool 'Fast IRQ handling' CONFIG_FAST_IRQ
+bool 'Builtin IPL record support' CONFIG_IPL
+if [ "$CONFIG_IPL" = "y" ]; then
+  choice 'IPL method generated into head.S' \
+          "tape                   CONFIG_IPL_TAPE \
+           vm_reader              CONFIG_IPL_VM" tape
+fi
+bool 'Networking support' CONFIG_NET
+bool 'System V IPC' CONFIG_SYSVIPC
+bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+bool 'Sysctl support' CONFIG_SYSCTL
+tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+
+endmenu
+
+source drivers/s390/Config.in
+
+if [ "$CONFIG_NET" = "y" ]; then
+  source net/Config.in
+fi
+
+source fs/Config.in
+
+# source drivers/char/Config.in
+
+mainmenu_option next_comment
+comment 'Kernel hacking'
+
+#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
+bool 'Kernel profiling support' CONFIG_PROFILE
+if [ "$CONFIG_PROFILE" = "y" ]; then
+  int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
+fi
+if [ "$CONFIG_CTC" = "y" ]; then
+  bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
+fi
+# this does not work. bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+endmenu
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/defconfig linux.14p16/arch/s390/defconfig
--- linux.vanilla/arch/s390/defconfig	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/defconfig	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,157 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_ARCH_S390=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Processor type and features
+#
+CONFIG_SMP=y
+CONFIG_IEEEFPU_EMULATION=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# General setup
+#
+CONFIG_FAST_IRQ=y
+CONFIG_IPL=y
+# CONFIG_IPL_TAPE is not set
+CONFIG_IPL_VM=y
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_BINFMT_ELF=y
+
+#
+# S/390 block device drivers
+#
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_MDISK=y
+# CONFIG_MDISK_SYNC is not set
+CONFIG_DASD=y
+CONFIG_DASD_ECKD=y
+
+#
+# S/390 Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_CTC=y
+# CONFIG_IUCV is not set
+# CONFIG_DUMMY is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_TR is not set
+
+#
+# S/390 Terminal and Console options
+#
+CONFIG_3215=y
+CONFIG_3215_CONSOLE=y
+CONFIG_HWC=y
+CONFIG_HWC_CONSOLE=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_RARP is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_SMD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PROFILE is not set
+# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_MAGIC_SYSRQ is not set
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/Makefile linux.14p16/arch/s390/kernel/Makefile
--- linux.vanilla/arch/s390/kernel/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/Makefile	Wed Dec 15 22:28:41 1999
@@ -0,0 +1,51 @@
+#
+# Makefile for the linux kernel.
+#
+# 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 definitions are now in the main makefile...
+
+ifdef CONFIG_SMP
+.S.o:
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+else
+.S.o:
+	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+endif
+
+all: kernel.o head.o init_task.o
+
+O_TARGET := kernel.o
+O_OBJS   := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \
+            setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
+            s390fpu.o s390io.o 
+
+OX_OBJS  := s390ksyms.o
+MX_OBJS  :=
+
+ifdef CONFIG_SMP
+O_OBJS += smp.o
+endif
+
+ifeq ($(CONFIG_IEEEFPU_EMULATION),y)
+  O_OBJS += mathemu.o floatlib.o
+endif
+
+#
+# Kernel debugging
+#
+ifdef CONFIG_REMOTE_DEBUG
+O_OBJS += gdb-stub.o #gdb-low.o 
+endif
+
+
+
+include $(TOPDIR)/Rules.make
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/bitmap.S linux.14p16/arch/s390/kernel/bitmap.S
--- linux.vanilla/arch/s390/kernel/bitmap.S	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/bitmap.S	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,37 @@
+/*
+ *  arch/s390/kernel/bitmap.S
+ *    Bitmaps for set_bit, clear_bit, test_and_set_bit, ...
+ *    See include/asm-s390/{bitops.h|posix_types.h} for details
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+         .globl _oi_bitmap
+_oi_bitmap:
+         .byte  0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
+
+         .globl _ni_bitmap
+_ni_bitmap:
+         .byte  0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F
+
+         .globl _zb_findmap
+_zb_findmap:
+         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5
+         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 
+         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6
+         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5
+         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7
+         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5
+         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6
+         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5
+         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+         .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/cpcmd.c linux.14p16/arch/s390/kernel/cpcmd.c
--- linux.vanilla/arch/s390/kernel/cpcmd.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/cpcmd.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,53 @@
+/*
+ *  arch/s390/kernel/cpcmd.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+#include <linux/stddef.h>
+#include <asm/string.h>
+#include <asm/ebcdic.h>
+
+void cpcmd(char *cmd, char *response, int rlen)
+{
+        const int mask = 0x40000000L;
+        char obuffer[128];
+        int olen;
+
+        olen = strlen(cmd);
+        strcpy(obuffer, cmd);
+        ASCEBC(obuffer,olen);
+
+        if (response != NULL && rlen > 0) {
+                asm volatile ("LRA   2,0(0,%0)\n\t"
+                              "LR    4,%1\n\t"
+                              "O     4,%4\n\t"
+                              "LRA   3,0(0,%2)\n\t"
+                              "LR    5,%3\n\t"
+                              ".long 0x83240008 # Diagnose 83\n\t"
+                              : /* no output */
+                              : "a" (obuffer), "d" (olen),
+                                "a" (response), "d" (rlen), "m" (mask)
+                              : "2", "3", "4", "5" );
+                EBCASC(response, rlen);
+        } else {
+                asm volatile ("LRA   2,0(0,%0)\n\t"
+                              "LR    3,%1\n\t"
+                              ".long 0x83230008 # Diagnose 83\n\t"
+                              : /* no output */
+                              : "a" (obuffer), "d" (olen)
+                              : "2", "3"  );
+        }
+}
+
+int sys_msgcp(char *str)
+{
+        char buffer[256];
+
+        sprintf(buffer, "MSG * %s", str);
+        cpcmd(buffer, NULL, 0);
+        cpcmd("STOP", NULL, 0);
+}
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/cpcmd.h linux.14p16/arch/s390/kernel/cpcmd.h
--- linux.vanilla/arch/s390/kernel/cpcmd.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/cpcmd.h	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,14 @@
+/*
+ *  arch/s390/kernel/cpcmd.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+#ifndef __CPCMD__
+#define __CPCMD__
+
+extern void cpcmd(char *cmd, char *response, int rlen);
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/ebcdic.c linux.14p16/arch/s390/kernel/ebcdic.c
--- linux.vanilla/arch/s390/kernel/ebcdic.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/ebcdic.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,242 @@
+/*
+ *  arch/s390/kernel/ebcdic.c
+ *    ECBDIC -> ASCII, ASCII -> ECBDIC,
+ *    upper to lower case (EBCDIC) conversion tables.
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *               Martin Peschke <peschke@fh-brandenburg.de>
+ */
+
+#include <asm/types.h>
+
+/*
+ * ASCII (IBM PC 437)  -> EBCDIC 037
+ */
+__u8 _ascebc[256] =
+{
+ /*00 NUL   SOH   STX   ETX   EOT   ENQ   ACK   BEL */
+     0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+ /*08  BS    HT    LF    VT    FF    CR    SO    SI */
+ /*              ->NL                               */
+     0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /*10 DLE   DC1   DC2   DC3   DC4   NAK   SYN   ETB */
+     0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+ /*18 CAN    EM   SUB   ESC    FS    GS    RS    US */
+ /*                               ->IGS ->IRS ->IUS */
+     0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+ /*20  SP     !     "     #     $     %     &     ' */
+     0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+ /*28   (     )     *     +     ,     -    .      / */
+     0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+ /*30   0     1     2     3     4     5     6     7 */
+     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ /*38   8     9     :     ;     <     =     >     ? */
+     0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+ /*40   @     A     B     C     D     E     F     G */
+     0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ /*48   H     I     J     K     L     M     N     O */
+     0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ /*50   P     Q     R     S     T     U     V     W */
+     0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ /*58   X     Y     Z     [     \     ]     ^     _ */
+     0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
+ /*60   `     a     b     c     d     e     f     g */
+     0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ /*68   h     i     j     k     l     m     n     o */
+     0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ /*70   p     q     r     s     t     u     v     w */
+     0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ /*78   x     y     z     {     |     }     ~    DL */
+     0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+ /*80*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*88*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*90*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*98*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A0*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A8*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B0*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B8*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C0*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C8*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D0*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D8*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E0        sz						*/
+     0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E8*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F0*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F8*/
+     0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+/*
+ * EBCDIC 037 -> ASCII (IBM PC 437)
+ */
+__u8 _ebcasc[256] =
+{
+ /* 0x00   NUL   SOH   STX   ETX  *SEL    HT  *RNL   DEL */
+          0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+ /* 0x08   -GE  -SPS  -RPT    VT    FF    CR    SO    SI */
+          0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /* 0x10   DLE   DC1   DC2   DC3  -RES   -NL    BS  -POC
+                                  -ENP  ->LF             */
+          0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+ /* 0x18   CAN    EM  -UBS  -CU1  -IFS  -IGS  -IRS  -ITB
+                                                    -IUS */
+          0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x20   -DS  -SOS    FS  -WUS  -BYP    LF   ETB   ESC
+                                  -INP                   */
+          0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+ /* 0x28   -SA  -SFE   -SM  -CSP  -MFA   ENQ   ACK   BEL
+                       -SW                               */ 
+          0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+ /* 0x30  ----  ----   SYN   -IR   -PP  -TRN  -NBS   EOT */
+          0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+ /* 0x38  -SBS   -IT  -RFF  -CU3   DC4   NAK  ----   SUB */
+          0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+ /* 0x40    SP   RSP           �ä              ----       */
+          0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+ /* 0x48                       .     <     (     +     | */
+          0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+ /* 0x50     &                                      ---- */
+          0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+ /* 0x58           �ß     !     $     *     )     ;       */
+          0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
+ /* 0x60     -     /  ----     �Ä  ----  ----  ----       */
+          0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+ /* 0x68              ----     ,     %     _     >     ? */ 
+          0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+ /* 0x70  ----        ----  ----  ----  ----  ----  ---- */
+          0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x78     *     `     :     #     @     '     =     " */
+          0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+ /* 0x80     *     a     b     c     d     e     f     g */
+          0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ /* 0x88     h     i              ----  ----  ----       */
+          0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+ /* 0x90     �°     j     k     l     m     n     o     p */
+          0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+ /* 0x98     q     r                    ----        ---- */
+          0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+ /* 0xA0           ~     s     t     u     v     w     x */
+          0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ /* 0xA8     y     z              ----  ----  ----  ---- */
+          0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+ /* 0xB0     ^                    ----     �§  ----       */
+          0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+ /* 0xB8        ----     [     ]  ----  ----  ----  ---- */
+          0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
+ /* 0xC0     {     A     B     C     D     E     F     G */
+          0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ /* 0xC8     H     I  ----           �ö              ---- */
+          0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+ /* 0xD0     }     J     K     L     M     N     O     P */
+          0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ /* 0xD8     Q     R  ----           �ü                   */
+          0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+ /* 0xE0     \           S     T     U     V     W     X */
+          0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ /* 0xE8     Y     Z        ----     �Ö  ----  ----  ---- */
+          0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+ /* 0xF0     0     1     2     3     4     5     6     7 */
+          0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ /* 0xF8     8     9  ----  ----     �Ü  ----  ----  ---- */
+          0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+
+/*
+ * EBCDIC 037 conversion table:
+ * from upper to lower case
+ */
+__u8 _ebc_tolower[256] =
+{
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+	0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+	0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+	0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+	0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+	0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+	0x60, 0x61, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+	0x48, 0x49, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+	0x70, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+	0x58, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+	0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+	0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9C, 0x9F,
+	0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+	0xA8, 0xA9, 0xAA, 0xAB, 0x8C, 0x8D, 0x8E, 0xAF,
+	0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
+	0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
+	0xC0, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+	0x88, 0x89, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+	0xD0, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+	0x98, 0x99, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+	0xE0, 0xE1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+	0xA8, 0xA9, 0xEA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+	0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+	0xF8, 0xF9, 0xFA, 0xDB, 0xDC, 0xDD, 0xDE, 0xFF
+};
+
+
+/*
+ * EBCDIC 037 conversion table:
+ * from lower to upper case
+ */
+__u8 _ebc_toupper[256] =
+{
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+	0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+	0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+	0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+	0x40, 0x41, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+	0x68, 0x69, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+	0x50, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+	0x78, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+	0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+	0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+	0x80, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+	0xC8, 0xC9, 0x8A, 0x8B, 0xAC, 0xAD, 0xAE, 0x8F,
+	0x90, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+	0xD8, 0xD9, 0x9A, 0x9B, 0x9E, 0x9D, 0x9E, 0x9F,
+	0xA0, 0xA1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+	0xE8, 0xE9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
+	0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
+	0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
+	0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+	0xC8, 0xC9, 0xCA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+	0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+	0xD8, 0xD9, 0xDA, 0xFB, 0xFC, 0xFD, 0xFE, 0xDF,
+	0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+	0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+	0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+	0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
+};
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/entry.S linux.14p16/arch/s390/kernel/entry.S
--- linux.vanilla/arch/s390/kernel/entry.S	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/entry.S	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,961 @@
+/*
+ *  arch/s390/kernel/entry.S
+ *    S390 low-level entry points.
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *               Hartmut Penner (hp@de.ibm.com),
+ *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <linux/config.h>
+#include <asm/lowcore.h>
+#include <asm/errno.h>
+#define ASSEMBLY
+#include <asm/smp.h>
+#include <asm/s390-regs-common.h>
+
+
+/*
+ * stack layout for the system_call stack entry
+ * Martin please don't modify these back to hard coded values 
+ * You know how bad I'm at mental arithmetic DJB & it gives 
+ * me grief when I modify the pt_regs
+ */
+SP_PTREGS    =  STACK_FRAME_OVERHEAD 
+SP_PSW       =  SP_PTREGS
+SP_R0        =  (SP_PSW+PSW_MASK_SIZE+PSW_ADDR_SIZE)
+SP_R1        =  (SP_R0+GPR_SIZE)
+SP_R2        =  (SP_R1+GPR_SIZE)
+SP_R3        =  (SP_R2+GPR_SIZE)
+SP_R4        =  (SP_R3+GPR_SIZE)
+SP_R5        =  (SP_R4+GPR_SIZE)
+SP_R6        =  (SP_R5+GPR_SIZE)
+SP_R7        =  (SP_R6+GPR_SIZE)
+SP_R8        =  (SP_R7+GPR_SIZE)
+SP_R9        =  (SP_R8+GPR_SIZE)
+SP_RA        =  (SP_R9+GPR_SIZE)
+SP_RB        =  (SP_RA+GPR_SIZE)
+SP_RC        =  (SP_RB+GPR_SIZE)
+SP_RD        =  (SP_RC+GPR_SIZE)
+SP_RE        =  (SP_RD+GPR_SIZE)
+SP_RF        =  (SP_RE+GPR_SIZE)
+SP_AREGS     =  (SP_RF+GPR_SIZE)
+SP_ORIG_R2   =  (SP_AREGS+(NUM_ACRS*ACR_SIZE))
+SP_TRAP      =  (SP_ORIG_R2+GPR_SIZE)
+#if CONFIG_REMOTE_DEBUG
+SP_CRREGS    =  (SP_TRAP+4)
+/* fpu registers are saved & restored by the gdb stub itself */
+SP_FPC       =  (SP_CRREGS+(NUM_CRS*CR_SIZE))
+SP_FPRS      =  (SP_FPC+FPC_SIZE+FPC_PAD_SIZE)
+SP_SIZE      =  (SP_FPRS+(NUM_FPRS*FPR_SIZE))
+#else
+SP_SIZE      =  (SP_TRAP+4)
+#endif
+/*
+ * these defines are offsets into the thread_struct
+ */
+_TSS_PTREGS  = 0
+_TSS_FPRS    = (_TSS_PTREGS+8)
+_TSS_AR2     = (_TSS_FPRS+136)
+_TSS_AR4     = (_TSS_AR2+4)
+_TSS_KSP     = (_TSS_AR4+4)
+_TSS_USERSEG = (_TSS_KSP+4)
+_TSS_ERROR   = (_TSS_USERSEG+4)
+_TSS_PROT    = (_TSS_ERROR+4)
+_TSS_TRAP    = (_TSS_PROT+4)
+_TSS_MM      = (_TSS_TRAP+4)
+_TSS_PER     = (_TSS_MM+8)
+
+/*
+ * these are offsets into the task-struct.
+ */
+state        =  0
+flags        =  4
+sigpending   =  8
+addr_limit   = 12
+exec_domain  = 20
+need_resched = 24
+
+/* PSW related defines */
+disable      = 0xFC
+enable       = 0x03
+daton        = 0x04
+
+
+#if 0
+/* some code left lying around in case we need a
+ *	printk for debugging purposes
+ */
+  sysc_printk:        .long  printk
+  sysc_msg:	      .string "<2>r15 %X\n"
+	.align 4
+		
+#	basr    %r13,0
+	l       %r0,SP_PSW+4(%r15)
+	sll     %r0,1
+	chi     %r0,0
+	jnz     sysc_dn
+	l       %r9,sysc_printk-sysc_lit(%r13)
+	la      %r2,sysc_msg-sysc_lit(%r13)
+	lr      %r3,%r15
+	basr    %r14,%r9
+sysc_dn:
+#endif
+
+/*
+ * Register usage in interrupt handlers:
+ *    R9  - pointer to current task structure
+ *    R13 - pointer to literal pool
+ *    R14 - return register for function calls
+ *    R15 - kernel stack pointer
+ */
+
+#define SAVE_ALL1(psworg) \
+	st      %r15,__LC_SAVE_AREA   ; \
+        tm      psworg+1,0x01         ; /* test problem state bit */ \
+	jz	0f		      ; /* skip stack setup save */ \
+	l	%r15,__LC_KERNEL_STACK ; /* problem state -> load ksp */ \
+0:	ahi     %r15,-SP_SIZE         ; /* make room for registers & psw */ \
+        srl     %r15,3                ; \
+        sll     %r15,3                ; /* align stack pointer to 8 */ \
+        stm     %r0,%r14,SP_R0(%r15)  ; /* store gprs 0-14 to kernel stack */ \
+        st      %r2,SP_ORIG_R2(%r15)  ; /* store original content of gpr 2 */ \
+        mvc     SP_RF(4,%r15),__LC_SAVE_AREA   ; /* move R15 to stack */ \
+        stam    %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */ \
+        mvc     SP_PSW(8,%r15),psworg ; /* move user PSW to stack */ \
+        xc      0(7,%r15),0(%r15)     ; /* clear back chain & trap ind. */ \
+        mvi     SP_TRAP+3(%r15),psworg ; /* store trap indication in pt_regs */ \
+        slr     %r0,%r0               ; \
+        sar     %a2,%r0               ; /* set ac.reg. 2 to primary space */ \
+        lhi     %r0,1                 ; \
+        sar     %a4,%r0               ; /* set access reg. 4 to home space */
+
+#define RESTORE_ALL1 \
+        mvc     0x50(8,0),SP_PSW(%r15)  ; /* move user PSW to lowcore */ \
+        lam     %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \
+        lm      %r0,%r15,SP_R0(%r15)  ; /* load gprs 0-15 of user */ \
+        ni      0x51(0),0xfd          ; /* clear wait state bit */ \
+        lpsw    0x50                    /* back to caller */
+
+#if CONFIG_REMOTE_DEBUG
+#define SAVE_ALL(psworg) \
+	SAVE_ALL1(psworg) \
+	tm      psworg+1,0x01         ; /* test problem state bit */ \
+	jz	0f		      ; /* skip stack setup save */ \
+	stctl    %c0,%c15,SP_CRREGS(%r15) ; /* save control regs for remote debugging */ \
+0:
+
+#define RESTORE_ALL  \
+	tm      SP_PSW+1(%r15),0x01          ; /* test problem state bit */ \
+	jz	0f		             ; /* skip cr restore */ \
+	lctl    %c0,%c15,SP_CRREGS(%r15) ; /* store control regs for remote debugging */ \
+0:	RESTORE_ALL1 
+#else
+	
+#define SAVE_ALL(psworg)  \
+	SAVE_ALL1(psworg)
+
+#define RESTORE_ALL  \
+	RESTORE_ALL1 
+#endif
+	
+#define GET_CURRENT /* load pointer to task_struct to R9 */ \
+        lhi     %r9,-8192             ; \
+        nr      %r9,15
+
+
+/*
+ * Scheduler resume function, called by switch_to
+ *  grp2 = (thread_struct *) prev->tss
+ *  grp3 = (thread_struct *) next->tss
+ * Returns:
+ *  gpr2 = prev
+ */
+        .globl  resume
+resume:
+        l       %r4,_TSS_PTREGS(%r3)
+        tm      SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ?
+        jz      RES_DN1                 # if not we're fine
+        stctl   %r9,%r11,24(%r15)       # We are using per stuff
+        clc     _TSS_PER(12,%r3),24(%r15)
+        je      RES_DN1                 # we got away without bashing TLB's
+        lctl    %c9,%c11,_TSS_PER(%r3)  # Nope we didn't
+RES_DN1:
+        stm     %r6,%r15,24(%r15)       # store resume registers of prev task
+	iac     %r1                     # get address space control bits
+        sacf    0
+	st      %r1,4(%r15)
+        st      %r15,_TSS_KSP(%r2) # store kernel stack ptr to prev->tss.ksp
+        lhi     %r0,-8192
+        nr      %r0,%r15
+        l       %r15,_TSS_KSP(%r3) # load kernel stack ptr from next->tss.ksp
+        lhi     %r1,8191
+        or      %r1,%r15
+        ahi     %r1,1
+        st      %r1,__LC_KERNEL_STACK   # __LC_KERNEL_STACK = new kernel stack
+        stam    %a2,%a2,_TSS_AR2(%r2)   # store kernel access reg. 2
+        stam    %a4,%a4,_TSS_AR4(%r2)   # store kernel access reg. 4
+        lam     %a2,%a2,_TSS_AR2(%r3)   # load kernel access reg. 2
+        lam     %a4,%a4,_TSS_AR4(%r3)   # load kernel access reg. 4
+        lctl    %c7,%c7,_TSS_USERSEG(%r3)   # load secondary-space for new task
+        lctl    %c13,%c13,_TSS_USERSEG(%r3) # load home-space for new task
+        lr      %r2,%r0                 # return task_struct of last task
+        l       %r1,4(%r15)
+        sacf    0(%r1)                  # set address space control bits
+        lm      %r6,%r15,24(%r15)       # load resume registers of next task
+        br      %r14
+
+/*
+ * SVC interrupt handler routine. System calls are synchronous events and
+ * are executed with interrupts enabled.
+ */
+
+sysc_lit:
+  sysc_bhmask:        .long  bh_mask
+  sysc_bhactive:      .long  bh_active
+  sysc_do_signal:     .long  do_signal
+  sysc_do_bottom_half:.long  do_bottom_half
+  sysc_schedule:      .long  schedule
+  sysc_trace:         .long  syscall_trace
+#ifdef __SMP__
+  sysc_schedtail:     .long  schedule_tail
+#endif
+  sysc_clone:         .long  sys_clone
+  sysc_fork:          .long  sys_fork
+  sysc_vfork:         .long  sys_vfork
+  sysc_sigreturn:     .long  sys_sigreturn
+  sysc_execve:        .long  sys_execve
+  sysc_sigsuspend:    .long  sys_sigsuspend
+  sysc_rt_sigsuspend: .long  sys_rt_sigsuspend
+
+	.globl  system_call
+system_call:
+        SAVE_ALL(0x20)
+        basr    %r13,0
+        ahi     %r13,sysc_lit-.   # setup base pointer R13 to sysc_lit
+        slr     %r8,%r8           # gpr 8 is call save (-> tracesys)
+        ic      %r8,0x8B          # get svc number from lowcore
+        stosm   24(%r15),0x03     # reenable interrupts
+        GET_CURRENT               # load pointer to task_struct to R9
+        sll     %r8,2
+        l       %r8,sys_call_table-sysc_lit(8,%r13) # get address of system call
+        tm      flags+3(%r9),0x20 # PF_TRACESYS
+        jnz     sysc_tracesys
+        basr    %r14,%r8          # call sys_xxxx
+        st      %r2,SP_R2(%r15)   # store return value (change R2 on stack)
+                                  # ATTENTION: check sys_execve_glue before
+                                  # changing anything here !!
+
+sysc_return:
+        GET_CURRENT               # load pointer to task_struct to R9
+        tm      SP_PSW+1(%r15),0x01 # returning to user ?
+#        tm      SP_PSW+2(%r15),0xc0 # returning to user or kernel thread ?
+        jno     sysc_leave        # no-> skip bottom half, resched & signal
+#
+# check, if bottom-half has to be done
+#
+        l       %r1,sysc_bhmask-sysc_lit(%r13)
+        l       %r0,0(%r1)
+        l       %r1,sysc_bhactive-sysc_lit(%r13)
+        n       %r0,0(%r1)
+        jnz     sysc_handle_bottom_half
+#
+# check, if reschedule is needed
+#
+sysc_return_bh:	
+        icm     %r0,15,need_resched(%r9) # get need_resched from task_struct
+        jnz     sysc_reschedule
+        icm     %r0,15,sigpending(%r9)   # get sigpending from task_struct
+        jnz     sysc_signal_return
+sysc_leave:
+  
+	stnsm   24(%r15),disable  # disable I/O and ext. interrupts
+        RESTORE_ALL
+
+#
+# call do_signal before return
+#
+sysc_signal_return:     
+        la      %r2,SP_PTREGS(%r15) # load pt_regs
+        sr      %r3,%r3           # clear *oldset
+        l       %r1,sysc_do_signal-sysc_lit(%r13)
+	la      %r14,sysc_leave-sysc_lit(%r13)
+        br      %r1               # return point is sysc_leave
+
+#
+# call trace before and after sys_call
+#
+sysc_tracesys:
+        l       %r1,sysc_trace-sysc_lit(%r13)
+	lhi     %r2,-ENOSYS
+	st      %r2,SP_R2(%r15)   # give sysc_trace an -ENOSYS retval
+        basr    %r14,%r1
+	lm      %r3,%r6,SP_R3(%r15)
+	l       %r2,SP_ORIG_R2(%r15)
+        basr    %r14,%r8          # call sys_xxx
+        st      %r2,SP_R2(%r15)   # store return value
+        l       %r1,sysc_trace-sysc_lit(%r13)
+	la      %r14,sysc_return-sysc_lit(%r13)
+        br      %r1               # return point is sysc_return
+
+
+#
+# call do_bottom_half and return from syscall, if interrupt-level
+# is zero
+#
+sysc_handle_bottom_half:        
+        l       %r1,sysc_do_bottom_half-sysc_lit(%r13)
+	la      %r14,sysc_return_bh-sysc_lit(%r13)
+        br      %r1               # call do_bottom_half
+
+#
+# call schedule with sysc_return as return-address
+#
+sysc_reschedule:        
+        l       %r1,sysc_schedule-sysc_lit(%r13)
+	la      %r14,sysc_return-sysc_lit(%r13)
+        br      %r1               # call scheduler, return to sysc_return
+
+#
+# a new process exits the kernel with ret_from_fork
+#
+        .globl  ret_from_fork
+ret_from_fork:  
+        basr    %r13,0
+        ahi     %r13,sysc_lit-.   # setup base pointer R13 to $SYSCDAT
+        GET_CURRENT               # load pointer to task_struct to R9
+        stosm   24(%r15),0x03     # reenable interrupts
+        sr      %r0,%r0           # child returns 0
+        st      %r0,SP_R2(%r15)   # store return value (change R2 on stack)
+#ifdef __SMP__
+        l       %r1,sysc_schedtail-sysc_lit(%r13)
+	la      %r14,sysc_return-sysc_lit(%r13)
+        br      %r1               # call schedule_tail, return to sysc_return
+#else
+        j       sysc_return
+#endif
+
+#
+# clone, fork, vfork, exec and sigreturn need glue,
+# because they all expect pt_regs as parameter,
+# but are called with different parameter.
+# return-address is set up above
+#
+sys_clone_glue: 
+        la      %r2,SP_PTREGS(%r15)    # load pt_regs
+        l       %r1,sysc_clone-sysc_lit(%r13)
+        br      %r1                   # branch to sys_clone
+
+sys_fork_glue:  
+        la      %r2,SP_PTREGS(%r15)    # load pt_regs
+        l       %r1,sysc_fork-sysc_lit(%r13)
+        br      %r1                   # branch to sys_fork
+
+sys_vfork_glue: 
+        la      %r2,SP_PTREGS(%r15)    # load pt_regs
+        l       %r1,sysc_vfork-sysc_lit(%r13)
+        br      %r1                   # branch to sys_vfork
+
+sys_execve_glue:        
+        la      %r2,SP_PTREGS(%r15)    # load pt_regs
+        l       %r1,sysc_execve-sysc_lit(%r13)
+        basr    %r14,%r1              # call sys_execve
+        ltr     %r2,%r2               # check if execve failed
+        jnz     sysc_return-4         # it did fail -> store result in gpr2
+        j       sysc_return           # SKIP ST 2,SP_R2(15) after BASR 14,8
+                                      # in system_call
+
+sys_sigreturn_glue:     
+        la      %r2,SP_PTREGS(%r15)   # load pt_regs as parameter
+        l       %r1,sysc_sigreturn-sysc_lit(%r13)
+        br      %r1                   # branch to sys_sigreturn
+
+#
+# sigsuspend and rt_sigsuspend need pt_regs as an additional
+# parameter and they have to skip the store of %r2 into the
+# user register %r2 because the return value was set in 
+# sigsuspend and rt_sigsuspend already and must not be overwritten!
+#
+
+sys_sigsuspend_glue:    
+        lr      %r5,%r4               # move mask back
+        lr      %r4,%r3               # move history1 parameter
+        lr      %r3,%r2               # move history0 parameter
+        la      %r2,SP_PTREGS(%r15)   # load pt_regs as first parameter
+        l       %r1,sysc_sigsuspend-sysc_lit(%r13)
+	la      %r14,sysc_return-sysc_lit(%r13) # skip store of return value
+        br      %r1                   # branch to sys_sigsuspend
+
+sys_rt_sigsuspend_glue: 
+        lr      %r4,%r3               # move sigsetsize parameter
+        lr      %r3,%r2               # move unewset parameter
+        la      %r2,SP_PTREGS(%r15)   # load pt_regs as first parameter
+        l       %r1,sysc_rt_sigsuspend-sysc_lit(%r13)
+	la      %r14,sysc_return-sysc_lit(%r13) # skip store of return value
+        br      %r1                   # branch to sys_rt_sigsuspend
+
+	.globl  sys_call_table	
+sys_call_table:
+        .long  sys_ni_syscall            /* 0 */
+        .long  sys_exit
+        .long  sys_fork_glue
+        .long  sys_read
+        .long  sys_write
+        .long  sys_open                  /* 5 */
+        .long  sys_close
+        .long  sys_waitpid
+        .long  sys_creat
+        .long  sys_link
+        .long  sys_unlink                /* 10 */
+        .long  sys_execve_glue
+        .long  sys_chdir
+        .long  sys_time
+        .long  sys_mknod
+        .long  sys_chmod                /* 15 */
+        .long  sys_lchown
+        .long  sys_ni_syscall           /* old break syscall holder */
+        .long  sys_stat
+        .long  sys_lseek
+        .long  sys_getpid               /* 20 */
+        .long  sys_mount
+        .long  sys_umount
+        .long  sys_setuid
+        .long  sys_getuid
+        .long  sys_stime                /* 25 */
+        .long  sys_ptrace
+        .long  sys_alarm
+        .long  sys_fstat
+        .long  sys_pause
+        .long  sys_utime                /* 30 */
+        .long  sys_ni_syscall           /* old stty syscall holder */
+        .long  sys_ni_syscall           /* old gtty syscall holder */
+        .long  sys_access
+        .long  sys_nice
+        .long  sys_ni_syscall           /* 35 */  /* old ftime syscall holder */
+        .long  sys_sync
+        .long  sys_kill
+        .long  sys_rename
+        .long  sys_mkdir
+        .long  sys_rmdir                /* 40 */
+        .long  sys_dup
+        .long  sys_pipe
+        .long  sys_times
+        .long  sys_ni_syscall           /* old prof syscall holder */
+        .long  sys_brk                  /* 45 */
+        .long  sys_setgid
+        .long  sys_getgid
+        .long  sys_signal
+        .long  sys_geteuid
+        .long  sys_getegid              /* 50 */
+        .long  sys_acct
+        .long  sys_ni_syscall           /* old phys syscall holder */
+        .long  sys_ni_syscall           /* old lock syscall holder */
+        .long  sys_ioctl
+        .long  sys_fcntl                /* 55 */
+        .long  sys_ni_syscall           /* old mpx syscall holder */
+        .long  sys_setpgid
+        .long  sys_ni_syscall           /* old ulimit syscall holder */
+        .long  sys_olduname
+        .long  sys_umask                /* 60 */
+        .long  sys_chroot
+        .long  sys_ustat
+        .long  sys_dup2
+        .long  sys_getppid
+        .long  sys_getpgrp              /* 65 */
+        .long  sys_setsid
+        .long  sys_sigaction
+        .long  sys_sgetmask
+        .long  sys_ssetmask
+        .long  sys_setreuid             /* 70 */
+        .long  sys_setregid
+        .long  sys_sigsuspend_glue
+        .long  sys_sigpending
+        .long  sys_sethostname
+        .long  sys_setrlimit            /* 75 */
+        .long  sys_getrlimit
+        .long  sys_getrusage
+        .long  sys_gettimeofday
+        .long  sys_settimeofday
+        .long  sys_getgroups            /* 80 */
+        .long  sys_setgroups
+        .long  old_select
+        .long  sys_symlink
+        .long  sys_lstat
+        .long  sys_readlink             /* 85 */
+        .long  sys_uselib
+        .long  sys_swapon
+        .long  sys_reboot
+        .long  old_readdir
+        .long  old_mmap                 /* 90 */
+        .long  sys_munmap
+        .long  sys_truncate
+        .long  sys_ftruncate
+        .long  sys_fchmod
+        .long  sys_fchown                /* 95 */
+        .long  sys_getpriority
+        .long  sys_setpriority
+        .long  sys_ni_syscall            /* old profil syscall holder */
+        .long  sys_statfs
+        .long  sys_fstatfs               /* 100 */
+        .long  sys_ioperm
+        .long  sys_socketcall
+        .long  sys_syslog
+        .long  sys_setitimer
+        .long  sys_getitimer             /* 105 */
+        .long  sys_newstat
+        .long  sys_newlstat
+        .long  sys_newfstat
+        .long  sys_uname
+        .long  sys_ni_syscall            /* 110 */ /* iopl for i386 */
+        .long  sys_vhangup
+        .long  sys_idle
+        .long  sys_ni_syscall            /* vm86old for i386 */
+        .long  sys_wait4
+        .long  sys_swapoff               /* 115 */
+        .long  sys_sysinfo
+        .long  sys_ipc
+        .long  sys_fsync
+        .long  sys_sigreturn_glue
+        .long  sys_clone_glue            /* 120 */
+        .long  sys_setdomainname
+        .long  sys_newuname
+        .long  sys_ni_syscall            /* modify_ldt for i386 */
+        .long  sys_adjtimex
+        .long  sys_mprotect              /* 125 */
+        .long  sys_sigprocmask
+        .long  sys_create_module
+        .long  sys_init_module
+        .long  sys_delete_module
+        .long  sys_get_kernel_syms       /* 130 */
+        .long  sys_quotactl
+        .long  sys_getpgid
+        .long  sys_fchdir
+        .long  sys_bdflush
+        .long  sys_sysfs                 /* 135 */
+        .long  sys_personality
+        .long  sys_ni_syscall            /* for afs_syscall */
+        .long  sys_setfsuid
+        .long  sys_setfsgid
+        .long  sys_llseek                /* 140 */
+        .long  sys_getdents
+        .long  sys_select
+        .long  sys_flock
+        .long  sys_msync
+        .long  sys_readv                 /* 145 */
+        .long  sys_writev
+        .long  sys_getsid
+        .long  sys_fdatasync
+        .long  sys_sysctl
+        .long  sys_mlock                 /* 150 */
+        .long  sys_munlock
+        .long  sys_mlockall
+        .long  sys_munlockall
+        .long  sys_sched_setparam
+        .long  sys_sched_getparam        /* 155 */
+        .long  sys_sched_setscheduler
+        .long  sys_sched_getscheduler
+        .long  sys_sched_yield
+        .long  sys_sched_get_priority_max
+        .long  sys_sched_get_priority_min  /* 160 */
+        .long  sys_sched_rr_get_interval
+        .long  sys_nanosleep
+        .long  sys_mremap
+        .long  sys_setresuid
+        .long  sys_getresuid             /* 165 */
+        .long  sys_ni_syscall            /* for vm86 */
+        .long  sys_query_module
+        .long  sys_poll
+        .long  sys_nfsservctl
+        .long  sys_setresgid             /* 170 */
+        .long  sys_getresgid
+        .long  sys_prctl
+        .long  sys_rt_sigreturn
+        .long  sys_rt_sigaction
+        .long  sys_rt_sigprocmask        /* 175 */
+        .long  sys_rt_sigpending
+        .long  sys_rt_sigtimedwait
+        .long  sys_rt_sigqueueinfo
+        .long  sys_rt_sigsuspend_glue
+        .long  sys_pread                 /* 180 */
+        .long  sys_pwrite
+        .long  sys_chown
+        .long  sys_getcwd
+        .long  sys_capget
+        .long  sys_capset                /* 185 */
+        .long  sys_sigaltstack
+        .long  sys_sendfile
+        .long  sys_ni_syscall            /* streams1 */
+        .long  sys_ni_syscall            /* streams2 */
+        .long  sys_vfork_glue            /* 190 */
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall            /* 195 */
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall     /* 205 */
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall    /* 215 */
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall    /* 225 */
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall    /* 235 */
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall    /* 245 */
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_ni_syscall
+        .long  sys_msgcp         /* 255 */
+
+/*
+ * Program check handler routine
+ */
+
+pgm_lit:
+  pgm_handle_per:  .long  handle_per_exception
+  pgm_jump_table:  .long  pgm_check_table
+  pgm_sysc_ret:    .long  sysc_return
+  pgm_sysc_lit:    .long  sysc_lit
+  pgm_do_signal:   .long  do_signal
+
+        .globl  pgm_check_handler
+pgm_check_handler:
+/*
+ * First we need to check for a special case:
+ * Single stepping an instruction that disables the PER event mask will
+ * cause a PER event AFTER the mask has been set. Example: SVC or LPSW.
+ * For a single stepped SVC the program check handler gets control after
+ * the SVC new PSW has been loaded. But we want to execute the SVC first and
+ * then handle the PER event. Therefore we update the SVC old PSW to point
+ * to the pgm_check_handler and branch to the SVC handler after we checked
+ * if we have to load the kernel stack register.
+ * For every other possible cause for PER event without the PER mask set
+ * we just ignore the PER event (FIXME: is there anything we have to do
+ * for LPSW?).
+ */
+        tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
+        jz      pgm_sv                   # skip if not
+        tm      __LC_PGM_OLD_PSW,0x40    # test if per event recording is on
+        jnz     pgm_sv                   # skip if it is
+# ok its one of the special cases, now we need to find out which one
+        clc     __LC_PGM_OLD_PSW(8),__LC_SVC_NEW_PSW
+        je      pgm_svcper
+# no interesting special case, ignore PER event
+        lpsw    0x28
+# it was a single stepped SVC that is causing all the trouble
+pgm_svcper:
+        st      %r15,__LC_SAVE_AREA
+        l       %r15,__LC_PGM_NEW_PSW+4  # prepare return psw
+        ahi     %r15,pgm_svcret-pgm_check_handler
+        st      %r15,__LC_PGM_OLD_PSW+4  # use pgm old psw as temp storage
+        tm      __LC_SVC_OLD_PSW,0x01    # test problem state of svc old psw
+        jz      .+8
+        l       %r15,__LC_KERNEL_STACK   # load ksp
+        ahi     %r15,-16
+        srl     %r15,3                   # align stack pointer to 8
+        sll     %r15,3
+        mvc     0(4,%r15),__LC_SAVE_AREA # save user r15
+        mvc     4(4,%r15),__LC_PGM_ILC   # save program check information
+        mvc     8(8,%r15),__LC_SVC_OLD_PSW # save return point
+        mvc     __LC_SVC_OLD_PSW(8),__LC_PGM_OLD_PSW # move prepared return pt.
+        j       system_call              # now do the svc
+pgm_svcret:
+        mvc     __LC_PGM_OLD_PSW(8),8(%r15) # return point is svc return point
+        mvc     __LC_PGM_ILC(4),4(%r15)  # restore program check info
+        l       %r15,0(%r15)             # restore user r15
+pgm_sv:
+        SAVE_ALL(0x28)
+        basr    %r13,0
+        ahi     %r13,pgm_lit-.    # setup base pointer R13 to $PGMDAT
+        lh      %r7,__LC_PGM_ILC  # load instruction length
+        lh      %r8,__LC_PGM_INT_CODE  # N.B. saved int code used later KEEP it
+        stosm   24(%r15),0x03     # reenable interrupts
+        lr      %r3,%r8
+        lhi     %r0,0x7f
+        nr      %r3,%r0           # clear per-event-bit
+        je      pgm_dn            # none of Martins exceptions occured bypass
+        l       %r9,pgm_jump_table-pgm_lit(%r13)
+        sll     %r3,2
+        l       %r9,0(%r3,%r9)    # load address of handler routine
+        la      %r2,SP_PTREGS(%r15) # address of register-save area
+        srl     %r3,2
+        chi     %r3,0x4           # protection-exception ?
+        jne     pgm_go            # if not,
+        l       %r5,SP_PSW+4(15)  # load psw addr
+        sr      %r5,%r7           # substract ilc from psw
+        st      %r5,SP_PSW+4(15)  # store corrected psw addr
+pgm_go: basr    %r14,%r9          # branch to interrupt-handler
+pgm_dn: lhi     %r0,0x80
+        nr      %r8,%r0           # check for per exception
+        je      pgm_return
+        la      %r2,SP_PTREGS(15) # address of register-save area
+        l       %r9,pgm_handle_per-pgm_lit(%r13) # load adr. of per handler
+        l       %r14,pgm_sysc_ret-pgm_lit(%r13)  # load adr. of system return
+        l       %r13,pgm_sysc_lit-pgm_lit(%r13)
+        br      %r9               # branch to handle_per_exception
+#
+# the backend code is the same as for sys-call
+#
+pgm_return:
+        l       %r14,pgm_sysc_ret-pgm_lit(%r13)
+        l       %r13,pgm_sysc_lit-pgm_lit(%r13)
+        br      %r14
+
+default_trap_handler:
+        .globl  default_trap_handler
+        lpsw    112
+
+/*
+ * IO interrupt handler routine
+ */
+
+io_lit:
+  io_do_IRQ:        .long do_IRQ
+  io_schedule:	    .long schedule
+  io_do_signal:     .long do_signal
+  io_bhmask:        .long  bh_mask
+  io_bhactive:      .long  bh_active
+  io_do_bottom_half:.long  do_bottom_half
+
+        .globl io_int_handler
+io_int_handler:
+        SAVE_ALL(0x38)
+        basr    %r13,0
+        ahi     %r13,io_lit-.     # setup base pointer R13 to $IODAT
+        la      %r2,SP_PTREGS(%r15) # address of register-save area
+        sr      %r3,%r3
+        icm     %r3,%r3,__LC_SUBCHANNEL_NR # load subchannel nr & extend to int
+        l       %r4,__LC_IO_INT_PARM       # load interuption parm
+        l       %r9,io_do_IRQ-io_lit(%r13) # load address of do_IRQ
+        basr    %r14,%r9          # branch to standard irq handler
+
+io_return:
+        GET_CURRENT               # load pointer to task_struct to R9
+        tm      SP_PSW+1(%r15),0x01 # returning to user ?
+#        tm      SP_PSW+2(%r15),0x80 # returning to user or kernel thread ?
+        jz      io_leave          # no-> skip resched & signal
+        stosm   24(%r15),0x03     # reenable interrupts
+#
+# check, if bottom-half has to be done
+#
+        l       %r1,io_bhmask-io_lit(%r13)
+        l       %r0,0(%r1)
+        l       %r1,io_bhactive-io_lit(%r13)
+        n       %r0,0(%r1)
+        jnz     io_handle_bottom_half
+io_return_bh:	
+#
+# check, if reschedule is needed
+#
+        icm     %r0,15,need_resched(%r9) # get need_resched from task_struct
+        jnz     io_reschedule
+        icm     %r0,15,sigpending(%r9)   # get sigpending from task_struct
+        jnz     io_signal_return
+io_leave:
+        stnsm   24(%r15),disable  # disable I/O and ext. interrupts
+        RESTORE_ALL
+
+#
+# call do_bottom_half and return from syscall, if interrupt-level
+# is zero
+#
+io_handle_bottom_half:        
+        l       %r1,io_do_bottom_half-io_lit(%r13)
+	la      %r14,io_return_bh-io_lit(%r13)
+        br      %r1               # call do_bottom_half
+
+#
+# call schedule with io_return as return-address
+#
+io_reschedule:        
+        l       %r1,io_schedule-io_lit(%r13)
+	la      %r14,io_return-io_lit(%r13)
+        br      %r1               # call scheduler, return to io_return
+
+#
+# call do_signal before return
+#
+io_signal_return:     
+        la      %r2,SP_PTREGS(%r15) # load pt_regs
+        sr      %r3,%r3           # clear *oldset
+        l       %r1,io_do_signal-io_lit(%r13)
+	la      %r14,io_leave-io_lit(%r13)
+        br      %r1               # return point is io_leave
+
+/*
+ * External interrupt handler routine
+ */
+
+ext_lit:
+  ext_timer_int:     .long  do_timer_interrupt
+#ifdef __SMP__
+  ext_call_int:      .long  do_ext_call_interrupt
+#endif
+#ifdef CONFIG_HWC
+  ext_hwc_int:      .long  do_hwc_interrupt
+#endif
+#ifdef CONFIG_MDISK
+  ext_mdisk_int:     .long  do_mdisk_interrupt
+#endif
+#ifdef CONFIG_IUCV
+  ext_iucv_int:      .long  do_iucv_interrupt
+#endif
+  ext_io_lit:	     .long  io_lit
+  ext_io_return:     .long  io_return
+
+        .globl  ext_int_handler
+ext_int_handler:
+        SAVE_ALL(0x18)
+        basr    %r13,0
+        ahi     %r13,ext_lit-.    # setup base pointer R13 to $EXTDAT
+        la      %r2,SP_PTREGS(%r15)    # address of register-save area
+        lh      %r3,__LC_EXT_INT_CODE  # error code
+#ifdef __SMP__
+	chi     %r3,0x1202        # EXTERNAL_CALL
+	jne     ext_no_extcall
+	l       %r9,ext_call_int-ext_lit(%r13) # load ext_call_interrupt
+	l       %r14,ext_io_return-ext_lit(%r13)
+        l       %r13,ext_io_lit-ext_lit(%r13)
+	br      %r9               # branch to ext call handler
+ext_no_extcall:
+#endif
+        chi     %r3,0x1004        # CPU_TIMER
+        jne     ext_no_timer
+        l       %r9,ext_timer_int-ext_lit(%r13) # load timer_interrupt
+	l       %r14,ext_io_return-ext_lit(%r13)
+        l       %r13,ext_io_lit-ext_lit(%r13)
+	br      %r9               # branch to ext call handler
+ext_no_timer:   
+#ifdef CONFIG_HWC
+        chi     %r3,0x2401        # HWC interrupt
+        jne     ext_no_hwc
+        l       %r9,ext_hwc_int-ext_lit(%r13) # load addr. of hwc routine
+	l       %r14,ext_io_return-ext_lit(%r13)
+        l       %r13,ext_io_lit-ext_lit(%r13)
+	br      %r9               # branch to ext call handler
+ext_no_hwc:    
+#endif
+#ifdef CONFIG_MDISK
+        chi     %r3,0x2603        # diag 250 (VM) interrupt
+        jne     ext_no_mdisk
+        l       %r9,ext_mdisk_int-ext_lit(%r13)
+	l       %r14,ext_io_return-ext_lit(%r13)
+        l       %r13,ext_io_lit-ext_lit(%r13)
+	br      %r9               # branch to ext call handler
+ext_no_mdisk:   
+#endif
+#ifdef CONFIG_IUCV
+        chi     %r3,0x4000        # diag 250 (VM) interrupt
+        jne     ext_no_iucv
+        l       %r9,ext_iucv_int-ext_lit(%r13)
+	l       %r14,ext_io_return-ext_lit(%r13)
+        l       %r13,ext_io_lit-ext_lit(%r13)
+	br      %r9               # branch to ext call handler
+ext_no_iucv:    
+#endif
+
+	l       %r14,ext_io_return-ext_lit(%r13)
+        l       %r13,ext_io_lit-ext_lit(%r13)
+	br      %r14              # use backend code of io_int_handler
+
+/*
+ * Machine check handler routines
+ */
+mcck_lit:
+  mcck_crw_pending: .long  do_crw_pending
+
+
+        .globl mcck_int_handler
+mcck_int_handler:
+        SAVE_ALL(0x30)
+        basr    %r13,0
+        ahi     %r13,mcck_lit-.   # setup base pointer R13 to $MCCKDAT
+	tm      __LC_MCCK_CODE+1,0x40
+	jno     mcck_no_crw
+	l       %r1,mcck_crw_pending-mcck_lit(%r13)
+	basr    %r14,%r1	  # call do_crw_pending
+mcck_no_crw:
+mcck_return:
+        RESTORE_ALL
+
+#ifdef __SMP__
+/*
+ * Restart interruption handler, kick starter for additional CPUs
+ */
+        .globl restart_int_handler
+restart_int_handler:
+        l       %r15,__LC_KERNEL_STACK # load ksp
+        lctl    %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs
+        lam     %a0,%a15,__LC_AREGS_SAVE_AREA
+        stosm   0(%r15),daton          # now we can turn dat on
+        lm      %r6,%r15,24(%r15)      # load registers from clone
+        bras    %r14,restart_go
+        .long   start_secondary
+restart_go:
+        l       %r14,0(%r14)
+        br      %r14                   # branch to start_secondary
+#else
+/*
+ * If we do not run with SMP enabled, let the new CPU crash ...
+ */
+        .globl restart_int_handler
+restart_int_handler:
+        basr    %r1,0
+restart_base:
+        lpsw    restart_crash-restart_base(%r1)
+        .align 8
+restart_crash:
+        .long  0x000a0000,0x00000000
+restart_go:
+#endif
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/floatlib.c linux.14p16/arch/s390/kernel/floatlib.c
--- linux.vanilla/arch/s390/kernel/floatlib.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/floatlib.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,1021 @@
+/*
+** libgcc support for software floating point.
+** Copyright (C) 1991 by Pipeline Associates, Inc.  All rights reserved.
+** Permission is granted to do *anything* you want with this file,
+** commercial or otherwise, provided this message remains intact.  So there!
+** I would appreciate receiving any updates/patches/changes that anyone
+** makes, and am willing to be the repository for said changes (am I
+** making a big mistake?).
+
+Warning! Only single-precision is actually implemented.  This file
+won't really be much use until double-precision is supported.
+
+However, once that is done, this file might eventually become a
+replacement for libgcc1.c.  It might also make possible
+cross-compilation for an IEEE target machine from a non-IEEE
+host such as a VAX.
+
+If you'd like to work on completing this, please talk to rms@gnu.ai.mit.edu.
+
+--> Double precision floating support added by James Carlson on 20 April 1998.
+
+**
+** Pat Wood
+** Pipeline Associates, Inc.
+** pipeline!phw@motown.com or
+** sun!pipeline!phw or
+** uunet!motown!pipeline!phw
+**
+** 05/01/91 -- V1.0 -- first release to gcc mailing lists
+** 05/04/91 -- V1.1 -- added float and double prototypes and return values
+**                  -- fixed problems with adding and subtracting zero
+**                  -- fixed rounding in truncdfsf2
+**                  -- fixed SWAP define and tested on 386
+*/
+
+/*
+** The following are routines that replace the libgcc soft floating point
+** routines that are called automatically when -msoft-float is selected.
+** The support single and double precision IEEE format, with provisions
+** for byte-swapped machines (tested on 386).  Some of the double-precision
+** routines work at full precision, but most of the hard ones simply punt
+** and call the single precision routines, producing a loss of accuracy.
+** long long support is not assumed or included.
+** Overall accuracy is close to IEEE (actually 68882) for single-precision
+** arithmetic.  I think there may still be a 1 in 1000 chance of a bit
+** being rounded the wrong way during a multiply.  I'm not fussy enough to
+** bother with it, but if anyone is, knock yourself out.
+**
+** Efficiency has only been addressed where it was obvious that something
+** would make a big difference.  Anyone who wants to do this right for
+** best speed should go in and rewrite in assembler.
+**
+** I have tested this only on a 68030 workstation and 386/ix integrated
+** in with -msoft-float.
+*/
+
+#define float long
+#define double long long
+
+/* the following deal with IEEE single-precision numbers */
+#define EXCESS          126
+#define SIGNBIT         0x80000000
+#define HIDDEN          (1 << 23)
+#define SIGN(fp)        ((fp) & SIGNBIT)
+#define EXP(fp)         (((fp) >> 23) & 0xFF)
+#define MANT(fp)        (((fp) & 0x7FFFFF) | HIDDEN)
+#define PACK(s,e,m)     ((s) | ((e) << 23) | (m))
+
+/* the following deal with IEEE double-precision numbers */
+#define EXCESSD         1022
+#define HIDDEND         (1 << 20)
+#define EXPD(fp)        (((fp.l.upper) >> 20) & 0x7FF)
+#define SIGND(fp)       ((fp.l.upper) & SIGNBIT)
+#define MANTD(fp)       (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) |(fp.l.lower >> 22))
+#define HIDDEND_LL      ((long long)1 << 52)
+#define MANTD_LL(fp)    ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL)
+#define PACKD_LL(s,e,m) (((long long)((s)+((e)<<20))<<32)|(m))
+
+/* define SWAP for 386/960 reverse-byte-order brain-damaged CPUs */
+union double_long {
+    double d;
+#ifdef SWAP
+    struct {
+      unsigned long lower;
+      long upper;
+    } l;
+#else
+    struct {
+      long upper;
+      unsigned long lower;
+    } l;
+#endif
+    long long ll;
+};
+
+union float_long
+  {
+    float f;
+    long l;
+  };
+
+long long
+__negdi2 (long long u)
+{
+
+  union lll {
+    long long ll;
+    long s[2];
+  };
+
+  union lll w,uu;
+
+  uu.ll = u;
+
+  w.s[1] = -uu.s[1];
+  w.s[0] = -uu.s[0] - ((int) w.s[1] != 0);
+
+  return w.ll;
+}
+
+
+
+/* add two floats */
+float
+__addsf3 (float a1, float a2)
+{
+  register long mant1, mant2;
+  register union float_long fl1, fl2;
+  register int exp1, exp2;
+  int sign = 0;
+
+  fl1.f = a1;
+  fl2.f = a2;
+
+  /* check for zero args */
+  if (!fl1.l) {
+      fl1.f = fl2.f;
+      goto test_done;
+  }
+  if (!fl2.l)
+      goto test_done;
+
+  exp1 = EXP (fl1.l);
+  exp2 = EXP (fl2.l);
+
+  if (exp1 > exp2 + 25)
+      goto test_done;
+  if (exp2 > exp1 + 25) {
+      fl1.f = fl2.f;
+      goto test_done;
+  }
+
+  /* do everything in excess precision so's we can round later */
+  mant1 = MANT (fl1.l) << 6;
+  mant2 = MANT (fl2.l) << 6;
+
+  if (SIGN (fl1.l))
+    mant1 = -mant1;
+  if (SIGN (fl2.l))
+    mant2 = -mant2;
+
+  if (exp1 > exp2)
+    {
+      mant2 >>= exp1 - exp2;
+    }
+  else
+    {
+      mant1 >>= exp2 - exp1;
+      exp1 = exp2;
+    }
+  mant1 += mant2;
+
+  if (mant1 < 0)
+    {
+      mant1 = -mant1;
+      sign = SIGNBIT;
+    }
+  else if (!mant1) {
+      fl1.f = 0;
+      goto test_done;
+  }
+
+  /* normalize up */
+  while (!(mant1 & 0xE0000000))
+    {
+      mant1 <<= 1;
+      exp1--;
+    }
+
+  /* normalize down? */
+  if (mant1 & (1 << 30))
+    {
+      mant1 >>= 1;
+      exp1++;
+    }
+
+  /* round to even */
+  mant1 += (mant1 & 0x40) ? 0x20 : 0x1F;
+
+  /* normalize down? */
+  if (mant1 & (1 << 30))
+    {
+      mant1 >>= 1;
+      exp1++;
+    }
+
+  /* lose extra precision */
+  mant1 >>= 6;
+
+  /* turn off hidden bit */
+  mant1 &= ~HIDDEN;
+
+  /* pack up and go home */
+  fl1.l = PACK (sign, exp1, mant1);
+test_done:
+  return (fl1.f);
+}
+
+/* subtract two floats */
+float
+__subsf3 (float a1, float a2)
+{
+  register union float_long fl1, fl2;
+
+  fl1.f = a1;
+  fl2.f = a2;
+
+  /* check for second arg zero */
+  if (!fl2.l)
+    return (fl1.f);
+  /* twiddle sign bit */
+  fl2.l ^= SIGNBIT;
+  /* check for first arg zero */
+  if (!fl1.l)
+    return (fl2.f);
+  /* add values */ 
+  return __addsf3 (a1, fl2.f);
+}
+
+/* compare two floats */
+long
+__cmpsf2 (float a1, float a2)
+{
+  register union float_long fl1, fl2;
+
+  fl1.f = a1;
+  fl2.f = a2;
+
+  if (SIGN (fl1.l) && SIGN (fl2.l))
+    {
+      fl1.l ^= SIGNBIT;
+      fl2.l ^= SIGNBIT;
+      if (fl1.l < fl2.l)
+	return (-1);
+      if (fl1.l > fl2.l)
+	return (1);
+      return 0;
+    } else {
+      if (fl1.l < fl2.l)
+	return (-1);
+      if (fl1.l > fl2.l)
+	return (1);
+      return (0);
+    }
+}
+
+/* multiply two floats */
+float
+__mulsf3 (float a1, float a2)
+{
+  register union float_long fl1, fl2;
+  register unsigned long result;
+  register int exp;
+  int sign;
+
+  fl1.f = a1;
+  fl2.f = a2;
+
+  if (!fl1.l || !fl2.l) {
+      fl1.f = 0;
+      goto test_done;
+  }
+
+  /* compute sign and exponent */
+  sign = SIGN (fl1.l) ^ SIGN (fl2.l);
+  exp = EXP (fl1.l) - EXCESS;
+  exp += EXP (fl2.l);
+
+  fl1.l = MANT (fl1.l);
+  fl2.l = MANT (fl2.l);
+
+  /* the multiply is done as one 16x16 multiply and two 16x8 multiples */
+  result = (fl1.l >> 8) * (fl2.l >> 8);
+  result += ((fl1.l & 0xFF) * (fl2.l >> 8)) >> 8;
+  result += ((fl2.l & 0xFF) * (fl1.l >> 8)) >> 8;
+
+  result >>= 2;
+  if (result & 0x20000000)
+    {
+      /* round */
+      result += 0x20;
+      result >>= 6;
+    }
+  else
+    {
+      /* round */
+      result += 0x10;
+      result >>= 5;
+      exp--;
+    }
+  if (result & (HIDDEN<<1)) {
+    result >>= 1;
+    exp++;
+  }
+
+  result &= ~HIDDEN;
+
+  /* pack up and go home */
+  fl1.l = PACK (sign, exp, result);
+test_done:
+  return (fl1.f);
+}
+
+/* divide two floats */
+float
+__divsf3 (float a1, float a2)
+{
+  register union float_long fl1, fl2;
+  register int result;
+  register int mask;
+  register int exp, sign;
+
+  fl1.f = a1;
+  fl2.f = a2;
+
+  /* subtract exponents */
+  exp = EXP (fl1.l) - EXP (fl2.l) + EXCESS;
+
+  /* compute sign */
+  sign = SIGN (fl1.l) ^ SIGN (fl2.l);
+
+  /* divide by zero??? */
+  if (!fl2.l)
+    /* return NaN or -NaN */
+    return (sign ? 0xFFFFFFFF : 0x7FFFFFFF);
+
+  /* numerator zero??? */
+  if (!fl1.l)
+    return (0);
+
+  /* now get mantissas */
+  fl1.l = MANT (fl1.l);
+  fl2.l = MANT (fl2.l);
+
+  /* this assures we have 25 bits of precision in the end */
+  if (fl1.l < fl2.l)
+    {
+      fl1.l <<= 1;
+      exp--;
+    }
+
+  /* now we perform repeated subtraction of fl2.l from fl1.l */
+  mask = 0x1000000;
+  result = 0;
+  while (mask)
+    {
+      if (fl1.l >= fl2.l)
+        {
+          result |= mask;
+          fl1.l -= fl2.l;
+        }
+      fl1.l <<= 1;
+      mask >>= 1;
+    }
+
+  /* round */
+  result += 1;
+
+  /* normalize down */
+  exp++;
+  result >>= 1;
+
+  result &= ~HIDDEN;
+
+  /* pack up and go home */
+  fl1.l = PACK (sign, exp, result);
+  return (fl1.f);
+}
+
+/* convert double to float */
+float
+__truncdfsf2 (double a1)
+{
+  register int exp;
+  register long mant;
+  register union float_long fl;
+  register union double_long dl1;
+
+  dl1.d = a1;
+
+  if (!dl1.l.upper && !dl1.l.lower)
+    return (float)(0);
+
+  exp = EXPD (dl1) - EXCESSD + EXCESS;
+
+  /* shift double mantissa 6 bits so we can round */
+  mant = MANTD (dl1) >> 6;
+
+  /* now round and shift down */
+  mant += 1;
+  mant >>= 1;
+   
+  /* did the round overflow? */
+  if (mant & 0xFF000000)
+    {
+      mant >>= 1;
+      exp++;
+    }
+
+  mant &= ~HIDDEN;
+
+  /* pack up and go home */
+  fl.l = PACK (SIGND (dl1), exp, mant);
+  return (fl.f);
+}
+
+/* convert int to double */
+double
+__floatsidf (register long a1)
+{
+  register int sign = 0, exp = 31 + EXCESSD;
+  union double_long dl;
+
+  if (a1 == 0x80000000)
+    {
+      /*
+       * -a1 would be 0 !
+       */
+      dl.l.upper = 0xc1e00000;
+      dl.l.lower = 0x0;
+      return (dl.d);
+    }
+
+  if (!a1)
+    {
+      dl.l.upper = dl.l.lower = 0;
+      return (dl.d);
+    }
+
+  if (a1 < 0)
+    {
+      sign = SIGNBIT;
+      a1 = -a1;
+    }
+
+  while (a1 < 0x1000000)
+    {
+      a1 <<= 4;
+      exp -= 4;
+    }
+
+  while (a1 < 0x40000000)
+    {
+      a1 <<= 1;
+      exp--;
+    }
+
+  /* pack up and go home */
+  dl.l.upper = sign;
+  dl.l.upper |= exp << 20;
+  dl.l.upper |= (a1 >> 10) & ~HIDDEND;
+  dl.l.lower = a1 << 22;
+
+  return (dl.d);
+}
+
+double
+__floatdidf (register long long a1)
+{
+    register int exp = 63 + EXCESSD;
+    union double_long dl;
+
+    dl.l.upper = dl.l.lower = 0;
+    if (a1 == 0)
+        return (dl.d);
+
+    if (a1 < 0) {
+        dl.l.upper = SIGNBIT;
+        a1 = -a1;
+    }
+
+    while (a1 < (long long)1<<54) {
+        a1 <<= 8;
+        exp -= 8;
+    }
+    while (a1 < (long long)1<<62) {
+        a1 <<= 1;
+        exp -= 1;
+    }
+  /* pack up and go home */
+    dl.ll |= (a1 >> 10) & ~HIDDEND_LL;
+    dl.l.upper |= exp << 20;
+
+    return (dl.d);
+}
+
+float
+__floatsisf (register long a1)
+{
+    return __truncdfsf2(__floatsidf(a1));
+}
+
+float
+__floatdisf (register long long a1)
+{
+    return (float)__floatdidf(a1);
+}
+/* negate a float */
+float
+__negsf2 (float a1)
+{
+  register union float_long fl1;
+
+  fl1.f = a1;
+  if (!fl1.l)
+    return (0);
+
+  fl1.l ^= SIGNBIT;
+  return (fl1.f);
+}
+
+/* negate a double */
+double
+__negdf2 (double a1)
+{
+  register union double_long dl1;
+
+  dl1.d = a1;
+
+  if (!dl1.l.upper && !dl1.l.lower)
+      return (dl1.d);
+
+  dl1.l.upper ^= SIGNBIT;
+  return (dl1.d);
+}
+
+/* convert float to double */
+double
+__extendsfdf2 (float a1)
+{
+  register union float_long fl1;
+  register union double_long dl;
+  register int exp;
+
+  fl1.f = a1;
+
+  if (!fl1.l)
+    {
+      dl.l.upper = dl.l.lower = 0;
+      return (dl.d);
+    }
+
+  dl.l.upper = SIGN (fl1.l);
+  exp = EXP (fl1.l) - EXCESS + EXCESSD;
+  dl.l.upper |= exp << 20;
+  dl.l.upper |= (MANT (fl1.l) & ~HIDDEN) >> 3;
+  dl.l.lower = MANT (fl1.l) << 29;
+
+  return (dl.d);
+}
+
+
+/* compare two doubles */
+long
+__cmpdf2 (double a1, double a2)
+{
+  register union double_long dl1, dl2;
+
+  dl1.d = a1;
+  dl2.d = a2;
+
+  if (SIGND (dl1) && SIGND (dl2))
+    {
+      dl1.l.upper ^= SIGNBIT;
+      dl2.l.upper ^= SIGNBIT;
+      if (dl1.l.upper < dl2.l.upper)
+	return (1);
+      if (dl1.l.upper > dl2.l.upper)
+	return (-1);
+      if (dl1.l.lower < dl2.l.lower)
+	return (1);
+      if (dl1.l.lower > dl2.l.lower)
+	return (-1);
+      return (0);
+    } else {
+      if (dl1.l.upper < dl2.l.upper)
+	return (-1);
+      if (dl1.l.upper > dl2.l.upper)
+	return (1);
+      if (dl1.l.lower < dl2.l.lower)
+	return (-1);
+      if (dl1.l.lower > dl2.l.lower)
+	return (1);
+      return (0);
+    }
+}
+
+/* convert double to int */
+long
+__fixdfsi (double a1)
+{
+  register union double_long dl1;
+  register int exp;
+  register long l;
+
+  dl1.d = a1;
+
+  if (!dl1.l.upper && !dl1.l.lower)
+    return (0);
+
+  exp = EXPD (dl1) - EXCESSD - 31;
+  l = MANTD (dl1);
+
+  if (exp > 0)
+      return SIGND(dl1) ? (1<<31) : ((1ul<<31)-1);
+
+  /* shift down until exp = 0 or l = 0 */
+  if (exp <= 0 && exp > -32 && l)
+    l >>= -exp;
+  else
+    return (0);
+
+  return (SIGND (dl1) ? -l : l);
+}
+
+/* convert float to int */
+long
+__fixsfsi (float a1)
+{
+    return __fixdfsi(__extendsfdf2(a1));
+}
+
+/* convert double to int */
+long long
+__fixdfdi (double a1)
+{
+    register union double_long dl1;
+    register int exp;
+    register long long l;
+
+    dl1.d = a1;
+
+    if (!dl1.l.upper && !dl1.l.lower)
+        return (0);
+
+    exp = EXPD (dl1) - EXCESSD - 64;
+    l = MANTD_LL(dl1);
+
+    if (exp > 0) {
+        l = (long long)1<<63;
+        if (!SIGND(dl1))
+            l--;
+        return l;
+    }
+
+    /* shift down until exp = 0 or l = 0 */
+    if (exp <= 0 && exp > -64 && l)
+        l >>= -exp;
+    else
+        return (0);
+
+    return (SIGND (dl1) ? -l : l);
+}
+
+/* convert double to unsigned int */
+unsigned long
+__fixunsdfsi (double a1)
+{
+  register union double_long dl1;
+  register int exp;
+  register unsigned long l;
+
+  dl1.d = a1;
+
+  if (!dl1.l.upper && !dl1.l.lower)
+    return (0);
+
+  exp = EXPD (dl1) - EXCESSD - 32;
+  l = (((((dl1.l.upper) & 0xFFFFF) | HIDDEND) << 11) | (dl1.l.lower >> 21));
+
+  if (exp > 0)
+    return (0xFFFFFFFFul);      /* largest integer */
+
+  /* shift down until exp = 0 or l = 0 */
+  if (exp < 0 && exp > -32 && l)
+    l >>= -exp;
+  else
+    return (0);
+
+  return (l);
+}
+
+/* convert double to unsigned int */
+unsigned long long
+__fixunsdfdi (double a1)
+{
+    register union double_long dl1;
+    register int exp;
+    register unsigned long long l;
+
+    dl1.d = a1;
+
+    if (dl1.ll == 0)
+        return (0);
+
+    exp = EXPD (dl1) - EXCESSD - 64;
+
+    l = dl1.ll;
+
+    if (exp > 0)
+        return (unsigned long long)-1;
+
+    /* shift down until exp = 0 or l = 0 */
+    if (exp < 0 && exp > -64 && l)
+        l >>= -exp;
+    else
+        return (0);
+
+    return (l);
+}
+
+/* addtwo doubles */
+double
+__adddf3 (double a1, double a2)
+{
+    register long long mant1, mant2;
+    register union double_long fl1, fl2;
+    register int exp1, exp2;
+    int sign = 0;
+
+    fl1.d = a1;
+    fl2.d = a2;
+
+    /* check for zero args */
+    if (!fl2.ll)
+        goto test_done;
+    if (!fl1.ll) {
+        fl1.d = fl2.d;
+        goto test_done;
+    }
+
+    exp1 = EXPD(fl1);
+    exp2 = EXPD(fl2);
+
+    if (exp1 > exp2 + 54)
+        goto test_done;
+    if (exp2 > exp1 + 54) {
+        fl1.d = fl2.d;
+        goto test_done;
+    }
+
+    /* do everything in excess precision so's we can round later */
+    mant1 = MANTD_LL(fl1) << 9;
+    mant2 = MANTD_LL(fl2) << 9;
+
+    if (SIGND(fl1))
+        mant1 = -mant1;
+    if (SIGND(fl2))
+        mant2 = -mant2;
+
+    if (exp1 > exp2)
+        mant2 >>= exp1 - exp2;
+    else {
+        mant1 >>= exp2 - exp1;
+        exp1 = exp2;
+    }
+    mant1 += mant2;
+
+    if (mant1 < 0) {
+        mant1 = -mant1;
+        sign = SIGNBIT;
+    } else if (!mant1) {
+        fl1.d = 0;
+        goto test_done;
+    }
+
+    /* normalize up */
+    while (!(mant1 & ((long long)7<<61))) {
+        mant1 <<= 1;
+        exp1--;
+    }
+
+    /* normalize down? */
+    if (mant1 & ((long long)3<<62)) {
+        mant1 >>= 1;
+        exp1++;
+    }
+
+    /* round to even */
+    mant1 += (mant1 & (1<<9)) ? (1<<8) : ((1<<8)-1);
+
+    /* normalize down? */
+    if (mant1 & ((long long)3<<62)) {
+        mant1 >>= 1;
+        exp1++;
+    }
+
+    /* lose extra precision */
+    mant1 >>= 9;
+
+    /* turn off hidden bit */
+    mant1 &= ~HIDDEND_LL;
+
+    /* pack up and go home */
+    fl1.ll = PACKD_LL(sign,exp1,mant1);
+
+test_done:
+    return (fl1.d);
+}
+
+/* subtract two doubles */
+double
+__subdf3 (double a1, double a2)
+{
+    register union double_long fl1, fl2;
+
+    fl1.d = a1;
+    fl2.d = a2;
+
+    /* check for zero args */
+    if (!fl2.ll)
+        return (fl1.d);
+    /* twiddle sign bit and add */
+    fl2.l.upper ^= SIGNBIT;
+    if (!fl1.ll)
+        return (fl2.d);
+    return __adddf3 (a1, fl2.d);
+}
+
+/* multiply two doubles */
+double
+__muldf3 (double a1, double a2)
+{
+    register union double_long fl1, fl2;
+    register unsigned long long result=0ULL;
+    register int exp;
+    int sign;
+
+    fl1.d = a1;
+    fl2.d = a2;
+
+    if (!fl1.ll || !fl2.ll) {
+        fl1.d = 0;
+        goto test_done;
+    }
+
+    /* compute sign and exponent */
+    sign = SIGND(fl1) ^ SIGND(fl2);
+    exp = EXPD(fl1) - EXCESSD;
+    exp += EXPD(fl2);
+
+    fl1.ll = MANTD_LL(fl1);
+    fl2.ll = MANTD_LL(fl2);
+
+  /* the multiply is done as one 31x31 multiply and two 31x21 multiples */
+    result = (fl1.ll >> 21) * (fl2.ll >> 21);
+    result += ((fl1.ll & 0x1FFFFF) * (fl2.ll >> 21)) >> 21;
+    result += ((fl2.ll & 0x1FFFFF) * (fl1.ll >> 21)) >> 21;
+
+    result >>= 2;
+    if (result & ((long long)1<<61)) {
+        /* round */
+        result += 1<<8;
+        result >>= 9;
+    } else {
+        /* round */
+        result += 1<<7;
+        result >>= 8;
+        exp--;
+    }
+    if (result & (HIDDEND_LL<<1)) {
+        result >>= 1;
+        exp++;
+    }
+
+    result &= ~HIDDEND_LL;
+
+    /* pack up and go home */
+    fl1.ll = PACKD_LL(sign,exp,result);
+test_done:
+    return (fl1.d);
+}
+
+/* divide two doubles */
+double
+__divdf3 (double a1, double a2)
+{
+    register union double_long fl1, fl2;
+    register long long mask,result;
+    register int exp, sign;
+
+    fl1.d = a1;
+    fl2.d = a2;
+
+    /* subtract exponents */
+    exp = EXPD(fl1) - EXPD(fl2) + EXCESSD;
+
+    /* compute sign */
+    sign = SIGND(fl1) ^ SIGND(fl2);
+
+    /* numerator zero??? */
+    if (fl1.ll == 0) {
+        /* divide by zero??? */
+        if (fl2.ll == 0)
+            fl1.ll = ((unsigned long long)1<<63)-1;     /* NaN */
+        else
+            fl1.ll = 0;
+        goto test_done;
+    }
+
+    /* return +Inf or -Inf */
+    if (fl2.ll == 0) {
+        fl1.ll = PACKD_LL(SIGND(fl1),2047,0);
+        goto test_done;
+    }
+
+
+    /* now get mantissas */
+    fl1.ll = MANTD_LL(fl1);
+    fl2.ll = MANTD_LL(fl2);
+
+    /* this assures we have 54 bits of precision in the end */
+    if (fl1.ll < fl2.ll) {
+        fl1.ll <<= 1;
+        exp--;
+    }
+
+    /* now we perform repeated subtraction of fl2.ll from fl1.ll */
+    mask = (long long)1<<53;
+    result = 0;
+    while (mask) {
+        if (fl1.ll >= fl2.ll)
+        {
+            result |= mask;
+            fl1.ll -= fl2.ll;
+        }
+        fl1.ll <<= 1;
+        mask >>= 1;
+    }
+
+    /* round */
+    result += 1;
+
+    /* normalize down */
+    exp++;
+    result >>= 1;
+
+    result &= ~HIDDEND_LL;
+
+    /* pack up and go home */
+    fl1.ll = PACKD_LL(sign, exp, result);
+
+test_done:
+    return (fl1.d);
+}
+
+int
+__gtdf2 (double a1, double a2)
+{
+    return __cmpdf2 ((float) a1, (float) a2) > 0;
+}
+
+int
+__gedf2 (double a1, double a2)
+{
+    return (__cmpdf2 ((float) a1, (float) a2) >= 0) - 1;
+}
+
+int
+__ltdf2 (double a1, double a2)
+{
+    return - (__cmpdf2 ((float) a1, (float) a2) < 0);
+}
+
+int
+__ledf2 (double a1, double a2)
+{
+    return __cmpdf2 ((float) a1, (float) a2) > 0;
+}
+
+int
+__eqdf2 (double a1, double a2)
+{
+    return *(long long *) &a1 == *(long long *) &a2;
+}
+
+int
+__nedf2 (double a1, double a2)
+{
+    return *(long long *) &a1 != *(long long *) &a2;
+}
+
+/* absolute value of double */
+double
+__absdf2(double a1)
+{
+  if (__cmpdf2(a1,0.0) < 0)
+      return __negdf2(a1);
+  else
+      return a1;
+}
+
+/* absolute value of float */
+float
+__abssf2(float a1)
+{
+  if (__cmpsf2(a1,0.0) < 0)
+      return __negsf2(a1);
+  else
+      return a1;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/gdb-stub.c linux.14p16/arch/s390/kernel/gdb-stub.c
--- linux.vanilla/arch/s390/kernel/gdb-stub.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/gdb-stub.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,575 @@
+/*
+ *  arch/s390/kernel/gdb-stub.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *
+ *  Originally written by Glenn Engel, Lake Stevens Instrument Division
+ *
+ *  Contributed by HP Systems
+ *
+ *  Modified for SPARC by Stu Grossman, Cygnus Support.
+ *
+ *  Modified for Linux/MIPS (and MIPS in general) by Andreas Busse
+ *  Send complaints, suggestions etc. to <andy@waldorf-gmbh.de>
+ *
+ *  Copyright (C) 1995 Andreas Busse
+ */
+
+/*
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing a BREAK instruction.
+ *
+ *
+ *    The following gdb commands are supported:
+ *
+ * command          function                               Return value
+ *
+ *    g             return the value of the CPU registers  hex data or ENN
+ *    G             set the value of the CPU registers     OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
+ *
+ *    c             Resume at current address              SNN   ( signal NN)
+ *    cAA..AA       Continue at address AA..AA             SNN
+ *
+ *    s             Step one instruction                   SNN
+ *    sAA..AA       Step one instruction from AA..AA       SNN
+ *
+ *    k             kill
+ *
+ *    ?             What was the last sigval ?             SNN   (signal NN)
+ *
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.  '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:                  Reply:
+ * $m0,10#2a               +$00010203040506070809101112131415#42
+ *
+ */
+
+#include <asm/gdb-stub.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+
+/*
+ * external low-level support routines
+ */
+
+extern int putDebugChar(char c);    /* write a single character      */
+extern char getDebugChar(void);     /* read and return a single char */
+extern void fltr_set_mem_err(void);
+extern void trap_low(void);
+
+/*
+ * breakpoint and test functions
+ */
+extern void breakpoint(void);
+extern void breakinst(void);
+
+/*
+ * local prototypes
+ */
+
+static void getpacket(char *buffer);
+static void putpacket(char *buffer);
+static int hex(unsigned char ch);
+static int hexToInt(char **ptr, int *intValue);
+static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault);
+
+
+/*
+ * BUFMAX defines the maximum number of characters in inbound/outbound buffers
+ * at least NUMREGBYTES*2 are needed for register packets
+ */
+#define BUFMAX 2048
+
+static char input_buffer[BUFMAX];
+static char output_buffer[BUFMAX];
+int gdb_stub_initialised = FALSE;	
+static const char hexchars[]="0123456789abcdef";
+
+
+/*
+ * Convert ch from a hex digit to an int
+ */
+static int hex(unsigned char ch)
+{
+	if (ch >= 'a' && ch <= 'f')
+		return ch-'a'+10;
+	if (ch >= '0' && ch <= '9')
+		return ch-'0';
+	if (ch >= 'A' && ch <= 'F')
+		return ch-'A'+10;
+	return -1;
+}
+
+/*
+ * scan for the sequence $<data>#<checksum>
+ */
+static void getpacket(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	unsigned char ch;
+
+	do {
+		/*
+		 * wait around for the start character,
+		 * ignore all other characters
+		 */
+		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+
+		checksum = 0;
+		xmitcsum = -1;
+		count = 0;
+	
+		/*
+		 * now, read until a # or end of buffer is found
+		 */
+		while (count < BUFMAX) {
+			ch = getDebugChar() & 0x7f;
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+
+		if (count >= BUFMAX)
+			continue;
+
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+			xmitcsum |= hex(getDebugChar() & 0x7f);
+
+			if (checksum != xmitcsum)
+				putDebugChar('-');	/* failed checksum */
+			else {
+				putDebugChar('+'); /* successful transfer */
+
+				/*
+				 * if a sequence char is present,
+				 * reply the sequence ID
+				 */
+				if (buffer[2] == ':') {
+					putDebugChar(buffer[0]);
+					putDebugChar(buffer[1]);
+
+					/*
+					 * remove sequence chars from buffer
+					 */
+					count = strlen(buffer);
+					for (i=3; i <= count; i++)
+						buffer[i-3] = buffer[i];
+				}
+			}
+		}
+	}
+	while (checksum != xmitcsum);
+}
+
+/*
+ * send the packet in buffer.
+ */
+static void putpacket(char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	unsigned char ch;
+
+	/*
+	 * $<packet info>#<checksum>.
+	 */
+
+	do {
+		putDebugChar('$');
+		checksum = 0;
+		count = 0;
+
+		while ((ch = buffer[count]) != 0) {
+			if (!(putDebugChar(ch)))
+				return;
+			checksum += ch;
+			count += 1;
+		}
+
+		putDebugChar('#');
+		putDebugChar(hexchars[checksum >> 4]);
+		putDebugChar(hexchars[checksum & 0xf]);
+
+	}
+	while ((getDebugChar() & 0x7f) != '+');
+}
+
+
+
+/*
+ * Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null), in case of mem fault,
+ * return 0.
+ * If MAY_FAULT is non-zero, then we will handle memory faults by returning
+ * a 0, else treat a fault like any other fault in the stub.
+ */
+static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+	unsigned char ch;
+
+/*	set_mem_fault_trap(may_fault); */
+
+	while (count-- > 0) {
+		ch = *(mem++);
+		if (mem_err)
+			return 0;
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch & 0xf];
+	}
+
+	*buf = 0;
+
+/*	set_mem_fault_trap(0); */
+
+	return buf;
+}
+
+/*
+ * convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte written
+ */
+static char *hex2mem(char *buf, char *mem, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+/*	set_mem_fault_trap(may_fault); */
+
+	for (i=0; i<count; i++)
+	{
+		ch = hex(*buf++) << 4;
+		ch |= hex(*buf++);
+		*(mem++) = ch;
+		if (mem_err)
+			return 0;
+	}
+
+/*	set_mem_fault_trap(0); */
+
+	return mem;
+}
+
+
+
+/*
+ * Set up exception handlers for tracing and breakpoints
+ */
+void set_debug_traps(void)
+{
+//	unsigned long flags;
+	unsigned char c;
+
+//	save_and_cli(flags);
+	/*
+	 * In case GDB is started before us, ack any packets
+	 * (presumably "$?#xx") sitting there.
+	 */
+	while((c = getDebugChar()) != '$');
+	while((c = getDebugChar()) != '#');
+	c = getDebugChar(); /* eat first csum byte */
+	c = getDebugChar(); /* eat second csum byte */
+	putDebugChar('+'); /* ack it */
+
+	gdb_stub_initialised = TRUE;
+//	restore_flags(flags);
+}
+
+
+/*
+ * Trap handler for memory errors.  This just sets mem_err to be non-zero.  It
+ * assumes that %l1 is non-zero.  This should be safe, as it is doubtful that
+ * 0 would ever contain code that could mem fault.  This routine will skip
+ * past the faulting instruction after setting mem_err.
+ */
+extern void fltr_set_mem_err(void)
+{
+  /* FIXME: Needs to be written... */
+}
+
+
+/*
+ * While we find nice hex chars, build an int.
+ * Return number of chars processed.
+ */
+static int hexToInt(char **ptr, int *intValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*intValue = 0;
+
+	while (**ptr)
+	{
+		hexValue = hex(**ptr);
+		if (hexValue < 0)
+			break;
+
+		*intValue = (*intValue << 4) | hexValue;
+		numChars ++;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+void gdb_stub_get_non_pt_regs(gdb_pt_regs *regs)
+{
+	s390_fp_regs *fpregs=&regs->fp_regs;
+	int has_ieee=save_fp_regs1(fpregs);
+
+	if(!has_ieee)
+	{
+		fpregs->fpc=0;
+		fpregs->fprs[1].d=
+		fpregs->fprs[3].d=
+		fpregs->fprs[5].d=
+		fpregs->fprs[7].d=0;
+		memset(&fpregs->fprs[8].d,0,sizeof(freg_t)*8);
+	}
+}
+
+void gdb_stub_set_non_pt_regs(gdb_pt_regs *regs)
+{
+	restore_fp_regs1(&regs->fp_regs);
+}
+
+void gdb_stub_send_signal(int sigval)
+{
+	char *ptr;
+	ptr = output_buffer;
+
+	/*
+	 * Send trap type (converted to signal)
+	 */
+	*ptr++ = 'S';
+	*ptr++ = hexchars[sigval >> 4];
+	*ptr++ = hexchars[sigval & 0xf];
+	*ptr++ = 0;
+	putpacket(output_buffer);	/* send it off... */
+}
+
+/*
+ * This function does all command processing for interfacing to gdb.  It
+ * returns 1 if you should skip the instruction at the trap address, 0
+ * otherwise.
+ */
+void gdb_stub_handle_exception(gdb_pt_regs *regs,int sigval)
+{
+	int trap;			/* Trap type */
+	int addr;
+	int length;
+	char *ptr;
+	unsigned long *stack;
+
+	
+	/*
+	 * reply to host that an exception has occurred
+	 */
+	send_signal(sigval);
+
+	/*
+	 * Wait for input from remote GDB
+	 */
+	while (1) {
+		output_buffer[0] = 0;
+		getpacket(input_buffer);
+
+		switch (input_buffer[0])
+		{
+		case '?':
+			send_signal(sigval);
+			continue;
+
+		case 'd':
+			/* toggle debug flag */
+			break;
+
+		/*
+		 * Return the value of the CPU registers
+		 */
+		case 'g':
+			gdb_stub_get_non_pt_regs(regs);
+			ptr = output_buffer;
+			ptr=  mem2hex((char *)regs,ptr,sizeof(s390_regs_common),FALSE);
+			ptr=  mem2hex((char *)&regs->crs[0],ptr,NUM_CRS*CR_SIZE,FALSE);
+			ptr = mem2hex((char *)&regs->fp_regs, ptr,sizeof(s390_fp_regs));
+			break;
+	  
+		/*
+		 * set the value of the CPU registers - return OK
+		 * FIXME: Needs to be written
+		 */
+		case 'G':
+			ptr=input_buffer;
+			hex2mem (ptr, (char *)regs,sizeof(s390_regs_common), FALSE);
+			ptr+=sizeof(s390_regs_common)*2;
+			hex2mem (ptr, (char *)regs->crs[0],NUM_CRS*CR_SIZE, FALSE);
+			ptr+=NUM_CRS*CR_SIZE*2;
+			hex2mem (ptr, (char *)regs->fp_regs,sizeof(s390_fp_regs), FALSE);
+			gdb_stub_set_non_pt_regs(regs);
+			strcpy(output_buffer,"OK");
+		break;
+
+		/*
+		 * mAA..AA,LLLL  Read LLLL bytes at address AA..AA
+		 */
+		case 'm':
+			ptr = &input_buffer[1];
+
+			if (hexToInt(&ptr, &addr)
+				&& *ptr++ == ','
+				&& hexToInt(&ptr, &length)) {
+				if (mem2hex((char *)addr, output_buffer, length, 1))
+					break;
+				strcpy (output_buffer, "E03");
+			} else
+				strcpy(output_buffer,"E01");
+			break;
+
+		/*
+		 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK
+		 */
+		case 'M': 
+			ptr = &input_buffer[1];
+
+			if (hexToInt(&ptr, &addr)
+				&& *ptr++ == ','
+				&& hexToInt(&ptr, &length)
+				&& *ptr++ == ':') {
+				if (hex2mem(ptr, (char *)addr, length, 1))
+					strcpy(output_buffer, "OK");
+				else
+					strcpy(output_buffer, "E03");
+			}
+			else
+				strcpy(output_buffer, "E02");
+			break;
+
+		/*
+		 * cAA..AA    Continue at address AA..AA(optional)
+		 */
+		case 'c':    
+			/* try to read optional parameter, pc unchanged if no parm */
+
+			ptr = &input_buffer[1];
+			if (hexToInt(&ptr, &addr))
+				regs->cp0_epc = addr;
+	  
+			/*
+			 * Need to flush the instruction cache here, as we may
+			 * have deposited a breakpoint, and the icache probably
+			 * has no way of knowing that a data ref to some location
+			 * may have changed something that is in the instruction
+			 * cache.
+			 * NB: We flush both caches, just to be sure...
+			 */
+
+			flush_cache_all();
+			return;
+			/* NOTREACHED */
+			break;
+
+
+		/*
+		 * kill the program
+		 */
+		case 'k' :
+			break;		/* do nothing */
+
+
+		/*
+		 * Reset the whole machine (FIXME: system dependent)
+		 */
+		case 'r':
+			break;
+
+
+		/*
+		 * Step to next instruction
+		 */
+		case 's':
+			/*
+			 * There is no single step insn in the MIPS ISA, so we
+			 * use breakpoints and continue, instead.
+			 */
+			single_step(regs);
+			flush_cache_all();
+			return;
+			/* NOTREACHED */
+
+		}
+		break;
+
+		}			/* switch */
+
+		/*
+		 * reply to the request
+		 */
+
+		putpacket(output_buffer);
+
+	} /* while */
+}
+
+/*
+ * This function will generate a breakpoint exception.  It is used at the
+ * beginning of a program to sync up with a debugger and can be used
+ * otherwise as a quick means to stop program execution and "break" into
+ * the debugger.
+ */
+void breakpoint(void)
+{
+	if (!gdb_stub_initialised)
+		return;
+	__asm__ __volatile__(
+			".globl	breakinst\n"
+			"breakinst:\t.word   %0\n\t"
+			:
+			: "i" (BREAKPOINT_U16)
+				:
+				);
+}
+
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/head.S linux.14p16/arch/s390/kernel/head.S
--- linux.vanilla/arch/s390/kernel/head.S	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/head.S	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,581 @@
+/*
+ *  arch/s390/kernel/head.S
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Hartmut Penner (hp@de.ibm.com),
+ *               Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ * There are 4 different IPL methods
+ *  1) load the image directly into ram at address 0 and do an PSW restart
+ *  2) linload will load the image from address 0x10000 to memory 0x10000
+ *     and start the code thru LPSW 0x0008000080010000 (VM only, deprecated)
+ *  3) generate the tape ipl header, store the generated image on a tape
+ *     and ipl from it
+ *  4) generate the vm reader ipl header, move the generated image to the
+ *     VM reader (use option NOH!) and do a ipl from reader (VM only)
+ *  We use the cpuid to distinguish between VM and native ipl
+ *  params for kernel are pushed to 0x10400 (see setup.h)
+ */
+
+#include <linux/config.h>
+#include <asm/setup.h>
+#include <asm/lowcore.h>
+
+#ifndef CONFIG_IPL
+        .org   0
+        .long  0x00080000,0x80000000+start     # Just a restart PSW
+#else
+#ifdef CONFIG_IPL_TAPE
+#define IPL_BS 1024
+        .org   0
+        .long  0x00080000,0x80000000+iplstart  # The first 24 bytes are loaded
+        .long  0x07000000,0x60000001           # by ipl to addresses 0-23.
+        .long  0x02000000,0x20000000+IPL_BS    # (a PSW and two CCWs).
+        .long  0x00000000,0x00000000           # external old psw
+        .long  0x00000000,0x00000000           # svc old psw
+        .long  0x00000000,0x00000000           # program check old psw
+        .long  0x00000000,0x00000000           # machine check old psw
+        .long  0x00000000,0x00000000           # io old psw
+        .long  0x00000000,0x00000000
+        .long  0x00000000,0x00000000
+        .long  0x00000000,0x00000000
+        .long  0x000a0000,0x00000058           # external new psw
+        .long  0x000a0000,0x00000060           # svc new psw
+        .long  0x000a0000,0x00000068           # program check new psw
+        .long  0x000a0000,0x00000070           # machine check new psw
+        .long  0x00080000,0x80000000+.Lioint   # io new psw
+
+        .org   0x100
+iplstart:
+	l     %r1,0xb8                         # load ipl subchannel number
+        lhi   %r2,IPL_BS                       # load start address
+        bras  %r14,.Lloader                    # load rest of ipl image
+        l     %r12,.Lparm                      # pointer to parameter area
+#
+# load parameter file from tape
+#
+ 	l     %r2,INITRD_START-PARMAREA(%r12)  # use ramdisk location as temp
+        bras  %r14,.Lloader                    # load parameter file
+        ltr   %r2,%r2                          # got anything ?
+        jz    .Lnopf
+	chi   %r2,896
+	jnh   .Lnotrunc
+	lhi   %r2,896
+.Lnotrunc:
+	l     %r4,INITRD_START-PARMAREA(%r12)
+	clc   0(6,%r4),.Lebcdic                # prefix EBCDIC in parm file ?
+	jne   .Lnocv
+	ahi   %r4,6                            # skip EBCDIC
+	ahi   %r2,-6
+	jnp   .Lnopf
+        l     %r3,.Lcvtab
+        tr    0(256,%r4),0(%r3)                # convert parameters to ascii
+        tr    256(256,%r4),0(%r3)
+        tr    512(256,%r4),0(%r3)
+        tr    768(128,%r4),0(%r3)
+.Lnocv: la    %r3,COMMAND_LINE-PARMAREA(%r12)  # load adr. of command line
+	mvc   0(256,%r3),0(%r4)
+	mvc   256(256,%r3),256(%r4)
+	mvc   512(256,%r3),512(%r4)
+	mvc   768(128,%r3),768(%r4)
+        slr   %r0,%r0
+        j     .Lcntlp
+.Ldelspc:
+        ic    %r0,0(%r2,%r3)
+        chi   %r0,0x20                         # is it a space ?
+        je    .Lcntlp
+        ahi   %r2,1
+        j     .Leolp
+.Lcntlp:
+        brct  %r2,.Ldelspc
+.Leolp:
+        slr   %r0,%r0
+        stc   %r0,0(%r2,%r3)                   # terminate buffer
+.Lnopf:
+
+#
+# load ramdisk from tape
+#	
+ 	l     %r2,INITRD_START-PARMAREA(%r12)  # load adr. of ramdisk
+        bras  %r14,.Lloader                    # load ramdisk
+ 	st    %r2,INITRD_SIZE-PARMAREA(%r12)   # store size of ramdisk
+        ltr   %r2,%r2
+        jnz   .Lrdcont
+        st    %r2,INITRD_START-PARMAREA(%r12)  # no ramdisk found, null it
+.Lrdcont:
+#
+# everything loaded, go for it
+#
+        j     start
+#
+# subroutine for loading from tape
+# Paramters:	
+#  R1 = device number
+#  R2 = load address
+.Lloader:	
+        st    %r14,.Lldret
+        la    %r3,.Lorbread                    # r3 = address of orb 
+	la    %r5,.Lirb                        # r5 = address of irb
+        st    %r2,.Lccwread+4                  # initialize CCW data addresses
+        lctl  %c6,%c6,.Lcr6               
+        slr   %r2,%r2
+.Lldlp:
+        lhi   %r6,3                            # 3 retries
+.Lssch:
+        ssch  0(%r3)                           # load chunk of IPL_BS bytes
+        jnz   .Llderr
+.Lw4end:
+        bras  %r14,.Lwait4io
+        tm    8(%r5),0x82                      # do we have a problem ?
+        jnz   .Lrecov
+        slr   %r7,%r7
+        icm   %r7,3,10(%r5)                    # get residual count
+        lcr   %r7,%r7
+        ahi   %r7,IPL_BS                       # IPL_BS-residual=#bytes read
+        ar    %r2,%r7                          # add to total size
+        tm    8(%r5),0x01                      # found a tape mark ?
+        jnz   .Ldone
+        l     %r0,.Lccwread+4                  # update CCW data addresses
+        ar    %r0,%r7
+        st    %r0,.Lccwread+4                
+        j     .Lldlp
+.Ldone:
+        l     %r14,.Lldret
+        br    %r14                             # r2 contains the total size
+.Lrecov:
+        bras  %r14,.Lsense                     # do the sensing
+        brct  %r6,.Lssch                       # dec. retry count & branch
+        j     .Llderr
+#
+# Sense subroutine
+#
+.Lsense:
+        st    %r14,.Lsnsret
+        la    %r7,.Lorbsense              
+        ssch  0(%r7)                           # start sense command
+        jnz   .Llderr
+        bras  %r14,.Lwait4io
+        l     %r14,.Lsnsret
+        tm    8(%r5),0x82                      # do we have a problem ?
+        jnz   .Llderr
+        br    %r14
+#
+# Wait for interrupt subroutine
+#
+.Lwait4io:
+        lpsw  .Lwaitpsw                 
+.Lioint:
+        c     %r1,0xb8                         # compare subchannel number
+        jne   .Lwait4io
+        tsch  0(%r5)
+        slr   %r0,%r0
+        tm    8(%r5),0x82                      # do we have a problem ?
+        jnz   .Lwtexit
+        tm    8(%r5),0x04                      # got device end ?
+        jz    .Lwait4io
+.Lwtexit:
+        br    %r14
+.Llderr:
+        lpsw  .Lcrash              
+
+        .align 8
+.Lorbread:
+	.long  0x00000000,0x0080ff00,.Lccwread
+        .align 8
+.Lorbsense:
+        .long  0x00000000,0x0080ff00,.Lccwsense
+        .align 8
+.Lccwread:
+        .long  0x02200000+IPL_BS,0x00000000
+.Lccwsense:
+        .long  0x04200001,0x00000000
+.Lwaitpsw:
+	.long  0x020a0000,0x80000000+.Lioint
+
+.Lirb:	.long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+.Lcr6:  .long  0xff000000
+        .align 8
+.Lcrash:.long  0x000a0000,0x00000000
+.Lparm: .long  PARMAREA
+.Lldret:.long  0
+.Lsnsret: .long 0
+.Lebcdic:.long 0xc5c2c3c4,0xc9c30000
+.Lcvtab:.long  _ebcasc                         # ebcdic to ascii table
+
+#endif  /* CONFIG_IPL_TAPE */
+
+#ifdef CONFIG_IPL_VM
+        .org   0
+        .long  0x00080000,0x80000000+iplstart  # The first 24 bytes are loaded
+        .long  0x02000018,0x60000050           # by ipl to addresses 0-23.
+        .long  0x02000068,0x60000050           # (a PSW and two CCWs).
+        .fill  80-24,1,0x40                    # bytes 24-79 are discarded !!
+        .long  0x020000f0,0x60000050           # The next 160 byte are loaded
+        .long  0x02000140,0x60000050           # to addresses 0x18-0xb7
+        .long  0x02000190,0x60000050           # They form the continuation
+        .long  0x020001e0,0x60000050           # of the CCW program started
+        .long  0x02000230,0x60000050           # by ipl and load the range
+        .long  0x02000280,0x60000050           # 0x0f0-0x730 from the image
+        .long  0x020002d0,0x60000050           # to the range 0x0f0-0x730
+        .long  0x02000320,0x60000050           # in memory. At the end of
+        .long  0x02000370,0x60000050           # the channel program the PSW
+        .long  0x020003c0,0x60000050           # at location 0 is loaded.
+        .long  0x02000410,0x60000050           # Initial processing starts
+        .long  0x02000460,0x60000050           # at 0xf0 = iplstart.
+        .long  0x020004b0,0x60000050
+        .long  0x02000500,0x60000050
+        .long  0x02000550,0x60000050
+        .long  0x020005a0,0x60000050
+        .long  0x020005f0,0x60000050
+        .long  0x02000640,0x60000050
+        .long  0x02000690,0x60000050
+        .long  0x020006e0,0x20000050
+
+
+        .org   0xf0
+iplstart:
+        stidp __LC_CPUID                       # store cpuid
+	tm    __LC_CPUID,0xff                  # running under VM ?
+	jno   start                            #   no -> skip loader part
+	l     %r1,0xb8                         # load ipl subchannel number
+        lhi   %r2,0x730                        # load start address
+        bras  %r14,.Lloader                    # load rest of ipl image
+
+	l     %r12,.Lparm                      # pointer to parameter area
+
+#
+# load parameter file from reader
+#
+        la    %r2,COMMAND_LINE-PARMAREA(%r12)  # load adr. of command line
+        bras  %r14,.Lloader                    # load parameter file
+        ltr   %r2,%r2                          # got anything ?
+        jz    .Lnopf
+        la    %r3,COMMAND_LINE-PARMAREA(%r12)  # load adr. of command line
+        l     %r4,.Lcvtab                 
+        tr    0(256,3),0(4)                    # convert parameters to ascii
+        l     %r4,.Lcvtab                 
+        tr    256(256,3),0(4)
+        l     %r4,.Lcvtab                 	
+        tr    512(256,3),0(4)
+        l     %r4,.Lcvtab                 	
+        tr    768(128,3),0(4)            
+        slr   %r0,%r0
+        j     .Lcntlp
+.Ldelspc:
+        ic    %r0,0(%r2,%r3)
+        chi   %r0,0x20                         # is it a space ?
+        je    .Lcntlp
+        ahi   %r2,1
+        j     .Leolp
+.Lcntlp:
+        brct  %r2,.Ldelspc
+.Leolp:
+        slr   %r0,%r0
+        stc   %r0,0(%r2,%r3)                   # terminate buffer
+.Lnopf:
+
+#
+# load ramdisk from reader
+#	
+	l     %r2,INITRD_START-PARMAREA(%r12)  # load adr. of ramdisk
+        bras  %r14,.Lloader                    # load ramdisk
+	st    %r2,INITRD_SIZE-PARMAREA(%r12)   # store size of ramdisk
+        ltr   %r2,%r2
+        jnz   .Lrdcont
+        st    %r2,INITRD_START-PARMAREA(%r12)  # no ramdisk found, null it
+.Lrdcont:
+
+#
+# everything loaded, reset files in reader, then go for it
+#
+        la    %r2,.Lreset              
+        lhi   %r3,26
+        .long 0x83230008
+	j     start
+
+#
+# subroutine for loading cards from the reader
+#
+.Lloader:	
+	la    %r3,.Lorb                        # r2 = address of orb into r2
+	la    %r5,.Lirb                        # r4 = address of irb
+        la    %r6,.Lccws              
+        la    %r7,20
+.Linit:
+        st    %r2,4(%r6)                       # initialize CCW data addresses
+        ahi   %r2,0x50
+        ahi   %r6,8
+        brct  7,.Linit
+
+        lctl  %c6,%c6,.Lcr6                    # set IO subclass mask
+	slr   %r2,%r2
+.Lldlp:
+        ssch  0(%r3)                           # load chunk of 1600 bytes
+        jnz   .Llderr
+.Lwait4irq:
+        mvc   __LC_IO_NEW_PSW(8),.Lnewpsw      # set up IO interrupt psw
+        lpsw  .Lwaitpsw              
+.Lioint:
+        c     %r1,0xb8                         # compare subchannel number
+	jne   .Lwait4irq
+	tsch  0(%r5)
+
+	slr   %r0,%r0
+	ic    %r0,8(%r5)                       # get device status
+	chi   %r0,8                            # channel end ?
+	je    .Lcont
+	chi   %r0,12                           # channel end + device end ?
+	je    .Lcont
+
+        l     %r0,4(%r5)
+        s     %r0,8(%r3)                       # r0/8 = number of ccws executed
+        mhi   %r0,10                           # *10 = number of bytes in ccws
+        lh    %r3,10(%r5)                      # get residual count
+        sr    %r0,%r3                          # #ccws*80-residual=#bytes read
+	ar    %r2,%r0
+	
+        br    %r14                             # r2 contains the total size
+
+.Lcont:
+	ahi   %r2,0x640                        # add 0x640 to total size
+        la    %r6,.Lccws             
+        la    %r7,20
+.Lincr:
+        l     %r0,4(%r6)                       # update CCW data addresses
+        ahi   %r0,0x640
+        st    %r0,4(%r6)
+        ahi   %r6,8
+        brct  7,.Lincr
+
+        j     .Lldlp
+.Llderr:
+        lpsw  .Lcrash              
+
+        .align 8
+.Lorb:	.long  0x00000000,0x0080ff00,.Lccws
+.Lirb:	.long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+.Lcr6:  .long  0xff000000
+.Lloadp:.long  0,0
+.Lparm:	.long  PARMAREA
+.Lcvtab:.long  _ebcasc                         # ebcdic to ascii table
+.Lreset:.byte  0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
+        .byte  0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
+        .byte  0xc8,0xd6,0xd3,0xc4             # "change rdr all keep nohold"
+        .align 8
+.Lcrash:
+        .long  0x000a0000,0x00000000
+.Lnewpsw:
+        .long  0x00080000,0x80000000+.Lioint
+.Lwaitpsw:
+        .long  0x020a0000,0x80000000+.Lioint
+
+        .align 8
+.Lccws: .rept  19
+        .long  0x02600050,0x00000000
+        .endr
+        .long  0x02200050,0x00000000
+	
+        .org   0x730     # end of the area loaded by the ipl channel program
+#endif  /* CONFIG_IPL_VM */
+
+#endif  /* CONFIG_IPL */
+
+#
+# startup-code at 0x10000, running in real mode
+# this is called either by the ipl loader or directly by PSW restart or linload
+#
+        .org  0x10000
+        .globl start
+start:  basr  %r13,0                     # get base
+.LPG1:  lctl  %c1,%c1,.Lpstd-.LPG1(%r13) # load pstd
+        lctl  %c7,%c7,.Lpstd-.LPG1(%r13) # load sstd
+        lctl  %c13,%c13,.Lpstd-.LPG1(%r13) # load hstd
+        lctl  %c0,%c0,.Lcr0-.LPG1(%r13)  # set CR0
+	l     %r12,.Lparm1-.LPG1(%r13)   # pointer to parameter area
+
+#
+# find out memory size
+#
+	mvc   104(8,0),.Lpcmem-.LPG1(%r13) # setup program check handler
+        slr   %r1,%r1
+        lhi   %r2,1
+        sll   %r2,20
+.Lloop:	
+	l     %r0,0(%r1)                 # test page
+	ar    %r1,%r2                    # add 1M
+	jnm   .Lloop                     # r1 < 0x80000000 -> loop
+.Lchkmem:
+	n     %r1,.L4malign-.LPG1(%r13)  # align to multiples of 4M
+	st    %r1,MEMORY_SIZE-PARMAREA(%r12)  # store memory size
+
+#
+# find out if we are running under VM
+#
+        stidp  __LC_CPUID               # store cpuid
+	tm     __LC_CPUID,0xff          # running under VM ?
+	jno    .Lnovm
+        oi     MACHINE_FLAGS+3-PARMAREA(%r12),1    # set VM flag
+.Lnovm:
+
+#
+# find out if we have an IEEE fpu
+#
+        mvc    104(8,0),.Lpcfpu-.LPG1(%r13) # setup program check handler
+        ld     %f0,.Lflt0-.LPG1(%r13)   # load (float) 0.0
+        ldr    %f2,%f0
+        adbr   %f0,%f2                  # test IEEE add instruction
+        oi     MACHINE_FLAGS+3-PARMAREA(%r12),2    # set IEEE fpu flag
+.Lchkfpu:
+
+#
+# move ramdisk to the end of storage, out of the way of the paging tables
+#
+        icm   %r2,15,INITRD_START-PARMAREA(%r12)  # load adr. of ramdisk
+        jz    .Lnocprd
+        icm   %r3,15,INITRD_SIZE-PARMAREA(%r12)   # store size of ramdisk
+        jz    .Lnocprd
+        l     %r4,MEMORY_SIZE-PARMAREA(%r12)
+        sr    %r4,%r3
+        srl   %r4,12
+        sll   %r4,12
+        st    %r4,INITRD_START-PARMAREA(%r12)
+        lr    %r5,%r3
+.Lcprd:
+        mvcle %r4,%r2,0
+        jo    .Lcprd
+.Lnocprd:
+        lpsw  .Lentry-.LPG1(13)         # jump to _stext in primary-space,
+                                        # virtual and never return ...
+        .align 8
+.Lentry:.long  0x0408C000,0x80000000 + _stext
+.Lpstd: .long  .Lpgd+0x7F               # segment-table
+.Lcr0:  .long  0x04b50002
+.Lpcmem:.long  0x00080000,0x80000000 + .Lchkmem
+.Lpcfpu:.long  0x00080000,0x80000000 + .Lchkfpu
+.Lflt0: .double 0
+.Lparm1:.long  PARMAREA
+.L4malign:.long 0xffc00000
+
+#
+# params at 10400 (setup.h)
+#
+	.org   PARMAREA
+        .long  0x0100                   # ORIG_ROOT_DEV: ramdisk major/minor
+        .word  0                        # MOUNT_ROOT_RDONLY: no
+	.long  0                        # MEMORY_SIZE
+	.long  0                        # MACHINE_FLAGS (bit 0:VM, bit 1:IEEE)
+        .long  RAMDISK_ORIGIN           # INITRD_START
+        .long  0x800000                 # INITRD_SIZE
+	.word  0                        # RAMDISK_FLAGS
+
+        .org   COMMAND_LINE
+#       .byte  "root=/dev/nfs rw nfsroot=9.164.160.7:/home/mschwide/nfsboot "
+#       .byte  "ip=9.164.147.12:9.164.160.7:9.164.147.1:255.255.255.0:vmlinux:tr0:off"
+#       .byte  "root=/dev/nfs nfsroot=9.164.160.7:/home/mschwide/nfsboot "
+#       .byte  "ip=9.164.181.228:9.164.160.7:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
+#       .byte  "root=/dev/nfs nfsroot=9.164.160.7:/home/pasch/nfsboot "
+#       .byte  "ip=9.164.185.120:9.164.160.7:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
+#       .byte  "mdisk=402:65536:1229,403:131072:2780 root=/dev/mnda ro"
+#       .byte  "root=/dev/nfs rw nfsroot=9.164.160.209:/usr/local/nfsboot "
+#       .byte  "ip=9.164.181.228:9.164.160.209:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
+    	.byte  "root=/dev/ram0 ro"
+#       .byte  0
+
+#
+# startup-code, running in virtual mode
+#
+        .org   0x10800
+        .globl _stext
+_stext:	basr  %r13,0                    # get base
+.LPG2:
+#
+# Setup lowcore
+#
+        spx   .Lprefix-.LPG2(%r13)      # set prefix to linux lowcore
+        l     %r15,.Linittu-.LPG2(%r13)
+        ahi   %r15,8192                 # init_task_union + 8191
+        st    %r15,__LC_KERNEL_STACK    # set end of kernel stack
+        ahi   %r15,-96
+        lhi   %r0,-1
+        st    %r0,__LC_KERNEL_LEVEL     # set interrupt count to -1
+#
+# clear bss memory
+#
+        l     %r2,.Lbss_bgn-.LPG2(%r13) # start of bss
+        l     %r3,.Lbss_end-.LPG2(%r13) # end of bss
+        sr    %r3,%r2                   # length of bss
+        sr    %r4,%r4                   #
+        sr    %r5,%r5                   # set src,length and pad to zero
+        sr    %r0,%r0                   #
+        mvcle %r2,%r4,0                 # clear mem
+        jo    .-4                       # branch back, if not finish
+# check control registers
+        stctl  %c0,%c15,0(%r15)
+        l     %r0,0(%r15)
+        o     %r0,.Lcr0or-.LPG2(%r13)   # enable sigp external ints.
+        st    %r0,0(%r15)
+        lctl   %c0,%c15,0(%r15)
+
+#
+        lam    0,15,.Laregs-.LPG2(%r13) # load access regs needed by uaccess
+        l      %r14,.Lstart-.LPG2(%r13)
+        basr   %r14,%r14                # call start_kernel
+#
+# We returned from start_kernel ?!? PANIK
+#
+        basr  %r13,0
+	lpsw  .Ldw-.(%r13)           # load disabled wait psw
+#
+.Lstart:    .long  start_kernel
+            .align 8
+.Lprefix:   .long  init_S390_lowcore	
+.Linittu:   .long  init_task_union
+.Lbss_bgn:  .long  __bss_start
+.Lbss_end:  .long  _end
+.Lcr0or:    .long  0x00002000
+            .align 4
+.Laregs:    .long  0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
+	    .align 8
+.Ldw:	    .long  0x000a0000,0x00000000
+
+#
+#        tempory segment-table at 0x11000
+#
+        .org   0x11000
+.Lpgd:  .long  .Lpt0+0x1f               # 00000000-000fffff
+        .long  .Lpt1+0x1f               # 00100000-001fffff
+        .long  .Lpt2+0x1f               # 00200000-002fffff
+        .long  .Lpt3+0x1f               # 00300000-003fffff
+        .fill  2044,4,0x20              # 00400000-7fffffff
+
+#
+#        tempory page-tables at 0x12000-0x15fff
+#
+        .macro  mktable from,to
+        .long   \from*0x10000
+        .long   \from*0x10000+0x1000
+        .long   \from*0x10000+0x2000
+        .long   \from*0x10000+0x3000
+        .long   \from*0x10000+0x4000
+        .long   \from*0x10000+0x5000
+        .long   \from*0x10000+0x6000
+        .long   \from*0x10000+0x7000
+        .long   \from*0x10000+0x8000
+        .long   \from*0x10000+0x9000
+        .long   \from*0x10000+0xa000
+        .long   \from*0x10000+0xb000
+        .long   \from*0x10000+0xc000
+        .long   \from*0x10000+0xd000
+        .long   \from*0x10000+0xe000
+        .long   \from*0x10000+0xf000
+        .if     \to-\from
+        mktable "(\from+1)",\to
+        .endif
+        .endm
+
+.Lpt0:  mktable 0,15
+.Lpt1:  mktable 16,31
+.Lpt2:  mktable 32,47
+.Lpt3:  mktable 48,63
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/ieee.h linux.14p16/arch/s390/kernel/ieee.h
--- linux.vanilla/arch/s390/kernel/ieee.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/ieee.h	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,90 @@
+/*
+ *  arch/s390/kernel/ieee.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+#include <linux/sched.h>
+
+static    inline void _adddf(int R1,int R2)
+{
+  current->tss.fprs[R1].fd = current->tss.fprs[R1].fd +
+                             current->tss.fprs[R2].fd;
+}
+
+static    inline void _subdf(int R1,int R2)
+{
+  current->tss.fprs[R1].fd = current->tss.fprs[R1].fd -
+                             current->tss.fprs[R2].fd;
+}
+
+static    inline void _muldf(int R1,int R2)
+{
+  current->tss.fprs[R1].fd = current->tss.fprs[R1].fd *
+                             current->tss.fprs[R2].fd;
+}
+
+static    inline void _divdf(int R1,int R2)
+{
+  current->tss.fprs[R1].fd = current->tss.fprs[R1].fd /
+                             current->tss.fprs[R2].fd;
+}
+
+static    inline void _negdf(int R1,int R2)
+{
+  current->tss.fprs[R1].fd = -current->tss.fprs[R1].fd;
+}
+
+static    inline void _fixdfsi(int R1,int R2)
+{
+  current->tss.regs->gprs[R1] = (__u32) current->tss.fprs[R2].fd;
+}
+
+static    inline void _extendsidf(int R1,int R2)
+{
+  current->tss.fprs[R1].fd = (double) current->tss.regs->gprs[R2];
+}
+
+
+static    inline  void _addsf(int R1,int R2)
+{
+  current->tss.fprs[R1].ff = current->tss.fprs[R1].ff +
+                             current->tss.fprs[R2].ff;
+}
+
+static    inline  void _subsf(int R1,int R2)
+{
+  current->tss.fprs[R1].ff = current->tss.fprs[R1].ff -
+                             current->tss.fprs[R2].ff;
+}
+
+static    inline void _mulsf(int R1,int R2)
+{
+  current->tss.fprs[R1].ff = current->tss.fprs[R1].ff *
+                             current->tss.fprs[R2].ff;
+}
+
+static    inline void _divsf(int R1,int R2)
+{
+  current->tss.fprs[R1].ff = current->tss.fprs[R1].ff /
+                             current->tss.fprs[R2].ff;
+}
+
+static    inline void _negsf(int R1,int R2)
+{
+  current->tss.fprs[R1].ff = -current->tss.fprs[R1].ff;
+}
+
+static    inline void _fixsfsi(int R1,int R2)
+{
+  current->tss.regs->gprs[R1] = (__u32) current->tss.fprs[R2].ff;
+}
+
+static    inline void _extendsisf(int R1,int R2)
+{
+  current->tss.fprs[R1].ff = (double) current->tss.regs->gprs[R2];
+}
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/init_task.c linux.14p16/arch/s390/kernel/init_task.c
--- linux.vanilla/arch/s390/kernel/init_task.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/init_task.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,31 @@
+/*
+ *  arch/s390/kernel/init_task.c
+ *
+ *  S390 version
+ *
+ *  Derived from "arch/i386/kernel/init_task.c"
+ */
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+
+/*
+ * Initial task structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by making sure
+ * the linker maps this in the .text segment right after head.S,
+ * and making head.S ensure the proper alignment.
+ *
+ * The things we do for performance..
+ */
+union task_union init_task_union __attribute__((aligned(8192))) = { INIT_TASK };
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/irq.c linux.14p16/arch/s390/kernel/irq.c
--- linux.vanilla/arch/s390/kernel/irq.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/irq.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,428 @@
+/*
+ *  arch/s390/kernel/irq.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Ingo Adlung (adlung@de.ibm.com)
+ *
+ *  Derived from "arch/i386/kernel/irq.c"
+ *    Copyright (C) 1992, 1999 Linus Torvalds, Ingo Molnar
+ *
+ *  S/390 I/O interrupt processing and I/O request processing is
+ *  implemented in linux/arch/s390/do_io.c
+ */
+
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/random.h>
+#include <linux/smp.h>
+#include <linux/tasks.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/smp.h>
+#include <asm/pgtable.h>
+#include <asm/delay.h>
+#include <asm/lowcore.h>
+
+#include "irq.h"
+
+
+void s390_init_IRQ(void);
+void s390_free_irq(unsigned int irq, void *dev_id);
+int  s390_request_irq( unsigned int   irq,
+                       void           (*handler)(int, void *, struct pt_regs *),
+                       unsigned long  irqflags,
+                       const char    *devname,
+                       void          *dev_id);
+
+atomic_t nmi_counter;
+spinlock_t s390_bh_lock = SPIN_LOCK_UNLOCKED;
+/*
+ * Dummy controller type for unused interrupts
+ */
+int  do_none(unsigned int irq, int cpu, struct pt_regs * regs) { return 0;}
+int  enable_none(unsigned int irq) { return(-ENODEV); }
+int  disable_none(unsigned int irq) { return(-ENODEV); }
+
+struct hw_interrupt_type no_irq_type = {
+	"none",
+	do_none,
+	enable_none,
+	disable_none
+};
+
+irq_desc_t irq_desc[NR_IRQS] = {
+	[0 ... (NR_IRQS-1)] = { 0, &no_irq_type, },
+};
+
+#if 0
+/*
+ * The following vectors are part of the Linux architecture, there
+ * is no hardware IRQ pin equivalent for them, they are triggered
+ * through the ICC by us (IPIs), via smp_message_pass():
+ */
+BUILD_SMP_INTERRUPT(reschedule_interrupt)
+BUILD_SMP_INTERRUPT(invalidate_interrupt)
+BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
+BUILD_SMP_INTERRUPT(mtrr_interrupt)
+BUILD_SMP_INTERRUPT(spurious_interrupt)
+#endif
+
+#if 0
+static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+#endif
+
+int get_irq_list(char *buf)
+{
+	int i, j;
+	struct irqaction * action;
+	char *p = buf;
+
+	p += sprintf(p, "           ");
+	for (j=0; j<smp_num_cpus; j++)
+		p += sprintf(p, "CPU%d       ",j);
+	*p++ = '\n';
+
+	for (i = 0 ; i < NR_IRQS ; i++) {
+		action = irq_desc[i].action;
+		if (!action)
+			continue;
+		p += sprintf(p, "%3d: ",i);
+#ifndef __SMP__
+		p += sprintf(p, "%10u ", kstat_irqs(i));
+#else
+		for (j=0; j<smp_num_cpus; j++)
+			p += sprintf(p, "%10u ",
+				     kstat.irqs[cpu_logical_map(j)][i]);
+#endif
+		p += sprintf(p, " %14s", irq_desc[i].handler->typename);
+		p += sprintf(p, "  %s", action->name);
+
+		for (action=action->next; action; action = action->next) {
+			p += sprintf(p, ", %s", action->name);
+		}
+		*p++ = '\n';
+	}
+	p += sprintf(p, "NMI: %10u\n", atomic_read(&nmi_counter));
+#ifdef __SMP__
+	p += sprintf(p, "IPI: %10u\n", atomic_read(&ipi_count));
+#endif
+	return p - buf;
+}
+
+/*
+ * Global interrupt locks for SMP. Allow interrupts to come in on any
+ * CPU, yet make cli/sti act globally to protect critical regions..
+ */
+#ifdef __SMP__
+atomic_t global_irq_holder = ATOMIC_INIT(NO_PROC_ID);
+atomic_t global_irq_lock;
+atomic_t global_irq_count = ATOMIC_INIT(0);
+
+atomic_t global_bh_count;
+atomic_t global_bh_lock;
+
+/*
+ * "global_cli()" is a special case, in that it can hold the
+ * interrupts disabled for a longish time, and also because
+ * we may be doing TLB invalidates when holding the global
+ * IRQ lock for historical reasons. Thus we may need to check
+ * SMP invalidate events specially by hand here (but not in
+ * any normal spinlocks)
+ *
+ * Thankfully we don't need this as we can deliver flush tlbs with
+ * interrupts disabled DJB :-)
+ */
+#define check_smp_invalidate(cpu)
+
+static void show(char * str)
+{
+	int i;
+	unsigned long *stack;
+	int cpu = smp_processor_id();
+
+	printk("\n%s, CPU %d:\n", str, cpu);
+	printk("irq:  %d [%d]\n",
+	       atomic_read(&global_irq_count),atomic_read(&S390_lowcore.local_irq_count));
+	printk("bh:   %d [%d]\n",
+	       atomic_read(&global_bh_count),atomic_read(&S390_lowcore.local_bh_count));
+	stack = (unsigned long *) &str;
+	for (i = 40; i ; i--) {
+		unsigned long x = *++stack;
+		if (x > (unsigned long) &init_task_union && x < (unsigned long) &vsprintf) {
+			printk("<[%08lx]> ", x);
+		}
+	}
+}
+
+#define MAXCOUNT 100000000
+
+static inline void wait_on_bh(void)
+{
+	int count = MAXCOUNT;
+	do {
+		if (!--count) {
+			show("wait_on_bh");
+			count = ~0;
+		}
+		/* nothing .. wait for the other bh's to go away */
+	} while (atomic_read(&global_bh_count) != 0);
+}
+
+static inline void wait_on_irq(int cpu)
+{
+	int count = MAXCOUNT;
+
+	for (;;) {
+
+		/*
+		 * Wait until all interrupts are gone. Wait
+		 * for bottom half handlers unless we're
+		 * already executing in one..
+		 */
+		if (!atomic_read(&global_irq_count)) {
+			if (atomic_read(&safe_get_cpu_lowcore(cpu).local_bh_count)||
+			    !atomic_read(&global_bh_count))
+				break;
+		}
+
+		/* Duh, we have to loop. Release the lock to avoid deadlocks */
+		clear_bit(0,&global_irq_lock);
+
+		for (;;) {
+			if (!--count) {
+				show("wait_on_irq");
+				count = ~0;
+			}
+			__sti();
+			SYNC_OTHER_CORES(cpu);
+			__cli();
+			check_smp_invalidate(cpu);
+			if (atomic_read(&global_irq_count))
+				continue;
+			if (atomic_read(&global_irq_lock))
+				continue;
+			if (!(atomic_read(&safe_get_cpu_lowcore(cpu).local_bh_count))
+			    && atomic_read(&global_bh_count))
+				continue;
+			if (!test_and_set_bit(0,&global_irq_lock))
+				break;
+		}
+	}
+}
+
+/*
+ * This is called when we want to synchronize with
+ * bottom half handlers. We need to wait until
+ * no other CPU is executing any bottom half handler.
+ *
+ * Don't wait if we're already running in an interrupt
+ * context or are inside a bh handler.
+ */
+void synchronize_bh(void)
+{
+	if (atomic_read(&global_bh_count) && !in_interrupt())
+		wait_on_bh();
+}
+
+/*
+ * This is called when we want to synchronize with
+ * interrupts. We may for example tell a device to
+ * stop sending interrupts: but to make sure there
+ * are no interrupts that are executing on another
+ * CPU we need to call this function.
+ */
+void synchronize_irq(void)
+{
+	if (atomic_read(&global_irq_count)) {
+		/* Stupid approach */
+		cli();
+		sti();
+	}
+}
+
+static inline void get_irqlock(int cpu)
+{
+	if (test_and_set_bit(0,&global_irq_lock)) {
+		/* do we already hold the lock? */
+		if ( cpu == atomic_read(&global_irq_holder))
+			return;
+		/* Uhhuh.. Somebody else got it. Wait.. */
+		do {
+			do {
+				check_smp_invalidate(cpu);
+			} while (test_bit(0,&global_irq_lock));
+		} while (test_and_set_bit(0,&global_irq_lock));
+	}
+	/*
+	 * We also to make sure that nobody else is running
+	 * in an interrupt context.
+	 */
+	wait_on_irq(cpu);
+
+	/*
+	 * Ok, finally..
+	 */
+	atomic_set(&global_irq_holder,cpu);
+}
+
+#define EFLAGS_I_SHIFT 25
+
+/*
+ * A global "cli()" while in an interrupt context
+ * turns into just a local cli(). Interrupts
+ * should use spinlocks for the (very unlikely)
+ * case that they ever want to protect against
+ * each other.
+ *
+ * If we already have local interrupts disabled,
+ * this will not turn a local disable into a
+ * global one (problems with spinlocks: this makes
+ * save_flags+cli+sti usable inside a spinlock).
+ */
+void __global_cli(void)
+{
+	unsigned int flags;
+
+	__save_flags(flags);
+	if (flags & (1 << EFLAGS_I_SHIFT)) {
+		int cpu = smp_processor_id();
+		__cli();
+		if (!atomic_read(&S390_lowcore.local_irq_count))
+			get_irqlock(cpu);
+	}
+}
+
+void __global_sti(void)
+{
+
+	if (!atomic_read(&S390_lowcore.local_irq_count))
+		release_irqlock(smp_processor_id());
+	__sti();
+}
+
+/*
+ * SMP flags value to restore to:
+ * 0 - global cli
+ * 1 - global sti
+ * 2 - local cli
+ * 3 - local sti
+ */
+unsigned long __global_save_flags(void)
+{
+	int retval;
+	int local_enabled;
+	unsigned long flags;
+
+	__save_flags(flags);
+	local_enabled = (flags >> EFLAGS_I_SHIFT) & 1;
+	/* default to local */
+	retval = 2 + local_enabled;
+
+	/* check for global flags if we're not in an interrupt */
+	if (!atomic_read(&S390_lowcore.local_irq_count))
+	{
+		if (local_enabled)
+			retval = 1;
+		if (atomic_read(&global_irq_holder)== smp_processor_id())
+			retval = 0;
+	}
+	return retval;
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+	switch (flags) {
+	case 0:
+		__global_cli();
+		break;
+	case 1:
+		__global_sti();
+		break;
+	case 2:
+		__cli();
+		break;
+	case 3:
+		__sti();
+		break;
+	default:
+		printk("global_restore_flags: %08lx (%08lx)\n",
+		       flags, (&flags)[-1]);
+	}
+}
+
+#endif
+
+/*
+ * Note : This fuction should be eliminated as it doesn't comply with the
+ *         S/390 irq scheme we have implemented ...
+ */
+int handle_IRQ_event(unsigned int irq, int cpu, struct pt_regs * regs)
+{
+	struct irqaction * action;
+	int                status;
+
+	status = 0;
+	action = irq_desc[irq].action;
+
+	if (action) {
+		status |= 1;
+
+		if (!(action->flags & SA_INTERRUPT))
+			__sti();
+
+		do {
+			status |= action->flags;
+			action->handler(irq, action->dev_id, regs);
+			action = action->next;
+		} while (action);
+		if (status & SA_SAMPLE_RANDOM)
+			add_interrupt_randomness(irq);
+		__cli();
+	}
+
+	return status;
+}
+
+
+void enable_nop(int irq)
+{
+}
+
+__initfunc(void init_IRQ(void))
+{
+
+   s390_init_IRQ();
+
+}
+
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+   s390_free_irq( irq, dev_id);
+}
+
+
+int request_irq( unsigned int   irq,
+                 void           (*handler)(int, void *, struct pt_regs *),
+                 unsigned long  irqflags,
+                 const char    *devname,
+                 void          *dev_id)
+{
+   return( s390_request_irq( irq, handler, irqflags, devname, dev_id ) );
+
+}
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/irq.h linux.14p16/arch/s390/kernel/irq.h
--- linux.vanilla/arch/s390/kernel/irq.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/irq.h	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,723 @@
+#ifndef __irq_h
+#define __irq_h
+
+#include <asm/irq.h>
+#include <asm/hardirq.h>
+
+/*
+ * Interrupt controller descriptor. This is all we need
+ * to describe about the low-level hardware.
+ */
+struct hw_interrupt_type {
+        const char   *typename;
+        int         (*handle)(unsigned int irq,
+                              int cpu,
+                              struct pt_regs * regs);
+        int         (*enable) (unsigned int irq);
+        int         (*disable)(unsigned int irq);
+};
+
+
+/*
+ * Status: reason for being disabled: somebody has
+ * done a "disable_irq()" or we must not re-enter the
+ * already executing irq..
+ */
+#define IRQ_INPROGRESS  1
+#define IRQ_DISABLED    2
+#define IRQ_PENDING     4
+
+/*
+ * path management control word
+ */
+typedef struct {
+      unsigned long  intparm;      /* interruption parameter */
+      unsigned int   res0 : 2;     /* reserved zeros */
+      unsigned int   isc  : 3;     /* interruption sublass */
+      unsigned int   res5 : 3;     /* reserved zeros */
+      unsigned int   ena  : 1;     /* enabled */
+      unsigned int   lm   : 2;     /* limit mode */
+      unsigned int   mme  : 2;     /* measurement-mode enable */
+      unsigned int   mp   : 1;     /* multipath mode */
+      unsigned int   tf   : 1;     /* timing facility */
+      unsigned int   dnv  : 1;     /* device number valid */
+      unsigned int   dev  : 16;    /* device number */
+      unsigned char  lpm;          /* logical path mask */
+      unsigned char  pnom;         /* path not operational mask */
+      unsigned char  lpum;         /* last path used mask */
+      unsigned char  pim;          /* path installed mask */
+      unsigned short mbi;          /* measurement-block index */
+      unsigned char  pom;          /* path operational mask */
+      unsigned char  pam;          /* path available mask */
+      unsigned char  chpid[8];     /* CHPID 0-7 (if available) */
+      unsigned int   unused1 : 8;  /* reserved zeros */
+      unsigned int   st      : 3;  /* subchannel type */
+      unsigned int   unused2 : 20; /* reserved zeros */
+      unsigned int   csense  : 1;  /* concurrent sense; can be enabled ...*/
+                                   /*  ... per MSCH, however, if facility */
+                                   /*  ... is not installed, this results */
+                                   /*  ... in an operand exception.       */
+   } pmcw_t;
+
+/*
+ * subchannel status word
+ */
+typedef struct {
+      unsigned int   key  : 4; /* subchannel key */
+      unsigned int   sctl : 1; /* suspend control */
+      unsigned int   eswf : 1; /* ESW format */
+      unsigned int   cc   : 2; /* deferred condition code */
+      unsigned int   fmt  : 1; /* format */
+      unsigned int   pfch : 1; /* prefetch */
+      unsigned int   isic : 1; /* initial-status interruption control */
+      unsigned int   alcc : 1; /* address-limit checking control */
+      unsigned int   ssi  : 1; /* supress-suspended interruption */
+      unsigned int   zcc  : 1; /* zero condition code */
+      unsigned int   ectl : 1; /* extended control */
+      unsigned int   pno  : 1;     /* path not operational */
+      unsigned int   res  : 1;     /* reserved */
+      unsigned int   fctl : 3;     /* function control */
+      unsigned int   actl : 7;     /* activity control */
+      unsigned int   stctl : 5;    /* status control */
+      unsigned long  cpa;          /* channel program address */
+      unsigned int   dstat : 8;    /* device status */
+      unsigned int   cstat : 8;    /* subchannel status */
+      unsigned int   count : 16;   /* residual count */
+   } scsw_t;
+
+#define SCSW_FCTL_CLEAR_FUNC     0x1
+#define SCSW_FCTL_HALT_FUNC      0x2
+#define SCSW_FCTL_START_FUNC     0x4
+
+#define SCSW_ACTL_SUSPENDED      0x1
+#define SCSW_ACTL_DEVACT         0x2
+#define SCSW_ACTL_SCHACT         0x4
+#define SCSW_ACTL_CLEAR_PEND     0x8
+#define SCSW_ACTL_HALT_PEND      0x10
+#define SCSW_ACTL_START_PEND     0x20
+#define SCSW_ACTL_RESUME_PEND    0x40
+
+#define SCSW_STCTL_STATUS_PEND   0x1
+#define SCSW_STCTL_SEC_STATUS    0x2
+#define SCSW_STCTL_PRIM_STATUS   0x4
+#define SCSW_STCTL_INTER_STATUS  0x8
+#define SCSW_STCTL_ALERT_STATUS  0x10
+
+#define DEV_STAT_ATTENTION       0x80
+#define DEV_STAT_STAT_MOD        0x40
+#define DEV_STAT_CU_END          0x20
+#define DEV_STAT_BUSY            0x10
+#define DEV_STAT_CHN_END         0x08
+#define DEV_STAT_DEV_END         0x04
+#define DEV_STAT_UNIT_CHECK      0x02
+#define DEV_STAT_UNIT_EXCEP      0x01
+
+#define SCHN_STAT_PCI            0x80
+#define SCHN_STAT_INCORR_LEN     0x40
+#define SCHN_STAT_PROG_CHECK     0x20
+#define SCHN_STAT_PROT_CHECK     0x10
+#define SCHN_STAT_CHN_DATA_CHK   0x08
+#define SCHN_STAT_CHN_CTRL_CHK   0x04
+#define SCHN_STAT_INTF_CTRL_CHK  0x02
+#define SCHN_STAT_CHAIN_CHECK    0x01
+
+/*
+ * subchannel information block
+ */
+typedef struct {
+      pmcw_t pmcw;             /* path management control word */
+      scsw_t scsw;             /* subchannel status word */
+      char mda[12];            /* model dependent area */
+   } schib_t;
+
+typedef struct {
+      char            cmd_code;/* command code */
+      char            flags;   /* flags, like IDA adressing, etc. */
+      unsigned short  count;   /* byte count */
+      void           *cda;     /* data address */
+   } ccw1_t __attribute__ ((aligned(8)));
+
+#define CCW_FLAG_DC             0x80
+#define CCW_FLAG_CC             0x40
+#define CCW_FLAG_SLI            0x20
+#define CCW_FLAG_SKIP           0x10
+#define CCW_FLAG_PCI            0x08
+#define CCW_FLAG_IDA            0x04
+#define CCW_FLAG_SUSPEND        0x02
+
+#define CCW_CMD_BASIC_SENSE     0x04
+#define CCW_CMD_TIC             0x08
+#define CCW_CMD_SENSE_ID        0xE4
+#define CCW_CMD_NOOP            0x03
+#define CCW_CMD_RDC             0x64
+
+#define SENSE_MAX_COUNT         0x20
+
+/*
+ * architectured values for first sense byte
+ */
+#define SNS0_CMD_REJECT         0x80
+#define SNS_CMD_REJECT          SNS0_CMD_REJECT
+#define SNS0_INTERVENTION_REQ   0x40
+#define SNS0_BUS_OUT_CHECK      0x20
+#define SNS0_EQUIPMENT_CHECK    0x10
+#define SNS0_DATA_CHECK         0x08
+#define SNS0_OVERRUN            0x04
+
+/*
+ * operation request block
+ */
+typedef struct {
+      unsigned long  intparm;  /* interruption parameter */
+      unsigned int   key  : 4; /* flags, like key, suspend control, etc. */
+      unsigned int   spnd : 1; /* suspend control */
+      unsigned int   res1 : 3; /* reserved */
+      unsigned int   fmt  : 1; /* format control */
+      unsigned int   pfch : 1; /* prefetch control */
+      unsigned int   isic : 1; /* initial-status-interruption control */
+      unsigned int   alcc : 1; /* address-limit-checking control */
+      unsigned int   ssic : 1; /* suppress-suspended-interr. control */
+      unsigned int   res2 : 3; /* reserved */
+      unsigned int   lpm  : 8; /* logical path mask */
+      unsigned int   ils  : 1; /* incorrect length */
+      unsigned int   zero : 7; /* reserved zeros */
+      ccw1_t        *cpa;      /* channel program address */
+   }  __attribute__ ((packed,aligned(4))) orb_t;
+
+typedef struct {
+      unsigned int res0  : 4;  /* reserved */
+      unsigned int pvrf  : 1;  /* path-verification-required flag */
+      unsigned int cpt   : 1;  /* channel-path timeout */
+      unsigned int fsavf : 1;  /* Failing storage address validity flag */
+      unsigned int cons  : 1;  /* concurrent-sense */
+      unsigned int res8  : 2;  /* reserved */
+      unsigned int scnt  : 6;  /* sense count if cons == 1 */
+      unsigned int res16 : 16; /* reserved */
+   } erw_t;
+
+/*
+ * subchannel logout area
+ */
+typedef struct {
+      unsigned int res0  : 1;  /* reserved */
+      unsigned int esf   : 7;  /* extended status flags */
+      unsigned int lpum  : 8;  /* last path used mask */
+      unsigned int res16 : 1;  /* reserved */
+      unsigned int fvf   : 5;  /* field-validity flags */
+      unsigned int sacc  : 2;  /* storage access code */
+      unsigned int termc : 2;  /* termination code */
+      unsigned int devsc : 1;  /* device-status check */
+      unsigned int serr  : 1;  /* secondary error */
+      unsigned int ioerr : 1;  /* i/o-error alert */
+      unsigned int seqc  : 3;  /* sequence code */
+   } sublog_t ;
+
+/*
+ * Format 0 Extended Status Word (ESW)
+ */
+typedef struct {
+      sublog_t      sublog;    /* subchannel logout */
+      erw_t         erw;       /* extended report word */
+      void         *faddr;     /* failing address */
+      unsigned int  zeros[2];  /* 2 fullwords of zeros */
+   } esw0_t;
+
+/*
+ * Format 1 Extended Status Word (ESW)
+ */
+typedef struct {
+      unsigned char  zero0;    /* reserved zeros */
+      unsigned char  lpum;     /* last path used mask */
+      unsigned short zero16;   /* reserved zeros */
+      erw_t          erw;      /* extended report word */
+      unsigned int   zeros[3]; /* 2 fullwords of zeros */
+   } esw1_t;
+
+/*
+ * Format 2 Extended Status Word (ESW)
+ */
+typedef struct {
+      unsigned char  zero0;    /* reserved zeros */
+      unsigned char  lpum;     /* last path used mask */
+      unsigned short dcti;     /* device-connect-time interval */
+      erw_t          erw;      /* extended report word */
+      unsigned int   zeros[3]; /* 2 fullwords of zeros */
+   } esw2_t;
+
+/*
+ * Format 3 Extended Status Word (ESW)
+ */
+typedef struct {
+      unsigned char  zero0;    /* reserved zeros */
+      unsigned char  lpum;     /* last path used mask */
+      unsigned short res;      /* reserved */
+      erw_t          erw;      /* extended report word */
+      unsigned int   zeros[3]; /* 2 fullwords of zeros */
+   } esw3_t;
+
+typedef union {
+      esw0_t esw0;
+      esw1_t esw1;
+      esw2_t esw2;
+      esw3_t esw3;
+   } esw_t;
+
+/*
+ * interruption response block
+ */
+typedef struct {
+      scsw_t scsw;             /* subchannel status word */
+      esw_t  esw;              /* extended status word */
+      char   ecw[32];          /* extended control word */
+   } irb_t __attribute__ ((aligned(4)));
+
+/*
+ * TPI info structure
+ */
+typedef struct {
+      unsigned int res : 16;   /* reserved 0x00000001 */
+      unsigned int irq : 16;   /* aka. subchannel number */
+      unsigned int intparm;    /* interruption parameter */
+   } tpi_info_t;
+
+
+/*
+ * This is the "IRQ descriptor", which contains various information
+ * about the irq, including what kind of hardware handling it has,
+ * whether it is disabled etc etc.
+ *
+ * Pad this out to 32 bytes for cache and indexing reasons.
+ */
+typedef struct {
+      unsigned int              status;    /* IRQ status - IRQ_INPROGRESS, IRQ_DISABLED */
+      struct hw_interrupt_type *handler;   /* handle/enable/disable functions */
+      struct irqaction         *action;    /* IRQ action list */
+      unsigned int              unused[3];
+      spinlock_t                irq_lock;
+   } irq_desc_t;
+
+//
+// command information word  (CIW) layout
+//
+typedef struct _ciw {
+   unsigned int et       :  2; // entry type
+   unsigned int reserved :  2; // reserved
+   unsigned int ct       :  4; // command type
+   unsigned int cmd      :  8; // command
+   unsigned int count    : 16; // count
+   } ciw_t;
+
+#define CIW_TYPE_RCD    0x0    // read configuration data
+#define CIW_TYPE_SII    0x1    // set interface identifier
+#define CIW_TYPE_RNI    0x2    // read node identifier
+
+//
+// sense-id response buffer layout
+//
+typedef struct {
+  /* common part */
+      unsigned char  reserved;     /* always 0x'FF' */
+      unsigned short cu_type;      /* control unit type */
+      unsigned char  cu_model;     /* control unit model */
+      unsigned short dev_type;     /* device type */
+      unsigned char  dev_model;    /* device model */
+      unsigned char  unused;       /* padding byte */
+  /* extended part */
+      ciw_t    ciw[62];            /* variable # of CIWs */
+   }  __attribute__ ((packed,aligned(4))) senseid_t;
+
+/*
+ * sense data
+ */
+typedef struct {
+      unsigned char res[32];   /* reserved   */
+      unsigned char data[32];  /* sense data */
+   } sense_t;
+
+/*
+ * device status area, to be provided by the device driver
+ *  when calling request_irq() as parameter "dev_id", later
+ *  tied to the "action" control block.
+ *
+ * Note : No data area must be added after union ii or the
+ *         effective devstat size calculation will fail !
+ */
+typedef struct {
+     unsigned int  devno;    /* device number, aka. "cuu" from irb */
+     unsigned int  intparm;  /* interrupt parameter */
+     unsigned char cstat;    /* channel status - accumulated */
+     unsigned char dstat;    /* device status - accumulated */
+     unsigned char lpum;     /* last path used mask from irb */
+     unsigned char unused;   /* not used - reserved */
+     unsigned int  flag;     /* flag : see below */
+     unsigned long cpa;      /* CCW address from irb at primary status */
+     unsigned int  rescnt;   /* res. count from irb at primary status */
+     unsigned int  scnt;     /* sense count, if DEVSTAT_FLAG_SENSE_AVAIL */
+     union {
+        irb_t   irb;         /* interruption response block */
+        sense_t sense;       /* sense information */
+        } ii;                /* interrupt information */
+  } devstat_t;
+
+#define DEVSTAT_FLAG_SENSE_AVAIL   0x00000001
+#define DEVSTAT_NOT_OPER           0x00000002
+#define DEVSTAT_START_FUNCTION     0x00000004
+#define DEVSTAT_HALT_FUNCTION      0x00000008
+#define DEVSTAT_STATUS_PENDING     0x00000010
+#define DEVSTAT_FINAL_STATUS       0x80000000
+
+/*
+ * Flags used as input parameters for do_IO()
+ */
+#define DOIO_EARLY_NOTIFICATION 0x01    /* allow for I/O completion ... */
+                                        /* ... notification after ... */
+                                        /* ... primary interrupt status */
+#define DOIO_RETURN_CHAN_END       DOIO_EARLY_NOTIFICATION
+#define DOIO_VALID_LPM          0x02    /* LPM input parameter is valid */
+#define DOIO_WAIT_FOR_INTERRUPT 0x04    /* wait synchronously for interrupt */
+#define DOIO_REPORT_ALL         0x08    /* report all interrupt conditions */
+#define DOIO_ALLOW_SUSPEND      0x10    /* allow for channel prog. suspend */
+#define DOIO_DENY_PREFETCH      0x20    /* don't allow for CCW prefetch */
+#define DOIO_SUPPRESS_INTER     0x40    /* suppress intermediate inter. */
+                                        /* ... for suspended CCWs */
+
+/*
+ * do_IO()
+ *
+ * Start a S/390 channel program. When the interrupt arrives
+ *  handle_IRQ_event() is called, which eventually calls the
+ *  IRQ handler, either immediately, delayed (dev-end missing,
+ *  or sense required) or never (no IRQ handler registered -
+ *  should never occur, as the IRQ (subchannel ID) should be
+ *  disabled if no handler is present. Depending on the action
+ *  taken, do_IO() returns :  0      - Success
+ *                           -EIO    - Status pending
+ *                                        see : action->dev_id->cstat
+ *                                              action->dev_id->dstat
+ *                           -EBUSY  - Device busy
+ *                           -ENODEV - Device not operational
+ */
+int do_IO( int            irq,          /* IRQ aka. subchannel number */
+           ccw1_t        *cpa,          /* logical channel program address */
+           unsigned long  initparm,     /* interruption parameter */
+           unsigned char  lpm,          /* logical path mask */
+           unsigned long  flag);        /* flags : see above */
+
+int start_IO( int            irq,       /* IRQ aka. subchannel number */
+              ccw1_t        *cpa,       /* logical channel program address */
+              unsigned long  intparm,   /* interruption parameter */
+              unsigned char  lpm,       /* logical path mask */
+              unsigned long  flag);     /* flags : see above */
+
+int resume_IO( int irq);                /* IRQ aka. subchannel number */
+
+int halt_IO( int          irq,          /* IRQ aka. subchannel number */
+             int          intparm,      /* dummy intparm */
+             unsigned int flag);        /* possible DOIO_WAIT_FOR_INTERRUPT */
+
+
+int process_IRQ( struct pt_regs regs,
+                 unsigned int   irq,
+                 unsigned int   intparm);
+
+
+int enable_cpu_sync_isc ( int irq );
+int disable_cpu_sync_isc( int irq );
+
+typedef struct {
+     int          irq;                  /* irq, aka. subchannel */
+     unsigned int devno;                /* device number */
+     unsigned int status;               /* device status */
+     senseid_t    sid_data;             /* senseID data */
+     } dev_info_t;
+
+int get_dev_info( int irq, dev_info_t *);   /* to be eliminated - don't use */
+
+int get_dev_info_by_irq  ( int irq, dev_info_t *pdi);
+int get_dev_info_by_devno( unsigned int devno, dev_info_t *pdi);
+
+int          get_irq_by_devno( unsigned int devno );
+unsigned int get_devno_by_irq( int irq );
+
+int read_dev_chars( int irq, void **buffer, int length );
+int read_conf_data( int irq, void **buffer, int *length );
+
+extern senseid_t senseid[NR_IRQS];
+
+extern irq_desc_t irq_desc[NR_IRQS];
+
+extern int handle_IRQ_event(unsigned int, int cpu, struct pt_regs *);
+
+extern int set_cons_dev(int irq);
+extern int reset_cons_dev(int irq);
+extern int wait_cons_dev(int irq);
+
+/*
+ * Some S390 specific IO instructions as inline
+ */
+
+extern __inline__ int stsch(int irq, volatile schib_t *addr)
+{
+        int ccode;
+
+        __asm__ __volatile__(
+                "LR 1,%1\n\t"
+                "STSCH 0(%2)\n\t"
+                "IPM %0\n\t"
+                "SRL %0,28\n\t"
+                : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr)
+                : "cc", "1" );
+        return ccode;
+}
+
+extern __inline__ int msch(int irq, volatile schib_t *addr)
+{
+        int ccode;
+
+        __asm__ __volatile__(
+                "LR 1,%1\n\t"
+                "MSCH 0(%2)\n\t"
+                "IPM %0\n\t"
+                "SRL %0,28\n\t"
+                : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr)
+                : "cc", "1" );
+        return ccode;
+}
+
+extern __inline__ int msch_err(int irq, volatile schib_t *addr)
+{
+        int ccode;
+
+        __asm__ __volatile__(
+                "    lr   1,%1\n"
+                "    msch 0(%2)\n"
+                "0:  ipm  %0\n"
+                "    srl  %0,28\n"
+                "1:\n"
+                ".section .fixup,\"ax\"\n"
+                "2:  l    %0,%3\n"
+                "    bras 1,3f\n"
+                "    .long 1b\n"
+                "3:  l    1,0(1)\n"
+                "    br   1\n"
+                ".previous\n"
+                ".section __ex_table,\"a\"\n"
+                "   .align 4\n"
+                "   .long 0b,2b\n"
+                ".previous"
+                : "=d" (ccode)
+                : "r" (irq | 0x10000L), "a" (addr), "i" (__LC_PGM_ILC)
+                : "cc", "1" );
+        return ccode;
+}
+
+extern __inline__ int tsch(int irq, volatile irb_t *addr)
+{
+        int ccode;
+
+        __asm__ __volatile__(
+                "LR 1,%1\n\t"
+                "TSCH 0(%2)\n\t"
+                "IPM %0\n\t"
+                "SRL %0,28\n\t"
+                : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr)
+                : "cc", "1" );
+        return ccode;
+}
+
+extern __inline__ int tpi( volatile tpi_info_t *addr)
+{
+        int ccode;
+
+        __asm__ __volatile__(
+                "TPI 0(%1)\n\t"
+                "IPM %0\n\t"
+                "SRL %0,28\n\t"
+                : "=d" (ccode) : "a" (addr)
+                : "cc", "1" );
+        return ccode;
+}
+
+extern __inline__ int ssch(int irq, volatile orb_t *addr)
+{
+        int ccode;
+
+        __asm__ __volatile__(
+                "LR 1,%1\n\t"
+                "SSCH 0(%2)\n\t"
+                "IPM %0\n\t"
+                "SRL %0,28\n\t"
+                : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr)
+                : "cc", "1" );
+        return ccode;
+}
+
+extern __inline__ int rsch(int irq)
+{
+        int ccode;
+
+        __asm__ __volatile__(
+                "LR 1,%1\n\t"
+                "RSCH\n\t"
+                "IPM %0\n\t"
+                "SRL %0,28\n\t"
+                : "=d" (ccode) : "r" (irq | 0x10000L)
+                : "cc", "1" );
+        return ccode;
+}
+
+extern __inline__ int csch(int irq)
+{
+        int ccode;
+
+        __asm__ __volatile__(
+                "LR 1,%1\n\t"
+                "CSCH\n\t"
+                "IPM %0\n\t"
+                "SRL %0,28\n\t"
+                : "=d" (ccode) : "r" (irq | 0x10000L)
+                : "cc", "1" );
+        return ccode;
+}
+
+extern __inline__ int hsch(int irq)
+{
+        int ccode;
+
+        __asm__ __volatile__(
+                "LR 1,%1\n\t"
+                "HSCH\n\t"
+                "IPM %0\n\t"
+                "SRL %0,28\n\t"
+                : "=d" (ccode) : "r" (irq | 0x10000L)
+                : "cc", "1" );
+        return ccode;
+}
+
+extern __inline__ int iac( void)
+{
+        int ccode;
+
+        __asm__ __volatile__(
+                "IAC %0\n\t"
+                "IPM %0\n\t"
+                "SRL %0,28\n\t"
+                : "=d" (ccode) : : "cc");
+        return ccode;
+}
+
+typedef struct {
+     unsigned int vrdcdvno : 16;   /* device number (input) */
+     unsigned int vrdclen  : 16;   /* data block length (input) */
+     unsigned int vrdcvcla : 8;    /* virtual device class (output) */
+     unsigned int vrdcvtyp : 8;    /* virtual device type (output) */
+     unsigned int vrdcvsta : 8;    /* virtual device status (output) */
+     unsigned int vrdcvfla : 8;    /* virtual device flags (output) */
+     unsigned int vrdcrccl : 8;    /* real device class (output) */
+     unsigned int vrdccrty : 8;    /* real device type (output) */
+     unsigned int vrdccrmd : 8;    /* real device model (output) */
+     unsigned int vrdccrft : 8;    /* real device feature (output) */
+     } __attribute__ ((packed,aligned(4))) diag210_t;
+
+void VM_virtual_device_info( int        devno,   /* device number */
+                             senseid_t *ps );    /* ptr to senseID data */
+
+extern __inline__ int diag210( diag210_t * addr)
+{
+        int ccode;
+
+        __asm__ __volatile__(
+                "LR 1,%1\n\t"
+                ".long 0x83110210\n\t"
+                "IPM %0\n\t"
+                "SRL %0,28\n\t"
+                : "=d" (ccode) : "a" (addr)
+                : "cc", "1" );
+        return ccode;
+}
+
+/*
+ * Various low-level irq details needed by irq.c, process.c,
+ * time.c, io_apic.c and smp.c
+ *
+ * Interrupt entry/exit code at both C and assembly level
+ */
+
+void mask_irq(unsigned int irq);
+void unmask_irq(unsigned int irq);
+
+#define MAX_IRQ_SOURCES 128
+
+extern spinlock_t irq_controller_lock;
+
+#ifdef __SMP__
+
+#include <asm/atomic.h>
+
+static inline void irq_enter(int cpu, unsigned int irq)
+{
+        hardirq_enter(cpu);
+        while (test_bit(0,&global_irq_lock)) {
+                eieio();
+        }
+}
+
+static inline void irq_exit(int cpu, unsigned int irq)
+{
+        hardirq_exit(cpu);
+        release_irqlock(cpu);
+}
+
+
+#else
+
+#define irq_enter(cpu, irq)     (++local_irq_count[cpu])
+#define irq_exit(cpu, irq)      (--local_irq_count[cpu])
+
+#endif
+
+#define __STR(x) #x
+#define STR(x) __STR(x)
+
+#ifdef __SMP__
+
+/*
+ *      SMP has a few special interrupts for IPI messages
+ */
+
+#endif /* __SMP__ */
+
+/*
+ * x86 profiling function, SMP safe. We might want to do this in
+ * assembly totally?
+ */
+static inline void s390_do_profile (unsigned long addr)
+{
+#if 0
+        if (prof_buffer && current->pid) {
+                addr -= (unsigned long) &_stext;
+                addr >>= prof_shift;
+                /*
+                 * Don't ignore out-of-bounds EIP values silently,
+                 * put them into the last histogram slot, so if
+                 * present, they will show up as a sharp peak.
+                 */
+                if (addr > prof_len-1)
+                        addr = prof_len-1;
+                atomic_inc((atomic_t *)&prof_buffer[addr]);
+        }
+#endif
+}
+
+#define s390irq_spin_lock(irq) \
+        spin_lock(&(irq_desc[irq].irq_lock))
+
+#define s390irq_spin_unlock(irq) \
+        spin_unlock(&(irq_desc[irq].irq_lock))
+
+#define s390irq_spin_lock_irqsave(irq,flags) \
+        spin_lock_irqsave(&(irq_desc[irq].irq_lock), flags)
+#define s390irq_spin_unlock_irqrestore(irq,flags) \
+        spin_unlock_irqrestore(&(irq_desc[irq].irq_lock), flags)
+#endif
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/irqextras390.c linux.14p16/arch/s390/kernel/irqextras390.c
--- linux.vanilla/arch/s390/kernel/irqextras390.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/irqextras390.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,35 @@
+/*
+ *  arch/s390/kernel/irqextras390.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *
+ *  Some channel code by D.J. Barrow
+ */
+
+/*
+	
+*/
+#include<asm/irqextras390.h>
+#include<asm/lowcore.h>
+
+#if 0
+// fixchannelprogram is now obselete
+void fixchannelprogram(orb_bits_t *orbptr)
+{
+	__u32	newAddress=orbptr->ccw_program_address;
+	fixccws(orbptr->ccw_program_address);
+	orbptr->ccw_program_address=newAddress;
+	orbptr->ccw_program_address=(ccw1_t *)(((__u32)orbptr->ccw_program_address));
+}
+#endif
+
+void fixccws(ccw1_bits_t *ccwptr)
+{
+	for(;;ccwptr++)
+	{	// Just hope nobody starts doing prefixing
+		if(!ccwptr->cc)
+			break;
+	}
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/lowcore.S linux.14p16/arch/s390/kernel/lowcore.S
--- linux.vanilla/arch/s390/kernel/lowcore.S	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/lowcore.S	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,60 @@
+/*
+ *  arch/s390/kernel/lowcore.S
+ *    S390 lowcore definition.
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Hartmut Penner (hp@de.ibm.com)
+ *               Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+#include <asm/lowcore.h>
+         .align 4096
+         .globl init_S390_lowcore
+init_S390_lowcore:      
+         .long  _RESTART_PSW_MASK
+         .long  restart_int_handler + _ADDR_31
+         .long  0,0
+         .long  0,0
+EXT_OLD: .long  0,0
+SVC_OLD: .long  0,0
+PGM_OLD: .long  0,0
+MCCK_OLD:.long  0,0
+IO_OLD:  .long  0,0
+         .long  0,0,0,0,0,0
+#
+# new psws need all to be physical
+# because we start with dat off
+#
+EXT_PSW: .long  _EXT_PSW_MASK
+         .long  ext_int_handler + _ADDR_31
+#
+SVC_PSW: .long  _SVC_PSW_MASK
+         .long  system_call + _ADDR_31
+#
+PGM_PSW: .long  _PGM_PSW_MASK
+         .long  pgm_check_handler + _ADDR_31
+#
+MCCK_PSW:.long  _MCCK_PSW_MASK
+         .long  mcck_int_handler + _ADDR_31
+#
+IO_PSW:  .long  _IO_PSW_MASK
+         .long  io_int_handler + _ADDR_31
+#
+#
+#
+EXTERNAL_PARAMETER:     .long  0
+CPU_ADDRESS:            .word 0
+EXT_INTERRUPT_CODE:     .word 0
+SVC_ILC:                .word 0
+SVC_CODE:               .word 0
+PGM_ILC:                .word 0
+PGM_CODE:               .word 0
+TRANS_EXC_ADDR:         .long  0                         # 090
+                        .fill 0xC00-0x094,1,0
+SAVE_AREA:              .fill 0x40,1,0                   # C00
+KERNEL_STACK:           .long 0                          # C40
+KERNEL_LEVEL:           .long 0                          # C44
+CPUID:                  .long 0,0                        # C48
+                        .fill 0x1000-0xC50,1,0
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/mathemu.c linux.14p16/arch/s390/kernel/mathemu.c
--- linux.vanilla/arch/s390/kernel/mathemu.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/mathemu.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,895 @@
+/*
+ *  arch/s390/kernel/mathemu.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ * 'mathemu.c' handles IEEE instructions on a S390 processor
+ * that does not have the IEEE fpu
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+
+#include <asm/uaccess.h>
+#include <asm/mathemu.h>
+
+static void set_CC_df(__u64 val1,__u64 val2) {
+        int rc;
+        rc = __cmpdf2(val1,val2);
+        current->tss.regs->psw.mask &= 0xFFFFCFFF;
+        switch (rc) {
+                case -1:
+                        current->tss.regs->psw.mask |= 0x00001000;
+                        break;
+                case 1:
+                        current->tss.regs->psw.mask |= 0x00002000;
+                        break;
+        }
+}
+
+static void set_CC_sf(__u32 val1,__u32 val2) {
+        int rc;
+        rc = __cmpsf2(val1,val2);
+        current->tss.regs->psw.mask &= 0xFFFFCFFF;
+        switch (rc) {
+                case -1:
+                        current->tss.regs->psw.mask |= 0x00001000;
+                        break;
+                case 1:
+                        current->tss.regs->psw.mask |= 0x00002000;
+                        break;
+        }
+}
+
+
+static void emu_adb (int rx, __u64 val) {
+        current->tss.fp_regs.fprs[rx].d = __adddf3(current->tss.fp_regs.fprs[rx].d,val);
+        set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_adbr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].d = __adddf3(current->tss.fp_regs.fprs[rx].d,
+                                         current->tss.fp_regs.fprs[ry].d);
+        set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_aeb (int rx, __u32 val) {
+        current->tss.fp_regs.fprs[rx].f = __addsf3(current->tss.fp_regs.fprs[rx].f,val);
+        set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_aebr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].f = __addsf3(current->tss.fp_regs.fprs[rx].f,
+                                        current->tss.fp_regs.fprs[ry].f);
+        set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_axbr (int rx, int ry) {
+        printk("axbr emulation not implemented!\n");
+}
+
+static void emu_cdb (int rx, __u64 val) {
+        set_CC_df(current->tss.fp_regs.fprs[rx].d,val);
+}
+
+static void emu_cdbr (int rx, int ry) {
+        set_CC_df(current->tss.fp_regs.fprs[rx].d,current->tss.fp_regs.fprs[ry].d);
+}
+
+static void emu_cdfbr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].d =
+                     __floatsidf(current->tss.regs->gprs[ry]);
+}
+
+static void emu_ceb (int rx, __u32 val) {
+        set_CC_sf(current->tss.fp_regs.fprs[rx].f,val);
+}
+
+static void emu_cebr (int rx, int ry) {
+        set_CC_sf(current->tss.fp_regs.fprs[rx].f,current->tss.fp_regs.fprs[ry].f);
+}
+
+static void emu_cefbr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].f =
+                     __floatsisf(current->tss.regs->gprs[ry]);
+}
+
+static void emu_cfdbr (int rx, int ry, int mask) {
+        current->tss.regs->gprs[rx] =
+                     __fixdfsi(current->tss.fp_regs.fprs[ry].d);
+}
+
+static void emu_cfebr (int rx, int ry, int mask) {
+        current->tss.regs->gprs[rx] =
+                     __fixsfsi(current->tss.fp_regs.fprs[ry].f);
+}
+
+static void emu_cfxbr (int rx, int ry, int mask) {
+        printk("cfxbr emulation not implemented!\n");
+}
+
+static void emu_cxbr (int rx, int ry) {
+        printk("cxbr emulation not implemented!\n");
+}
+
+static void emu_cxfbr (int rx, int ry) {
+        printk("cxfbr emulation not implemented!\n");
+}
+
+static void emu_ddb (int rx, __u64 val) {
+        current->tss.fp_regs.fprs[rx].d = __divdf3(current->tss.fp_regs.fprs[rx].d,val);
+        set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_ddbr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].d = __divdf3(current->tss.fp_regs.fprs[rx].d,
+                                         current->tss.fp_regs.fprs[ry].d);
+        set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_deb (int rx, __u32 val) {
+        current->tss.fp_regs.fprs[rx].f = __divsf3(current->tss.fp_regs.fprs[rx].f,val);
+        set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_debr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].f = __divsf3(current->tss.fp_regs.fprs[rx].f,
+                                         current->tss.fp_regs.fprs[ry].f);
+        set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_didbr (int rx, int ry, int mask) {
+        printk("didbr emulation not implemented!\n");
+}
+
+static void emu_diebr (int rx, int ry, int mask) {
+        printk("diebr emulation not implemented!\n");
+}
+
+static void emu_dxbr (int rx, int ry) {
+        printk("dxbr emulation not implemented!\n");
+}
+
+static void emu_efpc (int rx, int ry) {
+        printk("efpc emulation not implemented!\n");
+}
+
+static void emu_fidbr (int rx, int ry, int mask) {
+        printk("fidbr emulation not implemented!\n");
+}
+
+static void emu_fiebr (int rx, int ry, int mask) {
+        printk("fiebr emulation not implemented!\n");
+}
+
+static void emu_fixbr (int rx, int ry, int mask) {
+        printk("fixbr emulation not implemented!\n");
+}
+
+static void emu_kdb (int rx, __u64 val) {
+        printk("kdb emulation not implemented!\n");
+}
+
+static void emu_kdbr (int rx, int ry) {
+        printk("kdbr emulation not implemented!\n");
+}
+
+static void emu_keb (int rx, __u32 val) {
+        printk("keb emulation not implemented!\n");
+}
+
+static void emu_kebr (int rx, int ry) {
+        printk("kebr emulation not implemented!\n");
+}
+
+static void emu_kxbr (int rx, int ry) {
+        printk("kxbr emulation not implemented!\n");
+}
+
+static void emu_lcdbr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].d =
+        __negdf2(current->tss.fp_regs.fprs[ry].d);
+        set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_lcebr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].f =
+        __negsf2(current->tss.fp_regs.fprs[ry].f);
+        set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_lcxbr (int rx, int ry) {
+        printk("lcxbr emulation not implemented!\n");
+}
+
+static void emu_ldeb (int rx, __u32 val) {
+        current->tss.fp_regs.fprs[rx].d = __extendsfdf2(val);
+}
+
+static void emu_ldebr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].d =
+        __extendsfdf2(current->tss.fp_regs.fprs[ry].f);
+}
+
+static void emu_ldxbr (int rx, int ry) {
+        printk("ldxbr emulation not implemented!\n");
+}
+
+static void emu_ledbr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].f = __truncdfsf2(current->tss.fp_regs.fprs[ry].d);
+        set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_lexbr (int rx, int ry) {
+        printk("lexbr emulation not implemented!\n");
+}
+
+static void emu_lndbr (int rx, int ry) {
+        printk("lndbr emulation not implemented!\n");
+}
+
+static void emu_lnebr (int rx, int ry) {
+        printk("lnebr emulation not implemented!\n");
+}
+
+static void emu_lnxbr (int rx, int ry) {
+        printk("lnxbr emulation not implemented!\n");
+}
+
+static void emu_lpdbr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].d = __absdf2(current->tss.fp_regs.fprs[ry].d);
+        set_CC_df(current->tss.fp_regs.fprs[rx].d,0);
+}
+
+static void emu_lpebr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].f = __abssf2(current->tss.fp_regs.fprs[ry].f);
+        set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_lpxbr (int rx, int ry) {
+        printk("lpxbr emulation not implemented!\n");
+}
+
+static void emu_ltdbr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].d = current->tss.fp_regs.fprs[ry].d;
+        set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_ltebr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].f = current->tss.fp_regs.fprs[ry].f;
+        set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_ltxbr (int rx, int ry) {
+        printk("ltxbr emulation not implemented!\n");
+}
+
+static void emu_lxdb (int rx, __u64 val) {
+        printk("lxdb emulation not implemented!\n");
+}
+
+static void emu_lxdbr (int rx, int ry) {
+        printk("lxdbr emulation not implemented!\n");
+}
+
+static void emu_lxeb (int rx, __u32 val) {
+        printk("lxeb emulation not implemented!\n");
+}
+
+static void emu_lxebr (int rx, int ry) {
+        printk("lxebr emulation not implemented!\n");
+}
+
+static void emu_madb (int rx, __u64 val, int mask) {
+        printk("madb emulation not implemented!\n");
+}
+
+static void emu_madbr (int rx, int ry, int mask) {
+        printk(" emulation not implemented!\n");
+}
+
+static void emu_maeb (int rx, __u32 val, int mask) {
+        printk("maeb emulation not implemented!\n");
+}
+
+static void emu_maebr (int rx, int ry, int mask) {
+        printk("maebr emulation not implemented!\n");
+}
+
+static void emu_mdb (int rx, __u64 val) {
+        current->tss.fp_regs.fprs[rx].d = __muldf3(current->tss.fp_regs.fprs[rx].d,val);
+        set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_mdbr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].d = __muldf3(current->tss.fp_regs.fprs[rx].d,
+                                         current->tss.fp_regs.fprs[ry].d);
+        set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_mdeb (int rx, __u32 val) {
+        printk("mdeb emulation not implemented!\n");
+}
+
+static void emu_mdebr (int rx, int ry) {
+        printk("mdebr emulation not implemented!\n");
+}
+
+static void emu_meeb (int rx, __u32 val) {
+        current->tss.fp_regs.fprs[rx].f = __mulsf3(current->tss.fp_regs.fprs[rx].f,
+                                         val);
+        set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_meebr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].f = __mulsf3(current->tss.fp_regs.fprs[rx].f,
+                                         current->tss.fp_regs.fprs[ry].f);
+        set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_msdb (int rx, __u64 val, int mask) {
+        printk("msdb emulation not implemented!\n");
+}
+
+static void emu_msdbr (int rx, int ry, int mask) {
+        printk("msdbr emulation not implemented!\n");
+}
+
+static void emu_mseb (int rx, __u32 val, int mask) {
+        printk("mseb emulation not implemented!\n");
+}
+
+static void emu_msebr (int rx, int ry, int mask) {
+        printk("msebr emulation not implemented!\n");
+}
+
+static void emu_mxbr (int rx, int ry) {
+        printk("mxbr emulation not implemented!\n");
+}
+
+static void emu_mxdb (int rx, __u64 val) {
+        printk("mxdb emulation not implemented!\n");
+}
+
+static void emu_mxdbr (int rx, int ry) {
+        printk("mxdbr emulation not implemented!\n");
+}
+
+static void emu_sdb (int rx, __u64 val) {
+        current->tss.fp_regs.fprs[rx].d = __subdf3(current->tss.fp_regs.fprs[rx].d,
+                                         val);
+        set_CC_sf(current->tss.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_sdbr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].d = __subdf3(current->tss.fp_regs.fprs[rx].d,
+                                         current->tss.fp_regs.fprs[ry].d);
+        set_CC_sf(current->tss.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_seb (int rx, __u32 val) {
+        current->tss.fp_regs.fprs[rx].f = __subsf3(current->tss.fp_regs.fprs[rx].f,
+                                         val);
+        set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_sebr (int rx, int ry) {
+        current->tss.fp_regs.fprs[rx].f = __subsf3(current->tss.fp_regs.fprs[rx].f,
+                                         current->tss.fp_regs.fprs[ry].f);
+        set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_sfpc (int rx, int ry) {
+        printk("sfpc emulation not implemented!\n");
+}
+
+static void emu_sqdb (int rx, __u64 val) {
+        printk("sqdb emulation not implemented!\n");
+}
+
+static void emu_sqdbr (int rx, int ry) {
+        printk("sqdbr emulation not implemented!\n");
+}
+
+static void emu_sqeb (int rx, __u32 val) {
+        printk("sqeb emulation not implemented!\n");
+}
+
+static void emu_sqebr (int rx, int ry) {
+        printk("sqebr emulation not implemented!\n");
+}
+
+static void emu_sqxbr (int rx, int ry) {
+        printk("sqxbr emulation not implemented!\n");
+}
+
+static void emu_sxbr (int rx, int ry) {
+        printk("sxbr emulation not implemented!\n");
+}
+
+static void emu_tcdb (int rx, __u64 val) {
+        printk("tcdb emulation not implemented!\n");
+}
+
+static void emu_tceb (int rx, __u32 val) {
+        printk("tceb emulation not implemented!\n");
+}
+
+static void emu_tcxb (int rx, __u64 val) {
+        printk("tcxb emulation not implemented!\n");
+}
+
+
+static inline void emu_load_regd(int reg) {
+        if ((reg&9) == 0) {                /* test if reg in {0,2,4,6} */
+                __asm__ __volatile (       /* load reg from fp_regs.fprs[reg] */
+                        "     bras  1,0f\n"
+                        "     ld    0,0(%1)\n"
+                        "0:   ex    %0,0(1)"
+                        : /* no output */
+                        : "a" (reg<<4), "a" (&current->tss.fp_regs.fprs[reg].d)
+                        : "1" );
+        }
+}
+
+static inline void emu_load_rege(int reg) {
+        if ((reg&9) == 0) {                /* test if reg in {0,2,4,6} */
+                __asm__ __volatile (       /* load reg from fp_regs.fprs[reg] */
+                        "     bras  1,0f\n"
+                        "     le    0,0(%1)\n"
+                        "0:   ex    %0,0(1)"
+                        : /* no output */
+                        : "a" (reg<<4), "a" (&current->tss.fp_regs.fprs[reg].f)
+                        : "1" );
+        }
+}
+
+static inline void emu_store_regd(int reg) {
+        if ((reg&9) == 0) {                /* test if reg in {0,2,4,6} */
+                __asm__ __volatile (       /* store reg to fp_regs.fprs[reg] */
+                        "     bras  1,0f\n"
+                        "     std   0,0(%1)\n"
+                        "0:   ex    %0,0(1)"
+                        : /* no output */
+                        : "a" (reg<<4), "a" (&current->tss.fp_regs.fprs[reg].d)
+                        : "1" );
+        }
+}
+
+
+static inline void emu_store_rege(int reg) {
+        if ((reg&9) == 0) {                /* test if reg in {0,2,4,6} */
+                __asm__ __volatile (       /* store reg to fp_regs.fprs[reg] */
+                        "     bras  1,0f\n"
+                        "     ste   0,0(%1)\n"
+                        "0:   ex    %0,0(1)"
+                        : /* no output */
+                        : "a" (reg<<4), "a" (&current->tss.fp_regs.fprs[reg].f)
+                        : "1" );
+        }
+}
+
+int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
+        static const __u8 format_table[] = {
+                2, 2, 2, 2, 9, 1, 2, 1, 2, 2, 2, 2, 9, 2, 4, 4,
+                1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 3,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                1, 1, 1, 1,10, 1, 1, 3, 1, 1, 1, 1, 1, 1, 0, 0,
+                0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 3, 0, 0, 0, 3,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+                0, 0, 0, 0, 5, 6, 6, 0, 7, 8, 8, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        };
+        static const void *jump_table[]= {
+                emu_lpebr, emu_lnebr, emu_ltebr, emu_lcebr,
+                emu_ldebr, emu_lxdbr, emu_lxebr, emu_mxdbr,
+                emu_kebr,  emu_cebr,  emu_aebr,  emu_sebr,
+                emu_mdebr, emu_debr,  emu_maebr, emu_msebr,
+                emu_lpdbr, emu_lndbr, emu_ltdbr, emu_lcdbr,
+                emu_sqebr, emu_sqdbr, emu_sqxbr, emu_meebr,
+                emu_kdbr,  emu_cdbr,  emu_adbr,  emu_sdbr,
+                emu_mdbr,  emu_ddbr,  emu_madbr, emu_msdbr,
+                NULL,      NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                emu_lpxbr, emu_lnxbr, emu_ltxbr, emu_lcxbr,
+                emu_ledbr, emu_ldxbr, emu_lexbr, emu_fixbr,
+                emu_kxbr,  emu_cxbr,  emu_axbr,  emu_sxbr,
+                emu_mxbr,  emu_dxbr,  NULL,      NULL,
+                NULL,      NULL,      NULL,      emu_diebr,
+                NULL,      NULL,      NULL,      emu_fiebr,
+                NULL,      NULL,      NULL,      emu_didbr,
+                NULL,      NULL,      NULL,      emu_fidbr,
+                NULL,      NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                emu_sfpc,  NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                emu_efpc,  NULL,      NULL,      NULL,
+                NULL,      NULL,      NULL,      NULL,
+                emu_cefbr, emu_cdfbr, emu_cxfbr, NULL,
+                emu_cfebr, emu_cfdbr, emu_cfxbr
+        };
+
+        switch (format_table[opcode[1]]) {
+        case 1: /* RRE format, double operation */
+                emu_store_regd((opcode[3]>>4)&15);
+                emu_store_regd(opcode[3]&15);
+                /* call the emulation function */
+                ((void (*)(int, int))jump_table[opcode[1]])
+                        (opcode[3]>>4,opcode[3]&15);
+                emu_load_regd((opcode[3]>>4)&15);
+                emu_load_regd(opcode[3]&15);
+                return 0;
+        case 2: /* RRE format, float operation */
+                emu_store_rege((opcode[3]>>4)&15);
+                emu_store_rege(opcode[3]&15);
+                /* call the emulation function */
+                ((void (*)(int, int))jump_table[opcode[1]])
+                        (opcode[3]>>4,opcode[3]&15);
+                emu_load_rege((opcode[3]>>4)&15);
+                emu_load_rege(opcode[3]&15);
+                return 0;
+        case 3: /* RRF format, double operation */
+                emu_store_regd((opcode[3]>>4)&15);
+                emu_store_regd(opcode[3]&15);
+                /* call the emulation function */
+                ((void (*)(int, int, int))jump_table[opcode[1]])
+                        (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
+                emu_load_regd((opcode[3]>>4)&15);
+                emu_load_regd(opcode[3]&15);
+                return 0;
+        case 4: /* RRF format, float operation */
+                emu_store_rege((opcode[3]>>4)&15);
+                emu_store_rege(opcode[3]&15);
+                /* call the emulation function */
+                ((void (*)(int, int, int))jump_table[opcode[1]])
+                        (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
+                emu_load_rege((opcode[3]>>4)&15);
+                emu_load_rege(opcode[3]&15);
+                return 0;
+        case 5: /* RRE format, cefbr instruction */
+                emu_store_rege((opcode[3]>>4)&15);
+                /* call the emulation function */
+                ((void (*)(int, int))jump_table[opcode[1]])
+                        (opcode[3]>>4,opcode[3]&15);
+                emu_load_rege((opcode[3]>>4)&15);
+                return 0;
+        case 6: /* RRE format, cdfbr & cxfbr instruction */
+                emu_store_regd((opcode[3]>>4)&15);
+                /* call the emulation function */
+                ((void (*)(int, int))jump_table[opcode[1]])
+                        (opcode[3]>>4,opcode[3]&15);
+                emu_load_regd((opcode[3]>>4)&15);
+                return 0;
+                /* FIXME !! */
+                return 0;
+        case 7: /* RRF format, cfebr instruction */
+                emu_store_rege(opcode[3]&15);
+                /* call the emulation function */
+                ((void (*)(int, int, int))jump_table[opcode[1]])
+                        (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
+                return 0;
+        case 8: /* RRF format, cfdbr & cfxbr instruction */
+                emu_store_regd(opcode[3]&15);
+                /* call the emulation function */
+                ((void (*)(int, int, int))jump_table[opcode[1]])
+                        (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
+                return 0;
+	case 9: /* RRE format, ldebr & mdebr instruction */
+		/* float store but double load */
+                emu_store_rege((opcode[3]>>4)&15);
+                emu_store_rege(opcode[3]&15);
+                /* call the emulation function */
+                ((void (*)(int, int))jump_table[opcode[1]])
+                        (opcode[3]>>4,opcode[3]&15);
+                emu_load_regd((opcode[3]>>4)&15);
+                return 0;
+        case 10: /* RRE format, ledbr instruction */
+		/* double store but float load */
+                emu_store_regd((opcode[3]>>4)&15);
+                emu_store_regd(opcode[3]&15);
+                /* call the emulation function */
+                ((void (*)(int, int))jump_table[opcode[1]])
+                        (opcode[3]>>4,opcode[3]&15);
+                emu_load_rege((opcode[3]>>4)&15);
+                return 0;
+        default:
+                return 1;
+        }
+}
+
+static void* calc_addr(struct pt_regs *regs,int rx,int rb,int disp)
+{
+  rx &= 0xf;
+  rb &= 0xf;
+  disp &= 0xfff;
+  return (void*) ((rx != 0 ? regs->gprs[rx] : 0)  + /* index */   
+         (rb != 0 ? regs->gprs[rb] : 0)  + /* base */
+         disp);
+}
+    
+int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
+        static const __u8 format_table[] = {
+                0, 0, 0, 0, 5, 1, 2, 1, 2, 2, 2, 2, 5, 2, 4, 4,
+                2, 1, 1, 0, 2, 1, 0, 2, 1, 1, 1, 1, 1, 1, 3, 3,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        };
+        static const void *jump_table[]= {
+                NULL,     NULL,     NULL,     NULL,
+                emu_ldeb, emu_lxdb, emu_lxeb, emu_mxdb,
+                emu_keb,  emu_ceb,  emu_aeb,  emu_seb,
+                emu_mdeb, emu_deb,  emu_maeb, emu_mseb,
+                emu_tceb, emu_tcdb, emu_tcxb, NULL,
+                emu_sqeb, emu_sqdb, NULL,     emu_meeb,
+                emu_kdb,  emu_cdb,  emu_adb,  emu_sdb,
+                emu_mdb,  emu_ddb,  emu_madb, emu_msdb
+        };
+
+        switch (format_table[opcode[5]]) {
+        case 1: /* RXE format, __u64 constant */ {
+                __u64 *dxb, temp;
+                __u32 opc;
+
+                emu_store_regd((opcode[1]>>4)&15);
+                opc = *((__u32 *) opcode);
+                dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
+                /* FIXME: how to react if copy_from_user fails ? */
+                copy_from_user(&temp, dxb, 8);
+                /* call the emulation function */
+                ((void (*)(int, __u64))jump_table[opcode[5]])
+                        (opcode[1]>>4,temp);
+                emu_load_regd((opcode[1]>>4)&15);
+                return 0;
+        }
+        case 2: /* RXE format, __u32 constant */ {
+                __u32 *dxb, temp;
+                __u32 opc;
+
+                emu_store_rege((opcode[1]>>4)&15);
+                opc = *((__u32 *) opcode);
+                dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
+                /* FIXME: how to react if get_user fails ? */
+                get_user(temp, dxb);
+                /* call the emulation function */
+                ((void (*)(int, __u32))jump_table[opcode[5]])
+                        (opcode[1]>>4,temp);
+                emu_load_rege((opcode[1]>>4)&15);
+                return 0;
+        }
+        case 3: /* RXF format, __u64 constant */ {
+                __u32 *dxb, temp;
+                __u32 opc;
+
+                emu_store_regd((opcode[1]>>4)&15);
+                opc = *((__u32 *) opcode);
+                dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
+                /* FIXME: how to react if copy_from_user fails ? */
+                copy_from_user(&temp, dxb, 8);
+                /* call the emulation function */
+                ((void (*)(int, __u32, int))jump_table[opcode[5]])
+                        (opcode[1]>>4,temp,opcode[4]>>4);
+                emu_load_regd((opcode[1]>>4)&15);
+                return 0;
+        }
+        case 4: /* RXF format, __u32 constant */ {
+                __u32 *dxb, temp;
+                __u32 opc;
+
+                emu_store_rege((opcode[1]>>4)&15);
+                opc = *((__u32 *) opcode);
+                dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
+                /* FIXME: how to react if get_user fails ? */
+                get_user(temp, dxb);
+                /* call the emulation function */
+                ((void (*)(int, __u32, int))jump_table[opcode[5]])
+                        (opcode[1]>>4,temp,opcode[4]>>4);
+                emu_load_rege((opcode[1]>>4)&15);
+                return 0;
+        }
+	case 5: /* RXE format, __u32 constant */
+                /* store_rege and load_regd */ 
+		{
+                __u32 *dxb, temp;
+                __u32 opc;
+                emu_store_rege((opcode[1]>>4)&15);
+                opc = *((__u32 *) opcode);
+                dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
+                /* FIXME: how to react if get_user fails ? */
+                get_user(temp, dxb);
+                /* call the emulation function */
+                ((void (*)(int, __u32))jump_table[opcode[5]])
+                        (opcode[1]>>4,temp);
+                emu_load_regd((opcode[1]>>4)&15);
+                return 0;
+        }
+        default:
+                return 1;
+        }
+}
+
+/*
+ * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
+ */
+void math_emu_ldr(__u8 *opcode) {
+        __u16 opc = *((__u16 *) opcode);
+
+        if ((opc & 0x0090) == 0) {         /* test if rx in {0,2,4,6} */
+                /* we got an exception therfore ry can't be in {0,2,4,6} */
+                __asm__ __volatile (       /* load rx from fp_regs.fprs[ry] */
+                        "     bras  1,0f\n"
+                        "     ld    0,0(%1)\n"
+                        "0:   ex    %0,0(1)"
+                        : /* no output */
+                        : "a" (opc&0x00f0),
+                          "a" (&current->tss.fp_regs.fprs[opc&0x000f].d)
+                        : "1" );
+        } else if ((opc & 0x0009) == 0) {  /* test if ry in {0,2,4,6} */
+                __asm__ __volatile (       /* store ry to fp_regs.fprs[rx] */
+                        "     bras  1,0f\n"
+                        "     std   0,0(%1)\n"
+                        "0:   ex    %0,0(1)"
+                        : /* no output */
+                        : "a" ((opc&0x000f)<<4),
+                          "a" (&current->tss.fp_regs.fprs[(opc&0x00f0)>>4].d)
+                        : "1" );
+        } else {                          /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
+                current->tss.fp_regs.fprs[(opc&0x00f0)>>4] =
+                        current->tss.fp_regs.fprs[opc&0x000f];
+        }
+}
+
+/*
+ * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
+ */
+void math_emu_ler(__u8 *opcode) {
+        __u16 opc = *((__u16 *) opcode);
+
+        if ((opc & 0x0090) == 0) {         /* test if rx in {0,2,4,6} */
+                /* we got an exception therfore ry can't be in {0,2,4,6} */
+                __asm__ __volatile (       /* load rx from fp_regs.fprs[ry] */
+                        "     bras  1,0f\n"
+                        "     le    0,0(%1)\n"
+                        "0:   ex    %0,0(1)"
+                        : /* no output */
+                        : "a" (opc&0x00f0),
+                          "a" (&current->tss.fp_regs.fprs[opc&0x000f].f)
+                        : "1" );
+        } else if ((opc & 0x0009) == 0) {  /* test if ry in {0,2,4,6} */
+                __asm__ __volatile (       /* store ry to fp_regs.fprs[rx] */
+                        "     bras  1,0f\n"
+                        "     ste   0,0(%1)\n"
+                        "0:   ex    %0,0(1)"
+                        : /* no output */
+                        : "a" ((opc&0x000f)<<4),
+                          "a" (&current->tss.fp_regs.fprs[(opc&0x00f0)>>4].f)
+                        : "1" );
+        } else {                          /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
+                current->tss.fp_regs.fprs[(opc&0x00f0)>>4] =
+                        current->tss.fp_regs.fprs[opc&0x000f];
+        }
+}
+
+/*
+ * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6}
+ */
+void math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
+        __u32 opc = *((__u32 *) opcode);
+        __u64 *dxb;
+
+        dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
+        /* FIXME: how to react if copy_from_user fails ? */
+        copy_from_user(&current->tss.fp_regs.fprs[(opc>>20)&15].d, dxb, 8);
+}
+
+/*
+ * Emulate LE R,D(X,B) with R not in {0, 2, 4, 6}
+ */
+void math_emu_le(__u8 *opcode, struct pt_regs * regs) {
+        __u32 opc = *((__u32 *) opcode);
+        __u32 *mem, *dxb;
+
+        dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
+        /* FIXME: how to react if get_user fails ? */
+        mem = (__u32 *) (&current->tss.fp_regs.fprs[(opc>>20)&15].f);
+        get_user(mem[0], dxb);
+}
+
+/*
+ * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6}
+ */
+void math_emu_std(__u8 *opcode, struct pt_regs * regs) {
+        __u32 opc = *((__u32 *) opcode);
+        __u64 *dxb;
+        dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
+        /* FIXME: how to react if copy_to_user fails ? */
+        copy_to_user(dxb, &current->tss.fp_regs.fprs[(opc>>20)&15].d, 8);
+}
+
+/*
+ * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6}
+ */
+void math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
+        __u32 opc = *((__u32 *) opcode);
+        __u32 *mem, *dxb;
+        dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
+        /* FIXME: how to react if put_user fails ? */
+        mem = (__u32 *) (&current->tss.fp_regs.fprs[(opc>>20)&15].f);
+        put_user(mem[0], dxb);
+}
+
+/*
+ * Emulate LFPC D(B)
+ */
+int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) {
+        /* FIXME: how to do that ?!? */
+        return 0;
+}
+
+/*
+ * Emulate STFPC D(B)
+ */
+int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) {
+        /* FIXME: how to do that ?!? */
+        return 0;
+}
+
+/*
+ * Emulate SRNM D(B)
+ */
+int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) {
+        /* FIXME: how to do that ?!? */
+        return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/process.c linux.14p16/arch/s390/kernel/process.c
--- linux.vanilla/arch/s390/kernel/process.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/process.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,415 @@
+/*
+ *  arch/s390/kernel/process.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *               Hartmut Penner (hp@de.ibm.com),
+ *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *
+ *  Derived from "arch/i386/kernel/process.c"
+ *    Copyright (C) 1995, Linus Torvalds
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#define __KERNEL_SYSCALLS__
+#include <stdarg.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/unistd.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/misc390.h>
+#include "irq.h"
+
+spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED;
+
+asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
+
+/*
+ * The idle loop on a S390...
+ */
+
+static psw_t wait_psw;
+
+#ifndef __SMP__
+static
+#endif
+int cpu_idle(void *unused)
+{
+	/* endless idle loop with no priority at all */
+        init_idle();
+	current->priority = 0;
+	current->counter = -100;
+	wait_psw.mask = _WAIT_PSW_MASK;
+	wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L;
+	while(1) {
+                if (bh_mask & bh_active) {
+                        do_bottom_half();
+                        continue;
+                }
+                if (current->need_resched) {
+                        schedule();
+                        check_pgt_cache();
+                        continue;
+                }
+
+		/* load wait psw */
+		asm volatile (
+                        "lpsw %0"
+                        : : "m" (wait_psw) );
+idle_wakeup:
+	}
+}
+
+asmlinkage int sys_idle(void)
+{
+	if (current->pid != 0)
+		return -EPERM;
+	cpu_idle(NULL);
+	return 0;
+}
+
+/*
+  As all the register will only be made displayable to the root
+  user ( via printk ) or checking if the uid of the user is 0 from
+  the /proc filesystem please god this will be secure enough DJB.
+  The lines are given one at a time so as not to chew stack space in
+  printk on a crash & also for the proc filesystem when you get
+  0 returned you know you've got all the lines
+ */
+
+int sprintf_regs(int line,char *buff,struct task_struct * task,struct thread_struct *tss,struct pt_regs * regs)
+{	
+	int linelen=0;
+	int regno,chaincnt;
+	u32 backchain,prev_backchain,endchain;
+
+	enum
+	{
+		sp_linefeed,
+		sp_psw,
+		sp_ksp,
+		sp_gprs,
+		sp_gprs1,
+		sp_gprs2,
+		sp_gprs3,
+		sp_gprs4,
+		sp_acrs,
+		sp_acrs1,
+		sp_acrs2,
+		sp_acrs3,
+		sp_acrs4,
+		sp_kern_backchain,
+		sp_kern_backchain1
+	};
+
+	if(task)
+		tss=&task->tss;
+	if(tss)
+		regs=tss->regs;
+	switch(line)
+	{
+	case sp_linefeed: linelen=sprintf(buff,"\n");
+		break;
+	case sp_psw:
+		if(regs)
+			linelen=sprintf(buff,"User PSW:    %08lx %08lx\n",
+				(unsigned long) regs->psw.mask,
+				(unsigned long) regs->psw.addr);
+		else
+			linelen=sprintf(buff,"pt_regs=NULL some info unavailable\n");
+		break;
+	case sp_ksp:
+		if(task)
+			linelen+=sprintf(&buff[linelen],"task: %08x ",(addr_t)task);
+		if(tss)
+			linelen+=sprintf(&buff[linelen],"tss: %08x ksp: %08x ",
+					 (addr_t)tss,(addr_t)tss->ksp);
+		if(regs)
+			linelen+=sprintf(&buff[linelen],"pt_regs: %08x\n",(addr_t)regs);
+		break;
+	case sp_gprs:
+		if(regs)
+			linelen=sprintf(buff,"User GPRS:\n");
+		break;
+	case sp_gprs1 ... sp_gprs4:
+		if(regs)
+		{
+			regno=(line-sp_gprs1)*4;
+			linelen=sprintf(buff,"%08x  %08x  %08x  %08x\n",
+			       regs->gprs[regno], regs->gprs[regno+1],
+			       regs->gprs[regno+2], regs->gprs[regno+3]);
+		}
+		break;
+	case sp_acrs:
+		if(regs)
+			linelen=sprintf(buff,"User ACRS:\n");
+		break;	
+        case sp_acrs1 ... sp_acrs4:
+		if(regs)
+		{
+			regno=(line-sp_acrs1)*4;
+			linelen=sprintf(buff,"%08x  %08x  %08x  %08x\n",
+					regs->acrs[regno], regs->acrs[regno+1],
+					regs->acrs[regno+2], regs->acrs[regno+3]);
+		}
+		break;
+	case sp_kern_backchain:
+		if(tss&&tss->ksp&&regs)
+			linelen=sprintf(buff,"Kernel BackChain  CallChain    BackChain  CallChain\n");
+		break;
+	default:
+		if(tss&&tss->ksp&&regs)
+		{
+			
+			backchain=(tss->ksp&PSW_ADDR_MASK);
+			endchain=((backchain&(-8192))+8192);
+			prev_backchain=backchain-1;
+			line-=sp_kern_backchain1;
+			for(chaincnt=0;;chaincnt++)
+			{
+				if((backchain==0)||(backchain>=endchain)
+				   ||(chaincnt>=8)||(prev_backchain>=backchain))
+					break;
+				if((chaincnt>>1)==line)
+				{
+					linelen+=sprintf(&buff[linelen],"%s%08x   %08x     ",
+							 (chaincnt&1) ? "":"       ",
+							 backchain,*(u32 *)(backchain+56));
+				}
+				if((chaincnt>>1)>line)
+					break;
+				prev_backchain=backchain;
+				backchain=(*((u32 *)backchain))&PSW_ADDR_MASK;
+			}
+			if(linelen)
+				linelen+=sprintf(&buff[linelen],"\n");
+		}
+	}
+	return(linelen);
+}
+
+
+void show_regs(struct task_struct * task,struct thread_struct *tss,struct pt_regs *regs)
+{
+	char buff[80];
+	int line;
+	
+	for(line=0;sprintf_regs(line,buff,task,tss,regs);line++)
+		printk(buff);
+}
+
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+        int clone_arg = flags | CLONE_VM;
+        int retval;
+
+        __asm__ __volatile__(
+                "     sr    2,2\n"
+                "     lr    3,%1\n"
+                "     l     4,%6\n"     /* load kernel stack ptr of parent */
+                "     svc   %b2\n"                     /* Linux system call*/
+                "     cl    4,%6\n"    /* compare ksp's: child or parent ? */
+                "     je    0f\n"                          /* parent - jump*/
+                "     l     15,%6\n"            /* fix kernel stack pointer*/
+                "     ahi   15,%7\n"
+                "     xc    0(96,15),0(15)\n"           /* clear save area */
+                "     lr    2,%4\n"                        /* load argument*/
+                "     lr    14,%5\n"                      /* get fn-pointer*/
+                "     basr  14,14\n"                             /* call fn*/
+                "     svc   %b3\n"                     /* Linux system call*/
+                "0:   lr    %0,2"
+                : "=a" (retval)
+                : "d" (clone_arg), "i" (__NR_clone), "i" (__NR_exit),
+                  "d" (arg), "d" (fn), "i" (__LC_KERNEL_STACK) , "i" (-STACK_FRAME_OVERHEAD)
+                : "2", "3", "4" );
+        return retval;
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+}
+
+void flush_thread(void)
+{
+
+        current->used_math = 0;
+        current->flags &= ~PF_USEDFPU;
+}
+
+void release_thread(struct task_struct *dead_task)
+{
+}
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
+        struct task_struct * p, struct pt_regs * regs)
+{
+        struct stack_frame
+          {
+            unsigned long back_chain;
+            unsigned long eos;
+            unsigned long glue1;
+            unsigned long glue2;
+            unsigned long scratch[2];
+            unsigned long gprs[10];    /* gprs 6 -15                       */
+            unsigned long fprs[4];     /* fpr 4 and 6                      */
+            unsigned long empty[4];
+            struct pt_regs childregs;
+          } *frame;
+
+        frame = (struct stack_frame *) (2*PAGE_SIZE + (unsigned long) p) -1;
+        frame = (struct stack_frame *) (((unsigned long) frame)&-8L);
+        p->tss.regs = &frame->childregs;
+        p->tss.ksp = (unsigned long) frame;
+        frame->childregs = *regs;
+        frame->childregs.gprs[15] = new_stackp;
+        frame->eos = 0;
+
+        /* new return point is ret_from_sys_call */
+        frame->gprs[8] = ((unsigned long) &ret_from_fork) | 0x80000000;
+
+        /* fake return stack for resume(), don't go back to schedule */
+        frame->gprs[9]  = (unsigned long) frame;
+
+        /* save fprs, if used in last task */
+	save_fp_regs(&p->tss.fp_regs);
+        p->tss.user_seg = __pa((unsigned long) p->mm->pgd) | _USER_SEG_TABLE_LEN;
+        p->tss.fs = USER_DS;
+        /* Don't copy debug registers */
+        memset(&p->tss.per_info,0,sizeof(p->tss.per_info));
+        return 0;
+}
+
+
+
+asmlinkage int sys_fork(struct pt_regs regs)
+{
+        int ret;
+
+        lock_kernel();
+        ret = do_fork(SIGCHLD, regs.gprs[15], &regs);
+        unlock_kernel();
+        return ret;
+}
+
+asmlinkage int sys_clone(struct pt_regs regs)
+{
+        unsigned long clone_flags;
+        unsigned long newsp;
+        int ret;
+
+        lock_kernel();
+        clone_flags = regs.gprs[3];
+        newsp = regs.gprs[2];
+        if (!newsp)
+                newsp = regs.gprs[15];
+        ret = do_fork(clone_flags, newsp, &regs);
+        unlock_kernel();
+        return ret;
+}
+
+/*
+ * This is trivial, and on the face of it looks like it
+ * could equally well be done in user mode.
+ *
+ * Not so, for quite unobvious reasons - register pressure.
+ * In user mode vfork() cannot have a stack frame, and if
+ * done by calling the "clone()" system call directly, you
+ * do not have enough call-clobbered registers to hold all
+ * the information you need.
+ */
+asmlinkage int sys_vfork(struct pt_regs regs)
+{
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
+                       regs.gprs[15], &regs);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(struct pt_regs regs)
+{
+        int error;
+        char * filename;
+
+        lock_kernel();
+        filename = getname((char *) regs.orig_gpr2);
+        error = PTR_ERR(filename);
+        if (IS_ERR(filename))
+                goto out;
+        error = do_execve(filename, (char **) regs.gprs[3], (char **) regs.gprs[4], &regs);
+	if (error == 0)
+		current->flags &= ~PF_DTRACE;
+        putname(filename);
+out:
+        unlock_kernel();
+        return error;
+}
+
+
+/*
+ * fill in the FPU structure for a core dump.
+ */
+int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs)
+{
+	save_fp_regs(fpregs);
+	return(TRUE);
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread(struct pt_regs * regs, struct user * dump)
+{
+
+/* changed the size calculations - should hopefully work better. lbt */
+	dump->magic = CMAGIC;
+	dump->start_code = 0;
+	dump->start_stack = regs->gprs[15] & ~(PAGE_SIZE - 1);
+	dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
+	dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
+	dump->u_dsize -= dump->u_tsize;
+	dump->u_ssize = 0;
+	if (dump->start_stack < TASK_SIZE)
+		dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
+	memcpy(&dump->regs.gprs[0],regs,sizeof(s390_regs));
+	dump_fpu (regs, &dump->regs.fp_regs);
+	memcpy(&dump->regs.per_info,&current->tss.per_info,sizeof(per_struct));
+}
+
+
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/ptrace.c linux.14p16/arch/s390/kernel/ptrace.c
--- linux.vanilla/arch/s390/kernel/ptrace.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/ptrace.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,605 @@
+/*
+ *  arch/s390/kernel/ptrace.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *
+ *  Based on PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Derived from "arch/m68k/kernel/ptrace.c"
+ *  Copyright (C) 1994 by Hamish Macdonald
+ *  Taken from linux/kernel/ptrace.c and modified for M680x0.
+ *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu) 
+ *
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file README.legal in the main directory of
+ * this archive for more details.
+ */
+
+#include <stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+
+void FixPerRegisters(struct task_struct *task)
+{
+	struct pt_regs *regs = task->tss.regs;
+	per_struct *per_info=
+			(per_struct *)&task->tss.per_info;
+
+	per_info->control_regs.bits.em_instruction_fetch=
+	per_info->single_step|per_info->instruction_fetch;
+	
+	if(per_info->single_step)
+	{
+		per_info->control_regs.bits.starting_addr=0;
+		per_info->control_regs.bits.ending_addr=0x7fffffffUL;
+	}
+	else
+	{
+		per_info->control_regs.bits.starting_addr=
+		per_info->starting_addr;
+		per_info->control_regs.bits.ending_addr=
+		per_info->ending_addr;
+	}
+	/* if any of the control reg tracing bits are on 
+	   we switch on per in the psw */
+	if(per_info->control_regs.words.cr[0]&PER_EM_MASK)
+		regs->psw.mask |=PSW_PER_MASK;
+	else
+		regs->psw.mask &= ~PSW_PER_MASK;
+	if(per_info->control_regs.bits.storage_alt_space_ctl)
+		task->tss.user_seg|=USER_STD_MASK;
+	else
+		task->tss.user_seg&=~USER_STD_MASK;
+}
+
+void set_single_step(struct task_struct *task)
+{
+	per_struct *per_info=
+			(per_struct *)&task->tss.per_info;	
+	
+	per_info->single_step=1;  /* Single step */
+	FixPerRegisters(task);
+}
+
+void clear_single_step(struct task_struct *task)
+{
+	per_struct *per_info=
+			(per_struct *)&task->tss.per_info;
+
+	per_info->single_step=0;
+	FixPerRegisters(task);
+}
+
+
+
+/*
+ * This routine gets a long from any process space by following the page
+ * tables. NOTE! You should check that the long isn't on a page boundary,
+ * and that it is in the task area before calling this: this routine does
+ * no checking.
+ *
+ */
+static unsigned long get_long(struct task_struct * tsk, 
+	struct vm_area_struct * vma, unsigned long addr)
+{
+	pgd_t * pgdir;
+	pmd_t * pgmiddle;
+	pte_t * pgtable;
+	unsigned long page;
+
+repeat:
+	pgdir = pgd_offset(vma->vm_mm, addr);
+	if (pgd_none(*pgdir)) {
+		handle_mm_fault(tsk, vma, addr, 0);
+		goto repeat;
+	}
+	if (pgd_bad(*pgdir)) {
+		printk("ptrace[1]: bad page directory %lx\n", pgd_val(*pgdir));
+		pgd_clear(pgdir);
+		return 0;
+	}
+	pgmiddle = pmd_offset(pgdir,addr);
+	if (pmd_none(*pgmiddle)) {
+		handle_mm_fault(tsk, vma, addr, 0);
+		goto repeat;
+	}
+	if (pmd_bad(*pgmiddle)) {
+		printk("ptrace[3]: bad pmd %lx\n", pmd_val(*pgmiddle));
+		pmd_clear(pgmiddle);
+		return 0;
+	}
+	pgtable = pte_offset(pgmiddle, addr);
+	if (!pte_present(*pgtable)) {
+		handle_mm_fault(tsk, vma, addr, 0);
+		goto repeat;
+	}
+	page = pte_page(*pgtable);
+/* this is a hack for non-kernel-mapped video buffers and similar */
+	if (MAP_NR(page) >= max_mapnr)
+		return 0;
+	page += addr & ~PAGE_MASK;
+	return *(unsigned long *) page;
+}
+
+/*
+ * This routine puts a long into any process space by following the page
+ * tables. NOTE! You should check that the long isn't on a page boundary,
+ * and that it is in the task area before calling this: this routine does
+ * no checking.
+ *
+ * Now keeps R/W state of page so that a text page stays readonly
+ * even if a debugger scribbles breakpoints into it.  -M.U-
+ */
+static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
+		     unsigned long addr, unsigned long data)
+{
+	pgd_t *pgdir;
+	pmd_t *pgmiddle;
+	pte_t *pgtable;
+	unsigned long page;
+		
+repeat:
+	pgdir = pgd_offset(vma->vm_mm, addr);
+	if (!pgd_present(*pgdir)) {
+		handle_mm_fault(tsk, vma, addr, 1);
+		goto repeat;
+	}
+	if (pgd_bad(*pgdir)) {
+		printk("ptrace[2]: bad page directory %lx\n", pgd_val(*pgdir));
+		pgd_clear(pgdir);
+		return;
+	}
+	pgmiddle = pmd_offset(pgdir,addr);
+	if (pmd_none(*pgmiddle)) {
+		handle_mm_fault(tsk, vma, addr, 1);
+		goto repeat;
+	}
+	if (pmd_bad(*pgmiddle)) {
+		printk("ptrace[4]: bad pmd %lx\n", pmd_val(*pgmiddle));
+		pmd_clear(pgmiddle);
+		return;
+	}
+	pgtable = pte_offset(pgmiddle, addr);
+	if (!pte_present(*pgtable)) {
+		handle_mm_fault(tsk, vma, addr, 1);
+		goto repeat;
+	}
+	page = pte_page(*pgtable);
+	if (!pte_write(*pgtable)) {
+		handle_mm_fault(tsk, vma, addr, 1);
+		goto repeat;
+	}
+/* this is a hack for non-kernel-mapped video buffers and similar */
+	if (MAP_NR(page) < max_mapnr) {
+		unsigned long phys_addr = page + (addr & ~PAGE_MASK);
+		*(unsigned long *) phys_addr = data;
+		flush_icache_range(phys_addr, phys_addr+4);
+	}
+/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
+/* this should also re-instate whatever read-only mode there was before */
+	set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
+	flush_tlb_all();
+}
+
+static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
+{
+	struct vm_area_struct * vma;
+
+	addr &= PAGE_MASK;
+	vma = find_vma(tsk->mm,addr);
+	if (!vma)
+		return NULL;
+	if (vma->vm_start <= addr)
+		return vma;
+	if (!(vma->vm_flags & VM_GROWSDOWN))
+		return NULL;
+	if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
+		return NULL;
+	vma->vm_offset -= vma->vm_start - addr;
+	vma->vm_start = addr;
+	return vma;
+}
+
+/*
+ * This routine checks the page boundaries, and that the offset is
+ * within the task area. It then calls get_long() to read a long.
+ */
+static int read_long(struct task_struct * tsk, unsigned long addr,
+	unsigned long * result)
+{
+	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+
+	if (!vma)
+		return -EIO;
+	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
+		unsigned long low,high;
+		struct vm_area_struct * vma_low = vma;
+
+		if (addr + sizeof(long) >= vma->vm_end) {
+			vma_low = vma->vm_next;
+			if (!vma_low || vma_low->vm_start != vma->vm_end)
+				return -EIO;
+		}
+		high = get_long(tsk, vma,addr & ~(sizeof(long)-1));
+		low = get_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1));
+		switch (addr & (sizeof(long)-1)) {
+			case 3:
+				low >>= 8;
+				low |= high << 24;
+				break;
+			case 2:
+				low >>= 16;
+				low |= high << 16;
+				break;
+			case 1:
+				low >>= 24;
+				low |= high << 8;
+				break;
+		}
+		*result = low;
+	} else
+		*result = get_long(tsk, vma,addr);
+	return 0;
+}
+
+/*
+ * This routine checks the page boundaries, and that the offset is
+ * within the task area. It then calls put_long() to write a long.
+ */
+static int write_long(struct task_struct * tsk, unsigned long addr,
+	unsigned long data)
+{
+	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+
+	if (!vma)
+		return -EIO;
+	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
+		unsigned long low,high;
+		struct vm_area_struct * vma_low = vma;
+
+		if (addr + sizeof(long) >= vma->vm_end) {
+			vma_low = vma->vm_next;
+			if (!vma_low || vma_low->vm_start != vma->vm_end)
+				return -EIO;
+		}
+		high = get_long(tsk, vma,addr & ~(sizeof(long)-1));
+		low = get_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1));
+		switch (addr & (sizeof(long)-1)) {
+			case 0: /* shouldn't happen, but safety first */
+				high = data;
+				break;
+			case 3:
+				low &= 0x000000ff;
+				low |= data << 8;
+				high &= ~0xff;
+				high |= data >> 24;
+				break;
+			case 2:
+				low &= 0x0000ffff;
+				low |= data << 16;
+				high &= ~0xffff;
+				high |= data >> 16;
+				break;
+			case 1:
+				low &= 0x00ffffff;
+				low |= data << 24;
+				high &= ~0xffffff;
+				high |= data >> 8;
+				break;
+		}
+		put_long(tsk, vma,addr & ~(sizeof(long)-1),high);
+		put_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1),low);
+	} else
+		put_long(tsk, vma,addr,data);
+	return 0;
+}
+
+
+int ptrace_usercopy(addr_t realuseraddr,addr_t copyaddr,int len,int tofromuser,int writeuser,u32 mask)
+{
+	u32  tempuser;
+	int  retval=0;
+	
+	if(writeuser&&realuseraddr==(addr_t)NULL)
+		return(0);
+	if(mask!=0xffffffff)
+	{
+		tempuser=*((u32 *)realuseraddr);
+		if(!writeuser)
+		{
+			tempuser&=mask;
+			realuseraddr=(addr_t)&tempuser;
+		}
+	}
+	if(tofromuser)
+	{
+		if(writeuser)
+		{
+			retval=copy_from_user((void *)realuseraddr,(void *)copyaddr,len);
+		}
+		else
+		{
+			if(realuseraddr==(addr_t)NULL)
+				retval=(clear_user((void *)copyaddr,len)==-EFAULT ? -EIO:0);
+			else
+				retval=(copy_to_user((void *)copyaddr,(void *)realuseraddr,len)==-EFAULT ? -EIO:0);
+		}      
+	}
+	else
+	{
+		if(writeuser)
+			memcpy((void *)realuseraddr,(void *)copyaddr,len);
+		else
+			memcpy((void *)copyaddr,(void *)realuseraddr,len);
+	}
+	if(mask!=0xffffffff&&writeuser)
+			(*((u32 *)realuseraddr))=(((*((u32 *)realuseraddr))&mask)|(tempuser&~mask));
+	return(retval);
+}
+
+int copy_user(struct task_struct *task,saddr_t useraddr,addr_t copyaddr,int len,int tofromuser,int writingtouser)
+{
+	int copylen=0,copymax;
+	addr_t  realuseraddr;
+	saddr_t enduseraddr=useraddr+len;
+	
+	u32 mask;
+
+	if (useraddr < 0 || enduseraddr > sizeof(struct user)||
+	   (useraddr < PT_ENDREGS && (useraddr&3))||
+	   (enduseraddr < PT_ENDREGS && (enduseraddr&3)))
+		return (-EIO);
+	while(len>0)
+	{
+		mask=0xffffffff;
+		if(useraddr<PT_FPC)
+		{
+			realuseraddr=(addr_t)&(((u8 *)task->tss.regs)[useraddr]);
+			if(useraddr<PT_PSWMASK)
+			{
+				copymax=PT_PSWMASK;
+			}
+			else if(useraddr<(PT_PSWMASK+4))
+			{
+				copymax=(PT_PSWMASK+4);
+				if(writingtouser)
+					mask=PSW_MASK_DEBUGCHANGE;
+			}
+			else if(useraddr<(PT_PSWADDR+4))
+			{
+				copymax=PT_PSWADDR+4;
+				mask=PSW_ADDR_DEBUGCHANGE;
+			}
+			else
+				copymax=PT_FPC;
+			
+		}
+		else if(useraddr<(PT_FPR15_LO+4))
+		{
+			copymax=(PT_FPR15_LO+4);
+			realuseraddr=(addr_t)&(((u8 *)&task->tss.fp_regs)[useraddr-PT_FPC]);
+		}
+		else if(useraddr<sizeof(user_regs_struct))
+		{
+			copymax=sizeof(user_regs_struct);
+			realuseraddr=(addr_t)&(((u8 *)&task->tss.per_info)[useraddr-PT_CR_9]);
+		}
+		else 
+		{
+			copymax=sizeof(struct user);
+			realuseraddr=(addr_t)NULL;
+		}
+		copylen=copymax-useraddr;
+		copylen=(copylen>len ? len:copylen);
+		if(ptrace_usercopy(realuseraddr,copyaddr,copylen,tofromuser,writingtouser,mask))
+			return (-EIO);
+		copyaddr+=copylen;
+		len-=copylen;
+		useraddr+=copylen;
+	}
+	FixPerRegisters(task);
+	return(0);
+}
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	int ret = -EPERM;
+	unsigned long tmp;
+	ptrace_area   parea; 
+	lock_kernel();
+	if (request == PTRACE_TRACEME) 
+	{
+		/* are we already being traced? */
+		if (current->flags & PF_PTRACED)
+			goto out;
+		/* set the ptrace bit in the process flags. */
+		current->flags |= PF_PTRACED;
+		ret = 0;
+		goto out;
+	}
+	ret = -ESRCH;
+	if (!(child = find_task_by_pid(pid)))
+		goto out;
+	ret = -EPERM;
+	if (pid == 1)		/* you may not mess with init */
+		goto out;
+	if (request == PTRACE_ATTACH) 
+	{
+		if (child == current)
+			goto out;
+		if ((!child->dumpable ||
+		     (current->uid != child->euid) ||
+		     (current->uid != child->uid) ||
+		     (current->gid != child->egid) ||
+		     (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
+			goto out;
+		/* the same process cannot be attached many times */
+		if (child->flags & PF_PTRACED)
+			goto out;
+		child->flags |= PF_PTRACED;
+		if (child->p_pptr != current) 
+		{
+			REMOVE_LINKS(child);
+			child->p_pptr = current;
+			SET_LINKS(child);
+		}
+		send_sig(SIGSTOP, child, 1);
+		ret = 0;
+		goto out;
+	}
+	ret = -ESRCH;
+	// printk("child=%lX child->flags=%lX",child,child->flags);
+	if (!(child->flags & PF_PTRACED))
+		goto out;
+	if (child->state != TASK_STOPPED) 
+	{
+		if (request != PTRACE_KILL)
+			goto out;
+	}
+	if (child->p_pptr != current)
+		goto out;
+
+	switch (request) 
+	{
+		/* If I and D space are separate, these will need to be fixed. */
+	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+	case PTRACE_PEEKDATA: 
+		down(&child->mm->mmap_sem);
+		ret = read_long(child, addr, &tmp);
+		up(&child->mm->mmap_sem);
+		if (ret < 0)
+			break;
+		ret=put_user(tmp, (unsigned long *) data);
+		break;
+
+		/* read the word at location addr in the USER area. */
+	case PTRACE_PEEKUSR:
+		ret=copy_user(child,addr,data,sizeof(unsigned long),TRUE,FALSE);
+		break;
+
+		/* If I and D space are separate, this will have to be fixed. */
+	case PTRACE_POKETEXT: /* write the word at location addr. */
+	case PTRACE_POKEDATA:
+		down(&child->mm->mmap_sem);
+		ret = write_long(child,addr,data);
+		up(&child->mm->mmap_sem);
+		break;
+
+	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+		ret=copy_user(child,addr,(addr_t)&data,sizeof(unsigned long),FALSE,TRUE);
+		break;
+
+	case PTRACE_SYSCALL: 	/* continue and stop at next (return from) syscall */
+	case PTRACE_CONT: 	 /* restart after signal. */
+		ret = -EIO;
+		if ((unsigned long) data >= _NSIG)
+			break;
+		if (request == PTRACE_SYSCALL)
+			child->flags |= PF_TRACESYS;
+		else
+			child->flags &= ~PF_TRACESYS;
+		child->exit_code = data;
+		/* make sure the single step bit is not set. */
+		clear_single_step(child);
+		wake_up_process(child);
+		ret = 0;
+		break;
+
+/*
+ * make the child exit.  Best I can do is send it a sigkill. 
+ * perhaps it should be put in the status that it wants to 
+ * exit.
+ */
+	case PTRACE_KILL:
+		ret = 0;
+		if (child->state == TASK_ZOMBIE) /* already dead */
+			break;
+		child->exit_code = SIGKILL;
+		clear_single_step(child);
+		wake_up_process(child);
+		/* make sure the single step bit is not set. */
+		break;
+
+	case PTRACE_SINGLESTEP:  /* set the trap flag. */
+		ret = -EIO;
+		if ((unsigned long) data >= _NSIG)
+			break;
+		child->flags &= ~PF_TRACESYS;
+		child->exit_code = data;
+		set_single_step(child);
+		/* give it a chance to run. */
+		wake_up_process(child);
+		ret = 0;
+		break;
+
+	case PTRACE_DETACH:  /* detach a process that was attached. */
+		ret = -EIO;
+		if ((unsigned long) data >= _NSIG)
+			break;
+		child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+		wake_up_process(child);
+		child->exit_code = data;
+		REMOVE_LINKS(child);
+		child->p_pptr = child->p_opptr;
+		SET_LINKS(child);
+		/* make sure the single step bit is not set. */
+		clear_single_step(child);
+		ret = 0;
+		break;
+	case PTRACE_PEEKUSR_AREA:
+	case PTRACE_POKEUSR_AREA:
+		if((ret=copy_from_user(&parea,(void *)addr,sizeof(parea)))==0)  
+		   ret=copy_user(child,parea.kernel_addr,parea.process_addr,
+				 parea.len,TRUE,(request==PTRACE_POKEUSR_AREA));
+		break;
+	default:
+		ret = -EIO;
+		break;
+	}
+ out:
+	unlock_kernel();
+	return ret;
+}
+
+asmlinkage void syscall_trace(void)
+{
+	lock_kernel();
+	if ((current->flags & (PF_PTRACED|PF_TRACESYS))
+	    != (PF_PTRACED|PF_TRACESYS))
+		goto out;
+	current->exit_code = SIGTRAP;
+	current->state = TASK_STOPPED;
+	notify_parent(current, SIGCHLD);
+	schedule();
+	/*
+	 * this isn't the same as continuing with a signal, but it will do
+	 * for normal use.  strace only continues with a signal if the
+	 * stopping signal is not SIGTRAP.  -brl
+	 */
+	if (current->exit_code) {
+		send_sig(current->exit_code, current, 1);
+		current->exit_code = 0;
+	}
+ out:
+	unlock_kernel();
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/s390fpu.c linux.14p16/arch/s390/kernel/s390fpu.c
--- linux.vanilla/arch/s390/kernel/s390fpu.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/s390fpu.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,146 @@
+/*
+ *  arch/s390/kernel/s390fpu.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *
+ *  s390fpu.h functions for saving & restoring the fpu state.
+ *
+ *  I couldn't inline these as linux/sched.h included half the world
+ *  & was required to at the task structure.
+ *  & the functions were too complex to make macros from.
+ *  ( & as usual I didn't feel like debugging inline code ).
+ */
+
+#include <linux/sched.h>
+
+int save_fp_regs1(s390_fp_regs *fpregs)
+{
+	int has_ieee=MACHINE_HAS_IEEE;
+/*
+  I don't think we can use STE here as this would load
+  fp registers 0 & 2 into memory locations 0 & 1 etc. 
+ */	
+	asm volatile ("STD   0,8(%0)\n\t"
+		      "STD   2,24(%0)\n\t"
+		      "STD   4,40(%0)\n\t"
+		      "STD   6,56(%0)"
+                      : 
+		      : "a" (fpregs)
+		      : "memory"
+		);
+	if(has_ieee)
+	{
+		asm volatile ("STFPC 0(%0)\n\t"
+			      "STD   1,16(%0)\n\t"
+			      "STD   3,32(%0)\n\t"
+			      "STD   5,48(%0)\n\t"
+			      "STD   7,64(%0)\n\t"
+			      "STD   8,72(%0)\n\t"
+			      "STD   9,80(%0)\n\t"
+			      "STD   10,88(%0)\n\t"
+			      "STD   11,96(%0)\n\t"
+			      "STD   12,104(%0)\n\t"
+			      "STD   13,112(%0)\n\t"
+			      "STD   14,120(%0)\n\t"
+			      "STD   15,128(%0)\n\t"
+			      : 
+			      : "a" (fpregs)
+			      : "memory"
+			);
+	}
+	return(has_ieee);
+}
+
+
+void save_fp_regs(s390_fp_regs *fpregs)
+{
+#if CONFIG_IEEEFPU_EMULATION
+	s390_fp_regs *currentfprs;
+#endif
+#if CONFIG_IEEEFPU_EMULATION
+	if(!save_fp_regs1(fpregs))
+	{
+		currentfprs=&current->tss.fp_regs;
+		fpregs->fpc=currentfprs->fpc;
+		fpregs->fprs[1].d=currentfprs->fprs[1].d;
+		fpregs->fprs[3].d=currentfprs->fprs[3].d;
+		fpregs->fprs[5].d=currentfprs->fprs[5].d;
+		fpregs->fprs[7].d=currentfprs->fprs[7].d;
+		memcpy(&fpregs->fprs[8].d,&currentfprs->fprs[8].d,sizeof(freg_t)*8);
+	}
+#else
+	save_fp_regs1(fpregs);
+#endif
+}
+
+
+int restore_fp_regs1(s390_fp_regs *fpregs)
+{
+	int has_ieee=MACHINE_HAS_IEEE;
+
+	asm volatile ("LD   0,8(%0)\n\t"
+		      "LD   2,24(%0)\n\t"
+		      "LD   4,40(%0)\n\t"
+		      "LD   6,56(%0)"
+                      : 
+		      : "a" (fpregs)
+		      : "memory"
+		);
+	if(has_ieee)
+	{
+		asm volatile ("LFPC 0(%0)\n\t"
+			      "LD   1,16(%0)\n\t"
+			      "LD   3,32(%0)\n\t"
+			      "LD   5,48(%0)\n\t"
+			      "LD   7,64(%0)\n\t"
+			      "LD   8,72(%0)\n\t"
+			      "LD   9,80(%0)\n\t"
+			      "LD   10,88(%0)\n\t"
+			      "LD   11,96(%0)\n\t"
+			      "LD   12,104(%0)\n\t"
+			      "LD   13,112(%0)\n\t"
+			      "LD   14,120(%0)\n\t"
+			      "LD   15,128(%0)\n\t"
+			      : 
+			      : "a" (fpregs)
+			      : "memory"
+			);
+	}
+	return(has_ieee);
+}
+
+void restore_fp_regs(s390_fp_regs *fpregs)
+{
+#if CONFIG_IEEEFPU_EMULATION
+	s390_fp_regs *currentfprs;
+#endif
+
+#if CONFIG_IEEEFPU_EMULATION
+	if(!restore_fp_regs1(fpregs))
+	{
+		currentfprs=&current->tss.fp_regs;
+		currentfprs->fpc=fpregs->fpc;
+		currentfprs->fprs[1].d=fpregs->fprs[1].d;
+		currentfprs->fprs[3].d=fpregs->fprs[3].d;
+		currentfprs->fprs[5].d=fpregs->fprs[5].d;
+		currentfprs->fprs[7].d=fpregs->fprs[7].d;
+		memcpy(&currentfprs->fprs[8].d,&fpregs->fprs[8].d,sizeof(freg_t)*8);
+	}
+#else
+	restore_fp_regs1(fpregs);
+#endif
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/s390io.c linux.14p16/arch/s390/kernel/s390io.c
--- linux.vanilla/arch/s390/kernel/s390io.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/s390io.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,3386 @@
+/*
+ *  arch/s390/kernel/s390io.c
+ *   S/390 common I/O routines
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Ingo Adlung (adlung@de.ibm.com)
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/smp.h>
+#include <linux/tasks.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/smp.h>
+#include <asm/pgtable.h>
+#include <asm/delay.h>
+#include <asm/lowcore.h>
+
+#include "irq.h"
+#include "s390io.h"
+
+#undef CONFIG_DEBUG_IO    
+
+#define REIPL_DEVID_MAGIC 0x87654321
+
+struct irqaction  init_IRQ_action;
+unsigned int      highest_subchannel;
+senseid_t         senseid[NR_IRQS];
+schib_t           schiblock[NR_IRQS];
+ioinfo_t          ioinfo[NR_IRQS];
+spinlock_t        sync_isc;                 // synchronous irq processing lock
+psw_t             io_sync_wait;             // wait PSW for sync IO, prot. by sync_isc
+psw_t             io_new_psw;               // save I/O new PSW, prot. by sync_isc
+int               cons_dev          = -1;   // identify console device
+int               init_IRQ_complete = 0;
+
+extern struct hw_interrupt_type no_irq_type;
+
+static void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs);
+static int  s390_setup_irq(unsigned int irq, struct irqaction * new);
+static void s390_process_subchannels( void);
+static void s390_device_recognition( void);
+static int  s390_validate_subchannel( int irq);
+static int  s390_SenseID( int irq, senseid_t *sid);
+static int  s390_process_IRQ( unsigned int irq, unsigned int intparm);
+
+extern int do_none(unsigned int irq, int cpu, struct pt_regs * regs);
+extern int enable_none(unsigned int irq);
+extern int disable_none(unsigned int irq);
+extern void tod_wait(unsigned long usecs);
+
+asmlinkage void do_IRQ( struct pt_regs regs,
+                        unsigned int   irq,
+                        unsigned int   intparm );
+
+void s390_displayhex(char *str,void *ptr,s32 cnt);
+
+void s390_displayhex(char *str,void *ptr,s32 cnt)
+{
+	s32	cnt1,cnt2,maxcnt2;
+	u32	*currptr=(u32 *)ptr;
+
+	printk("\n%s\n",str);
+	for(cnt1=0;cnt1<cnt;cnt1+=16)
+	{
+		printk("%08X ",(u32)currptr);
+		maxcnt2=cnt-cnt1;
+		if(maxcnt2>16)
+			maxcnt2=16;
+		for(cnt2=0;cnt2<maxcnt2;cnt2+=4)
+			printk("%08X ",*currptr++);
+		printk("\n");
+	}
+}
+
+int s390_request_irq( unsigned int   irq,
+                      void           (*handler)(int, void *, struct pt_regs *),
+                      unsigned long  irqflags,
+                      const char    *devname,
+                      void          *dev_id)
+{
+	int               retval;
+	struct irqaction *action;
+
+	if (irq >= NR_IRQS)
+		return -EINVAL;
+
+	if ( !handler || !dev_id )
+		return -EINVAL;
+
+   /*
+    * during init_IRQ() processing we don't have memory
+    *  management yet, thus need to use a statically
+    *  allocated irqaction control block
+    */
+   if ( init_IRQ_complete )
+   {
+	   action = (struct irqaction *)
+		         kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+   }
+   else
+   {
+      action = &init_IRQ_action;
+
+   } /* endif */
+
+	if (!action)
+   {
+		return -ENOMEM;
+
+   } /* endif */
+
+	action->handler = handler;
+	action->flags   = irqflags;
+	action->mask    = 0;
+	action->name    = devname;
+	action->next    = NULL;
+	action->dev_id  = dev_id;
+
+	retval = s390_setup_irq(irq, action);
+
+	if ( retval && init_IRQ_complete )
+	{
+		kfree(action);
+
+	} /* endif */
+
+	return retval;
+}
+
+void s390_free_irq(unsigned int irq, void *dev_id)
+{
+	unsigned int flags;
+	int          ret;
+
+	unsigned int count = 0;
+
+	if ( irq >= NR_IRQS )
+	{
+		return;
+
+	} /* endif */
+
+	s390irq_spin_lock_irqsave(irq,flags);
+
+#ifdef  CONFIG_KERNEL_DEBUG
+	if ( irq != cons_dev )
+	{
+		printk("Trying to free IRQ%d\n",irq);
+
+	} /* endif */
+#endif
+
+	/*
+	 * disable the device and reset all IRQ info if
+	 *  the IRQ is actually owned by the handler ...
+	 */
+	if ( irq_desc[irq].action )
+	{
+		if ( irq_desc[irq].action->dev_id == dev_id ||
+		     dev_id == REIPL_DEVID_MAGIC )
+		{
+			ioinfo[irq].ui.flags.unready = 1; /* start deregister */
+
+			do
+         {
+				ret = irq_desc[irq].handler->disable(irq);
+
+				count++;
+
+				if ( count == 3 )
+				{
+					panic( "free_irq() - device busy, retry count exceeded\n");
+
+				} /* endif */
+
+			} while ( ret == -EBUSY );
+
+			if ( init_IRQ_complete )
+            kfree( irq_desc[irq].action );
+
+			irq_desc[irq].action           = NULL;
+			ioinfo[irq].ui.flags.ready     = 0;
+
+			irq_desc[irq].handler->enable  = &enable_none;
+			irq_desc[irq].handler->disable = &disable_none;
+
+			ioinfo[irq].ui.flags.unready   = 0; /* deregister ended */
+
+			s390irq_spin_unlock_irqrestore( irq, flags);
+		}
+		else
+		{
+			s390irq_spin_unlock_irqrestore( irq, flags);
+
+			printk("free_irq() : error, dev_id does not match !");
+
+		} /* endif */
+
+	}
+	else
+	{
+		s390irq_spin_unlock_irqrestore( irq, flags);
+
+		printk("free_irq() : error, no action block ... !");
+
+	} /* endif */
+
+}
+
+/*
+ * Generic enable/disable code
+ */
+int disable_irq(unsigned int irq)
+{
+	unsigned long flags;
+	int           ret;
+
+	s390irq_spin_lock_irqsave(irq, flags);
+
+	/*
+	 * At this point we may actually have a pending interrupt being active
+	 * on another CPU. So don't touch the IRQ_INPROGRESS bit..
+	 */
+	irq_desc[irq].status |= IRQ_DISABLED;
+	ret = irq_desc[irq].handler->disable(irq);
+	s390irq_spin_unlock_irqrestore(irq, flags);
+
+	synchronize_irq();
+
+	return( ret);
+}
+
+int enable_irq(unsigned int irq)
+{
+	unsigned long flags;
+	int           ret;
+
+	s390irq_spin_lock_irqsave(irq, flags);
+
+	irq_desc[irq].status = 0;
+	ret                  = irq_desc[irq].handler->enable(irq);
+
+	s390irq_spin_unlock_irqrestore(irq, flags);
+
+	return(ret);
+}
+
+/*
+ * Enable IRQ by modifying the subchannel
+ */
+static int enable_subchannel( unsigned int irq)
+{
+	int            ret;
+   int            ccode;
+   int            retry = 5;
+
+   if ( irq > highest_subchannel || irq < 0 )
+   {
+      return( -ENODEV );
+
+   } /* endif */
+
+	/*
+	 * If a previous disable request is pending we reset it. However, this
+	 *  status implies that the device may (still) be not-operational.
+	 */
+	if (  ioinfo[irq].ui.flags.d_disable )
+	{
+		ioinfo[irq].ui.flags.d_disable = 0;
+		ret                            = 0;
+	}
+	else
+	{
+		ccode = stsch(irq, &(ioinfo[irq].schib) );
+
+      if ( ccode )
+      {
+          ret = -ENODEV;
+      }
+      else
+      {
+   		ioinfo[irq].schib.pmcw.ena = 1;
+
+         do
+         {
+            ccode = msch( irq, &(ioinfo[irq].schib) );
+
+   		   switch (ccode) {
+            case 0:
+               ret = 0;
+               break;
+
+            case 1:
+	   			/*
+		   		 * very bad, requires interrupt alike processing, where
+			   	 *  "rbh" is a dummy parameter for interface compatibility
+				    *  only. Bottom-half handling cannot be required as
+   				 *  this must be an unsolicited interrupt (!busy).
+	   			 */
+
+		   	   ioinfo[irq].ui.flags.s_pend = 1;
+
+		   		s390_process_IRQ( irq, 0 );
+
+		   	   ioinfo[irq].ui.flags.s_pend = 0;
+
+			   	ret = -EIO;    /* might be overwritten on ... */
+                              /* ... re-driving the msch()   */
+               retry--;
+               break;
+
+            case 3:
+		   	   ioinfo[irq].ui.flags.oper = 0;
+               ret = -ENODEV;
+               break;
+
+            default:
+               panic( "enable_subchannel() : ccode 2 on msch() received !\n");
+               ret = -ENODEV; // never reached
+            }
+
+         } while ( (ccode == 1) && retry );
+
+      } /* endif */
+
+	}  /* endif */
+
+	return( ret );
+}
+
+
+/*
+ * Disable IRQ by modifying the subchannel
+ */
+static int disable_subchannel( unsigned int irq)
+{
+	int            cc;          /* condition code */
+	int            ret;         /* function return value */
+   int            retry = 5;
+
+	if ( irq > highest_subchannel )
+	{
+		ret = -ENODEV;
+	}
+	else if ( ioinfo[irq].ui.flags.busy )
+	{
+		/*
+		 * the disable function must not be called while there are
+		 *  requests pending for completion !
+		 */
+		ret = -EBUSY;
+	}
+	else
+	{
+		/*
+		 * If device isn't operational we have to perform delayed
+		 *  disabling when the next interrupt occurs - unless the
+		 *  irq is re-requested prior to the interrupt to occur.
+		 */
+		cc = stsch(irq, &(ioinfo[irq].schib) );
+
+		if ( cc == 3 )
+		{
+			ioinfo[irq].ui.flags.oper      = 0;
+			ioinfo[irq].ui.flags.d_disable = 1;
+
+			ret = 0;
+		}
+		else // cc == 0
+		{
+			ioinfo[irq].schib.pmcw.ena = 0;
+
+         do
+         {
+   			cc = msch( irq, &(ioinfo[irq].schib) );
+
+	   		switch (cc) {
+		   	case 0 :
+			   	ret = 0;   /* done */
+				   break;
+
+   			case 1 :
+	   			/*
+		   		 * very bad, requires interrupt alike processing, where
+			   	 *  "rbh" is a dummy parameter for interface compatibility
+				    *  only. Bottom-half handling cannot be required as
+   				 *  this must be an unsolicited interrupt (!busy).
+	   			 */
+		   	   ioinfo[irq].ui.flags.s_pend = 1;
+
+		   		s390_process_IRQ( irq, 0 );
+
+		   	   ioinfo[irq].ui.flags.s_pend = 0;
+
+			   	ret = -EBUSY;  /* might be overwritten on ... */
+                              /* ... re-driving the msch()   */
+               retry--;
+				   break;
+
+   			case 2 :
+	   			/*
+		   		 * *** must not occur !                                    ***
+			   	 * ***                                                     ***
+				    * *** indicates our internal interrupt accounting is out  ***
+   				 * ***  of sync ===> panic()                               ***
+	   			 */
+		   		panic( "disable_subchannel() : unexpected busy condition !\n");
+               ret = -ENODEV; // never reached
+				   break;
+
+   			case 3 :
+	   			/*
+		   		 * should hardly occur but not impossible ...
+			   	 */
+   				ioinfo[irq].ui.flags.oper      = 0;
+	   			ioinfo[irq].ui.flags.d_disable = 1;
+
+		   		ret = 0; /* if the device has gone we don't ... */
+                        /* ... need to disable it anymore !    */
+			   	break;
+
+   			default :
+	   			ret = -ENODEV;  // never reached ...
+		   		break;
+
+			   } /* endswitch */
+
+         } while ( (cc == 1) && retry );
+
+		} /* endif */
+
+	} /* endif */
+
+	return( ret);
+}
+
+
+
+int s390_setup_irq(unsigned int irq, struct irqaction * new)
+{
+	unsigned long      flags;
+	int                rc = 0;
+
+	/*
+	 * The following block of code has to be executed atomically
+	 */
+	s390irq_spin_lock_irqsave( irq, flags);
+
+	if ( irq_desc[irq].action == NULL )
+	{
+      irq_desc[irq].action           = new;
+		irq_desc[irq].status           = 0;
+		irq_desc[irq].handler->enable  = &enable_subchannel;
+		irq_desc[irq].handler->disable = &disable_subchannel;
+		irq_desc[irq].handler->handle  = &handle_IRQ_event;
+
+		ioinfo[irq].ui.flags.ready     = 1;
+
+		irq_desc[irq].handler->enable(irq);
+	}
+	else
+	{
+		/*
+		 *  interrupt already owned, and shared interrupts
+		 *   aren't supported on S/390.
+		 */
+		rc = -EBUSY;
+
+	} /* endif */
+
+	s390irq_spin_unlock_irqrestore(irq,flags);
+
+	return( rc);
+}
+
+
+void s390_init_IRQ( void )
+{
+	unsigned long flags;     /* PSW flags */
+	long          cr6 __attribute__ ((aligned (8)));
+	int           irq;       /* counter for I/O subchannels */
+
+	for (irq=0; irq<NR_IRQS; irq++)
+	{
+		irq_desc[irq].status = 0;
+		irq_desc[irq].handler = &no_irq_type;
+
+	} /* endfor */
+
+	// Hopefully bh_count's will get set when we copy the prefix lowcore
+	// structure to other CPI's ( DJB )
+	atomic_set(&S390_lowcore.local_bh_count,0);
+	atomic_set(&S390_lowcore.local_irq_count,0);
+
+	/*
+	 * As we don't know about the calling environment
+	 *  we assure running disabled. Before leaving the
+	 *  function we resestablish the old environment.
+    *
+    * Note : as we don't need a system wide lock, therefore
+    *        we shouldn't use cli(), but __cli() as this
+    *        affects the current CPU only.
+	 */
+	__save_flags(flags);
+	__cli();
+
+	/*
+	 * disable all interrupts
+	 */
+	cr6 = 0;
+	asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
+
+   s390_process_subchannels();
+
+	/*
+	 * enable default I/O-interrupt sublass 3
+	 */
+	cr6 = 0x10000000;
+	asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
+
+   s390_device_recognition();
+
+   init_IRQ_complete = 1;
+
+	__restore_flags(flags);
+}
+
+
+/*
+ * dummy handler, used during init_IRQ() processing for compatibility only
+ */
+void  init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs)
+{
+   /* this is a dummy handler only ... */
+}
+
+
+int s390_start_IO( int            irq,      /* IRQ */
+                   ccw1_t        *cpa,      /* logical channel program addr */
+                   unsigned long  intparm,  /* interruption parameter */
+                   unsigned char  lpm,      /* logical path mask */
+                   unsigned long  flag)     /* flags */
+{
+	int            ccode;
+	unsigned long  psw_flags;
+
+	int            sync_isc_locked = 0;
+	int            ret             = 0;
+
+	/*
+	 * The flag usage is mutal exclusive ...
+	 */
+	if (    (flag & DOIO_RETURN_CHAN_END)
+	     && (flag & DOIO_REPORT_ALL     ) )
+	{
+		return( -EINVAL );
+
+	} /* endif */
+
+	memset( &(ioinfo[irq].orb), '\0', sizeof( orb_t) );
+
+	/*
+	 * setup ORB
+	 */
+	ioinfo[irq].orb.intparm = intparm;
+	ioinfo[irq].orb.fmt     = 1;
+
+	ioinfo[irq].orb.pfch = !(flag & DOIO_DENY_PREFETCH);
+	ioinfo[irq].orb.spnd =  (flag & DOIO_ALLOW_SUSPEND);
+	ioinfo[irq].orb.ssic =  (    (flag & DOIO_ALLOW_SUSPEND )
+	                          && (flag & DOIO_SUPPRESS_INTER) );
+
+	if ( flag & DOIO_VALID_LPM )
+	{
+		ioinfo[irq].orb.lpm = lpm;
+	}
+	else
+	{
+		ioinfo[irq].orb.lpm = ioinfo[irq].schib.pmcw.pam;
+
+	} /* endif */
+
+	ioinfo[irq].orb.cpa = (ccw1_t *)virt_to_phys( cpa);
+
+	/*
+	 * If sync processing was requested we lock the sync ISC, modify the
+	 *  device to present interrupts for this ISC only and switch the
+	 *  CPU to handle this ISC + the console ISC exclusively.
+	 */
+	if ( flag & DOIO_WAIT_FOR_INTERRUPT )
+	{
+		//
+		// check whether we run recursively (sense processing)
+		//
+		if ( !ioinfo[irq].ui.flags.syncio )
+		{
+			spin_lock_irqsave( &sync_isc, psw_flags);
+ 	
+			ret = enable_cpu_sync_isc( irq);
+
+			if ( ret )
+			{
+				spin_unlock_irqrestore( &sync_isc, psw_flags);
+ 		
+				// sigh, there should be a single exit point only ...
+				return( ret);
+			}
+			else
+			{
+				sync_isc_locked             = 1; // local setting
+				ioinfo[irq].ui.flags.syncio = 1; // global setting
+
+			} /* endif */  	
+ 	
+		} /* endif */
+
+	} /* endif */
+
+	/*
+	 * Issue "Start subchannel" and process condition code
+	 */
+	ccode = ssch( irq, &(ioinfo[irq].orb) );
+
+	switch ( ccode ) {
+	case 0:
+
+      if ( !ioinfo[irq].ui.flags.w4sense )
+      {
+			/*
+			 * initialize the device driver specific devstat irb area
+			 *
+			 * Note : don´t clear saved irb information in case of sense !
+			 */
+			memset( &((devstat_t *) irq_desc[irq].action->dev_id)->ii.irb,
+				'\0', sizeof( irb_t) );
+		} /* endif */
+
+		/*
+		 * initialize device status information
+		 */
+		ioinfo[irq].ui.flags.busy   = 1;
+		ioinfo[irq].ui.flags.doio   = 1;
+
+		ioinfo[irq].devstat.intparm = intparm;
+		ioinfo[irq].devstat.cstat   = 0;
+		ioinfo[irq].devstat.dstat   = 0;
+		ioinfo[irq].devstat.lpum    = 0;
+		ioinfo[irq].devstat.flag    = DEVSTAT_START_FUNCTION;
+		ioinfo[irq].devstat.scnt    = 0;
+
+		ioinfo[irq].ui.flags.fast   = 0;
+		ioinfo[irq].ui.flags.repall = 0;
+
+		/*
+		 * Check for either early (FAST) notification requests
+		 *  or if we are to return all interrupt info.
+		 * Default is to call IRQ handler at secondary status only
+		 */
+		if ( flag & DOIO_RETURN_CHAN_END )
+		{
+			ioinfo[irq].ui.flags.fast = 1;
+		}
+		else if ( flag & DOIO_REPORT_ALL )
+		{
+			ioinfo[irq].ui.flags.repall = 1;
+
+		} /* endif */
+
+		if ( flag & DOIO_VALID_LPM )
+		{
+			ioinfo[irq].lpm = lpm;         /* specific path */
+		}
+		else
+		{
+			ioinfo[irq].lpm = 0xff;        /* any path */
+
+		} /* endif */
+
+		/*
+		 * If synchronous I/O processing is requested, we have
+		 *  to wait for the corresponding interrupt to occur by
+		 *  polling the interrupt condition. However, as multiple
+		 *  interrupts may be outstanding, we must not just wait
+		 *  for the first interrupt, but must poll until ours
+		 *  pops up.
+		 */
+		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
+		{
+			int              io_sub;
+			int              io_parm;
+         psw_t            io_new_psw;
+         int              ccode;
+
+			int              ready = 0;
+         struct _lowcore *lc    = NULL;
+
+         /*
+          * We shouldn't perform a TPI loop, waiting for an interrupt
+          *  to occur, but should load a WAIT PSW instead. Otherwise
+          *  we may keep the channel subsystem busy, not able to present
+          *  the interrupt. When our sync. interrupt arrived we reset
+          *  the I/O old PSW to its original value.
+          */
+         memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t));
+
+			ccode = iac();
+
+			switch (ccode) {
+				case 0:  		// primary-space
+					io_sync_wait.mask =   _IO_PSW_MASK
+					                    | _PSW_PRIM_SPACE_MODE
+					                    | _PSW_IO_WAIT;
+					break;
+				case 1:			// secondary-space
+					io_sync_wait.mask =   _IO_PSW_MASK
+					                    | _PSW_SEC_SPACE_MODE
+					                    | _PSW_IO_WAIT;
+					break;
+				case 2:			// access-register
+					io_sync_wait.mask =   _IO_PSW_MASK
+					                    | _PSW_ACC_REG_MODE
+					                    | _PSW_IO_WAIT;
+					break;
+				case 3:			// home-space	
+					io_sync_wait.mask =   _IO_PSW_MASK
+					                    | _PSW_HOME_SPACE_MODE
+					                    | _PSW_IO_WAIT;
+					break;
+				default:
+					panic( "start_IO() : unexpected "
+					       "address-space-control %d\n",
+					       ccode);
+					break;
+			} /* endswitch */
+
+	      io_sync_wait.addr = (unsigned long) &&io_wakeup | 0x80000000L;
+
+			/*
+			 * Martin didn't like modifying the new PSW, now we take
+			 *  a fast exit in do_IRQ() instead
+			 */
+			*(int *)__LC_SYNC_IO_WORD  = 1;
+
+			do
+			{
+
+      		asm volatile ( "lpsw %0" : : "m" (io_sync_wait) );
+io_wakeup:
+				io_parm = *(int *)__LC_IO_INT_PARM;
+				io_sub  = (int)*(short *)__LC_SUBCHANNEL_NR;
+
+				ready = s390_process_IRQ( io_sub, io_parm);
+
+			} while ( !((io_sub == irq) && (ready == 1)) );
+
+			*(int *)__LC_SYNC_IO_WORD = 0;
+
+		} /* endif */
+
+		break;
+
+	case 1 :            /* status pending */
+
+		ioinfo[irq].devstat.flag |= DEVSTAT_STATUS_PENDING;
+
+		/*
+		 * initialize the device driver specific devstat irb area
+		 */
+		memset( &((devstat_t *) irq_desc[irq].action->dev_id)->ii.irb,
+		        '\0', sizeof( irb_t) );
+
+      /*
+       * Let the common interrupt handler process the pending status.
+       *  However, we must avoid calling the user action handler, as
+       *  it won't be prepared to handle a pending status during do_IO()
+       *  processing inline. This also implies that process_IRQ must
+       *  terminate synchronously - especially if device sensing is
+       *  required.
+       */
+      ioinfo[irq].ui.flags.s_pend   = 1;
+		ioinfo[irq].ui.flags.busy     = 1;
+		ioinfo[irq].ui.flags.doio     = 1;
+
+	   s390_process_IRQ( irq, intparm );
+
+      ioinfo[irq].ui.flags.s_pend   = 0;
+		ioinfo[irq].ui.flags.busy     = 0;
+		ioinfo[irq].ui.flags.doio     = 0;
+		ioinfo[irq].ui.flags.repall   = 0;
+		ioinfo[irq].ui.flags.w4final  = 0;
+
+		ioinfo[irq].devstat.flag     |= DEVSTAT_FINAL_STATUS;
+
+		/*
+		 * In multipath mode a condition code 3 implies the last path
+		 *  has gone, except we have previously restricted the I/O to
+		 *  a particular path. A condition code 1 (0 won't occur)
+		 *  results in return code EIO as well as 3 with another path
+		 *  than the one used (i.e. path available mask is non-zero).
+		 */
+		if ( ioinfo[irq].devstat.ii.irb.scsw.cc == 3 )
+		{
+			ret                        = -ENODEV;
+			ioinfo[irq].devstat.flag  |= DEVSTAT_NOT_OPER;
+			ioinfo[irq].ui.flags.oper  = 0;
+
+#if CONFIG_DEBUG_IO
+      	{
+	      char buffer[80];
+
+		   stsch(irq, &(ioinfo[irq].schib) );
+
+   	   sprintf( buffer, "s390_start_IO(%04X) - irb for "
+			         "device %04X, after status pending\n",
+			         irq,
+			         ioinfo[irq].devstat.devno );
+
+			s390_displayhex( buffer,
+			                 &(ioinfo[irq].devstat.ii.irb) ,
+			                 sizeof(irb_t));
+
+   	   sprintf( buffer, "s390_start_IO(%04X) - schib for "
+			         "device %04X, after status pending\n",
+			         irq,
+			         ioinfo[irq].devstat.devno );
+
+			s390_displayhex( buffer,
+			                 &(ioinfo[irq].schib) ,
+			                 sizeof(schib_t));
+
+
+			if (ioinfo[irq].devstat.flag  & DEVSTAT_FLAG_SENSE_AVAIL)
+         {
+	   	   sprintf( buffer, "s390_start_IO(%04X) - sense data for "
+				         "device %04X, after status pending\n",
+				         irq,
+				         ioinfo[irq].devstat.devno );
+
+				s390_displayhex( buffer,
+     ((devstat_t *)(irq_desc[irq].action->dev_id))->ii.sense.data,
+     ((devstat_t *)(irq_desc[irq].action->dev_id))->rescnt);
+
+         }
+      	}
+#endif
+		}
+		else
+		{
+			ret                        = -EIO;
+			ioinfo[irq].devstat.flag  &= ~DEVSTAT_NOT_OPER;
+			ioinfo[irq].ui.flags.oper  = 1;
+
+		} /* endif */
+
+		break;
+
+	case 2 :            /* busy */
+
+		ret = -EBUSY;
+		break;
+
+	default:            /* device not operational */
+
+		ret                          = -ENODEV;
+		ioinfo[irq].ui.flags.oper    = 0;
+
+		ioinfo[irq].devstat.flag    |= DEVSTAT_NOT_OPER;
+		ioinfo[irq].devstat.intparm  = intparm;
+
+		memcpy( irq_desc[irq].action->dev_id,
+			&(ioinfo[irq].devstat),
+			sizeof( devstat_t) );
+
+#if CONFIG_DEBUG_IO
+      	{
+	      char buffer[80];
+
+		   stsch(irq, &(ioinfo[irq].schib) );
+
+   	   sprintf( buffer, "s390_start_IO(%04X) - schib for "
+			         "device %04X, after 'not oper' status\n",
+			         irq,
+			         ioinfo[irq].devstat.devno );
+
+			s390_displayhex( buffer,
+			                 &(ioinfo[irq].schib),
+			                 sizeof(schib_t));
+      	}
+#endif
+		break;
+
+	} /* endswitch */
+
+	if (    ( flag & DOIO_WAIT_FOR_INTERRUPT )   	
+	     && ( sync_isc_locked                ) )
+	{
+		disable_cpu_sync_isc( irq );
+
+		spin_unlock_irqrestore( &sync_isc, psw_flags);
+
+		sync_isc_locked             = 0;    // local setting
+	   ioinfo[irq].ui.flags.syncio = 0;    // global setting
+
+	} /* endif */
+
+	return( ret);
+}
+
+int do_IO( int            irq,          /* IRQ */
+           ccw1_t        *cpa,          /* channel program address */
+           unsigned long  intparm,      /* interruption parameter */
+           unsigned char  lpm,          /* logical path mask */
+           unsigned long  flag)         /* flags : see above */
+{
+	int ret = 0;
+
+	if ( irq > highest_subchannel || irq < 0 )
+	{
+		return( -ENODEV );
+
+	} /* endif */
+
+	/* handler registered ?    */
+	if ( !ioinfo[irq].ui.flags.ready )
+	{
+		return( -ENODEV );
+
+	} /* endif */
+
+	/*
+	 * Note: We ignore the device operational status - if not operational,
+	 *        the SSCH will lead to an -ENODEV condition ...
+	 */
+	if ( !ioinfo[irq].ui.flags.busy )         /* last I/O completed ? */
+	{
+		ret = s390_start_IO( irq, cpa, intparm, lpm, flag);
+	}
+	else if ( ioinfo[irq].ui.flags.fast )
+	{
+		/*
+		 * If primary status was received and ending status is missing, the
+		 *  device driver won't be notified on the ending status if early
+		 *  (fast) interrupt notification was requested. Therefore we have
+		 *  to queue the next incoming request. If halt_IO() is issued while
+		 *  there is a request queued, a HSCH needs to be issued and the queued
+		 *  request must be deleted but its intparm must be returned (see
+		 *  halt_IO() processing)
+		 */
+		if ( ioinfo[irq].ui.flags.w4final && !ioinfo[irq].ui.flags.doio_q )
+		{
+			ioinfo[irq].qflag    = flag;
+			ioinfo[irq].qcpa     = cpa;
+			ioinfo[irq].qintparm = intparm;
+			ioinfo[irq].qlpm     = lpm;
+		}
+		else
+		{
+			ret = -EBUSY;
+
+		} /* endif */
+	}
+	else
+	{
+		ret = -EBUSY;
+
+	} /* endif */
+
+	return( ret );
+
+}
+
+/*
+ * resume suspended I/O operation
+ */
+int resume_IO( int irq)
+{
+	int ret = 0;
+
+	if ( irq > highest_subchannel || irq < 0 )
+	{
+		return( -ENODEV );
+
+	} /* endif */
+
+	/*
+	 * We allow for 'resume' requests only for active I/O operations
+	 */
+	if ( ioinfo[irq].ui.flags.busy )
+	{
+		int ccode;
+
+		ccode = rsch( irq);
+
+		switch (ccode) {
+			case 0 :
+				break;
+
+			case 1 :
+		   	s390_process_IRQ( irq,
+				                  ioinfo[irq].devstat.intparm );
+				ret = -EBUSY;
+				break;
+
+			case 2 :
+				ret = -EINVAL;
+				break;
+
+			case 3 :
+				/*
+				 * useless to wait for request completion
+				 *  as device is no longer operational !
+				 */
+				ioinfo[irq].ui.flags.oper = 0;
+				ioinfo[irq].ui.flags.busy = 0;
+				ret                       = -ENODEV;
+				break;
+
+		} /* endswitch */          	
+		
+	}
+	else
+	{
+		ret = -ENOTCONN;
+
+	} /* endif  */
+
+	return( ret);
+}
+
+/*
+ * Note: The "intparm" parameter is not used by the halt_IO() function
+ *       itself, as no ORB is built for the HSCH instruction. However,
+ *       it allows the device interrupt handler to associate the upcoming
+ *       interrupt with the halt_IO() request.
+ */
+int halt_IO( int          irq,
+             int          intparm,
+             unsigned int flag)  /* possible DOIO_WAIT_FOR_INTERRUPT */
+{
+	int            ret;
+	int            ccode;
+	unsigned long  psw_flags;
+
+	int            sync_isc_locked = 0;
+
+	if ( irq > highest_subchannel || irq < 0 )
+	{
+		ret = -ENODEV;
+	}
+	/*
+	 * we only allow for halt_IO if the device has an I/O handler associated
+	 */
+	else if ( !ioinfo[irq].ui.flags.ready )
+	{
+		ret = -ENODEV;
+	}
+	/*
+	 * we ignore the halt_io() request if ending_status was received but
+	 *  a SENSE operation is waiting for completion.
+	 */
+	else if ( ioinfo[irq].ui.flags.w4sense )
+	{
+		ret = 0;
+	}
+	/*
+	 * We don't allow for halt_io with a sync do_IO() requests pending.
+	 */
+	else if ( ioinfo[irq].ui.flags.syncio )
+	{
+		ret = -EBUSY;
+	}
+	else
+	{
+		/*
+		 * If sync processing was requested we lock the sync ISC, modify the
+		 *  device to present interrupts for this ISC only and switch the
+		 *  CPU to handle this ISC + the console ISC exclusively.
+		 */
+		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
+		{
+			//
+			// check whether we run recursively (sense processing)
+			//
+			if ( !ioinfo[irq].ui.flags.syncio )
+			{
+				spin_lock_irqsave( &sync_isc, psw_flags);
+  	
+				ret = enable_cpu_sync_isc( irq);
+
+				if ( ret )
+				{
+					spin_unlock_irqrestore( &sync_isc, psw_flags);
+  		
+					// sigh, there should be a single exit point only ...
+					return( ret);
+				}
+				else
+				{
+					sync_isc_locked             = 1; // local setting
+					ioinfo[irq].ui.flags.syncio = 1; // global setting
+
+				} /* endif */  	
+  	
+			} /* endif */
+
+		} /* endif */
+
+		/*
+		 * Issue "Halt subchannel" and process condition code
+		 */
+		ccode = hsch( irq );
+
+		switch ( ccode ) {
+		case 0:
+
+			ioinfo[irq].ui.flags.haltio = 1;
+
+			if ( !ioinfo[irq].ui.flags.doio )
+			{
+				ioinfo[irq].ui.flags.busy   = 1;
+				ioinfo[irq].devstat.intparm = intparm;
+				ioinfo[irq].devstat.cstat   = 0;
+				ioinfo[irq].devstat.dstat   = 0;
+				ioinfo[irq].devstat.lpum    = 0;
+				ioinfo[irq].devstat.flag    = DEVSTAT_HALT_FUNCTION;
+				ioinfo[irq].devstat.scnt    = 0;
+
+			}
+			else
+			{
+				ioinfo[irq].devstat.flag   |= DEVSTAT_HALT_FUNCTION;
+
+			} /* endif */
+
+			/*
+			 * If synchronous I/O processing is requested, we have
+			 *  to wait for the corresponding interrupt to occur by
+			 *  polling the interrupt condition. However, as multiple
+			 *  interrupts may be outstanding, we must not just wait
+			 *  for the first interrupt, but must poll until ours
+			 *  pops up.
+			 */
+			if ( flag & DOIO_WAIT_FOR_INTERRUPT )
+			{
+				int              io_sub;
+				int              io_parm;
+  		      psw_t            io_new_psw;
+            int              ccode;
+  	
+				int              ready = 0;
+	         struct _lowcore *lc    = NULL;
+
+	         /*
+	          * We shouldn't perform a TPI loop, waiting for an interrupt
+	          *  to occur, but should load a WAIT PSW instead. Otherwise
+	          *  we may keep the channel subsystem busy, not able to present
+	          *  the interrupt. When our sync. interrupt arrived we reset
+	          *  the I/O old PSW to its original value.
+	          */
+	         memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t));
+
+				ccode = iac();
+
+				switch (ccode) {
+					case 0:  		// primary-space
+						io_sync_wait.mask =   _IO_PSW_MASK
+						                    | _PSW_PRIM_SPACE_MODE
+						                    | _PSW_IO_WAIT;
+						break;
+					case 1:			// secondary-space
+						io_sync_wait.mask =   _IO_PSW_MASK
+						                    | _PSW_SEC_SPACE_MODE
+						                    | _PSW_IO_WAIT;
+						break;
+					case 2:			// access-register
+						io_sync_wait.mask =   _IO_PSW_MASK
+						                    | _PSW_ACC_REG_MODE
+						                    | _PSW_IO_WAIT;
+						break;
+					case 3:			// home-space	
+						io_sync_wait.mask =   _IO_PSW_MASK
+						                    | _PSW_HOME_SPACE_MODE
+						                    | _PSW_IO_WAIT;
+						break;
+					default:
+						panic( "halt_IO() : unexpected "
+						       "address-space-control %d\n",
+						       ccode);
+						break;
+				} /* endswitch */
+
+		      io_sync_wait.addr = (unsigned long) &&hio_wakeup | 0x80000000L;
+
+				/*
+				 * Martin didn't like modifying the new PSW, now we take
+				 *  a fast exit in do_IRQ() instead
+				 */
+				*(int *)__LC_SYNC_IO_WORD  = 1;
+
+				do
+				{
+
+	      		asm volatile ( "lpsw %0" : : "m" (io_sync_wait) );
+hio_wakeup:
+				   io_parm = *(int *)__LC_IO_INT_PARM;
+				   io_sub  = (int)*(__u16 *)__LC_SUBCHANNEL_NR;
+
+				   ready = s390_process_IRQ( io_sub, io_parm);
+
+				} while ( !((io_sub == irq) && (ready == 1)) );
+
+				*(int *)__LC_SYNC_IO_WORD = 0;
+
+			} /* endif */
+
+			ret = 0;
+			break;
+
+		case 1 :            /* status pending */
+	
+			ioinfo[irq].devstat.flag |= DEVSTAT_STATUS_PENDING;
+
+			/*
+			 * initialize the device driver specific devstat irb area
+			 */
+			memset( &((devstat_t *) irq_desc[irq].action->dev_id)->ii.irb,
+			        '\0', sizeof( irb_t) );
+
+	      /*
+   	    * Let the common interrupt handler process the pending status.
+	       *  However, we must avoid calling the user action handler, as
+	       *  it won't be prepared to handle a pending status during do_IO()
+	       *  processing inline. This also implies that s390_process_IRQ must
+	       *  terminate synchronously - especially if device sensing is
+	       *  required.
+	       */
+	      ioinfo[irq].ui.flags.s_pend   = 1;
+			ioinfo[irq].ui.flags.busy     = 1;
+			ioinfo[irq].ui.flags.doio     = 1;
+
+		   s390_process_IRQ( irq, intparm );
+
+	      ioinfo[irq].ui.flags.s_pend   = 0;
+			ioinfo[irq].ui.flags.busy     = 0;
+			ioinfo[irq].ui.flags.doio     = 0;
+			ioinfo[irq].ui.flags.repall   = 0;
+			ioinfo[irq].ui.flags.w4final  = 0;
+
+			ioinfo[irq].devstat.flag     |= DEVSTAT_FINAL_STATUS;
+
+			/*
+			 * In multipath mode a condition code 3 implies the last path
+			 *  has gone, except we have previously restricted the I/O to
+			 *  a particular path. A condition code 1 (0 won't occur)
+			 *  results in return code EIO as well as 3 with another path
+			 *  than the one used (i.e. path available mask is non-zero).
+			 */
+			if ( ioinfo[irq].devstat.ii.irb.scsw.cc == 3 )
+			{
+				ret                        = -ENODEV;
+				ioinfo[irq].devstat.flag  |= DEVSTAT_NOT_OPER;
+				ioinfo[irq].ui.flags.oper  = 0;
+			}
+			else
+			{
+				ret                        = -EIO;
+				ioinfo[irq].devstat.flag  &= ~DEVSTAT_NOT_OPER;
+				ioinfo[irq].ui.flags.oper  = 1;
+
+			} /* endif */
+
+			break;
+
+		case 2 :            /* busy */
+
+			ret = -EBUSY;
+			break;
+
+		default:            /* device not operational */
+
+			ret = -ENODEV;
+			break;
+
+		} /* endswitch */
+
+		if (    ( flag & DOIO_WAIT_FOR_INTERRUPT )
+	   	  && ( sync_isc_locked                ) )
+		{
+			sync_isc_locked             = 0;    // local setting
+		   ioinfo[irq].ui.flags.syncio = 0;    // global setting
+  	
+			disable_cpu_sync_isc( irq );
+  	
+			spin_unlock_irqrestore( &sync_isc, psw_flags);
+  	
+		} /* endif */
+
+	} /* endif */
+
+	return( ret );
+}
+
+
+/*
+ * do_IRQ() handles all normal I/O device IRQ's (the special
+ *          SMP cross-CPU interrupts have their own specific
+ *          handlers).
+ *
+ * Returns: 0 - no ending status received, no further action taken
+ *          1 - interrupt handler was called with ending status
+ */
+asmlinkage void do_IRQ( struct pt_regs regs,
+                        unsigned int   irq,
+                        unsigned int   intparm )
+{
+#ifdef CONFIG_FAST_IRQ
+	int			ccode;
+	tpi_info_t 	tpi_info;
+	int			new_irq;
+#endif
+	int			use_irq     = irq;
+	long			use_intparm = intparm;
+
+	/*
+	 * take fast exit if CPU is in sync. I/O state
+	 *
+	 * Note: we have to turn off the WAIT bit and re-disable
+	 *       interrupts prior to return as this was the initial
+	 *       entry condition to synchronous I/O.
+	 */
+ 	if (    *(int *)__LC_SYNC_IO_WORD )
+	{
+		regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT);
+
+      return;
+
+	} /* endif */
+
+	s390irq_spin_lock(use_irq);
+
+#ifdef CONFIG_FAST_IRQ
+	do {
+#endif /*  CONFIG_FAST_IRQ */
+
+		s390_process_IRQ( use_irq, use_intparm);
+
+#ifdef CONFIG_FAST_IRQ
+
+		/*
+		 * more interrupts pending ?
+		 */
+		ccode = tpi( &tpi_info );
+
+		if ( ! ccode )
+			break;  	// no, leave ...
+
+		new_irq     = tpi_info.irq;
+		use_intparm = tpi_info.intparm;
+
+		/*
+		 * if the interrupt is for a different irq we
+		 *  release the current irq lock and obtain
+		 *  a new one ...
+		 */
+		if ( new_irq != use_irq )
+      {
+			s390irq_spin_unlock(use_irq);
+         use_irq = new_irq;
+			s390irq_spin_lock(use_irq);
+
+      } /* endif */
+
+	} while ( 1 );
+
+#endif /*  CONFIG_FAST_IRQ */
+
+	s390irq_spin_unlock(use_irq);
+
+	return;
+}
+
+/*
+ * s390_process_IRQ() handles status pending situations and interrupts
+ *
+ * Called by : do_IRQ()             - for "real" interrupts
+ *             s390_start_IO, halt_IO()
+ *                                  - status pending cond. after SSCH, or HSCH
+ *             disable_subchannel() - status pending conditions (after MSCH)
+ *
+ * Returns: 0 - no ending status received, no further action taken
+ *          1 - interrupt handler was called with ending status
+ */
+int s390_process_IRQ( unsigned int   irq,
+                      unsigned int   intparm)
+{
+	int               ccode;      /* condition code from tsch() operation */
+	int               irb_cc;     /* condition code from irb */
+	int               sdevstat;   /* effective struct devstat size to copy */
+	unsigned int      fctl;       /* function control */
+	unsigned int      stctl;      /* status   control */
+	unsigned int      actl;       /* activity control */
+	struct irqaction *action;
+	struct pt_regs    regs;       /* for interface compatibility only */
+
+	int               issense         = 0;
+	int               ending_status   = 0;
+	int               allow4handler   = 1;
+	int               cpu             = smp_processor_id();
+
+	kstat.irqs[cpu][irq]++;
+
+	action = irq_desc[irq].action;
+
+	/*
+	 * It might be possible that a device was not-oper. at the time
+	 *  of free_irq() processing. This means the handler is no longer
+	 *  available when the device possibly becomes ready again. In
+	 *  this case we perform delayed disable_subchannel() processing.
+	 */
+	if ( action == NULL )
+	{
+		if ( !ioinfo[irq].ui.flags.d_disable )
+		{
+			panic( "do_IRQ() : error, no irq_action available !\n");
+
+		} /* endif */
+
+	} /* endif */
+
+	/*
+	 * retrieve the i/o interrupt information (irb),
+	 *  update the device specific status information
+	 *  and possibly call the interrupt handler.
+	 *
+	 * Note 1: At this time we don't process the resulting
+	 *         condition code (ccode) from tsch(), although
+	 *         we probably should.
+	 *
+	 * Note 2: Here we will have to check for channel
+	 *         check conditions and call a channel check
+	 *         handler.
+	 *
+	 * Note 3: If a start function was issued, the interruption
+	 *         parameter relates to it. If a halt function was
+	 *         issued for an idle device, the intparm must not
+	 *         be taken from lowcore, but from the devstat area.
+	 */
+	ccode = tsch( irq, &(ioinfo[irq].devstat.ii.irb) );
+
+	//
+	// We must only accumulate the status if initiated by do_IO() or halt_IO()
+	//
+	if ( ioinfo[irq].ui.flags.busy )
+	{
+		ioinfo[irq].devstat.dstat   |= ioinfo[irq].devstat.ii.irb.scsw.dstat;
+		ioinfo[irq].devstat.cstat   |= ioinfo[irq].devstat.ii.irb.scsw.cstat;
+	}
+	else
+	{
+		ioinfo[irq].devstat.dstat    = ioinfo[irq].devstat.ii.irb.scsw.dstat;
+		ioinfo[irq].devstat.cstat    = ioinfo[irq].devstat.ii.irb.scsw.cstat;
+
+		ioinfo[irq].devstat.flag     = 0;   // reset status flags
+
+	} /* endif */
+
+	ioinfo[irq].devstat.lpum     = ioinfo[irq].devstat.ii.irb.esw.esw1.lpum;
+
+	if ( ioinfo[irq].ui.flags.doio)
+	{
+		ioinfo[irq].devstat.intparm  = intparm;
+
+	} /* endif */
+
+	/*
+	 * reset device-busy bit if no longer set in irb
+	 */
+	if (   (ioinfo[irq].devstat.dstat & DEV_STAT_BUSY                   )
+	    && ((ioinfo[irq].devstat.ii.irb.scsw.dstat & DEV_STAT_BUSY) == 0))
+	{
+		ioinfo[irq].devstat.dstat &= ~DEV_STAT_BUSY;
+
+	} /* endif */
+
+	/*
+	 * Save residual count and CCW information in case primary and
+	 *  secondary status are presented with different interrupts.
+	 */
+	if ( ioinfo[irq].devstat.ii.irb.scsw.stctl & SCSW_STCTL_PRIM_STATUS )
+	{
+		ioinfo[irq].devstat.rescnt = ioinfo[irq].devstat.ii.irb.scsw.count;
+
+#if CONFIG_DEBUG_IO
+      if ( irq != cons_dev )
+         printk( "s390_process_IRQ( %04X ) : "
+                 "residual count from irb after tsch() %d\n",
+                 irq, ioinfo[irq].devstat.rescnt );
+#endif
+	} /* endif */
+
+	if ( ioinfo[irq].devstat.ii.irb.scsw.cpa != 0 )
+	{
+		ioinfo[irq].devstat.cpa = ioinfo[irq].devstat.ii.irb.scsw.cpa;
+
+	} /* endif */
+
+	irb_cc = ioinfo[irq].devstat.ii.irb.scsw.cc;
+
+	//
+	// check for any kind of channel or interface control check but don't
+	//  issue the message for the console device
+	//
+	if (    (ioinfo[irq].devstat.ii.irb.scsw.cstat
+	            & (  SCHN_STAT_CHN_DATA_CHK
+	               | SCHN_STAT_CHN_CTRL_CHK
+	               | SCHN_STAT_INTF_CTRL_CHK )       )
+	     && (irq != cons_dev                         ) )
+	{
+		printk( "Channel-Check or Interface-Control-Check "
+		        "received\n"
+		        " ... device %X on subchannel %X, dev_stat "
+		        ": %X sch_stat : %X\n",
+		        ioinfo[irq].devstat.devno,
+		        irq,
+		        ioinfo[irq].devstat.dstat,
+		        ioinfo[irq].devstat.cstat);
+
+	} /* endif */
+
+	issense = ioinfo[irq].devstat.ii.irb.esw.esw0.erw.cons;
+
+	if ( issense )
+	{
+		ioinfo[irq].devstat.scnt  =
+		             ioinfo[irq].devstat.ii.irb.esw.esw0.erw.scnt;
+		ioinfo[irq].devstat.flag |=
+		             DEVSTAT_FLAG_SENSE_AVAIL;
+                  	
+		sdevstat = sizeof( devstat_t);
+
+#if CONFIG_DEBUG_IO
+      if ( irq != cons_dev )
+         printk( "s390_process_IRQ( %04X ) : "
+                 "concurrent sense bytes avail %d\n",
+                 irq, ioinfo[irq].devstat.scnt );
+#endif
+	}
+	else
+	{
+		/* don't copy the sense data area ! */
+		sdevstat = sizeof( devstat_t) - SENSE_MAX_COUNT;
+
+	} /* endif */
+
+	switch ( irb_cc ) {
+	case 1:      /* status pending */
+
+		ioinfo[irq].devstat.flag |= DEVSTAT_STATUS_PENDING;
+
+	case 0:      /* normal i/o interruption */
+
+		fctl  = ioinfo[irq].devstat.ii.irb.scsw.fctl;
+		stctl = ioinfo[irq].devstat.ii.irb.scsw.stctl;
+		actl  = ioinfo[irq].devstat.ii.irb.scsw.actl;
+
+			
+		ioinfo[irq].stctl |= stctl;
+
+		ending_status =    ( stctl & SCSW_STCTL_SEC_STATUS                          )
+			|| ( stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)         )
+		   || ( (fctl == SCSW_FCTL_HALT_FUNC)  && (stctl == SCSW_STCTL_STATUS_PEND) );
+
+		/*
+		 * Check for unsolicited interrupts - for debug purposes only
+		 *
+		 * We only consider an interrupt as unsolicited, if the device was not
+		 *  actively in use (busy) and an interrupt other than an ALERT status
+		 *  was received.
+		 *
+		 * Note: We must not issue a message to the console, if the
+		 *       unsolicited interrupt applies to the console device
+		 *       itself !
+		 */
+#if CONFIG_DEBUG_IO
+		if (     ( irq != cons_dev                 )
+			 && !( stctl & SCSW_STCTL_ALERT_STATUS )
+			 &&  ( ioinfo[irq].ui.flags.busy == 0  ) )
+		{
+	      char buffer[80];
+
+			printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n"
+				" ... device status : %02X subchannel status : %02X\n",
+				ioinfo[irq].devstat.devno,
+				irq,
+				ioinfo[irq].devstat.dstat,
+				ioinfo[irq].devstat.cstat);
+
+   	   sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
+			         "device %04X, ending_status %d\n",
+			         irq,
+			         ioinfo[irq].devstat.devno,
+		   	      ending_status);
+
+			s390_displayhex( buffer,
+			                 &(ioinfo[irq].devstat.ii.irb) ,
+			                 sizeof(irb_t));
+
+		} /* endif */
+#endif
+		/*
+		 * Check whether we must issue a SENSE CCW ourselves if there is no
+		 *  concurrent sense facility installed for the subchannel.
+		 *
+		 * Note: We should check for ioinfo[irq].ui.flags.consns but VM
+		 *       violates the ESA/390 architecture and doesn't present an
+		 *       operand exception for virtual devices without concurrent
+		 *       sense facility available/supported when enabling the
+       *       concurrent sense facility.
+		 */
+		if (    (    ( ioinfo[irq].devstat.ii.irb.scsw.dstat & DEV_STAT_UNIT_CHECK )
+			       && ( !issense                                                    ) )
+           || ( ioinfo[irq].ui.flags.delsense && ending_status                     ) )
+		{
+			int            ret_io;
+			ccw1_t        *s_ccw  = &ioinfo[irq].senseccw;
+			unsigned long  s_flag = 0;
+
+         if (ending_status)
+         {
+			   /*
+			    * We copy the current status information into the device driver
+			    *  status area. Then we can use the local devstat area for device
+			    *  sensing. When finally calling the IRQ handler we must not overlay
+			    *  the original device status but copy the sense data only.
+			    */
+			   memcpy( irq_desc[irq].action->dev_id,
+				        &(ioinfo[irq].devstat),
+				        sizeof( devstat_t) );
+
+			   s_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
+			   s_ccw->cda      = (char *)virt_to_phys( ioinfo[irq].devstat.ii.sense.data);
+			   s_ccw->count    = SENSE_MAX_COUNT;
+			   s_ccw->flags    = CCW_FLAG_SLI;
+
+			   /*
+			    * If free_irq() or a sync do_IO/s390_start_IO() is in
+			    *  process we have to sense synchronously
+			    */
+			   if ( ioinfo[irq].ui.flags.unready || ioinfo[irq].ui.flags.syncio )
+			   {
+				   s_flag = DOIO_WAIT_FOR_INTERRUPT;
+
+			   } /* endif */
+
+			   /*
+			    * Reset status info
+			    *
+			    * It does not matter whether this is a sync. or async.
+			    *  SENSE request, but we have to assure we don't call
+			    *  the irq handler now, but keep the irq in busy state.
+				 *  In sync. mode s390_process_IRQ() is called recursively,
+			    *  while in async. mode we re-enter do_IRQ() with the
+			    *  next interrupt.
+             *
+             * Note : this may be a delayed sense request !
+			    */
+			   allow4handler                 = 0;
+
+			   ioinfo[irq].ui.flags.fast     = 0;
+			   ioinfo[irq].ui.flags.repall   = 0;
+			   ioinfo[irq].ui.flags.w4final  = 0;
+			   ioinfo[irq].ui.flags.delsense = 0;
+
+			   ioinfo[irq].devstat.cstat     = 0;
+			   ioinfo[irq].devstat.dstat     = 0;
+			   ioinfo[irq].devstat.rescnt    = SENSE_MAX_COUNT;
+
+			   ioinfo[irq].ui.flags.w4sense = 1;
+			
+			   ret_io = s390_start_IO( irq,
+				                        s_ccw,
+				                        0xE2C5D5E2,  // = SENSe
+				                        0,           // n/a
+				                        s_flag);
+			}
+			else
+			{
+				/*
+				 * we received an Unit Check but we have no final
+				 *  status yet, therefore we must delay the SENSE
+				 *  processing. However, we must not report this
+				 *  intermediate status to the device interrupt
+				 *  handler.
+				 */
+				ioinfo[irq].ui.flags.fast     = 0;
+				ioinfo[irq].ui.flags.repall   = 0;
+
+				ioinfo[irq].ui.flags.delsense = 1;
+				allow4handler                 = 0;
+
+			} /* endif */
+
+		} /* endif */
+
+      /*
+       * we allow for the device action handler if .
+       *  - we received ending status
+		 *  - the action handler requested to see all interrupts
+		 *  - we received a PCI
+		 *  - fast notification was requested (primary status)
+		 *  - unsollicited interrupts
+		 *
+		 */
+		if ( allow4handler )
+		{
+			allow4handler =    ending_status
+	  		   || ( ioinfo[irq].ui.flags.repall                                      )
+		      || ( ioinfo[irq].devstat.ii.irb.scsw.cstat & SCHN_STAT_PCI            )
+	  			|| ( (ioinfo[irq].ui.flags.fast ) && (stctl & SCSW_STCTL_PRIM_STATUS) )
+	  			|| ( ioinfo[irq].ui.flags.oper == 0                                   );
+		}
+
+      /*
+       * We used to copy the device status information right before
+       *  calling the device action handler. However, in status
+       *  pending situations during do_IO() or halt_IO(), as well as
+       *  enable_subchannel/disable_subchannel processing we must
+       *  synchronously return the status information and must not
+       *  call the device action handler.
+       *
+       */
+		if ( allow4handler )
+		{
+			/*
+			 * if we were waiting for sense data we copy the sense
+			 *  bytes only as the original status information was
+			 *  saved prior to sense already.
+			 */
+			if ( ioinfo[irq].ui.flags.w4sense )
+			{
+				int sense_count = SENSE_MAX_COUNT-ioinfo[irq].devstat.rescnt;
+
+#if CONFIG_DEBUG_IO
+      if ( irq != cons_dev )
+         printk( "s390_process_IRQ( %04X ) : "
+                 "BASIC SENSE bytes avail %d\n",
+                 irq, sense_count );
+#endif
+				ioinfo[irq].ui.flags.w4sense           = 0;
+				((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
+				((devstat_t *)(action->dev_id))->scnt  = sense_count;
+
+				if (sense_count >= 0)
+					memcpy( ((devstat_t *)(action->dev_id))->ii.sense.data,
+						&(ioinfo[irq].devstat.ii.sense.data), sense_count);
+            else
+#if 0
+					panic( "s390_process_IRQ(%04x) encountered "
+					       "negative sense count\n",
+					       irq);
+#else
+					printk( "s390_process_IRQ(%04x) encountered "
+					        "negative sense count\n",
+					        irq);
+#endif
+			}
+			else
+			{
+				memcpy( action->dev_id, &(ioinfo[irq].devstat), sdevstat );
+
+			}  /* endif */
+
+      } /* endif */
+
+      /*
+       * for status pending situations other than deferred interrupt
+		 *  conditions detected by s390_process_IRQ() itself we must not
+		 *  call the handler.
+       */
+		if ( ioinfo[irq].ui.flags.s_pend )
+			allow4handler = 0;
+
+		/*
+		 * Call device action handler if applicable
+		 */
+		if ( allow4handler )
+		{
+
+			/*
+			 *  We only reset the busy condition when we are sure that no further
+			 *   interrupt is pending for the current I/O request (ending_status).
+			 */
+			if ( ending_status || !ioinfo[irq].ui.flags.oper )
+			{
+				ioinfo[irq].ui.flags.oper     = 1;  /* dev IS oper */
+
+				ioinfo[irq].ui.flags.busy     = 0;
+				ioinfo[irq].ui.flags.doio     = 0;
+				ioinfo[irq].ui.flags.haltio   = 0;
+				ioinfo[irq].ui.flags.fast     = 0;
+				ioinfo[irq].ui.flags.repall   = 0;
+				ioinfo[irq].ui.flags.w4final  = 0;
+
+				ioinfo[irq].devstat.flag              |= DEVSTAT_FINAL_STATUS;
+				((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FINAL_STATUS;
+
+				action->handler( irq, action->dev_id, &regs);
+
+				//
+				// reset intparm after final status or we will badly present unsolicited
+				//  interrupts with a intparm value possibly no longer valid.
+				//
+				ioinfo[irq].devstat.intparm   = 0;
+
+				//
+				// Was there anything queued ? Start the pending channel program
+				//  if there is one.
+				//
+				if ( ioinfo[irq].ui.flags.doio_q )
+				{
+					int ret;
+
+					ret = s390_start_IO( irq,
+							               ioinfo[irq].qcpa,
+							               ioinfo[irq].qintparm,
+							               ioinfo[irq].qlpm,
+							               ioinfo[irq].qflag);
+
+					ioinfo[irq].ui.flags.doio_q = 0;
+
+					/*
+					 * If s390_start_IO() failed call the device's interrupt
+					 *  handler, the IRQ related devstat area was setup by
+					 *  s390_start_IO() accordingly already (status pending
+					 *  condition).
+					 */
+					if ( ret )
+					{
+						action->handler( irq, action->dev_id, &regs);
+
+					} /* endif */
+
+				} /* endif */
+
+			}
+			else
+			{
+				ioinfo[irq].ui.flags.w4final = 1;
+				action->handler( irq, action->dev_id, &regs);
+
+			} /* endif */
+
+		} /* endif */
+
+		break;
+
+	case 3:      /* device not operational */
+
+		ioinfo[irq].ui.flags.oper    = 0;
+
+		ioinfo[irq].ui.flags.busy    = 0;
+		ioinfo[irq].ui.flags.doio    = 0;
+		ioinfo[irq].ui.flags.haltio  = 0;
+
+		ioinfo[irq].devstat.cstat    = 0;
+		ioinfo[irq].devstat.dstat    = 0;
+		ioinfo[irq].devstat.flag    |= DEVSTAT_NOT_OPER;
+		ioinfo[irq].devstat.flag    |= DEVSTAT_FINAL_STATUS;
+
+		/*
+		 * When we find a device "not oper" we save the status
+		 *  information into the device status area and call the
+		 *  device specific interrupt handler.
+		 *
+		 * Note: currently we don't have any way to reenable
+		 *       the device unless an unsolicited interrupt
+		 *       is presented. We don't check for spurious
+		 *       interrupts on "not oper" conditions.
+		 */
+
+		if ( ioinfo[irq].ui.flags.fast && ioinfo[irq].ui.flags.w4final )
+		{
+			/*
+			 * If a new request was queued already, we have
+			 *  to simulate the "not oper" status for the
+			 *  queued request by switching the "intparm" value
+			 *  and notify the interrupt handler.
+			 */
+			if ( ioinfo[irq].ui.flags.doio_q )
+			{
+				ioinfo[irq].devstat.intparm   = ioinfo[irq].qintparm;
+
+			} /* endif */
+
+		} /* endif */
+
+		ioinfo[irq].ui.flags.fast    = 0;
+		ioinfo[irq].ui.flags.repall  = 0;
+		ioinfo[irq].ui.flags.w4final = 0;
+
+		memcpy( action->dev_id, &(ioinfo[irq].devstat), sdevstat );
+
+		ioinfo[irq].devstat.intparm  = 0;
+
+		if ( !ioinfo[irq].ui.flags.s_pend )
+		   action->handler( irq, action->dev_id, &regs);
+
+		ending_status    = 1;
+
+		break;
+
+	} /* endswitch */
+
+	return( ending_status );
+}
+
+/*
+ * Set the special i/o-interruption sublass 7 for the
+ *  device specified by parameter irq. There can only
+ *  be a single device been operated on this special
+ *  isc. This function is aimed being able to check
+ *  on special device interrupts in disabled state,
+ *  without having to delay I/O processing (by queueing)
+ *  for non-console devices.
+ *
+ * Setting of this isc is done by set_cons_dev(), while
+ *  reset_cons_dev() resets this isc and re-enables the
+ *  default isc3 for this device. wait_cons_dev() allows
+ *  to actively wait on an interrupt for this device in
+ *  disabed state. When the interrupt condition is
+ *  encountered, wait_cons_dev(9 calls do_IRQ() to have
+ *  the console device driver processing the interrupt.
+ */
+int set_cons_dev( int irq )
+{
+	int           ccode;
+	unsigned long cr6 __attribute__ ((aligned (8)));
+	int           rc = 0;
+
+	if ( cons_dev != -1  )
+	{
+		rc = -EBUSY;
+	}
+	else if ( (irq > highest_subchannel) || (irq < 0) )
+	{
+		rc = -ENODEV;
+	}
+	else
+	{
+		/*
+		 * modify the indicated console device to operate
+		 *  on special console interrupt sublass 7
+		 */
+		ccode = stsch( irq, &(ioinfo[irq].schib) );
+
+		if (ccode)
+		{
+			rc                        = -ENODEV;
+			ioinfo[irq].devstat.flag |= DEVSTAT_NOT_OPER;
+		}
+		else
+		{
+			ioinfo[irq].schib.pmcw.isc = 7;
+
+			ccode = msch( irq, &(ioinfo[irq].schib) );
+
+			if (ccode)
+			{
+				rc = -EIO;
+			}
+			else
+			{
+				cons_dev = irq;
+
+				/*
+				 * enable console I/O-interrupt sublass 7
+				 */
+				asm volatile ("STCTL 6,6,%0": "=m" (cr6));
+				cr6 |= 0x01000000;
+				asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
+
+			} /* endif */
+
+		} /* endif */
+
+	} /* endif */
+
+	return( rc);
+}
+
+int reset_cons_dev( int irq)
+{
+	int     rc = 0;
+	int     ccode;
+	long    cr6 __attribute__ ((aligned (8)));
+
+	if ( cons_dev != -1  )
+	{
+		rc = -EBUSY;
+	}
+	else if ( (irq > highest_subchannel) || (irq < 0) )
+	{
+		rc = -ENODEV;
+	}
+	else
+	{
+		/*
+		 * reset the indicated console device to operate
+		 *  on default console interrupt sublass 3
+		 */
+		ccode = stsch( irq, &(ioinfo[irq].schib) );
+
+		if (ccode)
+		{
+			rc                        = -ENODEV;
+			ioinfo[irq].devstat.flag |= DEVSTAT_NOT_OPER;
+		}
+		else
+		{
+
+			ioinfo[irq].schib.pmcw.isc = 3;
+
+			ccode = msch( irq, &(ioinfo[irq].schib) );
+
+			if (ccode)
+			{
+				rc = -EIO;
+			}
+			else
+			{
+				cons_dev = -1;
+
+				/*
+				 * disable special console I/O-interrupt sublass 7
+				 */
+				asm volatile ("STCTL 6,6,%0": "=m" (cr6));
+				cr6 &= 0xFEFFFFFF;
+				asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
+
+			} /* endif */
+
+		} /* endif */
+
+	} /* endif */
+
+	return( rc);
+}
+
+int wait_cons_dev( int irq )
+{
+	int              rc = 0;
+	long             save_cr6;
+
+	if ( irq == cons_dev )
+	{
+
+		/*
+		 * before entering the spinlock we may already have
+		 *  processed the interrupt on a different CPU ...
+		 */
+		if ( ioinfo[irq].ui.flags.busy == 1 )
+		{
+			long cr6 __attribute__ ((aligned (8)));
+
+			/*
+			 * disable all, but isc 7 (console device)
+			 */
+			asm volatile ("STCTL 6,6,%0": "=m" (cr6));
+			save_cr6  = cr6;
+			cr6      &= 0x01FFFFFF;
+			asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
+
+			do {
+				tpi_info_t tpi_info;
+				if (tpi(&tpi_info) == 1) {
+					s390_process_IRQ(tpi_info.irq,
+					    	         tpi_info.intparm);
+				} else {
+					s390irq_spin_unlock(irq);
+					tod_wait(100);
+					s390irq_spin_lock(irq);
+				}
+				eieio();
+			} while (ioinfo[irq].ui.flags.busy == 1);
+
+			/*
+			 * restore previous isc value
+			 */
+			asm volatile ("STCTL 6,6,%0": "=m" (cr6));
+			cr6 = save_cr6;
+			asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
+
+		} /* endif */
+
+	}
+	else
+	{
+		rc = EINVAL;
+
+	} /* endif */
+
+
+	return(rc);
+}
+
+
+int enable_cpu_sync_isc( int irq )
+{
+	int             ccode;
+	long            cr6 __attribute__ ((aligned (8)));
+
+	int             count = 0;
+	int             rc    = 0;
+
+	if ( irq <= highest_subchannel )
+	{
+		ccode = stsch( irq, &(ioinfo[irq].schib) );
+
+		if ( !ccode )
+		{
+			ioinfo[irq].schib.pmcw.isc = 5;
+
+			do
+			{
+				ccode = msch( irq, &(ioinfo[irq].schib) );
+
+				if (ccode == 0 )
+				{
+					/*
+					 * enable interrupt subclass in CPU
+					 */
+					asm volatile ("STCTL 6,6,%0": "=m" (cr6));
+					cr6 |= 0x04000000;  // enable sync isc 5
+					cr6 &= 0xEFFFFFFF;  // disable standard isc 3
+					asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
+				}
+				else if (ccode == 3)
+				{
+					rc = -ENODEV;  // device not-oper - very unlikely
+
+				}
+				else if (ccode == 2)
+				{
+					rc = -EBUSY;   // device busy - should not happen
+
+				}
+				else if (ccode == 1)
+				{
+					//
+					// process pending status
+					//
+			      ioinfo[irq].ui.flags.s_pend = 1;
+
+					s390_process_IRQ( irq, 0 );
+
+			      ioinfo[irq].ui.flags.s_pend = 0;
+
+					count++;
+
+				} /* endif */
+
+			} while ( ccode == 1 && count < 3 );
+
+			if ( count == 3)
+			{
+				rc = -EIO;
+
+			} /* endif */
+		}
+		else
+		{
+			rc = -ENODEV;     // device is not-operational
+
+		} /* endif */
+	}
+	else
+	{
+		rc = -EINVAL;
+
+	} /* endif */
+
+	return( rc);
+}
+
+int disable_cpu_sync_isc( int irq)
+{
+	int     rc = 0;
+	int     ccode;
+	long    cr6 __attribute__ ((aligned (8)));
+
+	if ( irq <= highest_subchannel )
+	{
+		ccode = stsch( irq, &(ioinfo[irq].schib) );
+
+		ioinfo[irq].schib.pmcw.isc = 3;
+
+		ccode = msch( irq, &(ioinfo[irq].schib) );
+
+		if (ccode)
+		{
+			rc = -EIO;
+		}
+		else
+		{
+
+			/*
+			 * enable interrupt subclass in CPU
+			 */
+			asm volatile ("STCTL 6,6,%0": "=m" (cr6));
+			cr6 &= 0xFBFFFFFF;             // disable sync isc 5
+			cr6 |= 0x10000000;             // enable standard isc 3
+			asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
+
+		} /* endif */
+
+	}
+	else
+	{
+		rc = -EINVAL;
+
+	} /* endif */
+
+	return( rc);
+}
+
+void VM_virtual_device_info( int        devno,   /* device number                 */
+                             senseid_t *ps )     /* pointer to sense ID data area */
+{
+	diag210_t  diag_data;
+	int        ccode;
+
+	int        error = 0;
+
+	diag_data.vrdcdvno = devno;
+	diag_data.vrdclen  = sizeof( diag210_t);
+	ccode              = diag210( (diag210_t *)virt_to_phys( &diag_data ) );
+	ps->reserved       = 0xff;
+
+	switch (diag_data.vrdcvcla) {
+	case 0x80:
+
+		switch (diag_data.vrdcvtyp) {
+		case 00:
+
+			ps->cu_type   = 0x3215;
+
+			break;
+
+		default:
+
+			error = 1;
+
+			break;
+
+		} /* endswitch */
+
+		break;
+
+	case 40:
+
+		switch (diag_data.vrdcvtyp) {
+		case 0xC0:
+
+			ps->cu_type   = 0x5080;
+
+			break;
+
+		case 0x80:
+
+			ps->cu_type   = 0x2250;
+
+			break;
+
+		case 0x04:
+
+			ps->cu_type   = 0x3277;
+
+			break;
+
+		case 0x01:
+
+			ps->cu_type   = 0x3278;
+
+			break;
+
+		default:
+
+			error = 1;
+
+			break;
+
+		} /* endswitch */
+
+		break;
+
+	case 0x20:
+
+		switch (diag_data.vrdcvtyp) {
+		case 0x84:
+
+			ps->cu_type   = 0x3505;
+
+			break;
+
+		case 0x82:
+
+			ps->cu_type   = 0x2540;
+
+			break;
+
+		case 0x81:
+
+			ps->cu_type   = 0x2501;
+
+			break;
+
+		default:
+
+			error = 1;
+
+			break;
+
+		} /* endswitch */
+
+		break;
+
+	case 0x10:
+
+		switch (diag_data.vrdcvtyp) {
+		case 0x84:
+
+			ps->cu_type   = 0x3525;
+
+			break;
+
+		case 0x82:
+
+			ps->cu_type   = 0x2540;
+
+			break;
+
+		case 0x4F:
+		case 0x4E:
+		case 0x48:
+
+			ps->cu_type   = 0x3820;
+
+			break;
+
+		case 0x4D:
+		case 0x49:
+		case 0x45:
+
+			ps->cu_type   = 0x3800;
+
+			break;
+
+		case 0x4B:
+
+			ps->cu_type   = 0x4248;
+
+			break;
+
+		case 0x4A:
+
+			ps->cu_type   = 0x4245;
+
+			break;
+
+		case 0x47:
+
+			ps->cu_type   = 0x3262;
+
+			break;
+
+		case 0x43:
+
+			ps->cu_type   = 0x3203;
+
+			break;
+
+		case 0x42:
+
+			ps->cu_type   = 0x3211;
+
+			break;
+
+		case 0x41:
+
+			ps->cu_type   = 0x1403;
+
+			break;
+
+		default:
+
+			error = 1;
+
+			break;
+
+		} /* endswitch */
+
+		break;
+
+	case 0x08:
+
+		switch (diag_data.vrdcvtyp) {
+		case 0x82:
+
+			ps->cu_type   = 0x3422;
+
+			break;
+
+		case 0x81:
+
+			ps->cu_type   = 0x3490;
+
+			break;
+
+		case 0x10:
+
+			ps->cu_type   = 0x3420;
+
+			break;
+
+		case 0x02:
+
+			ps->cu_type   = 0x3430;
+
+			break;
+
+		case 0x01:
+
+			ps->cu_type   = 0x3480;
+
+			break;
+
+		case 0x42:
+
+			ps->cu_type   = 0x3424;
+
+			break;
+
+		case 0x44:
+
+			ps->cu_type   = 0x9348;
+
+			break;
+
+		default:
+
+			error = 1;
+
+			break;
+
+		} /* endswitch */
+
+		break;
+
+	default:
+
+		error = 1;
+
+		break;
+
+	} /* endswitch */
+
+	if ( error )
+	{printk( "DIAG X'210' for device %04X returned (cc = %d): vdev class : %02X, "
+			"vdev type : %04X \n ...  rdev class : %02X, rdev type : %04X, rdev model: %02X\n",
+			devno,
+			ccode,
+			diag_data.vrdcvcla,
+			diag_data.vrdcvtyp,
+			diag_data.vrdcrccl,
+			diag_data.vrdccrty,
+			diag_data.vrdccrmd );
+
+	} /* endif */
+
+}
+
+/*
+ * This routine returns the characteristics for the device
+ *  specified. Some old devices might not provide the necessary
+ *  command code information during SenseID processing. In this
+ *  case the function returns -EINVAL. Otherwise the function
+ *  allocates a decice specific data buffer and provides the
+ *  device characteristics together with the buffer size. Its
+ *  the callers responability to release the kernel memory if
+ *  not longer needed. In case of persistent I/O problems -EBUSY
+ *  is returned.
+ *
+ *  The function may be called enabled or disabled. However, the
+ *   caller must have locked the irq it is requesting data for.
+ *
+ * Note : It would have been nice to collect this information
+ *         during init_IRQ() processing but this is not possible
+ *
+ *         a) without statically pre-allocation fixed size buffers
+ *            as virtual memory management isn't available yet.
+ *
+ *         b) without unnecessarily increase system startup by
+ *            evaluating devices eventually not used at all.
+ */
+int read_dev_chars( int irq, void **buffer, int length )
+{
+  unsigned int  flags;
+  ccw1_t       *rdc_ccw;
+  devstat_t     devstat;
+  char         *rdc_buf;
+  int           devflag;
+
+  int           ret      = 0;
+  int           emulated = 0;
+  int           retry    = 5;
+
+  if ( !buffer || !length )
+  {
+    return( -EINVAL );
+
+  } /* endif */
+
+  if ( (irq > highest_subchannel) || (irq < 0 ) )
+  {
+    return( -ENODEV );
+
+  } /* endif */
+
+  if ( ioinfo[irq].ui.flags.oper == 0 )
+  {
+    return( -ENODEV );
+
+  } /* endif */
+
+	/*
+	 * Before playing around with irq locks we should assure
+	 *   running disabled on (just) our CPU. Sync. I/O requests
+    *   also require to run disabled.
+	 *
+	 * Note : as no global lock is required, we must not use
+	 *        cli(), but __cli() instead.  	
+	 */
+  __save_flags(flags);
+  __cli();
+
+  rdc_ccw = &ioinfo[irq].senseccw;
+
+  if ( !ioinfo[irq].ui.flags.ready )
+  {
+    ret = request_irq( irq, init_IRQ_handler, 0, "RDC", &devstat );
+
+    if ( !ret )
+    {
+      emulated = 1;
+
+    } /* endif */
+
+  } /* endif */
+
+  if ( !ret )
+  {
+    if ( ! *buffer )
+    {
+      rdc_buf  = kmalloc( length, GFP_KERNEL);
+    }
+    else
+    {
+      rdc_buf = *buffer;
+
+    } /* endif */
+
+    if ( !rdc_buf )
+    {
+       ret = -ENOMEM;
+    }
+    else
+    {
+      do
+      {
+         rdc_ccw->cmd_code = CCW_CMD_RDC;
+         rdc_ccw->cda      = (char *)virt_to_phys( rdc_buf );
+         rdc_ccw->count    = length;
+         rdc_ccw->flags    = CCW_FLAG_SLI;
+
+         ret = s390_start_IO( irq,
+                              rdc_ccw,
+		                        0x00524443, // RDC
+		                        0,          // n/a
+		                        DOIO_WAIT_FOR_INTERRUPT );
+         retry--;
+         devflag = ((devstat_t *)(irq_desc[irq].action->dev_id))->flag;
+
+      } while (    ( retry                                     )
+	             && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) );
+
+    } /* endif */
+
+    if ( !retry )
+    {
+      ret = -EBUSY;
+
+    } /* endif */
+
+    __restore_flags(flags);
+
+    /*
+     * on success we update the user input parms
+     */
+    if ( !ret )
+    {
+      *buffer = rdc_buf;
+
+    } /* endif */
+
+    if ( emulated )
+    {
+      free_irq( irq, &devstat);
+
+    } /* endif */
+
+  } /* endif */
+
+  return( ret );
+}
+
+/*
+ *  Read Configuration data
+ */
+int read_conf_data( int irq, void **buffer, int *length )
+{
+   int          found   = 0;
+   int          ciw_cnt = 0;
+   unsigned int flags;
+
+   int          ret = 0;
+
+   if ( (irq > highest_subchannel) || (irq < 0 ) )
+   {
+      return( -ENODEV );
+
+   } /* endif */
+
+   if ( ioinfo[irq].ui.flags.oper == 0 )
+   {
+      return( -ENODEV );
+
+   } /* endif */
+
+   /*
+    * scan for RCD command in extended SenseID data
+    */
+   for ( ; (found == 0) && (ciw_cnt < 62); ciw_cnt++ )
+   {
+      if ( senseid[irq].ciw[ciw_cnt].ct == CIW_TYPE_RCD )
+      {
+         found = 1;
+      	break;
+      } /* endif */
+
+   } /* endfor */
+
+   if ( found )
+   {
+       ccw1_t    *rcd_ccw = &ioinfo[irq].senseccw;
+       devstat_t  devstat;
+       char      *rcd_buf;
+       int        devflag;
+
+       int        emulated = 0;
+       int        retry    = 5;
+
+   	 __save_flags(flags);
+	    __cli();
+
+       if ( !ioinfo[irq].ui.flags.ready )
+       {
+          ret = request_irq( irq, init_IRQ_handler, 0, "RCD", &devstat );
+
+          if ( !ret )
+          {
+             emulated = 1;
+
+          } /* endif */
+
+       } /* endif */
+
+       if ( !ret )
+       {
+          rcd_buf  = kmalloc( senseid[irq].ciw[ciw_cnt].count, GFP_KERNEL);
+
+          do
+          {
+     		    rcd_ccw->cmd_code = senseid[irq].ciw[ciw_cnt].cmd;
+	   	    rcd_ccw->cda      = (char *)virt_to_phys( rcd_buf );
+             rcd_ccw->count    = senseid[irq].ciw[ciw_cnt].count;
+		       rcd_ccw->flags    = CCW_FLAG_SLI;
+
+             ret = s390_start_IO( irq,
+                                  rcd_ccw,
+                                  0x00524344,  // == RCD
+                                  0,           // n/a
+                                  DOIO_WAIT_FOR_INTERRUPT );
+
+             retry--;
+
+             devflag = ((devstat_t *)(irq_desc[irq].action->dev_id))->flag;
+
+          } while (    ( retry                                     )
+                    && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) );
+
+          if ( !retry )
+             ret = -EBUSY;
+
+          __restore_flags(flags);
+
+       } /* endif */
+
+       /*
+        * on success we update the user input parms
+        */
+       if ( !ret )
+       {
+          *length = senseid[irq].ciw[ciw_cnt].count;
+          *buffer = rcd_buf;
+
+       } /* endif */
+
+       if ( emulated )
+          free_irq( irq, &devstat);
+   }
+   else
+   {
+      ret = -EINVAL;
+
+   } /* endif */
+
+   return( ret );
+
+}
+
+
+int get_dev_info( int irq, dev_info_t *pdi)
+{
+   return( get_dev_info_by_irq( irq, pdi) );
+}
+
+int get_dev_info_by_irq( int irq, dev_info_t *pdi)
+{
+
+	if ( irq > highest_subchannel )
+	{
+		return -ENODEV;
+	}
+	else if ( pdi == NULL )
+	{
+      return -EINVAL;
+	}
+	else
+	{
+	   pdi->devno = ioinfo[irq].schib.pmcw.dev;
+      pdi->irq   = irq;
+
+      if ( ioinfo[irq].ui.flags.oper )
+      {
+		   pdi->status = 0;
+	   	memcpy( &(pdi->sid_data), &senseid[irq], sizeof( senseid_t));
+      }
+      else
+      {
+		   pdi->status = DEVSTAT_NOT_OPER;
+	   	memcpy( &(pdi->sid_data), '\0', sizeof( senseid_t));
+         pdi->sid_data.cu_type = 0xFFFF;
+
+      } /* endif */
+
+		return 0;
+
+	} /* endif */
+
+}
+
+
+int get_dev_info_by_devno( unsigned int devno, dev_info_t *pdi)
+{
+   int i;
+   int rc = -ENODEV;
+
+	if ( devno > 0x0000ffff )
+	{
+		return -ENODEV;
+	}
+	else if ( pdi == NULL )
+	{
+      return -EINVAL;
+	}
+	else
+	{
+
+      for ( i=0; i <= highest_subchannel; i++ )
+      {
+
+         if ( ioinfo[i].schib.pmcw.dev == devno )
+         {
+            if ( ioinfo[i].ui.flags.oper )
+            {
+		         pdi->status = 0;
+               pdi->irq    = i;
+		         pdi->devno  = devno;
+	   	      memcpy( &(pdi->sid_data),
+                       &senseid[i],
+                       sizeof( senseid_t));
+            }
+            else
+            {
+		         pdi->status = DEVSTAT_NOT_OPER;
+               pdi->irq    = i;
+               pdi->devno  = devno;
+	   	      memcpy( &(pdi->sid_data), '\0', sizeof( senseid_t));
+               pdi->sid_data.cu_type = 0xFFFF;
+
+            } /* endif */
+
+            rc = 0; /* found */
+            break;
+
+         } /* endif */
+
+      } /* endfor */
+
+		return( rc);
+
+	} /* endif */
+
+}
+
+int get_irq_by_devno( unsigned int devno )
+{
+   int i;
+   int rc = -1;
+
+	if ( devno <= 0x0000ffff )
+	{
+      for ( i=0; i <= highest_subchannel; i++ )
+      {
+         if ( devno == ioinfo[i].schib.pmcw.dev )
+         {
+            rc = i;
+            break;
+
+         } /* endif */
+
+      } /* endfor */
+
+	} /* endif */
+
+   return( rc);
+
+}
+
+unsigned int get_devno_by_irq( int irq )
+{
+
+	if ( irq > highest_subchannel )
+	{
+		return -1;
+
+	} /* endif */
+
+   /*
+    * we don't need to check for the device be operational
+    *  as the initial STSCH will always present the device
+    *  number defined by the IOCDS regardless of the device
+    *  existing or not.
+    */
+   return( ioinfo[irq].schib.pmcw.dev );
+
+}
+
+/*
+ * s390_device_recognition
+ *
+ * Used for system wide device recognition. Issues the device
+ *  independant SenseID command to obtain info the device type.
+ *
+ */
+void s390_device_recognition( void)
+{
+
+	int irq = 0; /* let's start with subchannel 0 ... */
+
+	do
+	{
+      /*
+       * We issue the SenseID command on I/O subchannels we think are
+       *  operational only.
+       */
+      if ( 	  ( schiblock[irq].pmcw.st == 0    )
+           && ( ioinfo[irq].ui.flags.oper == 1 ) )
+      {
+         s390_SenseID( irq, &senseid[irq] );
+
+      } /* endif */
+
+		irq ++;
+
+	} while ( irq <= highest_subchannel );
+
+}
+
+
+/*
+ * s390_search_devices
+ *
+ * Determines all subchannels available to the system.
+ *
+ */
+void s390_process_subchannels( void)
+{
+   int   isValid;
+
+	int   irq = 0;   /* Evaluate all subchannels starting with 0 ... */
+
+	do
+	{
+		isValid = s390_validate_subchannel( irq);
+
+      irq++;
+
+	} while ( isValid && irq < NR_IRQS );
+
+	highest_subchannel = --irq;
+
+	printk( "\nHighest subchannel number detected: %u\n",
+	        highest_subchannel);
+}
+
+/*
+ * s390_validate_subchannel()
+ *
+ * Process the subchannel for the requested irq. Returns 1 for valid
+ *  subchannels, otherwise 0.
+ */
+int s390_validate_subchannel( int irq )
+{
+
+   int   retry;     /* retry count for status pending conditions */
+	int   ccode;     /* condition code for stsch() only */
+	int   ccode2;    /* condition code for other I/O routines */
+
+	/*
+	 * The first subchannel that is not-operational (ccode==3)
+	 *  indicates that there aren't any more devices available.
+	 */
+	ccode = stsch( irq, &schiblock[irq]);
+
+   if ( ccode == 0)
+   {
+   	/*
+	    * ... just being curious we check for non I/O subchannels
+		 */
+		if ( schiblock[irq].pmcw.st )
+		{
+			printk( "Subchannel %04X reports "
+			        "non-I/O subchannel type %04X\n",
+			        irq,
+			        schiblock[irq].pmcw.st);
+
+			ioinfo[irq].ui.flags.oper = 0;
+
+		} /* endif */
+
+		if ( !schiblock[irq].pmcw.dnv )
+		{
+			/*
+			 * don't process invalid device numbers ...
+			 */
+			ioinfo[irq].ui.flags.oper = 0;
+		}
+		else
+		{
+			printk( "Detected device %04X on subchannel %04X"
+			        " - PIM = %02X, PAM = %02X, POM = %02X\n",
+			        schiblock[irq].pmcw.dev,
+			        irq,
+			        schiblock[irq].pmcw.pim,
+			        schiblock[irq].pmcw.pam,
+			        schiblock[irq].pmcw.pom);
+
+			/*
+			 * We now have to initially ...
+			 *  ... set "interruption sublass"
+			 *  ... enable "concurrent sense"
+			 *  ... enable "multipath mode" if more than
+			 *        one CHPID is available
+			 *
+			 * Note : we don't enable the device here, this is temporarily
+			 *        done during device sensing below.
+			 */
+			schiblock[irq].pmcw.isc    = 3;     /* could be smth. else ... */
+			schiblock[irq].pmcw.csense = 1;     /* concurrent sense */
+			schiblock[irq].pmcw.ena    = 0;     /* force disable it */
+
+			if (    ( schiblock[irq].pmcw.pim != 0    )
+			     && ( schiblock[irq].pmcw.pim != 0x80 ) )
+			{
+				schiblock[irq].pmcw.mp     = 1;     /* multipath mode */
+
+			} /* endif */
+
+			/*
+			 * initialize ioinfo structure
+		    */
+			ioinfo[irq].irq             = irq;
+			ioinfo[irq].ui.flags.busy   = 0;
+			ioinfo[irq].ui.flags.ready  = 0;
+			ioinfo[irq].ui.flags.oper   = 1;
+			ioinfo[irq].devstat.intparm = irq;
+			ioinfo[irq].devstat.devno   = schiblock[irq].pmcw.dev;
+
+			memcpy( &(ioinfo[irq].schib), &(schiblock[irq]), sizeof( schib_t));
+
+         retry = 5;
+
+         do
+			{
+			   ccode2 = msch_err( irq, &schiblock[irq]);
+
+            switch (ccode2) {
+            case 0:  // successful completion
+			      //
+				   // concurrent sense facility available ...
+				   //
+				   ioinfo[irq].ui.flags.consns = 1;
+               break;
+
+            case 1:  // status pending
+               //
+               // How can we have a pending status as device is
+               //  disabled for interrupts ? Anyway, clear it ...
+               //
+		         tsch( irq, &(ioinfo[irq].devstat.ii.irb) );
+               retry--;
+               break;
+
+            case 2:  // busy
+               retry--;
+               break;
+
+            case 3:  // not operational
+				   ioinfo[irq].ui.flags.oper = 0;
+               retry                     = 0;
+               break;
+
+            default:
+#define PGMCHK_OPERAND_EXC      0x15
+
+				   if ( (ccode2 & PGMCHK_OPERAND_EXC) == PGMCHK_OPERAND_EXC )
+				   {
+						/*
+						 * re-issue the modify subchannel without trying to
+						 *  enable the concurrent sense facility
+						 */
+						schiblock[irq].pmcw.csense = 0;
+
+						memcpy( &(ioinfo[irq].schib),
+						        &(schiblock[irq]),
+						        sizeof( schib_t));
+
+						ccode2 = msch_err( irq, &schiblock[irq]);
+
+						if ( ccode2 != 0 )
+						{
+						   printk( " ... modify subchannel (2) failed with CC = %X\n",
+						           ccode2 );
+						   ioinfo[irq].ui.flags.oper = 0;
+						}
+						else
+						{
+						   ioinfo[irq].ui.flags.consns = 0;
+
+						} /* endif */
+					}
+					else
+					{
+						printk( " ... modify subchannel (1) failed with CC = %X\n",
+						        ccode2);
+						ioinfo[irq].ui.flags.oper = 0;
+
+					} /* endif */
+
+					retry  = 0;
+					break;
+
+				} /* endswitch */
+
+			} while ( ccode2 && retry );
+
+         if ( (ccode2 < 3) && (!retry) )
+         {
+			   printk( " ... msch() retry count for "
+                    "subchannel %04X exceeded, CC = %d\n",
+                    irq,
+                    ccode2);
+
+         } /* endif */
+
+      } /* endif */
+
+   } /* endif */
+
+   /*
+	 * indicate whether the subchannel is valid
+    */
+   if ( ccode == 3)
+      return(0);
+   else
+      return(1);
+}
+
+/*
+ * s390_SenseID
+ *
+ * Try to obtain the 'control unit'/'device type' information
+ *  associated with the subchannel.
+ *
+ * The function is primarily meant to be called without irq
+ *  action handler in place. However, it also allows for
+ *  use with an action handler in place. If there is already
+ *  an action handler registered assure it can handle the
+ *  s390_SenseID() related device interrupts - interruption
+ *  parameter used is 0x00E2C9C4 ( SID ).
+ */
+int s390_SenseID( int irq, senseid_t *sid )
+{
+	ccw1_t     sense_ccw;   /* ccw area for SenseID command */
+   devstat_t  devstat;     /* required by request_irq() */
+
+   int        irq_ret = 0; /* return code */
+   int        retry   = 5; /* retry count */
+   int        inlreq  = 0; /* inline request_irq() */
+
+	if ( (irq > highest_subchannel) || (irq < 0 ) )
+	{
+		return( -ENODEV );
+
+	} /* endif */
+
+	if ( ioinfo[irq].ui.flags.oper == 0 )
+	{
+		return( -ENODEV );
+
+	} /* endif */
+
+	if ( !ioinfo[irq].ui.flags.ready )
+	{
+		/*
+		 * Perform SENSE ID command processing. We have to request device
+		 *  ownership and provide a dummy I/O handler. We issue sync. I/O
+       *  requests and evaluate the devstat area on return therefore
+       *  we don't need a real I/O handler in place.
+       */
+		irq_ret = request_irq( irq, init_IRQ_handler, 0, "SID", &devstat);
+
+		if ( irq_ret == 0 )
+			inlreq = 1;
+
+	} /* endif */
+
+	if ( irq_ret == 0 )
+   {
+		s390irq_spin_lock( irq);
+
+		sense_ccw.cmd_code = CCW_CMD_SENSE_ID;
+		sense_ccw.cda      = (char *)virt_to_phys( sid );
+		sense_ccw.count    = sizeof( senseid_t);
+		sense_ccw.flags    = CCW_FLAG_SLI;
+
+		senseid[irq].cu_type    = 0xFFFF;  /* initialize fields ... */
+		senseid[irq].cu_model   = 0;
+		senseid[irq].dev_type   = 0;
+		senseid[irq].dev_model  = 0;
+
+		/*
+		 * We now issue a SenseID request. In case of BUSY
+		 *  or STATUS PENDING conditions we retry 5 times.
+		 */
+		do
+		{
+			memset( &devstat, '\0', sizeof( devstat_t) );
+
+			irq_ret = s390_start_IO( irq,
+			                         &sense_ccw,
+			                         0x00E2C9C4,  // == SID
+			                         0,           // n/a
+			                         DOIO_WAIT_FOR_INTERRUPT );
+
+			if ( sid->cu_type == 0xFFFF )
+			{
+				if ( devstat.flag & DEVSTAT_STATUS_PENDING )
+				{
+#if CONFIG_DEBUG_IO
+					printk( "Device %04X on Subchannel %04X "
+					        "reports pending status, retry : %d\n",
+					        schiblock[irq].pmcw.dev,
+					        irq,
+					        retry);
+#endif
+				} /* endif */
+
+				if ( devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL )
+				{
+					/*
+					 * if the device doesn't support the SenseID
+					 *  command further retries wouldn't help ...
+					 */
+					if ( devstat.ii.sense.data[0] == SNS0_CMD_REJECT )
+					{
+						retry = 0;
+					}
+#if CONFIG_DEBUG_IO
+					else
+					{
+						printk( "Device %04X,"
+						        " UC/SenseID,"
+						        " retry %d, cnt %02d,"
+						        " sns :"
+						        " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+						        schiblock[irq].pmcw.dev,
+						        retry,
+						        devstat.scnt,
+						        devstat.ii.sense.data[0],
+						        devstat.ii.sense.data[1],
+						        devstat.ii.sense.data[2],
+						        devstat.ii.sense.data[3],
+						        devstat.ii.sense.data[4],
+						        devstat.ii.sense.data[5],
+						        devstat.ii.sense.data[6],
+						        devstat.ii.sense.data[7]);
+
+					} /* endif */
+#endif
+				}
+				else if ( devstat.flag & DEVSTAT_NOT_OPER )
+				{
+					printk( "Device %04X on Subchannel %04X "
+					        "became 'not operational'\n",
+					        schiblock[irq].pmcw.dev,
+					        irq);
+
+					retry = 0;
+
+				} /* endif */
+			}
+			else   // we got it ...
+			{
+				retry = 0;
+
+			} /* endif */
+
+			retry--;
+
+		} while ( retry > 0 );
+
+		s390irq_spin_unlock( irq);
+
+		/*
+		 * If we installed the irq action handler we have to
+		 *  release it too.
+		 */
+		if ( inlreq )
+			free_irq( irq, &devstat);
+
+		/*
+		 * if running under VM check there ... perhaps we should do
+		 *  only if we suffered a command reject, but it doesn't harm
+		 */
+		if (    ( sid->cu_type == 0xFFFF )
+		     && ( MACHINE_IS_VM              ) )
+		{
+			VM_virtual_device_info( schiblock[irq].pmcw.dev,
+			                        sid );
+		} /* endif */
+
+		if ( sid->cu_type == 0xFFFF )
+		{
+			/*
+			 * SenseID CU-type of 0xffff indicates that no device
+			 *  information could be retrieved (pre-init value).
+			 *
+			 * If we can't couldn't identify the device type we
+			 *  consider the device "not operational".
+			 */
+			printk( "Unknown device %04X on subchannel %04X\n",
+			        schiblock[irq].pmcw.dev,
+			        irq);
+			ioinfo[irq].ui.flags.oper = 0;
+
+		} /* endif */
+
+		/*
+		 * Issue device info message if unit was operational .
+		 */
+		if ( ioinfo[irq].ui.flags.oper )
+		{
+			if ( sid->dev_type != 0 )
+			{
+				printk( "Device %04X reports: CU  Type/Mod = %04X/%02X,"
+				        " Dev Type/Mod = %04X/%02X\n",
+				        schiblock[irq].pmcw.dev,
+				        sid->cu_type,
+				        sid->cu_model,
+				        sid->dev_type,
+				        sid->dev_model);
+			}
+			else
+			{
+				printk( "Device %04X reports:"
+				        " Dev Type/Mod = %04X/%02X\n",
+				        schiblock[irq].pmcw.dev,
+				        sid->cu_type,
+				        sid->cu_model);
+
+			} /* endif */
+
+		} /* endif */
+
+		if ( ioinfo[irq].ui.flags.oper )
+			irq_ret = 0;
+		else
+			irq_ret = -ENODEV;
+
+	} /* endif */
+
+   return( irq_ret );
+}
+
+void do_crw_pending(void)
+{
+}
+#ifdef CONFIG_READIPL_ENABLED
+void 
+do_reipl ( int sch ) 
+{
+	static ccw1_t iplccw[2] = {
+		{ CCW_CMD_READ_IPL, CCW_FLAG_CC, 24, 0x00000000 },
+		{ CCW_CMD_TIC     , CCW_FLAG_CC,  0, 0x00000008 }
+	};
+	static orb_t  iplorb = {
+	  0,
+	};
+	static psw_t psw_0 = {0,};
+	static long cr6_0 = 0x0;
+	static psw_t psw_1 = {0,};
+	static long cr6_1 = 0x0;
+        int i;
+
+	/* First disable all Devices/IRQs */
+	for ( i = 0; i < highest_subchannel; i ++ ) {
+	  free_irq ( i, (void*)REIPL_DEVID_MAGIC );
+	}
+	/* re enable the one device */
+	enable_subchannel (sch);
+	__asm__ __volatile__ ( "spx 0" );
+	__asm__ __volatile__ ( "lpsw %0" ::  "m" (psw_0) ); /* disable all */
+	__asm__ __volatile__ ( "lctl 6,6,%0" : : "m" (cr6_0) ); 
+	__asm__ __volatile__ ( "lr 1,%0\n" 
+			       "ssch %1\n"
+			       :: "d" (sch), "m" (iplorb) : "1" );
+	__asm__ __volatile__ ( "lctl 6,6,%0" :: "m" (cr6_1) );
+	__asm__ __volatile__ ( "lpsw %0" ::  "m" (psw_1) );
+	__asm__ __volatile__ ( "lpsw 0" ); /* restart */
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/s390io.h linux.14p16/arch/s390/kernel/s390io.h
--- linux.vanilla/arch/s390/kernel/s390io.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/s390io.h	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,72 @@
+/*
+ *  arch/s390/kernel/s390io.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Ingo Adlung (adlung@de.ibm.com)
+ */
+
+#ifndef __s390io_h
+#define __s390io_h
+
+/*
+ * Private data structure used by do_IO()
+ *
+ * Note : If bit flags are added, the "unused" value must be
+ *        decremented accordingly !
+ */
+typedef struct {
+      unsigned int  irq;           /* aka. subchannel number */
+      union {
+         unsigned int info;
+         struct {
+            unsigned int  busy      : 1;  /* device currently in use */
+            unsigned int  oper      : 1;  /* device is operational */
+            unsigned int  fast      : 1;  /* post with "channel end", ...    */
+                                          /* ... don't wait for "device end" */
+                                          /* ... from do_IO() parameters     */
+            unsigned int  ready     : 1;  /* interrupt handler registered */
+            unsigned int  haltio    : 1;  /* halt_IO in process */
+            unsigned int  doio      : 1;  /* do_IO in process */
+            unsigned int  doio_q    : 1;  /* do_IO queued - only possible ... */
+                                          /* ... if 'fast' is set too */
+            unsigned int  w4final   : 1;  /* wait for final status, internally */
+                                          /* ... used with 'fast' setting only */
+            unsigned int  repall    : 1;  /* report every interrupt status */
+            unsigned int  unready   : 1;  /* deregister irq handler in process */
+            unsigned int  d_disable : 1;  /* delayed disabling required */
+            unsigned int  w4sense   : 1;  /* SENSE status pending */
+            unsigned int  syncio    : 1;  /* synchronous I/O requested */
+            unsigned int  consns    : 1;  /* concurrent sense is available */
+            unsigned int  delsense  : 1;  /* delayed SENSE required */
+            unsigned int  s_pend    : 1;  /* status pending condition */
+            unsigned int  unused    : 16; /* unused */
+               } __attribute__ ((packed)) flags;
+         } ui;
+      unsigned int  lpm;           /* logical path mask to be used ... */
+                                   /* ... from do_IO() parms. Only ... */
+                                   /* ... valid if vlpm is set too.    */
+      schib_t       schib;         /* subchannel information block */
+      orb_t         orb;           /* operation request block */
+      devstat_t     devstat;       /* device status */
+      ccw1_t       *qcpa;          /* queued channel program */
+      ccw1_t        senseccw;      /* ccw for sense command */
+      unsigned int  stctl;         /* accumulated status control from irb */
+      unsigned int  qintparm;      /* queued interruption parameter  */
+      unsigned long qflag;         /* queued flags */
+      unsigned char qlpm;          /* queued logical path mask */
+
+   } __attribute__ ((aligned(8))) ioinfo_t;
+
+#define IOINFO_FLAGS_BUSY    0x80000000
+#define IOINFO_FLAGS_OPER    0x40000000
+#define IOINFO_FLAGS_FAST    0x20000000
+#define IOINFO_FLAGS_READY   0x10000000
+#define IOINFO_FLAGS_HALTIO  0x08000000
+#define IOINFO_FLAGS_DOIO    0x04000000
+#define IOINFO_FLAGS_DOIO_Q  0x02000000
+#define IOINFO_FLAGS_W4FINAL 0x01000000
+#define IOINFO_FLAGS_REPALL  0x00800000
+
+#endif  /* __s390io_h */
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/s390ksyms.c linux.14p16/arch/s390/kernel/s390ksyms.c
--- linux.vanilla/arch/s390/kernel/s390ksyms.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/s390ksyms.c	Wed Dec 15 22:27:44 1999
@@ -0,0 +1,22 @@
+/*
+ *  arch/s390/kernel/s390ksyms.c
+ *
+ *  S390 version
+ */
+
+#include "irq.h"
+#include "asm/string.h"
+
+EXPORT_SYMBOL(get_dev_info_by_irq);
+EXPORT_SYMBOL(get_dev_info_by_devno);
+EXPORT_SYMBOL(get_irq_by_devno);
+EXPORT_SYMBOL(get_devno_by_irq);
+EXPORT_SYMBOL(halt_IO);
+EXPORT_SYMBOL(irq_desc);
+EXPORT_SYMBOL(do_IO);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(init_mm);
+EXPORT_SYMBOL(_oi_bitmap);
+EXPORT_SYMBOL(_ni_bitmap);
+EXPORT_SYMBOL(_zb_findmap);
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/setup.c linux.14p16/arch/s390/kernel/setup.c
--- linux.vanilla/arch/s390/kernel/setup.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/setup.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,308 @@
+/*
+ *  arch/s390/kernel/setup.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Hartmut Penner (hp@de.ibm.com),
+ *               Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *  Derived from "arch/i386/kernel/setup.c"
+ *    Copyright (C) 1995, Linus Torvalds
+ */
+
+/*
+ * This file handles the architecture-dependent parts of initialization
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#ifdef CONFIG_BLK_DEV_RAM
+#include <linux/blk.h>
+#endif
+#include <linux/console.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/smp.h>
+
+/*
+ * Machine setup..
+ */
+__u16 boot_cpu_addr;
+int cpus_initialized = 0;
+unsigned long cpu_initialized = 0;
+
+/*
+ * Setup options
+ */
+
+#ifdef CONFIG_BLK_DEV_RAM
+extern int rd_doload;                  /* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt;           /* 1 = prompt for ramdisk, 0 = don't prompt*/
+extern int rd_image_start;             /* starting block # of image        */
+#endif
+
+extern int root_mountflags;
+extern int _etext, _edata, _end;
+
+
+/*
+ * This is set up by the setup-routine at boot-time
+ * for S390 need to find out, what we have to setup
+ * using address 0x10400 ...
+ */
+
+#include <asm/setup.h>
+
+static char command_line[COMMAND_LINE_SIZE] = { 0, };
+       char saved_command_line[COMMAND_LINE_SIZE];
+
+/*
+ * cpu_init() initializes state that is per-CPU.
+ */
+void cpu_init (void)
+{
+        int nr = smp_processor_id();
+
+        if (test_and_set_bit(nr,&cpu_initialized)) {
+                printk("CPU#%d ALREADY INITIALIZED!!!!!!!!!\n", nr);
+                for (;;) __sti();
+        }
+        cpus_initialized++;
+
+        /*
+         * Store processor id in lowcore (used e.g. in timer_interrupt)
+         */
+        asm volatile ("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id));
+        S390_lowcore.cpu_data.cpu_addr = hard_smp_processor_id();
+        S390_lowcore.cpu_data.cpu_nr = nr;
+
+        /*
+         * Force FPU initialization:
+         */
+        current->flags &= ~PF_USEDFPU;
+        current->used_math = 0;
+}
+
+/*
+ * Reboot, halt and power_off routines for non SMP.
+ */
+#ifndef __SMP__
+void machine_restart(char * __unused)
+{
+        if (MACHINE_IS_VM) {
+                cpcmd("IPL", NULL, 0);
+        } else {
+                /* FIXME: how to reipl ? */
+                disabled_wait(2);
+        }
+}
+
+void machine_halt(void)
+{
+        if (MACHINE_IS_VM) {
+                cpcmd("IPL 200 STOP", NULL, 0);
+        } else {
+                disabled_wait(0);
+        }
+}
+
+void machine_power_off(void)
+{
+        if (MACHINE_IS_VM) {
+                cpcmd("IPL CMS", NULL, 0);
+        } else {
+                disabled_wait(0);
+        }
+}
+#endif
+
+/*
+ * Waits for 'delay' microseconds using the tod clock
+ */
+void tod_wait(unsigned long delay)
+{
+        uint64_t start_cc, end_cc;
+
+	if (delay == 0)
+		return;
+        asm volatile ("STCK %0" : "=m" (start_cc));
+	do {
+		asm volatile ("STCK %0" : "=m" (end_cc));
+	} while (((end_cc - start_cc)/4096) < delay);
+}
+
+/*
+ * Setup function called from init/main.c just after the banner
+ * was printed.
+ */
+__initfunc(void setup_arch(char **cmdline_p,
+        unsigned long * memory_start_p, unsigned long * memory_end_p))
+{
+        unsigned long memory_start, memory_end;
+        char c = ' ', *to = command_line, *from = COMMAND_LINE;
+        static unsigned int smptrap=0;
+        unsigned long delay = 0;
+        int len = 0;
+
+        if (smptrap)
+                return;
+        smptrap=1;
+
+        printk("Command line is: %s\n", COMMAND_LINE);
+
+        /*
+         * Setup lowcore information for boot cpu
+         */
+        cpu_init();
+        boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
+
+        /*
+         * print what head.S has found out about the machine 
+         */
+        if (MACHINE_IS_VM)
+                printk("We are running under VM\n");
+        else
+                printk("We are running native\n");
+        if (MACHINE_HAS_IEEE)
+                printk("This machine has an IEEE fpu\n");
+        else
+                printk("This machine has no IEEE fpu\n");
+
+        ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
+#ifdef CONFIG_BLK_DEV_RAM
+        rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
+        rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
+        rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
+#endif
+	/* nasty stuff with PARMAREAs. we use head.S or parameterline
+	  if (!MOUNT_ROOT_RDONLY)
+	  root_mountflags &= ~MS_RDONLY;
+	*/
+        memory_start = (unsigned long) &_end;    /* fixit if use $CODELO etc*/
+	memory_end = MEMORY_SIZE;
+        init_task.mm->start_code = PAGE_OFFSET;
+        init_task.mm->end_code = (unsigned long) &_etext;
+        init_task.mm->end_data = (unsigned long) &_edata;
+        init_task.mm->brk = (unsigned long) &_end;
+
+        /* Save unparsed command line copy for /proc/cmdline */
+        memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
+        saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
+
+        for (;;) {
+                /*
+                 * "mem=XXX[kKmM]" sets memsize != 32M
+                 * memory size
+                 */
+                if (c == ' ' && strncmp(from, "mem=", 4) == 0) {
+                        if (to != command_line) to--;
+                        memory_end = simple_strtoul(from+4, &from, 0);
+                        if ( *from == 'K' || *from == 'k' ) {
+                                memory_end = memory_end << 10;
+                                from++;
+                        } else if ( *from == 'M' || *from == 'm' ) {
+                                memory_end = memory_end << 20;
+                                from++;
+                        }
+                }
+                if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) {
+			if (to != command_line) to--;
+                        delay = simple_strtoul(from+9, &from, 0);
+			if (*from == 's' || *from == 'S') {
+				delay = delay*1000000;
+				from++;
+			} else if (*from == 'm' || *from == 'M') {
+				delay = delay*60*1000000;
+				from++;
+			}
+			tod_wait(delay);
+                }
+                c = *(from++);
+                if (!c)
+                        break;
+                if (COMMAND_LINE_SIZE <= ++len)
+                        break;
+                *(to++) = c;
+        }
+        *to = '\0';
+        *cmdline_p = command_line;
+        memory_end += PAGE_OFFSET;
+        *memory_start_p = memory_start;
+        *memory_end_p = memory_end;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+        initrd_start = INITRD_START;
+        if (initrd_start) {
+                initrd_end = initrd_start+INITRD_SIZE;
+                printk("Initial ramdisk at: 0x%p (%lu bytes)\n",
+                       (void *) initrd_start, INITRD_SIZE);
+                initrd_below_start_ok = 1;
+                if (initrd_end > *memory_end_p) {
+                        printk("initrd extends beyond end of memory "
+                               "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+                               initrd_end, (unsigned long) memory_end_p);
+                        initrd_start = initrd_end = 0;
+                }
+        }
+#endif
+
+}
+
+void print_cpu_info(struct cpuinfo_S390 *cpuinfo)
+{
+   printk("cpu %d "
+#ifdef __SMP__
+           "phys_idx=%d "
+#endif
+           "vers=%02X ident=%06X machine=%04X unused=%04X\n",
+           cpuinfo->cpu_nr,
+#ifdef __SMP__
+           cpuinfo->cpu_addr,
+#endif
+           cpuinfo->cpu_id.version,
+           cpuinfo->cpu_id.ident,
+           cpuinfo->cpu_id.machine,
+           cpuinfo->cpu_id.unused);
+}
+
+/*
+ *	Get CPU information for use by the procfs.
+ */
+
+int get_cpuinfo(char * buffer)
+{
+        struct cpuinfo_S390 *cpuinfo;
+        char *p = buffer;
+        int i;
+
+        p += sprintf(p,"vendor_id       : IBM/S390\n"
+                       "# processors    : %i\n"
+                       "bogomips per cpu: %lu.%02lu\n",
+                       smp_num_cpus, loops_per_sec/500000,
+                       (loops_per_sec/5000)%100);
+        for (i = 0; i < smp_num_cpus; i++) {
+                cpuinfo = &safe_get_cpu_lowcore(i).cpu_data;
+                p += sprintf(p,"processor %i: "
+                               "version = %02X,  "
+                               "identification = %06X,  "
+                               "machine = %04X\n",
+                               i, cpuinfo->cpu_id.version,
+                               cpuinfo->cpu_id.ident,
+                               cpuinfo->cpu_id.machine);
+        }
+        return p - buffer;
+}
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/signal.c linux.14p16/arch/s390/kernel/signal.c
--- linux.vanilla/arch/s390/kernel/signal.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/signal.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,519 @@
+/*
+ *  arch/s390/kernel/signal.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *
+ *  based on PPC & i386 signal handling by  Linus Torvalds &  Gary Thomas 
+ *
+ *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#if CONFIG_BINFMT_TOC
+#include <linux/toc.h>
+#endif
+/*
+ * These are the flags in the MSR that the user is allowed to change
+ * by modifying the saved value of the MSR on the stack.  SE and BE
+ * should not be in this list since gdb may want to change these.  I.e,
+ * you should be able to step out of a signal handler to see what
+ * instruction executes next after the signal handler completes.
+ * Alternately, if you stepped into a signal handler, you should be
+ * able to continue 'til the next breakpoint from within the signal
+ * handler, even if the handler returns.
+ */
+
+
+#define __390_TO_DO__    0
+#define __390_NEEDED__   0 
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+int do_signal(struct pt_regs *reg,sigset_t *oldset);
+extern int sys_wait4(pid_t pid, unsigned long *stat_addr,
+		     int options, unsigned long *ru);
+
+
+
+
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int sys_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t mask)
+{
+	sigset_t saveset;
+
+	mask &= _BLOCKABLE;
+	spin_lock_irq(&current->sigmask_lock);
+	saveset = current->blocked;
+	siginitset(&current->blocked, mask);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+	regs->gprs[2] = -EINTR;
+
+	while (1) 
+	  {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(regs, &saveset))
+			return -EINTR;
+	  }
+}
+
+
+//
+// N.B. This hasn't been tested it just compiles easily
+//
+asmlinkage int sys_rt_sigsuspend(struct pt_regs * regs,sigset_t *unewset, size_t sigsetsize)
+{
+	sigset_t saveset, newset;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset_t))
+		return -EINVAL;
+
+	if (copy_from_user(&newset, unewset, sizeof(newset)))
+		return -EFAULT;
+	sigdelsetmask(&newset, ~_BLOCKABLE);
+
+	spin_lock_irq(&current->sigmask_lock);
+	saveset = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+	regs->gprs[2]	= -EINTR;
+	while (1) 
+	  {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(regs, &saveset))
+			return -EINTR;
+	  }
+}
+
+asmlinkage int sys_rt_sigreturn(unsigned long __unused)
+{
+	printk("sys_rt_sigreturn(): %s/%d not yet implemented.\n",
+	       current->comm,current->pid);
+	do_exit(SIGSEGV);
+}
+
+asmlinkage int
+sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+{
+	struct pt_regs *regs = (struct pt_regs *) &uss;
+	return do_sigaltstack(uss, uoss, regs->gprs[15]);
+}
+
+
+asmlinkage int sys_sigaction(int sig, const struct old_sigaction *act,struct old_sigaction *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+
+	if (act) 
+	  {
+		old_sigset_t mask;
+		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+			return -EFAULT;
+		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		__get_user(mask, &act->sa_mask);
+		siginitset(&new_ka.sa.sa_mask, mask);
+	  }
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) 
+	  {
+		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+
+
+		    __put_user((u32)old_ka.sa.sa_handler,&oact->sa_handler) ||
+		    __put_user((u32)old_ka.sa.sa_restorer, &oact->sa_restorer))
+			return -EFAULT;
+		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+	  }
+	return ret;
+}
+
+/*
+ * When we have signals to deliver, we set up on the
+ * user stack, going down from the original stack pointer:
+ *	a sigregs struct
+ *	one or more sigcontext structs
+ *	a gap of __SIGNAL_FRAMESIZE bytes
+ *
+ * Each of these things must be a multiple of 16 bytes in size.
+ *
+ * XXX ultimately we will have to stack up a siginfo and ucontext
+ * for each rt signal.
+ */
+
+struct sigregs {
+	user_regs_struct user_regs;
+
+        unsigned short   tramp[1];
+        /* Programs using the rs6000/xcoff abi can save up to 19 gp regs
+           and 18 fp regs below sp before decrementing it. */
+};   
+
+
+int sys_sigreturn(struct pt_regs *regs)
+{
+	struct sigcontext_struct *sc, sigctx;
+	struct sigregs *sr;
+	int ret;
+        user_regs_struct saved_regs;  
+	sigset_t set;
+	unsigned long prevsp;
+	routine_descriptor tempdes;
+
+	sc = (struct sigcontext_struct *)(regs->gprs[15] + __SIGNAL_FRAMESIZE);
+	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
+		goto badframe;
+	memcpy(&set.sig[0],&sigctx.oldmask[0],SIGMASK_COPY_SIZE);
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = set;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	sc++;			/* Look at next sigcontext */
+	if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
+		/* Last stacked signal - restore registers */
+		sr = (struct sigregs *) sigctx.regs;
+		if (copy_from_user(&saved_regs, &sr->user_regs,
+				   sizeof(sr->user_regs)))
+			goto badframe;
+		saved_regs.psw.mask=(regs->psw.mask&~PSW_MASK_DEBUGCHANGE)
+			|(saved_regs.psw.mask&PSW_MASK_DEBUGCHANGE);
+		saved_regs.psw.addr=(regs->psw.addr&~PSW_ADDR_DEBUGCHANGE)
+			|(saved_regs.psw.addr&PSW_ADDR_DEBUGCHANGE);
+		memcpy(regs,&saved_regs,sizeof(s390_regs));
+		restore_fp_regs(&saved_regs.fp_regs);
+		ret = regs->gprs[2];
+
+	} else {
+		/* More signals to go */
+		regs->gprs[15] = (unsigned long)sc - __SIGNAL_FRAMESIZE;
+		if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
+			goto badframe;
+		sr = (struct sigregs *) sigctx.regs;
+		regs->gprs[2] = ret = sigctx.signal;
+#if DEBUG_SIG
+		regs->gprs[3] = (unsigned long) sr; // My best guess says this is used for debugging only DJB
+#endif
+		regs->gprs[14] = (unsigned long) sr->tramp; // return address
+		
+		if(uses_routine_descriptors())
+		{
+		   if(copy_from_user(&tempdes,(char *)sigctx.handler,sizeof(tempdes)))
+		      goto badframe;
+		   fix_routine_descriptor_regs(&tempdes,regs);
+		}
+		else
+		   regs->psw.addr = FIX_PSW(sigctx.handler);
+
+		if (get_user(prevsp, &sr->user_regs.gprs[15])
+		    || put_user(prevsp, (unsigned long *) regs->gprs[15]))
+			goto badframe;
+	}
+	return ret;
+
+badframe:
+	lock_kernel();
+	do_exit(SIGSEGV);
+}	
+
+
+/*
+ * Set up a signal frame.
+ */
+void setup_frame(struct pt_regs *regs, struct sigregs *frame,unsigned long newsp)
+{
+	struct sigcontext_struct *sc = (struct sigcontext_struct *) newsp;
+	s390_fp_regs fpregs;
+
+	routine_descriptor tempdes,*tempdesptr;
+
+	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto badframe;
+	save_fp_regs(&fpregs);
+	if (__copy_to_user(&frame->user_regs, regs, sizeof(s390_regs))
+	    || __copy_to_user(&frame->user_regs.fp_regs,&fpregs,sizeof(fpregs))
+	    || __put_user(0x0A77, &frame->tramp[0]))    /* SVC 0x77 */
+		goto badframe;
+	newsp -= __SIGNAL_FRAMESIZE;
+	if (put_user(regs->gprs[15], (unsigned long *)newsp) || get_user(regs->gprs[2], &sc->signal))
+		goto badframe;
+
+	if(uses_routine_descriptors())
+	{
+	    if(get_user(tempdesptr, (routine_descriptor **)& sc->handler)
+	       || copy_from_user(&tempdes,tempdesptr,sizeof(tempdes)))
+	       goto badframe;
+	    fix_routine_descriptor_regs(&tempdes,regs);
+	}
+	else
+	{
+	   if(get_user(regs->psw.addr, (void **) & sc->handler))
+		goto badframe;
+	   regs->psw.addr=FIX_PSW(regs->psw.addr);
+	}
+	regs->gprs[15] = newsp;
+#if DEBUG_SIG
+	regs->gprs[3] = (unsigned long) frame;
+#endif
+	regs->gprs[14] = (unsigned long) frame->tramp;
+
+	return;
+
+badframe:
+#if DEBUG_SIG
+	printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n",
+	       regs, frame, newsp);
+#endif
+	lock_kernel();
+	do_exit(SIGSEGV);
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+void
+handle_signal(unsigned long sig, struct k_sigaction *ka,
+	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
+	      unsigned long *newspp, unsigned long frame)
+{
+	struct sigcontext_struct *sc;
+
+	if (regs->trap == 0x20) /* System Call! */
+	{
+		switch(regs->gprs[2])
+		{
+		case -ERESTARTNOHAND:
+				regs->gprs[2] = -EINTR;
+				break;
+		case -ERESTARTSYS:
+			if (!(ka->sa.sa_flags & SA_RESTART)) 
+			{
+				regs->gprs[2] = -EINTR;
+				break;
+			}
+			/* fallthrough */
+		case -ERESTARTNOINTR:
+			regs->gprs[2] = regs->orig_gpr2;
+			regs->psw.addr -= 2;	      
+                        /* Back up & retry system call */
+		}
+	}
+	/* Put another sigcontext on the stack */
+	*newspp -= sizeof(*sc);
+	sc = (struct sigcontext_struct *) *newspp;
+	if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
+		goto badframe;
+
+	if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
+	    || copy_to_user(&sc->oldmask[0],&oldset->sig[0],SIGMASK_COPY_SIZE)
+	    || __put_user((u32)((struct pt_regs *)frame), &sc->regs)
+	    || __put_user(sig, &sc->signal))
+		goto badframe;
+
+	if (ka->sa.sa_flags & SA_ONESHOT)
+		ka->sa.sa_handler = SIG_DFL;
+
+	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+		spin_lock_irq(&current->sigmask_lock);
+		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigaddset(&current->blocked,sig);
+		recalc_sigpending(current);
+		spin_unlock_irq(&current->sigmask_lock);
+	}
+	return;
+
+badframe:
+#if DEBUG_SIG
+	printk("badframe in handle_signal, regs=%p frame=%lx newsp=%lx\n",
+	       regs, frame, *newspp);
+	printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset);
+#endif
+	lock_kernel();
+	do_exit(SIGSEGV);
+}
+
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+int do_signal(struct pt_regs *regs,sigset_t *oldset)
+{
+	siginfo_t info;
+	struct k_sigaction *ka;
+	unsigned long frame, newsp;
+
+	if (!oldset)
+		oldset = &current->blocked;
+
+	newsp = frame = regs->gprs[15] - sizeof(struct sigregs);
+
+	for (;;) {
+		unsigned long signr;
+
+		spin_lock_irq(&current->sigmask_lock);
+		signr = dequeue_signal(&current->blocked, &info);
+		spin_unlock_irq(&current->sigmask_lock);
+
+		if (!signr)
+			break;
+
+		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+			/* Let the debugger run.  */
+			current->exit_code = signr;
+			current->state = TASK_STOPPED;
+			notify_parent(current, SIGCHLD);
+			schedule();
+
+			/* We're back.  Did the debugger cancel the sig?  */
+			if (!(signr = current->exit_code))
+				continue;
+			current->exit_code = 0;
+
+			/* The debugger continued.  Ignore SIGSTOP.  */
+			if (signr == SIGSTOP)
+				continue;
+
+			/* Update the siginfo structure.  Is this good?  */
+			if (signr != info.si_signo) {
+				info.si_signo = signr;
+				info.si_errno = 0;
+				info.si_code = SI_USER;
+				info.si_pid = current->p_pptr->pid;
+				info.si_uid = current->p_pptr->uid;
+			}
+
+			/* If the (new) signal is now blocked, requeue it.  */
+			if (sigismember(&current->blocked, signr)) {
+				send_sig_info(signr, &info, current);
+				continue;
+			}
+		}
+
+		ka = &current->sig->action[signr-1];
+		if (ka->sa.sa_handler == SIG_IGN) {
+			if (signr != SIGCHLD)
+				continue;
+			/* Check for SIGCHLD: it's special.  */
+			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+				/* nothing */;
+			continue;
+		}
+
+		if (ka->sa.sa_handler == SIG_DFL) {
+			int exit_code = signr;
+
+			/* Init gets no signals it doesn't want.  */
+			if (current->pid == 1)
+				continue;
+
+			switch (signr) {
+			case SIGCONT: case SIGCHLD: case SIGWINCH:
+				continue;
+
+			case SIGTSTP: case SIGTTIN: case SIGTTOU:
+				if (is_orphaned_pgrp(current->pgrp))
+					continue;
+				/* FALLTHRU */
+
+			case SIGSTOP:
+				current->state = TASK_STOPPED;
+				current->exit_code = signr;
+				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+					notify_parent(current, SIGCHLD);
+				schedule();
+				continue;
+
+			case SIGQUIT: case SIGILL: case SIGTRAP:
+			case SIGABRT: case SIGFPE: case SIGSEGV:
+				lock_kernel();
+				if (current->binfmt
+				    && current->binfmt->core_dump
+				    && current->binfmt->core_dump(signr, regs))
+					exit_code |= 0x80;
+				unlock_kernel();
+				/* FALLTHRU */
+
+			default:
+				lock_kernel();
+				sigaddset(&current->signal, signr);
+				recalc_sigpending(current);
+				current->flags |= PF_SIGNALED;
+				do_exit(exit_code);
+				/* NOTREACHED */
+			}
+		}
+
+		/* Whee!  Actually deliver the signal.  */
+		handle_signal(signr, ka, &info, oldset, regs, &newsp, frame);
+	}
+
+	if (
+	    regs->trap == 0x20 /* System Call! */ &&
+	    ((int)regs->gprs[2] == -ERESTARTNOHAND ||
+	     (int)regs->gprs[2] == -ERESTARTSYS ||
+	     (int)regs->gprs[2] == -ERESTARTNOINTR)) {
+		regs->gprs[2] = regs->orig_gpr2;
+		regs->psw.addr -= 2;	      /* Back up & retry system call */
+	}
+
+	if (newsp == frame)
+		return 0;		/* no signals delivered */
+
+	setup_frame(regs, (struct sigregs *) frame, newsp);
+	return 1;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/smp.c linux.14p16/arch/s390/kernel/smp.c
--- linux.vanilla/arch/s390/kernel/smp.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/smp.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,693 @@
+/*
+ *  arch/s390/kernel/smp.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *               Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *  based on other smp stuff by 
+ *    (c) 1995 Alan Cox, CymruNET Ltd  <alan@cymru.net>
+ *    (c) 1998 Ingo Molnar
+ *
+ * We work with logical cpu numbering everywhere we can. The only
+ * functions using the real cpu address (got from STAP) are the sigp
+ * functions. For all other functions we use the identity mapping.
+ * That means that cpu_number_map[i] == i for every cpu. cpu_number_map is
+ * used e.g. to find the idle task belonging to a logical cpu. Every array
+ * in the kernel is sorted by the logical cpu number and not by the physical
+ * one which is causing all the confusion with __cpu_logical_map and
+ * cpu_number_map in other architectures.
+ */
+
+#include <asm/sigp.h>
+#include <asm/timex.h>
+#include <asm/init.h>
+#include <asm/spinlock.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/smp.h>
+#include <linux/mm.h>
+#include <asm/pgtable.h>
+#include <asm/string.h>
+
+#include "cpcmd.h"
+#include "irq.h"
+
+/* prototypes */
+extern void update_one_process( struct task_struct *p,
+                                unsigned long ticks, unsigned long user,
+                                unsigned long system, int cpu);
+extern int cpu_idle(void * unused);
+
+extern __u16 boot_cpu_addr;
+
+/*
+ * An array with a pointer the lowcore of every CPU.
+ */
+static int       max_cpus = NR_CPUS;	  /* Setup configured maximum number of CPUs to activate	*/
+int              smp_num_cpus;
+struct _lowcore *lowcore_ptr[NR_CPUS];
+unsigned int     prof_multiplier[NR_CPUS];
+unsigned int     prof_counter[NR_CPUS];
+volatile int     cpu_number_map[NR_CPUS];
+volatile int     __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
+cycles_t         cacheflush_time=0;
+int              smp_threads_ready=0;      /* Set when the idlers are all forked. */
+unsigned long    ipi_count=0;              /* Number of IPIs delivered. */
+static atomic_t  smp_commenced = ATOMIC_INIT(0);
+
+spinlock_t       kernel_flag = SPIN_LOCK_UNLOCKED;
+
+/*
+ *      Setup routine for controlling SMP activation
+ *
+ *      Command-line option of "nosmp" or "maxcpus=0" will disable SMP
+ *      activation entirely (the MPS table probe still happens, though).
+ *
+ *      Command-line option of "maxcpus=<NUM>", where <NUM> is an integer
+ *      greater than 0, limits the maximum number of CPUs activated in
+ *      SMP mode to <NUM>.
+ */
+
+void __init smp_setup(char *str, int *ints)
+{
+   if (ints && ints[0] > 0)
+      max_cpus = ints[1];
+   else
+      max_cpus = 0;
+}
+
+/*
+ * Reboot, halt and power_off routines for SMP.
+ */
+void do_machine_restart(void)
+{
+        smp_send_stop();
+        if (MACHINE_IS_VM) {
+                cpcmd("IPL", NULL, 0);
+        } else {
+                /* FIXME: how to reipl ? */
+                disabled_wait(2);
+        }
+}
+
+void machine_restart(char * __unused) 
+{
+        if (smp_processor_id() != 0) {
+                smp_ext_call_async(0, ec_restart);
+                for (;;);
+        } else
+                do_machine_restart();
+}
+
+void do_machine_halt(void)
+{
+        smp_send_stop();
+        if (MACHINE_IS_VM) {
+                cpcmd("IPL CMS", NULL, 0);
+        } else {
+                disabled_wait(0);
+        }
+}
+
+void machine_halt(void)
+{
+        if (smp_processor_id() != 0) {
+                smp_ext_call_async(0, ec_halt);
+                for (;;);
+        } else
+                do_machine_halt();
+}
+
+void do_machine_power_off(void)
+{
+        smp_send_stop();
+        if (MACHINE_IS_VM) {
+                cpcmd("IPL CMS", NULL, 0);
+        } else {
+                disabled_wait(0);
+        }
+}
+
+void machine_power_off(void)
+{
+        if (smp_processor_id() != 0) {
+                smp_ext_call_async(0, ec_power_off);
+                for (;;);
+        } else
+                do_machine_power_off();
+}
+
+/*
+ * This is the main routine where commands issued by other
+ * cpus are handled.
+ */
+
+void do_ext_call_interrupt(__u16 source_cpu_addr)
+{
+        ec_ext_call *ec, *next;
+        int bits;
+
+        /*
+         * handle bit signal external calls
+         *
+         * For the ec_schedule signal we have to do nothing. All the work
+         * is done automatically when we return from the interrupt.
+	 * For the ec_restart, ec_halt and ec_power_off we call the
+         * appropriate routine.
+         */
+        do {
+                bits = atomic_read(&S390_lowcore.ext_call_fast);
+        } while (atomic_compare_and_swap(bits,0,&S390_lowcore.ext_call_fast));
+
+        if (test_bit(ec_restart, &bits))
+		do_machine_restart();
+        if (test_bit(ec_halt, &bits))
+		do_machine_halt();
+        if (test_bit(ec_power_off, &bits))
+		do_machine_power_off();
+
+        /*
+         * Handle external call commands with a parameter area
+         */
+        do {
+                ec = (ec_ext_call *) atomic_read(&S390_lowcore.ext_call_queue);
+        } while (atomic_compare_and_swap((int) ec, 0,
+                                         &S390_lowcore.ext_call_queue));
+        if (ec == NULL)
+                return;   /* no command signals */
+
+        /* Make a fifo out of the lifo */
+        next = ec;
+        ec->next = NULL;
+        while (next != NULL) {
+                ec_ext_call *tmp = next->next;
+                next->next = ec;
+                ec = next;
+                next = tmp;
+        }
+
+        /* Execute every sigp command on the queue */
+        while (ec != NULL) {
+                switch (ec->cmd) {
+                case ec_get_ctl: {
+                        ec_creg_parms *pp;
+                        pp = (ec_creg_parms *) ec->parms;
+                        atomic_set(&ec->status,ec_executing);
+                        asm volatile (
+                                "   bras  1,0f\n"
+                                "   stctl 0,0,0(%0)\n"
+                                "0: ex    %1,0(1)\n"
+                                : : "a" (pp->cregs+pp->start_ctl),
+                                "a" ((pp->start_ctl<<4) + pp->end_ctl)
+                                : "memory", "1" );
+                        atomic_set(&ec->status,ec_done);
+                        return;
+                }
+                case ec_set_ctl: {
+                        ec_creg_parms *pp;
+                        pp = (ec_creg_parms *) ec->parms;
+                        atomic_set(&ec->status,ec_executing);
+                        asm volatile (
+                                "   bras  1,0f\n"
+                                "   lctl 0,0,0(%0)\n"
+                                "0: ex    %1,0(1)\n"
+                                : : "a" (pp->cregs+pp->start_ctl),
+                                "a" ((pp->start_ctl<<4) + pp->end_ctl)
+                                : "memory", "1" );
+                        atomic_set(&ec->status,ec_done);
+                        return;
+                }
+                case ec_set_ctl_masked: {
+                        ec_creg_mask_parms *pp;
+                        u32 cregs[16];
+                        int i;
+
+                        pp = (ec_creg_mask_parms *) ec->parms;
+                        atomic_set(&ec->status,ec_executing);
+                        asm volatile (
+                                "   bras  1,0f\n"
+                                "   stctl 0,0,0(%0)\n"
+                                "0: ex    %1,0(1)\n"
+                                : : "a" (cregs+pp->start_ctl),
+                                "a" ((pp->start_ctl<<4) + pp->end_ctl)
+                                : "memory", "1" );
+                        for (i = pp->start_ctl; i <= pp->end_ctl; i++)
+                                cregs[i] = (cregs[i] & pp->andvals[i])
+                                                     | pp->orvals[i];
+                        asm volatile (
+                                "   bras  1,0f\n"
+                                "   lctl 0,0,0(%0)\n"
+                                "0: ex    %1,0(1)\n"
+                                : : "a" (cregs+pp->start_ctl),
+                                "a" ((pp->start_ctl<<4) + pp->end_ctl)
+                                : "memory", "1" );
+                        atomic_set(&ec->status,ec_done);
+                        return;
+                }
+                default:
+                }
+                ec = ec->next;
+        }
+}
+
+/*
+ * Send an external call sigp to another cpu and wait for its completion.
+ */
+sigp_ccode smp_ext_call_sync(int cpu, ec_cmd_sig cmd, void *parms)
+{
+        struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
+        sigp_ccode ccode;
+        ec_ext_call ec;
+
+        ec.cmd = cmd;
+        atomic_set(&ec.status, ec_pending);
+        ec.parms = parms;
+        do {
+                ec.next = (ec_ext_call*) atomic_read(&lowcore->ext_call_queue);
+        } while (atomic_compare_and_swap((int) ec.next, (int)(&ec),
+                                         &lowcore->ext_call_queue));
+        /*
+         * We try once to deliver the signal. There are four possible
+         * return codes:
+         * 0) Order code accepted - can't show up on an external call
+         * 1) Status stored - fine, wait for completion.
+         * 2) Busy - there is another signal pending. Thats fine too, because
+         *    do_ext_call from the pending signal will execute all signals on
+         *    the queue. We wait for completion.
+         * 3) Not operational - something very bad has happened to the cpu.
+         *    do not wait for completion.
+         */
+        ccode = signal_processor(cpu, sigp_external_call);
+
+        if (ccode != sigp_not_operational)
+                /* wait for completion, FIXME: possible seed of a deadlock */
+                while (atomic_read(&ec.status) != ec_done);
+
+        return ccode;
+}
+
+/*
+ * Send an external call sigp to another cpu and return without waiting
+ * for its completion. Currently we do not support parameters with
+ * asynchronous sigps.
+ */
+sigp_ccode smp_ext_call_async(int cpu, ec_bit_sig sig)
+{
+        struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
+        sigp_ccode ccode;
+
+        /*
+         * Set signaling bit in lowcore of target cpu and kick it
+         */
+        atomic_set_mask(1<<sig, &lowcore->ext_call_fast);
+        ccode = signal_processor(cpu, sigp_external_call);
+        return ccode;
+}
+
+/*
+ * Send an external call sigp to every other cpu in the system and
+ * wait for the completion of the sigps.
+ */
+void smp_ext_call_sync_others(ec_cmd_sig cmd, void *parms)
+{
+        struct _lowcore *lowcore;
+        ec_ext_call ec[NR_CPUS];
+        sigp_ccode ccode;
+        int i;
+
+        for (i = 0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() == i)
+                        continue;
+                lowcore = &get_cpu_lowcore(i);
+                ec[i].cmd = cmd;
+                atomic_set(&ec[i].status, ec_pending);
+                ec[i].parms = parms;
+                do {
+                        ec[i].next = (ec_ext_call *)
+                                        atomic_read(&lowcore->ext_call_queue);
+                } while (atomic_compare_and_swap((int) ec[i].next, (int)(ec+i),
+                                                 &lowcore->ext_call_queue));
+                ccode = signal_processor(i, sigp_external_call);
+        }
+
+        /* wait for completion, FIXME: possible seed of a deadlock */
+        for (i = 0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() == i)
+                        continue;
+                while (atomic_read(&ec[i].status) != ec_done);
+        }
+}
+
+/*
+ * Send an external call sigp to every other cpu in the system and
+ * return without waiting for the completion of the sigps. Currently
+ * we do not support parameters with asynchronous sigps.
+ */
+void smp_ext_call_async_others(ec_bit_sig sig)
+{
+        struct _lowcore *lowcore;
+        sigp_ccode ccode;
+        int i;
+
+        for (i = 0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() == i)
+                        continue;
+                lowcore = &get_cpu_lowcore(i);
+                /*
+                 * Set signaling bit in lowcore of target cpu and kick it
+                 */
+                atomic_set_mask(1<<sig, &lowcore->ext_call_fast);
+                ccode = signal_processor(i, sigp_external_call);
+        }
+}
+
+/*
+ * cycles through all the cpus,
+ * returns early if info is not NULL & the processor has something
+ * of intrest to report in the info structure.
+ * it returns the next cpu to check if it returns early.
+ * i.e. it should be used as follows if you wish to receive info.
+ * next_cpu=0;
+ * do
+ * {
+ *    info->cpu=next_cpu;
+ *    next_cpu=smp_signal_others(order_code,parameter,TRUE,info);
+ *    ... check info here
+ * } while(next_cpu<=smp_num_cpus)
+ *
+ *  if you are lazy just use it like
+ * smp_signal_others(order_code,parameter,0,TRUE,NULL);
+ */
+int smp_signal_others(sigp_order_code order_code, u32 parameter,
+                      int spin, sigp_info *info)
+{
+        sigp_ccode   ccode;
+        u32          dummy;
+        u16          i;
+
+        if (info)
+                info->intresting = FALSE;
+        for (i = (info ? info->cpu : 0); i < smp_num_cpus; i++) {
+                if (smp_processor_id() != i) {
+                        do {
+                                ccode = signal_processor_ps(
+                                        (info ? &info->status : &dummy),
+                                        parameter, i, order_code);
+                        } while(spin && ccode == sigp_busy);
+                        if (info && ccode != sigp_order_code_accepted) {
+                                info->intresting = TRUE;
+                                info->cpu = i;
+                                info->ccode = ccode;
+                                i++;
+                                break;
+                        }
+                }
+        }
+        return i;
+}
+
+/*
+ * this function sends a 'stop' sigp to all other CPUs in the system.
+ * it goes straight through.
+ */
+
+void smp_send_stop(void)
+{
+        smp_signal_others(sigp_stop, 0, TRUE, NULL);
+}
+
+/*
+ * this function sends a 'reschedule' IPI to another CPU.
+ * it goes straight through and wastes no time serializing
+ * anything. Worst case is that we lose a reschedule ...
+ */
+
+void smp_send_reschedule(int cpu)
+{
+        smp_ext_call_async(cpu, ec_schedule);
+}
+
+/*
+ * Set a bit in a control register of all cpus
+ */
+void smp_ctl_set_bit(int cr, int bit) {
+        ec_creg_mask_parms parms;
+
+        if (atomic_read(&smp_commenced) != 0) {
+                parms.start_ctl = cr;
+                parms.end_ctl = cr;
+                parms.orvals[cr] = 1 << bit;
+                parms.andvals[cr] = 0xFFFFFFFF;
+                smp_ext_call_sync_others(ec_set_ctl_masked,&parms);
+        }
+        __ctl_set_bit(cr, bit);
+}
+
+/*
+ * Clear a bit in a control register of all cpus
+ */
+void smp_ctl_clear_bit(int cr, int bit) {
+        ec_creg_mask_parms parms;
+
+        if (atomic_read(&smp_commenced) != 0) {
+                parms.start_ctl = cr;
+                parms.end_ctl = cr;
+                parms.orvals[cr] = 0x00000000;
+                parms.andvals[cr] = ~(1 << bit);
+                smp_ext_call_sync_others(ec_set_ctl_masked,&parms);
+        }
+        __ctl_clear_bit(cr, bit);
+}
+
+
+/*
+ * Lets check how many CPUs we have.
+ */
+
+void smp_count_cpus(void)
+{
+        int curr_cpu;
+
+        __cpu_logical_map[0] = boot_cpu_addr;
+        current->processor = 0;
+        smp_num_cpus = 1;
+        for (curr_cpu = 0;
+             curr_cpu <= 65535 && smp_num_cpus < max_cpus; curr_cpu++) {
+                if ((__u16) curr_cpu == boot_cpu_addr)
+                        continue;
+                __cpu_logical_map[smp_num_cpus] = (__u16) curr_cpu;
+                if (signal_processor(smp_num_cpus, sigp_sense) ==
+                    sigp_not_operational)
+                        continue;
+                smp_num_cpus++;
+        }
+        printk("Detected %d CPU's\n",(int) smp_num_cpus);
+        printk("Boot cpu address %2X\n", boot_cpu_addr);
+}
+
+
+/*
+ *      Activate a secondary processor.
+ */
+extern void init_100hz_timer(void);
+
+int __init start_secondary(void *cpuvoid)
+{
+        cpu_init();
+        print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id()).cpu_data);
+        while (!atomic_read(&smp_commenced))
+                /* nothing */ ;
+        init_100hz_timer();
+        return cpu_idle(NULL);
+}
+
+/*
+ * The restart interrupt handler jumps to start_secondary directly
+ * without the detour over initialize_secondary. We defined it here
+ * so that the linker doesn't complain.
+ */
+void __init initialize_secondary(void)
+{
+}
+
+static void __init do_boot_cpu(int cpu)
+{
+        struct task_struct *idle;
+        struct _lowcore    *cpu_lowcore;
+        /*
+         *	We need an idle process for each processor.
+         */
+        
+        kernel_thread(start_secondary,(void *)cpu, CLONE_PID);
+        idle = task[cpu];
+        if (!idle)
+                panic("No idle process for CPU %d",cpu);
+        idle->processor = cpu;
+        cpu_number_map[cpu] = cpu;
+        cpu_lowcore=&get_cpu_lowcore(cpu);
+        cpu_lowcore->kernel_stack=idle->tss.ksp;
+        __asm__ __volatile__("stctl 0,15,%0\n\t"
+                             "stam  0,15,%1"
+                             : "=m" (cpu_lowcore->cregs_save_area[0]), 
+                               "=m" (cpu_lowcore->access_regs_save_area[0])
+                             : : "memory");
+        
+        eieio();
+        signal_processor(cpu,sigp_restart);
+}
+
+/*
+ *      Architecture specific routine called by the kernel just before init is
+ *      fired off. This allows the BP to have everything in order [we hope].
+ *      At the end of this all the APs will hit the system scheduling and off
+ *      we go. Each AP will load the system gdt's and jump through the kernel
+ *      init into idle(). At this point the scheduler will one day take over
+ *      and give them jobs to do. smp_callin is a standard routine
+ *      we use to track CPUs as they power up.
+ */
+
+void __init smp_commence(void)
+{
+        /*
+         *      Lets the callins below out of their loop.
+         */
+        atomic_set(&smp_commenced,1);
+}
+
+/*
+ *	Cycle through the processors sending APIC IPIs to boot each.
+ */
+
+void __init smp_boot_cpus(void)
+{
+        struct _lowcore *curr_lowcore;
+        sigp_ccode   ccode;
+        int curr_cpu;
+        int i;
+        
+        smp_count_cpus();
+        memset(lowcore_ptr,0,sizeof(lowcore_ptr));  
+        
+        /*
+         *      Initialize the logical to physical CPU number mapping
+         *      and the per-CPU profiling counter/multiplier
+         */
+        
+        for (i = 0; i < NR_CPUS; i++) {
+                cpu_number_map[i] = -1;
+                prof_counter[i] = 1;
+                prof_multiplier[i] = 1;
+        }
+
+        cpu_number_map[0] = 0;
+	print_cpu_info(&safe_get_cpu_lowcore(0).cpu_data);
+
+        for(curr_cpu = 0; curr_cpu < smp_num_cpus; curr_cpu++)
+        {
+                curr_lowcore = (struct _lowcore *)
+                                    __get_free_page(GFP_KERNEL|GFP_DMA);
+                if (curr_lowcore == NULL) {
+                        printk("smp_boot_cpus failed to allocate prefix memory\n"); 
+                        break;
+                }
+                lowcore_ptr[curr_cpu] = curr_lowcore;
+                memcpy(curr_lowcore, &S390_lowcore, sizeof(struct _lowcore));
+                /*
+                 * Most of the parameters are set up when the cpu is
+                 * started up.
+                 */
+                if(smp_processor_id()==curr_cpu)
+                        set_prefix((u32)curr_lowcore);
+                else {
+                        ccode=signal_processor_p((u32)(curr_lowcore),
+                                                 curr_cpu,sigp_set_prefix);
+                        if(ccode) {
+                                /* if this gets troublesome I'll have to do 
+                                 * something about it. */
+                                printk("ccode %d for cpu %d  returned when "
+                                       "setting prefix in smp_boot_cpus not good.\n",
+                                       (int)ccode,(int)curr_cpu);
+                        }
+                        else
+                                do_boot_cpu(curr_cpu);
+                }
+        }
+}
+
+/*
+ * the frequency of the profiling timer can be changed
+ * by writing a multiplier value into /proc/profile.
+ *
+ * usually you want to run this on all CPUs ;)
+ */
+int setup_profiling_timer(unsigned int multiplier)
+{
+        return 0;
+}
+
+/*
+ * Local timer interrupt handler. It does both profiling and
+ * process statistics/rescheduling.
+ *
+ * We do profiling in every local tick, statistics/rescheduling
+ * happen only every 'profiling multiplier' ticks. The default
+ * multiplier is 1 and it can be changed by writing the new multiplier
+ * value into /proc/profile.
+ */
+
+void smp_local_timer_interrupt(struct pt_regs * regs)
+{
+        int cpu = smp_processor_id();
+
+        /*
+         * The profiling function is SMP safe. (nothing can mess
+         * around with "current", and the profiling counters are
+         * updated with atomic operations). This is especially
+         * useful with a profiling multiplier != 1
+         */
+        if (!user_mode(regs))
+                s390_do_profile(regs->psw.addr);
+
+        if (!--prof_counter[cpu]) {
+                int user=0,system=0;
+                struct task_struct * p = current;
+
+                /*
+                 * After doing the above, we need to make like
+                 * a normal interrupt - otherwise timer interrupts
+                 * ignore the global interrupt lock, which is the
+                 * WrongThing (tm) to do.
+                 */
+
+                if (user_mode(regs))
+                        user=1;
+                else
+                        system=1;
+
+                irq_enter(cpu, 0);
+                update_one_process(p, 1, user, system, cpu);
+                if (p->pid) {
+                        p->counter -= 1;
+                        if (p->counter < 0) {
+                                p->counter = 0;
+                                p->need_resched = 1;
+                        }
+                        if (p->priority < DEF_PRIORITY) {
+                                kstat.cpu_nice += user;
+                                kstat.per_cpu_nice[cpu] += user;
+                        } else {
+                                kstat.cpu_user += user;
+                                kstat.per_cpu_user[cpu] += user;
+                        }
+                        kstat.cpu_system += system;
+                        kstat.per_cpu_system[cpu] += system;
+
+                }
+                prof_counter[cpu]=prof_multiplier[cpu];
+                irq_exit(cpu, 0);
+        }
+}
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/sys_s390.c linux.14p16/arch/s390/kernel/sys_s390.c
--- linux.vanilla/arch/s390/kernel/sys_s390.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/sys_s390.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,225 @@
+/*
+ *  arch/s390/kernel/sys_s390.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ *  Derived from "arch/i386/kernel/sys_i386.c"
+ *
+ *  This file contains various random system calls that
+ *  have a non-standard calling sequence on the Linux/s390
+ *  platform.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+#include <linux/utsname.h>
+
+#include <asm/uaccess.h>
+#include <asm/ipc.h>
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way Unix traditionally does this, though.
+ */
+asmlinkage int sys_pipe(unsigned long * fildes)
+{
+	int fd[2];
+	int error;
+
+	lock_kernel();
+	error = do_pipe(fd);
+	unlock_kernel();
+	if (!error) {
+		if (copy_to_user(fildes, fd, 2*sizeof(int)))
+			error = -EFAULT;
+	}
+	return error;
+}
+
+/*
+ * Perform the select(nd, in, out, ex, tv) and mmap() system
+ * calls. Linux/i386 didn't use to be able to handle more than
+ * 4 system call parameters, so these system calls used a memory
+ * block for parameter passing..
+ */
+
+struct mmap_arg_struct {
+	unsigned long addr;
+	unsigned long len;
+	unsigned long prot;
+	unsigned long flags;
+	unsigned long fd;
+	unsigned long offset;
+};
+
+asmlinkage int old_mmap(struct mmap_arg_struct *arg)
+{
+	int error = -EFAULT;
+	struct file * file = NULL;
+	struct mmap_arg_struct a;
+
+	if (copy_from_user(&a, arg, sizeof(a)))
+		return -EFAULT;
+
+	down(&current->mm->mmap_sem);
+	lock_kernel();
+	if (!(a.flags & MAP_ANONYMOUS)) {
+		error = -EBADF;
+		file = fget(a.fd);
+		if (!file)
+			goto out;
+	}
+	a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+	error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
+	if (file)
+		fput(file);
+out:
+	unlock_kernel();
+	up(&current->mm->mmap_sem);
+	return error;
+}
+
+extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+
+struct sel_arg_struct {
+	unsigned long n;
+	fd_set *inp, *outp, *exp;
+	struct timeval *tvp;
+};
+
+asmlinkage int old_select(struct sel_arg_struct *arg)
+{
+	struct sel_arg_struct a;
+
+	if (copy_from_user(&a, arg, sizeof(a)))
+		return -EFAULT;
+	/* sys_select() does the appropriate kernel locking */
+	return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+asmlinkage int sys_ipc (uint call, int first, int second, 
+                        int third, void *ptr, long fifth)
+{
+	int ret;
+
+        switch (call) {
+        case SEMOP:
+                return sys_semop (first, (struct sembuf *)ptr, second);
+        case SEMGET:
+                return sys_semget (first, second, third);
+        case SEMCTL: {
+                union semun fourth;
+                if (!ptr)
+                        return -EINVAL;
+                if (get_user(fourth.__pad, (void **) ptr))
+                        return -EFAULT;
+                return sys_semctl (first, second, third, fourth);
+        } 
+        case MSGSND:
+		return sys_msgsnd (first, (struct msgbuf *) ptr, 
+                                   second, third);
+		break;
+        case MSGRCV:
+                return sys_msgrcv (first, 
+                                   (struct msgbuf *) ptr,
+                                   second, fifth, third);
+        case MSGGET:
+                return sys_msgget ((key_t) first, second);
+        case MSGCTL:
+                return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+                
+	case SHMAT: {
+		ulong raddr;
+		ret = sys_shmat (first, (char *) ptr, second, &raddr);
+		if (ret)
+			return ret;
+		return put_user (raddr, (ulong *) third);
+		break;
+        }
+	case SHMDT: 
+		return sys_shmdt ((char *)ptr);
+	case SHMGET:
+		return sys_shmget (first, second, third);
+	case SHMCTL:
+		return sys_shmctl (first, second,
+                                   (struct shmid_ds *) ptr);
+	default:
+		return -EINVAL;
+
+	}
+        
+	return -EINVAL;
+}
+
+/*
+ * Old cruft
+ */
+asmlinkage int sys_uname(struct old_utsname * name)
+{
+	int err;
+	if (!name)
+		return -EFAULT;
+	down(&uts_sem);
+	err=copy_to_user(name, &system_utsname, sizeof (*name));
+	up(&uts_sem);
+	return err?-EFAULT:0;
+}
+
+asmlinkage int sys_olduname(struct oldold_utsname * name)
+{
+	int error;
+
+	if (!name)
+		return -EFAULT;
+	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+		return -EFAULT;
+  
+  	down(&uts_sem);
+	
+	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+	error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
+	error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+	error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
+	error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+	error |= __put_user(0,name->release+__OLD_UTS_LEN);
+	error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+	error |= __put_user(0,name->version+__OLD_UTS_LEN);
+	error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
+	error |= __put_user(0,name->machine+__OLD_UTS_LEN);
+	
+	up(&uts_sem);
+	
+	error = error ? -EFAULT : 0;
+
+	return error;
+}
+
+asmlinkage int sys_pause(void)
+{
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	return -ERESTARTNOHAND;
+}
+
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
+{
+  return -ENOSYS;
+}
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/time.c linux.14p16/arch/s390/kernel/time.c
--- linux.vanilla/arch/s390/kernel/time.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/time.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,250 @@
+/*
+ *  arch/s390/kernel/time.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Hartmut Penner (hp@de.ibm.com),
+ *               Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *
+ *  Derived from "arch/i386/kernel/time.c"
+ *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/types.h>
+
+#include <asm/uaccess.h>
+#include <asm/delay.h>
+
+#include <linux/mc146818rtc.h>
+#include <linux/timex.h>
+#include <linux/config.h>
+
+#include "irq.h"
+
+
+extern volatile unsigned long lost_ticks;
+
+/* change this if you have some constant time drift */
+#define USECS_PER_JIFFY ((signed long)1000000/HZ)
+#define CLK_TICKS_PER_JIFFY ((signed long)USECS_PER_JIFFY<<12)
+
+#define TICK_SIZE tick
+
+static uint64_t init_timer_cc, last_timer_cc;
+
+extern rwlock_t xtime_lock;
+
+void tod_to_timeval(uint64_t todval, struct timeval *xtime)
+{
+        const int high_bit = 0x80000000L;
+        const int c_f4240 = 0xf4240L;
+        const int c_7a120 = 0x7a120;
+	/* We have to divide the 64 bit value todval by 4096
+	 * (because the 2^12 bit is the one that changes every 
+         * microsecond) and then split it into seconds and
+         * microseconds. A value of max (2^52-1) divided by
+         * the value 0xF4240 can yield a max result of approx
+         * (2^32.068). Thats to big to fit into a signed int
+	 *   ... hacking time!
+         */
+	asm volatile ("L     2,%1\n\t"
+		      "LR    3,2\n\t"
+		      "SRL   2,12\n\t"
+		      "SLL   3,20\n\t"
+		      "L     4,%O1+4(%R1)\n\t"
+		      "SRL   4,12\n\t"
+		      "OR    3,4\n\t"  /* now R2/R3 contain (todval >> 12) */
+		      "SR    4,4\n\t"
+		      "CL    2,%2\n\t"
+		      "JL    .+12\n\t"
+		      "S     2,%2\n\t"
+		      "L     4,%3\n\t"
+                      "D     2,%4\n\t"
+		      "OR    3,4\n\t"
+		      "ST    2,%O0+4(%R0)\n\t"
+		      "ST    3,%0"
+		      : "=m" (*xtime) : "m" (todval),
+		        "m" (c_7a120), "m" (high_bit), "m" (c_f4240)
+		      : "cc", "memory", "2", "3", "4" );
+}
+
+unsigned long do_gettimeoffset(void) 
+{
+	__u64 timer_cc;
+
+	asm volatile ("STCK %0" : "=m" (timer_cc));
+        /* We require the offset from the previous interrupt */
+        return ((unsigned long)((timer_cc - last_timer_cc)>>12));
+}
+
+/*
+ * This version of gettimeofday has microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+	extern volatile unsigned long lost_ticks;
+	unsigned long flags;
+	unsigned long usec, sec;
+
+	read_lock_irqsave(&xtime_lock, flags);
+	usec = do_gettimeoffset();
+	if (lost_ticks)
+		usec +=(USECS_PER_JIFFY*lost_ticks);
+	sec = xtime.tv_sec;
+	usec += xtime.tv_usec;
+	read_unlock_irqrestore(&xtime_lock, flags);
+
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		sec++;
+	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+
+	write_lock_irq(&xtime_lock);
+	/* This is revolting. We need to set the xtime.tv_usec
+	 * correctly. However, the value in this location is
+	 * is value at the last tick.
+	 * Discover what correction gettimeofday
+	 * would have done, and then undo it!
+	 */
+	tv->tv_usec -= do_gettimeoffset();
+
+	while (tv->tv_usec < 0) {
+		tv->tv_usec += 1000000;
+		tv->tv_sec--;
+	}
+
+	xtime = *tv;
+	time_adjust = 0;		/* stop active adjtime() */
+	time_status |= STA_UNSYNC;
+	time_maxerror = NTP_PHASE_LIMIT;
+	time_esterror = NTP_PHASE_LIMIT;
+	write_unlock_irq(&xtime_lock);
+}
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+
+#ifdef __SMP__
+extern __u16 boot_cpu_addr;
+#endif
+
+void do_timer_interrupt(struct pt_regs *regs,int error_code)
+{
+        unsigned long flags;
+
+        /*
+         * reset timer to 10ms minus time already elapsed
+         * since timer-interrupt pending
+         */
+ 
+        save_flags(flags);
+        cli();
+#ifdef __SMP__
+	if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr) {
+		write_lock(&xtime_lock);
+		last_timer_cc = S390_lowcore.jiffy_timer_cc;
+	}
+#else
+        last_timer_cc = S390_lowcore.jiffy_timer_cc;
+#endif
+        /* set clock comparator */
+        S390_lowcore.jiffy_timer_cc += CLK_TICKS_PER_JIFFY;
+        asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer_cc));
+
+/*
+ * In the SMP case we use the local timer interrupt to do the
+ * profiling, except when we simulate SMP mode on a uniprocessor
+ * system, in that case we have to call the local interrupt handler.
+ */
+#ifdef __SMP__
+        /* when SMP, do smp_local_timer_interrupt for *all* CPUs,
+           but only do the rest for the boot CPU */
+        smp_local_timer_interrupt(regs);
+#else
+        if (!user_mode(regs))
+                s390_do_profile(regs->psw.addr);
+#endif
+
+#ifdef __SMP__
+	if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr)
+#endif
+	{
+		do_timer(regs);
+#ifdef __SMP__
+		write_unlock(&xtime_lock);
+#endif
+	}
+        restore_flags(flags);
+
+}
+
+/*
+ * Start the clock comparator on the current CPU
+ */
+static long cr0 __attribute__ ((aligned (8)));
+
+void init_100hz_timer(void)
+{
+        /* allow clock comparator timer interrupt */
+        asm volatile ("STCTL 0,0,%0" : "=m" (cr0) : : "memory");
+        cr0 |= 0x800;
+        asm volatile ("LCTL 0,0,%0" : : "m" (cr0) : "memory");
+        /* set clock comparator */
+        /* read the TOD clock */
+        asm volatile ("STCK %0" : "=m" (S390_lowcore.jiffy_timer_cc));
+        S390_lowcore.jiffy_timer_cc += CLK_TICKS_PER_JIFFY;
+        asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer_cc));
+}
+
+/*
+ * Initialize the TOD clock and the CPU timer of
+ * the boot cpu.
+ */
+__initfunc(void time_init(void))
+{
+	int cc;
+
+        /* kick the TOD clock */
+        asm volatile ("STCK %1\n\t"
+                      "IPM  %0\n\t"
+                      "SRL  %0,28" : "=r" (cc), "=m" (init_timer_cc));
+        switch (cc) {
+        case 0: /* clock in set state: all is fine */
+                break;
+        case 1: /* clock in non-set state: FIXME */
+                printk("time_init: TOD clock in non-set state\n");
+                break;
+        case 2: /* clock in error state: FIXME */
+                printk("time_init: TOD clock in error state\n");
+                break;
+        case 3: /* clock in stopped or not-operational state: FIXME */
+                printk("time_init: TOD clock stopped/non-operational\n");
+                break;
+        }
+        init_100hz_timer();
+        init_timer_cc = S390_lowcore.jiffy_timer_cc;
+        init_timer_cc -= 0x8126d60e46000000LL -
+                         (0x3c26700LL*1000000*4096);
+        tod_to_timeval(init_timer_cc, &xtime);
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/kernel/traps.c linux.14p16/arch/s390/kernel/traps.c
--- linux.vanilla/arch/s390/kernel/traps.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/kernel/traps.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,461 @@
+/*
+ *  arch/s390/kernel/traps.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *
+ *  Derived from "arch/i386/kernel/traps.c"
+ *    Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/*
+ * 'Traps.c' handles hardware traps and faults after we have saved some
+ * state in 'asm.s'.
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/spinlock.h>
+#include <asm/atomic.h>
+#include <asm/mathemu.h>
+#if CONFIG_REMOTE_DEBUG
+#include <asm/gdb-stub.h>
+#endif
+
+/* Called from entry.S only */
+extern void handle_per_exception(struct pt_regs *regs);
+
+typedef void pgm_check_handler_t(struct pt_regs *, long);
+pgm_check_handler_t *pgm_check_table[128];
+
+extern pgm_check_handler_t default_trap_handler;
+extern pgm_check_handler_t do_page_fault;
+
+asmlinkage int system_call(void);
+
+static inline void console_verbose(void)
+{
+        extern int console_loglevel;
+        console_loglevel = 15;
+}
+
+#define DO_ERROR(trapnr, signr, str, name, tsk) \
+asmlinkage void name(struct pt_regs * regs, long error_code) \
+{ \
+        if (check_for_fixup(regs) == 0) { \
+                tsk->tss.error_code = error_code; \
+                tsk->tss.trap_no = trapnr; \
+                force_sig(signr, tsk); \
+	        die(str,regs,error_code); \
+        } \
+}
+
+
+void page_exception(void);
+
+/* TODO: define these as 'pgm_check_handler_t xxx;'
+asmlinkage void divide_error(void);
+asmlinkage void debug(void);
+asmlinkage void nmi(void);
+asmlinkage void int3(void);
+asmlinkage void overflow(void);
+asmlinkage void bounds(void);
+asmlinkage void invalid_op(void);
+asmlinkage void device_not_available(void);
+asmlinkage void double_fault(void);
+asmlinkage void coprocessor_segment_overrun(void);
+asmlinkage void invalid_TSS(void);
+asmlinkage void segment_not_present(void);
+asmlinkage void stack_segment(void);
+asmlinkage void general_protection(void);
+asmlinkage void coprocessor_error(void);
+asmlinkage void reserved(void);
+asmlinkage void alignment_check(void);
+asmlinkage void spurious_interrupt_bug(void);
+*/
+
+int kstack_depth_to_print = 24;
+
+/*
+ * These constants are for searching for possible module text
+ * segments.  VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
+ * a guess of how much space is likely to be vmalloced.
+ */
+#define VMALLOC_OFFSET (8*1024*1024)
+#define MODULE_RANGE (8*1024*1024)
+
+void show_crashed_task_info(void)
+{
+	printk("CPU:    %d\n",smp_processor_id());
+	printk("Process %s (pid: %d, stackpage=%08X)\n",
+                current->comm, current->pid, 4096+(addr_t)current);
+	show_regs(current,NULL,NULL);
+}
+#if 0
+static void show_registers(struct pt_regs *regs)
+{
+        printk("CPU:    %d\nPSW:    %08lx %08lx\n",
+                smp_processor_id(), (unsigned long) regs->psw.mask,
+                (unsigned long) regs->psw.addr);
+        printk("GPRS:\n");
+
+        printk("%08lx  %08lx  %08lx  %08lx\n",
+                regs->gprs[0], regs->gprs[1],
+                regs->gprs[2], regs->gprs[3]);
+        printk("%08lx  %08lx  %08lx  %08lx\n",
+                regs->gprs[4], regs->gprs[5],
+                regs->gprs[6], regs->gprs[7]);
+        printk("%08lx  %08lx  %08lx  %08lx\n",
+                regs->gprs[8], regs->gprs[9],
+                regs->gprs[10], regs->gprs[11]);
+        printk("%08lx  %08lx  %08lx  %08lx\n",
+                regs->gprs[12], regs->gprs[13],
+                regs->gprs[14], regs->gprs[15]);
+        printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ",
+                current->comm, current->pid, 4096+(unsigned long)current);
+/*
+        stack = (unsigned long *) esp;
+        for(i=0; i < kstack_depth_to_print; i++) {
+                if (((long) stack & 4095) == 0)
+                        break;
+                if (i && ((i % 8) == 0))
+                        printk("\n       ");
+                printk("%08lx ", get_seg_long(ss,stack++));
+        }
+        printk("\nCall Trace: ");
+        stack = (unsigned long *) esp;
+        i = 1;
+        module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT);
+        module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
+        module_end = module_start + MODULE_RANGE;
+        while (((long) stack & 4095) != 0) {
+                addr = get_seg_long(ss, stack++); */
+                /*
+                 * If the address is either in the text segment of the
+                 * kernel, or in the region which contains vmalloc'ed
+                 * memory, it *may* be the address of a calling
+                 * routine; if so, print it so that someone tracing
+                 * down the cause of the crash will be able to figure
+                 * out the call path that was taken.
+                 */
+/*                if (((addr >= (unsigned long) &_stext) &&
+                     (addr <= (unsigned long) &_etext)) ||
+                    ((addr >= module_start) && (addr <= module_end))) {
+                        if (i && ((i % 8) == 0))
+                                printk("\n       ");
+                        printk("[<%08lx>] ", addr);
+                        i++;
+                }
+        }
+        printk("\nCode: ");
+        for(i=0;i<20;i++)
+                printk("%02x ",0xff & get_seg_byte(regs->xcs & 0xffff,(i+(char *)regs->eip)));
+        printk("\n");
+*/
+}
+#endif
+
+
+spinlock_t die_lock;
+
+void die(const char * str, struct pt_regs * regs, long err)
+{
+        console_verbose();
+        spin_lock_irq(&die_lock);
+        printk("%s: %04lx\n", str, err & 0xffff);
+        show_crashed_task_info();
+        spin_unlock_irq(&die_lock);
+        do_exit(SIGSEGV);
+}
+
+int check_for_fixup(struct pt_regs * regs)
+{
+        if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
+		unsigned long fixup;
+		fixup = search_exception_table(regs->psw.addr);
+		if (fixup) {
+			regs->psw.addr = fixup;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+int do_debugger_trap(struct pt_regs *regs,int signal)
+{
+	if(regs->psw.mask&PSW_PROBLEM_STATE)
+	{
+		if(current->flags & PF_PTRACED)
+			force_sig(signal,current);
+		else
+			return(TRUE);
+	}
+	else
+	{
+#if CONFIG_REMOTE_DEBUG
+		if(gdb_stub_initialised)
+		{
+			gdb_stub_handle_exception((gdb_pt_regs *)regs,signal);
+			return(FALSE);
+		}
+#endif
+		return(TRUE);
+	}
+	return(FALSE);
+}
+
+
+DO_ERROR(2, SIGILL, "privileged operation", privileged_op, current)
+DO_ERROR(3, SIGILL, "execute exception", execute_exception, current)
+DO_ERROR(5, SIGSEGV, "addressing exception", addressing_exception, current)
+DO_ERROR(9, SIGFPE, "fixpoint divide exception", divide_exception, current)
+DO_ERROR(0x12, SIGILL, "translation exception", translation_exception, current)
+DO_ERROR(0x13, SIGILL, "special operand exception", special_op_exception, current)
+DO_ERROR(0x15, SIGILL, "operand exception", operand_exception, current)
+
+/* need to define
+DO_ERROR( 6, SIGILL,  "invalid operand", invalid_op, current)
+DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current)
+DO_ERROR( 9, SIGFPE,  "coprocessor segment overrun", coprocessor_segment_overrun, last_task_used_math)
+DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current)
+DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present, current)
+DO_ERROR(12, SIGBUS,  "stack segment", stack_segment, current)
+DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
+DO_ERROR(18, SIGSEGV, "reserved", reserved, current)
+DO_ERROR(19, SIGSEGV, "cache flush denied", cache_flush_denied, current)
+*/
+
+#ifdef CONFIG_IEEEFPU_EMULATION
+
+asmlinkage void illegal_op(struct pt_regs * regs, long error_code)
+{
+        __u8 opcode[6];
+	__u16 *location;
+	int do_sig = 0;
+	int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE);
+
+        lock_kernel();
+	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+	if(problem_state)
+		get_user(*((__u16 *) opcode), location);
+	else
+		*((__u16 *)opcode)=*((__u16 *)location);
+	if(*((__u16 *)opcode)==BREAKPOINT_U16)
+        {
+		if(do_debugger_trap(regs,SIGTRAP))
+			do_sig=1;
+	}
+        else if (problem_state )
+	{
+		if (opcode[0] == 0xb3) {
+			get_user(*((__u16 *) (opcode+2)), location+1);
+			do_sig = math_emu_b3(opcode, regs);
+                } else if (opcode[0] == 0xed) {
+			get_user(*((__u32 *) (opcode+2)),
+				 (__u32 *)(location+1));
+			do_sig = math_emu_ed(opcode, regs);
+		} else if (*((__u16 *) opcode) == 0xb299) {
+			get_user(*((__u16 *) (opcode+2)), location+1);
+			do_sig = math_emu_srnm(opcode, regs);
+		} else if (*((__u16 *) opcode) == 0xb29c) {
+			get_user(*((__u16 *) (opcode+2)), location+1);
+			do_sig = math_emu_stfpc(opcode, regs);
+		} else if (*((__u16 *) opcode) == 0xb29d) {
+			get_user(*((__u16 *) (opcode+2)), location+1);
+			do_sig = math_emu_lfpc(opcode, regs);
+		} else
+			do_sig = 1;
+        } else
+		do_sig = 1;
+	if (do_sig) {
+                if (check_for_fixup(regs) == 0) {
+                        current->tss.error_code = error_code;
+                        current->tss.trap_no = 1;
+                        force_sig(SIGILL, current);
+                        die("illegal operation", regs, error_code);
+                }
+        }
+        unlock_kernel();
+}
+
+asmlinkage void specification_exception(struct pt_regs * regs, long error_code)
+{
+        __u8 opcode[6];
+	__u16 *location;
+	int do_sig = 0;
+
+        lock_kernel();
+        if (regs->psw.mask & 0x00010000L) {
+		location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+		get_user(*((__u16 *) opcode), location);
+		switch (opcode[0]) {
+		case 0x28: /* LDR Rx,Ry   */
+			math_emu_ldr(opcode);
+			break;
+		case 0x38: /* LER Rx,Ry   */
+			math_emu_ler(opcode);
+			break;
+		case 0x60: /* STD R,D(X,B) */
+			get_user(*((__u16 *) (opcode+2)), location+1);
+			math_emu_std(opcode, regs);
+			break;
+		case 0x68: /* LD R,D(X,B) */
+			get_user(*((__u16 *) (opcode+2)), location+1);
+			math_emu_ld(opcode, regs);
+			break;
+		case 0x70: /* STE R,D(X,B) */
+			get_user(*((__u16 *) (opcode+2)), location+1);
+			math_emu_ste(opcode, regs);
+			break;
+		case 0x78: /* LE R,D(X,B) */
+			get_user(*((__u16 *) (opcode+2)), location+1);
+			math_emu_le(opcode, regs);
+			break;
+		default:
+			do_sig = 1;
+			break;
+                }
+        } else
+		do_sig = 1;
+	if (do_sig) {
+                if (check_for_fixup(regs) == 0) {
+                        current->tss.error_code = error_code;
+                        current->tss.trap_no = 1;
+                        force_sig(SIGILL, current);
+                        die("illegal operation", regs, error_code);
+                }
+        }
+        unlock_kernel();
+}
+
+asmlinkage void data_exception(struct pt_regs * regs, long error_code)
+{
+        __u8 opcode[6];
+	__u16 *location;
+	int do_sig = 0;
+
+        lock_kernel();
+        if (regs->psw.mask & 0x00010000L) {
+		location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+		get_user(*((__u16 *) opcode), location);
+		switch (opcode[0]) {
+		case 0x28: /* LDR Rx,Ry   */
+			math_emu_ldr(opcode);
+			break;
+		case 0x38: /* LER Rx,Ry   */
+			math_emu_ler(opcode);
+			break;
+		case 0x60: /* STD R,D(X,B) */
+			get_user(*((__u16 *) (opcode+2)), location+1);
+			math_emu_std(opcode, regs);
+			break;
+		case 0x68: /* LD R,D(X,B) */
+			get_user(*((__u16 *) (opcode+2)), location+1);
+			math_emu_ld(opcode, regs);
+			break;
+		case 0x70: /* STE R,D(X,B) */
+			get_user(*((__u16 *) (opcode+2)), location+1);
+			math_emu_ste(opcode, regs);
+			break;
+		case 0x78: /* LE R,D(X,B) */
+			get_user(*((__u16 *) (opcode+2)), location+1);
+			math_emu_le(opcode, regs);
+			break;
+		case 0xb3:
+			get_user(*((__u16 *) (opcode+2)), location+1);
+			do_sig = math_emu_b3(opcode, regs);
+			break;
+                case 0xed:
+			get_user(*((__u32 *) (opcode+2)),
+				 (__u32 *)(location+1));
+			do_sig = math_emu_ed(opcode, regs);
+			break;
+	        case 0xb2:
+			if (opcode[1] == 0x99) {
+				get_user(*((__u16 *) (opcode+2)), location+1);
+				do_sig = math_emu_srnm(opcode, regs);
+			} else if (opcode[1] == 0x9c) {
+				get_user(*((__u16 *) (opcode+2)), location+1);
+				do_sig = math_emu_stfpc(opcode, regs);
+			} else if (opcode[1] == 0x9d) {
+				get_user(*((__u16 *) (opcode+2)), location+1);
+				do_sig = math_emu_lfpc(opcode, regs);
+			} else
+				do_sig = 1;
+			break;
+		default:
+			do_sig = 1;
+			break;
+                }
+        } else
+		do_sig = 1;
+	if (do_sig) {
+                if (check_for_fixup(regs) == 0) {
+                        current->tss.error_code = error_code;
+                        current->tss.trap_no = 7;
+                        force_sig(SIGILL, current);
+                        die("data exception", regs, error_code);
+                }
+        }
+        unlock_kernel();
+}
+
+#else
+DO_ERROR(1, SIGILL, "illegal operation", illegal_op, current)
+DO_ERROR(6, SIGILL, "specification exception", specification_exception, current)
+DO_ERROR(7, SIGILL, "data exception", data_exception, current)
+#endif /* CONFIG_IEEEFPU_EMULATION */
+
+
+/* init is done in lowcore.S and head.S */
+
+__initfunc(void trap_init(void))
+{
+        int i;
+
+        for (i = 0; i < 128; i++)
+          pgm_check_table[i] = &default_trap_handler;
+        pgm_check_table[1] = &illegal_op;
+        pgm_check_table[2] = &privileged_op;
+        pgm_check_table[3] = &execute_exception;
+        pgm_check_table[5] = &addressing_exception;
+        pgm_check_table[6] = &specification_exception;
+        pgm_check_table[7] = &data_exception;
+        pgm_check_table[9] = &divide_exception;
+        pgm_check_table[0x12] = &translation_exception;
+        pgm_check_table[0x13] = &special_op_exception;
+        pgm_check_table[0x15] = &operand_exception;
+        pgm_check_table[4] = &do_page_fault;
+        pgm_check_table[0x10] = &do_page_fault;
+        pgm_check_table[0x11] = &do_page_fault;
+}
+
+
+void handle_per_exception(struct pt_regs *regs)
+{
+	if(regs->psw.mask&PSW_PROBLEM_STATE)
+	{
+		per_struct *per_info=&current->tss.per_info;
+		per_info->lowcore.words.perc_atmid=S390_lowcore.per_perc_atmid;
+		per_info->lowcore.words.address=S390_lowcore.per_address;
+		per_info->lowcore.words.access_id=S390_lowcore.per_access_id;
+	}
+	if(do_debugger_trap(regs,SIGTRAP))
+		printk("Spurious per exception detected\n");
+}
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/lib/Makefile linux.14p16/arch/s390/lib/Makefile
--- linux.vanilla/arch/s390/lib/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/lib/Makefile	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,17 @@
+#
+# Makefile for s390-specific library files..
+#
+
+ifdef SMP
+.S.o:
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+else
+.S.o:
+	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+endif
+
+L_TARGET = lib.a
+L_OBJS = checksum.o delay.o memset.o strcmp.o strncpy.o
+
+include $(TOPDIR)/Rules.make
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/lib/checksum.c linux.14p16/arch/s390/lib/checksum.c
--- linux.vanilla/arch/s390/lib/checksum.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/lib/checksum.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,56 @@
+/*
+ *  arch/s390/lib/checksum.c
+ *    S390 fast network checksum routines
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Ulrich Hild        (first version),
+ *               Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *
+ * This file contains network checksum routines
+ */
+ 
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+#include <asm/checksum.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+unsigned int
+csum_partial (const unsigned char *buff, int len, unsigned int sum)
+{
+	  /*
+	   * Experiments with ethernet and slip connections show that buff
+	   * is aligned on either a 2-byte or 4-byte boundary.
+	   */
+        __asm__ __volatile__ (
+                "    lr   2,%1\n"    /* address in gpr 2 */
+                "    lr   3,%2\n"    /* length in gpr 3 */
+                "0:  cksm %0,2\n"    /* do checksum on longs */
+                "    jo   0b\n"
+                : "+&d" (sum)
+                : "d" (buff), "d" (len)
+                : "cc", "2", "3" );
+        return sum;
+}
+
+/*
+ *	Fold a partial checksum without adding pseudo headers
+ */
+unsigned short csum_fold(unsigned int sum)
+{
+        __asm__ __volatile__ (
+                "    sr   3,3\n"   /* %0 = H*65536 + L */
+                "    lr   2,%0\n"  /* %0 = H L, R2/R3 = H L / 0 0 */
+                "    srdl 2,16\n"  /* %0 = H L, R2/R3 = 0 H / L 0 */
+                "    alr  2,3\n"   /* %0 = H L, R2/R3 = L H / L 0 */
+                "    alr  %0,2\n"  /* %0 = H+L+C L+H */
+                "    srl  %0,16\n" /* %0 = H+L+C */
+                : "+d" (sum) : : "cc", "2", "3");
+        return ((unsigned short) ~sum);
+}
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/lib/delay.c linux.14p16/arch/s390/lib/delay.c
--- linux.vanilla/arch/s390/lib/delay.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/lib/delay.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,44 @@
+/*
+ *  arch/s390/kernel/delay.c
+ *    Precise Delay Loops for S390
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ *  Derived from "arch/i386/lib/delay.c"
+ *    Copyright (C) 1993 Linus Torvalds
+ *    Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <linux/sched.h>
+#include <linux/delay.h>
+
+#ifdef __SMP__
+#include <asm/smp.h>
+#endif
+
+void __delay(unsigned long loops)
+{
+	__asm__ __volatile__(
+                "0: ahi  %0,-1\n"
+                "   jnm  0b"
+                : /* no outputs */ : "r" (loops) );
+}
+
+inline void __const_udelay(unsigned long xloops)
+{
+
+	__asm__("LR    3,%1\n\t"
+		"MR    2,%2\n\t"
+		"LR    %0,2\n\t"
+		: "=r" (xloops)
+		: "r" (xloops) , "r"  (loops_per_sec)
+		: "2" , "3");
+        __delay(xloops);
+}
+
+void __udelay(unsigned long usecs)
+{
+	__const_udelay(usecs * 0x000010c6);  /* 2**32 / 1000000 */
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/lib/memset.S linux.14p16/arch/s390/lib/memset.S
--- linux.vanilla/arch/s390/lib/memset.S	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/lib/memset.S	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,30 @@
+/*
+ *  arch/s390/lib/memset.S
+ *    S390 fast memset routine
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+/*
+ * R2 = address to memory area
+ * R3 = byte to fill memory with
+ * R4 = number of bytes to fill
+ */
+        .globl  memset
+memset:
+        LTR     4,4
+        JZ      memset_end
+        LR      0,2                    # save pointer to memory area
+        LR      1,3                    # move pad byte to R1
+        LR      3,4
+        SR      4,4                    # no source for MVCLE, only a pad byte
+        SR      5,5
+        MVCLE   2,4,0(1)               # thats it, MVCLE is your friend
+        JO      .-4
+        LR      2,0                    # return pointer to mem.
+memset_end:
+        BR      14
+        
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/lib/strcmp.S linux.14p16/arch/s390/lib/strcmp.S
--- linux.vanilla/arch/s390/lib/strcmp.S	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/lib/strcmp.S	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,27 @@
+/*
+ *  arch/s390/lib/strcmp.S
+ *    S390 strcmp routine
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+/*
+ * R2 = address of compare string
+ * R3 = address of test string
+ */
+        .globl   strcmp
+strcmp:
+        SR      0,0
+        SR      1,1
+        CLST    2,3
+        JO      .-4
+        JE      strcmp_equal
+        IC      0,0(0,3)
+        IC      1,0(0,2)
+        SR      1,0
+strcmp_equal:
+        LR      2,1
+        BR      14
+        
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/lib/strncpy.S linux.14p16/arch/s390/lib/strncpy.S
--- linux.vanilla/arch/s390/lib/strncpy.S	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/lib/strncpy.S	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,32 @@
+/*
+ *  arch/s390/kernel/strncpy.S
+ *    S390 strncpy routine
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+/*
+ * R2 = address of destination
+ * R3 = address of source string
+ * R4 = max number of bytes to copy
+ */
+        .globl   strncpy
+strncpy:
+        LR      1,2            # don't touch address in R2
+	LTR     4,4
+        JZ      strncpy_exit   # 0 bytes -> nothing to do
+        AHI     4,-1
+	SR      0,0
+        BASR    5,0
+strncpy_loop:
+        ICM     0,1,0(3)       # ICM sets the cc, IC does not
+	LA      3,1(0,3)
+        STC     0,0(0,1)
+	LA      1,1(0,1)
+        JZ      strncpy_exit   # ICM inserted a 0x00
+        BCTR    4,5            # R4 -= 1, jump to strncpy_loop if >= 0
+strncpy_exit:
+        BR      14
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/mm/Makefile linux.14p16/arch/s390/mm/Makefile
--- linux.vanilla/arch/s390/mm/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/mm/Makefile	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,13 @@
+#
+# Makefile for the linux i386-specific parts of the memory manager.
+#
+# 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 := mm.o
+O_OBJS	 := init.o fault.o ioremap.o extable.o
+
+include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/mm/extable.c linux.14p16/arch/s390/mm/extable.c
--- linux.vanilla/arch/s390/mm/extable.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/mm/extable.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,63 @@
+/*
+ *  arch/s390/mm/extable.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Hartmut Penner (hp@de.ibm.com)
+ *
+ *  Derived from "arch/i386/mm/extable.c"
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+extern const struct exception_table_entry __start___ex_table[];
+extern const struct exception_table_entry __stop___ex_table[];
+
+static inline unsigned long
+search_one_table(const struct exception_table_entry *first,
+		 const struct exception_table_entry *last,
+		 unsigned long value)
+{
+        while (first <= last) {
+		const struct exception_table_entry *mid;
+		long diff;
+
+		mid = (last - first) / 2 + first;
+		diff = mid->insn - value;
+                if (diff == 0)
+                        return mid->fixup;
+                else if (diff < 0)
+                        first = mid+1;
+                else
+                        last = mid-1;
+        }
+        return 0;
+}
+
+unsigned long
+search_exception_table(unsigned long addr)
+{
+	unsigned long ret;
+
+#ifndef CONFIG_MODULES
+        addr &= 0x7fffffff;  /* remove amode bit from address */
+	/* There is only the kernel to search.  */
+	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
+	if (ret) return FIX_PSW(ret);
+#else
+	/* The kernel is the last "module" -- no need to treat it special.  */
+	struct module *mp;
+        addr &= 0x7fffffff;  /* remove amode bit from address */
+	for (mp = module_list; mp != NULL; mp = mp->next) {
+		if (mp->ex_table_start == NULL)
+			continue;
+		ret = search_one_table(mp->ex_table_start,
+				       mp->ex_table_end - 1, addr);
+		if (ret) return FIX_PSW(ret);
+	}
+#endif
+
+	return 0;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/mm/fault.c linux.14p16/arch/s390/mm/fault.c
--- linux.vanilla/arch/s390/mm/fault.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/mm/fault.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,203 @@
+/*
+ *  arch/s390/mm/fault.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Hartmut Penner (hp@de.ibm.com)
+ *
+ *  Derived from "arch/i386/mm/fault.c"
+ *    Copyright (C) 1995  Linus Torvalds
+ */
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/hardirq.h>
+
+extern void die(const char *,struct pt_regs *,long);
+
+/*
+ * This routine handles page faults.  It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ *
+ * error_code:
+ *             ****0004       Protection           ->  Write-Protection  (suprression)
+ *             ****0010       Segment translation  ->  Not present       (nullification)
+ *             ****0011       Page translation     ->  Not present       (nullification)
+ */
+asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+{
+        struct task_struct *tsk;
+        struct mm_struct *mm;
+        struct vm_area_struct * vma;
+        unsigned long address;
+        unsigned long fixup;
+        int write;
+        unsigned long psw_mask;
+        unsigned long psw_addr;
+
+        /*
+         *  get psw mask of Program old psw to find out,
+         *  if user or kernel mode
+         */
+
+        psw_mask = S390_lowcore.program_old_psw.mask;
+        psw_addr = S390_lowcore.program_old_psw.addr;
+
+        /* 
+         * get the failing address 
+         * more specific the segment and page table portion of 
+         * the address 
+         */
+
+        address = S390_lowcore.trans_exc_code&0x7ffff000;
+
+        if (atomic_read(&S390_lowcore.local_irq_count))
+                die("page fault from irq handler",regs,error_code);
+
+        tsk = current;
+        mm = tsk->mm;
+
+        down(&mm->mmap_sem);
+
+        vma = find_vma(mm, address);
+        if (!vma) {
+	        printk("no vma for address %lX\n",address);
+                goto bad_area;
+        }
+        if (vma->vm_start <= address) 
+                goto good_area;
+        if (!(vma->vm_flags & VM_GROWSDOWN)) {
+                printk("VM_GROWSDOWN not set, but address %lX \n",address);
+                printk("not in vma %p (start %lX end %lX)\n",vma,
+                       vma->vm_start,vma->vm_end);
+                goto bad_area;
+        }
+        if (expand_stack(vma, address)) {
+                printk("expand of vma failed address %lX\n",address);
+                printk("vma %p (start %lX end %lX)\n",vma,
+                       vma->vm_start,vma->vm_end);
+                goto bad_area;
+        }
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+        write = 0;
+        switch (error_code & 0xFF) {
+                case 0x04:                                /* write, present*/
+                        write = 1;
+                        break;
+                case 0x10:                                   /* not present*/
+                case 0x11:                                   /* not present*/
+                        if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) {
+                                printk("flags %X of vma for address %lX wrong \n",
+                                       vma->vm_flags,address);
+                                printk("vma %p (start %lX end %lX)\n",vma,
+                                       vma->vm_start,vma->vm_end);
+                                goto bad_area;
+                        }
+                        break;
+                default:
+                       printk("code should be 4, 10 or 11 (%lX) \n",error_code&0xFF);  
+                       goto bad_area;
+        }
+        handle_mm_fault(tsk, vma, address, write);
+
+        up(&mm->mmap_sem);
+        return;
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+        up(&mm->mmap_sem);
+
+        /* User mode accesses just cause a SIGSEGV */
+        if (psw_mask & PSW_PROBLEM_STATE) {
+                tsk->tss.prot_addr = address;
+                tsk->tss.error_code = error_code;
+                tsk->tss.trap_no = 14;
+
+                printk("User process fault: interruption code 0x%lX\n",error_code);
+                printk("failing address: %lX\n",address);
+		show_crashed_task_info();
+                force_sig(SIGSEGV, tsk);
+                return;
+	}
+
+        /* Are we prepared to handle this kernel fault?  */
+
+        if ((fixup = search_exception_table(regs->psw.addr)) != 0) {
+                regs->psw.addr = fixup;
+                return;
+        }
+
+/*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ *
+ * First we check if it was the bootup rw-test, though..
+ */
+        if (address < PAGE_SIZE)
+                printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+        else
+                printk(KERN_ALERT "Unable to handle kernel paging request");
+        printk(" at virtual address %08lx\n",address);
+/*
+ * need to define, which information is useful here
+ */
+
+        lock_kernel();
+        die("Oops", regs, error_code);
+        do_exit(SIGKILL);
+        unlock_kernel();
+}
+
+/*
+                {
+		  char c;
+                  int i,j;
+		  char *addr;
+		  addr = ((char*) psw_addr)-0x20;
+		  for (i=0;i<16;i++) {
+		    if (i == 2)
+		      printk("\n");
+		    printk ("%08X:    ",(unsigned long) addr);
+		    for (j=0;j<4;j++) {
+		      printk("%08X ",*(unsigned long*)addr);
+		      addr += 4;
+		    }
+		    addr -=0x10;
+		    printk(" | ");
+		    for (j=0;j<16;j++) {
+		      printk("%c",(c=*addr++) < 0x20 ? '.' : c );
+		    }
+
+		    printk("\n");
+		  }
+                  printk("\n");
+                }
+
+*/
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/mm/init.c linux.14p16/arch/s390/mm/init.c
--- linux.vanilla/arch/s390/mm/init.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/mm/init.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,430 @@
+/*
+ *  arch/s390/mm/init.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Hartmut Penner (hp@de.ibm.com)
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1995  Linus Torvalds
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/dma.h>
+#include <asm/lowcore.h>
+
+static int test_access(unsigned long loc)
+{
+	static const int ssm_mask = 0x07000000L;
+	int rc, i;
+
+        rc = 0;
+	for (i=0; i<4; i++) {
+		__asm__ __volatile__(
+                        "    slr   %0,%0\n"
+			"    ssm   %1\n"
+			"    tprot 0(%2),0\n"
+			"0:  jne   1f\n"
+			"    lhi   %0,1\n"
+			"1:  ssm   %3\n"
+                        ".section __ex_table,\"a\"\n"
+                        "   .align 4\n"
+                        "   .long  0b,1b\n"
+                        ".previous"
+			: "+&d" (rc) : "i" (0), "a" (loc), "m" (ssm_mask)
+			: "cc");
+		if (rc == 0)
+			break;
+		loc += 0x100000;
+	}
+	return rc;
+}
+
+extern void show_net_buffers(void);
+
+extern unsigned long initrd_start,initrd_end;
+
+static inline void invalidate_page(pte_t *pte)
+{
+        int i;
+        for (i=0;i<PTRS_PER_PTE;i++)
+                pte_clear(pte++);
+}
+
+void __bad_pte_kernel(pmd_t *pmd)
+{
+        printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+        pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
+}
+
+void __bad_pte(pmd_t *pmd)
+{
+        printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+        pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
+}
+
+pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
+{
+        pte_t *pte;
+
+        pte = (pte_t *) __get_free_page(GFP_KERNEL);
+        if (pmd_none(*pmd)) {
+                if (pte) {
+                        invalidate_page(pte);
+                        pmd_val(pmd[0]) = _KERNPG_TABLE + __pa(pte);
+                        pmd_val(pmd[1]) = _KERNPG_TABLE + __pa(pte)+1024;
+                        pmd_val(pmd[2]) = _KERNPG_TABLE + __pa(pte)+2048;
+                        pmd_val(pmd[3]) = _KERNPG_TABLE + __pa(pte)+3072;
+                        return pte + offset;
+                }
+                pmd_val(pmd[0]) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
+                pmd_val(pmd[1]) = _KERNPG_TABLE + __pa(BAD_PAGETABLE)+1024;
+                pmd_val(pmd[2]) = _KERNPG_TABLE + __pa(BAD_PAGETABLE)+2048;
+                pmd_val(pmd[3]) = _KERNPG_TABLE + __pa(BAD_PAGETABLE)+3072;
+                return NULL;
+        }
+        free_page((unsigned long)pte);
+        if (pmd_bad(*pmd)) {
+                __bad_pte_kernel(pmd);
+                return NULL;
+        }
+        return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+        unsigned long pte;
+
+        pte = (unsigned long) __get_free_page(GFP_KERNEL);
+        if (pmd_none(*pmd)) {
+                if (pte) {
+                        invalidate_page((pte_t*) pte);
+                        pmd_val(pmd[0]) = _PAGE_TABLE + __pa(pte);
+                        pmd_val(pmd[1]) = _PAGE_TABLE + __pa(pte)+1024;
+                        pmd_val(pmd[2]) = _PAGE_TABLE + __pa(pte)+2048;
+                        pmd_val(pmd[3]) = _PAGE_TABLE + __pa(pte)+3072;
+                        return (pte_t *) pte + offset;
+                }
+                pmd_val(pmd[0]) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
+                pmd_val(pmd[1]) = _PAGE_TABLE + __pa(BAD_PAGETABLE)+1024;
+                pmd_val(pmd[2]) = _PAGE_TABLE + __pa(BAD_PAGETABLE)+2048;
+                pmd_val(pmd[3]) = _PAGE_TABLE + __pa(BAD_PAGETABLE)+3072;
+                return NULL;
+        }
+        free_page(pte);
+        if (pmd_bad(*pmd)) {
+                __bad_pte(pmd);
+                return NULL;
+        }
+        return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+int do_check_pgt_cache(int low, int high)
+{
+        int freed = 0;
+        if(pgtable_cache_size > high) {
+                do {
+                        if(pgd_quicklist)
+                                free_pgd_slow(get_pgd_fast()), freed++;
+                        if(pmd_quicklist)
+                                free_pmd_slow(get_pmd_fast()), freed++;
+                        if(pte_quicklist)
+                                free_pte_slow(get_pte_fast()), freed++;
+                } while(pgtable_cache_size > low);
+        }
+        return freed;
+}
+
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving an inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+pte_t * __bad_pagetable(void)
+{
+        extern char empty_bad_page_table[PAGE_SIZE];
+
+	memset((void *)empty_bad_page_table, 0, PAGE_SIZE);
+        return (pte_t *) empty_bad_page_table;
+}
+
+pte_t __bad_page(void)
+{
+        extern char empty_bad_page[PAGE_SIZE];
+
+	memset((void *)empty_bad_page, 0, PAGE_SIZE);
+        return pte_mkdirty(mk_pte((unsigned long) empty_bad_page, PAGE_SHARED));
+}
+
+void show_mem(void)
+{
+        int i,free = 0,total = 0,reserved = 0;
+        int shared = 0, cached = 0;
+
+        printk("Mem-info:\n");
+        show_free_areas();
+        printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+        i = max_mapnr;
+        while (i-- > 0) {
+                total++;
+                if (PageReserved(mem_map+i))
+                        reserved++;
+                else if (PageSwapCache(mem_map+i))
+                        cached++;
+                else if (!atomic_read(&mem_map[i].count))
+                        free++;
+                else
+                        shared += atomic_read(&mem_map[i].count) - 1;
+        }
+        printk("%d pages of RAM\n",total);
+        printk("%d reserved pages\n",reserved);
+        printk("%d pages shared\n",shared);
+        printk("%d pages swap cached\n",cached);
+        printk("%ld pages in page table cache\n",pgtable_cache_size);
+        show_buffers();
+#ifdef CONFIG_NET
+        show_net_buffers();
+#endif
+}
+
+extern unsigned long free_area_init(unsigned long, unsigned long);
+
+/* References to section boundaries */
+
+extern unsigned long _text;
+extern unsigned long _etext;
+extern unsigned long _edata;
+extern unsigned long __bss_start;
+extern unsigned long _end;
+
+extern unsigned long __init_begin;
+extern unsigned long __init_end;
+
+/*
+ * the initial mapping is set up by linload to address of  4 MB
+ * to enable virtual addressing to the first 4 MB
+ * paging_init will erase this initial mapping
+ */
+
+pgd_t         swapper_pg_dir[512]   __attribute__ ((__aligned__ (4096)));
+unsigned long empty_bad_page[1024] __attribute__ ((__aligned__ (4096)));
+unsigned long empty_zero_page[1024] __attribute__ ((__aligned__ (4096)));
+pte_t         empty_bad_page_table[1024] __attribute__ ((__aligned__ (4096)));
+
+/*
+ * paging_init() sets up the page tables - note that the first 4MB are
+ * already mapped by head.S.
+ *
+ * This routines also unmaps the page at virtual kernel address 0, so
+ * that we can trap those pesky NULL-reference errors in the kernel.
+ */
+__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem))
+{
+        pgd_t * pg_dir;
+        pte_t * pg_table;
+        pte_t   pte;
+	int     i;
+        unsigned long tmp;
+        unsigned long address=0;
+        unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
+
+	/* unmap whole virtual address space */
+
+        pg_dir = swapper_pg_dir;
+
+	for (i=0;i<KERNEL_PGD_PTRS;i++) 
+	        pmd_clear((pmd_t*)pg_dir++);
+
+	/*
+	 * map whole physical memory to virtual memory (identity mapping) 
+	 */
+
+        start_mem = PAGE_ALIGN(start_mem);
+        pg_dir = swapper_pg_dir;
+
+        while (address < end_mem) {
+                /*
+                 * pg_table is physical at this point
+                 */
+                pg_table = (pte_t *) __pa(start_mem);
+
+
+                pg_dir->pgd0 =  (_PAGE_TABLE | ((unsigned long) pg_table));
+                pg_dir->pgd1 =  (_PAGE_TABLE | ((unsigned long) pg_table+1024));
+                pg_dir->pgd2 =  (_PAGE_TABLE | ((unsigned long) pg_table+2048));
+                pg_dir->pgd3 =  (_PAGE_TABLE | ((unsigned long) pg_table+3072));
+                pg_dir++;
+
+                /* now change pg_table to kernel virtual addresses */
+                pg_table = (pte_t *) start_mem;
+                start_mem += PAGE_SIZE;
+
+                for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) {
+                        pte = mk_pte(address, PAGE_KERNEL);
+                        if (address >= end_mem)
+                                pte_clear(&pte);
+                        set_pte(pg_table, pte);
+                        address += PAGE_SIZE;
+                }
+        }
+
+        /* enable virtual mapping in kernel mode */
+        __asm__ __volatile__("    LCTL  1,1,%0\n"
+                             "    LCTL  7,7,%0\n"
+                             "    LCTL  13,13,%0" : :"m" (pgdir_k));
+
+        local_flush_tlb();
+
+        return free_area_init(start_mem, end_mem);
+}
+
+__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
+{
+        unsigned long start_low_mem = PAGE_SIZE;
+        int codepages = 0;
+        int reservedpages = 0;
+        int datapages = 0;
+        int initpages = 0;
+        unsigned long tmp;
+
+        end_mem &= PAGE_MASK;
+        high_memory = (void *) end_mem;
+        max_mapnr = num_physpages = MAP_NR(end_mem);
+
+        /* clear the zero-page */
+        memset(empty_zero_page, 0, PAGE_SIZE);
+
+        /* mark usable pages in the mem_map[] */
+        start_low_mem = PAGE_ALIGN(start_low_mem)+PAGE_OFFSET;
+
+#if 0 /* FIXME: WHATS THAT FOR ?!?! */
+#ifdef __SMP__
+        /*
+         * But first pinch a few for the stack/trampoline stuff
+         *      FIXME: Don't need the extra page at 4K, but need to fix
+         *      trampoline before removing it. (see the GDT stuff)
+         *
+         */
+        start_low_mem += PAGE_SIZE;                   /* 32bit startup code*/
+        start_low_mem = smp_alloc_memory(start_low_mem);/* AP processor stacks*/
+#endif
+#endif
+        start_mem = PAGE_ALIGN(start_mem);
+
+        tmp = start_mem;
+        while (tmp < end_mem) {
+                if ((tmp & 0x3ff000) == 0 && test_access(tmp) == 0) {
+                        int i;
+                        printk("4M Segment %lX not available\n",tmp);
+                        for (i = 0;i<0x400;i++) {
+                                set_bit(PG_reserved,
+                                        &mem_map[MAP_NR(tmp)].flags);
+                                tmp += PAGE_SIZE;
+                        }
+                } else {
+                        clear_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
+                        tmp += PAGE_SIZE;
+                }
+        }
+        for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) {
+                if (PageReserved(mem_map+MAP_NR(tmp))) {
+                        if (tmp >= (unsigned long) &_text && tmp < (unsigned long) &_edata) {
+                                if (tmp < (unsigned long) &_etext) {
+#if 0
+                                        if (tmp >= 0x00001000UL) {
+                                                pgd_t *pgd = pgd_offset_k(tmp);
+                                                pmd_t *pmd = pmd_offset(pgd, tmp);
+                                                pte_t *pte = pte_offset(pmd, tmp);
+
+                                                *pte = pte_wrprotect(*pte);
+                                        }
+#endif
+                                        codepages++;
+                                } else
+                                        datapages++;
+                        } else if (tmp >= (unsigned long) __init_begin
+                                   && tmp < (unsigned long) __init_end)
+                                initpages++;
+                        else if (tmp >= (unsigned long) &__bss_start
+                                 && tmp < (unsigned long) start_mem)
+                                datapages++;
+                        else
+                                reservedpages++;
+                        continue;
+                }
+                atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+                if (!initrd_start || (tmp < initrd_start || tmp >=
+                    initrd_end))
+#endif
+                        free_page(tmp);
+        }
+        printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
+                (unsigned long) nr_free_pages << (PAGE_SHIFT-10),
+                max_mapnr << (PAGE_SHIFT-10),
+                codepages << (PAGE_SHIFT-10),
+                reservedpages << (PAGE_SHIFT-10),
+                datapages << (PAGE_SHIFT-10),
+                initpages << (PAGE_SHIFT-10));
+
+}
+
+void free_initmem(void)
+{
+        unsigned long addr;
+
+        addr = (unsigned long)(&__init_begin);
+        for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+                mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+                atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+                free_page(addr);
+        }
+        printk ("Freeing unused kernel memory: %ldk freed\n", (&__init_end - &__init_begin) >> 10);
+}
+
+void si_meminfo(struct sysinfo *val)
+{
+        int i;
+
+        i = max_mapnr;
+        val->totalram = 0;
+        val->sharedram = 0;
+        val->freeram = nr_free_pages << PAGE_SHIFT;
+        val->bufferram = buffermem;
+        while (i-- > 0)  {
+                if (PageReserved(mem_map+i))
+                        continue;
+                val->totalram++;
+                if (!atomic_read(&mem_map[i].count))
+                        continue;
+                val->sharedram += atomic_read(&mem_map[i].count) - 1;
+        }
+        val->totalram <<= PAGE_SHIFT;
+        val->sharedram <<= PAGE_SHIFT;
+        return;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/mm/ioremap.c linux.14p16/arch/s390/mm/ioremap.c
--- linux.vanilla/arch/s390/mm/ioremap.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/mm/ioremap.c	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,120 @@
+/*
+ *  arch/s390/mm/ioremap.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Hartmut Penner (hp@de.ibm.com)
+ *
+ *  Derived from "arch/i386/mm/extable.c"
+ *    (C) Copyright 1995 1996 Linus Torvalds
+ *
+ * Re-map IO memory to kernel address space so that we can access it.
+ * This is needed for high PCI addresses that aren't mapped in the
+ * 640k-1MB IO memory area on PC's
+ */
+
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+
+static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+        unsigned long phys_addr, unsigned long flags)
+{
+        unsigned long end;
+
+        address &= ~PMD_MASK;
+        end = address + size;
+        if (end > PMD_SIZE)
+                end = PMD_SIZE;
+        do {
+                if (!pte_none(*pte))
+                        printk("remap_area_pte: page already exists\n");
+                set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT |
+                                        _PAGE_DIRTY | _PAGE_ACCESSED | flags)));
+                address += PAGE_SIZE;
+                phys_addr += PAGE_SIZE;
+                pte++;
+        } while (address < end);
+}
+
+static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+        unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	phys_addr -= address;
+	do {
+		pte_t * pte = pte_alloc_kernel(pmd, address);
+		if (!pte)
+			return -ENOMEM;
+		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address < end);
+	return 0;
+}
+
+static int remap_area_pages(unsigned long address, unsigned long phys_addr,
+				 unsigned long size, unsigned long flags)
+{
+	pgd_t * dir;
+	unsigned long end = address + size;
+
+	phys_addr -= address;
+	dir = pgd_offset(&init_mm, address);
+	flush_cache_all();
+	while (address < end) {
+		pmd_t *pmd = pmd_alloc_kernel(dir, address);
+		if (!pmd)
+			return -ENOMEM;
+		if (remap_area_pmd(pmd, address, end - address,
+					 phys_addr + address, flags))
+			return -ENOMEM;
+		set_pgdir(address, *dir);
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	}
+	flush_tlb_all();
+	return 0;
+}
+
+/*
+ * Generic mapping function (not visible outside):
+ */
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ */
+void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
+{
+	void * addr;
+	struct vm_struct * area;
+
+	if (phys_addr < virt_to_phys(high_memory))
+		return phys_to_virt(phys_addr);
+	if (phys_addr & ~PAGE_MASK)
+		return NULL;
+	size = PAGE_ALIGN(size);
+	if (!size || size > phys_addr + size)
+		return NULL;
+	area = get_vm_area(size);
+	if (!area)
+		return NULL;
+	addr = area->addr;
+	if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
+		vfree(addr);
+		return NULL;
+	}
+	return addr;
+}
+
+void iounmap(void *addr)
+{
+	if (addr > high_memory)
+		return vfree(addr);
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/s390/vmlinux.lds linux.14p16/arch/s390/vmlinux.lds
--- linux.vanilla/arch/s390/vmlinux.lds	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/s390/vmlinux.lds	Wed Dec 15 22:16:29 1999
@@ -0,0 +1,69 @@
+/* ld script to make s390 Linux kernel
+ * Written by Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390")
+OUTPUT_ARCH(s390)
+ENTRY(_start)
+SECTIONS
+{
+  . = 0x00000000;
+  _text = .;			/* Text and read-only data */
+  .text : {
+	*(.text)
+	*(.fixup)
+	*(.gnu.warning)
+	} = 0x0700
+  .text.lock : { *(.text.lock) }	/* out-of-line lock text */
+  .rodata : { *(.rodata) }
+  .kstrtab : { *(.kstrtab) }
+
+  . = ALIGN(16);		/* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___ksymtab = .;	/* Kernel symbol table */
+  __ksymtab : { *(__ksymtab) }
+  __stop___ksymtab = .;
+
+  _etext = .;			/* End of text section */
+
+  .data : {			/* Data */
+	*(.data)
+	CONSTRUCTORS
+	}
+
+  _edata = .;			/* End of data section */
+
+  . = ALIGN(8192);		/* init_task */
+  .data.init_task : { *(.data.init_task) }
+
+  . = ALIGN(4096);		/* Init code and data */
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+
+  . = ALIGN(32);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+  . = ALIGN(4096);
+  .data.page_aligned : { *(.data.idt) }
+
+
+  __bss_start = .;		/* BSS */
+  .bss : {
+	*(.bss)
+	}
+  _end = . ;
+
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/Makefile linux.14p16/arch/sparc/Makefile
--- linux.vanilla/arch/sparc/Makefile	Sun Oct  4 18:22:42 1998
+++ linux.14p16/arch/sparc/Makefile	Thu Dec  9 15:34:21 1999
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.39 1998/09/16 12:31:31 jj Exp $
+# $Id: Makefile,v 1.39.2.1 1999/09/20 12:05:00 jj Exp $
 # sparc/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -62,10 +62,8 @@
 	-$(MAKE) -C arch/sparc/boot clean
 
 archmrproper:
-	-$(MAKE) -C arch/sparc/math-emu cleansymlinks
 
 archdep:
-	-$(MAKE) -C arch/sparc/math-emu symlinks
 
 check_asm:
 	$(MAKE) -C arch/sparc/kernel check_asm
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/entry.S linux.14p16/arch/sparc/kernel/entry.S
--- linux.vanilla/arch/sparc/kernel/entry.S	Wed Oct 20 01:12:33 1999
+++ linux.14p16/arch/sparc/kernel/entry.S	Thu Dec  9 15:34:21 1999
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.159.2.2 1999/09/22 11:37:29 jj Exp $
+/* $Id: entry.S,v 1.159.2.6 1999/10/11 08:24:35 davem Exp $
  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -829,13 +829,13 @@
 	.globl	C_LABEL(invalid_segment_patch1_ff)
 	.globl	C_LABEL(invalid_segment_patch2_ff)
 C_LABEL(invalid_segment_patch1_ff):	cmp	%l4, 0xff
-C_LABEL(invalid_segment_patch2_ff):	mov	0xff, %l4
+C_LABEL(invalid_segment_patch2_ff):	mov	0xff, %l3
 
 	.align	4
 	.globl	C_LABEL(invalid_segment_patch1_1ff)
 	.globl	C_LABEL(invalid_segment_patch2_1ff)
 C_LABEL(invalid_segment_patch1_1ff):	cmp	%l4, 0x1ff
-C_LABEL(invalid_segment_patch2_1ff):	mov	0x1ff, %l4
+C_LABEL(invalid_segment_patch2_1ff):	mov	0x1ff, %l3
 
 	.align	4
 	.globl	C_LABEL(num_context_patch1_16), C_LABEL(num_context_patch2_16)
@@ -856,7 +856,7 @@
 #ifdef CONFIG_SUN4
 C_LABEL(vac_hwflush_patch1_on):		nop
 #else
-C_LABEL(vac_hwflush_patch1_on):		subcc	%l7, (PAGE_SIZE - 4), %l7
+C_LABEL(vac_hwflush_patch1_on):		addcc	%l7, -PAGE_SIZE, %l7
 #endif
 
 C_LABEL(vac_hwflush_patch2_on):		sta	%g0, [%l3 + %l7] ASI_HWFLUSHSEG
@@ -972,12 +972,12 @@
 	bne	1f
 	 sethi	%hi(C_LABEL(sun4c_kfree_ring)), %l4
 	or	%l4, %lo(C_LABEL(sun4c_kfree_ring)), %l4
-	ld	[%l4 + 0x10], %l3
+	ld	[%l4 + 0x18], %l3
 	deccc	%l3			! do we have a free entry?
 	bcs,a	2f			! no, unmap one.
 	 sethi	%hi(C_LABEL(sun4c_kernel_ring)), %l4
 
-	st	%l3, [%l4 + 0x10]	! sun4c_kfree_ring.num_entries--
+	st	%l3, [%l4 + 0x18]	! sun4c_kfree_ring.num_entries--
 
 	ld	[%l4 + 0x00], %l6	! entry = sun4c_kfree_ring.ringhd.next
 	st	%l5, [%l6 + 0x08]	! entry->vaddr = address
@@ -1000,10 +1000,11 @@
 
 	st	%l6, [%l4 + 0x00]	! head->next = entry
 
-	ld	[%l4 + 0x10], %l3
+	ld	[%l4 + 0x18], %l3
 	inc	%l3			! sun4c_kernel_ring.num_entries++
+	st	%l3, [%l4 + 0x18]
 	b	4f
-	 st	%l3, [%l4 + 0x10]
+	 ld	[%l6 + 0x08], %l5
 
 2:
 	or	%l4, %lo(C_LABEL(sun4c_kernel_ring)), %l4
@@ -1023,7 +1024,7 @@
 C_LABEL(vac_hwflush_patch1):
 C_LABEL(vac_linesize_patch):
 	subcc	%l7, 16, %l7
-	bg	9b
+	bne	9b
 C_LABEL(vac_hwflush_patch2):
 	 sta	%g0, [%l3 + %l7] ASI_FLUSHSEG
 
@@ -1044,47 +1045,36 @@
 
 	mov	%l3, %l5		! address = tmp
 
+4:
 C_LABEL(num_context_patch1):
 	mov	0x08, %l7
 
-C_LABEL(invalid_segment_patch2):
-	mov	0x7f, %l4
+	ld	[%l6 + 0x08], %l4
+	ldub	[%l6 + 0x0c], %l3
+	or	%l4, %l3, %l4		! encode new vaddr/pseg into l4
 
 	sethi	%hi(AC_CONTEXT), %l3
 	lduba	[%l3] ASI_CONTROL, %l6
 
-3:
-	deccc	%l7
-	stba	%l7, [%l3] ASI_CONTROL
-	bne	3b
-	 stXa	%l4, [%l5] ASI_SEGMAP
-
-	stba	%l6, [%l3] ASI_CONTROL
-
-	! reload the entry
-
-	sethi	%hi(C_LABEL(sun4c_kernel_ring)), %l4
-	ld	[%l4 + %lo(C_LABEL(sun4c_kernel_ring))], %l6
-
-	ld	[%l6 + 0x08], %l5	! restore address from entry->vaddr
-
-4:
-C_LABEL(num_context_patch2):
-	mov	0x08, %l7
-
-	ldub	[%l6 + 0x0c], %l4	! entry->pseg
-
+	/* Invalidate old mapping, instantiate new mapping,
+	 * for each context.  Registers l6/l7 are live across
+	 * this loop.
+	 */
+3:	deccc	%l7
 	sethi	%hi(AC_CONTEXT), %l3
-	lduba	[%l3] ASI_CONTROL, %l6
-
-3:
-	deccc	%l7
 	stba	%l7, [%l3] ASI_CONTROL
+C_LABEL(invalid_segment_patch2):
+	mov	0x7f, %l3
+	stXa	%l3, [%l5] ASI_SEGMAP
+	andn	%l4, 0x1ff, %l3
 	bne	3b
-	 stXa	%l4, [%l5] ASI_SEGMAP
+	 stXa	%l4, [%l3] ASI_SEGMAP
 
+	sethi	%hi(AC_CONTEXT), %l3
 	stba	%l6, [%l3] ASI_CONTROL
 
+	andn	%l4, 0x1ff, %l5
+
 1:
 	sethi	%hi(SUN4C_VMALLOC_START), %l4
 	cmp	%l5, %l4
@@ -1152,6 +1142,7 @@
 
 sun4c_fault_fromuser:
 	SAVE_ALL
+	 nop
 	
 	mov	%l7, %o1		! Decode the info from %l7
 	mov	%l7, %o2
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/head.S linux.14p16/arch/sparc/kernel/head.S
--- linux.vanilla/arch/sparc/kernel/head.S	Wed Oct 20 01:12:33 1999
+++ linux.14p16/arch/sparc/kernel/head.S	Thu Dec  9 15:34:21 1999
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.95.2.2 1999/09/23 09:53:18 anton Exp $
+/* $Id: head.S,v 1.95.2.5 1999/12/02 11:51:56 davem Exp $
  * head.S: The initial boot code for the Sparc port of Linux.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -173,7 +173,8 @@
 t_bad9b:BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) BAD_TRAP(0x9f)
 t_getcc:GETCC_TRAP                          /* Get Condition Codes           */
 t_setcc:SETCC_TRAP                          /* Set Condition Codes           */
-t_bada2:BAD_TRAP(0xa2) BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
+t_getpsr:GETPSR_TRAP                        /* Get PSR Register              */
+t_bada3:BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
 t_slowi:INDIRECT_SOLARIS_SYSCALL(156)
 t_bada8:BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
 t_badac:BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0)
@@ -253,8 +254,8 @@
 	LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94)
 	BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99)
 	BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e)
-	BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP
-	BAD_TRAP(0xa2) BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
+	BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP
+	BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
 	INDIRECT_SOLARIS_SYSCALL(156) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
 	BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0)
 	BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5)
@@ -325,8 +326,8 @@
 	LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94)
 	BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99)
 	BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e)
-	BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP
-	BAD_TRAP(0xa2) BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
+	BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP
+	BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
 	INDIRECT_SOLARIS_SYSCALL(156) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
 	BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0)
 	BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5)
@@ -397,8 +398,8 @@
 	LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94)
 	BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99)
 	BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e)
-	BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP
-	BAD_TRAP(0xa2) BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
+	BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP
+	BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
 	INDIRECT_SOLARIS_SYSCALL(156) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
 	BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0)
 	BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5)
@@ -450,7 +451,7 @@
  */
 	.ascii	"HdrS"
 	.word	LINUX_VERSION_CODE
-	.half	0x0201		/* HdrS version */
+	.half	0x0203		/* HdrS version */
 C_LABEL(root_flags):
 	.half	1
 C_LABEL(root_dev):
@@ -462,6 +463,8 @@
 C_LABEL(sparc_ramdisk_size):
 	.word	0
 	.word	C_LABEL(reboot_command)
+	.word	0, 0, 0
+	.word	_end
 
 /* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in
  * %g7 and at prom_vector_p. And also quickly check whether we are on
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/process.c linux.14p16/arch/sparc/kernel/process.c
--- linux.vanilla/arch/sparc/kernel/process.c	Sat Aug 14 02:27:15 1999
+++ linux.14p16/arch/sparc/kernel/process.c	Thu Dec  9 15:34:21 1999
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.137.2.1 1999/08/07 10:42:45 davem Exp $
+/*  $Id: process.c,v 1.137.2.2 1999/10/01 01:32:53 anton Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -55,7 +55,6 @@
 {
 	int ret = -EPERM;
 
-	lock_kernel();
 	if (current->pid != 0)
 		goto out;
 
@@ -100,7 +99,6 @@
 	}
 	ret = 0;
 out:
-	unlock_kernel();
 	return ret;
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/ptrace.c linux.14p16/arch/sparc/kernel/ptrace.c
--- linux.vanilla/arch/sparc/kernel/ptrace.c	Wed Mar 24 23:10:40 1999
+++ linux.14p16/arch/sparc/kernel/ptrace.c	Thu Dec  9 15:34:21 1999
@@ -37,12 +37,17 @@
 	pmd_t * pgmiddle;
 	pte_t * pgtable;
 	unsigned long page, retval;
+	int fault;
 
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (pgd_none(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 0);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return 0;
 	}
 	if (pgd_bad(*pgdir)) {
 		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
@@ -51,8 +56,12 @@
 	}
 	pgmiddle = pmd_offset(pgdir, addr);
 	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 0);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return 0;
 	}
 	if (pmd_bad(*pgmiddle)) {
 		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
@@ -61,8 +70,12 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 0);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return 0;
 	}
 	page = pte_page(*pgtable);
 /* this is a hack for non-kernel-mapped video buffers and similar */
@@ -90,12 +103,17 @@
 	pmd_t *pgmiddle;
 	pte_t *pgtable;
 	unsigned long page;
+	int fault;
 
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (!pgd_present(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 1);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return;
 	}
 	if (pgd_bad(*pgdir)) {
 		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
@@ -104,8 +122,12 @@
 	}
 	pgmiddle = pmd_offset(pgdir, addr);
 	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 1);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return;
 	}
 	if (pmd_bad(*pgmiddle)) {
 		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
@@ -114,13 +136,21 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 1);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return;
 	}
 	page = pte_page(*pgtable);
 	if (!pte_write(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, 1);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return;
 	}
 /* this is a hack for non-kernel-mapped video buffers and similar */
 	flush_cache_page(vma, addr);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/setup.c linux.14p16/arch/sparc/kernel/setup.c
--- linux.vanilla/arch/sparc/kernel/setup.c	Sat Aug 14 02:25:55 1999
+++ linux.14p16/arch/sparc/kernel/setup.c	Thu Dec  9 15:34:21 1999
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.105 1999/04/13 14:17:08 jj Exp $
+/*  $Id: setup.c,v 1.105.2.1 1999/11/16 06:29:31 davem Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
@@ -424,7 +424,9 @@
 				initrd_start -= KERNBASE;
 				initrd_end -= KERNBASE;
 				break;
-			}
+			default:
+				break;
+			};
 		}
 	}
 #endif	
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/sparc_ksyms.c linux.14p16/arch/sparc/kernel/sparc_ksyms.c
--- linux.vanilla/arch/sparc/kernel/sparc_ksyms.c	Wed Oct 20 01:12:33 1999
+++ linux.14p16/arch/sparc/kernel/sparc_ksyms.c	Thu Dec  9 15:34:21 1999
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.77.2.3 1999/09/22 17:06:50 jj Exp $
+/* $Id: sparc_ksyms.c,v 1.77.2.4 1999/09/28 16:47:30 davem Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -63,6 +63,7 @@
 
 extern void bcopy (const char *, char *, int);
 extern int __ashrdi3(int, int);
+extern int __ashldi3(int, int);
 extern int __lshrdi3(int, int);
 
 extern void dump_thread(struct pt_regs *, struct user *);
@@ -269,6 +270,7 @@
 EXPORT_SYMBOL_NOVERS(memset);
 EXPORT_SYMBOL_NOVERS(memmove);
 EXPORT_SYMBOL_NOVERS(__ashrdi3);
+EXPORT_SYMBOL_NOVERS(__ashldi3);
 EXPORT_SYMBOL_NOVERS(__lshrdi3);
 
 EXPORT_SYMBOL_DOT(rem);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/sun4d_smp.c linux.14p16/arch/sparc/kernel/sun4d_smp.c
--- linux.vanilla/arch/sparc/kernel/sun4d_smp.c	Sat Aug 14 02:26:14 1999
+++ linux.14p16/arch/sparc/kernel/sun4d_smp.c	Thu Dec  9 15:34:21 1999
@@ -99,6 +99,14 @@
 	local_flush_cache_all();
 	local_flush_tlb_all();
 
+	/*
+	 * Unblock the master CPU _only_ when the scheduler state
+	 * of all secondary CPUs will be up-to-date, so after
+	 * the SMP initialization the master will be just allowed
+	 * to call the scheduler code.
+	 */
+	init_idle();
+
 	/* Get our local ticker going. */
 	smp_setup_percpu_timer();
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/sun4m_smp.c linux.14p16/arch/sparc/kernel/sun4m_smp.c
--- linux.vanilla/arch/sparc/kernel/sun4m_smp.c	Sat Aug 14 02:26:14 1999
+++ linux.14p16/arch/sparc/kernel/sun4m_smp.c	Thu Dec  9 15:34:21 1999
@@ -93,6 +93,14 @@
 	local_flush_cache_all();
 	local_flush_tlb_all();
 
+	/*
+	 * Unblock the master CPU _only_ when the scheduler state
+	 * of all secondary CPUs will be up-to-date, so after
+	 * the SMP initialization the master will be just allowed
+	 * to call the scheduler code.
+	 */
+	init_idle();
+
 	/* Allow master to continue. */
 	swap((unsigned long *)&cpu_callin_map[cpuid], 1);
 	local_flush_cache_all();
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/sys_sparc.c linux.14p16/arch/sparc/kernel/sys_sparc.c
--- linux.vanilla/arch/sparc/kernel/sys_sparc.c	Sat Aug 14 02:26:14 1999
+++ linux.14p16/arch/sparc/kernel/sys_sparc.c	Thu Dec  9 15:34:21 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.52 1999/05/08 08:09:48 anton Exp $
+/* $Id: sys_sparc.c,v 1.52.2.1 1999/10/04 10:36:15 davem Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -192,24 +192,23 @@
 	}
 	retval = -ENOMEM;
 	len = PAGE_ALIGN(len);
-	if(!(flags & MAP_FIXED) && !addr) {
-		addr = get_unmapped_area(addr, len);
+	if(!(flags & MAP_FIXED) &&
+	   (!addr || (ARCH_SUN4C_SUN4 &&
+		      (addr >= 0x20000000 && addr < 0xe0000000)))) {
+		addr = get_unmapped_area(0, len);
 		if(!addr)
 			goto out_putf;
+		if (ARCH_SUN4C_SUN4 &&
+		    (addr >= 0x20000000 && addr < 0xe0000000)) {
+			retval = -EINVAL;
+			goto out_putf;
+		}
 	}
 
 	/* See asm-sparc/uaccess.h */
 	retval = -EINVAL;
 	if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE)))
 		goto out_putf;
-
-	if(ARCH_SUN4C_SUN4) {
-		if(((addr >= 0x20000000) && (addr < 0xe0000000))) {
-			/* VM hole */
-			retval = current->mm->brk;
-			goto out_putf;
-		}
-	}
 
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	retval = do_mmap(file, addr, len, prot, flags, off);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/sys_sunos.c linux.14p16/arch/sparc/kernel/sys_sunos.c
--- linux.vanilla/arch/sparc/kernel/sys_sunos.c	Sat Aug 14 02:27:15 1999
+++ linux.14p16/arch/sparc/kernel/sys_sunos.c	Thu Dec  9 15:34:21 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.94.2.2 1999/08/07 10:42:49 davem Exp $
+/* $Id: sys_sunos.c,v 1.94.2.3 1999/10/04 10:36:20 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -85,10 +85,17 @@
 	}
 
 	retval = -ENOMEM;
-	if(!(flags & MAP_FIXED) && !addr) {
-		addr = get_unmapped_area(addr, len);
+	if(!(flags & MAP_FIXED) &&
+	   (!addr || (ARCH_SUN4C_SUN4 &&
+		      (addr >= 0x20000000 && addr < 0xe0000000)))) {
+		addr = get_unmapped_area(0, len);
 		if(!addr)
 			goto out_putf;
+		if (ARCH_SUN4C_SUN4 &&
+		    (addr >= 0x20000000 && addr < 0xe0000000)) {
+			retval = -EINVAL;
+			goto out_putf;
+		}
 	}
 	/* If this is ld.so or a shared library doing an mmap
 	 * of /dev/zero, transform it into an anonymous mapping.
@@ -110,13 +117,6 @@
 	retval = -EINVAL;
 	if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE)))
 		goto out_putf;
-
-	if(ARCH_SUN4C_SUN4) {
-		if(((addr >= 0x20000000) && (addr < 0xe0000000))) {
-			retval = current->mm->brk;
-			goto out_putf;
-		}
-	}
 
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	retval = do_mmap(file, addr, len, prot, flags, off);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/lib/Makefile linux.14p16/arch/sparc/lib/Makefile
--- linux.vanilla/arch/sparc/lib/Makefile	Sun Mar 21 15:23:38 1999
+++ linux.14p16/arch/sparc/lib/Makefile	Thu Dec  9 15:34:21 1999
@@ -1,11 +1,12 @@
-# $Id: Makefile,v 1.28 1999/03/21 06:37:44 davem Exp $
+# $Id: Makefile,v 1.28.2.1 1999/09/28 16:47:36 davem Exp $
 # Makefile for Sparc library files..
 #
 
 OBJS  = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \
         strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \
 	strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \
-	copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o
+	copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o \
+	ashldi3.o
 
 ifdef CONFIG_SMP
 OBJS += irqlock.o
@@ -88,6 +89,9 @@
 
 ashrdi3.o: ashrdi3.S
 	$(CC) -D__ASSEMBLY__ -c -o ashrdi3.o ashrdi3.S
+
+ashldi3.o: ashldi3.S
+	$(CC) -D__ASSEMBLY__ -c -o ashldi3.o ashldi3.S
 
 lshrdi3.o: lshrdi3.S
 	$(CC) -D__ASSEMBLY__ -c -o lshrdi3.o lshrdi3.S
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/lib/ashldi3.S linux.14p16/arch/sparc/lib/ashldi3.S
--- linux.vanilla/arch/sparc/lib/ashldi3.S	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/sparc/lib/ashldi3.S	Thu Dec  9 15:34:21 1999
@@ -0,0 +1,36 @@
+/* $Id: ashldi3.S,v 1.1.2.1 1999/09/28 16:47:39 davem Exp $
+ * ashldi3.S:	GCC emits these for certain drivers playing
+ *		with long longs.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+#include <asm/cprefix.h>
+
+	.text
+	.align	4
+	.globl	C_LABEL(__ashldi3)
+C_LABEL(__ashldi3):
+	cmp	%o2, 0
+	be	9f
+	 mov	0x20, %g2
+
+	sub	%g2, %o2, %g2
+	cmp	%g2, 0
+	bg	7f
+	 sll	%o0, %o2, %g3
+
+	neg	%g2
+	clr	%o5
+	b	8f
+	 sll	%o1, %g2, %o4
+7:
+	srl	%o1, %g2, %g2
+	sll	%o1, %o2, %o5
+	or	%g3, %g2, %o4
+8:
+	mov	%o4, %o0
+	mov	%o5, %o1
+9:
+	retl
+	 nop
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/lib/ashrdi3.S linux.14p16/arch/sparc/lib/ashrdi3.S
--- linux.vanilla/arch/sparc/lib/ashrdi3.S	Sat Nov  9 08:12:00 1996
+++ linux.14p16/arch/sparc/lib/ashrdi3.S	Thu Dec  9 15:34:21 1999
@@ -1,4 +1,4 @@
-/* $Id: ashrdi3.S,v 1.3 1996/09/07 23:18:10 davem Exp $
+/* $Id: ashrdi3.S,v 1.3.12.1 1999/09/28 16:47:42 davem Exp $
  * ashrdi3.S:	The filesystem code creates all kinds of references to
  *              this little routine on the sparc with gcc.
  *
@@ -7,7 +7,9 @@
 
 #include <asm/cprefix.h>
 
-		.globl C_LABEL(__ashrdi3)
+	.text
+	.align	4
+	.globl C_LABEL(__ashrdi3)
 C_LABEL(__ashrdi3):
 	tst	%o2
 	be	3f
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/Makefile linux.14p16/arch/sparc/math-emu/Makefile
--- linux.vanilla/arch/sparc/math-emu/Makefile	Wed Apr 15 01:44:19 1998
+++ linux.14p16/arch/sparc/math-emu/Makefile	Thu Dec  9 15:34:22 1999
@@ -8,19 +8,7 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := math-emu.o
-O_OBJS   := math.o ashldi3.o fabss.o faddd.o faddq.o fadds.o 		\
-		fcmpd.o fcmped.o fcmpeq.o fcmpes.o fcmpq.o fcmps.o	\
-		fdivd.o fdivq.o fdivs.o fdmulq.o fdtoi.o fdtoq.o	\
-		fdtos.o fitoq.o fmovs.o fmuld.o fmulq.o fmuls.o		\
-		fnegs.o fqtod.o fqtoi.o fqtos.o fsmuld.o fsqrtd.o	\
-		fsqrtq.o fsqrts.o fstod.o fstoi.o fstoq.o fsubd.o 	\
-		fsubq.o	fsubs.o udivmodti4.o
-
-LINKS	 := double.h faddd.c faddq.c fadds.c fdivd.c fdivq.c fdivs.c	\
-		fdtoi.c fitoq.c fmuld.c fmulq.c fmuls.c fqtoi.c		\
-		fsqrtd.c fsqrtq.c fsqrts.c fstoi.c fsubd.c 		\
-		fsubq.c	fsubs.c op-1.h op-2.h op-4.h op-common.h quad.h	\
-		single.h soft-fp.h udivmodti4.c
+O_OBJS   := math.o ashldi3.o
 
 .S.s:
 	$(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
@@ -28,10 +16,6 @@
 .S.o:
 	$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
 
-include $(TOPDIR)/Rules.make
-
-symlinks:
-	ln -sf $(patsubst %,../../sparc64/math-emu/%,$(LINKS)) .
+CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w
 
-cleansymlinks:
-	rm -f $(LINKS)
+include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fabss.c linux.14p16/arch/sparc/math-emu/fabss.c
--- linux.vanilla/arch/sparc/math-emu/fabss.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/fabss.c	Thu Jan  1 01:00:00 1970
@@ -1,6 +0,0 @@
-int FABSS(unsigned long *rd, unsigned long *rs2)
-{
-	/* Clear the sign bit (high bit of word 0) */
-	rd[0] = rs2[0] & 0x7fffffffUL;
-	return 0;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fcmpd.c linux.14p16/arch/sparc/math-emu/fcmpd.c
--- linux.vanilla/arch/sparc/math-emu/fcmpd.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/fcmpd.c	Thu Jan  1 01:00:00 1970
@@ -1,18 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-
-int FCMPD(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_D(A); FP_DECL_D(B);
-	long ret;
-	unsigned long *fsr = rd;
-	
-	__FP_UNPACK_D(A, rs1);
-	__FP_UNPACK_D(B, rs2);
-	FP_CMP_D(ret, B, A, 2);
-	if (ret == -1)
-		ret = 2;
-
-	*fsr = (*fsr & ~0xc00) | (ret << 10); 
-	return 0;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fcmped.c linux.14p16/arch/sparc/math-emu/fcmped.c
--- linux.vanilla/arch/sparc/math-emu/fcmped.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/fcmped.c	Thu Jan  1 01:00:00 1970
@@ -1,18 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-
-int FCMPED(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_D(A); FP_DECL_D(B);
-	long ret;
-	unsigned long *fsr = rd;
-	
-	__FP_UNPACK_D(A, rs1);
-	__FP_UNPACK_D(B, rs2);
-	FP_CMP_D(ret, B, A, 2);
-	if (ret == -1)
-		ret = 2;
-
-	*fsr = (*fsr & ~0xc00) | (ret << 10); 
-	return 0;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fcmpeq.c linux.14p16/arch/sparc/math-emu/fcmpeq.c
--- linux.vanilla/arch/sparc/math-emu/fcmpeq.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/fcmpeq.c	Thu Jan  1 01:00:00 1970
@@ -1,18 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-
-int FCMPEQ(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_Q(A); FP_DECL_Q(B);
-	long ret;
-	unsigned long fsr;
-	
-	__FP_UNPACK_Q(A, rs1);
-	__FP_UNPACK_Q(B, rs2);
-	FP_CMP_Q(ret, B, A, 3);
-	if (ret == -1) ret = 2;
-	fsr = *(unsigned long *)rd;
-	fsr &= ~0xc00; fsr |= (ret << 10);
-	*(unsigned long *)rd = fsr;
-	return 0;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fcmpes.c linux.14p16/arch/sparc/math-emu/fcmpes.c
--- linux.vanilla/arch/sparc/math-emu/fcmpes.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/fcmpes.c	Thu Jan  1 01:00:00 1970
@@ -1,18 +0,0 @@
-#include "soft-fp.h"
-#include "single.h"
-
-int FCMPES(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_S(A); FP_DECL_S(B);
-	long ret;
-	unsigned long *fsr = rd;
-	
-	__FP_UNPACK_S(A, rs1);
-	__FP_UNPACK_S(B, rs2);
-	FP_CMP_S(ret, B, A, 1);
-	if (ret == -1)
-		ret = 2;
-
-	*fsr = (*fsr & ~0xc00) | (ret << 10); 
-	return 0;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fcmpq.c linux.14p16/arch/sparc/math-emu/fcmpq.c
--- linux.vanilla/arch/sparc/math-emu/fcmpq.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/fcmpq.c	Thu Jan  1 01:00:00 1970
@@ -1,18 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-
-int FCMPQ(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_Q(A); FP_DECL_Q(B);
-	long ret;
-	unsigned long fsr;
-	
-	__FP_UNPACK_Q(A, rs1);
-	__FP_UNPACK_Q(B, rs2);
-	FP_CMP_Q(ret, B, A, 3);
-	if (ret == -1) ret = 2;
-	fsr = *(unsigned long *)rd;
-	fsr &= ~0xc00; fsr |= (ret << 10);
-	*(unsigned long *)rd = fsr;
-	return 0;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fcmps.c linux.14p16/arch/sparc/math-emu/fcmps.c
--- linux.vanilla/arch/sparc/math-emu/fcmps.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/fcmps.c	Thu Jan  1 01:00:00 1970
@@ -1,18 +0,0 @@
-#include "soft-fp.h"
-#include "single.h"
-
-int FCMPS(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_S(A); FP_DECL_S(B);
-	long ret;
-	unsigned long *fsr = rd;
-	
-	__FP_UNPACK_S(A, rs1);
-	__FP_UNPACK_S(B, rs2);
-	FP_CMP_S(ret, B, A, 1);
-	if (ret == -1)
-		ret = 2;
-
-	*fsr = (*fsr & ~0xc00) | (ret << 10); 
-	return 0;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fdmulq.c linux.14p16/arch/sparc/math-emu/fdmulq.c
--- linux.vanilla/arch/sparc/math-emu/fdmulq.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/fdmulq.c	Thu Jan  1 01:00:00 1970
@@ -1,15 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-#include "double.h"
-
-int FDMULQ(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_D(IN); FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R);
-
-	__FP_UNPACK_D(IN, rs1);
-	FP_CONV(Q,D,4,2,A,IN);
-	__FP_UNPACK_D(IN, rs2);
-	FP_CONV(Q,D,4,2,B,IN);
-	FP_MUL_Q(R, A, B);
-	return __FP_PACK_Q(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fdtoq.c linux.14p16/arch/sparc/math-emu/fdtoq.c
--- linux.vanilla/arch/sparc/math-emu/fdtoq.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/fdtoq.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-#include "double.h"
-
-int FDTOQ(void *rd, void *rs2)
-{
-	FP_DECL_D(A); FP_DECL_Q(R);
-
-	__FP_UNPACK_D(A, rs2);
-	FP_CONV(Q,D,4,2,R,A);
-	return __FP_PACK_Q(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fdtos.c linux.14p16/arch/sparc/math-emu/fdtos.c
--- linux.vanilla/arch/sparc/math-emu/fdtos.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/fdtos.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
-
-int FDTOS(void *rd, void *rs2)
-{
-	FP_DECL_D(A); FP_DECL_S(R);
-
-	__FP_UNPACK_D(A, rs2);
-	FP_CONV(S,D,1,2,R,A);
-	return __FP_PACK_S(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fmovs.c linux.14p16/arch/sparc/math-emu/fmovs.c
--- linux.vanilla/arch/sparc/math-emu/fmovs.c	Wed Apr 15 01:44:19 1998
+++ linux.14p16/arch/sparc/math-emu/fmovs.c	Thu Jan  1 01:00:00 1970
@@ -1,5 +0,0 @@
-int FMOVS(unsigned long *rd, unsigned long *rs2)
-{
-	rd[0] = rs2[0];
-	return 0;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fnegs.c linux.14p16/arch/sparc/math-emu/fnegs.c
--- linux.vanilla/arch/sparc/math-emu/fnegs.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/fnegs.c	Thu Jan  1 01:00:00 1970
@@ -1,6 +0,0 @@
-int FNEGS(unsigned long *rd, unsigned long *rs2)
-{
- 	/* just change the sign bit */
-	rd[0] = rs2[0] ^ 0x80000000UL;
-	return 0;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fqtod.c linux.14p16/arch/sparc/math-emu/fqtod.c
--- linux.vanilla/arch/sparc/math-emu/fqtod.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/fqtod.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-#include "double.h"
-
-int FQTOD(void *rd, void *rs2)
-{
-	FP_DECL_Q(A); FP_DECL_D(R);
-
-	__FP_UNPACK_Q(A, rs2);
-	FP_CONV(D,Q,2,4,R,A);
-	return __FP_PACK_D(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fqtos.c linux.14p16/arch/sparc/math-emu/fqtos.c
--- linux.vanilla/arch/sparc/math-emu/fqtos.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/fqtos.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-#include "single.h"
-
-int FQTOS(void *rd, void *rs2)
-{
-	FP_DECL_Q(A); FP_DECL_S(R);
-
-	__FP_UNPACK_Q(A, rs2);
-	FP_CONV(S,Q,1,4,R,A);
-	return __FP_PACK_S(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fsmuld.c linux.14p16/arch/sparc/math-emu/fsmuld.c
--- linux.vanilla/arch/sparc/math-emu/fsmuld.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/fsmuld.c	Thu Jan  1 01:00:00 1970
@@ -1,15 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
-
-int FSMULD(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_S(IN); FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R);
-
-	__FP_UNPACK_S(IN, rs1);
-	FP_CONV(D,S,2,1,A,IN);
-	__FP_UNPACK_S(IN, rs2);
-	FP_CONV(D,S,2,1,B,IN);
-	FP_MUL_D(R, A, B);
-	return __FP_PACK_D(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fstod.c linux.14p16/arch/sparc/math-emu/fstod.c
--- linux.vanilla/arch/sparc/math-emu/fstod.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/fstod.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
-
-int FSTOD(void *rd, void *rs2)
-{
-	FP_DECL_S(A); FP_DECL_D(R);
-
-	__FP_UNPACK_S(A, rs2);
-	FP_CONV(D,S,2,1,R,A);
-	return __FP_PACK_D(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/fstoq.c linux.14p16/arch/sparc/math-emu/fstoq.c
--- linux.vanilla/arch/sparc/math-emu/fstoq.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/fstoq.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-#include "single.h"
-
-int FSTOQ(void *rd, void *rs2)
-{
-	FP_DECL_S(A); FP_DECL_Q(R);
-
-	__FP_UNPACK_S(A, rs2);
-	FP_CONV(Q,S,4,1,R,A);
-	return __FP_PACK_Q(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/math.c linux.14p16/arch/sparc/math-emu/math.c
--- linux.vanilla/arch/sparc/math-emu/math.c	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/math-emu/math.c	Thu Dec  9 15:34:22 1999
@@ -1,26 +1,19 @@
-/* 
+/*
  * arch/sparc/math-emu/math.c
  *
  * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
- * Based on the sparc64 code by Jakub Jelinek.
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
  *
  * This is a good place to start if you're trying to understand the
- * emulation code, because it's pretty simple. What we do is 
+ * emulation code, because it's pretty simple. What we do is
  * essentially analyse the instruction to work out what the operation
  * is and which registers are involved. We then execute the appropriate
  * FXXXX function. [The floating point queue introduces a minor wrinkle;
  * see below...]
  * The fxxxxx.c files each emulate a single insn. They look relatively
  * simple because the complexity is hidden away in an unholy tangle
- * of preprocessor macros. 
- *
- * WARNING : don't look at the macro definitions unless you 
- * absolutely have to! They're extremely ugly, rather complicated
- * and a single line in an fxxxx.c file can expand to the equivalent 
- * of  30 lines or more of C. Of course, any error in those 30 lines 
- * is reported by the compiler as an error in the single line with the
- * macro usage...
- * Question: should we replace them with inline functions?
+ * of preprocessor macros.
  *
  * The first layer of macros is single.h, double.h, quad.h. Generally
  * these files define macros for working with floating point numbers
@@ -29,11 +22,11 @@
  * generic macros (in this case _FP_ADD(D,2,R,X,Y) where the number
  * of machine words required to store the given IEEE format is passed
  * as a parameter. [double.h and co check the number of bits in a word
- * and define FP_ADD_D & co appropriately]. 
+ * and define FP_ADD_D & co appropriately].
  * The generic macros are defined in op-common.h. This is where all
  * the grotty stuff like handling NaNs is coded. To handle the possible
  * word sizes macros in op-common.h use macros like _FP_FRAC_SLL_##wc()
- * where wc is the 'number of machine words' parameter (here 2). 
+ * where wc is the 'number of machine words' parameter (here 2).
  * These are defined in the third layer of macros: op-1.h, op-2.h
  * and op-4.h. These handle operations on floating point numbers composed
  * of 1,2 and 4 machine words respectively. [For example, on sparc64
@@ -41,7 +34,7 @@
  * constructs in op-1.h, but on sparc32 they use op-2.h definitions.]
  * soft-fp.h is on the same level as op-common.h, and defines some
  * macros which are independent of both word size and FP format.
- * Finally, sfp-machine.h is the machine dependent part of the 
+ * Finally, sfp-machine.h is the machine dependent part of the
  * code: it defines the word size and what type a word is. It also
  * defines how _FP_MUL_MEAT_t() maps to _FP_MUL_MEAT_n_* : op-n.h
  * provide several possible flavours of multiply algorithm, most
@@ -64,59 +57,11 @@
  * so we follow that practice...
  */
 
-/* WISHLIST:
- *
- * + Replace all the macros with inline functions. These should
- * have the same effect but be much easier to work with.
- *
- * + Emulate the IEEE exception flags. We don't currently do this
- * because a) it would require significant alterations to
- * the emulation macros [see the comments about _FP_NEG()
- * in op-common.c and note that we'd need to invent a convention
- * for passing in the flags to FXXXX fns and returning them] and 
- * b) SPARClinux doesn't let users access the flags anyway 
- * [contrast Solaris, which allows you to examine, clear or set
- * the flags, and request that exceptions cause SIGFPE 
- * [which you then set up a signal handler for, obviously...]].
- * Erm, (b) may quite possibly be garbage. %fsr is user-writable
- * so you don't need a syscall. There may or may not be library
- * support.
- *
- * + Emulation of FMULQ, FDIVQ, FSQRTQ, FDMULQ needs to be 
- * written!
- * 
- * + reindent code to conform to Linux kernel standard :->
- *
- * + work out whether all the compile-time warnings are bogus
- *
- * + check that conversion to/from integers works
- * 
- * + check with the SPARC architecture manual to see if we resolve
- * the implementation-dependent bits of the IEEE spec in the
- * same manner as the hardware.
- *
- * + more test cases for the test script always welcome!
- *
- * + illegal opcodes currently cause SIGFPEs. We should arrange
- * to tell the traps.c code to SIGILL instead. Currently,
- * everywhere that we return 0 should cause SIGILL, I think.
- * SIGFPE should only be caused if we set an IEEE exception bit
- * and the relevant trap bit is also set. (this means that 
- * traps.c should do this; also it should handle the case of
- * IEEE exception generated directly by the hardware.)
- * Should illegal_fp_register (which is a flavour of fp exception)
- * cause SIGFPE or  SIGILL?
- *
- * + the test script needs to be extended to handle the quadword
- * and comparison insns.
- *
- * + _FP_DIV_MEAT_2_udiv_64() appears to work but it should be
- * checked by somebody who understands the algorithm :->
- * 
- * + fpsave() saves the FP queue but fpload() doesn't reload it.
+/* TODO:
+ * fpsave() saves the FP queue but fpload() doesn't reload it.
  * Therefore when we context switch or change FPU ownership
  * we have to check to see if the queue had anything in it and
- * emulate it if it did. This is going to be a pain. 
+ * emulate it if it did. This is going to be a pain.
  */
 
 #include <linux/types.h>
@@ -124,71 +69,57 @@
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 
+#include "sfp-util.h"
 #include "soft-fp.h"
+#include "single.h"
+#include "double.h"
+#include "quad.h"
 
 #define FLOATFUNC(x) extern int x(void *,void *,void *)
 
-/* Current status: we don't properly emulate the difficult quadword
- * insns (MUL, DIV, SQRT).
- * There are also some ops involving the FP registers which we don't
- * emulate: the branch on FP condition flags and the load/store to
- * FP regs or FSR. I'm assuming that these will never generate traps
- * (not unreasonable if there's an FPU at all; comments in the NetBSD
- * kernel source agree on this point). If we wanted to allow
- * purely software-emulation of the FPU with FPU totally disabled
- * or non-existent, we'd have to emulate these as well. We'd also
- * need to alter the fp_disabled trap handler to call the math-emu
- * code appropriately. The structure of do_one_mathemu() is also
- * inappropriate for these ops (as it has no way to alter the pc, 
- * for a start) and it might be better to special-case them in do_mathemu().
- * Oh, and you'd need to alter the traps.c code so it didn't try to
- * fpsave() and fpload(). If there's genuinely no FPU then there's 
- * probably bits of kernel stuff that just won't work anyway...
- */
-
 /* The Vn labels indicate what version of the SPARC architecture gas thinks
- * each insn is. This is from the binutils source :-> 
+ * each insn is. This is from the binutils source :->
  */
 /* quadword instructions */
-FLOATFUNC(FSQRTQ);                                /* v8 NYI */
-FLOATFUNC(FADDQ);                                 /* v8 */
-FLOATFUNC(FSUBQ);                                 /* v8 */
-FLOATFUNC(FMULQ);                                 /* v8 NYI */
-FLOATFUNC(FDIVQ);                                 /* v8 NYI */
-FLOATFUNC(FDMULQ);                                /* v8 NYI */
-FLOATFUNC(FQTOS);                                 /* v8 */
-FLOATFUNC(FQTOD);                                 /* v8 */
-FLOATFUNC(FITOQ);                                 /* v8 */
-FLOATFUNC(FSTOQ);                                 /* v8 */
-FLOATFUNC(FDTOQ);                                 /* v8 */
-FLOATFUNC(FQTOI);                                 /* v8 */
-FLOATFUNC(FCMPQ);                                 /* v8 */
-FLOATFUNC(FCMPEQ);                                /* v8 */
+#define FSQRTQ	0x02b		/* v8 */
+#define FADDQ	0x043		/* v8 */
+#define FSUBQ	0x047		/* v8 */
+#define FMULQ	0x04b		/* v8 */
+#define FDIVQ	0x04f		/* v8 */
+#define FDMULQ	0x06e		/* v8 */
+#define FQTOS	0x0c7		/* v8 */
+#define FQTOD	0x0cb		/* v8 */
+#define FITOQ	0x0cc		/* v8 */
+#define FSTOQ	0x0cd		/* v8 */
+#define FDTOQ	0x0ce		/* v8 */
+#define FQTOI	0x0d3		/* v8 */
+#define FCMPQ	0x053		/* v8 */
+#define FCMPEQ	0x057		/* v8 */
 /* single/double instructions (subnormal): should all work */
-FLOATFUNC(FSQRTS);                                /* v7 */
-FLOATFUNC(FSQRTD);                                /* v7 */
-FLOATFUNC(FADDS);                                 /* v6 */
-FLOATFUNC(FADDD);                                 /* v6 */
-FLOATFUNC(FSUBS);                                 /* v6 */
-FLOATFUNC(FSUBD);                                 /* v6 */
-FLOATFUNC(FMULS);                                 /* v6 */
-FLOATFUNC(FMULD);                                 /* v6 */
-FLOATFUNC(FDIVS);                                 /* v6 */
-FLOATFUNC(FDIVD);                                 /* v6 */
-FLOATFUNC(FSMULD);                                /* v8 */
-FLOATFUNC(FDTOS);                                 /* v6 */
-FLOATFUNC(FSTOD);                                 /* v6 */
-FLOATFUNC(FSTOI);                                 /* v6 */
-FLOATFUNC(FDTOI);                                 /* v6 */
-FLOATFUNC(FABSS);                                 /* v6 */
-FLOATFUNC(FCMPS);                                 /* v6 */
-FLOATFUNC(FCMPES);                                /* v6 */
-FLOATFUNC(FCMPD);                                 /* v6 */
-FLOATFUNC(FCMPED);                                /* v6 */
-FLOATFUNC(FMOVS);                                 /* v6 */
-FLOATFUNC(FNEGS);                                 /* v6 */
-FLOATFUNC(FITOS);                                 /* v6 */
-FLOATFUNC(FITOD);                                 /* v6 */
+#define FSQRTS	0x029		/* v7 */
+#define FSQRTD	0x02a		/* v7 */
+#define FADDS	0x041		/* v6 */
+#define FADDD	0x042		/* v6 */
+#define FSUBS	0x045		/* v6 */
+#define FSUBD	0x046		/* v6 */
+#define FMULS	0x049		/* v6 */
+#define FMULD	0x04a		/* v6 */
+#define FDIVS	0x04d		/* v6 */
+#define FDIVD	0x04e		/* v6 */
+#define FSMULD	0x069		/* v6 */
+#define FDTOS	0x0c6		/* v6 */
+#define FSTOD	0x0c9		/* v6 */
+#define FSTOI	0x0d1		/* v6 */
+#define FDTOI	0x0d2		/* v6 */
+#define FABSS	0x009		/* v6 */
+#define FCMPS	0x051		/* v6 */
+#define FCMPES	0x055		/* v6 */
+#define FCMPD	0x052		/* v6 */
+#define FCMPED	0x056		/* v6 */
+#define FMOVS	0x001		/* v6 */
+#define FNEGS	0x005		/* v6 */
+#define FITOS	0x0c4		/* v6 */
+#define FITOD	0x0c8		/* v6 */
 
 #define FSR_TEM_SHIFT	23UL
 #define FSR_TEM_MASK	(0x1fUL << FSR_TEM_SHIFT)
@@ -197,7 +128,7 @@
 #define FSR_CEXC_SHIFT	0UL
 #define FSR_CEXC_MASK	(0x1fUL << FSR_CEXC_SHIFT)
 
-static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs);   
+static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs);
 
 /* Unlike the Sparc64 version (which has a struct fpustate), we
  * pass the taskstruct corresponding to the task which currently owns the
@@ -210,65 +141,65 @@
  */
 int do_mathemu(struct pt_regs *regs, struct task_struct *fpt)
 {
-   /* regs->pc isn't necessarily the PC at which the offending insn is sitting.
-    * The FPU maintains a queue of FPops which cause traps. 
-    * When it hits an instruction that requires that the trapped op succeeded
-    * (usually because it reads a reg. that the trapped op wrote) then it
-    * causes this exception. We need to emulate all the insns on the queue
-    * and then allow the op to proceed.
-    * This code should also handle the case where the trap was precise,
-    * in which case the queue length is zero and regs->pc points at the 
-    * single FPop to be emulated. (this case is untested, though :->) 
-    * You'll need this case if you want to be able to emulate all FPops
-    * because the FPU either doesn't exist or has been software-disabled.
-    * [The UltraSPARC makes FP a precise trap; this isn't as stupid as it 
-    * might sound because the Ultra does funky things with a superscalar
-    * architecture.]
-    */
-   
-   /* You wouldn't believe how often I typed 'ftp' when I meant 'fpt' :-> */
-
-   int i;
-   int retcode = 0;                               /* assume all succeed */
-   unsigned long insn;
-   
-#ifdef DEBUG_MATHEMU   
-   printk("In do_mathemu()... pc is %08lx\n", regs->pc);
-   printk("fpqdepth is %ld\n",fpt->tss.fpqdepth);
-   for (i = 0; i < fpt->tss.fpqdepth; i++)
-      printk("%d: %08lx at %08lx\n",i,fpt->tss.fpqueue[i].insn, (unsigned long)fpt->tss.fpqueue[i].insn_addr);
-#endif      
-
-   if (fpt->tss.fpqdepth == 0) {                   /* no queue, guilty insn is at regs->pc */
-#ifdef DEBUG_MATHEMU   
-      printk("precise trap at %08lx\n", regs->pc);
+	/* regs->pc isn't necessarily the PC at which the offending insn is sitting.
+	 * The FPU maintains a queue of FPops which cause traps.
+	 * When it hits an instruction that requires that the trapped op succeeded
+	 * (usually because it reads a reg. that the trapped op wrote) then it
+	 * causes this exception. We need to emulate all the insns on the queue
+	 * and then allow the op to proceed.
+	 * This code should also handle the case where the trap was precise,
+	 * in which case the queue length is zero and regs->pc points at the
+	 * single FPop to be emulated. (this case is untested, though :->)
+	 * You'll need this case if you want to be able to emulate all FPops
+	 * because the FPU either doesn't exist or has been software-disabled.
+	 * [The UltraSPARC makes FP a precise trap; this isn't as stupid as it
+	 * might sound because the Ultra does funky things with a superscalar
+	 * architecture.]
+	 */
+
+	/* You wouldn't believe how often I typed 'ftp' when I meant 'fpt' :-> */
+
+	int i;
+	int retcode = 0;                               /* assume all succeed */
+	unsigned long insn;
+
+#ifdef DEBUG_MATHEMU
+	printk("In do_mathemu()... pc is %08lx\n", regs->pc);
+	printk("fpqdepth is %ld\n", fpt->tss.fpqdepth);
+	for (i = 0; i < fpt->tss.fpqdepth; i++)
+		printk("%d: %08lx at %08lx\n", i, fpt->tss.fpqueue[i].insn,
+		       (unsigned long)fpt->tss.fpqueue[i].insn_addr);
+#endif
+
+	if (fpt->tss.fpqdepth == 0) {                   /* no queue, guilty insn is at regs->pc */
+#ifdef DEBUG_MATHEMU
+		printk("precise trap at %08lx\n", regs->pc);
 #endif
-      if (!get_user(insn, (u32 *)regs->pc)) {
-         retcode = do_one_mathemu(insn, &fpt->tss.fsr, fpt->tss.float_regs);
-         if (retcode) {
-            /* in this case we need to fix up PC & nPC */
-            regs->pc = regs->npc;
-            regs->npc += 4;
-         }
-      }
-      return retcode;
-   }
-
-   /* Normal case: need to empty the queue... */
-   for (i = 0; i < fpt->tss.fpqdepth; i++)
-   {
-      retcode = do_one_mathemu(fpt->tss.fpqueue[i].insn, &(fpt->tss.fsr), fpt->tss.float_regs);
-      if (!retcode)                               /* insn failed, no point doing any more */
-         break;
-   }
-   /* Now empty the queue and clear the queue_not_empty flag */
-   if(retcode)
-	   fpt->tss.fsr &= ~(0x3000 | FSR_CEXC_MASK);
-   else
-	   fpt->tss.fsr &= ~0x3000;
-   fpt->tss.fpqdepth = 0;
-   
-   return retcode;
+		if (!get_user(insn, (u32 *)regs->pc)) {
+			retcode = do_one_mathemu(insn, &fpt->tss.fsr, fpt->tss.float_regs);
+			if (retcode) {
+				/* in this case we need to fix up PC & nPC */
+				regs->pc = regs->npc;
+				regs->npc += 4;
+			}
+		}
+		return retcode;
+	}
+
+	/* Normal case: need to empty the queue... */
+	for (i = 0; i < fpt->tss.fpqdepth; i++) {
+		retcode = do_one_mathemu(fpt->tss.fpqueue[i].insn, &(fpt->tss.fsr), fpt->tss.float_regs);
+		if (!retcode)                               /* insn failed, no point doing any more */
+			break;
+	}
+	/* Now empty the queue and clear the queue_not_empty flag */
+	if(retcode)
+		fpt->tss.fsr &= ~(0x3000 | FSR_CEXC_MASK);
+	else
+		fpt->tss.fsr &= ~0x3000;
+	fpt->tss.fpqdepth = 0;
+
+	return retcode;
 }
 
 /* All routines returning an exception to raise should detect
@@ -279,7 +210,7 @@
  *
  * We return 0 if a SIGFPE should be sent, 1 otherwise.
  */
-static int record_exception(unsigned long *pfsr, int eflag)
+static inline int record_exception(unsigned long *pfsr, int eflag)
 {
 	unsigned long fsr = *pfsr;
 	int would_trap;
@@ -291,46 +222,36 @@
 	if(would_trap != 0) {
 		eflag &= ((fsr & FSR_TEM_MASK) >> FSR_TEM_SHIFT);
 		if((eflag & (eflag - 1)) != 0) {
-			if(eflag & EFLAG_INVALID)
-				eflag = EFLAG_INVALID;
-			else if(eflag & EFLAG_DIVZERO)
-				eflag = EFLAG_DIVZERO;
-			else if(eflag & EFLAG_INEXACT)
-				eflag = EFLAG_INEXACT;
+			if(eflag & FP_EX_INVALID)
+				eflag = FP_EX_INVALID;
+			else if(eflag & FP_EX_OVERFLOW)
+				eflag = FP_EX_OVERFLOW;
+			else if(eflag & FP_EX_UNDERFLOW)
+				eflag = FP_EX_UNDERFLOW;
+			else if(eflag & FP_EX_DIVZERO)
+				eflag = FP_EX_DIVZERO;
+			else if(eflag & FP_EX_INEXACT)
+				eflag = FP_EX_INEXACT;
 		}
 	}
 
-	/* Set CEXC, here are the rules:
+	/* Set CEXC, here is the rule:
 	 *
-	 * 1) In general all FPU ops will set one and only one
+	 *    In general all FPU ops will set one and only one
 	 *    bit in the CEXC field, this is always the case
 	 *    when the IEEE exception trap is enabled in TEM.
-	 *
-	 * 2) As a special case, if an overflow or underflow
-	 *    is being signalled, AND the trap is not enabled
-	 *    in TEM, then the inexact field shall also be set.
 	 */
 	fsr &= ~(FSR_CEXC_MASK);
-	if(would_trap ||
-	   (eflag & (EFLAG_OVERFLOW | EFLAG_UNDERFLOW)) == 0) {
-		fsr |= ((long)eflag << FSR_CEXC_SHIFT);
-	} else {
-		fsr |= (((long)eflag << FSR_CEXC_SHIFT) |
-			(EFLAG_INEXACT << FSR_CEXC_SHIFT));
-	}
+	fsr |= ((long)eflag << FSR_CEXC_SHIFT);
 
-	/* Set the AEXC field, rules are:
+	/* Set the AEXC field, rule is:
 	 *
-	 * 1) If a trap would not be generated, the
+	 *    If a trap would not be generated, the
 	 *    CEXC just generated is OR'd into the
 	 *    existing value of AEXC.
-	 *
-	 * 2) When a trap is generated, AEXC is cleared.
 	 */
 	if(would_trap == 0)
 		fsr |= ((long)eflag << FSR_AEXC_SHIFT);
-	else
-		fsr &= ~(FSR_AEXC_MASK);
 
 	/* If trapping, indicate fault trap type IEEE. */
 	if(would_trap != 0)
@@ -341,159 +262,264 @@
 	return (would_trap ? 0 : 1);
 }
 
-static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs)
+typedef union {
+	u32 s;
+	u64 d;
+	u64 q[2];
+} *argp;
+
+static int do_one_mathemu(u32 insn, unsigned long *pfsr, unsigned long *fregs)
 {
-   /* Emulate the given insn, updating fsr and fregs appropriately. */
-   int type = 0; 
-   /* 01 is single, 10 is double, 11 is quad, 
-    * 000011 is rs1, 001100 is rs2, 110000 is rd (00 in rd is fcc)
-    * 111100000000 tells which ftt that may happen in 
-    * (this field not used on sparc32 code, as we can't 
-    * extract trap type info for ops on the FP queue) 
-    */
-   int freg, eflag;
-   int (*func)(void *,void *,void *) = NULL;
-   void *rs1 = NULL, *rs2 = NULL, *rd = NULL;   
+	/* Emulate the given insn, updating fsr and fregs appropriately. */
+	int type = 0;
+	/* r is rd, b is rs2 and a is rs1. The *u arg tells
+	   whether the argument should be packed/unpacked (0 - do not unpack/pack, 1 - unpack/pack)
+	   non-u args tells the size of the argument (0 - no argument, 1 - single, 2 - double, 3 - quad */
+#define TYPE(dummy, r, ru, b, bu, a, au) type = (au << 2) | (a << 0) | (bu << 5) | (b << 3) | (ru << 8) | (r << 6)
+	int freg;
+	argp rs1 = NULL, rs2 = NULL, rd = NULL;
+	FP_DECL_EX;
+	FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+	FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+	FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
+	int IR;
+	long fsr;
 
 #ifdef DEBUG_MATHEMU
-   printk("In do_mathemu(), emulating %08lx\n", insn);
-#endif   
-      
-   if ((insn & 0xc1f80000) == 0x81a00000) /* FPOP1 */ {
-      switch ((insn >> 5) & 0x1ff) {
-         /* QUAD - ftt == 3 */
-         case 0x001: type = 0x314; func = FMOVS; break;
-         case 0x005: type = 0x314; func = FNEGS; break;
-         case 0x009: type = 0x314; func = FABSS; break;
-         case 0x02b: type = 0x33c; func = FSQRTQ; break;
-         case 0x043: type = 0x33f; func = FADDQ; break;
-         case 0x047: type = 0x33f; func = FSUBQ; break;
-         case 0x04b: type = 0x33f; func = FMULQ; break;
-         case 0x04f: type = 0x33f; func = FDIVQ; break;
-         case 0x06e: type = 0x33a; func = FDMULQ; break;
-         case 0x0c7: type = 0x31c; func = FQTOS; break;
-         case 0x0cb: type = 0x32c; func = FQTOD; break;
-         case 0x0cc: type = 0x334; func = FITOQ; break;
-         case 0x0cd: type = 0x334; func = FSTOQ; break;
-         case 0x0ce: type = 0x338; func = FDTOQ; break;
-         case 0x0d3: type = 0x31c; func = FQTOI; break;
-            /* SUBNORMAL - ftt == 2 */
-         case 0x029: type = 0x214; func = FSQRTS; break;
-         case 0x02a: type = 0x228; func = FSQRTD; break;
-         case 0x041: type = 0x215; func = FADDS; break;
-         case 0x042: type = 0x22a; func = FADDD; break;
-         case 0x045: type = 0x215; func = FSUBS; break;
-         case 0x046: type = 0x22a; func = FSUBD; break;
-         case 0x049: type = 0x215; func = FMULS; break;
-         case 0x04a: type = 0x22a; func = FMULD; break;
-         case 0x04d: type = 0x215; func = FDIVS; break;
-         case 0x04e: type = 0x22a; func = FDIVD; break;
-         case 0x069: type = 0x225; func = FSMULD; break;
-         case 0x0c6: type = 0x218; func = FDTOS; break;
-         case 0x0c9: type = 0x224; func = FSTOD; break;
-         case 0x0d1: type = 0x214; func = FSTOI; break;
-         case 0x0d2: type = 0x218; func = FDTOI; break;
-         default: 
-#ifdef DEBUG_MATHEMU         
-         	printk("unknown FPop1: %03lx\n",(insn>>5)&0x1ff);
-#endif         
-      }
-   }
-   else if ((insn & 0xc1f80000) == 0x81a80000) /* FPOP2 */ {
-      switch ((insn >> 5) & 0x1ff) {
-         case 0x051: type = 0x305; func = FCMPS; break;
-         case 0x052: type = 0x30a; func = FCMPD; break;
-         case 0x053: type = 0x30f; func = FCMPQ; break;
-         case 0x055: type = 0x305; func = FCMPES; break;
-         case 0x056: type = 0x30a; func = FCMPED; break;
-         case 0x057: type = 0x30f; func = FCMPEQ; break;
-         default: 
-#ifdef DEBUG_MATHEMU         
-         	printk("unknown FPop2: %03lx\n",(insn>>5)&0x1ff);
-#endif         	
-      }
-   }
-   
-   if (!type) { /* oops, didn't recognise that FPop */
-      printk("attempt to emulate unrecognised FPop!\n");
-      return 0;
-   }
-   
-   /* Decode the registers to be used */
-   freg = (*fsr >> 14) & 0xf;
-
-   *fsr &= ~0x1c000;                              /* clear the traptype bits */
-    
-   freg = ((insn >> 14) & 0x1f);
-   switch (type & 0x3)                            /* is rs1 single, double or quad? */
-   {
-      case 3:
-         if (freg & 3)                            /* quadwords must have bits 4&5 of the */
-         {                                        /* encoded reg. number set to zero. */
-            *fsr |= (6 << 14);                  
-            return 0;                             /* simulate invalid_fp_register exception */
-         }
-         /* fall through */
-      case 2:
-         if (freg & 1)                            /* doublewords must have bit 5 zeroed */
-         {
-            *fsr |= (6 << 14);
-            return 0;
-         }
-   }
-   rs1 = (void *)&fregs[freg];
-   freg = (insn & 0x1f);
-   switch ((type >> 2) & 0x3)
-   {                                              /* same again for rs2 */
-      case 3:
-         if (freg & 3)                            /* quadwords must have bits 4&5 of the */
-         {                                        /* encoded reg. number set to zero. */
-            *fsr |= (6 << 14);                  
-            return 0;                             /* simulate invalid_fp_register exception */
-         }
-         /* fall through */
-      case 2:
-         if (freg & 1)                            /* doublewords must have bit 5 zeroed */
-         {
-            *fsr |= (6 << 14);
-            return 0;
-         }
-   }
-   rs2 = (void *)&fregs[freg];
-   freg = ((insn >> 25) & 0x1f);
-   switch ((type >> 4) & 0x3)                     /* and finally rd. This one's a bit different */
-   {
-      case 0:                                     /* dest is fcc. (this must be FCMPQ or FCMPEQ) */
-         if (freg)                                /* V8 has only one set of condition codes, so */
-         {                                        /* anything but 0 in the rd field is an error */
-            *fsr |= (6 << 14);                    /* (should probably flag as invalid opcode */
-            return 0;                             /* but SIGFPE will do :-> ) */
-         }
-         rd = (void *)(fsr);                      /* FCMPQ and FCMPEQ are special and only  */
-         break;                                   /* set bits they're supposed to :-> */
-      case 3:
-         if (freg & 3)                            /* quadwords must have bits 4&5 of the */
-         {                                        /* encoded reg. number set to zero. */
-            *fsr |= (6 << 14);
-            return 0;                             /* simulate invalid_fp_register exception */
-         }
-         /* fall through */
-      case 2:
-         if (freg & 1)                            /* doublewords must have bit 5 zeroed */
-         {
-            *fsr |= (6 << 14);
-            return 0;
-         }
-         /* fall through */
-      case 1:
-         rd = (void *)&fregs[freg];
-         break;
-   }
-#ifdef DEBUG_MATHEMU   
-   printk("executing insn...\n");
-#endif   
-   eflag = func(rd, rs2, rs1);                   /* do the Right Thing */
-   if(eflag == 0)
-	   return 1;                             /* success! */
-   return record_exception(fsr, eflag);
+	printk("In do_mathemu(), emulating %08lx\n", insn);
+#endif
+
+	if ((insn & 0xc1f80000) == 0x81a00000)	/* FPOP1 */ {
+		switch ((insn >> 5) & 0x1ff) {
+		case FSQRTQ: TYPE(3,3,1,3,1,0,0); break;
+		case FADDQ:
+		case FSUBQ:
+		case FMULQ:
+		case FDIVQ: TYPE(3,3,1,3,1,3,1); break;
+		case FDMULQ: TYPE(3,3,1,2,1,2,1); break;
+		case FQTOS: TYPE(3,1,1,3,1,0,0); break;
+		case FQTOD: TYPE(3,2,1,3,1,0,0); break;
+		case FITOQ: TYPE(3,3,1,1,0,0,0); break;
+		case FSTOQ: TYPE(3,3,1,1,1,0,0); break;
+		case FDTOQ: TYPE(3,3,1,2,1,0,0); break;
+		case FQTOI: TYPE(3,1,0,3,1,0,0); break;
+		case FSQRTS: TYPE(2,1,1,1,1,0,0); break;
+		case FSQRTD: TYPE(2,2,1,2,1,0,0); break;
+		case FADDD:
+		case FSUBD:
+		case FMULD:
+		case FDIVD: TYPE(2,2,1,2,1,2,1); break;
+		case FADDS:
+		case FSUBS:
+		case FMULS:
+		case FDIVS: TYPE(2,1,1,1,1,1,1); break;
+		case FSMULD: TYPE(2,2,1,1,1,1,1); break;
+		case FDTOS: TYPE(2,1,1,2,1,0,0); break;
+		case FSTOD: TYPE(2,2,1,1,1,0,0); break;
+		case FSTOI: TYPE(2,1,0,1,1,0,0); break;
+		case FDTOI: TYPE(2,1,0,2,1,0,0); break;
+		case FITOS: TYPE(2,1,1,1,0,0,0); break;
+		case FITOD: TYPE(2,2,1,1,0,0,0); break;
+		case FMOVS:
+		case FABSS:
+		case FNEGS: TYPE(2,1,0,1,0,0,0); break;
+		default:
+#ifdef DEBUG_MATHEMU
+			printk("unknown FPop1: %03lx\n",(insn>>5)&0x1ff);
+#endif
+		}
+	} else if ((insn & 0xc1f80000) == 0x81a80000)	/* FPOP2 */ {
+		switch ((insn >> 5) & 0x1ff) {
+		case FCMPS: TYPE(3,0,0,1,0,1,0); break;
+		case FCMPES: TYPE(3,0,0,1,0,1,0); break;
+		case FCMPD: TYPE(3,0,0,2,0,2,0); break;
+		case FCMPED: TYPE(3,0,0,2,0,2,0); break;
+		case FCMPQ: TYPE(3,0,0,3,0,3,0); break;
+		case FCMPEQ: TYPE(3,0,0,3,0,3,0); break;
+		default:
+#ifdef DEBUG_MATHEMU
+			printk("unknown FPop2: %03lx\n",(insn>>5)&0x1ff);
+#endif
+		}
+	}
+
+	if (!type) {	/* oops, didn't recognise that FPop */
+#ifdef DEBUG_MATHEMU
+		printk("attempt to emulate unrecognised FPop!\n");
+#endif
+		return 0;
+	}
+
+	/* Decode the registers to be used */
+	freg = (*pfsr >> 14) & 0xf;
+
+	*pfsr &= ~0x1c000;				/* clear the traptype bits */
+	
+	freg = ((insn >> 14) & 0x1f);
+	switch (type & 0x3) {				/* is rs1 single, double or quad? */
+	case 3:
+		if (freg & 3) {				/* quadwords must have bits 4&5 of the */
+							/* encoded reg. number set to zero. */
+			*pfsr |= (6 << 14);
+			return 0;			/* simulate invalid_fp_register exception */
+		}
+	/* fall through */
+	case 2:
+		if (freg & 1) {				/* doublewords must have bit 5 zeroed */
+			*pfsr |= (6 << 14);
+			return 0;
+		}
+	}
+	rs1 = (argp)&fregs[freg];
+	switch (type & 0x7) {
+	case 7: FP_UNPACK_QP (QA, rs1); break;
+	case 6: FP_UNPACK_DP (DA, rs1); break;
+	case 5: FP_UNPACK_SP (SA, rs1); break;
+	}
+	freg = (insn & 0x1f);
+	switch ((type >> 3) & 0x3) {			/* same again for rs2 */
+	case 3:
+		if (freg & 3) {				/* quadwords must have bits 4&5 of the */
+							/* encoded reg. number set to zero. */
+			*pfsr |= (6 << 14);
+			return 0;			/* simulate invalid_fp_register exception */
+		}
+	/* fall through */
+	case 2:
+		if (freg & 1) {				/* doublewords must have bit 5 zeroed */
+			*pfsr |= (6 << 14);
+			return 0;
+		}
+	}
+	rs2 = (argp)&fregs[freg];
+	switch ((type >> 3) & 0x7) {
+	case 7: FP_UNPACK_QP (QB, rs2); break;
+	case 6: FP_UNPACK_DP (DB, rs2); break;
+	case 5: FP_UNPACK_SP (SB, rs2); break;
+	}
+	freg = ((insn >> 25) & 0x1f);
+	switch ((type >> 6) & 0x3) {			/* and finally rd. This one's a bit different */
+	case 0:						/* dest is fcc. (this must be FCMPQ or FCMPEQ) */
+		if (freg) {				/* V8 has only one set of condition codes, so */
+							/* anything but 0 in the rd field is an error */
+			*pfsr |= (6 << 14);		/* (should probably flag as invalid opcode */
+			return 0;			/* but SIGFPE will do :-> ) */
+		}
+		break;
+	case 3:
+		if (freg & 3) {				/* quadwords must have bits 4&5 of the */
+							/* encoded reg. number set to zero. */
+			*pfsr |= (6 << 14);
+			return 0;			/* simulate invalid_fp_register exception */
+		}
+	/* fall through */
+	case 2:
+		if (freg & 1) {				/* doublewords must have bit 5 zeroed */
+			*pfsr |= (6 << 14);
+			return 0;
+		}
+	/* fall through */
+	case 1:
+		rd = (void *)&fregs[freg];
+		break;
+	}
+#ifdef DEBUG_MATHEMU
+	printk("executing insn...\n");
+#endif
+	/* do the Right Thing */
+	switch ((insn >> 5) & 0x1ff) {
+	/* + */
+	case FADDS: FP_ADD_S (SR, SA, SB); break;
+	case FADDD: FP_ADD_D (DR, DA, DB); break;
+	case FADDQ: FP_ADD_Q (QR, QA, QB); break;
+	/* - */
+	case FSUBS: FP_SUB_S (SR, SA, SB); break;
+	case FSUBD: FP_SUB_D (DR, DA, DB); break;
+	case FSUBQ: FP_SUB_Q (QR, QA, QB); break;
+	/* * */
+	case FMULS: FP_MUL_S (SR, SA, SB); break;
+	case FSMULD: FP_CONV (D, S, 2, 1, DA, SA);
+		     FP_CONV (D, S, 2, 1, DB, SB);
+	case FMULD: FP_MUL_D (DR, DA, DB); break;
+	case FDMULQ: FP_CONV (Q, D, 4, 2, QA, DA);
+		     FP_CONV (Q, D, 4, 2, QB, DB);
+	case FMULQ: FP_MUL_Q (QR, QA, QB); break;
+	/* / */
+	case FDIVS: FP_DIV_S (SR, SA, SB); break;
+	case FDIVD: FP_DIV_D (DR, DA, DB); break;
+	case FDIVQ: FP_DIV_Q (QR, QA, QB); break;
+	/* sqrt */
+	case FSQRTS: FP_SQRT_S (SR, SB); break;
+	case FSQRTD: FP_SQRT_D (DR, DB); break;
+	case FSQRTQ: FP_SQRT_Q (QR, QB); break;
+	/* mov */
+	case FMOVS: rd->s = rs2->s; break;
+	case FABSS: rd->s = rs2->s & 0x7fffffff; break;
+	case FNEGS: rd->s = rs2->s ^ 0x80000000; break;
+	/* float to int */
+	case FSTOI: FP_TO_INT_S (IR, SB, 32, 1); break;
+	case FDTOI: FP_TO_INT_D (IR, DB, 32, 1); break;
+	case FQTOI: FP_TO_INT_Q (IR, QB, 32, 1); break;
+	/* int to float */
+	case FITOS: IR = rs2->s; FP_FROM_INT_S (SR, IR, 32, int); break;
+	case FITOD: IR = rs2->s; FP_FROM_INT_D (DR, IR, 32, int); break;
+	case FITOQ: IR = rs2->s; FP_FROM_INT_Q (QR, IR, 32, int); break;
+	/* float to float */
+	case FSTOD: FP_CONV (D, S, 2, 1, DR, SB); break;
+	case FSTOQ: FP_CONV (Q, S, 4, 1, QR, SB); break;
+	case FDTOQ: FP_CONV (Q, D, 4, 2, QR, DB); break;
+	case FDTOS: FP_CONV (S, D, 1, 2, SR, DB); break;
+	case FQTOS: FP_CONV (S, Q, 1, 4, SR, QB); break;
+	case FQTOD: FP_CONV (D, Q, 2, 4, DR, QB); break;
+	/* comparison */
+	case FCMPS:
+	case FCMPES:
+		FP_UNPACK_RAW_SP (SA, rs1);
+		FP_UNPACK_RAW_SP (SB, rs2);
+		FP_CMP_S(IR, SB, SA, 3);
+		if (IR == 3 &&
+		    (((insn >> 5) & 0x1ff) == FCMPES ||
+		     FP_ISSIGNAN_S(SA) ||
+		     FP_ISSIGNAN_S(SB)))
+			FP_SET_EXCEPTION (FP_EX_INVALID);
+		break;
+	case FCMPD:
+	case FCMPED:
+		FP_UNPACK_RAW_DP (DA, rs1);
+		FP_UNPACK_RAW_DP (DB, rs2);
+		FP_CMP_D(IR, DB, DA, 3);
+		if (IR == 3 &&
+		    (((insn >> 5) & 0x1ff) == FCMPED ||
+		     FP_ISSIGNAN_D(DA) ||
+		     FP_ISSIGNAN_D(DB)))
+			FP_SET_EXCEPTION (FP_EX_INVALID);
+		break;
+	case FCMPQ:
+	case FCMPEQ:
+		FP_UNPACK_RAW_QP (QA, rs1);
+		FP_UNPACK_RAW_QP (QB, rs2);
+		FP_CMP_Q(IR, QB, QA, 3);
+		if (IR == 3 &&
+		    (((insn >> 5) & 0x1ff) == FCMPEQ ||
+		     FP_ISSIGNAN_Q(QA) ||
+		     FP_ISSIGNAN_Q(QB)))
+			FP_SET_EXCEPTION (FP_EX_INVALID);
+	}
+	if (!FP_INHIBIT_RESULTS) {
+		switch ((type >> 6) & 0x7) {
+		case 0: fsr = *pfsr;
+			if (IR == -1) IR = 2;
+			/* fcc is always fcc0 */
+			fsr &= ~0xc00; fsr |= (IR << 10); break;
+			*pfsr = fsr;
+			break;
+		case 1: rd->s = IR; break;
+		case 5: FP_PACK_SP (rd, SR); break;
+		case 6: FP_PACK_DP (rd, DR); break;
+		case 7: FP_PACK_QP (rd, QR); break;
+		}
+	}
+	if(_fex == 0)
+		return 1;				/* success! */
+	return record_exception(pfsr, _fex);
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/sfp-machine.h linux.14p16/arch/sparc/math-emu/sfp-machine.h
--- linux.vanilla/arch/sparc/math-emu/sfp-machine.h	Sat Aug 14 02:27:15 1999
+++ linux.14p16/arch/sparc/math-emu/sfp-machine.h	Thu Dec  9 15:34:22 1999
@@ -1,6 +1,11 @@
-/* Machine-dependent software floating-point definitions.  Sparc version.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+/* Machine-dependent software floating-point definitions.
+   Sparc userland (_Q_*) version.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+		  Jakub Jelinek (jj@ultra.linux.cz),
+		  David S. Miller (davem@redhat.com) and
+		  Peter Maydell (pmaydell@chiark.greenend.org.uk).
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public License as
@@ -15,405 +20,186 @@
    You should have received a copy of the GNU Library General Public
    License along with the GNU C Library; see the file COPYING.LIB.  If
    not, write to the Free Software Foundation, Inc.,
-   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
-   Actually, this is a sparc (32bit) version, written based on the
-   i386 and sparc64 versions, by me, 
-   Peter Maydell (pmaydell@chiark.greenend.org.uk).
-   Comments are by and large also mine, although they may be inaccurate.
-
-   In picking out asm fragments I've gone with the lowest common
-   denominator, which also happens to be the hardware I have :->
-   That is, a SPARC without hardware multiply and divide.
- */
-
-
-/* basic word size definitions */
+#ifndef _SFP_MACHINE_H
+#define _SFP_MACHINE_H
+   
 #define _FP_W_TYPE_SIZE		32
 #define _FP_W_TYPE		unsigned long
 #define _FP_WS_TYPE		signed long
 #define _FP_I_TYPE		long
 
-/* You can optionally code some things like addition in asm. For
- * example, i386 defines __FP_FRAC_ADD_2 as asm. If you don't
- * then you get a fragment of C code [if you change an #ifdef 0
- * in op-2.h] or a call to add_ssaaaa (see below).
- * Good places to look for asm fragments to use are gcc and glibc.
- * gcc's longlong.h is useful.
- */
-
-/* We need to know how to multiply and divide. If the host word size
- * is >= 2*fracbits you can use FP_MUL_MEAT_n_imm(t,R,X,Y) which
- * codes the multiply with whatever gcc does to 'a * b'.
- * _FP_MUL_MEAT_n_wide(t,R,X,Y,f) is used when you have an asm 
- * function that can multiply two 1W values and get a 2W result. 
- * Otherwise you're stuck with _FP_MUL_MEAT_n_hard(t,R,X,Y) which
- * does bitshifting to avoid overflow.
- * For division there is FP_DIV_MEAT_n_imm(t,R,X,Y,f) for word size
- * >= 2*fracbits, where f is either _FP_DIV_HELP_imm or 
- * _FP_DIV_HELP_ldiv (see op-1.h).
- * _FP_DIV_MEAT_udiv() is if you have asm to do 2W/1W => (1W, 1W).
- * [GCC and glibc have longlong.h which has the asm macro udiv_qrnnd
- * to do this.]
- * In general, 'n' is the number of words required to hold the type,
- * and 't' is either S, D or Q for single/double/quad.
- *           -- PMM
- */
-/* Example: SPARC64:
- * #define _FP_MUL_MEAT_S(R,X,Y)	_FP_MUL_MEAT_1_imm(S,R,X,Y)
- * #define _FP_MUL_MEAT_D(R,X,Y)	_FP_MUL_MEAT_1_wide(D,R,X,Y,umul_ppmm)
- * #define _FP_MUL_MEAT_Q(R,X,Y)	_FP_MUL_MEAT_2_wide(Q,R,X,Y,umul_ppmm)
- *
- * #define _FP_DIV_MEAT_S(R,X,Y)	_FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm)
- * #define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_1_udiv(D,R,X,Y)
- * #define _FP_DIV_MEAT_Q(R,X,Y)	_FP_DIV_MEAT_2_udiv_64(Q,R,X,Y)
- *
- * Example: i386:
- * #define _FP_MUL_MEAT_S(R,X,Y)   _FP_MUL_MEAT_1_wide(S,R,X,Y,_i386_mul_32_64)
- * #define _FP_MUL_MEAT_D(R,X,Y)   _FP_MUL_MEAT_2_wide(D,R,X,Y,_i386_mul_32_64)
- *
- * #define _FP_DIV_MEAT_S(R,X,Y)   _FP_DIV_MEAT_1_udiv(S,R,X,Y,_i386_div_64_32)
- * #define _FP_DIV_MEAT_D(R,X,Y)   _FP_DIV_MEAT_2_udiv_64(D,R,X,Y)
- */
-#define _FP_MUL_MEAT_S(R,X,Y)   _FP_MUL_MEAT_1_wide(S,R,X,Y,umul_ppmm)
-#define _FP_MUL_MEAT_D(R,X,Y)   _FP_MUL_MEAT_2_wide(D,R,X,Y,umul_ppmm)
-/* FIXME: This is not implemented, but should be soon */
-#define _FP_MUL_MEAT_Q(R,X,Y)   _FP_FRAC_SET_4(R, _FP_ZEROFRAC_4)
-#define _FP_DIV_MEAT_S(R,X,Y)   _FP_DIV_MEAT_1_udiv(S,R,X,Y)
-#define _FP_DIV_MEAT_D(R,X,Y)   _FP_DIV_MEAT_2_udiv_64(D,R,X,Y)
-/* FIXME: This is not implemented, but should be soon */
-#define _FP_DIV_MEAT_Q(R,X,Y)   _FP_FRAC_SET_4(R, _FP_ZEROFRAC_4)
-
-/* These macros define what NaN looks like. They're supposed to expand to 
- * a comma-separated set of 32bit unsigned ints that encode NaN.
- */
-#define _FP_NANFRAC_S		_FP_QNANBIT_S
-#define _FP_NANFRAC_D		_FP_QNANBIT_D, 0
-#define _FP_NANFRAC_Q           _FP_QNANBIT_Q, 0, 0, 0
-
-/* On some architectures float-to-int conversions return a result
- * code.  On others (e.g. Sparc) they return 0
- */
-#define _FTOI_RESULT		0
+#define _FP_MUL_MEAT_S(R,X,Y)					\
+  _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_D(R,X,Y)					\
+  _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y)					\
+  _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
+
+#define _FP_DIV_MEAT_S(R,X,Y)	_FP_DIV_MEAT_1_udiv(S,R,X,Y)
+#define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_2_udiv(D,R,X,Y)
+#define _FP_DIV_MEAT_Q(R,X,Y)	_FP_DIV_MEAT_4_udiv(Q,R,X,Y)
+
+#define _FP_NANFRAC_S		((_FP_QNANBIT_S << 1) - 1)
+#define _FP_NANFRAC_D		((_FP_QNANBIT_D << 1) - 1), -1
+#define _FP_NANFRAC_Q		((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
+#define _FP_NANSIGN_S		0
+#define _FP_NANSIGN_D		0
+#define _FP_NANSIGN_Q		0
 
 #define _FP_KEEPNANFRACP 1
 
-/* This macro appears to be called when both X and Y are NaNs, and 
- * has to choose one and copy it to R. i386 goes for the larger of the
- * two, sparc64 just picks Y. I don't understand this at all so I'll
- * go with sparc64 because it's shorter :->   -- PMM 
+/* If one NaN is signaling and the other is not,
+ * we choose that one, otherwise we choose X.
  */
-#define _FP_CHOOSENAN(fs, wc, R, X, Y)				\
+/* For _Qp_* and _Q_*, this should prefer X, for
+ * CPU instruction emulation this should prefer Y.
+ * (see SPAMv9 B.2.2 section).
+ */
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)			\
   do {								\
-    R##_s = Y##_s;						\
-    _FP_FRAC_COPY_##wc(R,Y);					\
+    if ((_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)		\
+	&& !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))	\
+      {								\
+	R##_s = X##_s;						\
+	_FP_FRAC_COPY_##wc(R,X);				\
+      }								\
+    else							\
+      {								\
+	R##_s = Y##_s;						\
+	_FP_FRAC_COPY_##wc(R,Y);				\
+      }								\
     R##_c = FP_CLS_NAN;						\
   } while (0)
 
-#define _FP_CHOOSENAN_SQRT(fs, wc, R, X)			\
-  do {								\
-    	R##_s = 0;						\
-    	R##_c = FP_CLS_NAN;					\
-    	_FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);		\
-  } while (0)
+/* Some assembly to speed things up. */
+#define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)			\
+  __asm__ ("addcc %r7,%8,%2
+	    addxcc %r5,%6,%1
+	    addx %r3,%4,%0"						\
+	   : "=r" ((USItype)(r2)),					\
+	     "=&r" ((USItype)(r1)),					\
+	     "=&r" ((USItype)(r0))					\
+	   : "%rJ" ((USItype)(x2)),					\
+	     "rI" ((USItype)(y2)),					\
+	     "%rJ" ((USItype)(x1)),					\
+	     "rI" ((USItype)(y1)),					\
+	     "%rJ" ((USItype)(x0)),					\
+	     "rI" ((USItype)(y0))					\
+	   : "cc")
+
+#define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)			\
+  __asm__ ("subcc %r7,%8,%2
+	    subxcc %r5,%6,%1
+	    subx %r3,%4,%0"						\
+	   : "=r" ((USItype)(r2)),					\
+	     "=&r" ((USItype)(r1)),					\
+	     "=&r" ((USItype)(r0))					\
+	   : "%rJ" ((USItype)(x2)),					\
+	     "rI" ((USItype)(y2)),					\
+	     "%rJ" ((USItype)(x1)),					\
+	     "rI" ((USItype)(y1)),					\
+	     "%rJ" ((USItype)(x0)),					\
+	     "rI" ((USItype)(y0))					\
+	   : "cc")
+
+#define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)		\
+  do {									\
+    /* We need to fool gcc,  as we need to pass more than 10		\
+       input/outputs.  */						\
+    register USItype _t1 __asm__ ("g1"), _t2 __asm__ ("g2");		\
+    __asm__ __volatile__ ("
+	    addcc %r8,%9,%1
+	    addxcc %r6,%7,%0
+	    addxcc %r4,%5,%%g2
+	    addx %r2,%3,%%g1"						\
+	   : "=&r" ((USItype)(r1)),					\
+	     "=&r" ((USItype)(r0))					\
+	   : "%rJ" ((USItype)(x3)),					\
+	     "rI" ((USItype)(y3)),					\
+	     "%rJ" ((USItype)(x2)),					\
+	     "rI" ((USItype)(y2)),					\
+	     "%rJ" ((USItype)(x1)),					\
+	     "rI" ((USItype)(y1)),					\
+	     "%rJ" ((USItype)(x0)),					\
+	     "rI" ((USItype)(y0))					\
+	   : "cc", "g1", "g2");						\
+    __asm__ __volatile__ ("" : "=r" (_t1), "=r" (_t2));			\
+    r3 = _t1; r2 = _t2;							\
+  } while (0)
+
+#define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)		\
+  do {									\
+    /* We need to fool gcc,  as we need to pass more than 10		\
+       input/outputs.  */						\
+    register USItype _t1 __asm__ ("g1"), _t2 __asm__ ("g2");		\
+    __asm__ __volatile__ ("
+	    subcc %r8,%9,%1
+	    subxcc %r6,%7,%0
+	    subxcc %r4,%5,%%g2
+	    subx %r2,%3,%%g1"						\
+	   : "=&r" ((USItype)(r1)),					\
+	     "=&r" ((USItype)(r0))					\
+	   : "%rJ" ((USItype)(x3)),					\
+	     "rI" ((USItype)(y3)),					\
+	     "%rJ" ((USItype)(x2)),					\
+	     "rI" ((USItype)(y2)),					\
+	     "%rJ" ((USItype)(x1)),					\
+	     "rI" ((USItype)(y1)),					\
+	     "%rJ" ((USItype)(x0)),					\
+	     "rI" ((USItype)(y0))					\
+	   : "cc", "g1", "g2");						\
+    __asm__ __volatile__ ("" : "=r" (_t1), "=r" (_t2));			\
+    r3 = _t1; r2 = _t2;							\
+  } while (0)
+
+#define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0) __FP_FRAC_SUB_3(x2,x1,x0,x2,x1,x0,y2,y1,y0)
+
+#define __FP_FRAC_DEC_4(x3,x2,x1,x0,y3,y2,y1,y0) __FP_FRAC_SUB_4(x3,x2,x1,x0,x3,x2,x1,x0,y3,y2,y1,y0)
+
+#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i)					\
+  __asm__ ("addcc %3,%4,%3
+	    addxcc %2,%%g0,%2
+	    addxcc %1,%%g0,%1
+	    addx %0,%%g0,%0"						\
+	   : "=&r" ((USItype)(x3)),					\
+	     "=&r" ((USItype)(x2)),					\
+	     "=&r" ((USItype)(x1)),					\
+	     "=&r" ((USItype)(x0))					\
+	   : "rI" ((USItype)(i)),					\
+	     "0" ((USItype)(x3)),					\
+	     "1" ((USItype)(x2)),					\
+	     "2" ((USItype)(x1)),					\
+	     "3" ((USItype)(x0))					\
+	   : "cc")
 
-  
-#define __FP_UNPACK_DENORM(fs, wc, X)				\
-    {								\
-	_FP_I_TYPE _shift;					\
-	_FP_FRAC_CLZ_##wc(_shift, X);				\
-	_shift -= _FP_FRACXBITS_##fs;				\
-	_FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS));		\
-	X##_e -= _FP_EXPBIAS_##fs - 1 + _shift;			\
-	X##_c = FP_CLS_NORMAL;					\
-    }
-
-#define __FP_UNPACK_RAW_1(fs, X, val)				\
-  do {								\
-    union _FP_UNION_##fs *_flo =				\
-    	(union _FP_UNION_##fs *)val;				\
-								\
-    X##_f = _flo->bits.frac;					\
-    X##_e = _flo->bits.exp;					\
-    X##_s = _flo->bits.sign;					\
-  } while (0)
-
-#define __FP_UNPACK_RAW_2(fs, X, val)			\
-  do {							\
-    union _FP_UNION_##fs *_flo =			\
-    	(union _FP_UNION_##fs *)val;			\
-							\
-    X##_f0 = _flo->bits.frac0;				\
-    X##_f1 = _flo->bits.frac1;				\
-    X##_e  = _flo->bits.exp;				\
-    X##_s  = _flo->bits.sign;				\
-  } while (0)
-
-#define __FP_UNPACK_RAW_4(fs, X, val)			\
-  do {							\
-    union _FP_UNION_##fs *_flo =			\
-    	(union _FP_UNION_##fs *)val;			\
-							\
-    X##_f[0] = _flo->bits.frac0;			\
-    X##_f[1] = _flo->bits.frac1;			\
-    X##_f[2] = _flo->bits.frac2;			\
-    X##_f[3] = _flo->bits.frac3;			\
-    X##_e  = _flo->bits.exp;				\
-    X##_s  = _flo->bits.sign;				\
-  } while (0)
-
-#define __FP_UNPACK_S(X,val)		\
-  do {					\
-    __FP_UNPACK_RAW_1(S,X,val);		\
-    _FP_UNPACK_CANONICAL(S,1,X);	\
-  } while (0)
-
-#define __FP_UNPACK_D(X,val)		\
-  do {					\
-    __FP_UNPACK_RAW_2(D,X,val);		\
-    _FP_UNPACK_CANONICAL(D,2,X);	\
-  } while (0)
-
-#define __FP_UNPACK_Q(X,val)		\
-  do {					\
-    __FP_UNPACK_RAW_4(Q,X,val);		\
-    _FP_UNPACK_CANONICAL(Q,4,X);	\
-  } while (0)
-
-#define __FP_PACK_RAW_1(fs, val, X)				\
-  do {								\
-    union _FP_UNION_##fs *_flo =				\
-    	(union _FP_UNION_##fs *)val;				\
-								\
-    _flo->bits.frac = X##_f;					\
-    _flo->bits.exp  = X##_e;					\
-    _flo->bits.sign = X##_s;					\
-  } while (0)
-  
-#define __FP_PACK_RAW_2(fs, val, X)			\
-  do {							\
-    union _FP_UNION_##fs *_flo =			\
-    	(union _FP_UNION_##fs *)val;			\
-							\
-    _flo->bits.frac0 = X##_f0;				\
-    _flo->bits.frac1 = X##_f1;				\
-    _flo->bits.exp   = X##_e;				\
-    _flo->bits.sign  = X##_s;				\
-  } while (0)
-
-#define __FP_PACK_RAW_4(fs, val, X)			\
-  do {							\
-    union _FP_UNION_##fs *_flo =			\
-    	(union _FP_UNION_##fs *)val;			\
-							\
-    _flo->bits.frac0 = X##_f[0];			\
-    _flo->bits.frac1 = X##_f[1];			\
-    _flo->bits.frac2 = X##_f[2];			\
-    _flo->bits.frac3 = X##_f[3];			\
-    _flo->bits.exp   = X##_e;				\
-    _flo->bits.sign  = X##_s;				\
-  } while (0)
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-
-/* We only actually write to the destination register
- * if exceptions signalled (if any) will not trap.
- */
-#ifdef __SMP__
-#define __FPU_TEM \
-	(((current->tss.fsr)>>23)&0x1f)
-#else
+#ifndef __SMP__
 extern struct task_struct *last_task_used_math;
-#define __FPU_TEM \
-	(((last_task_used_math->tss.fsr)>>23)&0x1f)
 #endif
-#define __FPU_TRAP_P(bits) \
-	((__FPU_TEM & (bits)) != 0)
-
-#define __FP_PACK_S(val,X)			\
-({  int __exc = _FP_PACK_CANONICAL(S,1,X);	\
-    if(!__exc || !__FPU_TRAP_P(__exc))		\
-        __FP_PACK_RAW_1(S,val,X);		\
-    __exc;					\
-})
-
-#define __FP_PACK_D(val,X)			\
-({  int __exc = _FP_PACK_CANONICAL(D,2,X);	\
-    if(!__exc || !__FPU_TRAP_P(__exc))		\
-        __FP_PACK_RAW_2(D,val,X);		\
-    __exc;					\
-})
-
-#define __FP_PACK_Q(val,X)			\
-({  int __exc = _FP_PACK_CANONICAL(Q,4,X);	\
-    if(!__exc || !__FPU_TRAP_P(__exc))		\
-        __FP_PACK_RAW_4(Q,val,X);		\
-    __exc;					\
-})
 
 /* Obtain the current rounding mode. */
+#ifndef FP_ROUNDMODE
 #ifdef __SMP__
 #define FP_ROUNDMODE	((current->tss.fsr >> 30) & 0x3)
 #else
 #define FP_ROUNDMODE	((last_task_used_math->tss.fsr >> 30) & 0x3)
 #endif
+#endif
 
-/* the asm fragments go here: all these are taken from glibc-2.0.5's stdlib/longlong.h */
-
-#include <linux/types.h>
-#include <asm/byteorder.h>
-
-/* add_ssaaaa is used in op-2.h and should be equivalent to
- * #define add_ssaaaa(sh,sl,ah,al,bh,bl) (sh = ah+bh+ (( sl = al+bl) < al))
- * add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1,
- * high_addend_2, low_addend_2) adds two UWtype integers, composed by
- * HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2
- * respectively.  The result is placed in HIGH_SUM and LOW_SUM.  Overflow
- * (i.e. carry out) is not stored anywhere, and is lost.
- */
-#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
-  __asm__ ("addcc %r4,%5,%1
-        addx %r2,%3,%0"                                                 \
-           : "=r" ((USItype)(sh)),                                      \
-             "=&r" ((USItype)(sl))                                      \
-           : "%rJ" ((USItype)(ah)),                                     \
-             "rI" ((USItype)(bh)),                                      \
-             "%rJ" ((USItype)(al)),                                     \
-             "rI" ((USItype)(bl))                                       \
-           : "cc")
-
-
-/* sub_ddmmss is used in op-2.h and udivmodti4.c and should be equivalent to
- * #define sub_ddmmss(sh, sl, ah, al, bh, bl) (sh = ah-bh - ((sl = al-bl) > al))
- * sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend,
- * high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers,
- * composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and
- * LOW_SUBTRAHEND_2 respectively.  The result is placed in HIGH_DIFFERENCE
- * and LOW_DIFFERENCE.  Overflow (i.e. carry out) is not stored anywhere,
- * and is lost.
- */
-
-#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
-  __asm__ ("subcc %r4,%5,%1
-        subx %r2,%3,%0"                                                 \
-           : "=r" ((USItype)(sh)),                                      \
-             "=&r" ((USItype)(sl))                                      \
-           : "rJ" ((USItype)(ah)),                                      \
-             "rI" ((USItype)(bh)),                                      \
-             "rJ" ((USItype)(al)),                                      \
-             "rI" ((USItype)(bl))                                       \
-           : "cc")
-
-
-/* asm fragments for mul and div */	 
-/* umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two
- * UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype
- * word product in HIGH_PROD and LOW_PROD.
- * These look ugly because the sun4/4c don't have umul/udiv/smul/sdiv in
- * hardware. 
- */
-#define umul_ppmm(w1, w0, u, v) \
-  __asm__ ("! Inlined umul_ppmm
-        wr      %%g0,%2,%%y     ! SPARC has 0-3 delay insn after a wr
-        sra     %3,31,%%g2      ! Don't move this insn
-        and     %2,%%g2,%%g2    ! Don't move this insn
-        andcc   %%g0,0,%%g1     ! Don't move this insn
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,0,%%g1
-        add     %%g1,%%g2,%0
-        rd      %%y,%1"                                                 \
-           : "=r" ((USItype)(w1)),                                      \
-             "=r" ((USItype)(w0))                                       \
-           : "%rI" ((USItype)(u)),                                      \
-             "r" ((USItype)(v))                                         \
-           : "%g1", "%g2", "cc")
-
-/* udiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
- * denominator) divides a UDWtype, composed by the UWtype integers
- * HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient
- * in QUOTIENT and the remainder in REMAINDER.  HIGH_NUMERATOR must be less
- * than DENOMINATOR for correct operation.  If, in addition, the most
- * significant bit of DENOMINATOR must be 1, then the pre-processor symbol
- * UDIV_NEEDS_NORMALIZATION is defined to 1.
- */
-
-#define udiv_qrnnd(q, r, n1, n0, d) \
-  __asm__ ("! Inlined udiv_qrnnd
-        mov     32,%%g1
-        subcc   %1,%2,%%g0
-1:      bcs     5f
-         addxcc %0,%0,%0        ! shift n1n0 and a q-bit in lsb
-        sub     %1,%2,%1        ! this kills msb of n
-        addx    %1,%1,%1        ! so this can't give carry
-        subcc   %%g1,1,%%g1
-2:      bne     1b
-         subcc  %1,%2,%%g0
-        bcs     3f
-         addxcc %0,%0,%0        ! shift n1n0 and a q-bit in lsb
-        b       3f
-         sub    %1,%2,%1        ! this kills msb of n
-4:      sub     %1,%2,%1
-5:      addxcc  %1,%1,%1
-        bcc     2b
-         subcc  %%g1,1,%%g1
-! Got carry from n.  Subtract next step to cancel this carry.
-        bne     4b
-         addcc  %0,%0,%0        ! shift n1n0 and a 0-bit in lsb
-        sub     %1,%2,%1
-3:      xnor    %0,0,%0
-        ! End of inline udiv_qrnnd"                                     \
-           : "=&r" ((USItype) (q)),                                     \
-             "=&r" ((USItype) (r))                                      \
-           : "r" ((USItype) (d)),                                       \
-             "1" ((USItype) (n1)),                                      \
-             "0" ((USItype) (n0)) : "%g1", "cc")
-
-#define UDIV_NEEDS_NORMALIZATION 0
+/* Exception flags. */
+#define FP_EX_INVALID		(1 << 4)
+#define FP_EX_OVERFLOW		(1 << 3)
+#define FP_EX_UNDERFLOW		(1 << 2)
+#define FP_EX_DIVZERO		(1 << 1)
+#define FP_EX_INEXACT		(1 << 0)
 
-#define abort()								\
-	return 0
+#define FP_HANDLE_EXCEPTIONS return _fex
 
-#ifdef __BIG_ENDIAN
-#define __BYTE_ORDER __BIG_ENDIAN
+#ifdef __SMP__
+#define FP_INHIBIT_RESULTS ((current->tss.fsr >> 23) & _fex)
 #else
-#define __BYTE_ORDER __LITTLE_ENDIAN
+#define FP_INHIBIT_RESULTS ((last_task_used_math->tss.fsr >> 23) & _fex)
 #endif
 
-/* Exception flags. */
-#define EFLAG_INVALID		(1 << 4)
-#define EFLAG_OVERFLOW		(1 << 3)
-#define EFLAG_UNDERFLOW		(1 << 2)
-#define EFLAG_DIVZERO		(1 << 1)
-#define EFLAG_INEXACT		(1 << 0)
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/math-emu/sfp-util.h linux.14p16/arch/sparc/math-emu/sfp-util.h
--- linux.vanilla/arch/sparc/math-emu/sfp-util.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/sparc/math-emu/sfp-util.h	Thu Dec  9 15:34:22 1999
@@ -0,0 +1,115 @@
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) 				\
+  __asm__ ("addcc %r4,%5,%1
+	addx %r2,%3,%0"							\
+	   : "=r" ((USItype)(sh)),					\
+	     "=&r" ((USItype)(sl))					\
+	   : "%rJ" ((USItype)(ah)),					\
+	     "rI" ((USItype)(bh)),					\
+	     "%rJ" ((USItype)(al)),					\
+	     "rI" ((USItype)(bl))					\
+	   : "cc")
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) 				\
+  __asm__ ("subcc %r4,%5,%1
+	subx %r2,%3,%0"							\
+	   : "=r" ((USItype)(sh)),					\
+	     "=&r" ((USItype)(sl))					\
+	   : "rJ" ((USItype)(ah)),					\
+	     "rI" ((USItype)(bh)),					\
+	     "rJ" ((USItype)(al)),					\
+	     "rI" ((USItype)(bl))					\
+	   : "cc")
+
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("! Inlined umul_ppmm
+	wr	%%g0,%2,%%y	! SPARC has 0-3 delay insn after a wr
+	sra	%3,31,%%g2	! Don't move this insn
+	and	%2,%%g2,%%g2	! Don't move this insn
+	andcc	%%g0,0,%%g1	! Don't move this insn
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,%3,%%g1
+	mulscc	%%g1,0,%%g1
+	add	%%g1,%%g2,%0
+	rd	%%y,%1"							\
+	   : "=r" ((USItype)(w1)),					\
+	     "=r" ((USItype)(w0))					\
+	   : "%rI" ((USItype)(u)),					\
+	     "r" ((USItype)(v))						\
+	   : "%g1", "%g2", "cc")
+
+/* It's quite necessary to add this much assembler for the sparc.
+   The default udiv_qrnnd (in C) is more than 10 times slower!  */
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  __asm__ ("! Inlined udiv_qrnnd
+	mov	32,%%g1
+	subcc	%1,%2,%%g0
+1:	bcs	5f
+	 addxcc %0,%0,%0	! shift n1n0 and a q-bit in lsb
+	sub	%1,%2,%1	! this kills msb of n
+	addx	%1,%1,%1	! so this can't give carry
+	subcc	%%g1,1,%%g1
+2:	bne	1b
+	 subcc	%1,%2,%%g0
+	bcs	3f
+	 addxcc %0,%0,%0	! shift n1n0 and a q-bit in lsb
+	b	3f
+	 sub	%1,%2,%1	! this kills msb of n
+4:	sub	%1,%2,%1
+5:	addxcc	%1,%1,%1
+	bcc	2b
+	 subcc	%%g1,1,%%g1
+! Got carry from n.  Subtract next step to cancel this carry.
+	bne	4b
+	 addcc	%0,%0,%0	! shift n1n0 and a 0-bit in lsb
+	sub	%1,%2,%1
+3:	xnor	%0,0,%0
+	! End of inline udiv_qrnnd"					\
+	   : "=&r" ((USItype)(q)),					\
+	     "=&r" ((USItype)(r))					\
+	   : "r" ((USItype)(d)),					\
+	     "1" ((USItype)(n1)),					\
+	     "0" ((USItype)(n0)) : "%g1", "cc")
+#define UDIV_NEEDS_NORMALIZATION 0
+
+#define abort()								\
+	return 0
+
+#ifdef __BIG_ENDIAN
+#define __BYTE_ORDER __BIG_ENDIAN
+#else
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/mm/Makefile linux.14p16/arch/sparc/mm/Makefile
--- linux.vanilla/arch/sparc/mm/Makefile	Thu Mar 11 00:53:36 1999
+++ linux.14p16/arch/sparc/mm/Makefile	Thu Dec  9 15:34:21 1999
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.33 1999/01/02 16:45:47 davem Exp $
+# $Id: Makefile,v 1.33.2.1 1999/10/06 15:36:20 davem Exp $
 # Makefile for the linux Sparc-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -12,7 +12,7 @@
 ifeq ($(CONFIG_SUN4),y)
 O_OBJS	 += nosrmmu.o
 else
-O_OBJS	 += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o
+O_OBJS	 += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
 endif
 ifdef CONFIG_SMP
 O_OBJS   += nosun4c.o
@@ -30,3 +30,6 @@
 
 tsunami.o: tsunami.S
 	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o tsunami.o tsunami.S
+
+swift.o: swift.S
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o swift.o swift.S
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/mm/asyncd.c linux.14p16/arch/sparc/mm/asyncd.c
--- linux.vanilla/arch/sparc/mm/asyncd.c	Sun Oct  4 18:22:42 1998
+++ linux.14p16/arch/sparc/mm/asyncd.c	Thu Dec  9 15:34:21 1999
@@ -1,4 +1,4 @@
-/*  $Id: asyncd.c,v 1.12 1998/09/13 04:30:30 davem Exp $
+/*  $Id: asyncd.c,v 1.12.2.1 1999/11/16 06:29:36 davem Exp $
  *  The asyncd kernel daemon. This handles paging on behalf of 
  *  processes that receive page faults due to remote (async) memory
  *  accesses. 
@@ -152,7 +152,9 @@
 	if(!pte)
 		goto no_memory;
 	if(!pte_present(*pte)) {
-		handle_mm_fault(tsk, vma, address, write);
+		int fault = handle_mm_fault(tsk, vma, address, write);
+		if (fault < 0)
+			goto no_memory;
 		goto finish_up;
 	}
 	set_pte(pte, pte_mkyoung(*pte));
@@ -164,7 +166,11 @@
 		flush_tlb_page(vma, address);
 		goto finish_up;
 	}
-	handle_mm_fault(tsk, vma, address, write);
+	{
+		int fault = handle_mm_fault(tsk, vma, address, write);
+		if (fault < 0)
+			goto no_memory;
+	}
 
 	/* Fall through for do_wp_page */
 finish_up:
@@ -173,7 +179,7 @@
 
 no_memory:
 	stats.failure++;
-	oom(tsk);
+	force_sig(SIGKILL, tsk);
 	return 1;
 	
 bad_area:	  
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/mm/fault.c linux.14p16/arch/sparc/mm/fault.c
--- linux.vanilla/arch/sparc/mm/fault.c	Sat Aug 14 02:27:15 1999
+++ linux.14p16/arch/sparc/mm/fault.c	Thu Dec  9 15:34:21 1999
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.101.2.2 1999/08/07 10:42:53 davem Exp $
+/* $Id: fault.c,v 1.101.2.5 1999/11/16 06:29:39 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -237,8 +237,14 @@
 		if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
 	}
-	if (!handle_mm_fault(current, vma, address, write))
-		goto do_sigbus;
+survive:
+	{
+		int fault = handle_mm_fault(current, vma, address, write);
+		if (!fault)
+			goto do_sigbus;
+		if (fault < 0)
+			goto out_of_memory;
+	}
 	up(&mm->mmap_sem);
 	return;
 	/*
@@ -288,6 +294,17 @@
 	unhandled_fault (address, tsk, regs);
 	return;
 
+out_of_memory:
+	if (tsk->pid == 1) {
+		tsk->policy |= SCHED_YIELD;
+		schedule();
+		goto survive;
+	}
+	up(&mm->mmap_sem);
+	printk("VM: killing process %s\n", tsk->comm);
+	do_exit(SIGKILL);
+	return;
+
 do_sigbus:
 	up(&mm->mmap_sem);
 	tsk->tss.sig_address = address;
@@ -309,8 +326,18 @@
 	pgd_t *pgdp;
 	pte_t *ptep;
 
-	if (text_fault)
+	if (text_fault) {
 		address = regs->pc;
+	} else if (!write &&
+		   !(regs->psr & PSR_PS)) {
+		unsigned int insn, *ip;
+
+		ip = (unsigned int *)regs->pc;
+		if (! get_user(insn, ip)) {
+			if ((insn & 0xc1680000) == 0xc0680000)
+				write = 1;
+		}
+	}
 
 	pgdp = sun4c_pgd_offset(mm, address);
 	ptep = sun4c_pte_offset((pmd_t *) pgdp, address);
@@ -319,28 +346,36 @@
 	    if (write) {
 		if ((pte_val(*ptep) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT))
 				   == (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT)) {
+			unsigned long flags;
 
 			*ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
 				      _SUN4C_PAGE_MODIFIED |
 				      _SUN4C_PAGE_VALID |
 				      _SUN4C_PAGE_DIRTY);
 
+			save_and_cli(flags);
 			if (sun4c_get_segmap(address) != invalid_segment) {
 				sun4c_put_pte(address, pte_val(*ptep));
+				restore_flags(flags);
 				return;
 			}
+			restore_flags(flags);
 		}
 	    } else {
 		if ((pte_val(*ptep) & (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT))
 				   == (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT)) {
+			unsigned long flags;
 
 			*ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
 				      _SUN4C_PAGE_VALID);
 
+			save_and_cli(flags);
 			if (sun4c_get_segmap(address) != invalid_segment) {
 				sun4c_put_pte(address, pte_val(*ptep));
+				restore_flags(flags);
 				return;
 			}
+			restore_flags(flags);
 		}
 	    }
 	}
@@ -389,8 +424,14 @@
 		if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
 	}
-	if (!handle_mm_fault(current, vma, address, write))
-		goto do_sigbus;
+survive:
+	{
+		int fault = handle_mm_fault(current, vma, address, write);
+		if (!fault)
+			goto do_sigbus;
+		if (fault < 0)
+			goto out_of_memory;
+	}
 	up(&mm->mmap_sem);
 	return;
 bad_area:
@@ -404,6 +445,17 @@
 	send_sig(SIGSEGV, tsk, 1);
 	return;
 
+out_of_memory:
+	if (tsk->pid == 1) {
+		tsk->policy |= SCHED_YIELD;
+		schedule();
+		goto survive;
+	}
+	up(&mm->mmap_sem);
+	printk("VM: killing process %s\n", tsk->comm);
+	do_exit(SIGKILL);
+	return;
+
 do_sigbus:
 	up(&mm->mmap_sem);
 	tsk->tss.sig_address = address;
@@ -415,31 +467,25 @@
 {
 	unsigned long sp;
 
-	lock_kernel();
 	sp = current->tss.rwbuf_stkptrs[0];
 	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
 		force_user_fault(sp + 0x38, 1);
 	force_user_fault(sp, 1);
-	unlock_kernel();
 }
 
 void window_underflow_fault(unsigned long sp)
 {
-	lock_kernel();
 	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
 		force_user_fault(sp + 0x38, 0);
 	force_user_fault(sp, 0);
-	unlock_kernel();
 }
 
 void window_ret_fault(struct pt_regs *regs)
 {
 	unsigned long sp;
 
-	lock_kernel();
 	sp = regs->u_regs[UREG_FP];
 	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
 		force_user_fault(sp + 0x38, 0);
 	force_user_fault(sp, 0);
-	unlock_kernel();
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/mm/iommu.c linux.14p16/arch/sparc/mm/iommu.c
--- linux.vanilla/arch/sparc/mm/iommu.c	Sat Aug 28 20:00:54 1999
+++ linux.14p16/arch/sparc/mm/iommu.c	Thu Dec  9 15:34:22 1999
@@ -1,4 +1,4 @@
-/* $Id: iommu.c,v 1.10.2.1 1999/08/13 12:35:35 davem Exp $
+/* $Id: iommu.c,v 1.10.2.2 1999/11/03 03:05:55 davem Exp $
  * iommu.c:  IOMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -16,6 +16,7 @@
 #include <asm/sbus.h>
 #include <asm/io.h>
 #include <asm/mxcc.h>
+#include <asm/mbus.h>
 
 /* srmmu.c */
 extern int viking_mxcc_present;
@@ -201,16 +202,19 @@
 #ifdef CONFIG_SBUS
 static void iommu_map_dma_area(unsigned long addr, int len)
 {
-	unsigned long page, end;
+	unsigned long page, end, ipte_cache;
 	pgprot_t dvma_prot;
 	struct iommu_struct *iommu = SBus_chain->iommu;
 	iopte_t *iopte = iommu->page_table;
 	iopte_t *first;
 
-	if(viking_mxcc_present)
+	if(viking_mxcc_present || srmmu_modtype == HyperSparc) {
 		dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV);
-	else
+		ipte_cache = 1;
+	} else {
 		dvma_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV);
+		ipte_cache = 0;
+	}
 
 	iopte += ((addr - iommu->start) >> PAGE_SHIFT);
 	first = iopte;
@@ -229,13 +233,20 @@
 				viking_mxcc_flush_page(page);
 			else if (viking_flush)
 				viking_flush_page(page);
+			else
+				flush_page_to_ram(page);
 
 			pgdp = pgd_offset(init_task.mm, addr);
 			pmdp = pmd_offset(pgdp, addr);
 			ptep = pte_offset(pmdp, addr);
 
 			set_pte(ptep, pte_val(mk_pte(page, dvma_prot)));
-			iopte_val(*iopte++) = MKIOPTE(mmu_v2p(page));
+			if (ipte_cache != 0) {
+				iopte_val(*iopte++) = MKIOPTE(mmu_v2p(page));
+			} else {
+				iopte_val(*iopte++) =
+					MKIOPTE(mmu_v2p(page)) & ~IOPTE_CACHE;
+			}
 		}
 		addr += PAGE_SIZE;
 	}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/mm/nosrmmu.c linux.14p16/arch/sparc/mm/nosrmmu.c
--- linux.vanilla/arch/sparc/mm/nosrmmu.c	Sat Aug 14 02:25:55 1999
+++ linux.14p16/arch/sparc/mm/nosrmmu.c	Thu Dec  9 15:34:22 1999
@@ -1,4 +1,4 @@
-/* $Id: nosrmmu.c,v 1.2 1999/03/30 10:17:39 jj Exp $
+/* $Id: nosrmmu.c,v 1.2.2.1 1999/10/06 10:52:37 anton Exp $
  * nosrmmu.c: This file is a bunch of dummies for sun4 compiles, 
  *         so that it does not need srmmu and avoid ifdefs.
  *
@@ -13,6 +13,8 @@
 static char shouldnothappen[] __initdata = "SUN4 kernel can only run on SUN4\n";
 
 enum mbus_module srmmu_modtype;
+
+int vac_cache_size = 0;
 
 __initfunc(static void should_not_happen(void))
 {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/mm/srmmu.c linux.14p16/arch/sparc/mm/srmmu.c
--- linux.vanilla/arch/sparc/mm/srmmu.c	Wed Oct 20 01:12:34 1999
+++ linux.14p16/arch/sparc/mm/srmmu.c	Thu Dec  9 15:34:21 1999
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.187.2.2 1999/09/21 11:24:15 anton Exp $
+/* $Id: srmmu.c,v 1.187.2.7 1999/11/16 06:29:44 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -114,7 +114,9 @@
 #define srmmu_ahashfn(addr)	((addr) >> 24)
 
 int viking_mxcc_present = 0;
+#ifdef __SMP__
 static spinlock_t srmmu_context_spinlock = SPIN_LOCK_UNLOCKED;
+#endif
 
 /* Physical memory can be _very_ non-contiguous on the sun4m, especially
  * the SS10/20 class machines and with the latest openprom revisions.
@@ -725,6 +727,17 @@
 	srmmu_set_entry(ptep, pte_val(pteval));
 }
 
+extern void swift_flush_chunk(unsigned long chunk);
+
+static void srmmu_set_pte_nocache_swift(pte_t *ptep, pte_t pteval)
+{
+	unsigned long page;
+
+	srmmu_set_entry(ptep, pte_val(pteval));
+	page = ((unsigned long)ptep) & PAGE_MASK;
+	swift_flush_chunk(page);
+}
+
 static void srmmu_set_pte_nocache_cypress(pte_t *ptep, pte_t pteval)
 {
 	register unsigned long a, b, c, d, e, f, g;
@@ -909,7 +922,8 @@
 /* tsunami.S */
 extern void tsunami_flush_cache_all(void);
 extern void tsunami_flush_cache_mm(struct mm_struct *mm);
-extern void tsunami_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void tsunami_flush_cache_range(struct mm_struct *mm,
+				      unsigned long start, unsigned long end);
 extern void tsunami_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
 extern void tsunami_flush_page_to_ram(unsigned long page);
 extern void tsunami_flush_page_for_dma(unsigned long page);
@@ -917,111 +931,54 @@
 extern void tsunami_flush_chunk(unsigned long chunk);
 extern void tsunami_flush_tlb_all(void);
 extern void tsunami_flush_tlb_mm(struct mm_struct *mm);
-extern void tsunami_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void tsunami_flush_tlb_range(struct mm_struct *mm,
+				    unsigned long start, unsigned long end);
 extern void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
+extern void tsunami_setup_blockops(void);
 
-/* Workaround, until we find what's going on with Swift. When low on memory, it sometimes
- * loops in fault/handle_mm_fault incl. flush_tlb_page to find out it is already in page tables/
- * fault again on the same instruction. I really don't understand it, have checked it and contexts
- * are right, flush_tlb_all is done as well, and it faults again... Strange. -jj
- */
-static void swift_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte)
-{
-	static unsigned long last;
-
-	if (last == address) viking_hwprobe(address);
-	last = address;
-}
-
-/* Swift flushes.  It has the recommended SRMMU specification flushing
- * facilities, so we can do things in a more fine grained fashion than we
- * could on the tsunami.  Let's watch out for HARDWARE BUGS...
- */
+/* swift.S */
+extern void swift_flush_cache_all(void);
+extern void swift_flush_cache_mm(struct mm_struct *mm);
+extern void swift_flush_cache_range(struct mm_struct *mm,
+				    unsigned long start, unsigned long end);
+extern void swift_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
+extern void swift_flush_page_to_ram(unsigned long page);
+extern void swift_flush_page_for_dma(unsigned long page);
+extern void swift_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
+extern void swift_flush_tlb_all(void);
+extern void swift_flush_tlb_mm(struct mm_struct *mm);
+extern void swift_flush_tlb_range(struct mm_struct *mm,
+				  unsigned long start, unsigned long end);
+extern void swift_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 
-static void swift_flush_cache_all(void)
-{
-	flush_user_windows();
-	swift_idflash_clear();
-}
-
-static void swift_flush_cache_mm(struct mm_struct *mm)
-{
-	FLUSH_BEGIN(mm)
-	flush_user_windows();
-	swift_idflash_clear();
-	FLUSH_END
-}
-
-static void swift_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
-	FLUSH_BEGIN(mm)
-	flush_user_windows();
-	swift_idflash_clear();
-	FLUSH_END
-}
-
-static void swift_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
-{
-	FLUSH_BEGIN(vma->vm_mm)
-	flush_user_windows();
-	if(vma->vm_flags & VM_EXEC)
-		swift_flush_icache();
-	swift_flush_dcache();
-	FLUSH_END
-}
-
-/* Not copy-back on swift. */
-static void swift_flush_page_to_ram(unsigned long page)
-{
-}
-
-/* But not IO coherent either. */
-static void swift_flush_page_for_dma(unsigned long page)
-{
-	swift_flush_dcache();
-}
-
-/* Again, Swift is non-snooping split I/D cache'd just like tsunami,
- * so have to punt the icache for on-stack signal insns.  Only the
- * icache need be flushed since the dcache is write-through.
- */
-static void swift_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
-{
-	swift_flush_icache();
-}
-
-static void swift_flush_chunk(unsigned long chunk)
+static void swift_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) 
 {
+	if(pgdp != swapper_pg_dir)
+		swift_flush_chunk((unsigned long)pgdp);
+	if(tsk->mm->context != NO_CONTEXT &&
+	   tsk->mm->pgd != pgdp) {
+		swift_flush_cache_mm(tsk->mm);
+		ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
+		swift_flush_tlb_mm(tsk->mm);
+	}
 }
 
-static void swift_flush_tlb_all(void)
+static void swift_init_new_context(struct mm_struct *mm)
 {
-	srmmu_flush_whole_tlb();
-	module_stats.invall++;
-}
+	ctxd_t *ctxp;
 
-static void swift_flush_tlb_mm(struct mm_struct *mm)
-{
-	FLUSH_BEGIN(mm)
-	srmmu_flush_whole_tlb();
-	module_stats.invmm++;
-	FLUSH_END
-}
+	spin_lock(&srmmu_context_spinlock);
+	alloc_context(mm);
+	spin_unlock(&srmmu_context_spinlock);
 
-static void swift_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
-	FLUSH_BEGIN(mm)
-	srmmu_flush_whole_tlb();
-	module_stats.invrnge++;
-	FLUSH_END
-}
+	ctxp = &srmmu_context_table[mm->context];
+	srmmu_set_entry((pte_t *)ctxp,
+			__pte((SRMMU_ET_PTD |
+			       (srmmu_v2p((unsigned long) mm->pgd) >> 4))));
+	swift_flush_chunk(((unsigned long)ctxp) & PAGE_MASK);
 
-static void swift_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
-	FLUSH_BEGIN(vma->vm_mm)
-	srmmu_flush_whole_tlb();
-	module_stats.invpg++;
-	FLUSH_END
+	if(mm == current->mm)
+		srmmu_set_context(mm->context);
 }
 
 /* The following are all MBUS based SRMMU modules, and therefore could
@@ -1306,7 +1263,8 @@
 /* hypersparc.S */
 extern void hypersparc_flush_cache_all(void);
 extern void hypersparc_flush_cache_mm(struct mm_struct *mm);
-extern void hypersparc_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void hypersparc_flush_cache_range(struct mm_struct *mm,
+					 unsigned long start, unsigned long end);
 extern void hypersparc_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
 extern void hypersparc_flush_page_to_ram(unsigned long page);
 extern void hypersparc_flush_chunk(unsigned long chunk);
@@ -1314,7 +1272,8 @@
 extern void hypersparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
 extern void hypersparc_flush_tlb_all(void);
 extern void hypersparc_flush_tlb_mm(struct mm_struct *mm);
-extern void hypersparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void hypersparc_flush_tlb_range(struct mm_struct *mm,
+				       unsigned long start, unsigned long end);
 extern void hypersparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 extern void hypersparc_setup_blockops(void);
 
@@ -1328,7 +1287,8 @@
 
 static void hypersparc_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp)
 {
-	srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4))));
+	srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD |
+					      (srmmu_v2p((unsigned long) pgdp) >> 4))));
 	hypersparc_flush_page_to_ram((unsigned long)ctxp);
 	hyper_flush_whole_icache();
 }
@@ -1407,7 +1367,9 @@
 		alloc_context(tsk->mm);
 		spin_unlock(&srmmu_context_spinlock);
 		ctxp = &srmmu_context_table[tsk->mm->context];
-		srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) tsk->mm->pgd) >> 4))));
+		srmmu_set_entry((pte_t *)ctxp,
+				__pte((SRMMU_ET_PTD |
+				       (srmmu_v2p((unsigned long) tsk->mm->pgd) >> 4))));
 		hypersparc_flush_page_to_ram((unsigned long)ctxp);
 	}
 	hyper_flush_whole_icache();
@@ -1423,7 +1385,9 @@
 	spin_unlock(&srmmu_context_spinlock);
 
 	ctxp = &srmmu_context_table[mm->context];
-	srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) mm->pgd) >> 4))));
+	srmmu_set_entry((pte_t *)ctxp,
+			__pte((SRMMU_ET_PTD |
+			       (srmmu_v2p((unsigned long) mm->pgd) >> 4))));
 	hypersparc_flush_page_to_ram((unsigned long)ctxp);
 
 	if(mm == current->mm) {
@@ -1450,12 +1414,14 @@
 
 static inline void srmmu_early_pgd_set(pgd_t *pgdp, pmd_t *pmdp)
 {
-	set_pte((pte_t *)pgdp, __pte((SRMMU_ET_PTD | (srmmu_early_paddr((unsigned long) pmdp) >> 4))));
+	set_pte((pte_t *)pgdp, __pte((SRMMU_ET_PTD |
+				      (srmmu_early_paddr((unsigned long) pmdp) >> 4))));
 }
 
 static inline void srmmu_early_pmd_set(pmd_t *pmdp, pte_t *ptep)
 {
-	set_pte((pte_t *)pmdp, __pte((SRMMU_ET_PTD | (srmmu_early_paddr((unsigned long) ptep) >> 4))));
+	set_pte((pte_t *)pmdp, __pte((SRMMU_ET_PTD |
+				      (srmmu_early_paddr((unsigned long) ptep) >> 4))));
 }
 
 static inline unsigned long srmmu_early_pgd_page(pgd_t pgd)
@@ -1470,12 +1436,14 @@
 
 static inline pmd_t *srmmu_early_pmd_offset(pgd_t *dir, unsigned long address)
 {
-	return (pmd_t *) srmmu_early_pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1));
+	return (pmd_t *) srmmu_early_pgd_page(*dir) +
+		((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1));
 }
 
 static inline pte_t *srmmu_early_pte_offset(pmd_t *dir, unsigned long address)
 {
-	return (pte_t *) srmmu_early_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
+	return (pte_t *) srmmu_early_pmd_page(*dir) +
+		((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
 }
 
 static inline void srmmu_allocate_ptable_skeleton(unsigned long start, unsigned long end)
@@ -2245,6 +2213,7 @@
 __initfunc(static void init_hypersparc(void))
 {
 	srmmu_name = "ROSS HyperSparc";
+	srmmu_modtype = HyperSparc;
 
 	init_vac_layout();
 
@@ -2373,21 +2342,14 @@
 
 __initfunc(static void poke_swift(void))
 {
-	unsigned long mreg = srmmu_get_mmureg();
+	unsigned long mreg;
 
 	/* Clear any crap from the cache or else... */
-	swift_idflash_clear();
-	mreg |= (SWIFT_IE | SWIFT_DE); /* I & D caches on */
+	swift_flush_cache_all();
 
-	/* The Swift branch folding logic is completely broken.  At
-	 * trap time, if things are just right, if can mistakenly
-	 * think that a trap is coming from kernel mode when in fact
-	 * it is coming from user mode (it mis-executes the branch in
-	 * the trap code).  So you see things like crashme completely
-	 * hosing your machine which is completely unacceptable.  Turn
-	 * this shit off... nice job Fujitsu.
-	 */
-	mreg &= ~(SWIFT_BF);
+	/* Enable I & D caches */
+	mreg = srmmu_get_mmureg();
+	mreg |= (SWIFT_IE | SWIFT_DE);
 	srmmu_set_mmureg(mreg);
 }
 
@@ -2444,18 +2406,24 @@
 	BTFIXUPSET_CALL(flush_cache_page, swift_flush_cache_page, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(flush_cache_range, swift_flush_cache_range, BTFIXUPCALL_NORM);
 
-	BTFIXUPSET_CALL(flush_chunk, swift_flush_chunk, BTFIXUPCALL_NOP); /* local flush _only_ */
+	BTFIXUPSET_CALL(flush_chunk, swift_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */
 
 	BTFIXUPSET_CALL(flush_tlb_all, swift_flush_tlb_all, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(flush_tlb_mm, swift_flush_tlb_mm, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(flush_tlb_page, swift_flush_tlb_page, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(flush_tlb_range, swift_flush_tlb_range, BTFIXUPCALL_NORM);
 
-	BTFIXUPSET_CALL(flush_page_to_ram, swift_flush_page_to_ram, BTFIXUPCALL_NOP);
+	BTFIXUPSET_CALL(flush_page_to_ram, swift_flush_page_to_ram, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(flush_sig_insns, swift_flush_sig_insns, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(flush_page_for_dma, swift_flush_page_for_dma, BTFIXUPCALL_NORM);
 
-	BTFIXUPSET_CALL(update_mmu_cache, swift_update_mmu_cache, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(update_mmu_cache, srmmu_update_mmu_cache, BTFIXUPCALL_NOP);
+
+	BTFIXUPSET_CALL(sparc_update_rootmmu_dir, swift_update_rootmmu_dir, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(set_pte, srmmu_set_pte_nocache_swift, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(init_new_context, swift_init_new_context, BTFIXUPCALL_NORM);
+
+	flush_page_for_dma_global = 0;
 
 	/* Are you now convinced that the Swift is one of the
 	 * biggest VLSI abortions of all time?  Bravo Fujitsu!
@@ -2613,7 +2581,7 @@
 	BTFIXUPSET_CALL(flush_chunk, turbosparc_flush_chunk, BTFIXUPCALL_NORM);
 
 	BTFIXUPSET_CALL(flush_sig_insns, turbosparc_flush_sig_insns, BTFIXUPCALL_NOP);
-	BTFIXUPSET_CALL(flush_page_for_dma, turbosparc_flush_page_for_dma, BTFIXUPCALL_NOP);
+	BTFIXUPSET_CALL(flush_page_for_dma, turbosparc_flush_page_for_dma, BTFIXUPCALL_NORM);
 
 	poke_srmmu = poke_turbosparc;
 }
@@ -2644,7 +2612,7 @@
 	BTFIXUPSET_CALL(flush_cache_page, tsunami_flush_cache_page, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(flush_cache_range, tsunami_flush_cache_range, BTFIXUPCALL_NORM);
 
-	BTFIXUPSET_CALL(flush_chunk, tsunami_flush_chunk, BTFIXUPCALL_NOP); /* local flush _only_ */
+	BTFIXUPSET_CALL(flush_chunk, tsunami_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */
 
 	BTFIXUPSET_CALL(flush_tlb_all, tsunami_flush_tlb_all, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(flush_tlb_mm, tsunami_flush_tlb_mm, BTFIXUPCALL_NORM);
@@ -2656,6 +2624,8 @@
 	BTFIXUPSET_CALL(flush_page_for_dma, tsunami_flush_page_for_dma, BTFIXUPCALL_NORM);
 
 	poke_srmmu = poke_tsunami;
+
+	tsunami_setup_blockops();
 }
 
 __initfunc(static void poke_viking(void))
@@ -2738,8 +2708,7 @@
 		 * which we use the IOMMU.
 		 */
 		BTFIXUPSET_CALL(flush_page_for_dma, viking_flush_page, BTFIXUPCALL_NORM);
-		/* Also, this is so far the only chip which actually uses
-		   the page argument to flush_page_for_dma */
+
 		flush_page_for_dma_global = 0;
 	} else {
 		srmmu_name = "TI Viking/MXCC";
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/mm/sun4c.c linux.14p16/arch/sparc/mm/sun4c.c
--- linux.vanilla/arch/sparc/mm/sun4c.c	Wed Oct 20 01:12:34 1999
+++ linux.14p16/arch/sparc/mm/sun4c.c	Thu Dec  9 15:34:21 1999
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.173.2.1 1999/09/08 00:32:02 davem Exp $
+/* $Id: sun4c.c,v 1.173.2.5 1999/10/11 08:24:44 davem Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -27,42 +27,19 @@
 #include <asm/mmu_context.h>
 #include <asm/sun4paddr.h>
 
-/* TODO: Make it such that interrupt handlers cannot dick with
- *       the user segment lists, most of the cli/sti pairs can
- *       disappear once that is taken care of.
- */
-
-/* XXX Ok the real performance win, I figure, will be to use a combined hashing
- * XXX and bitmap scheme to keep track of what we have mapped where.  The whole
- * XXX incentive is to make it such that the range flushes can be serviced
- * XXX always in near constant time. --DaveM
+/* Because of our dynamic kernel TLB miss strategy, and how
+ * our DVMA mapping allocation works, you _MUST_:
+ *
+ * 1) Disable interrupts _and_ not touch any dynamic kernel
+ *    memory while messing with kernel MMU state.  By
+ *    dynamic memory I mean any object which is not in
+ *    the kernel image itself or a task_struct (both of
+ *    which are locked into the MMU).
+ * 2) Disable interrupts while messing with user MMU state.
  */
 
 extern int num_segmaps, num_contexts;
 
-/* Define this to get extremely anal debugging, undefine for performance. */
-/* #define DEBUG_SUN4C_MM */
-
-#define UWINMASK_OFFSET (const unsigned long)(&(((struct task_struct *)0)->tss.uwinmask))
-
-/* This is used in many routines below. */
-#define FUW_INLINE do {							\
-	register int ctr asm("g5");					\
-	ctr = 0;							\
-	__asm__ __volatile__("\n"					\
-	"1:	ld	[%%g6 + %2], %%g4	! flush user windows\n"	\
-	"	orcc	%%g0, %%g4, %%g0\n"				\
-	"	add	%0, 1, %0\n"					\
-	"	bne	1b\n"						\
-	"	 save	%%sp, -64, %%sp\n"				\
-	"2:	subcc	%0, 1, %0\n"					\
-	"	bne	2b\n"						\
-	"	 restore %%g0, %%g0, %%g0\n"				\
-	: "=&r" (ctr)							\
-	: "0" (ctr), "i" (UWINMASK_OFFSET)				\
-	: "g4", "cc");							\
-} while(0);
-
 #ifdef CONFIG_SUN4
 #define SUN4C_VAC_SIZE sun4c_vacinfo.num_bytes
 #else
@@ -82,58 +59,21 @@
 #define MIN(a,b) ((a)<(b)?(a):(b))
 #endif
 
-
-#define KGPROF_PROFILING 0
-#if KGPROF_PROFILING
-#define KGPROF_DEPTH 3 /* this needs to match the code below */
-#define KGPROF_SIZE 100
-static struct {
-	unsigned addr[KGPROF_DEPTH];
-	unsigned count;
-} kgprof_counters[KGPROF_SIZE];
-
-/* just call this function from whatever function you think needs it then
-   look at /proc/cpuinfo to see where the function is being called from
-   and how often. This gives a type of "kernel gprof" */
-#define NEXT_PROF(prev,lvl) (prev>PAGE_OFFSET?__builtin_return_address(lvl):0)
-static inline void kgprof_profile(void)
-{
-	unsigned ret[KGPROF_DEPTH];
-	int i,j;
-	/* you can't use a variable argument to __builtin_return_address() */
-	ret[0] = (unsigned)__builtin_return_address(0);
-	ret[1] = (unsigned)NEXT_PROF(ret[0],1);
-	ret[2] = (unsigned)NEXT_PROF(ret[1],2);
-
-	for (i=0;i<KGPROF_SIZE && kgprof_counters[i].addr[0];i++) {
-		for (j=0;j<KGPROF_DEPTH;j++) 
-			if (ret[j] != kgprof_counters[i].addr[j]) break;
-		if (j==KGPROF_DEPTH) break;
-	}
-	if (i<KGPROF_SIZE) {		
-		for (j=0;j<KGPROF_DEPTH;j++)
-			kgprof_counters[i].addr[j] = ret[j];
-		kgprof_counters[i].count++;
-	}
-}
-#endif
-
-
 /* Flushing the cache. */
 struct sun4c_vac_props sun4c_vacinfo;
-static int ctxflushes, segflushes, pageflushes;
 unsigned long sun4c_kernel_faults;
 
 /* convert a virtual address to a physical address and vice
-   versa. Easy on the 4c */
+ * versa. Easy on the 4c
+ */
 static unsigned long sun4c_v2p(unsigned long vaddr)
 {
-  return(vaddr - PAGE_OFFSET);
+	return (vaddr - PAGE_OFFSET);
 }
 
 static unsigned long sun4c_p2v(unsigned long vaddr)
 {
-  return(vaddr + PAGE_OFFSET);
+	return (vaddr + PAGE_OFFSET);
 }
 
 
@@ -142,44 +82,64 @@
 {
 	unsigned long begin, end;
 
-	if(sun4c_vacinfo.on)
+	if (sun4c_vacinfo.on)
 		panic("SUN4C: AIEEE, trying to invalidate vac while"
                       " it is on.");
 
 	/* Clear 'valid' bit in all cache line tags */
 	begin = AC_CACHETAGS;
 	end = (AC_CACHETAGS + SUN4C_VAC_SIZE);
-	while(begin < end) {
+	while (begin < end) {
 		__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
 				     "r" (begin), "i" (ASI_CONTROL));
 		begin += sun4c_vacinfo.linesize;
 	}
 }
 
-/* Context level flush. */
-static inline void sun4c_flush_context_hw(void)
+static __inline__ void sun4c_flush_context_hw(void)
 {
 	unsigned long end = SUN4C_VAC_SIZE;
-	unsigned pgsz = PAGE_SIZE;
 
-	ctxflushes++;
-	__asm__ __volatile__("
-1:	subcc	%0, %2, %0
-	bg	1b
-	 sta	%%g0, [%0] %3
-	nop; nop; nop;		! Weitek hwbug
-"	: "=&r" (end)
-	: "0" (end), "r" (pgsz), "i" (ASI_HWFLUSHCONTEXT)
+	__asm__ __volatile__(
+		"1:	addcc	%0, -4096, %0\n\t"
+		"	bne	1b\n\t"
+		"	 sta	%%g0, [%0] %2"
+	: "=&r" (end)
+	: "0" (end), "i" (ASI_HWFLUSHCONTEXT)
 	: "cc");
 }
 
+/* Must be called minimally with IRQs disabled. */
+static void sun4c_flush_segment_hw(unsigned long addr)
+{
+	if (sun4c_get_segmap(addr) != invalid_segment) {
+		unsigned long vac_size = SUN4C_VAC_SIZE;
+
+		__asm__ __volatile__(
+			"1:	addcc	%0, -4096, %0\n\t"
+			"	bne	1b\n\t"
+			"	 sta	%%g0, [%2 + %0] %3"
+			: "=&r" (vac_size)
+			: "0" (vac_size), "r" (addr), "i" (ASI_HWFLUSHSEG)
+			: "cc");
+	}
+}
+
+/* Must be called minimally with interrupts disabled. */
+static __inline__ void sun4c_flush_page_hw(unsigned long addr)
+{
+	addr &= PAGE_MASK;
+	if ((int)sun4c_get_pte(addr) < 0)
+		__asm__ __volatile__("sta %%g0, [%0] %1"
+				     : : "r" (addr), "i" (ASI_HWFLUSHPAGE));
+}
+
 /* Don't inline the software version as it eats too many cache lines if expanded. */
 static void sun4c_flush_context_sw(void)
 {
 	unsigned long nbytes = SUN4C_VAC_SIZE;
 	unsigned long lsize = sun4c_vacinfo.linesize;
 
-	ctxflushes++;
 	__asm__ __volatile__("
 	add	%2, %2, %%g1
 	add	%2, %%g1, %%g2
@@ -203,72 +163,13 @@
 	: "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
 }
 
-/* Scrape the segment starting at ADDR from the virtual cache. */
-static inline void sun4c_flush_segment(unsigned long addr)
-{
-	if(sun4c_get_segmap(addr) == invalid_segment)
-		return;
-
-	segflushes++;
-	if(sun4c_vacinfo.do_hwflushes) {
-		unsigned long end = (addr + SUN4C_VAC_SIZE);
-
-		for( ; addr < end; addr += PAGE_SIZE)
-			__asm__ __volatile__("sta %%g0, [%0] %1;nop;nop;nop;\n\t" : :
-					     "r" (addr), "i" (ASI_HWFLUSHSEG));
-	} else {
-		unsigned long nbytes = SUN4C_VAC_SIZE;
-		unsigned long lsize = sun4c_vacinfo.linesize;
-
-		__asm__ __volatile__("add	%2, %2, %%g1\n\t"
-				     "add	%2, %%g1, %%g2\n\t"
-				     "add	%2, %%g2, %%g3\n\t"
-				     "add	%2, %%g3, %%g4\n\t"
-				     "add	%2, %%g4, %%g5\n\t"
-				     "add	%2, %%g5, %%o4\n\t"
-				     "add	%2, %%o4, %%o5\n"
-				     "1:\n\t"
-				     "subcc	%1, %%o5, %1\n\t"
-				     "sta	%%g0, [%0] %6\n\t"
-				     "sta	%%g0, [%0 + %2] %6\n\t"
-				     "sta	%%g0, [%0 + %%g1] %6\n\t"
-				     "sta	%%g0, [%0 + %%g2] %6\n\t"
-				     "sta	%%g0, [%0 + %%g3] %6\n\t"
-				     "sta	%%g0, [%0 + %%g4] %6\n\t"
-				     "sta	%%g0, [%0 + %%g5] %6\n\t"
-				     "sta	%%g0, [%0 + %%o4] %6\n\t"
-				     "bg	1b\n\t"
-				     " add	%0, %%o5, %0\n\t"
-				     : "=&r" (addr), "=&r" (nbytes), "=&r" (lsize)
-				     : "0" (addr), "1" (nbytes), "2" (lsize),
-				       "i" (ASI_FLUSHSEG)
-				     : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
-	}
-}
-
-/* Call this version when you know hardware flushes are available. */
-static inline void sun4c_flush_segment_hw(unsigned long addr)
-{
-	if(sun4c_get_segmap(addr) != invalid_segment) {
-		unsigned long end;
-
-		segflushes++;
-		for(end = addr + SUN4C_VAC_SIZE; addr < end; addr += PAGE_SIZE)
-			__asm__ __volatile__("sta %%g0, [%0] %1"
-					     : : "r" (addr), "i" (ASI_HWFLUSHSEG));
-		/* Weitek POWER-UP hwbug workaround. */
-		__asm__ __volatile__("nop;nop;nop;	! Weitek hwbug");
-	}
-}
-
 /* Don't inline the software version as it eats too many cache lines if expanded. */
 static void sun4c_flush_segment_sw(unsigned long addr)
 {
-	if(sun4c_get_segmap(addr) != invalid_segment) {
+	if (sun4c_get_segmap(addr) != invalid_segment) {
 		unsigned long nbytes = SUN4C_VAC_SIZE;
 		unsigned long lsize = sun4c_vacinfo.linesize;
 
-		segflushes++;
 		__asm__ __volatile__("
 		add	%2, %2, %%g1
 		add	%2, %%g1, %%g2
@@ -300,12 +201,11 @@
 {
 	addr &= PAGE_MASK;
 
-	if((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) !=
-	   _SUN4C_PAGE_VALID)
+	if ((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) !=
+	    _SUN4C_PAGE_VALID)
 		return;
 
-	pageflushes++;
-	if(sun4c_vacinfo.do_hwflushes) {
+	if (sun4c_vacinfo.do_hwflushes) {
 		__asm__ __volatile__("sta %%g0, [%0] %1;nop;nop;nop;\n\t" : :
 				     "r" (addr), "i" (ASI_HWFLUSHPAGE));
 	} else {
@@ -338,30 +238,15 @@
 	}
 }
 
-/* Again, hw-only and sw-only cache page-level flush variants. */
-static inline void sun4c_flush_page_hw(unsigned long addr)
-{
-	addr &= PAGE_MASK;
-	if((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) ==
-	   _SUN4C_PAGE_VALID) {
-		pageflushes++;
-		__asm__ __volatile__("sta %%g0, [%0] %1"
-				     : : "r" (addr), "i" (ASI_HWFLUSHPAGE));
-		/* Weitek POWER-UP hwbug workaround. */
-		__asm__ __volatile__("nop;nop;nop;	! Weitek hwbug");
-	}
-}
-
 /* Don't inline the software version as it eats too many cache lines if expanded. */
 static void sun4c_flush_page_sw(unsigned long addr)
 {
 	addr &= PAGE_MASK;
-	if((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) ==
-	   _SUN4C_PAGE_VALID) {
+	if ((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) ==
+	    _SUN4C_PAGE_VALID) {
 		unsigned long left = PAGE_SIZE;
 		unsigned long lsize = sun4c_vacinfo.linesize;
 
-		pageflushes++;
 		__asm__ __volatile__("
 		add	%2, %2, %%g1
 		add	%2, %%g1, %%g2
@@ -411,7 +296,7 @@
 	unsigned long vaddr;
 
 	sun4c_put_segmap(0, pseg);
-	for(vaddr = 0; vaddr < SUN4C_REAL_PGDIR_SIZE; vaddr+=PAGE_SIZE)
+	for (vaddr = 0; vaddr < SUN4C_REAL_PGDIR_SIZE; vaddr += PAGE_SIZE)
 		sun4c_put_pte(vaddr, 0);
 	sun4c_put_segmap(0, invalid_segment);
 }
@@ -423,15 +308,15 @@
 
 	savectx = sun4c_get_context();
 	kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
-	for(ctx = 0; ctx < num_contexts; ctx++) {
+	for (ctx = 0; ctx < num_contexts; ctx++) {
 		sun4c_set_context(ctx);
-		for(vaddr = 0; vaddr < 0x20000000; vaddr += SUN4C_REAL_PGDIR_SIZE)
+		for (vaddr = 0; vaddr < 0x20000000; vaddr += SUN4C_REAL_PGDIR_SIZE)
 			sun4c_put_segmap(vaddr, invalid_segment);
-		for(vaddr = 0xe0000000; vaddr < KERNBASE; vaddr += SUN4C_REAL_PGDIR_SIZE)
+		for (vaddr = 0xe0000000; vaddr < KERNBASE; vaddr += SUN4C_REAL_PGDIR_SIZE)
 			sun4c_put_segmap(vaddr, invalid_segment);
-		for(vaddr = kernel_end; vaddr < KADB_DEBUGGER_BEGVM; vaddr += SUN4C_REAL_PGDIR_SIZE)
+		for (vaddr = kernel_end; vaddr < KADB_DEBUGGER_BEGVM; vaddr += SUN4C_REAL_PGDIR_SIZE)
 			sun4c_put_segmap(vaddr, invalid_segment);
-		for(vaddr = LINUX_OPPROM_ENDVM; vaddr; vaddr += SUN4C_REAL_PGDIR_SIZE)
+		for (vaddr = LINUX_OPPROM_ENDVM; vaddr; vaddr += SUN4C_REAL_PGDIR_SIZE)
 			sun4c_put_segmap(vaddr, invalid_segment);
 	}
 	sun4c_set_context(savectx);
@@ -442,7 +327,7 @@
 	sun4c_disable_vac();
 
 	if (ARCH_SUN4) {
-		switch(idprom->id_machtype) {
+		switch (idprom->id_machtype) {
 
 		case (SM_SUN4|SM_4_110):
 			sun4c_vacinfo.type = NONE;
@@ -477,12 +362,12 @@
 		default:
 			prom_printf("Cannot initialize VAC - wierd sun4 model idprom->id_machtype = %d", idprom->id_machtype);
 			prom_halt();
-		}
+		};
 	} else {
 		sun4c_vacinfo.type = WRITE_THROUGH;
 
-		if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
-		   (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+		if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+		    (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
 			/* PROM on SS1 lacks this info, to be super safe we
 			 * hard code it here since this arch is cast in stone.
 			 */
@@ -497,7 +382,7 @@
 		sun4c_vacinfo.do_hwflushes =
 		 prom_getintdefault(prom_root_node, "vac-hwflush", 0);
 
-		if(sun4c_vacinfo.do_hwflushes == 0)
+		if (sun4c_vacinfo.do_hwflushes == 0)
 			sun4c_vacinfo.do_hwflushes =
 			 prom_getintdefault(prom_root_node, "vac_hwflush", 0);
 
@@ -509,7 +394,7 @@
 
 	sun4c_vacinfo.num_lines =
 		(sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
-	switch(sun4c_vacinfo.linesize) {
+	switch (sun4c_vacinfo.linesize) {
 	case 16:
 		sun4c_vacinfo.log2lsize = 4;
 		break;
@@ -566,7 +451,7 @@
 			prom_printf("Unhandled number of segmaps: %d\n",
 				    num_segmaps);
 			prom_halt();
-	}
+	};
 	switch (num_contexts) {
 		case 8:
 			/* Default, nothing to do. */
@@ -574,19 +459,22 @@
 		case 16:
 			PATCH_INSN(num_context_patch1_16,
 				   num_context_patch1);
+#if 0
 			PATCH_INSN(num_context_patch2_16,
 				   num_context_patch2);
+#endif
 			break;
 		default:
 			prom_printf("Unhandled number of contexts: %d\n",
 				    num_contexts);
 			prom_halt();
-	}
-	if(sun4c_vacinfo.do_hwflushes != 0) {
+	};
+
+	if (sun4c_vacinfo.do_hwflushes != 0) {
 		PATCH_INSN(vac_hwflush_patch1_on, vac_hwflush_patch1);
 		PATCH_INSN(vac_hwflush_patch2_on, vac_hwflush_patch2);
 	} else {
-		switch(sun4c_vacinfo.linesize) {
+		switch (sun4c_vacinfo.linesize) {
 		case 16:
 			/* Default, nothing to do. */
 			break;
@@ -604,7 +492,7 @@
 __initfunc(static void sun4c_probe_mmu(void))
 {
 	if (ARCH_SUN4) {
-		switch(idprom->id_machtype) {
+		switch (idprom->id_machtype) {
 		case (SM_SUN4|SM_4_110):
 			prom_printf("No support for 4100 yet\n");
 			prom_halt();
@@ -631,10 +519,10 @@
 		default:
 			prom_printf("Invalid SUN4 model\n");
 			prom_halt();
-		}
+		};
 	} else {
-		if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
-	   	(idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+		if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+		    (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
 			/* Hardcode these just to be safe, PROM on SS1 does
 		 	* not have this info available in the root node.
 		 	*/
@@ -679,10 +567,10 @@
 {
 	extern unsigned long start;
 
-	if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) ||
-	   (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) ||
-	   (idprom->id_machtype == (SM_SUN4 | SM_4_330)) ||
-	   (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) {
+	if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) ||
+	    (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) ||
+	    (idprom->id_machtype == (SM_SUN4 | SM_4_330)) ||
+	    (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) {
 		/* Whee.. */
 		printk("SS2 cache bug detected, uncaching trap table page\n");
 		sun4c_flush_page((unsigned int) &start);
@@ -697,9 +585,9 @@
 	unsigned long page, end;
 
 	end = PAGE_ALIGN((addr + len));
-	while(addr < end) {
+	while (addr < end) {
 		page = get_free_page(GFP_KERNEL);
-		if(!page) {
+		if (!page) {
 			prom_printf("alloc_dvma: Cannot get a dvma page\n");
 			prom_halt();
 		}
@@ -726,6 +614,13 @@
 	unsigned long vaddr;
 	unsigned char pseg;
 	unsigned char locked;
+
+	/* For user mappings only, and completely hidden from kernel
+	 * TLB miss code.
+	 */
+	unsigned char ctx;
+	struct sun4c_mmu_entry *lru_next;
+	struct sun4c_mmu_entry *lru_prev;
 };
 
 static struct sun4c_mmu_entry mmu_entry_pool[SUN4C_MAX_SEGMAPS];
@@ -734,12 +629,15 @@
 {
 	int i;
 
-	for(i=0; i < SUN4C_MAX_SEGMAPS; i++) {
+	for (i = 0; i < SUN4C_MAX_SEGMAPS; i++) {
 		mmu_entry_pool[i].pseg = i;
 		mmu_entry_pool[i].next = 0;
 		mmu_entry_pool[i].prev = 0;
 		mmu_entry_pool[i].vaddr = 0;
 		mmu_entry_pool[i].locked = 0;
+		mmu_entry_pool[i].ctx = 0;
+		mmu_entry_pool[i].lru_next = 0;
+		mmu_entry_pool[i].lru_prev = 0;
 	}
 	mmu_entry_pool[invalid_segment].locked = 1;
 }
@@ -750,8 +648,8 @@
 	unsigned long start, end;
 
 	end = vaddr + SUN4C_REAL_PGDIR_SIZE;
-	for(start = vaddr; start < end; start += PAGE_SIZE)
-		if(sun4c_get_pte(start) & _SUN4C_PAGE_VALID)
+	for (start = vaddr; start < end; start += PAGE_SIZE)
+		if (sun4c_get_pte(start) & _SUN4C_PAGE_VALID)
 			sun4c_put_pte(start, (sun4c_get_pte(start) | bits_on) &
 				      ~bits_off);
 }
@@ -762,16 +660,16 @@
 	unsigned char pseg, ctx;
 #ifdef CONFIG_SUN4
 	/* sun4/110 and 260 have no kadb. */
-	if((idprom->id_machtype != (SM_SUN4 | SM_4_260)) && 
-	   (idprom->id_machtype != (SM_SUN4 | SM_4_110))) {
+	if ((idprom->id_machtype != (SM_SUN4 | SM_4_260)) && 
+	    (idprom->id_machtype != (SM_SUN4 | SM_4_110))) {
 #endif
-	for(vaddr = KADB_DEBUGGER_BEGVM;
-	    vaddr < LINUX_OPPROM_ENDVM;
-	    vaddr += SUN4C_REAL_PGDIR_SIZE) {
+	for (vaddr = KADB_DEBUGGER_BEGVM;
+	     vaddr < LINUX_OPPROM_ENDVM;
+	     vaddr += SUN4C_REAL_PGDIR_SIZE) {
 		pseg = sun4c_get_segmap(vaddr);
-		if(pseg != invalid_segment) {
+		if (pseg != invalid_segment) {
 			mmu_entry_pool[pseg].locked = 1;
-			for(ctx = 0; ctx < num_contexts; ctx++)
+			for (ctx = 0; ctx < num_contexts; ctx++)
 				prom_putsegment(ctx, vaddr, pseg);
 			fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
 		}
@@ -779,10 +677,10 @@
 #ifdef CONFIG_SUN4
 	}
 #endif
-	for(vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
+	for (vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
 		pseg = sun4c_get_segmap(vaddr);
 		mmu_entry_pool[pseg].locked = 1;
-		for(ctx = 0; ctx < num_contexts; ctx++)
+		for (ctx = 0; ctx < num_contexts; ctx++)
 			prom_putsegment(ctx, vaddr, pseg);
 		fix_permissions(vaddr, _SUN4C_PAGE_PRIV, _SUN4C_PAGE_NOCACHE);
 	}
@@ -792,13 +690,13 @@
 {
 	int i, ctx;
 
-	while(start < end) {
-		for(i=0; i < invalid_segment; i++)
-			if(!mmu_entry_pool[i].locked)
+	while (start < end) {
+		for (i = 0; i < invalid_segment; i++)
+			if (!mmu_entry_pool[i].locked)
 				break;
 		mmu_entry_pool[i].locked = 1;
 		sun4c_init_clean_segmap(i);
-		for(ctx = 0; ctx < num_contexts; ctx++)
+		for (ctx = 0; ctx < num_contexts; ctx++)
 			prom_putsegment(ctx, start, mmu_entry_pool[i].pseg);
 		start += SUN4C_REAL_PGDIR_SIZE;
 	}
@@ -815,13 +713,15 @@
 
 static struct sun4c_mmu_ring sun4c_context_ring[SUN4C_MAX_CONTEXTS]; /* used user entries */
 static struct sun4c_mmu_ring sun4c_ufree_ring;       /* free user entries */
+static struct sun4c_mmu_ring sun4c_ulru_ring;	     /* LRU user entries */
 struct sun4c_mmu_ring sun4c_kernel_ring;      /* used kernel entries */
 struct sun4c_mmu_ring sun4c_kfree_ring;       /* free kernel entries */
 
 static inline void sun4c_init_rings(unsigned long *mempool)
 {
 	int i;
-	for(i=0; i<SUN4C_MAX_CONTEXTS; i++) {
+
+	for (i = 0; i<SUN4C_MAX_CONTEXTS; i++) {
 		sun4c_context_ring[i].ringhd.next =
 			sun4c_context_ring[i].ringhd.prev =
 			&sun4c_context_ring[i].ringhd;
@@ -830,6 +730,9 @@
 	sun4c_ufree_ring.ringhd.next = sun4c_ufree_ring.ringhd.prev =
 		&sun4c_ufree_ring.ringhd;
 	sun4c_ufree_ring.num_entries = 0;
+	sun4c_ulru_ring.ringhd.lru_next = sun4c_ulru_ring.ringhd.lru_prev =
+		&sun4c_ulru_ring.ringhd;
+	sun4c_ulru_ring.num_entries = 0;
 	sun4c_kernel_ring.ringhd.next = sun4c_kernel_ring.ringhd.prev =
 		&sun4c_kernel_ring.ringhd;
 	sun4c_kernel_ring.num_entries = 0;
@@ -838,8 +741,8 @@
 	sun4c_kfree_ring.num_entries = 0;
 }
 
-static inline void add_ring(struct sun4c_mmu_ring *ring,
-			    struct sun4c_mmu_entry *entry)
+static void add_ring(struct sun4c_mmu_ring *ring,
+		     struct sun4c_mmu_entry *entry)
 {
 	struct sun4c_mmu_entry *head = &ring->ringhd;
 
@@ -849,49 +752,58 @@
 	ring->num_entries++;
 }
 
-static inline void add_ring_ordered(struct sun4c_mmu_ring *ring,
-				    struct sun4c_mmu_entry *entry)
+static __inline__ void add_lru(struct sun4c_mmu_entry *entry)
+{
+	struct sun4c_mmu_ring *ring = &sun4c_ulru_ring;
+	struct sun4c_mmu_entry *head = &ring->ringhd;
+
+	entry->lru_next = head;
+	(entry->lru_prev = head->lru_prev)->lru_next = entry;
+	head->lru_prev = entry;
+}
+
+static void add_ring_ordered(struct sun4c_mmu_ring *ring,
+			     struct sun4c_mmu_entry *entry)
 {
 	struct sun4c_mmu_entry *head = &ring->ringhd;
 	unsigned long addr = entry->vaddr;
 
-	if(head->next != &ring->ringhd) {
-		while((head->next != &ring->ringhd) && (head->next->vaddr < addr))
-			head = head->next;
-	}
+	while ((head->next != &ring->ringhd) && (head->next->vaddr < addr))
+		head = head->next;
+
 	entry->prev = head;
 	(entry->next = head->next)->prev = entry;
 	head->next = entry;
 	ring->num_entries++;
+
+	add_lru(entry);
 }
 
-static inline void remove_ring(struct sun4c_mmu_ring *ring,
-			       struct sun4c_mmu_entry *entry)
+static __inline__ void remove_ring(struct sun4c_mmu_ring *ring,
+				   struct sun4c_mmu_entry *entry)
 {
 	struct sun4c_mmu_entry *next = entry->next;
 
 	(next->prev = entry->prev)->next = next;
 	ring->num_entries--;
-#ifdef DEBUG_SUN4C_MM
-	if(ring->num_entries < 0)
-		panic("sun4c: Ring num_entries < 0!");
-#endif
 }
 
-static inline void free_user_entry(int ctx, struct sun4c_mmu_entry *entry)
+static void remove_lru(struct sun4c_mmu_entry *entry)
 {
-        remove_ring(sun4c_context_ring+ctx, entry);
-        add_ring(&sun4c_ufree_ring, entry);
+	struct sun4c_mmu_entry *next = entry->lru_next;
+
+	(next->lru_prev = entry->lru_prev)->lru_next = next;
 }
 
-static inline void assign_user_entry(int ctx, struct sun4c_mmu_entry *entry) 
+static void free_user_entry(int ctx, struct sun4c_mmu_entry *entry)
 {
-        remove_ring(&sun4c_ufree_ring, entry);
-        add_ring_ordered(sun4c_context_ring+ctx, entry);
+        remove_ring(sun4c_context_ring+ctx, entry);
+	remove_lru(entry);
+        add_ring(&sun4c_ufree_ring, entry);
 }
 
-static inline void free_kernel_entry(struct sun4c_mmu_entry *entry,
-				     struct sun4c_mmu_ring *ring)
+static void free_kernel_entry(struct sun4c_mmu_entry *entry,
+			      struct sun4c_mmu_ring *ring)
 {
         remove_ring(ring, entry);
         add_ring(&sun4c_kfree_ring, entry);
@@ -901,9 +813,9 @@
 {
 	int i;
 
-	while(howmany) {
-		for(i=0; i < invalid_segment; i++)
-			if(!mmu_entry_pool[i].locked)
+	while (howmany) {
+		for (i = 0; i < invalid_segment; i++)
+			if (!mmu_entry_pool[i].locked)
 				break;
 		mmu_entry_pool[i].locked = 1;
 		sun4c_init_clean_segmap(i);
@@ -916,54 +828,40 @@
 {
 	int i;
 
-	for(i=0; i < invalid_segment; i++) {
-		if(mmu_entry_pool[i].locked)
+	for (i = 0; i < invalid_segment; i++) {
+		if (mmu_entry_pool[i].locked)
 			continue;
 		sun4c_init_clean_segmap(i);
 		add_ring(&sun4c_ufree_ring, &mmu_entry_pool[i]);
 	}
 }
 
-static inline void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry)
+static void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry)
 {
 	int savectx, ctx;
 
 	savectx = sun4c_get_context();
-	for(ctx = 0; ctx < num_contexts; ctx++) {
+	for (ctx = 0; ctx < num_contexts; ctx++) {
 		sun4c_set_context(ctx);
 		sun4c_put_segmap(kentry->vaddr, invalid_segment);
 	}
 	sun4c_set_context(savectx);
 }
 
-static inline void sun4c_kernel_map(struct sun4c_mmu_entry *kentry)
+static void sun4c_kernel_map(struct sun4c_mmu_entry *kentry)
 {
 	int savectx, ctx;
 
 	savectx = sun4c_get_context();
-	for(ctx = 0; ctx < num_contexts; ctx++) {
+	for (ctx = 0; ctx < num_contexts; ctx++) {
 		sun4c_set_context(ctx);
 		sun4c_put_segmap(kentry->vaddr, kentry->pseg);
 	}
 	sun4c_set_context(savectx);
 }
 
-static inline void sun4c_user_unmap(struct sun4c_mmu_entry *uentry)
-{
-	sun4c_put_segmap(uentry->vaddr, invalid_segment);
-}
-
-static inline void sun4c_user_map(struct sun4c_mmu_entry *uentry)
-{
-	unsigned long start = uentry->vaddr;
-	unsigned long end = start + SUN4C_REAL_PGDIR_SIZE;
-
-	sun4c_put_segmap(uentry->vaddr, uentry->pseg);
-	while(start < end) {
-		sun4c_put_pte(start, 0);
-		start += PAGE_SIZE;
-	}
-}
+#define sun4c_user_unmap(__entry) \
+	sun4c_put_segmap((__entry)->vaddr, invalid_segment)
 
 static void sun4c_demap_context_hw(struct sun4c_mmu_ring *crp, unsigned char ctx)
 {
@@ -971,11 +869,11 @@
 	unsigned long flags;
 
 	save_and_cli(flags);
-	if(head->next != head) {
+	if (head->next != head) {
 		struct sun4c_mmu_entry *entry = head->next;
 		int savectx = sun4c_get_context();
 
-		FUW_INLINE
+		flush_user_windows();
 		sun4c_set_context(ctx);
 		sun4c_flush_context_hw();
 		do {
@@ -985,7 +883,7 @@
 			free_user_entry(ctx, entry);
 
 			entry = next;
-		} while(entry != head);
+		} while (entry != head);
 		sun4c_set_context(savectx);
 	}
 	restore_flags(flags);
@@ -997,11 +895,11 @@
 	unsigned long flags;
 
 	save_and_cli(flags);
-	if(head->next != head) {
+	if (head->next != head) {
 		struct sun4c_mmu_entry *entry = head->next;
 		int savectx = sun4c_get_context();
 
-		FUW_INLINE
+		flush_user_windows();
 		sun4c_set_context(ctx);
 		sun4c_flush_context_sw();
 		do {
@@ -1011,49 +909,31 @@
 			free_user_entry(ctx, entry);
 
 			entry = next;
-		} while(entry != head);
+		} while (entry != head);
 		sun4c_set_context(savectx);
 	}
 	restore_flags(flags);
 }
 
-static inline void sun4c_demap_one(struct sun4c_mmu_ring *crp, unsigned char ctx)
-{
-	/* by using .prev we get a kind of "lru" algorithm */
-	struct sun4c_mmu_entry *entry = crp->ringhd.prev;
-	unsigned long flags;
-	int savectx = sun4c_get_context();
-
-#ifdef DEBUG_SUN4C_MM
-	if(entry == &crp->ringhd)
-		panic("sun4c_demap_one: Freeing from empty ctx ring.");
-#endif
-	FUW_INLINE
-	save_and_cli(flags);
-	sun4c_set_context(ctx);
-	sun4c_flush_segment(entry->vaddr);
-	sun4c_user_unmap(entry);
-	free_user_entry(ctx, entry);
-	sun4c_set_context(savectx);
-	restore_flags(flags);
-}
-
 static int sun4c_user_taken_entries = 0;  /* This is how much we have.             */
 static int max_user_taken_entries = 0;    /* This limits us and prevents deadlock. */
 
-static inline struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
+static struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
 {
 	struct sun4c_mmu_entry *this_entry;
 
 	/* If some are free, return first one. */
-	if(sun4c_kfree_ring.num_entries) {
+	if (sun4c_kfree_ring.num_entries) {
 		this_entry = sun4c_kfree_ring.ringhd.next;
 		return this_entry;
 	}
 
 	/* Else free one up. */
 	this_entry = sun4c_kernel_ring.ringhd.prev;
-	sun4c_flush_segment(this_entry->vaddr);
+	if (sun4c_vacinfo.do_hwflushes)
+		sun4c_flush_segment_hw(this_entry->vaddr);
+	else
+		sun4c_flush_segment_sw(this_entry->vaddr);
 	sun4c_kernel_unmap(this_entry);
 	free_kernel_entry(this_entry, &sun4c_kernel_ring);
 	this_entry = sun4c_kfree_ring.ringhd.next;
@@ -1061,141 +941,73 @@
 	return this_entry;
 }
 
-void sun4c_shrink_kernel_ring(void)
-{
-	struct sun4c_mmu_entry *entry;
-	unsigned long flags;
-
-	/* If an interrupt comes in here, we die... */
-	save_and_cli(flags);
-
-	if (sun4c_user_taken_entries) {
-		entry = sun4c_kernel_strategy();
-        	remove_ring(&sun4c_kfree_ring, entry);
-		add_ring(&sun4c_ufree_ring, entry);
-		sun4c_user_taken_entries--;
-#if 0
-		printk("shrink: ufree= %d, kfree= %d, kernel= %d\n",
-			sun4c_ufree_ring.num_entries,
-			sun4c_kfree_ring.num_entries,
-			sun4c_kernel_ring.num_entries);
-#endif
-#ifdef DEBUG_SUN4C_MM
-		if(sun4c_user_taken_entries < 0)
-			panic("sun4c_shrink_kernel_ring: taken < 0.");
-#endif
-	}
-	restore_flags(flags);
-}
-
 /* Using this method to free up mmu entries eliminates a lot of
  * potential races since we have a kernel that incurs tlb
  * replacement faults.  There may be performance penalties.
+ *
+ * NOTE: Must be called with interrupts disabled.
  */
-static inline struct sun4c_mmu_entry *sun4c_user_strategy(void)
+static struct sun4c_mmu_entry *sun4c_user_strategy(void)
 {
-	struct ctx_list *next_one;
-	struct sun4c_mmu_ring *rp = 0;
+	struct sun4c_mmu_entry *entry;
 	unsigned char ctx;
-#ifdef DEBUG_SUN4C_MM
-	int lim = num_contexts;
-#endif
+	int savectx;
 
 	/* If some are free, return first one. */
-	if(sun4c_ufree_ring.num_entries) {
-#ifdef DEBUG_SUN4C_MM
-		if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd)
-			panic("sun4c_user_strategy: num_entries!=0 but ring empty.");
-#endif
-		return sun4c_ufree_ring.ringhd.next;
+	if (sun4c_ufree_ring.num_entries) {
+		entry = sun4c_ufree_ring.ringhd.next;
+		goto unlink_out;
 	}
 
 	if (sun4c_user_taken_entries) {
-		sun4c_shrink_kernel_ring();
-#ifdef DEBUG_SUN4C_MM
-		if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd)
-			panic("sun4c_user_strategy: kernel shrunk but ufree empty.");
-#endif
-		return sun4c_ufree_ring.ringhd.next;
+		entry = sun4c_kernel_strategy();
+		sun4c_user_taken_entries--;
+		goto kunlink_out;
 	}
 
-	/* Grab one from the LRU context. */
-	next_one = ctx_used.next;
-	while ((sun4c_context_ring[next_one->ctx_number].num_entries == 0)
-#ifdef DEBUG_SUN4C_MM
-	       && (--lim >= 0)
-#endif
-	       )
-		next_one = next_one->next;
+	/* Grab from the beginning of the LRU list. */
+	entry = sun4c_ulru_ring.ringhd.lru_next;
+	ctx = entry->ctx;
 
-#ifdef DEBUG_SUN4C_MM
-	if(lim < 0)
-		panic("No user segmaps!");
-#endif
+	savectx = sun4c_get_context();
+	flush_user_windows();
+	sun4c_set_context(ctx);
+	if (sun4c_vacinfo.do_hwflushes)
+		sun4c_flush_segment_hw(entry->vaddr);
+	else
+		sun4c_flush_segment_sw(entry->vaddr);
+	sun4c_user_unmap(entry);
+	remove_ring(sun4c_context_ring + ctx, entry);
+	remove_lru(entry);
+	sun4c_set_context(savectx);
 
-	ctx = next_one->ctx_number;
-	rp = &sun4c_context_ring[ctx];
+	return entry;
 
-	sun4c_demap_one(rp, ctx);
-#ifdef DEBUG_SUN4C_MM
-	if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd)
-		panic("sun4c_user_strategy: demapped one but ufree empty.");
-#endif
-	return sun4c_ufree_ring.ringhd.next;
+unlink_out:
+	remove_ring(&sun4c_ufree_ring, entry);
+	return entry;
+kunlink_out:
+	remove_ring(&sun4c_kfree_ring, entry);
+	return entry;
 }
 
+/* NOTE: Must be called with interrupts disabled. */
 void sun4c_grow_kernel_ring(void)
 {
 	struct sun4c_mmu_entry *entry;
 
-#if 0
-	printk("grow: ");
-#endif
-
 	/* Prevent deadlock condition. */
-	if(sun4c_user_taken_entries >= max_user_taken_entries) {
-#if 0
-		printk("deadlock avoidance, taken= %d max= %d\n",
-		       sun4c_user_taken_entries, max_user_taken_entries);
-#endif
+	if (sun4c_user_taken_entries >= max_user_taken_entries)
 		return;
-	}
 
 	if (sun4c_ufree_ring.num_entries) {
 		entry = sun4c_ufree_ring.ringhd.next;
-#ifdef DEBUG_SUN4C_MM
-		if(entry == &sun4c_ufree_ring.ringhd)
-			panic("\nsun4c_grow_kernel_ring: num_entries!=0, ring empty.");
-#endif
         	remove_ring(&sun4c_ufree_ring, entry);
 		add_ring(&sun4c_kfree_ring, entry);
-#ifdef DEBUG_SUN4C_MM
-		if(sun4c_user_taken_entries < 0)
-			panic("\nsun4c_grow_kernel_ring: taken < 0.");
-#endif
 		sun4c_user_taken_entries++;
-#if 0
-		printk("ufree= %d, kfree= %d, kernel= %d\n",
-			sun4c_ufree_ring.num_entries,
-			sun4c_kfree_ring.num_entries,
-			sun4c_kernel_ring.num_entries);
-#endif
 	}
 }
 
-static inline void alloc_user_segment(unsigned long address, unsigned char ctx)
-{
-	struct sun4c_mmu_entry *entry;
-	unsigned long flags;
-
-	save_and_cli(flags);
-	entry = sun4c_user_strategy();
-	entry->vaddr = (address & SUN4C_REAL_PGDIR_MASK);
-	assign_user_entry(ctx, entry);
-	sun4c_user_map(entry);
-	restore_flags(flags);
-}
-
 /* This is now a fast in-window trap handler to avoid any and all races. */
 static void sun4c_quick_kernel_fault(unsigned long address)
 {
@@ -1234,7 +1046,7 @@
 #define BUCKET_PTE_PAGE(pte)   \
         (PAGE_OFFSET + (((pte) & SUN4C_PFN_MASK) << PAGE_SHIFT))
 
-static inline void get_locked_segment(unsigned long addr)
+static void get_locked_segment(unsigned long addr)
 {
 	struct sun4c_mmu_entry *stolen;
 	unsigned long flags;
@@ -1242,19 +1054,14 @@
 	save_and_cli(flags);
 	addr &= SUN4C_REAL_PGDIR_MASK;
 	stolen = sun4c_user_strategy();
-	remove_ring(&sun4c_ufree_ring, stolen);
 	max_user_taken_entries--;
-#ifdef DEBUG_SUN4C_MM
-	if(max_user_taken_entries < 0)
-		panic("get_locked_segment: max_user_taken < 0.");
-#endif
 	stolen->vaddr = addr;
-	FUW_INLINE
+	flush_user_windows();
 	sun4c_kernel_map(stolen);
 	restore_flags(flags);
 }
 
-static inline void free_locked_segment(unsigned long addr)
+static void free_locked_segment(unsigned long addr)
 {
 	struct sun4c_mmu_entry *entry;
 	unsigned long flags;
@@ -1265,14 +1072,13 @@
 	pseg = sun4c_get_segmap(addr);
 	entry = &mmu_entry_pool[pseg];
 
-	FUW_INLINE
-	sun4c_flush_segment(addr);
+	flush_user_windows();
+	if (sun4c_vacinfo.do_hwflushes)
+		sun4c_flush_segment_hw(addr);
+	else
+		sun4c_flush_segment_sw(addr);
 	sun4c_kernel_unmap(entry);
 	add_ring(&sun4c_ufree_ring, entry);
-#ifdef DEBUG_SUN4C_MM
-	if(max_user_taken_entries < 0)
-		panic("free_locked_segment: max_user_taken < 0.");
-#endif
 	max_user_taken_entries++;
 	restore_flags(flags);
 }
@@ -1284,8 +1090,8 @@
 	/* 32 buckets per segment... */
 	entry &= ~31;
 	start = entry;
-	for(end = (start + 32); start < end; start++)
-		if(sun4c_bucket[start] != BUCKET_EMPTY)
+	for (end = (start + 32); start < end; start++)
+		if (sun4c_bucket[start] != BUCKET_EMPTY)
 			return;
 
 	/* Entire segment empty, release it. */
@@ -1304,23 +1110,39 @@
 	int entry;
 
 	pages = __get_free_pages(GFP_KERNEL, TASK_STRUCT_ORDER);
-	if(!pages)
+	if (!pages)
 		return (struct task_struct *) 0;
 
-	for(entry = sun4c_lowbucket_avail; entry < NR_TASK_BUCKETS; entry++)
-		if(sun4c_bucket[entry] == BUCKET_EMPTY)
+	for (entry = sun4c_lowbucket_avail; entry < NR_TASK_BUCKETS; entry++)
+		if (sun4c_bucket[entry] == BUCKET_EMPTY)
 			break;
-	if(entry == NR_TASK_BUCKETS) {
+	if (entry == NR_TASK_BUCKETS) {
 		free_pages(pages, TASK_STRUCT_ORDER);
 		return (struct task_struct *) 0;
 	}
-	if(entry >= sun4c_lowbucket_avail)
+	if (entry >= sun4c_lowbucket_avail)
 		sun4c_lowbucket_avail = entry + 1;
 
 	addr = BUCKET_ADDR(entry);
 	sun4c_bucket[entry] = (union task_union *) addr;
-	if(sun4c_get_segmap(addr) == invalid_segment)
+	if (sun4c_get_segmap(addr) == invalid_segment)
 		get_locked_segment(addr);
+
+	/* We are changing the virtual color of the page(s)
+	 * so we must flush the cache to guarentee consistancy.
+	 */
+	if (sun4c_vacinfo.do_hwflushes) {
+		sun4c_flush_page_hw(pages);
+#ifndef CONFIG_SUN4	
+		sun4c_flush_page_hw(pages + PAGE_SIZE);
+#endif
+	} else {
+		sun4c_flush_page_sw(pages);
+#ifndef CONFIG_SUN4	
+		sun4c_flush_page_sw(pages + PAGE_SIZE);
+#endif
+	}
+
 	sun4c_put_pte(addr, BUCKET_PTE(pages));
 #ifndef CONFIG_SUN4	
 	sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE));
@@ -1344,7 +1166,7 @@
 	sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
 #endif
 	sun4c_bucket[entry] = BUCKET_EMPTY;
-	if(entry < sun4c_lowbucket_avail)
+	if (entry < sun4c_lowbucket_avail)
 		sun4c_lowbucket_avail = entry;
 
 	free_pages(pages, TASK_STRUCT_ORDER);
@@ -1367,7 +1189,7 @@
 	sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
 #endif
 	sun4c_bucket[entry] = BUCKET_EMPTY;
-	if(entry < sun4c_lowbucket_avail)
+	if (entry < sun4c_lowbucket_avail)
 		sun4c_lowbucket_avail = entry;
 
 	free_pages(pages, TASK_STRUCT_ORDER);
@@ -1378,10 +1200,10 @@
 {
 	int entry;
 
-	if(sizeof(union task_union) != (PAGE_SIZE << TASK_STRUCT_ORDER)) {
+	if (sizeof(union task_union) != (PAGE_SIZE << TASK_STRUCT_ORDER)) {
 		prom_printf("task union not %d page(s)!\n", 1 << TASK_STRUCT_ORDER);
 	}
-	for(entry = 0; entry < NR_TASK_BUCKETS; entry++)
+	for (entry = 0; entry < NR_TASK_BUCKETS; entry++)
 		sun4c_bucket[entry] = BUCKET_EMPTY;
 	sun4c_lowbucket_avail = 0;
 }
@@ -1501,7 +1323,7 @@
 	unsigned long page;
 
 	page = ((unsigned long)bufptr) & PAGE_MASK;
-	if(MAP_NR(page) > max_mapnr) {
+	if (MAP_NR(page) > max_mapnr) {
 		sun4c_flush_page(page);
 		return (__u32)bufptr; /* already locked */
 	}
@@ -1510,7 +1332,7 @@
 
 static void sun4c_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
 {
-	while(sz >= 0) {
+	while (sz >= 0) {
 		sg[sz].dvma_addr = (__u32)sun4c_lockarea(sg[sz].addr, sg[sz].len);
 		sz--;
 	}
@@ -1518,14 +1340,14 @@
 
 static void sun4c_release_scsi_one(__u32 bufptr, unsigned long len, struct linux_sbus *sbus)
 {
-	if(bufptr < sun4c_iobuffer_start)
+	if (bufptr < sun4c_iobuffer_start)
 		return; /* On kernel stack or similar, see above */
 	sun4c_unlockarea((char *)bufptr, len);
 }
 
 static void sun4c_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
 {
-	while(sz >= 0) {
+	while (sz >= 0) {
 		sun4c_unlockarea((char *)sg[sz].dvma_addr, sg[sz].len);
 		sz--;
 	}
@@ -1546,7 +1368,7 @@
 	sun4c_taskstack_start = SUN4C_LOCK_VADDR;
 	sun4c_taskstack_end = (sun4c_taskstack_start +
 			       (TASK_ENTRY_SIZE * NR_TASK_BUCKETS));
-	if(sun4c_taskstack_end >= SUN4C_LOCK_END) {
+	if (sun4c_taskstack_end >= SUN4C_LOCK_END) {
 		prom_printf("Too many tasks, decrease NR_TASK_BUCKETS please.\n");
 		prom_halt();
 	}
@@ -1576,12 +1398,12 @@
 {
 	unsigned long begin, end;
 
-	FUW_INLINE
+	flush_user_windows();
 	begin = (KERNBASE + SUN4C_REAL_PGDIR_SIZE);
 	end = (begin + SUN4C_VAC_SIZE);
 
-	if(sun4c_vacinfo.linesize == 32) {
-		while(begin < end) {
+	if (sun4c_vacinfo.linesize == 32) {
+		while (begin < end) {
 			__asm__ __volatile__("
 			ld	[%0 + 0x00], %%g0
 			ld	[%0 + 0x20], %%g0
@@ -1603,7 +1425,7 @@
 			begin += 512;
 		}
 	} else {
-		while(begin < end) {
+		while (begin < end) {
 			__asm__ __volatile__("
 			ld	[%0 + 0x00], %%g0
 			ld	[%0 + 0x10], %%g0
@@ -1631,29 +1453,31 @@
 {
 	int new_ctx = mm->context;
 
-	if(new_ctx != NO_CONTEXT && sun4c_context_ring[new_ctx].num_entries) {
-		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
-		unsigned long flags;
+	if (new_ctx != NO_CONTEXT) {
+		flush_user_windows();
+		if (sun4c_context_ring[new_ctx].num_entries) {
+			struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
+			unsigned long flags;
+
+			save_and_cli(flags);
+			if (head->next != head) {
+				struct sun4c_mmu_entry *entry = head->next;
+				int savectx = sun4c_get_context();
+
+				sun4c_set_context(new_ctx);
+				sun4c_flush_context_hw();
+				do {
+					struct sun4c_mmu_entry *next = entry->next;
 
-		save_and_cli(flags);
-		if(head->next != head) {
-			struct sun4c_mmu_entry *entry = head->next;
-			int savectx = sun4c_get_context();
-
-			FUW_INLINE
-			sun4c_set_context(new_ctx);
-			sun4c_flush_context_hw();
-			do {
-				struct sun4c_mmu_entry *next = entry->next;
-
-				sun4c_user_unmap(entry);
-				free_user_entry(new_ctx, entry);
+					sun4c_user_unmap(entry);
+					free_user_entry(new_ctx, entry);
 
-				entry = next;
-			} while(entry != head);
-			sun4c_set_context(savectx);
+					entry = next;
+				} while (entry != head);
+				sun4c_set_context(savectx);
+			}
+			restore_flags(flags);
 		}
-		restore_flags(flags);
 	}
 }
 
@@ -1661,29 +1485,28 @@
 {
 	int new_ctx = mm->context;
 	
-#if KGPROF_PROFILING
-	kgprof_profile();
-#endif
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
 		struct sun4c_mmu_entry *entry;
 		unsigned long flags;
 
-		FUW_INLINE
+		flush_user_windows();
+
 		save_and_cli(flags);
 
 		/* All user segmap chains are ordered on entry->vaddr. */
-		for(entry = head->next;
-		    (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
-		    entry = entry->next)
+		for (entry = head->next;
+		     (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+		     entry = entry->next)
 			;
 
 		/* Tracing various job mixtures showed that this conditional
 		 * only passes ~35% of the time for most worse case situations,
 		 * therefore we avoid all of this gross overhead ~65% of the time.
 		 */
-		if((entry != head) && (entry->vaddr < end)) {
+		if ((entry != head) && (entry->vaddr < end)) {
 			int octx = sun4c_get_context();
+
 			sun4c_set_context(new_ctx);
 
 			/* At this point, always, (start >= entry->vaddr) and
@@ -1698,11 +1521,11 @@
 
 				/* "realstart" is always >= entry->vaddr */
 				realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE;
-				if(end < realend)
+				if (end < realend)
 					realend = end;
-				if((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
+				if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
 					unsigned long page = entry->vaddr;
-					while(page < realend) {
+					while (page < realend) {
 						sun4c_flush_page_hw(page);
 						page += PAGE_SIZE;
 					}
@@ -1712,14 +1535,13 @@
 					free_user_entry(new_ctx, entry);
 				}
 				entry = next;
-			} while((entry != head) && (entry->vaddr < end));
+			} while ((entry != head) && (entry->vaddr < end));
 			sun4c_set_context(octx);
 		}
 		restore_flags(flags);
 	}
 }
 
-/* XXX no save_and_cli/restore_flags needed, but put here if darkside still crashes */
 static void sun4c_flush_cache_page_hw(struct vm_area_struct *vma, unsigned long page)
 {
 	struct mm_struct *mm = vma->vm_mm;
@@ -1728,76 +1550,84 @@
 	/* Sun4c has no separate I/D caches so cannot optimize for non
 	 * text page flushes.
 	 */
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		int octx = sun4c_get_context();
+		unsigned long flags;
 
-		FUW_INLINE
+		flush_user_windows();
+		save_and_cli(flags);
 		sun4c_set_context(new_ctx);
 		sun4c_flush_page_hw(page);
 		sun4c_set_context(octx);
+		restore_flags(flags);
 	}
 }
 
 static void sun4c_flush_page_to_ram_hw(unsigned long page)
 {
+	unsigned long flags;
+
+	save_and_cli(flags);
 	sun4c_flush_page_hw(page);
+	restore_flags(flags);
 }
 
 static void sun4c_flush_cache_mm_sw(struct mm_struct *mm)
 {
 	int new_ctx = mm->context;
 
-	if(new_ctx != NO_CONTEXT && sun4c_context_ring[new_ctx].num_entries) {
-		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
-		unsigned long flags;
+	if (new_ctx != NO_CONTEXT) {
+		flush_user_windows();
 
-		save_and_cli(flags);
-		if(head->next != head) {
-			struct sun4c_mmu_entry *entry = head->next;
-			int savectx = sun4c_get_context();
-
-			FUW_INLINE
-			sun4c_set_context(new_ctx);
-			sun4c_flush_context_sw();
-			do {
-				struct sun4c_mmu_entry *next = entry->next;
+		if (sun4c_context_ring[new_ctx].num_entries) {
+			struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
+			unsigned long flags;
+
+			save_and_cli(flags);
+			if (head->next != head) {
+				struct sun4c_mmu_entry *entry = head->next;
+				int savectx = sun4c_get_context();
+
+				sun4c_set_context(new_ctx);
+				sun4c_flush_context_sw();
+				do {
+					struct sun4c_mmu_entry *next = entry->next;
 
-				sun4c_user_unmap(entry);
-				free_user_entry(new_ctx, entry);
+					sun4c_user_unmap(entry);
+					free_user_entry(new_ctx, entry);
 
-				entry = next;
-			} while(entry != head);
-			sun4c_set_context(savectx);
+					entry = next;
+				} while (entry != head);
+				sun4c_set_context(savectx);
+			}
+			restore_flags(flags);
 		}
-		restore_flags(flags);
 	}
 }
 
 static void sun4c_flush_cache_range_sw(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
 	int new_ctx = mm->context;
-	
-#if KGPROF_PROFILING
-	kgprof_profile();
-#endif
-	if(new_ctx != NO_CONTEXT) {
+
+	if (new_ctx != NO_CONTEXT) {
 		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
 		struct sun4c_mmu_entry *entry;
 		unsigned long flags;
 
-		FUW_INLINE
+		flush_user_windows();
+
 		save_and_cli(flags);
 		/* All user segmap chains are ordered on entry->vaddr. */
-		for(entry = head->next;
-		    (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
-		    entry = entry->next)
+		for (entry = head->next;
+		     (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+		     entry = entry->next)
 			;
 
 		/* Tracing various job mixtures showed that this conditional
 		 * only passes ~35% of the time for most worse case situations,
 		 * therefore we avoid all of this gross overhead ~65% of the time.
 		 */
-		if((entry != head) && (entry->vaddr < end)) {
+		if ((entry != head) && (entry->vaddr < end)) {
 			int octx = sun4c_get_context();
 			sun4c_set_context(new_ctx);
 
@@ -1813,11 +1643,11 @@
 
 				/* "realstart" is always >= entry->vaddr */
 				realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE;
-				if(end < realend)
+				if (end < realend)
 					realend = end;
-				if((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
+				if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
 					unsigned long page = entry->vaddr;
-					while(page < realend) {
+					while (page < realend) {
 						sun4c_flush_page_sw(page);
 						page += PAGE_SIZE;
 					}
@@ -1827,7 +1657,7 @@
 					free_user_entry(new_ctx, entry);
 				}
 				entry = next;
-			} while((entry != head) && (entry->vaddr < end));
+			} while ((entry != head) && (entry->vaddr < end));
 			sun4c_set_context(octx);
 		}
 		restore_flags(flags);
@@ -1842,19 +1672,26 @@
 	/* Sun4c has no separate I/D caches so cannot optimize for non
 	 * text page flushes.
 	 */
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		int octx = sun4c_get_context();
+		unsigned long flags;
 
-		FUW_INLINE
+		flush_user_windows();
+		save_and_cli(flags);
 		sun4c_set_context(new_ctx);
 		sun4c_flush_page_sw(page);
 		sun4c_set_context(octx);
+		restore_flags(flags);
 	}
 }
 
 static void sun4c_flush_page_to_ram_sw(unsigned long page)
 {
+	unsigned long flags;
+
+	save_and_cli(flags);
 	sun4c_flush_page_sw(page);
+	restore_flags(flags);
 }
 
 /* Sun4c cache is unified, both instructions and data live there, so
@@ -1881,8 +1718,11 @@
 	flush_user_windows();
 	while (sun4c_kernel_ring.num_entries) {
 		next_entry = this_entry->next;
-		sun4c_flush_segment(this_entry->vaddr);
-		for(ctx = 0; ctx < num_contexts; ctx++) {
+		if (sun4c_vacinfo.do_hwflushes)
+			sun4c_flush_segment_hw(this_entry->vaddr);
+		else
+			sun4c_flush_segment_sw(this_entry->vaddr);
+		for (ctx = 0; ctx < num_contexts; ctx++) {
 			sun4c_set_context(ctx);
 			sun4c_put_segmap(this_entry->vaddr, invalid_segment);
 		}
@@ -1897,16 +1737,15 @@
 {
 	int new_ctx = mm->context;
 
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
 		unsigned long flags;
 
 		save_and_cli(flags);
-		if(head->next != head) {
+		if (head->next != head) {
 			struct sun4c_mmu_entry *entry = head->next;
 			int savectx = sun4c_get_context();
 
-			FUW_INLINE
 			sun4c_set_context(new_ctx);
 			sun4c_flush_context_hw();
 			do {
@@ -1916,7 +1755,7 @@
 				free_user_entry(new_ctx, entry);
 
 				entry = next;
-			} while(entry != head);
+			} while (entry != head);
 			sun4c_set_context(savectx);
 		}
 		restore_flags(flags);
@@ -1927,26 +1766,21 @@
 {
 	int new_ctx = mm->context;
 
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
 		struct sun4c_mmu_entry *entry;
 		unsigned long flags;
-#if KGPROF_PROFILING
-		kgprof_profile();
-#endif
 
 		save_and_cli(flags);
 		/* See commentary in sun4c_flush_cache_range_*(). */
-		for(entry = head->next;
-		    (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
-		    entry = entry->next)
+		for (entry = head->next;
+		     (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+		     entry = entry->next)
 			;
 
-		if((entry != head) && (entry->vaddr < end)) {
+		if ((entry != head) && (entry->vaddr < end)) {
 			int octx = sun4c_get_context();
 
-			/* This window flush is paranoid I think... -DaveM */
-			FUW_INLINE
 			sun4c_set_context(new_ctx);
 			do {
 				struct sun4c_mmu_entry *next = entry->next;
@@ -1956,7 +1790,7 @@
 				free_user_entry(new_ctx, entry);
 
 				entry = next;
-			} while((entry != head) && (entry->vaddr < end));
+			} while ((entry != head) && (entry->vaddr < end));
 			sun4c_set_context(octx);
 		}
 		restore_flags(flags);
@@ -1968,15 +1802,17 @@
 	struct mm_struct *mm = vma->vm_mm;
 	int new_ctx = mm->context;
 
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		int savectx = sun4c_get_context();
+		unsigned long flags;
 
-		FUW_INLINE
+		save_and_cli(flags);
 		sun4c_set_context(new_ctx);
 		page &= PAGE_MASK;
 		sun4c_flush_page_hw(page);
 		sun4c_put_pte(page, 0);
 		sun4c_set_context(savectx);
+		restore_flags(flags);
 	}
 }
 
@@ -1984,16 +1820,15 @@
 {
 	int new_ctx = mm->context;
 
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
 		unsigned long flags;
 
 		save_and_cli(flags);
-		if(head->next != head) {
+		if (head->next != head) {
 			struct sun4c_mmu_entry *entry = head->next;
 			int savectx = sun4c_get_context();
 
-			FUW_INLINE
 			sun4c_set_context(new_ctx);
 			sun4c_flush_context_sw();
 			do {
@@ -2003,7 +1838,7 @@
 				free_user_entry(new_ctx, entry);
 
 				entry = next;
-			} while(entry != head);
+			} while (entry != head);
 			sun4c_set_context(savectx);
 		}
 		restore_flags(flags);
@@ -2014,27 +1849,21 @@
 {
 	int new_ctx = mm->context;
 
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
 		struct sun4c_mmu_entry *entry;
 		unsigned long flags;
 
-#if KGPROF_PROFILING
-		kgprof_profile();
-#endif
-
 		save_and_cli(flags);
 		/* See commentary in sun4c_flush_cache_range_*(). */
-		for(entry = head->next;
-		    (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
-		    entry = entry->next)
+		for (entry = head->next;
+		     (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+		     entry = entry->next)
 			;
 
-		if((entry != head) && (entry->vaddr < end)) {
+		if ((entry != head) && (entry->vaddr < end)) {
 			int octx = sun4c_get_context();
 
-			/* This window flush is paranoid I think... -DaveM */
-			FUW_INLINE
 			sun4c_set_context(new_ctx);
 			do {
 				struct sun4c_mmu_entry *next = entry->next;
@@ -2044,7 +1873,7 @@
 				free_user_entry(new_ctx, entry);
 
 				entry = next;
-			} while((entry != head) && (entry->vaddr < end));
+			} while ((entry != head) && (entry->vaddr < end));
 			sun4c_set_context(octx);
 		}
 		restore_flags(flags);
@@ -2056,15 +1885,17 @@
 	struct mm_struct *mm = vma->vm_mm;
 	int new_ctx = mm->context;
 
-	if(new_ctx != NO_CONTEXT) {
+	if (new_ctx != NO_CONTEXT) {
 		int savectx = sun4c_get_context();
+		unsigned long flags;
 
-		FUW_INLINE
+		save_and_cli(flags);
 		sun4c_set_context(new_ctx);
 		page &= PAGE_MASK;
 		sun4c_flush_page_sw(page);
 		sun4c_put_pte(page, 0);
 		sun4c_set_context(savectx);
+		restore_flags(flags);
 	}
 }
 
@@ -2077,7 +1908,6 @@
 {
 }
 
-
 void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
 		     int bus_type, int rdonly)
 {
@@ -2085,7 +1915,7 @@
 
 	page_entry = ((physaddr >> PAGE_SHIFT) & SUN4C_PFN_MASK);
 	page_entry |= ((pg_iobits | _SUN4C_PAGE_PRIV) & ~(_SUN4C_PAGE_PRESENT));
-	if(rdonly)
+	if (rdonly)
 		page_entry &= ~_SUN4C_WRITEABLE;
 	sun4c_put_pte(virt_addr, page_entry);
 }
@@ -2100,7 +1930,7 @@
 	struct ctx_list *ctxp;
 
 	ctxp = ctx_free.next;
-	if(ctxp != &ctx_free) {
+	if (ctxp != &ctx_free) {
 		remove_from_ctx_list(ctxp);
 		add_to_used_ctxlist(ctxp);
 		mm->context = ctxp->ctx_number;
@@ -2108,26 +1938,22 @@
 		return;
 	}
 	ctxp = ctx_used.next;
-	if(ctxp->ctx_mm == current->mm)
+	if (ctxp->ctx_mm == current->mm)
 		ctxp = ctxp->next;
-#ifdef DEBUG_SUN4C_MM
-	if(ctxp == &ctx_used)
-		panic("out of mmu contexts");
-#endif
 	remove_from_ctx_list(ctxp);
 	add_to_used_ctxlist(ctxp);
 	ctxp->ctx_mm->context = NO_CONTEXT;
 	ctxp->ctx_mm = mm;
 	mm->context = ctxp->ctx_number;
 	sun4c_demap_context_hw(&sun4c_context_ring[ctxp->ctx_number],
-			    ctxp->ctx_number);
+			       ctxp->ctx_number);
 }
 
 static void sun4c_switch_to_context_hw(struct task_struct *tsk)
 {
 	struct ctx_list *ctx;
 
-	if(tsk->mm->context == NO_CONTEXT) {
+	if (tsk->mm->context == NO_CONTEXT) {
 		sun4c_alloc_context_hw(tsk->mm);
 	} else {
 		/* Update the LRU ring of contexts. */
@@ -2141,7 +1967,7 @@
 static void sun4c_init_new_context_hw(struct mm_struct *mm)
 {
 	sun4c_alloc_context_hw(mm);
-	if(mm == current->mm)
+	if (mm == current->mm)
 		sun4c_set_context(mm->context);
 }
 
@@ -2149,7 +1975,7 @@
 {
 	struct ctx_list *ctx_old;
 
-	if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
+	if (mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
 		sun4c_demap_context_hw(&sun4c_context_ring[mm->context], mm->context);
 		ctx_old = ctx_list_pool + mm->context;
 		remove_from_ctx_list(ctx_old);
@@ -2163,7 +1989,7 @@
 	struct ctx_list *ctxp;
 
 	ctxp = ctx_free.next;
-	if(ctxp != &ctx_free) {
+	if (ctxp != &ctx_free) {
 		remove_from_ctx_list(ctxp);
 		add_to_used_ctxlist(ctxp);
 		mm->context = ctxp->ctx_number;
@@ -2171,26 +1997,22 @@
 		return;
 	}
 	ctxp = ctx_used.next;
-	if(ctxp->ctx_mm == current->mm)
+	if (ctxp->ctx_mm == current->mm)
 		ctxp = ctxp->next;
-#ifdef DEBUG_SUN4C_MM
-	if(ctxp == &ctx_used)
-		panic("out of mmu contexts");
-#endif
 	remove_from_ctx_list(ctxp);
 	add_to_used_ctxlist(ctxp);
 	ctxp->ctx_mm->context = NO_CONTEXT;
 	ctxp->ctx_mm = mm;
 	mm->context = ctxp->ctx_number;
 	sun4c_demap_context_sw(&sun4c_context_ring[ctxp->ctx_number],
-			    ctxp->ctx_number);
+			       ctxp->ctx_number);
 }
 
 static void sun4c_switch_to_context_sw(struct task_struct *tsk)
 {
 	struct ctx_list *ctx;
 
-	if(tsk->mm->context == NO_CONTEXT) {
+	if (tsk->mm->context == NO_CONTEXT) {
 		sun4c_alloc_context_sw(tsk->mm);
 	} else {
 		/* Update the LRU ring of contexts. */
@@ -2204,7 +2026,7 @@
 static void sun4c_init_new_context_sw(struct mm_struct *mm)
 {
 	sun4c_alloc_context_sw(mm);
-	if(mm == current->mm)
+	if (mm == current->mm)
 		sun4c_set_context(mm->context);
 }
 
@@ -2212,7 +2034,7 @@
 {
 	struct ctx_list *ctx_old;
 
-	if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
+	if (mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
 		sun4c_demap_context_sw(&sun4c_context_ring[mm->context], mm->context);
 		ctx_old = ctx_list_pool + mm->context;
 		remove_from_ctx_list(ctx_old);
@@ -2227,7 +2049,7 @@
 	int len;
 
 	used_user_entries = 0;
-	for(i=0; i < num_contexts; i++)
+	for (i = 0; i < num_contexts; i++)
 		used_user_entries += sun4c_context_ring[i].num_entries;
 
 	len = sprintf(buf, 
@@ -2241,10 +2063,7 @@
 		"usedpsegs\t: %d\n"
 		"ufreepsegs\t: %d\n"
 		"user_taken\t: %d\n"
-		"max_taken\t: %d\n"
-		"context\t\t: %d flushes\n"
-		"segment\t\t: %d flushes\n"
-		"page\t\t: %d flushes\n",
+		"max_taken\t: %d\n",
 		sun4c_vacinfo.num_bytes,
 		(sun4c_vacinfo.do_hwflushes ? "yes" : "no"),
 		sun4c_vacinfo.linesize,
@@ -2255,22 +2074,7 @@
 		used_user_entries,
 		sun4c_ufree_ring.num_entries,
 		sun4c_user_taken_entries,
-		max_user_taken_entries,
-		ctxflushes, segflushes, pageflushes);
-
-#if KGPROF_PROFILING
-	{
-		int i,j;
-		len += sprintf(buf + len,"kgprof profiling:\n");
-		for (i=0;i<KGPROF_SIZE && kgprof_counters[i].addr[0];i++) {
-			len += sprintf(buf + len,"%5d  ",kgprof_counters[i].count);
-			for (j=0;j<KGPROF_DEPTH;j++) {
-				len += sprintf(buf + len,"%08x ",kgprof_counters[i].addr[j]);
-			}
-			len += sprintf(buf + len,"\n");
-		}
-	}
-#endif
+		max_user_taken_entries);
 
 	return len;
 }
@@ -2279,13 +2083,6 @@
  * data structures.
  */
 
-#if 0 /* Not used due to BTFIXUPs */
-static unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); }
-#endif
-#if 0 /* Not used due to BTFIXUPs */
-static unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); }
-#endif
-
 /* First the functions which the mid-level code uses to directly
  * manipulate the software page tables.  Some defines since we are
  * emulating the i386 page directory layout.
@@ -2297,17 +2094,6 @@
 #define PGD_DIRTY    0x040
 #define PGD_TABLE    (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY)
 
-#if 0 /* Not used due to BTFIXUPs */
-static unsigned long sun4c_vmalloc_start(void)
-{
-	return SUN4C_VMALLOC_START;
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static int sun4c_pte_none(pte_t pte)		{ return !pte_val(pte); }
-#endif
-
 static int sun4c_pte_present(pte_t pte)
 {
 	return ((pte_val(pte) & (_SUN4C_PAGE_PRESENT | _SUN4C_PAGE_PRIV)) != 0);
@@ -2336,48 +2122,6 @@
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-#if 0 /* Not used due to BTFIXUPs */
-static int sun4c_pte_write(pte_t pte)
-{
-	return pte_val(pte) & _SUN4C_PAGE_WRITE;
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static int sun4c_pte_dirty(pte_t pte)
-{
-	return pte_val(pte) & _SUN4C_PAGE_MODIFIED;
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static int sun4c_pte_young(pte_t pte)
-{
-	return pte_val(pte) & _SUN4C_PAGE_ACCESSED;
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static pte_t sun4c_pte_wrprotect(pte_t pte)
-{
-	return __pte(pte_val(pte) & ~(_SUN4C_PAGE_WRITE | _SUN4C_PAGE_SILENT_WRITE));
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static pte_t sun4c_pte_mkclean(pte_t pte)
-{
-	return __pte(pte_val(pte) & ~(_SUN4C_PAGE_MODIFIED | _SUN4C_PAGE_SILENT_WRITE));
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static pte_t sun4c_pte_mkold(pte_t pte)
-{
-	return __pte(pte_val(pte) & ~(_SUN4C_PAGE_ACCESSED | _SUN4C_PAGE_SILENT_READ));
-}
-#endif
-
 static pte_t sun4c_pte_mkwrite(pte_t pte)
 {
 	pte = __pte(pte_val(pte) | _SUN4C_PAGE_WRITE);
@@ -2421,14 +2165,6 @@
 	return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
 }
 
-#if 0 /* Not used due to BTFIXUPs */
-static pte_t sun4c_pte_modify(pte_t pte, pgprot_t newprot)
-{
-	return __pte((pte_val(pte) & _SUN4C_PAGE_CHG_MASK) |
-		     pgprot_val(newprot));
-}
-#endif
-
 static unsigned long sun4c_pte_page(pte_t pte)
 {
 	return (PAGE_OFFSET + ((pte_val(pte) & SUN4C_PFN_MASK) << (PAGE_SHIFT)));
@@ -2489,7 +2225,7 @@
 
 static pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
 {
-	if(address >= SUN4C_LOCK_VADDR)
+	if (address >= SUN4C_LOCK_VADDR)
 		return NULL;
 	address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
 	if (sun4c_pmd_none(*pmd))
@@ -2529,7 +2265,7 @@
 {
 	unsigned long *ret;
 
-	if((ret = pgd_quicklist) != NULL) {
+	if ((ret = pgd_quicklist) != NULL) {
 		pgd_quicklist = (unsigned long *)(*ret);
 		ret[0] = ret[1];
 		pgtable_cache_size--;
@@ -2548,15 +2284,15 @@
 static int sun4c_check_pgt_cache(int low, int high)
 {
 	int freed = 0;
-	if(pgtable_cache_size > high) {
+	if (pgtable_cache_size > high) {
 		do {
-			if(pgd_quicklist)
+			if (pgd_quicklist)
 				free_pgd_slow(get_pgd_fast()), freed++;
-			if(pmd_quicklist)
+			if (pmd_quicklist)
 				free_pmd_slow(get_pmd_fast()), freed++;
-			if(pte_quicklist)
+			if (pte_quicklist)
 				free_pte_slow(get_pte_fast()), freed++;
-		} while(pgtable_cache_size > low);
+		} while (pgtable_cache_size > low);
 	}
 	return freed;
 }
@@ -2577,7 +2313,7 @@
 {
 	unsigned long *ret;
 
-	if((ret = (unsigned long *)pte_quicklist) != NULL) {
+	if ((ret = (unsigned long *)pte_quicklist) != NULL) {
 		pte_quicklist = (unsigned long *)(*ret);
 		ret[0] = ret[1];
 		pgtable_cache_size--;
@@ -2680,9 +2416,9 @@
 
 	if (vma->vm_file)
 		dentry = vma->vm_file->f_dentry;
-	if(dentry)
+	if (dentry)
 		inode = dentry->d_inode;
-	if(inode) {
+	if (inode) {
 		unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
 		struct vm_area_struct *vmaring = inode->i_mmap; 
 		int alias_found = 0;
@@ -2691,19 +2427,21 @@
 			unsigned long start;
 
 			/* Do not mistake ourselves as another mapping. */
-			if(vmaring == vma)
+			if (vmaring == vma)
 				continue;
 
 			if (S4CVAC_BADALIAS(vaddr, address)) {
 				alias_found++;
 				start = vmaring->vm_start;
-				while(start < vmaring->vm_end) {
+				while (start < vmaring->vm_end) {
 					pgdp = sun4c_pgd_offset(vmaring->vm_mm, start);
-					if(!pgdp) goto next;
+					if (!pgdp)
+						goto next;
 					ptep = sun4c_pte_offset((pmd_t *) pgdp, start);
-					if(!ptep) goto next;
+					if (!ptep)
+						goto next;
 
-					if(pte_val(*ptep) & _SUN4C_PAGE_PRESENT) {
+					if (pte_val(*ptep) & _SUN4C_PAGE_PRESENT) {
 						flush_cache_page(vmaring, start);
 						*ptep = __pte(pte_val(*ptep) |
 							      _SUN4C_PAGE_NOCACHE);
@@ -2715,7 +2453,7 @@
 			}
 		} while ((vmaring = vmaring->vm_next_share) != NULL);
 
-		if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
+		if (alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
 			pgdp = sun4c_pgd_offset(vma->vm_mm, address);
 			ptep = sun4c_pte_offset((pmd_t *) pgdp, address);
 			*ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_NOCACHE);
@@ -2724,16 +2462,62 @@
 	}
 }
 
+/* An experiment, turn off by default for now... -DaveM */
+#define SUN4C_PRELOAD_PSEG
+
 void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
 	unsigned long flags;
+	int pseg;
 
 	save_and_cli(flags);
 	address &= PAGE_MASK;
-	if(sun4c_get_segmap(address) == invalid_segment)
-		alloc_user_segment(address, sun4c_get_context());
+	if ((pseg = sun4c_get_segmap(address)) == invalid_segment) {
+		struct sun4c_mmu_entry *entry = sun4c_user_strategy();
+		struct mm_struct *mm = vma->vm_mm;
+		unsigned long start, end;
+
+		entry->vaddr = start = (address & SUN4C_REAL_PGDIR_MASK);
+		entry->ctx = mm->context;
+		add_ring_ordered(sun4c_context_ring + mm->context, entry);
+		sun4c_put_segmap(entry->vaddr, entry->pseg);
+		end = start + SUN4C_REAL_PGDIR_SIZE;
+		while (start < end) {
+#ifdef SUN4C_PRELOAD_PSEG
+			pgd_t *pgdp = sun4c_pgd_offset(mm, start);
+			pte_t *ptep;
+
+			if (!pgdp)
+				goto no_mapping;
+			ptep = sun4c_pte_offset((pmd_t *) pgdp, start);
+			if (!ptep || !(pte_val(*ptep) & _SUN4C_PAGE_PRESENT))
+				goto no_mapping;
+			sun4c_put_pte(start, pte_val(*ptep));
+			goto next;
+
+		no_mapping:
+#endif
+			sun4c_put_pte(start, 0);
+#ifdef SUN4C_PRELOAD_PSEG
+		next:
+#endif
+			start += PAGE_SIZE;
+		}
+		if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
+			sun4c_vac_alias_fixup(vma, address, pte);
+#ifndef SUN4C_PRELOAD_PSEG
+		sun4c_put_pte(address, pte_val(pte));
+#endif
+		restore_flags(flags);
+		return;
+	} else {
+		struct sun4c_mmu_entry *entry = &mmu_entry_pool[pseg];
+
+		remove_lru(entry);
+		add_lru(entry);
+	}
 
-	if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
+	if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
 		sun4c_vac_alias_fixup(vma, address, pte);
 
 	sun4c_put_pte(address, pte_val(pte));
@@ -2786,8 +2570,8 @@
 	start_mem = sparc_context_init(start_mem, num_contexts);
 	start_mem = free_area_init(start_mem, end_mem);
 	cnt = 0;
-	for(i = 0; i < num_segmaps; i++)
-		if(mmu_entry_pool[i].locked)
+	for (i = 0; i < num_segmaps; i++)
+		if (mmu_entry_pool[i].locked)
 			cnt++;
 
 	max_user_taken_entries = num_segmaps - cnt - 40 - 1;
@@ -2839,7 +2623,7 @@
 
 	BTFIXUPSET_CALL(flush_cache_all, sun4c_flush_cache_all, BTFIXUPCALL_NORM);
 
-	if(sun4c_vacinfo.do_hwflushes) {
+	if (sun4c_vacinfo.do_hwflushes) {
 		BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm_hw, BTFIXUPCALL_NORM);
 		BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range_hw, BTFIXUPCALL_NORM);
 		BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page_hw, BTFIXUPCALL_NORM);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/mm/swift.S linux.14p16/arch/sparc/mm/swift.S
--- linux.vanilla/arch/sparc/mm/swift.S	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/sparc/mm/swift.S	Thu Dec  9 15:34:22 1999
@@ -0,0 +1,274 @@
+/* $Id: swift.S,v 1.1.2.3 1999/10/14 01:00:17 davem Exp $
+ * swift.S: MicroSparc-II mmu/cache operations.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+#include <asm/psr.h>
+#include <asm/asi.h>
+#include <asm/page.h>
+#include <asm/pgtsrmmu.h>
+#include <asm/asm_offsets.h>
+
+#define WINDOW_FLUSH(tmp1, tmp2)					\
+	mov	0, tmp1;						\
+98:	ld	[%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2;	\
+	orcc	%g0, tmp2, %g0;						\
+	add	tmp1, 1, tmp1;						\
+	bne	98b;							\
+	 save	%sp, -64, %sp;						\
+99:	subcc	tmp1, 1, tmp1;						\
+	bne	99b;							\
+	 restore %g0, %g0, %g0;
+
+	.text
+	.align	4
+
+#if 1	/* XXX screw this, I can't get the VAC flushes working
+	 * XXX reliably... -DaveM
+	 */
+	.globl	swift_flush_cache_all, swift_flush_cache_mm
+	.globl	swift_flush_cache_range, swift_flush_cache_page
+	.globl	swift_flush_page_for_dma, swift_flush_chunk
+	.globl	swift_flush_page_to_ram
+
+swift_flush_cache_all:
+swift_flush_cache_mm:
+swift_flush_cache_range:
+swift_flush_cache_page:
+swift_flush_page_for_dma:
+swift_flush_chunk:
+swift_flush_page_to_ram:
+	sethi	%hi(0x2000), %o0
+1:	subcc	%o0, 0x10, %o0
+	sta	%g0, [%o0] ASI_M_TXTC_TAG
+	sta	%g0, [%o0] ASI_M_DATAC_TAG
+	bne	1b
+	 nop
+	retl
+	 nop
+#else
+
+	.globl	swift_flush_cache_all
+swift_flush_cache_all:
+	WINDOW_FLUSH(%g4, %g5)
+
+	/* Just clear out all the tags. */
+	sethi	%hi(16 * 1024), %o0
+1:	subcc	%o0, 16, %o0
+	sta	%g0, [%o0] ASI_M_TXTC_TAG
+	bne	1b
+	 sta	%g0, [%o0] ASI_M_DATAC_TAG
+	retl
+	 nop
+
+	.globl	swift_flush_cache_mm
+swift_flush_cache_mm:
+#ifndef __SMP__
+	ld	[%o0 + AOFF_mm_context], %g2
+	cmp	%g2, -1
+	be	swift_flush_cache_mm_out
+#endif
+	WINDOW_FLUSH(%g4, %g5)
+	rd	%psr, %g1
+	andn	%g1, PSR_ET, %g3
+	wr	%g3, 0x0, %psr
+	nop
+	nop
+	mov	SRMMU_CTX_REG, %g7
+	lda	[%g7] ASI_M_MMUREGS, %g5
+	sta	%g2, [%g7] ASI_M_MMUREGS
+
+#if 1
+	sethi	%hi(0x2000), %o0
+1:	subcc	%o0, 0x10, %o0
+	sta	%g0, [%o0] ASI_M_FLUSH_CTX
+	bne	1b
+	 nop
+#else
+	clr	%o0
+	or	%g0, 2048, %g7
+	or	%g0, 2048, %o1
+	add	%o1, 2048, %o2
+	add	%o2, 2048, %o3
+	mov	16, %o4
+	add	%o4, 2048, %o5
+	add	%o5, 2048, %g2
+	add	%g2, 2048, %g3
+1:	sta	%g0, [%o0      ] ASI_M_FLUSH_CTX
+	sta	%g0, [%o0 + %o1] ASI_M_FLUSH_CTX
+	sta	%g0, [%o0 + %o2] ASI_M_FLUSH_CTX
+	sta	%g0, [%o0 + %o3] ASI_M_FLUSH_CTX
+	sta	%g0, [%o0 + %o4] ASI_M_FLUSH_CTX
+	sta	%g0, [%o0 + %o5] ASI_M_FLUSH_CTX
+	sta	%g0, [%o0 + %g2] ASI_M_FLUSH_CTX
+	sta	%g0, [%o0 + %g3] ASI_M_FLUSH_CTX
+	subcc	%g7, 32, %g7
+	bne	1b
+	 add	%o0, 32, %o0
+#endif
+
+	mov	SRMMU_CTX_REG, %g7
+	sta	%g5, [%g7] ASI_M_MMUREGS
+	wr	%g1, 0x0, %psr
+	nop
+	nop
+swift_flush_cache_mm_out:
+	retl
+	 nop
+
+	.globl	swift_flush_cache_range
+swift_flush_cache_range:
+	sub	%o2, %o1, %o2
+	sethi	%hi(4096), %o3
+	cmp	%o2, %o3
+	bgu	swift_flush_cache_mm
+	 nop
+	b	70f
+	 nop
+
+	.globl	swift_flush_cache_page
+swift_flush_cache_page:
+	ld	[%o0 + 0x0], %o0		/* XXX vma->vm_mm, GROSS XXX */
+70:
+#ifndef __SMP__
+	ld	[%o0 + AOFF_mm_context], %g2
+	cmp	%g2, -1
+	be	swift_flush_cache_page_out
+#endif
+	WINDOW_FLUSH(%g4, %g5)
+	rd	%psr, %g1
+	andn	%g1, PSR_ET, %g3
+	wr	%g3, 0x0, %psr
+	nop
+	nop
+	mov	SRMMU_CTX_REG, %g7
+	lda	[%g7] ASI_M_MMUREGS, %g5
+	sta	%g2, [%g7] ASI_M_MMUREGS
+
+	andn	%o1, (PAGE_SIZE - 1), %o1
+#if 1
+	sethi	%hi(0x1000), %o0
+1:	subcc	%o0, 0x10, %o0
+	sta	%g0, [%o1 + %o0] ASI_M_FLUSH_PAGE
+	bne	1b
+	 nop
+#else
+	or	%g0, 512, %g7
+	or	%g0, 512, %o0
+	add	%o0, 512, %o2
+	add	%o2, 512, %o3
+	add	%o3, 512, %o4
+	add	%o4, 512, %o5
+	add	%o5, 512, %g3
+	add	%g3, 512, %g4
+1:	sta	%g0, [%o1      ] ASI_M_FLUSH_PAGE
+	sta	%g0, [%o1 + %o0] ASI_M_FLUSH_PAGE
+	sta	%g0, [%o1 + %o2] ASI_M_FLUSH_PAGE
+	sta	%g0, [%o1 + %o3] ASI_M_FLUSH_PAGE
+	sta	%g0, [%o1 + %o4] ASI_M_FLUSH_PAGE
+	sta	%g0, [%o1 + %o5] ASI_M_FLUSH_PAGE
+	sta	%g0, [%o1 + %g3] ASI_M_FLUSH_PAGE
+	sta	%g0, [%o1 + %g4] ASI_M_FLUSH_PAGE
+	subcc	%g7, 16, %g7
+	bne	1b
+	 add	%o1, 16, %o1
+#endif
+
+	mov	SRMMU_CTX_REG, %g7
+	sta	%g5, [%g7] ASI_M_MMUREGS
+	wr	%g1, 0x0, %psr
+	nop
+	nop
+swift_flush_cache_page_out:
+	retl
+	 nop
+
+	/* Swift is write-thru, however it is not
+	 * I/O nor TLB-walk coherent.  Also it has
+	 * caches which are virtually indexed and tagged.
+	 */
+	.globl	swift_flush_page_for_dma
+	.globl	swift_flush_chunk
+	.globl	swift_flush_page_to_ram
+swift_flush_page_for_dma:
+swift_flush_chunk:
+swift_flush_page_to_ram:
+	andn	%o0, (PAGE_SIZE - 1), %o1
+#if 1
+	sethi	%hi(0x1000), %o0
+1:	subcc	%o0, 0x10, %o0
+	sta	%g0, [%o1 + %o0] ASI_M_FLUSH_PAGE
+	bne	1b
+	 nop
+#else
+	or	%g0, 512, %g7
+	or	%g0, 512, %o0
+	add	%o0, 512, %o2
+	add	%o2, 512, %o3
+	add	%o3, 512, %o4
+	add	%o4, 512, %o5
+	add	%o5, 512, %g3
+	add	%g3, 512, %g4
+1:	sta	%g0, [%o1      ] ASI_M_FLUSH_PAGE
+	sta	%g0, [%o1 + %o0] ASI_M_FLUSH_PAGE
+	sta	%g0, [%o1 + %o2] ASI_M_FLUSH_PAGE
+	sta	%g0, [%o1 + %o3] ASI_M_FLUSH_PAGE
+	sta	%g0, [%o1 + %o4] ASI_M_FLUSH_PAGE
+	sta	%g0, [%o1 + %o5] ASI_M_FLUSH_PAGE
+	sta	%g0, [%o1 + %g3] ASI_M_FLUSH_PAGE
+	sta	%g0, [%o1 + %g4] ASI_M_FLUSH_PAGE
+	subcc	%g7, 16, %g7
+	bne	1b
+	 add	%o1, 16, %o1
+#endif
+	retl
+	 nop
+#endif
+
+	.globl	swift_flush_sig_insns
+swift_flush_sig_insns:
+	flush	%o1
+	retl
+	 flush	%o1 + 4
+
+	.globl	swift_flush_tlb_mm
+	.globl	swift_flush_tlb_range
+	.globl	swift_flush_tlb_all
+swift_flush_tlb_mm:
+swift_flush_tlb_range:
+#ifndef __SMP__
+	ld	[%o0 + AOFF_mm_context], %g2
+	cmp	%g2, -1
+	be	swift_flush_tlb_all_out
+#endif
+swift_flush_tlb_all:
+	mov	0x400, %o1
+	sta	%g0, [%o1] ASI_M_FLUSH_PROBE
+swift_flush_tlb_all_out:
+	retl
+	 nop
+
+	.globl	swift_flush_tlb_page
+swift_flush_tlb_page:
+	ld	[%o0 + 0x00], %o0	/* XXX vma->vm_mm GROSS XXX */
+	mov	SRMMU_CTX_REG, %g1
+	ld	[%o0 + AOFF_mm_context], %o3
+	andn	%o1, (PAGE_SIZE - 1), %o1
+#ifndef __SMP__
+	cmp	%o3, -1
+	be	swift_flush_tlb_page_out
+	 nop
+#endif
+#if 1
+	mov	0x400, %o1
+	sta	%g0, [%o1] ASI_M_FLUSH_PROBE	
+#else
+	lda	[%g1] ASI_M_MMUREGS, %g5
+	sta	%o3, [%g1] ASI_M_MMUREGS
+	sta	%g0, [%o1] ASI_M_FLUSH_PROBE
+	sta	%g5, [%g1] ASI_M_MMUREGS
+#endif
+swift_flush_tlb_page_out:
+	retl
+	 nop
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/mm/tsunami.S linux.14p16/arch/sparc/mm/tsunami.S
--- linux.vanilla/arch/sparc/mm/tsunami.S	Sat Aug 14 02:27:15 1999
+++ linux.14p16/arch/sparc/mm/tsunami.S	Thu Dec  9 15:34:21 1999
@@ -1,4 +1,4 @@
-/* $Id: tsunami.S,v 1.1.6.1 1999/08/09 13:00:16 davem Exp $
+/* $Id: tsunami.S,v 1.1.6.3 1999/10/06 15:36:38 davem Exp $
  * tsunami.S: High speed MicroSparc-I mmu/cache operations.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -44,11 +44,11 @@
 tsunami_flush_cache_all:
 	WINDOW_FLUSH(%g4, %g5)
 tsunami_flush_page_for_dma:
-	sta	%g0, [%g0] ASI_M_DC_FLCLEAR
 	sta	%g0, [%g0] ASI_M_IC_FLCLEAR
+tsunami_flush_chunk:
+	sta	%g0, [%g0] ASI_M_DC_FLCLEAR
 tsunami_flush_cache_out:
 tsunami_flush_page_to_ram:
-tsunami_flush_chunk:
 	retl
 	 nop
 
@@ -98,3 +98,51 @@
 tsunami_flush_tlb_page_out:
 	retl
 	 sta	%g5, [%g1] ASI_M_MMUREGS
+
+#define MIRROR_BLOCK(dst, src, offset, t0, t1, t2, t3) \
+	ldd	[src + offset + 0x18], t0; \
+	std	t0, [dst + offset + 0x18]; \
+	ldd	[src + offset + 0x10], t2; \
+	std	t2, [dst + offset + 0x10]; \
+	ldd	[src + offset + 0x08], t0; \
+	std	t0, [dst + offset + 0x08]; \
+	ldd	[src + offset + 0x00], t2; \
+	std	t2, [dst + offset + 0x00];
+
+	.globl	tsunami_copy_1page
+tsunami_copy_1page:
+/* NOTE: This routine has to be shorter than 70insns --jj */
+	or	%g0, (PAGE_SIZE >> 8), %g1
+1:
+	MIRROR_BLOCK(%o0, %o1, 0x00, %o2, %o3, %o4, %o5)
+	MIRROR_BLOCK(%o0, %o1, 0x20, %o2, %o3, %o4, %o5)
+	MIRROR_BLOCK(%o0, %o1, 0x40, %o2, %o3, %o4, %o5)
+	MIRROR_BLOCK(%o0, %o1, 0x60, %o2, %o3, %o4, %o5)
+	MIRROR_BLOCK(%o0, %o1, 0x80, %o2, %o3, %o4, %o5)
+	MIRROR_BLOCK(%o0, %o1, 0xa0, %o2, %o3, %o4, %o5)
+	MIRROR_BLOCK(%o0, %o1, 0xc0, %o2, %o3, %o4, %o5)
+	MIRROR_BLOCK(%o0, %o1, 0xe0, %o2, %o3, %o4, %o5)
+	subcc	%g1, 1, %g1
+	add	%o0, 0x100, %o0
+	bne	1b
+	 add	%o1, 0x100, %o1
+
+	.globl	tsunami_setup_blockops
+tsunami_setup_blockops:
+	sethi	%hi(__copy_1page), %o0
+	or	%o0, %lo(__copy_1page), %o0
+	sethi	%hi(tsunami_copy_1page), %o1
+	or	%o1, %lo(tsunami_copy_1page), %o1
+	sethi	%hi(tsunami_setup_blockops), %o2
+	or	%o2, %lo(tsunami_setup_blockops), %o2
+	ld	[%o1], %o4
+1:	add	%o1, 4, %o1
+	st	%o4, [%o0]
+	add	%o0, 4, %o0
+	cmp	%o1, %o2
+	bne	1b
+	ld	[%o1], %o4
+	sta	%g0, [%g0] ASI_M_IC_FLCLEAR
+	sta	%g0, [%g0] ASI_M_DC_FLCLEAR
+	retl
+	 nop
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/config.in linux.14p16/arch/sparc64/config.in
--- linux.vanilla/arch/sparc64/config.in	Wed Oct 20 01:12:34 1999
+++ linux.14p16/arch/sparc64/config.in	Thu Dec  9 15:34:35 1999
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.67.2.2 1999/09/22 11:37:42 jj Exp $
+# $Id: config.in,v 1.67.2.5 1999/10/19 16:49:37 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -169,7 +169,7 @@
 	    bool '   Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
 	    int  '   Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
 	  fi
-	  dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
+	  dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI
 	  if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then
 	    int  '  default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
 	    int  '  maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/defconfig linux.14p16/arch/sparc64/defconfig
--- linux.vanilla/arch/sparc64/defconfig	Wed Oct 20 01:12:34 1999
+++ linux.14p16/arch/sparc64/defconfig	Thu Dec  9 15:34:35 1999
@@ -27,7 +27,9 @@
 CONFIG_PROM_CONSOLE=y
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FB_PM2 is not set
+CONFIG_FB_PM2=y
+# CONFIG_FB_PM2_FIFO_DISCONNECT is not set
+CONFIG_FB_PM2_PCI=y
 # CONFIG_FB_MATROX is not set
 CONFIG_FB_ATY=y
 CONFIG_FB_SBUS=y
@@ -200,10 +202,10 @@
 CONFIG_SCSI_QLOGICPTI=m
 CONFIG_SCSI_AIC7XXX=y
 # CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
-# CONFIG_CMDS_PER_DEVICE is not set
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=5
-CONFIG_SCSI_NCR53C8XX=y
+CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
 CONFIG_SCSI_NCR53C8XX_SYNC=10
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/dtlb_backend.S linux.14p16/arch/sparc64/kernel/dtlb_backend.S
--- linux.vanilla/arch/sparc64/kernel/dtlb_backend.S	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/kernel/dtlb_backend.S	Thu Dec  9 15:34:36 1999
@@ -1,4 +1,4 @@
-/* $Id: dtlb_backend.S,v 1.7 1998/12/16 04:33:28 davem Exp $
+/* $Id: dtlb_backend.S,v 1.7.2.1 1999/12/05 10:41:57 davem Exp $
  * dtlb_backend.S: Back end to DTLB miss replacement strategy.
  *                 This is included directly into the trap table.
  *
@@ -10,7 +10,7 @@
 #define VPTE_SHIFT		(PAGE_SHIFT - 3)
 #define PMD_SHIFT		(23 - PAGE_SHIFT + 3)
 #define PGD_SHIFT		(34 - PAGE_SHIFT + 3)
-#define VPTE_BITS		(_PAGE_CP | _PAGE_P | _PAGE_W)
+#define VPTE_BITS		(_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
 
 /* Ways we can get here:
  *
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/ebus.c linux.14p16/arch/sparc64/kernel/ebus.c
--- linux.vanilla/arch/sparc64/kernel/ebus.c	Wed Oct 20 01:12:34 1999
+++ linux.14p16/arch/sparc64/kernel/ebus.c	Thu Dec  9 15:34:35 1999
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.36.2.3 1999/09/21 15:45:37 davem Exp $
+/* $Id: ebus.c,v 1.36.2.4 1999/11/08 23:25:45 davem Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -56,15 +56,15 @@
 	return mem;
 }
 
-__initfunc(void ebus_intmap_match(struct linux_ebus *ebus,
-				  struct linux_prom_registers *reg,
-				  int *interrupt))
+__initfunc(int ebus_intmap_match(struct linux_ebus *ebus,
+				 struct linux_prom_registers *reg,
+				 int *interrupt))
 {
 	unsigned int hi, lo, irq;
 	int i;
 
 	if (!ebus->num_ebus_intmap)
-		return;
+		return 0;
 
 	hi = reg->which_io & ebus->ebus_intmask.phys_hi;
 	lo = reg->phys_addr & ebus->ebus_intmask.phys_lo;
@@ -74,13 +74,10 @@
 		    (ebus->ebus_intmap[i].phys_lo == lo) &&
 		    (ebus->ebus_intmap[i].interrupt == irq)) {
 			*interrupt = ebus->ebus_intmap[i].cinterrupt;
-			return;
+			return 0;
 		}
 	}
-
-	prom_printf("ebus: IRQ [%08x.%08x.%08x] not found in interrupt-map\n",
-		    reg->which_io, reg->phys_addr, *interrupt);
-	prom_halt();
+	return -1;
 }
 
 __initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg,
@@ -132,9 +129,16 @@
 	} else {
 		dev->num_irqs = len / sizeof(irqs[0]);
 		for (i = 0; i < dev->num_irqs; i++) {
-			ebus_intmap_match(dev->bus, preg, &irqs[i]);
-			dev->irqs[i] = psycho_irq_build(dev->bus->parent,
-							dev->bus->self, irqs[i]);
+			if (ebus_intmap_match(dev->bus, preg, &irqs[i]) != -1) {
+				dev->irqs[i] = psycho_irq_build(dev->bus->parent,
+								dev->bus->self,
+								irqs[i]);
+			} else {
+				/* If we get a bogus interrupt property, just
+				 * record the raw value instead of punting.
+				 */
+				dev->irqs[i] = irqs[i];
+			}
 		}
 	}
 
@@ -186,9 +190,16 @@
 	} else {
 		dev->num_irqs = len / sizeof(irqs[0]);
 		for (i = 0; i < dev->num_irqs; i++) {
-			ebus_intmap_match(dev->bus, &regs[0], &irqs[i]);
-			dev->irqs[i] = psycho_irq_build(dev->bus->parent,
-							dev->bus->self, irqs[i]);
+			if (ebus_intmap_match(dev->bus, &regs[0], &irqs[i]) != -1) {
+				dev->irqs[i] = psycho_irq_build(dev->bus->parent,
+								dev->bus->self,
+								irqs[i]);
+			} else {
+				/* If we get a bogus interrupt property, just
+				 * record the raw value instead of punting.
+				 */
+				dev->irqs[i] = irqs[i];
+			}
 		}
 	}
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/entry.S linux.14p16/arch/sparc64/kernel/entry.S
--- linux.vanilla/arch/sparc64/kernel/entry.S	Wed Oct 20 01:12:34 1999
+++ linux.14p16/arch/sparc64/kernel/entry.S	Thu Dec  9 15:34:35 1999
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.103.2.2 1999/09/22 11:37:37 jj Exp $
+/* $Id: entry.S,v 1.103.2.4 1999/10/24 17:29:13 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -214,8 +214,8 @@
 	.align		32
 	.globl		do_ivec
 do_ivec:
-	wr		%g0, ASI_UDB_INTR_R, %asi
-	ldxa		[%g0 + 0x40] %asi, %g3
+	mov		0x40, %g3
+	ldxa		[%g3 + %g0] ASI_UDB_INTR_R, %g3
 	sethi		%hi(KERNBASE), %g4
 	cmp		%g3, %g4
 	bgeu,pn		%xcc, do_ivec_xcall
@@ -234,22 +234,25 @@
 
 	sllx		%g2, %g4, %g2
 	sllx		%g4, 2, %g4
-	lduw		[%g1 + %g4], %g5	/* g5 = irq_work(cpu, pil) */
+	lduw		[%g6 + %g4], %g5	/* g5 = irq_work(cpu, pil) */
 	stw		%g5, [%g3 + 0x00]	/* bucket->irq_chain = g5 */
-	stw		%g3, [%g1 + %g4]	/* irq_work(cpu, pil) = bucket */
+	stw		%g3, [%g6 + %g4]	/* irq_work(cpu, pil) = bucket */
 	wr		%g2, 0x0, %set_softint
 	retry
 do_ivec_xcall:
-	ldxa		[%g0 + 0x50] %asi, %g6
+	mov		0x50, %g1
 
+	ldxa		[%g1 + %g0] ASI_UDB_INTR_R, %g1
 	srl		%g3, 0, %g3
-	ldxa		[%g0 + 0x60] %asi, %g7
+	mov		0x60, %g7
+	ldxa		[%g7 + %g0] ASI_UDB_INTR_R, %g7
 	stxa		%g0, [%g0] ASI_INTR_RECEIVE
 	membar		#Sync
 	jmpl		%g3, %g0
 	 nop
+
 do_ivec_spurious:
-	stw		%g3, [%g1 + 0x00]	/* irq_work(cpu, 0) = bucket */
+	stw		%g3, [%g6 + 0x00]	/* irq_work(cpu, 0) = bucket */
 	rdpr		%pstate, %g5
 
 	wrpr		%g5, PSTATE_IG | PSTATE_AG, %pstate
@@ -260,6 +263,76 @@
 	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
+
+	.globl		save_alternate_globals
+save_alternate_globals: /* %o0 = save_area */
+	rdpr		%pstate, %o5
+	andn		%o5, PSTATE_IE, %o1
+	wrpr		%o1, PSTATE_AG, %pstate
+	stx		%g0, [%o0 + 0x00]
+	stx		%g1, [%o0 + 0x08]
+	stx		%g2, [%o0 + 0x10]
+	stx		%g3, [%o0 + 0x18]
+	stx		%g4, [%o0 + 0x20]
+	stx		%g5, [%o0 + 0x28]
+	stx		%g6, [%o0 + 0x30]
+	stx		%g7, [%o0 + 0x38]
+	wrpr		%o1, PSTATE_IG, %pstate
+	stx		%g0, [%o0 + 0x40]
+	stx		%g1, [%o0 + 0x48]
+	stx		%g2, [%o0 + 0x50]
+	stx		%g3, [%o0 + 0x58]
+	stx		%g4, [%o0 + 0x60]
+	stx		%g5, [%o0 + 0x68]
+	stx		%g6, [%o0 + 0x70]
+	stx		%g7, [%o0 + 0x78]
+	wrpr		%o1, PSTATE_MG, %pstate
+	stx		%g0, [%o0 + 0x80]
+	stx		%g1, [%o0 + 0x88]
+	stx		%g2, [%o0 + 0x90]
+	stx		%g3, [%o0 + 0x98]
+	stx		%g4, [%o0 + 0xa0]
+	stx		%g5, [%o0 + 0xa8]
+	stx		%g6, [%o0 + 0xb0]
+	stx		%g7, [%o0 + 0xb8]
+	wrpr		%o5, 0x0, %pstate
+	retl
+	 nop
+
+	.globl		restore_alternate_globals
+restore_alternate_globals: /* %o0 = save_area */
+	rdpr		%pstate, %o5
+	andn		%o5, PSTATE_IE, %o1
+	wrpr		%o1, PSTATE_AG, %pstate
+	ldx		[%o0 + 0x00], %g0
+	ldx		[%o0 + 0x08], %g1
+	ldx		[%o0 + 0x10], %g2
+	ldx		[%o0 + 0x18], %g3
+	ldx		[%o0 + 0x20], %g4
+	ldx		[%o0 + 0x28], %g5
+	ldx		[%o0 + 0x30], %g6
+	ldx		[%o0 + 0x38], %g7
+	wrpr		%o1, PSTATE_IG, %pstate
+	ldx		[%o0 + 0x40], %g0
+	ldx		[%o0 + 0x48], %g1
+	ldx		[%o0 + 0x50], %g2
+	ldx		[%o0 + 0x58], %g3
+	ldx		[%o0 + 0x60], %g4
+	ldx		[%o0 + 0x68], %g5
+	ldx		[%o0 + 0x70], %g6
+	ldx		[%o0 + 0x78], %g7
+	wrpr		%o1, PSTATE_MG, %pstate
+	ldx		[%o0 + 0x80], %g0
+	ldx		[%o0 + 0x88], %g1
+	ldx		[%o0 + 0x90], %g2
+	ldx		[%o0 + 0x98], %g3
+	ldx		[%o0 + 0xa0], %g4
+	ldx		[%o0 + 0xa8], %g5
+	ldx		[%o0 + 0xb0], %g6
+	ldx		[%o0 + 0xb8], %g7
+	wrpr		%o5, 0x0, %pstate
+	retl
+	 nop
 
 	.globl		getcc, setcc
 getcc:
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/head.S linux.14p16/arch/sparc64/kernel/head.S
--- linux.vanilla/arch/sparc64/kernel/head.S	Wed Oct 20 01:12:34 1999
+++ linux.14p16/arch/sparc64/kernel/head.S	Thu Dec  9 15:34:35 1999
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.60.2.2 1999/08/19 01:11:12 davem Exp $
+/* $Id: head.S,v 1.60.2.4 1999/11/12 15:45:47 davem Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -52,7 +52,7 @@
 
         .ascii  "HdrS"
         .word   LINUX_VERSION_CODE
-        .half   0x0202          /* HdrS version */
+        .half   0x0203          /* HdrS version */
 root_flags:
         .half   1
 root_dev:
@@ -65,6 +65,7 @@
         .word   0
         .xword  reboot_command
 	.xword	bootstr_len
+	.word	_end
 
 	/* We must be careful, 32-bit OpenBOOT will get confused if it
 	 * tries to save away a register window to a 64-bit kernel
@@ -92,28 +93,6 @@
 	wrpr    %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
 	wr	%g0, 0, %fprs
 
-#ifdef __SMP__
-	/* Ugly but necessary... */
-	sethi	%hi(KERNBASE), %g7
-	sethi	%hi(sparc64_cpu_startup), %g5
-	or	%g5, %lo(sparc64_cpu_startup), %g5
-	sub	%g5, %g7, %g5
-	sethi	%hi(sparc64_cpu_startup_end), %g6
-	or	%g6, %lo(sparc64_cpu_startup_end), %g6
-	sub	%g6, %g7, %g6
-	sethi	%hi(smp_trampoline), %g3
-	or	%g3, %lo(smp_trampoline), %g3
-	sub	%g3, %g7, %g3
-1:	ldx	[%g5], %g1
-	stx	%g1, [%g3]
-	membar	#StoreStore
-	flush	%g3
-	add	%g5, 8, %g5
-	cmp	%g5, %g6
-	blu,pt	%xcc, 1b
-	 add	%g3, 8, %g3
-#endif
-
 create_mappings:
 	/* %g5 holds the tlb data */
         sethi   %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
@@ -379,7 +358,7 @@
 	wrpr	%o1, (PSTATE_IG|PSTATE_IE), %pstate
 #ifndef __SMP__
 	sethi	%hi(__up_workvec), %g5
-	or	%g5, %lo(__up_workvec), %g1
+	or	%g5, %lo(__up_workvec), %g6
 #else
 	/* By definition of where we are, this is boot_cpu. */
 	sethi	%hi(cpu_data), %g5
@@ -403,7 +382,7 @@
 set_worklist:
 	sllx	%g1, 7, %g1
 	add	%g5, %g1, %g5
-	add	%g5, 64, %g1
+	add	%g5, 64, %g6
 #endif
 
 	/* Kill PROM timer */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/ioctl32.c linux.14p16/arch/sparc64/kernel/ioctl32.c
--- linux.vanilla/arch/sparc64/kernel/ioctl32.c	Wed Oct 20 01:12:34 1999
+++ linux.14p16/arch/sparc64/kernel/ioctl32.c	Thu Dec  9 15:34:35 1999
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.62.2.4 1999/09/22 17:06:56 jj Exp $
+/* $Id: ioctl32.c,v 1.62.2.8 1999/11/16 23:59:31 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -17,7 +17,6 @@
 #include <linux/if.h>
 #include <linux/malloc.h>
 #include <linux/hdreg.h>
-#include <linux/raid/md.h>
 #include <linux/kd.h>
 #include <linux/route.h>
 #include <linux/skbuff.h>
@@ -1699,9 +1698,9 @@
 	int error = -EBADF;
 
 	lock_kernel();
-	filp = fcheck(fd);
+	filp = fget(fd);
 	if(!filp)
-		goto out;
+		goto out2;
 
 	if (!filp->f_op || !filp->f_op->ioctl) {
 		error = sys_ioctl (fd, cmd, arg);
@@ -1920,6 +1919,9 @@
 	case TIOCSCTTY:
 	case TIOCGPTN:
 	case TIOCSPTLCK:
+	case TIOCGSERIAL:
+	case TIOCSSERIAL:
+	case TIOCSERGETLSR:
 	
 	/* Big F */
 	case FBIOGTYPE:
@@ -1995,23 +1997,23 @@
 	case BLKRASET:
 	
 	/* 0x09 */
-	case RAID_VERSION:
-	case GET_ARRAY_INFO:
-	case GET_DISK_INFO:
-	case CLEAR_ARRAY:
-	case ADD_NEW_DISK:
-	case HOT_REMOVE_DISK:
-	case SET_ARRAY_INFO:
-	case SET_DISK_INFO:
-	case WRITE_RAID_INFO:
-	case UNPROTECT_ARRAY:
-	case PROTECT_ARRAY:
-	case HOT_ADD_DISK:
-	case RUN_ARRAY:
-	case START_ARRAY:
-	case STOP_ARRAY:
-	case STOP_ARRAY_RO:
-	case RESTART_ARRAY_RW:
+	case /* RAID_VERSION */		_IOR (MD_MAJOR, 0x10, char[12]):
+	case /* GET_ARRAY_INFO */	_IOR (MD_MAJOR, 0x11, char[72]):
+	case /* GET_DISK_INFO */	_IOR (MD_MAJOR, 0x12, char[20]):
+	case /* CLEAR_ARRAY */		_IO (MD_MAJOR, 0x20):
+	case /* ADD_NEW_DISK */		_IOW (MD_MAJOR, 0x21, char[20]):
+	case /* HOT_REMOVE_DISK */	_IO (MD_MAJOR, 0x22):
+	case /* SET_ARRAY_INFO */	_IOW (MD_MAJOR, 0x23, char[72]):
+	case /* SET_DISK_INFO */	_IO (MD_MAJOR, 0x24):
+	case /* WRITE_RAID_INFO */	_IO (MD_MAJOR, 0x25):
+	case /* UNPROTECT_ARRAY */	_IO (MD_MAJOR, 0x26):
+	case /* PROTECT_ARRAY */	_IO (MD_MAJOR, 0x27):
+	case /* HOT_ADD_DISK */		_IO (MD_MAJOR, 0x28):
+	case /* RUN_ARRAY */		_IOW (MD_MAJOR, 0x30, char[12]):
+	case /* START_ARRAY */		_IO (MD_MAJOR, 0x31):
+	case /* STOP_ARRAY */		_IO (MD_MAJOR, 0x32):
+	case /* STOP_ARRAY_RO */	_IO (MD_MAJOR, 0x33):
+	case /* RESTART_ARRAY_RW */	_IO (MD_MAJOR, 0x34):
 
 	/* Big K */
 	case PIO_FONT:
@@ -2219,6 +2221,9 @@
 	case CDROM_DRIVE_STATUS:
 	case CDROM_DISC_STATUS:
 	case CDROM_CHANGER_NSLOTS:
+	case CDROM_LOCKDOOR:
+	case CDROM_DEBUG:
+	case CDROM_GET_CAPABILITY:
 	
 	/* Big L */
 	case LOOP_SET_FD:
@@ -2385,6 +2390,10 @@
 	case AUTOFS_IOC_PROTOVER:
 	case AUTOFS_IOC_EXPIRE:
 	
+	/* Raw devices */
+	case _IO(0xac, 0): /* RAW_SETBIND */
+	case _IO(0xac, 1): /* RAW_GETBIND */
+
 		error = sys_ioctl (fd, cmd, arg);
 		goto out;
 
@@ -2397,9 +2406,11 @@
 				       (int)fd, (unsigned int)cmd, (unsigned int)arg);
 		} while(0);
 		error = -EINVAL;
-		break;
+		goto out;
 	}
 out:
+	fput(filp);
+out2:
 	unlock_kernel();
 	return error;
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/irq.c linux.14p16/arch/sparc64/kernel/irq.c
--- linux.vanilla/arch/sparc64/kernel/irq.c	Sat Aug 14 02:25:55 1999
+++ linux.14p16/arch/sparc64/kernel/irq.c	Thu Dec  9 15:34:35 1999
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.76 1999/04/02 14:54:30 davem Exp $
+/* $Id: irq.c,v 1.76.2.1 1999/12/05 07:24:37 davem Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997  David S. Miller  (davem@caip.rutgers.edu)
@@ -825,10 +825,10 @@
 	int cpu = smp_processor_id();
 
 	printk("\n%s, CPU %d:\n", str, cpu);
-	printk("irq:  %d [%ld %ld]\n",
+	printk("irq:  %d [%u %u]\n",
 	       atomic_read(&global_irq_count),
 	       cpu_data[0].irq_count, cpu_data[1].irq_count);
-	printk("bh:   %d [%ld %ld]\n",
+	printk("bh:   %d [%u %u]\n",
 	       (spin_is_locked(&global_bh_count) ? 1 : 0),
 	       cpu_data[0].bh_count, cpu_data[1].bh_count);
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/process.c linux.14p16/arch/sparc64/kernel/process.c
--- linux.vanilla/arch/sparc64/kernel/process.c	Wed Oct 20 01:12:34 1999
+++ linux.14p16/arch/sparc64/kernel/process.c	Thu Dec  9 15:34:35 1999
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.92.2.2 1999/08/31 18:21:27 davem Exp $
+/*  $Id: process.c,v 1.92.2.3 1999/12/05 07:24:38 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -277,7 +277,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&regdump_lock, flags);
-	printk("CPU[%d]: local_irq_count[%ld] global_irq_count[%d]\n",
+	printk("CPU[%d]: local_irq_count[%u] global_irq_count[%d]\n",
 	       smp_processor_id(), local_irq_count,
 	       atomic_read(&global_irq_count));
 #endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/psycho.c linux.14p16/arch/sparc64/kernel/psycho.c
--- linux.vanilla/arch/sparc64/kernel/psycho.c	Sat Aug 14 02:27:15 1999
+++ linux.14p16/arch/sparc64/kernel/psycho.c	Thu Dec  9 15:34:35 1999
@@ -1,4 +1,4 @@
-/* $Id: psycho.c,v 1.85.2.2 1999/08/09 13:00:21 davem Exp $
+/* $Id: psycho.c,v 1.85.2.5 1999/10/28 02:28:38 davem Exp $
  * psycho.c: Ultra/AX U2P PCI controller support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
@@ -221,15 +221,12 @@
 	control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
 	switch(tsbsize) {
 	case 8:
-		pci_dvma_mask = 0x1fffffffUL;
 		control |= IOMMU_TSBSZ_8K;
 		break;
 	case 16:
-		pci_dvma_mask = 0x3fffffffUL;
 		control |= IOMMU_TSBSZ_16K;
 		break;
 	case 32:
-		pci_dvma_mask = 0x7fffffffUL;
 		control |= IOMMU_TSBSZ_32K;
 		break;
 	default:
@@ -461,8 +458,19 @@
 
 		err = prom_getproperty(node, "model", namebuf, sizeof(namebuf));
 		if ((err > 0) && !strncmp(namebuf, "SUNW,sabre", err)) {
+			/* SABRE/APB is composed of a 4GB aligned 4GB
+			 * total PCI memory space.
+			 */
+			pci_dvma_mask = 0xffffffff;
+
 			sabre_init(node);
 			goto next_pci;
+		} else {
+			/* PSYCHO has two independant 4GB, 2GB aligned,
+			 * memory spaces, and the lower 2GB is the region
+			 * for all PCI memory space device mappings.
+			 */
+			pci_dvma_mask = 0x7fffffff;
 		}
 
 		portid = prom_getintdefault(node, "upa-portid", 0xff);
@@ -755,17 +763,18 @@
 {
 	struct pci_dev *pdev;
 	unsigned short stmp;
-	unsigned int itmp;
-	unsigned char btmp;
+#if 0
+	unsigned char sabre_latency_timer = 32;
 
 	for(pdev = pci_devices; pdev; pdev = pdev->next) {
 		if(pdev->vendor == PCI_VENDOR_ID_SUN &&
 		   pdev->device == PCI_DEVICE_ID_SUN_SABRE) {
-			pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
+			pci_read_config_byte(pdev, PCI_LATENCY_TIMER,
+					     &sabre_latency_timer);
 			break;
 		}
 	}
-
+#endif
 	for (pdev = sabre->pci_bus->devices; pdev; pdev = pdev->sibling) {
 		if (pdev->vendor == PCI_VENDOR_ID_SUN &&
 		    pdev->device == PCI_DEVICE_ID_SUN_SIMBA) {
@@ -778,52 +787,11 @@
 			/* Status register bits are "write 1 to clear". */
 			pci_write_config_word(pdev, PCI_STATUS, 0xffff);
 			pci_write_config_word(pdev, PCI_SEC_STATUS, 0xffff);
-
-			pci_read_config_word(pdev, PCI_BRIDGE_CONTROL, &stmp);
-			stmp = PCI_BRIDGE_CTL_MASTER_ABORT |
-			       PCI_BRIDGE_CTL_SERR |
-			       PCI_BRIDGE_CTL_PARITY;
-			pci_write_config_word(pdev, PCI_BRIDGE_CONTROL, stmp);
-
-			pci_read_config_dword(pdev, APB_PCI_CONTROL_HIGH, &itmp);
-			itmp = APB_PCI_CTL_HIGH_SERR |
-			       APB_PCI_CTL_HIGH_ARBITER_EN;
-			pci_write_config_dword(pdev, APB_PCI_CONTROL_HIGH, itmp);
-
-			/* Systems with SIMBA are usually workstations, so
-			 * we configure to park to SIMBA not to the previous
-			 * bus owner.
-			 */
-			pci_read_config_dword(pdev, APB_PCI_CONTROL_LOW, &itmp);
-			itmp = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f;
-			pci_write_config_dword(pdev, APB_PCI_CONTROL_LOW, itmp);
-
-			/* Don't mess with the retry limit and PIO/DMA latency
-			 * timer settings.  But do set primary and secondary
-			 * latency timers.
-			 */
-			pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
-			pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 64);
-
-			/* Here is an overview of the behavior of various
-			 * revisions of APB wrt. write buffer full conditions:
-			 *
-			 * Revision 1.0: pre-FCS, always stalls
-			 * Revision 1.1: pre-FCS, always disconnects
-			 * Revision 1.2: same behavior as rev 1.1
-			 * Revision 1.3: behavior is determined by bit 4 of
-			 *               secondary control register
-			 *		 0: stall initially, but disconnect
-			 *		    if PCI latency timer expires
-			 *		 1: always disconnect
-			 *
-			 * By setting the bit, since it is reserved in previous
-			 * revisions of APB, we get all FCS hardware to have
-			 * identical behavior when APB's write buffer fills up.
-			 */
-			pci_read_config_byte(pdev, APB_SECONDARY_CONTROL, &btmp);
-			btmp |= APB_SECONDARY_CTL_DISCON_FULL;
-			pci_write_config_byte(pdev, APB_SECONDARY_CONTROL, btmp);
+#if 0
+			/* Propagate Sabre latency timer value into APB. */
+			pci_write_config_byte(pdev, PCI_LATENCY_TIMER,
+					      sabre_latency_timer);
+#endif
 		}
 	}
 }
@@ -1958,6 +1926,12 @@
 	}
 
 	node = pcp->prom_node;
+
+	/* No need to crash if the PCI device lacks PROM
+	 * information.
+	 */
+	if (node == -1)
+		return;
 
 	err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
 	if(err == 0 || err == -1) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/ptrace.c linux.14p16/arch/sparc64/kernel/ptrace.c
--- linux.vanilla/arch/sparc64/kernel/ptrace.c	Wed Mar 24 23:10:28 1999
+++ linux.14p16/arch/sparc64/kernel/ptrace.c	Thu Dec  9 15:34:36 1999
@@ -40,6 +40,7 @@
 	pgd_t * pgdir;
 	pmd_t * pgmiddle;
 	pte_t * pgtable;
+	int fault;
 
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
@@ -50,8 +51,12 @@
 	current->mm->segments = (void *) (addr & PAGE_SIZE);
 
 	if (pgd_none(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, write);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, write);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return 0;
 	}
 	if (pgd_bad(*pgdir)) {
 		printk("ptrace: bad page directory %016lx\n", pgd_val(*pgdir));
@@ -60,8 +65,12 @@
 	}
 	pgmiddle = pmd_offset(pgdir, addr);
 	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, write);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, write);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return 0;
 	}
 	if (pmd_bad(*pgmiddle)) {
 		printk("ptrace: bad page middle %016lx\n", pmd_val(*pgmiddle));
@@ -70,12 +79,20 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, write);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, write);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return 0;
 	}
 	if (write && !pte_write(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, write);
-		goto repeat;
+		fault = handle_mm_fault(tsk, vma, addr, write);
+		if (fault > 0)
+			goto repeat;
+		if (fault < 0)
+			force_sig(SIGKILL, tsk);
+		return 0;
 	}
 	return pgtable;
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/setup.c linux.14p16/arch/sparc64/kernel/setup.c
--- linux.vanilla/arch/sparc64/kernel/setup.c	Sat Aug 14 02:26:47 1999
+++ linux.14p16/arch/sparc64/kernel/setup.c	Thu Dec  9 15:34:35 1999
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.43.2.1 1999/05/28 02:18:13 davem Exp $
+/*  $Id: setup.c,v 1.43.2.2 1999/10/24 17:29:20 davem Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -434,6 +434,17 @@
 
 extern struct consw sun_serial_con;
 
+void register_prom_callbacks(void)
+{
+	prom_setcallback(prom_callback);
+	prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; "
+		   "' linux-va>tte-data to va>tte-data");
+	prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; "
+		   "' linux-.soft1 to .soft1");
+	prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; "
+		   "' linux-.soft2 to .soft2");
+}
+
 __initfunc(void setup_arch(char **cmdline_p,
 	unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
@@ -478,13 +489,6 @@
 			}
 		}
 	}
-	prom_setcallback(prom_callback);
-	prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; "
-		   "' linux-va>tte-data to va>tte-data");
-	prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; "
-		   "' linux-.soft1 to .soft1");
-	prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; "
-		   "' linux-.soft2 to .soft2");
 
 	/* In paging_init() we tip off this value to see if we need
 	 * to change init_mm.pgd to point to the real alias mapping.
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/smp.c linux.14p16/arch/sparc64/kernel/smp.c
--- linux.vanilla/arch/sparc64/kernel/smp.c	Sat Aug 14 02:26:15 1999
+++ linux.14p16/arch/sparc64/kernel/smp.c	Thu Dec  9 15:34:36 1999
@@ -94,7 +94,8 @@
 	cpu_data[id].udelay_val			= loops_per_sec;
 
 	cpu_data[id].pgcache_size		= 0;
-	cpu_data[id].pte_cache			= NULL;
+	cpu_data[id].pte_cache[0]		= NULL;
+	cpu_data[id].pte_cache[1]		= NULL;
 	cpu_data[id].pgdcache_size		= 0;
 	cpu_data[id].pgd_cache			= NULL;
 	cpu_data[id].idle_volume		= 1;
@@ -180,7 +181,7 @@
 
 extern struct prom_cpuinfo linux_cpus[64];
 
-extern unsigned long smp_trampoline;
+extern unsigned long sparc64_cpu_startup;
 
 /* The OBP cpu startup callback truncates the 3rd arg cookie to
  * 32-bits (I think) so to be safe we have it read the pointer
@@ -206,15 +207,13 @@
 			continue;
 
 		if(cpu_present_map & (1UL << i)) {
-			unsigned long entry = (unsigned long)(&smp_trampoline);
+			unsigned long entry = (unsigned long)(&sparc64_cpu_startup);
 			unsigned long cookie = (unsigned long)(&cpu_new_task);
 			struct task_struct *p;
 			int timeout;
 			int no;
-			extern unsigned long phys_base;
 
-			entry += phys_base - KERNBASE;
-			cookie += phys_base - KERNBASE;
+			prom_printf("Starting CPU %d... ", i);
 			kernel_thread(start_secondary, NULL, CLONE_PID);
 			p = task[++cpucount];
 			p->processor = i;
@@ -235,9 +234,11 @@
 				cpu_number_map[i] = cpucount;
 				__cpu_logical_map[cpucount] = i;
 				prom_cpu_nodes[i] = linux_cpus[no].prom_node;
+				prom_printf("OK\n");
 			} else {
 				cpucount--;
 				printk("Processor %d is stuck.\n", i);
+				prom_printf("FAILED\n");
 			}
 		}
 		if(!callin_flag) {
@@ -536,14 +537,31 @@
 /* Imprisoned penguins run with %pil == 15, but PSTATE_IE set, so they
  * can service tlb flush xcalls...
  */
+extern void prom_world(int);
+extern void save_alternate_globals(unsigned long *);
+extern void restore_alternate_globals(unsigned long *);
 void smp_penguin_jailcell(void)
 {
-	flushw_user();
+	unsigned long global_save[24];
+
+	__asm__ __volatile__("flushw");
+	save_alternate_globals(global_save);
+	prom_world(1);
 	atomic_inc(&smp_capture_registry);
 	membar("#StoreLoad | #StoreStore");
 	while(penguins_are_doing_time)
 		membar("#LoadLoad");
+	restore_alternate_globals(global_save);
 	atomic_dec(&smp_capture_registry);
+	prom_world(0);
+}
+
+extern unsigned long xcall_promstop;
+
+void smp_promstop_others(void)
+{
+	if (smp_processors_ready)
+		smp_cross_call(&xcall_promstop, 0, 0, 0);
 }
 
 static inline void sparc64_do_profile(unsigned long pc)
@@ -774,7 +792,8 @@
 	       (int) cacheflush_time);
 }
 
-int __init setup_profiling_timer(unsigned int multiplier)
+/* /proc/profile writes can call this, don't __init it please. */
+int setup_profiling_timer(unsigned int multiplier)
 {
 	unsigned long flags;
 	int i;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/sys_sparc32.c linux.14p16/arch/sparc64/kernel/sys_sparc32.c
--- linux.vanilla/arch/sparc64/kernel/sys_sparc32.c	Sat Aug 14 02:26:47 1999
+++ linux.14p16/arch/sparc64/kernel/sys_sparc32.c	Thu Dec  9 15:34:35 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.107.2.1 1999/05/16 10:48:44 davem Exp $
+/* $Id: sys_sparc32.c,v 1.107.2.5 1999/11/12 11:17:47 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -44,6 +44,7 @@
 #include <linux/personality.h>
 #include <linux/stat.h>
 #include <linux/timex.h>
+#include <linux/filter.h>
 
 #include <asm/types.h>
 #include <asm/ipc.h>
@@ -1136,8 +1137,10 @@
 	}
 
 	ret = -EINVAL;
-	if (n < 0 || n > KFDS_NR)
+	if (n < 0)
 		goto out_nofds;
+	if (n > current->files->max_fdset)
+		n = current->files->max_fdset;
 
 	/*
 	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
@@ -1197,84 +1200,157 @@
 	return ret;
 }
 
-static inline int putstat(struct stat32 *ubuf, struct stat *kbuf)
+static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf)
 {
+	unsigned long ino, blksize, blocks;
+	kdev_t dev, rdev;
+	umode_t mode;
+	nlink_t nlink;
+	uid_t uid;
+	gid_t gid;
+	off_t size;
+	time_t atime, mtime, ctime;
 	int err;
-	
-	err = put_user (kbuf->st_dev, &ubuf->st_dev);
-	err |= __put_user (kbuf->st_ino, &ubuf->st_ino);
-	err |= __put_user (kbuf->st_mode, &ubuf->st_mode);
-	err |= __put_user (kbuf->st_nlink, &ubuf->st_nlink);
-	err |= __put_user (kbuf->st_uid, &ubuf->st_uid);
-	err |= __put_user (kbuf->st_gid, &ubuf->st_gid);
-	err |= __put_user (kbuf->st_rdev, &ubuf->st_rdev);
-	err |= __put_user (kbuf->st_size, &ubuf->st_size);
-	err |= __put_user (kbuf->st_atime, &ubuf->st_atime);
-	err |= __put_user (kbuf->st_mtime, &ubuf->st_mtime);
-	err |= __put_user (kbuf->st_ctime, &ubuf->st_ctime);
-	err |= __put_user (kbuf->st_blksize, &ubuf->st_blksize);
-	err |= __put_user (kbuf->st_blocks, &ubuf->st_blocks);
+
+	/* Stream the loads of inode data into the load buffer,
+	 * then we push it all into the store buffer below.  This
+	 * should give optimal cache performance.
+	 */
+	ino = inode->i_ino;
+	dev = inode->i_dev;
+	mode = inode->i_mode;
+	nlink = inode->i_nlink;
+	uid = inode->i_uid;
+	gid = inode->i_gid;
+	rdev = inode->i_rdev;
+	size = inode->i_size;
+	atime = inode->i_atime;
+	mtime = inode->i_mtime;
+	ctime = inode->i_ctime;
+	blksize = inode->i_blksize;
+	blocks = inode->i_blocks;
+
+	err  = put_user(kdev_t_to_nr(dev), &statbuf->st_dev);
+	err |= put_user(ino, &statbuf->st_ino);
+	err |= put_user(mode, &statbuf->st_mode);
+	err |= put_user(nlink, &statbuf->st_nlink);
+	err |= put_user(uid, &statbuf->st_uid);
+	err |= put_user(gid, &statbuf->st_gid);
+	err |= put_user(kdev_t_to_nr(rdev), &statbuf->st_rdev);
+	err |= put_user(size, &statbuf->st_size);
+	err |= put_user(atime, &statbuf->st_atime);
+	err |= put_user(0, &statbuf->__unused1);
+	err |= put_user(mtime, &statbuf->st_mtime);
+	err |= put_user(0, &statbuf->__unused2);
+	err |= put_user(ctime, &statbuf->st_ctime);
+	err |= put_user(0, &statbuf->__unused3);
+	if (blksize) {
+		err |= put_user(blksize, &statbuf->st_blksize);
+		err |= put_user(blocks, &statbuf->st_blocks);
+	} else {
+		unsigned int tmp_blocks;
+
+#define D_B   7
+#define I_B   (BLOCK_SIZE / sizeof(unsigned short))
+		tmp_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
+		if (tmp_blocks > D_B) {
+			unsigned int indirect;
+
+			indirect = (tmp_blocks - D_B + I_B - 1) / I_B;
+			tmp_blocks += indirect;
+			if (indirect > 1) {
+				indirect = (indirect - 1 + I_B - 1) / I_B;
+				tmp_blocks += indirect;
+				if (indirect > 1)
+					tmp_blocks++;
+			}
+		}
+		err |= put_user(BLOCK_SIZE, &statbuf->st_blksize);
+		err |= put_user((BLOCK_SIZE / 512) * tmp_blocks, &statbuf->st_blocks);
+#undef D_B
+#undef I_B
+	}
+	err |= put_user(0, &statbuf->__unused4[0]);
+	err |= put_user(0, &statbuf->__unused4[1]);
+
 	return err;
 }
 
-extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf);
-
 asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf)
 {
-	int ret;
-	struct stat s;
-	char *filenam;
-	mm_segment_t old_fs = get_fs();
-	
-	filenam = getname32 (filename);
-	ret = PTR_ERR(filenam);
-	if (!IS_ERR(filenam)) {
-		set_fs (KERNEL_DS);
-		ret = sys_newstat(filenam, &s);
-		set_fs (old_fs);
-		putname (filenam);
-		if (putstat (statbuf, &s))
-			return -EFAULT;
+	struct dentry *dentry;
+	int error;
+
+	lock_kernel();
+	dentry = namei(filename);
+
+	error = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		struct inode *inode = dentry->d_inode;
+
+		if (inode->i_op &&
+		    inode->i_op->revalidate)
+			error = inode->i_op->revalidate(dentry);
+		else
+			error = 0;
+		if (!error)
+			error = cp_new_stat32(inode, statbuf);
+
+		dput(dentry);
 	}
-	return ret;
+	unlock_kernel();
+	return error;
 }
 
-extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf);
-
 asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf)
 {
-	int ret;
-	struct stat s;
-	char *filenam;
-	mm_segment_t old_fs = get_fs();
-	
-	filenam = getname32 (filename);
-	ret = PTR_ERR(filenam);
-	if (!IS_ERR(filenam)) {
-		set_fs (KERNEL_DS);
-		ret = sys_newlstat(filenam, &s);
-		set_fs (old_fs);
-		putname (filenam);
-		if (putstat (statbuf, &s))
-			return -EFAULT;
+	struct dentry *dentry;
+	int error;
+
+	lock_kernel();
+	dentry = lnamei(filename);
+
+	error = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		struct inode *inode = dentry->d_inode;
+
+		if (inode->i_op &&
+		    inode->i_op->revalidate)
+			error = inode->i_op->revalidate(dentry);
+		else
+			error = 0;
+		if (!error)
+			error = cp_new_stat32(inode, statbuf);
+
+		dput(dentry);
 	}
-	return ret;
+	unlock_kernel();
+	return error;
 }
 
-extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf);
-
 asmlinkage int sys32_newfstat(unsigned int fd, struct stat32 *statbuf)
 {
-	int ret;
-	struct stat s;
-	mm_segment_t old_fs = get_fs();
-	
-	set_fs (KERNEL_DS);
-	ret = sys_newfstat(fd, &s);
-	set_fs (old_fs);
-	if (putstat (statbuf, &s))
-		return -EFAULT;
-	return ret;
+	struct file *f;
+	int err = -EBADF;
+
+	lock_kernel();
+	f = fget(fd);
+	if (f) {
+		struct dentry *dentry = f->f_dentry;
+		struct inode *inode = dentry->d_inode;
+
+		if (inode->i_op &&
+		    inode->i_op->revalidate)
+			err = inode->i_op->revalidate(dentry);
+		else
+			err = 0;
+		if (!err)
+			err = cp_new_stat32(inode, statbuf);
+
+		fput(f);
+	}
+	unlock_kernel();
+	return err;
 }
 
 extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
@@ -1677,7 +1753,7 @@
 siginfo_t32 *
 siginfo64to32(siginfo_t32 *d, siginfo_t *s)
 {
-	memset (&d, 0, sizeof(siginfo_t32));
+	memset (d, 0, sizeof(siginfo_t32));
 	d->si_signo = s->si_signo;
 	d->si_errno = s->si_errno;
 	d->si_code = s->si_code;
@@ -2581,6 +2657,48 @@
 	return len;
 }
 
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
+				     char *optval, int optlen);
+
+asmlinkage int sys32_setsockopt(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	if (optname == SO_ATTACH_FILTER) {
+		struct sock_fprog32 {
+			__u16 len;
+			__u32 filter;
+		} *fprog32 = (struct sock_fprog32 *)optval;
+		struct sock_fprog kfprog;
+		struct sock_filter *kfilter;
+		unsigned int fsize;
+		mm_segment_t old_fs;
+		__u32 uptr;
+		int ret;
+
+		if (get_user(kfprog.len, &fprog32->len) ||
+		    __get_user(uptr, &fprog32->filter))
+			return -EFAULT;
+		kfprog.filter = (struct sock_filter *)A(uptr);
+		fsize = kfprog.len * sizeof(struct sock_filter);
+		kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL);
+		if (kfilter == NULL)
+			return -ENOMEM;
+		if (copy_from_user(kfilter, kfprog.filter, fsize)) {
+			kfree(kfilter);
+			return -EFAULT;
+		}
+		kfprog.filter = kfilter;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		ret = sys_setsockopt(fd, level, optname,
+				     (char *)&kfprog, sizeof(kfprog));
+		set_fs(old_fs);
+		kfree(kfilter);
+		return ret;
+	}
+	return sys_setsockopt(fd, level, optname, optval, optlen);
+}
+
 /* Argument list sizes for sys_socketcall */
 #define AL(x) ((x) * sizeof(u32))
 static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
@@ -2599,8 +2717,6 @@
 extern asmlinkage int sys_recv(int fd, void *ubuf, size_t size, unsigned flags);
 extern asmlinkage int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size,
 				     unsigned flags, u32 addr, u32 addr_len);
-extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
-				     char *optval, int optlen);
 extern asmlinkage int sys32_getsockopt(int fd, int level, int optname,
 				       u32 optval, u32 optlen);
 
@@ -2651,7 +2767,7 @@
 		case SYS_SHUTDOWN:
 			return sys_shutdown(a0,a1);
 		case SYS_SETSOCKOPT:
-			return sys_setsockopt(a0, a1, a[2], (char *)A(a[3]), a[4]);
+			return sys32_setsockopt(a0, a1, a[2], (char *)A(a[3]), a[4]);
 		case SYS_GETSOCKOPT:
 			return sys32_getsockopt(a0, a1, a[2], a[3], a[4]);
 		case SYS_SENDMSG:
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/time.c linux.14p16/arch/sparc64/kernel/time.c
--- linux.vanilla/arch/sparc64/kernel/time.c	Tue Mar 16 00:10:43 1999
+++ linux.14p16/arch/sparc64/kernel/time.c	Thu Dec  9 15:34:36 1999
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.20 1999/03/15 22:13:40 davem Exp $
+/* $Id: time.c,v 1.20.2.1 1999/10/09 06:03:23 davem Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -47,7 +47,7 @@
  */
 unsigned long timer_tick_offset;
 static unsigned long timer_tick_compare;
-static unsigned long timer_ticks_per_usec;
+static unsigned long timer_ticks_per_usec_quotient;
 
 static __inline__ void timer_check_rtc(void)
 {
@@ -392,7 +392,7 @@
 
 	init_timers(timer_interrupt, &clock);
 	timer_tick_offset = clock / HZ;
-	timer_ticks_per_usec = clock / 1000000;
+	timer_ticks_per_usec_quotient = ((1UL<<32) / (clock / 1000020UL));
 }
 
 static __inline__ unsigned long do_gettimeoffset(void)
@@ -408,7 +408,7 @@
 		: "r" (timer_tick_offset), "r" (timer_tick_compare)
 		: "g1", "g2");
 
-	return ticks / timer_ticks_per_usec;
+	return (ticks * timer_ticks_per_usec_quotient) >> 32UL;
 }
 
 /* This need not obtain the xtime_lock as it is coded in
@@ -431,24 +431,22 @@
 	or	%g2, %lo(xtime), %g2
 	or	%g1, %lo(timer_tick_compare), %g1
 1:	ldda	[%g2] 0x24, %o4
-	membar	#LoadLoad | #MemIssue
 	rd	%tick, %o1
 	ldx	[%g1], %g7
-	membar	#LoadLoad | #MemIssue
 	ldda	[%g2] 0x24, %o2
-	membar	#LoadLoad
 	xor	%o4, %o2, %o2
 	xor	%o5, %o3, %o3
 	orcc	%o2, %o3, %g0
 	bne,pn	%xcc, 1b
 	 sethi	%hi(lost_ticks), %o2
-	sethi	%hi(timer_ticks_per_usec), %o3
+	sethi	%hi(timer_ticks_per_usec_quotient), %o3
 	ldx	[%o2 + %lo(lost_ticks)], %o2
 	add	%g3, %o1, %o1
-	ldx	[%o3 + %lo(timer_ticks_per_usec)], %o3
+	ldx	[%o3 + %lo(timer_ticks_per_usec_quotient)], %o3
 	sub	%o1, %g7, %o1
+	mulx	%o3, %o1, %o1
 	brz,pt	%o2, 1f
-	 udivx	%o1, %o3, %o1
+	 srlx	%o1, 32, %o1
 	sethi	%hi(10000), %g2
 	or	%g2, %lo(10000), %g2
 	add	%o1, %g2, %o1
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/trampoline.S linux.14p16/arch/sparc64/kernel/trampoline.S
--- linux.vanilla/arch/sparc64/kernel/trampoline.S	Wed Oct 20 01:12:34 1999
+++ linux.14p16/arch/sparc64/kernel/trampoline.S	Thu Dec  9 15:34:36 1999
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.8.2.2 1999/08/19 01:11:14 davem Exp $
+/* $Id: trampoline.S,v 1.8.2.4 1999/10/27 00:22:24 davem Exp $
  * trampoline.S: Jump start slave processors on sparc64.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -14,21 +14,107 @@
 #include <asm/asm_offsets.h>
 
 	.data
-	.align		8
-	.globl		smp_trampoline
-smp_trampoline:		.skip	0x300
+	.align	8
+call_method:
+	.asciz	"call-method"
+	.align	8
+itlb_load:
+	.asciz	"SUNW,itlb-load"
+	.align	8
+dtlb_load:
+	.asciz	"SUNW,dtlb-load"
 
 	.text
 	.align		8
 	.globl		sparc64_cpu_startup, sparc64_cpu_startup_end
 sparc64_cpu_startup:
 	flushw
+
 	mov	(LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1
 	stxa	%g1, [%g0] ASI_LSU_CONTROL
 	membar	#Sync
-	wrpr	%g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
-	wr	%g0, 0, %fprs
+
 	wrpr	%g0, 15, %pil
+	wr	%g0, 0, %tick_cmpr
+
+	/* Call OBP by hand to lock KERNBASE into i/d tlbs. */
+	mov	%o0, %l0
+
+	sethi	%hi(prom_entry_lock), %g2
+1:	ldstub	[%g2 + %lo(prom_entry_lock)], %g1
+	brnz,pn	%g1, 1b
+	 membar	#StoreLoad | #StoreStore
+
+	sethi	%hi(p1275buf), %g2
+	or	%g2, %lo(p1275buf), %g2
+	ldx	[%g2 + 0x10], %l2
+	mov	%sp, %l1
+	add	%l2, -(192 + 128), %sp
+	flushw
+
+	sethi	%hi(call_method), %g2
+	or	%g2, %lo(call_method), %g2
+	stx	%g2, [%sp + 2047 + 128 + 0x00]
+	mov	5, %g2
+	stx	%g2, [%sp + 2047 + 128 + 0x08]
+	mov	1, %g2
+	stx	%g2, [%sp + 2047 + 128 + 0x10]
+	sethi	%hi(itlb_load), %g2
+	or	%g2, %lo(itlb_load), %g2
+	stx	%g2, [%sp + 2047 + 128 + 0x18]
+	sethi	%hi(mmu_ihandle_cache), %g2
+	lduw	[%g2 + %lo(mmu_ihandle_cache)], %g2
+	stx	%g2, [%sp + 2047 + 128 + 0x20]
+	sethi	%hi(KERNBASE), %g2
+	stx	%g2, [%sp + 2047 + 128 + 0x28]
+	sethi	%hi(kern_locked_tte_data), %g2
+	ldx	[%g2 + %lo(kern_locked_tte_data)], %g2
+	stx	%g2, [%sp + 2047 + 128 + 0x30]
+	mov	63, %g2
+	stx	%g2, [%sp + 2047 + 128 + 0x38]
+	sethi	%hi(p1275buf), %g2
+	or	%g2, %lo(p1275buf), %g2
+	ldx	[%g2 + 0x08], %o1
+	call	%o1
+	 add	%sp, (2047 + 128), %o0
+
+	sethi	%hi(call_method), %g2
+	or	%g2, %lo(call_method), %g2
+	stx	%g2, [%sp + 2047 + 128 + 0x00]
+	mov	5, %g2
+	stx	%g2, [%sp + 2047 + 128 + 0x08]
+	mov	1, %g2
+	stx	%g2, [%sp + 2047 + 128 + 0x10]
+	sethi	%hi(dtlb_load), %g2
+	or	%g2, %lo(dtlb_load), %g2
+	stx	%g2, [%sp + 2047 + 128 + 0x18]
+	sethi	%hi(mmu_ihandle_cache), %g2
+	lduw	[%g2 + %lo(mmu_ihandle_cache)], %g2
+	stx	%g2, [%sp + 2047 + 128 + 0x20]
+	sethi	%hi(KERNBASE), %g2
+	stx	%g2, [%sp + 2047 + 128 + 0x28]
+	sethi	%hi(kern_locked_tte_data), %g2
+	ldx	[%g2 + %lo(kern_locked_tte_data)], %g2
+	stx	%g2, [%sp + 2047 + 128 + 0x30]
+	mov	63, %g2
+	stx	%g2, [%sp + 2047 + 128 + 0x38]
+	sethi	%hi(p1275buf), %g2
+	or	%g2, %lo(p1275buf), %g2
+	ldx	[%g2 + 0x08], %o1
+	call	%o1
+	 add	%sp, (2047 + 128), %o0
+
+	sethi	%hi(prom_entry_lock), %g2
+	stb	%g0, [%g2 + %lo(prom_entry_lock)]
+	membar	#StoreStore | #StoreLoad
+
+	mov	%l1, %sp
+	flushw
+
+	mov	%l0, %o0
+
+	wrpr	%g0, (PSTATE_PRIV | PSTATE_PEF), %pstate
+	wr	%g0, 0, %fprs
 
 	sethi	%uhi(PAGE_OFFSET), %g4
 	sllx	%g4, 32, %g4
@@ -37,99 +123,6 @@
 	srl	%o0, 0, %o0
 	ldx	[%o0], %g6
 
-	sethi	%uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
-	sllx	%g5, 32, %g5
-	or	%g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5
-
-	sethi	%uhi(_PAGE_PADDR), %g3
-	or	%g3, %ulo(_PAGE_PADDR), %g3
-	sllx	%g3, 32, %g3
-	sethi	%hi(_PAGE_PADDR), %g7
-	or	%g7, %lo(_PAGE_PADDR), %g7
-	or	%g3, %g7, %g3
-
-	clr	%l0
-	set	0x1fff, %l2
-	rd	%pc, %l3
-	andn	%l3, %l2, %g2
-1:	ldxa	[%l0] ASI_ITLB_TAG_READ, %g1
-	nop
-	nop
-	nop
-	andn	%g1, %l2, %g1
-	cmp	%g1, %g2
-	be,a,pn	%xcc, 2f
-	 ldxa	[%l0] ASI_ITLB_DATA_ACCESS, %g1
-	cmp	%l0, (63 << 3)
-	blu,pt	%xcc, 1b
-	 add	%l0, (1 << 3), %l0
-
-2:	nop
-	nop
-	nop
-	and	%g1, %g3, %g1
-	sub	%g1, %g2, %g1
-	or	%g5, %g1, %g5
-	clr	%l0
-	sethi	%hi(KERNBASE), %g3
-	sethi	%hi(KERNBASE<<1), %g7
-	mov	TLB_TAG_ACCESS, %l7
-1:	ldxa	[%l0] ASI_ITLB_TAG_READ, %g1
-	nop
-	nop
-	nop
-	andn	%g1, %l2, %g1
-	cmp	%g1, %g3
-	blu,pn	%xcc, 2f
-	 cmp	%g1, %g7
-	bgeu,pn	%xcc, 2f
-	 nop
-	stxa	%g0, [%l7] ASI_IMMU
-	stxa	%g0, [%l0] ASI_ITLB_DATA_ACCESS
-2:	cmp	%l0, (63 << 3)
-	blu,pt	%xcc, 1b
-	 add	%l0, (1 << 3), %l0
-
-	nop
-	nop
-	nop
-	clr	%l0
-1:	ldxa	[%l0] ASI_DTLB_TAG_READ, %g1
-	nop
-	nop
-	nop
-	andn	%g1, %l2, %g1
-	cmp	%g1, %g3
-	blu,pn	%xcc, 2f
-	 cmp	%g1, %g7
-	bgeu,pn	%xcc, 2f
-	 nop
-	stxa	%g0, [%l7] ASI_DMMU
-	stxa	%g0, [%l0] ASI_DTLB_DATA_ACCESS
-2:	cmp	%l0, (63 << 3)
-	blu,pt	%xcc, 1b
-	 add	%l0, (1 << 3), %l0
-
-	nop
-	nop
-	nop
-	sethi	%hi(KERNBASE), %g3
-	mov	(63 << 3), %g7
-	stxa	%g3, [%l7] ASI_DMMU
-	stxa	%g5, [%g7] ASI_DTLB_DATA_ACCESS
-	membar	#Sync
-	stxa	%g3, [%l7] ASI_IMMU
-	stxa	%g5, [%g7] ASI_ITLB_DATA_ACCESS
-	membar	#Sync
-	flush	%g3
-	membar	#Sync
-	b,pt	%xcc, 1f
-	 nop
-1:	set	bounce, %g2
-	jmpl	%g2 + %g0, %g0
-	 nop
-
-bounce:
 	mov	PRIMARY_CONTEXT, %g7
 	stxa	%g0, [%g7] ASI_DMMU
 	membar	#Sync
@@ -137,24 +130,6 @@
 	stxa	%g0, [%g7] ASI_DMMU
 	membar	#Sync
 
-	mov	TLB_TAG_ACCESS, %g2
-	stxa	%g3, [%g2] ASI_IMMU
-	stxa	%g3, [%g2] ASI_DMMU
-
-	mov	(63 << 3), %g7
-	ldxa	[%g7] ASI_ITLB_DATA_ACCESS, %g1
-	andn	%g1, (_PAGE_G), %g1
-	stxa	%g1, [%g7] ASI_ITLB_DATA_ACCESS
-	membar	#Sync
-
-	ldxa	[%g7] ASI_DTLB_DATA_ACCESS, %g1
-	andn	%g1, (_PAGE_G), %g1
-	stxa	%g1, [%g7] ASI_DTLB_DATA_ACCESS
-	membar	#Sync
-
-	flush	%g3
-	membar	#Sync
-
 	mov	1, %g5
 	sllx	%g5, (PAGE_SHIFT + 1), %g5
 	sub	%g5, (REGWIN_SZ + STACK_BIAS), %g5
@@ -167,12 +142,12 @@
 	/* Setup the trap globals, then we can resurface. */
 	rdpr	%pstate, %o1
 	mov	%g6, %o2
-	wrpr	%o1, (PSTATE_AG | PSTATE_IE), %pstate
+	wrpr	%o1, PSTATE_AG, %pstate
 	sethi	%hi(sparc64_ttable_tl0), %g5
 	wrpr	%g5, %tba
 	mov	%o2, %g6
 
-	wrpr	%o1, (PSTATE_MG | PSTATE_IE), %pstate
+	wrpr	%o1, PSTATE_MG, %pstate
 #define KERN_HIGHBITS		((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
 #define KERN_LOWBITS		(_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
 #ifdef THIS_IS_CHEETAH
@@ -198,7 +173,7 @@
 #undef VPTE_BASE
 
 	/* Setup interrupt globals, we are always SMP. */
-	wrpr	%o1, (PSTATE_IG | PSTATE_IE), %pstate
+	wrpr	%o1, PSTATE_IG, %pstate
 
 	/* Get our UPA MID. */
 	lduw	[%o2 + AOFF_task_processor], %g1
@@ -208,11 +183,14 @@
 	/* In theory this is: &(cpu_data[this_upamid].irq_worklists[0]) */
 	sllx	%g1, 7, %g1
 	add	%g5, %g1, %g1
-	add	%g1, 64, %g1
+	add	%g1, 64, %g6
 
 	wrpr	%g0, 0, %wstate
 	or	%o1, PSTATE_IE, %o1
 	wrpr	%o1, 0, %pstate
+
+	call	prom_set_trap_table
+	 sethi	%hi(sparc64_ttable_tl0), %o0
 
 	call	smp_callin
 	 nop
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/traps.c linux.14p16/arch/sparc64/kernel/traps.c
--- linux.vanilla/arch/sparc64/kernel/traps.c	Wed Oct 20 01:12:34 1999
+++ linux.14p16/arch/sparc64/kernel/traps.c	Thu Dec  9 15:34:36 1999
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.58.2.1 1999/08/19 01:11:16 davem Exp $
+/* $Id: traps.c,v 1.58.2.2 1999/12/01 23:55:43 davem Exp $
  * arch/sparc64/kernel/traps.c
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -26,6 +26,7 @@
 #include <asm/uaccess.h>
 #include <asm/fpumacro.h>
 #include <asm/lsu.h>
+#include <asm/psrcompat.h>
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif
@@ -814,6 +815,13 @@
 #endif
 }
 #endif
+
+void do_getpsr(struct pt_regs *regs)
+{
+	regs->u_regs[UREG_I0] = tstate_to_psr(regs->tstate);
+	regs->tpc   = regs->tnpc;
+	regs->tnpc += 4;
+}
 
 void trap_init(void)
 {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/ttable.S linux.14p16/arch/sparc64/kernel/ttable.S
--- linux.vanilla/arch/sparc64/kernel/ttable.S	Wed Oct 20 01:12:34 1999
+++ linux.14p16/arch/sparc64/kernel/ttable.S	Thu Dec  9 15:34:35 1999
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.28.2.1 1999/08/19 01:11:14 davem Exp $
+/* $Id: ttable.S,v 1.28.2.2 1999/12/01 23:55:44 davem Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -120,7 +120,8 @@
 tl0_resv11e:	TRAP_UTRAP(UT_TRAP_INSTRUCTION_30,0x11e) TRAP_UTRAP(UT_TRAP_INSTRUCTION_31,0x11f)
 tl0_getcc:	GETCC_TRAP
 tl0_setcc:	SETCC_TRAP
-tl0_resv122:	BTRAP(0x122) BTRAP(0x123) BTRAP(0x124) BTRAP(0x125) BTRAP(0x126)
+tl0_getpsr:	TRAP(do_getpsr)
+tl0_resv123:	BTRAP(0x123) BTRAP(0x124) BTRAP(0x125) BTRAP(0x126)
 tl0_solindir:	INDIRECT_SOLARIS_SYSCALL(156)
 tl0_resv128:	BTRAP(0x128) BTRAP(0x129) BTRAP(0x12a) BTRAP(0x12b) BTRAP(0x12c)
 tl0_resv12d:	BTRAP(0x12d) BTRAP(0x12e) BTRAP(0x12f) BTRAP(0x130) BTRAP(0x131)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/lib/blockops.S linux.14p16/arch/sparc64/lib/blockops.S
--- linux.vanilla/arch/sparc64/lib/blockops.S	Tue Oct 27 17:52:20 1998
+++ linux.14p16/arch/sparc64/lib/blockops.S	Thu Dec  9 15:34:36 1999
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.16 1998/10/20 03:09:04 jj Exp $
+/* $Id: blockops.S,v 1.16.2.1 1999/10/07 20:48:14 davem Exp $
  * blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu)
@@ -136,16 +136,18 @@
 
 	faddd		%f0, %f2, %f12			! FPA	Group
 	fmuld		%f0, %f2, %f14			! FPM
-	wr		%g0, ASI_BLK_P, %asi		! LSU	Group
 	membar		#StoreLoad | #StoreStore | #LoadStore	! LSU	Group
-1:	stda		%f0, [%o0 + 0x00] %asi		! Store	Group
-	stda		%f0, [%o0 + 0x40] %asi		! Store	Group
-	stda		%f0, [%o0 + 0x80] %asi		! Store	Group
-	stda		%f0, [%o0 + 0xc0] %asi		! Store	Group
+1:	stda		%f0, [%o0 + %g0] ASI_BLK_P	! Store	Group
+	add		%o0, 0x40, %o0			! IEU0
+	stda		%f0, [%o0 + %g0] ASI_BLK_P	! Store	Group
+	add		%o0, 0x40, %o0			! IEU0
+	stda		%f0, [%o0 + %g0] ASI_BLK_P	! Store	Group
 
+	add		%o0, 0x40, %o0			! IEU0	Group
+	stda		%f0, [%o0 + %g0] ASI_BLK_P	! Store	Group
 	subcc		%o1, 1, %o1			! IEU1
 	bne,pt		%icc, 1b			! CTI
-	 add		%o0, 0x100, %o0			! IEU0	Group
+	 add		%o0, 0x40, %o0			! IEU0	Group
 	membar		#Sync				! LSU	Group
 	VISExitHalf
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/Makefile linux.14p16/arch/sparc64/math-emu/Makefile
--- linux.vanilla/arch/sparc64/math-emu/Makefile	Tue Oct 27 17:52:20 1998
+++ linux.14p16/arch/sparc64/math-emu/Makefile	Thu Dec  9 15:34:37 1999
@@ -8,12 +8,7 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := math-emu.o
-O_OBJS   := math.o fabsq.o faddq.o fdivq.o fdmulq.o fitoq.o 		\
-		fmovq.o fmulq.o fnegq.o fqtoi.o fqtox.o fsubq.o		\
-		fxtoq.o fdtoq.o fstoq.o fqtos.o fqtod.o fsqrtq.o	\
-		fcmpq.o fcmpeq.o udivmodti4.o				\
-		fsqrts.o fsqrtd.o fadds.o faddd.o fsubs.o fsubd.o	\
-		fmuls.o fmuld.o fdivs.o fdivd.o fsmuld.o		\
-		fstoi.o fdtoi.o fstox.o fdtox.o fstod.o fdtos.o
+O_OBJS   := math.o
+CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w
 
 include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/double.h linux.14p16/arch/sparc64/math-emu/double.h
--- linux.vanilla/arch/sparc64/math-emu/double.h	Wed Apr 15 01:44:21 1998
+++ linux.14p16/arch/sparc64/math-emu/double.h	Thu Jan  1 01:00:00 1970
@@ -1,129 +0,0 @@
-/*
- * Definitions for IEEE Double Precision
- */
-
-#if _FP_W_TYPE_SIZE < 32
-#error "Here's a nickel kid.  Go buy yourself a real computer."
-#endif
-
-#if _FP_W_TYPE_SIZE < 64
-#define _FP_FRACTBITS_D		(2 * _FP_W_TYPE_SIZE)
-#else
-#define _FP_FRACTBITS_D		_FP_W_TYPE_SIZE
-#endif
-
-#define _FP_FRACBITS_D		53
-#define _FP_FRACXBITS_D		(_FP_FRACTBITS_D - _FP_FRACBITS_D)
-#define _FP_WFRACBITS_D		(_FP_WORKBITS + _FP_FRACBITS_D)
-#define _FP_WFRACXBITS_D	(_FP_FRACTBITS_D - _FP_WFRACBITS_D)
-#define _FP_EXPBITS_D		11
-#define _FP_EXPBIAS_D		1023
-#define _FP_EXPMAX_D		2047
-
-#define _FP_QNANBIT_D		\
-	((_FP_W_TYPE)1 << (_FP_FRACBITS_D-2) % _FP_W_TYPE_SIZE)
-#define _FP_IMPLBIT_D		\
-	((_FP_W_TYPE)1 << (_FP_FRACBITS_D-1) % _FP_W_TYPE_SIZE)
-#define _FP_OVERFLOW_D		\
-	((_FP_W_TYPE)1 << _FP_WFRACBITS_D % _FP_W_TYPE_SIZE)
-
-#if _FP_W_TYPE_SIZE < 64
-
-union _FP_UNION_D
-{
-  double flt;
-  struct {
-#if __BYTE_ORDER == __BIG_ENDIAN
-    unsigned sign  : 1;
-    unsigned exp   : _FP_EXPBITS_D;
-    unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE;
-    unsigned frac0 : _FP_W_TYPE_SIZE;
-#else
-    unsigned frac0 : _FP_W_TYPE_SIZE;
-    unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE;
-    unsigned exp   : _FP_EXPBITS_D;
-    unsigned sign  : 1;
-#endif
-  } bits __attribute__((packed));
-};
-
-#define FP_DECL_D(X)		_FP_DECL(2,X)
-#define FP_UNPACK_RAW_D(X,val)	_FP_UNPACK_RAW_2(D,X,val)
-#define FP_PACK_RAW_D(val,X)	_FP_PACK_RAW_2(D,val,X)
-
-#define FP_UNPACK_D(X,val)		\
-  do {					\
-    _FP_UNPACK_RAW_2(D,X,val);		\
-    _FP_UNPACK_CANONICAL(D,2,X);	\
-  } while (0)
-
-#define FP_PACK_D(val,X)		\
-  do {					\
-    _FP_PACK_CANONICAL(D,2,X);		\
-    _FP_PACK_RAW_2(D,val,X);		\
-  } while (0)
-
-#define FP_NEG_D(R,X)		_FP_NEG(D,2,R,X)
-#define FP_ADD_D(R,X,Y)		_FP_ADD(D,2,R,X,Y)
-#define FP_SUB_D(R,X,Y)		_FP_SUB(D,2,R,X,Y)
-#define FP_MUL_D(R,X,Y)		_FP_MUL(D,2,R,X,Y)
-#define FP_DIV_D(R,X,Y)		_FP_DIV(D,2,R,X,Y)
-#define FP_SQRT_D(R,X)		_FP_SQRT(D,2,R,X)
-
-#define FP_CMP_D(r,X,Y,un)	_FP_CMP(D,2,r,X,Y,un)
-#define FP_CMP_EQ_D(r,X,Y)	_FP_CMP_EQ(D,2,r,X,Y)
-
-#define FP_TO_INT_D(r,X,rsz,rsg)  _FP_TO_INT(D,2,r,X,rsz,rsg)
-#define FP_FROM_INT_D(X,r,rs,rt)  _FP_FROM_INT(D,2,X,r,rs,rt)
-
-#else
-
-union _FP_UNION_D
-{
-  double flt;
-  struct {
-#if __BYTE_ORDER == __BIG_ENDIAN
-    unsigned sign : 1;
-    unsigned exp  : _FP_EXPBITS_D;
-    unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0);
-#else
-    unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0);
-    unsigned exp  : _FP_EXPBITS_D;
-    unsigned sign : 1;
-#endif
-  } bits __attribute__((packed));
-};
-
-#define FP_DECL_D(X)		_FP_DECL(1,X)
-#define FP_UNPACK_RAW_D(X,val)	_FP_UNPACK_RAW_1(D,X,val)
-#define FP_PACK_RAW_D(val,X)	_FP_PACK_RAW_1(D,val,X)
-
-#define FP_UNPACK_D(X,val)		\
-  do {					\
-    _FP_UNPACK_RAW_1(D,X,val);		\
-    _FP_UNPACK_CANONICAL(D,1,X);	\
-  } while (0)
-
-#define FP_PACK_D(val,X)		\
-  do {					\
-    _FP_PACK_CANONICAL(D,1,X);		\
-    _FP_PACK_RAW_1(D,val,X);		\
-  } while (0)
-
-#define FP_NEG_D(R,X)		_FP_NEG(D,1,R,X)
-#define FP_ADD_D(R,X,Y)		_FP_ADD(D,1,R,X,Y)
-#define FP_SUB_D(R,X,Y)		_FP_SUB(D,1,R,X,Y)
-#define FP_MUL_D(R,X,Y)		_FP_MUL(D,1,R,X,Y)
-#define FP_DIV_D(R,X,Y)		_FP_DIV(D,1,R,X,Y)
-#define FP_SQRT_D(R,X)		_FP_SQRT(D,1,R,X)
-
-/* The implementation of _FP_MUL_D and _FP_DIV_D should be chosen by
-   the target machine.  */
-
-#define FP_CMP_D(r,X,Y,un)	_FP_CMP(D,1,r,X,Y,un)
-#define FP_CMP_EQ_D(r,X,Y)	_FP_CMP_EQ(D,1,r,X,Y)
-
-#define FP_TO_INT_D(r,X,rsz,rsg)  _FP_TO_INT(D,1,r,X,rsz,rsg)
-#define FP_FROM_INT_D(X,r,rs,rt)  _FP_FROM_INT(D,1,X,r,rs,rt)
-
-#endif /* W_TYPE_SIZE < 64 */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fabsq.c linux.14p16/arch/sparc64/math-emu/fabsq.c
--- linux.vanilla/arch/sparc64/math-emu/fabsq.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fabsq.c	Thu Jan  1 01:00:00 1970
@@ -1,6 +0,0 @@
-int FABSQ(unsigned long *rd, unsigned long *rs2)
-{
-	rd[0] = rs2[0] & 0x7fffffffffffffffUL;
-	rd[1] = rs2[1];
-	return 0;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/faddd.c linux.14p16/arch/sparc64/math-emu/faddd.c
--- linux.vanilla/arch/sparc64/math-emu/faddd.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/faddd.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-
-int FADDD(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R);
-
-	__FP_UNPACK_D(A, rs1);
-	__FP_UNPACK_D(B, rs2);
-	FP_ADD_D(R, A, B);
-	return __FP_PACK_D(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/faddq.c linux.14p16/arch/sparc64/math-emu/faddq.c
--- linux.vanilla/arch/sparc64/math-emu/faddq.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/faddq.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-
-int FADDQ(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R);
-
-	__FP_UNPACK_Q(A, rs1);
-	__FP_UNPACK_Q(B, rs2);
-	FP_ADD_Q(R, A, B);
-	return __FP_PACK_Q(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fadds.c linux.14p16/arch/sparc64/math-emu/fadds.c
--- linux.vanilla/arch/sparc64/math-emu/fadds.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fadds.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "single.h"
-
-int FADDS(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R);
-
-	__FP_UNPACK_S(A, rs1);
-	__FP_UNPACK_S(B, rs2);
-	FP_ADD_S(R, A, B);
-	return __FP_PACK_S(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fcmpeq.c linux.14p16/arch/sparc64/math-emu/fcmpeq.c
--- linux.vanilla/arch/sparc64/math-emu/fcmpeq.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fcmpeq.c	Thu Jan  1 01:00:00 1970
@@ -1,25 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-
-int FCMPEQ(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_Q(A); FP_DECL_Q(B);
-	long ret;
-	int fccno = ((long)rd) & 3;
-	unsigned long fsr;
-	
-	rd = (void *)(((long)rd)&~3);
-	__FP_UNPACK_Q(A, rs1);
-	__FP_UNPACK_Q(B, rs2);
-	FP_CMP_Q(ret, B, A, 3);
-	if (ret == -1) ret = 2;
-	fsr = *(unsigned long *)rd;
-	switch (fccno) {
-	case 0: fsr &= ~0xc00; fsr |= (ret << 10); break;
-	case 1: fsr &= ~0x300000000UL; fsr |= (ret << 32); break;
-	case 2: fsr &= ~0xc00000000UL; fsr |= (ret << 34); break;
-	case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break;
-	}
-	*(unsigned long *)rd = fsr;
-	return 0;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fcmpq.c linux.14p16/arch/sparc64/math-emu/fcmpq.c
--- linux.vanilla/arch/sparc64/math-emu/fcmpq.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fcmpq.c	Thu Jan  1 01:00:00 1970
@@ -1,25 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-
-int FCMPQ(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_Q(A); FP_DECL_Q(B);
-	long ret;
-	int fccno = ((long)rd) & 3;
-	unsigned long fsr;
-	
-	rd = (void *)(((long)rd)&~3);
-	__FP_UNPACK_Q(A, rs1);
-	__FP_UNPACK_Q(B, rs2);
-	FP_CMP_Q(ret, B, A, 3);
-	if (ret == -1) ret = 2;
-	fsr = *(unsigned long *)rd;
-	switch (fccno) {
-	case 0: fsr &= ~0xc00; fsr |= (ret << 10); break;
-	case 1: fsr &= ~0x300000000UL; fsr |= (ret << 32); break;
-	case 2: fsr &= ~0xc00000000UL; fsr |= (ret << 34); break;
-	case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break;
-	}
-	*(unsigned long *)rd = fsr;
-	return 0;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fdivd.c linux.14p16/arch/sparc64/math-emu/fdivd.c
--- linux.vanilla/arch/sparc64/math-emu/fdivd.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fdivd.c	Thu Jan  1 01:00:00 1970
@@ -1,19 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-
-int FDIVD(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R);
-	int ret = 0;
-
-	__FP_UNPACK_D(A, rs1);
-	__FP_UNPACK_D(B, rs2);
-	if(B_c == FP_CLS_ZERO &&
-	   A_c != FP_CLS_ZERO) {
-		ret |= EFLAG_DIVZERO;
-		if(__FPU_TRAP_P(EFLAG_DIVZERO))
-			return ret;
-	}
-	FP_DIV_D(R, A, B);
-	return (ret | __FP_PACK_D(rd, R));
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fdivq.c linux.14p16/arch/sparc64/math-emu/fdivq.c
--- linux.vanilla/arch/sparc64/math-emu/fdivq.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fdivq.c	Thu Jan  1 01:00:00 1970
@@ -1,19 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-
-int FDIVQ(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R);
-	int ret;
-
-	__FP_UNPACK_Q(A, rs1);
-	__FP_UNPACK_Q(B, rs2);
-	if(B_c == FP_CLS_ZERO &&
-	   A_c != FP_CLS_ZERO) {
-		ret |= EFLAG_DIVZERO;
-		if(__FPU_TRAP_P(EFLAG_DIVZERO))
-			return ret;
-	}
-	FP_DIV_Q(R, A, B);
-	return (ret | __FP_PACK_Q(rd, R));
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fdivs.c linux.14p16/arch/sparc64/math-emu/fdivs.c
--- linux.vanilla/arch/sparc64/math-emu/fdivs.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fdivs.c	Thu Jan  1 01:00:00 1970
@@ -1,20 +0,0 @@
-#include "soft-fp.h"
-#include "single.h"
-
-int FDIVS(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R);
-	int ret = 0;
-
-	__FP_UNPACK_S(A, rs1);
-	__FP_UNPACK_S(B, rs2);
-	if(B_c == FP_CLS_ZERO &&
-	   A_c != FP_CLS_ZERO) {
-		ret |= EFLAG_DIVZERO;
-		if(__FPU_TRAP_P(EFLAG_DIVZERO))
-			return ret;
-	}
-	FP_DIV_S(R, A, B);
-	return (ret | __FP_PACK_S(rd, R));
-}
-
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fdmulq.c linux.14p16/arch/sparc64/math-emu/fdmulq.c
--- linux.vanilla/arch/sparc64/math-emu/fdmulq.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fdmulq.c	Thu Jan  1 01:00:00 1970
@@ -1,15 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-#include "double.h"
-
-int FDMULQ(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_D(IN); FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R);
-
-	__FP_UNPACK_D(IN, rs1);
-	FP_CONV(Q,D,2,1,A,IN);
-	__FP_UNPACK_D(IN, rs2);
-	FP_CONV(Q,D,2,1,B,IN);
-	FP_MUL_Q(R, A, B);
-	return __FP_PACK_Q(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fdtoi.c linux.14p16/arch/sparc64/math-emu/fdtoi.c
--- linux.vanilla/arch/sparc64/math-emu/fdtoi.c	Sat Aug 14 02:27:15 1999
+++ linux.14p16/arch/sparc64/math-emu/fdtoi.c	Thu Jan  1 01:00:00 1970
@@ -1,13 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-
-int FDTOI(unsigned *rd, void *rs2)
-{
-	FP_DECL_D(A);
-	unsigned r;
-
-	__FP_UNPACK_D(A, rs2);
-	FP_TO_INT_D(r, A, 32, 1);
-	*rd = r;
-	return _FTOI_RESULT;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fdtoq.c linux.14p16/arch/sparc64/math-emu/fdtoq.c
--- linux.vanilla/arch/sparc64/math-emu/fdtoq.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fdtoq.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-#include "double.h"
-
-int FDTOQ(void *rd, void *rs2)
-{
-	FP_DECL_D(A); FP_DECL_Q(R);
-
-	__FP_UNPACK_D(A, rs2);
-	FP_CONV(Q,D,2,1,R,A);
-	return __FP_PACK_Q(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fdtos.c linux.14p16/arch/sparc64/math-emu/fdtos.c
--- linux.vanilla/arch/sparc64/math-emu/fdtos.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fdtos.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
-
-int FDTOS(void *rd, void *rs2)
-{
-	FP_DECL_D(A); FP_DECL_S(R);
-
-	__FP_UNPACK_D(A, rs2);
-	FP_CONV(S,D,1,1,R,A);
-	return __FP_PACK_S(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fdtox.c linux.14p16/arch/sparc64/math-emu/fdtox.c
--- linux.vanilla/arch/sparc64/math-emu/fdtox.c	Sat Aug 14 02:27:15 1999
+++ linux.14p16/arch/sparc64/math-emu/fdtox.c	Thu Jan  1 01:00:00 1970
@@ -1,13 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-
-int FDTOX(unsigned long *rd, void *rs2)
-{
-	FP_DECL_D(A);
-	unsigned long r;
-
-	__FP_UNPACK_D(A, rs2);
-	FP_TO_INT_D(r, A, 64, 1);
-	*rd = r;
-	return _FTOI_RESULT;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fitoq.c linux.14p16/arch/sparc64/math-emu/fitoq.c
--- linux.vanilla/arch/sparc64/math-emu/fitoq.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fitoq.c	Thu Jan  1 01:00:00 1970
@@ -1,11 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-
-int FITOQ(void *rd, void *rs2)
-{
-	FP_DECL_Q(R);
-	int a = *(int *)rs2;
-
-	FP_FROM_INT_Q(R, a, 32, int);
-	return __FP_PACK_Q(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fmovq.c linux.14p16/arch/sparc64/math-emu/fmovq.c
--- linux.vanilla/arch/sparc64/math-emu/fmovq.c	Mon Jan 12 23:15:44 1998
+++ linux.14p16/arch/sparc64/math-emu/fmovq.c	Thu Jan  1 01:00:00 1970
@@ -1,6 +0,0 @@
-int FMOVQ(unsigned long *rd, unsigned long *rs2)
-{
-	rd[0] = rs2[0];
-	rd[1] = rs2[1];
-	return 0;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fmuld.c linux.14p16/arch/sparc64/math-emu/fmuld.c
--- linux.vanilla/arch/sparc64/math-emu/fmuld.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fmuld.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-
-int FMULD(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R);
-
-	__FP_UNPACK_D(A, rs1);
-	__FP_UNPACK_D(B, rs2);
-	FP_MUL_D(R, A, B);
-	return __FP_PACK_D(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fmulq.c linux.14p16/arch/sparc64/math-emu/fmulq.c
--- linux.vanilla/arch/sparc64/math-emu/fmulq.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fmulq.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-
-int FMULQ(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R);
-
-	__FP_UNPACK_Q(A, rs1);
-	__FP_UNPACK_Q(B, rs2);
-	FP_MUL_Q(R, A, B);
-	return __FP_PACK_Q(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fmuls.c linux.14p16/arch/sparc64/math-emu/fmuls.c
--- linux.vanilla/arch/sparc64/math-emu/fmuls.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fmuls.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "single.h"
-
-int FMULS(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R);
-
-	__FP_UNPACK_S(A, rs1);
-	__FP_UNPACK_S(B, rs2);
-	FP_MUL_S(R, A, B);
-	return __FP_PACK_S(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fnegq.c linux.14p16/arch/sparc64/math-emu/fnegq.c
--- linux.vanilla/arch/sparc64/math-emu/fnegq.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fnegq.c	Thu Jan  1 01:00:00 1970
@@ -1,7 +0,0 @@
-int FNEGQ(unsigned long *rd, unsigned long *rs2)
-{
-	rd[0] = rs2[0] ^ 0x8000000000000000UL;
-	rd[1] = rs2[1];
-	return 0;
-}
-
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fqtod.c linux.14p16/arch/sparc64/math-emu/fqtod.c
--- linux.vanilla/arch/sparc64/math-emu/fqtod.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fqtod.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-#include "double.h"
-
-int FQTOD(void *rd, void *rs2)
-{
-	FP_DECL_Q(A); FP_DECL_D(R);
-
-	__FP_UNPACK_Q(A, rs2);
-	FP_CONV(D,Q,1,2,R,A);
-	return __FP_PACK_D(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fqtoi.c linux.14p16/arch/sparc64/math-emu/fqtoi.c
--- linux.vanilla/arch/sparc64/math-emu/fqtoi.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fqtoi.c	Thu Jan  1 01:00:00 1970
@@ -1,13 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-
-int FQTOI(unsigned *rd, void *rs2)
-{
-	FP_DECL_Q(A);
-	unsigned r;
-
-	__FP_UNPACK_Q(A, rs2);
-	FP_TO_INT_Q(r, A, 32, 1);
-	*rd = r;
-	return 0;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fqtos.c linux.14p16/arch/sparc64/math-emu/fqtos.c
--- linux.vanilla/arch/sparc64/math-emu/fqtos.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fqtos.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-#include "single.h"
-
-int FQTOS(void *rd, void *rs2)
-{
-	FP_DECL_Q(A); FP_DECL_S(R);
-
-	__FP_UNPACK_Q(A, rs2);
-	FP_CONV(S,Q,1,2,R,A);
-	return __FP_PACK_S(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fqtox.c linux.14p16/arch/sparc64/math-emu/fqtox.c
--- linux.vanilla/arch/sparc64/math-emu/fqtox.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fqtox.c	Thu Jan  1 01:00:00 1970
@@ -1,13 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-
-int FQTOX(unsigned long *rd, void *rs2)
-{
-	FP_DECL_Q(A);
-	unsigned long r;
-
-	__FP_UNPACK_Q(A, rs2);
-	FP_TO_INT_Q(r, A, 64, 1);
-	*rd = r;
-	return 0;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fsmuld.c linux.14p16/arch/sparc64/math-emu/fsmuld.c
--- linux.vanilla/arch/sparc64/math-emu/fsmuld.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fsmuld.c	Thu Jan  1 01:00:00 1970
@@ -1,15 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
-
-int FSMULD(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_S(IN); FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R);
-
-	__FP_UNPACK_S(IN, rs1);
-	FP_CONV(D,S,1,1,A,IN);
-	__FP_UNPACK_S(IN, rs2);
-	FP_CONV(D,S,1,1,B,IN);
-	FP_MUL_D(R, A, B);
-	return __FP_PACK_D(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fsqrtd.c linux.14p16/arch/sparc64/math-emu/fsqrtd.c
--- linux.vanilla/arch/sparc64/math-emu/fsqrtd.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fsqrtd.c	Thu Jan  1 01:00:00 1970
@@ -1,11 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-
-int FSQRTD(void *rd, void *rs2)
-{
-	FP_DECL_D(A); FP_DECL_D(R);
-        
-	__FP_UNPACK_D(A, rs2);
-	FP_SQRT_D(R, A);
-	return __FP_PACK_D(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fsqrtq.c linux.14p16/arch/sparc64/math-emu/fsqrtq.c
--- linux.vanilla/arch/sparc64/math-emu/fsqrtq.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fsqrtq.c	Thu Jan  1 01:00:00 1970
@@ -1,11 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-
-int FSQRTQ(void *rd, void *rs2)
-{
-	FP_DECL_Q(A); FP_DECL_Q(R);
-        
-	__FP_UNPACK_Q(A, rs2);
-	FP_SQRT_Q(R, A);
-	return __FP_PACK_Q(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fsqrts.c linux.14p16/arch/sparc64/math-emu/fsqrts.c
--- linux.vanilla/arch/sparc64/math-emu/fsqrts.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fsqrts.c	Thu Jan  1 01:00:00 1970
@@ -1,11 +0,0 @@
-#include "soft-fp.h"
-#include "single.h"
-
-int FSQRTS(void *rd, void *rs2)
-{
-	FP_DECL_S(A); FP_DECL_S(R);
-        
-	__FP_UNPACK_S(A, rs2);
-	FP_SQRT_S(R, A);
-	return __FP_PACK_S(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fstod.c linux.14p16/arch/sparc64/math-emu/fstod.c
--- linux.vanilla/arch/sparc64/math-emu/fstod.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fstod.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
-
-int FSTOD(void *rd, void *rs2)
-{
-	FP_DECL_S(A); FP_DECL_D(R);
-
-	__FP_UNPACK_S(A, rs2);
-	FP_CONV(D,S,1,1,R,A);
-	return __FP_PACK_D(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fstoi.c linux.14p16/arch/sparc64/math-emu/fstoi.c
--- linux.vanilla/arch/sparc64/math-emu/fstoi.c	Sat Aug 14 02:27:15 1999
+++ linux.14p16/arch/sparc64/math-emu/fstoi.c	Thu Jan  1 01:00:00 1970
@@ -1,13 +0,0 @@
-#include "soft-fp.h"
-#include "single.h"
-
-int FSTOI(unsigned *rd, void *rs2)
-{
-	FP_DECL_S(A);
-	unsigned r;
-
-	__FP_UNPACK_S(A, rs2);
-	FP_TO_INT_S(r, A, 32, 1);
-	*rd = r;
-	return _FTOI_RESULT;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fstoq.c linux.14p16/arch/sparc64/math-emu/fstoq.c
--- linux.vanilla/arch/sparc64/math-emu/fstoq.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fstoq.c	Thu Jan  1 01:00:00 1970
@@ -1,12 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-#include "single.h"
-
-int FSTOQ(void *rd, void *rs2)
-{
-	FP_DECL_S(A); FP_DECL_Q(R);
-
-	__FP_UNPACK_S(A, rs2);
-	FP_CONV(Q,S,2,1,R,A);
-	return __FP_PACK_Q(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fstox.c linux.14p16/arch/sparc64/math-emu/fstox.c
--- linux.vanilla/arch/sparc64/math-emu/fstox.c	Sat Aug 14 02:27:15 1999
+++ linux.14p16/arch/sparc64/math-emu/fstox.c	Thu Jan  1 01:00:00 1970
@@ -1,13 +0,0 @@
-#include "soft-fp.h"
-#include "single.h"
-
-int FSTOX(unsigned long *rd, void *rs2)
-{
-	FP_DECL_S(A);
-	unsigned long r;
-
-	__FP_UNPACK_S(A, rs2);
-	FP_TO_INT_S(r, A, 64, 1);
-	*rd = r;
-	return _FTOI_RESULT;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fsubd.c linux.14p16/arch/sparc64/math-emu/fsubd.c
--- linux.vanilla/arch/sparc64/math-emu/fsubd.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fsubd.c	Thu Jan  1 01:00:00 1970
@@ -1,14 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-
-int FSUBD(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R);
-
-	__FP_UNPACK_D(A, rs1);
-	__FP_UNPACK_D(B, rs2);
-	if (B_c != FP_CLS_NAN)
-		B_s ^= 1;
-	FP_ADD_D(R, A, B);
-	return __FP_PACK_D(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fsubq.c linux.14p16/arch/sparc64/math-emu/fsubq.c
--- linux.vanilla/arch/sparc64/math-emu/fsubq.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fsubq.c	Thu Jan  1 01:00:00 1970
@@ -1,14 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-
-int FSUBQ(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R);
-
-	__FP_UNPACK_Q(A, rs1);
-	__FP_UNPACK_Q(B, rs2);
-	if (B_c != FP_CLS_NAN)
-		B_s ^= 1;
-	FP_ADD_Q(R, A, B);
-	return __FP_PACK_Q(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fsubs.c linux.14p16/arch/sparc64/math-emu/fsubs.c
--- linux.vanilla/arch/sparc64/math-emu/fsubs.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fsubs.c	Thu Jan  1 01:00:00 1970
@@ -1,14 +0,0 @@
-#include "soft-fp.h"
-#include "single.h"
-
-int FSUBS(void *rd, void *rs2, void *rs1)
-{
-	FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R);
-
-	__FP_UNPACK_S(A, rs1);
-	__FP_UNPACK_S(B, rs2);
-	if (B_c != FP_CLS_NAN)
-		B_s ^= 1;
-	FP_ADD_S(R, A, B);
-	return __FP_PACK_S(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/fxtoq.c linux.14p16/arch/sparc64/math-emu/fxtoq.c
--- linux.vanilla/arch/sparc64/math-emu/fxtoq.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/fxtoq.c	Thu Jan  1 01:00:00 1970
@@ -1,11 +0,0 @@
-#include "soft-fp.h"
-#include "quad.h"
-
-int FXTOQ(void *rd, void *rs2)
-{
-	FP_DECL_Q(R);
-	long a = *(long *)rs2;
-
-	FP_FROM_INT_Q(R, a, 64, long);
-	return __FP_PACK_Q(rd, R);
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/math.c linux.14p16/arch/sparc64/math-emu/math.c
--- linux.vanilla/arch/sparc64/math-emu/math.c	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/math.c	Thu Dec  9 15:34:37 1999
@@ -1,7 +1,7 @@
-/* $Id: math.c,v 1.7 1999/02/10 14:16:26 davem Exp $
+/* $Id: math.c,v 1.7.2.2 1999/11/19 08:24:37 jj Exp $
  * arch/sparc64/math-emu/math.c
  *
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1999 Jakub Jelinek (jj@ultra.linux.cz)
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
  *
  * Emulation routines originate from soft-fp package, which is part
@@ -15,47 +15,63 @@
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
 
+#include "sfp-util.h"
 #include "soft-fp.h"
-
-#define FLOATFUNC(x) extern int x(void *,void *,void *);
-
-FLOATFUNC(FMOVQ)
-FLOATFUNC(FNEGQ)
-FLOATFUNC(FABSQ)
-FLOATFUNC(FSQRTQ)
-FLOATFUNC(FADDQ)
-FLOATFUNC(FSUBQ)
-FLOATFUNC(FMULQ)
-FLOATFUNC(FDIVQ)
-FLOATFUNC(FDMULQ)
-FLOATFUNC(FQTOX)
-FLOATFUNC(FXTOQ)
-FLOATFUNC(FQTOS)
-FLOATFUNC(FQTOD)
-FLOATFUNC(FITOQ)
-FLOATFUNC(FSTOQ)
-FLOATFUNC(FDTOQ)
-FLOATFUNC(FQTOI)
-FLOATFUNC(FCMPQ)
-FLOATFUNC(FCMPEQ)
-
-FLOATFUNC(FSQRTS)
-FLOATFUNC(FSQRTD)
-FLOATFUNC(FADDS)
-FLOATFUNC(FADDD)
-FLOATFUNC(FSUBS)
-FLOATFUNC(FSUBD)
-FLOATFUNC(FMULS)
-FLOATFUNC(FMULD)
-FLOATFUNC(FDIVS)
-FLOATFUNC(FDIVD)
-FLOATFUNC(FSMULD)
-FLOATFUNC(FSTOX)
-FLOATFUNC(FDTOX)
-FLOATFUNC(FDTOS)
-FLOATFUNC(FSTOD)
-FLOATFUNC(FSTOI)
-FLOATFUNC(FDTOI)
+#include "single.h"
+#include "double.h"
+#include "quad.h"
+
+/* QUAD - ftt == 3 */
+#define FMOVQ	0x003
+#define FNEGQ	0x007
+#define FABSQ	0x00b
+#define FSQRTQ	0x02b
+#define FADDQ	0x043
+#define FSUBQ	0x047
+#define FMULQ	0x04b
+#define FDIVQ	0x04f
+#define FDMULQ	0x06e
+#define FQTOX	0x083
+#define FXTOQ	0x08c
+#define FQTOS	0x0c7
+#define FQTOD	0x0cb
+#define FITOQ	0x0cc
+#define FSTOQ	0x0cd
+#define FDTOQ	0x0ce
+#define FQTOI	0x0d3
+/* SUBNORMAL - ftt == 2 */
+#define FSQRTS	0x029
+#define FSQRTD	0x02a
+#define FADDS	0x041
+#define FADDD	0x042
+#define FSUBS	0x045
+#define FSUBD	0x046
+#define FMULS	0x049
+#define FMULD	0x04a
+#define FDIVS	0x04d
+#define FDIVD	0x04e
+#define FSMULD	0x069
+#define FSTOX	0x081
+#define FDTOX	0x082
+#define FDTOS	0x0c6
+#define FSTOD	0x0c9
+#define FSTOI	0x0d1
+#define FDTOI	0x0d2
+/* FPOP2 */
+#define FCMPQ	0x053
+#define FCMPEQ	0x057
+#define FMOVQ0	0x003
+#define FMOVQ1	0x043
+#define FMOVQ2	0x083
+#define FMOVQ3	0x0c3
+#define FMOVQI	0x103
+#define FMOVQX	0x183
+#define FMOVQZ	0x027
+#define FMOVQLE	0x047
+#define FMOVQLZ 0x067
+#define FMOVQNZ	0x0a7
+#define FMOVQGZ	0x0c7
+#define FMOVQGE 0x0e7
 
 #define FSR_TEM_SHIFT	23UL
 #define FSR_TEM_MASK	(0x1fUL << FSR_TEM_SHIFT)
@@ -72,7 +88,7 @@
  *
  * We return 0 if a SIGFPE should be sent, 1 otherwise.
  */
-static int record_exception(struct pt_regs *regs, int eflag)
+static inline int record_exception(struct pt_regs *regs, int eflag)
 {
 	u64 fsr = current->tss.xfsr[0];
 	int would_trap;
@@ -84,46 +100,36 @@
 	if(would_trap != 0) {
 		eflag &= ((fsr & FSR_TEM_MASK) >> FSR_TEM_SHIFT);
 		if((eflag & (eflag - 1)) != 0) {
-			if(eflag & EFLAG_INVALID)
-				eflag = EFLAG_INVALID;
-			else if(eflag & EFLAG_DIVZERO)
-				eflag = EFLAG_DIVZERO;
-			else if(eflag & EFLAG_INEXACT)
-				eflag = EFLAG_INEXACT;
+			if(eflag & FP_EX_INVALID)
+				eflag = FP_EX_INVALID;
+			else if(eflag & FP_EX_OVERFLOW)
+				eflag = FP_EX_OVERFLOW;
+			else if(eflag & FP_EX_UNDERFLOW)
+				eflag = FP_EX_UNDERFLOW;
+			else if(eflag & FP_EX_DIVZERO)
+				eflag = FP_EX_DIVZERO;
+			else if(eflag & FP_EX_INEXACT)
+				eflag = FP_EX_INEXACT;
 		}
 	}
 
-	/* Set CEXC, here are the rules:
+	/* Set CEXC, here is the rule:
 	 *
-	 * 1) In general all FPU ops will set one and only one
+	 *    In general all FPU ops will set one and only one
 	 *    bit in the CEXC field, this is always the case
 	 *    when the IEEE exception trap is enabled in TEM.
-	 *
-	 * 2) As a special case, if an overflow or underflow
-	 *    is being signalled, AND the trap is not enabled
-	 *    in TEM, then the inexact field shall also be set.
 	 */
 	fsr &= ~(FSR_CEXC_MASK);
-	if(would_trap ||
-	   (eflag & (EFLAG_OVERFLOW | EFLAG_UNDERFLOW)) == 0) {
-		fsr |= ((long)eflag << FSR_CEXC_SHIFT);
-	} else {
-		fsr |= (((long)eflag << FSR_CEXC_SHIFT) |
-			(EFLAG_INEXACT << FSR_CEXC_SHIFT));
-	}
+	fsr |= ((long)eflag << FSR_CEXC_SHIFT);
 
-	/* Set the AEXC field, rules are:
+	/* Set the AEXC field, rule is:
 	 *
-	 * 1) If a trap would not be generated, the
+	 *    If a trap would not be generated, the
 	 *    CEXC just generated is OR'd into the
 	 *    existing value of AEXC.
-	 *
-	 * 2) When a trap is generated, AEXC is cleared.
 	 */
 	if(would_trap == 0)
 		fsr |= ((long)eflag << FSR_AEXC_SHIFT);
-	else
-		fsr &= ~(FSR_AEXC_MASK);
 
 	/* If trapping, indicate fault trap type IEEE. */
 	if(would_trap != 0)
@@ -142,18 +148,31 @@
 	return (would_trap ? 0 : 1);
 }
 
+typedef union {
+	u32 s;
+	u64 d;
+	u64 q[2];
+} *argp;
+
 int do_mathemu(struct pt_regs *regs, struct fpustate *f)
 {
 	unsigned long pc = regs->tpc;
 	unsigned long tstate = regs->tstate;
 	u32 insn = 0;
-	int type = 0; /* 01 is single, 10 is double, 11 is quad, 
-			 000011 is rs1, 001100 is rs2, 110000 is rd (00 in rd is fcc)
-			 111100000000 tells which ftt may that happen in */
+	int type = 0;
+	/* ftt tells which ftt it may happen in, r is rd, b is rs2 and a is rs1. The *u arg tells
+	   whether the argument should be packed/unpacked (0 - do not unpack/pack, 1 - unpack/pack)
+	   non-u args tells the size of the argument (0 - no argument, 1 - single, 2 - double, 3 - quad */
+#define TYPE(ftt, r, ru, b, bu, a, au) type = (au << 2) | (a << 0) | (bu << 5) | (b << 3) | (ru << 8) | (r << 6) | (ftt << 9)
 	int freg;
 	static u64 zero[2] = { 0L, 0L };
 	int flags;
-	int (*func)(void *,void *,void *) = NULL;
+	FP_DECL_EX;
+	FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+	FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+	FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
+	int IR;
+	long XR, xfsr;
 
 	if(tstate & TSTATE_PRIV)
 		die_if_kernel("FPQuad from kernel", regs);
@@ -163,55 +182,145 @@
 		if ((insn & 0xc1f80000) == 0x81a00000) /* FPOP1 */ {
 			switch ((insn >> 5) & 0x1ff) {
 			/* QUAD - ftt == 3 */
-			case 0x003: type = 0x33c; func = FMOVQ; break;
-			case 0x007: type = 0x33c; func = FNEGQ; break;
-			case 0x00b: type = 0x33c; func = FABSQ; break;
-			case 0x02b: type = 0x33c; func = FSQRTQ; break;
-			case 0x043: type = 0x33f; func = FADDQ; break;
-			case 0x047: type = 0x33f; func = FSUBQ; break;
-			case 0x04b: type = 0x33f; func = FMULQ; break;
-			case 0x04f: type = 0x33f; func = FDIVQ; break;
-			case 0x06e: type = 0x33a; func = FDMULQ; break;
-			case 0x083: type = 0x32c; func = FQTOX; break;
-			case 0x08c: type = 0x338; func = FXTOQ; break;
-			case 0x0c7: type = 0x31c; func = FQTOS; break;
-			case 0x0cb: type = 0x32c; func = FQTOD; break;
-			case 0x0cc: type = 0x334; func = FITOQ; break;
-			case 0x0cd: type = 0x334; func = FSTOQ; break;
-			case 0x0ce: type = 0x338; func = FDTOQ; break;
-			case 0x0d3: type = 0x31c; func = FQTOI; break;
+			case FMOVQ:
+			case FNEGQ:
+			case FABSQ: TYPE(3,3,0,3,0,0,0); break;
+			case FSQRTQ: TYPE(3,3,1,3,1,0,0); break;
+			case FADDQ:
+			case FSUBQ:
+			case FMULQ:
+			case FDIVQ: TYPE(3,3,1,3,1,3,1); break;
+			case FDMULQ: TYPE(3,3,1,2,1,2,1); break;
+			case FQTOX: TYPE(3,2,0,3,1,0,0); break;
+			case FXTOQ: TYPE(3,3,1,2,0,0,0); break;
+			case FQTOS: TYPE(3,1,1,3,1,0,0); break;
+			case FQTOD: TYPE(3,2,1,3,1,0,0); break;
+			case FITOQ: TYPE(3,3,1,1,0,0,0); break;
+			case FSTOQ: TYPE(3,3,1,1,1,0,0); break;
+			case FDTOQ: TYPE(3,3,1,2,1,0,0); break;
+			case FQTOI: TYPE(3,1,0,3,1,0,0); break;
 			/* SUBNORMAL - ftt == 2 */
-			case 0x029: type = 0x214; func = FSQRTS; break;
-			case 0x02a: type = 0x228; func = FSQRTD; break;
-			case 0x041: type = 0x215; func = FADDS; break;
-			case 0x042: type = 0x22a; func = FADDD; break;
-			case 0x045: type = 0x215; func = FSUBS; break;
-			case 0x046: type = 0x22a; func = FSUBD; break;
-			case 0x049: type = 0x215; func = FMULS; break;
-			case 0x04a: type = 0x22a; func = FMULD; break;
-			case 0x04d: type = 0x215; func = FDIVS; break;
-			case 0x04e: type = 0x22a; func = FDIVD; break;
-			case 0x069: type = 0x225; func = FSMULD; break;
-			case 0x081: type = 0x224; func = FSTOX; break;
-			case 0x082: type = 0x228; func = FDTOX; break;
-			case 0x0c6: type = 0x218; func = FDTOS; break;
-			case 0x0c9: type = 0x224; func = FSTOD; break;
-			case 0x0d1: type = 0x214; func = FSTOI; break;
-			case 0x0d2: type = 0x218; func = FDTOI; break;
+			case FSQRTS: TYPE(2,1,1,1,1,0,0); break;
+			case FSQRTD: TYPE(2,2,1,2,1,0,0); break;
+			case FADDD:
+			case FSUBD:
+			case FMULD:
+			case FDIVD: TYPE(2,2,1,2,1,2,1); break;
+			case FADDS:
+			case FSUBS:
+			case FMULS:
+			case FDIVS: TYPE(2,1,1,1,1,1,1); break;
+			case FSMULD: TYPE(2,2,1,1,1,1,1); break;
+			case FSTOX: TYPE(2,2,0,1,1,0,0); break;
+			case FDTOX: TYPE(2,2,0,2,1,0,0); break;
+			case FDTOS: TYPE(2,1,1,2,1,0,0); break;
+			case FSTOD: TYPE(2,2,1,1,1,0,0); break;
+			case FSTOI: TYPE(2,1,0,1,1,0,0); break;
+			case FDTOI: TYPE(2,1,0,2,1,0,0); break;
 			}
 		}
 		else if ((insn & 0xc1f80000) == 0x81a80000) /* FPOP2 */ {
+			IR = 2;
 			switch ((insn >> 5) & 0x1ff) {
-			case 0x053: type = 0x30f; func = FCMPQ; break;
-			case 0x057: type = 0x30f; func = FCMPEQ; break;
+			case FCMPQ: TYPE(3,0,0,3,0,3,0); break;
+			case FCMPEQ: TYPE(3,0,0,3,0,3,0); break;
+			/* Now the conditional fmovq support */
+			case FMOVQ0:
+			case FMOVQ1:
+			case FMOVQ2:
+			case FMOVQ3:
+				/* fmovq %fccX, %fY, %fZ */
+				if (!((insn >> 11) & 3))
+					XR = current->tss.xfsr[0] >> 10;
+				else
+					XR = current->tss.xfsr[0] >> (30 + ((insn >> 10) & 0x6));
+				XR &= 3;
+				IR = 0;
+				switch ((insn >> 14) & 0x7) {
+				/* case 0: IR = 0; break; */			/* Never */
+				case 1: if (XR) IR = 1; break;			/* Not Equal */
+				case 2: if (XR == 1 || XR == 2) IR = 1; break;	/* Less or Greater */
+				case 3: if (XR & 1) IR = 1; break;		/* Unordered or Less */
+				case 4: if (XR == 1) IR = 1; break;		/* Less */
+				case 5: if (XR & 2) IR = 1; break;		/* Unordered or Greater */
+				case 6: if (XR == 2) IR = 1; break;		/* Greater */
+				case 7: if (XR == 3) IR = 1; break;		/* Unordered */
+				}
+				if ((insn >> 14) & 8)
+					IR ^= 1;
+				break;
+			case FMOVQI:
+			case FMOVQX:
+				/* fmovq %[ix]cc, %fY, %fZ */
+				XR = regs->tstate >> 32;
+				if ((insn >> 5) & 0x80)
+					XR >>= 4;
+				XR &= 0xf;
+				IR = 0;
+				freg = ((XR >> 2) ^ XR) & 2;
+				switch ((insn >> 14) & 0x7) {
+				/* case 0: IR = 0; break; */			/* Never */
+				case 1: if (XR & 4) IR = 1; break;		/* Equal */
+				case 2: if ((XR & 4) || freg) IR = 1; break;	/* Less or Equal */
+				case 3: if (freg) IR = 1; break;		/* Less */
+				case 4: if (XR & 5) IR = 1; break;		/* Less or Equal Unsigned */
+				case 5: if (XR & 1) IR = 1; break;		/* Carry Set */
+				case 6: if (XR & 8) IR = 1; break;		/* Negative */
+				case 7: if (XR & 2) IR = 1; break;		/* Overflow Set */
+				}
+				if ((insn >> 14) & 8)
+					IR ^= 1;
+				break;
+			case FMOVQZ:
+			case FMOVQLE:
+			case FMOVQLZ:
+			case FMOVQNZ:
+			case FMOVQGZ:
+			case FMOVQGE:
+				freg = (insn >> 14) & 0x1f;
+				if (!freg)
+					XR = 0;
+				else if (freg < 16)
+					XR = regs->u_regs[freg];
+				else if (current->tss.flags & SPARC_FLAG_32BIT) {
+					struct reg_window32 *win32;
+					flushw_user ();
+					win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
+					get_user(XR, &win32->locals[freg - 16]);
+				} else {
+					struct reg_window *win;
+					flushw_user ();
+					win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
+					get_user(XR, &win->locals[freg - 16]);
+				}
+				IR = 0;
+				switch ((insn >> 10) & 3) {
+				case 1: if (!XR) IR = 1; break;			/* Register Zero */
+				case 2: if (XR <= 0) IR = 1; break;		/* Register Less Than or Equal to Zero */
+				case 3: if (XR < 0) IR = 1; break;		/* Register Less Than Zero */
+				}
+				if ((insn >> 10) & 4)
+					IR ^= 1;
+				break;
+			}
+			if (IR == 0) {
+				/* The fmov test was false. Do a nop instead */
+				current->tss.xfsr[0] &= ~(FSR_CEXC_MASK);
+				regs->tpc = regs->tnpc;
+				regs->tnpc += 4;
+				return 1;
+			} else if (IR == 1) {
+				/* Change the instruction into plain fmovq */
+				insn = (insn & 0x3e00001f) | 0x81a00060;
+				TYPE(3,3,0,3,0,0,0); 
 			}
 		}
 	}
 	if (type) {
-		void *rs1 = NULL, *rs2 = NULL, *rd = NULL;
+		argp rs1 = NULL, rs2 = NULL, rd = NULL;
 		
 		freg = (current->tss.xfsr[0] >> 14) & 0xf;
-		if (freg != (type >> 8))
+		if (freg != (type >> 9))
 			goto err;
 		current->tss.xfsr[0] &= ~0x1c000;
 		freg = ((insn >> 14) & 0x1f);
@@ -221,34 +330,43 @@
 				goto err;
 			}
 		case 2: freg = ((freg & 1) << 5) | (freg & 0x1e);
-		case 1: rs1 = (void *)&f->regs[freg]; 
+		case 1: rs1 = (argp)&f->regs[freg];
 			flags = (freg < 32) ? FPRS_DL : FPRS_DU; 
 			if (!(current->tss.fpsaved[0] & flags))
-				rs1 = (void *)&zero;
+				rs1 = (argp)&zero;
 			break;
 		}
+		switch (type & 0x7) {
+		case 7: FP_UNPACK_QP (QA, rs1); break;
+		case 6: FP_UNPACK_DP (DA, rs1); break;
+		case 5: FP_UNPACK_SP (SA, rs1); break;
+		}
 		freg = (insn & 0x1f);
-		switch ((type >> 2) & 0x3) {
+		switch ((type >> 3) & 0x3) {
 		case 3: if (freg & 2) {
 				current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
 				goto err;
 			}
 		case 2: freg = ((freg & 1) << 5) | (freg & 0x1e);
-		case 1: rs2 = (void *)&f->regs[freg];
+		case 1: rs2 = (argp)&f->regs[freg];
 			flags = (freg < 32) ? FPRS_DL : FPRS_DU; 
 			if (!(current->tss.fpsaved[0] & flags))
-				rs2 = (void *)&zero;
+				rs2 = (argp)&zero;
 			break;
 		}
+		switch ((type >> 3) & 0x7) {
+		case 7: FP_UNPACK_QP (QB, rs2); break;
+		case 6: FP_UNPACK_DP (DB, rs2); break;
+		case 5: FP_UNPACK_SP (SB, rs2); break;
+		}
 		freg = ((insn >> 25) & 0x1f);
-		switch ((type >> 4) & 0x3) {
-		case 0: rd = (void *)(((long)&current->tss.xfsr[0]) | (freg & 3)); break;
+		switch ((type >> 6) & 0x3) {
 		case 3: if (freg & 2) {
 				current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
 				goto err;
 			}
 		case 2: freg = ((freg & 1) << 5) | (freg & 0x1e);
-		case 1: rd = (void *)&f->regs[freg];
+		case 1: rd = (argp)&f->regs[freg];
 			flags = (freg < 32) ? FPRS_DL : FPRS_DU; 
 			if (!(current->tss.fpsaved[0] & FPRS_FEF)) {
 				current->tss.fpsaved[0] = FPRS_FEF;
@@ -263,9 +381,87 @@
 			current->tss.fpsaved[0] |= flags;
 			break;
 		}
-		flags = func(rd, rs2, rs1);
-		if(flags != 0)
-			return record_exception(regs, flags);
+		switch ((insn >> 5) & 0x1ff) {
+		/* + */
+		case FADDS: FP_ADD_S (SR, SA, SB); break;
+		case FADDD: FP_ADD_D (DR, DA, DB); break;
+		case FADDQ: FP_ADD_Q (QR, QA, QB); break;
+		/* - */
+		case FSUBS: FP_SUB_S (SR, SA, SB); break;
+		case FSUBD: FP_SUB_D (DR, DA, DB); break;
+		case FSUBQ: FP_SUB_Q (QR, QA, QB); break;
+		/* * */
+		case FMULS: FP_MUL_S (SR, SA, SB); break;
+		case FSMULD: FP_CONV (D, S, 1, 1, DA, SA);
+			     FP_CONV (D, S, 1, 1, DB, SB);
+		case FMULD: FP_MUL_D (DR, DA, DB); break;
+		case FDMULQ: FP_CONV (Q, D, 2, 1, QA, DA);
+			     FP_CONV (Q, D, 2, 1, QB, DB);
+		case FMULQ: FP_MUL_Q (QR, QA, QB); break;
+		/* / */
+		case FDIVS: FP_DIV_S (SR, SA, SB); break;
+		case FDIVD: FP_DIV_D (DR, DA, DB); break;
+		case FDIVQ: FP_DIV_Q (QR, QA, QB); break;
+		/* sqrt */
+		case FSQRTS: FP_SQRT_S (SR, SB); break;
+		case FSQRTD: FP_SQRT_D (DR, DB); break;
+		case FSQRTQ: FP_SQRT_Q (QR, QB); break;
+		/* mov */
+		case FMOVQ: rd->q[0] = rs2->q[0]; rd->q[1] = rs2->q[1]; break;
+		case FABSQ: rd->q[0] = rs2->q[0] & 0x7fffffffffffffffUL; rd->q[1] = rs2->q[1]; break;
+		case FNEGQ: rd->q[0] = rs2->q[0] ^ 0x8000000000000000UL; rd->q[1] = rs2->q[1]; break;
+		/* float to int */
+		case FSTOI: FP_TO_INT_S (IR, SB, 32, 1); break;
+		case FDTOI: FP_TO_INT_D (IR, DB, 32, 1); break;
+		case FQTOI: FP_TO_INT_Q (IR, QB, 32, 1); break;
+		case FSTOX: FP_TO_INT_S (XR, SB, 64, 1); break;
+		case FDTOX: FP_TO_INT_D (XR, DB, 64, 1); break;
+		case FQTOX: FP_TO_INT_Q (XR, QB, 64, 1); break;
+		/* int to float */
+		case FITOQ: IR = rs2->s; FP_FROM_INT_Q (QR, IR, 32, int); break;
+		case FXTOQ: XR = rs2->d; FP_FROM_INT_Q (QR, XR, 64, long); break;
+		/* float to float */
+		case FSTOD: FP_CONV (D, S, 1, 1, DR, SB); break;
+		case FSTOQ: FP_CONV (Q, S, 2, 1, QR, SB); break;
+		case FDTOQ: FP_CONV (Q, D, 2, 1, QR, DB); break;
+		case FDTOS: FP_CONV (S, D, 1, 1, SR, DB); break;
+		case FQTOS: FP_CONV (S, Q, 1, 2, SR, QB); break;
+		case FQTOD: FP_CONV (D, Q, 1, 2, DR, QB); break;
+		/* comparison */
+		case FCMPQ:
+		case FCMPEQ:
+			FP_UNPACK_RAW_QP (QA, rs1);
+			FP_UNPACK_RAW_QP (QB, rs2);
+			FP_CMP_Q(XR, QB, QA, 3);
+			if (XR == 3 &&
+			    (((insn >> 5) & 0x1ff) == FCMPEQ ||
+			     FP_ISSIGNAN_Q(QA) ||
+			     FP_ISSIGNAN_Q(QB)))
+				FP_SET_EXCEPTION (FP_EX_INVALID);
+		}
+		if (!FP_INHIBIT_RESULTS) {
+			switch ((type >> 6) & 0x7) {
+			case 0: xfsr = current->tss.xfsr[0];
+				if (XR == -1) XR = 2;
+				switch (freg & 3) {
+				/* fcc0, 1, 2, 3 */
+				case 0: xfsr &= ~0xc00; xfsr |= (XR << 10); break;
+				case 1: xfsr &= ~0x300000000UL; xfsr |= (XR << 32); break;
+				case 2: xfsr &= ~0xc00000000UL; xfsr |= (XR << 34); break;
+				case 3: xfsr &= ~0x3000000000UL; xfsr |= (XR << 36); break;
+				}
+				current->tss.xfsr[0] = xfsr;
+				break;
+			case 1: rd->s = IR; break;
+			case 2: rd->d = XR; break;
+			case 5: FP_PACK_SP (rd, SR); break;
+			case 6: FP_PACK_DP (rd, DR); break;
+			case 7: FP_PACK_QP (rd, QR); break;
+			}
+		}
+
+		if(_fex != 0)
+			return record_exception(regs, _fex);
 
 		/* Success and no exceptions detected. */
 		current->tss.xfsr[0] &= ~(FSR_CEXC_MASK);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/op-1.h linux.14p16/arch/sparc64/math-emu/op-1.h
--- linux.vanilla/arch/sparc64/math-emu/op-1.h	Mon Jan 12 23:15:44 1998
+++ linux.14p16/arch/sparc64/math-emu/op-1.h	Thu Jan  1 01:00:00 1970
@@ -1,245 +0,0 @@
-/*
- * Basic one-word fraction declaration and manipulation.
- */
-
-#define _FP_FRAC_DECL_1(X)	_FP_W_TYPE X##_f
-#define _FP_FRAC_COPY_1(D,S)	(D##_f = S##_f)
-#define _FP_FRAC_SET_1(X,I)	(X##_f = I)
-#define _FP_FRAC_HIGH_1(X)	(X##_f)
-#define _FP_FRAC_LOW_1(X)	(X##_f)
-#define _FP_FRAC_WORD_1(X,w)	(X##_f)
-
-#define _FP_FRAC_ADDI_1(X,I)	(X##_f += I)
-#define _FP_FRAC_SLL_1(X,N)			\
-  do {						\
-    if (__builtin_constant_p(N) && (N) == 1)	\
-      X##_f += X##_f;				\
-    else					\
-      X##_f <<= (N);				\
-  } while (0)
-#define _FP_FRAC_SRL_1(X,N)	(X##_f >>= N)
-
-/* Right shift with sticky-lsb.  */
-#define _FP_FRAC_SRS_1(X,N,sz)	__FP_FRAC_SRS_1(X##_f, N, sz)
-
-#define __FP_FRAC_SRS_1(X,N,sz)						\
-   (X = (X >> (N) | (__builtin_constant_p(N) && (N) == 1		\
-		     ? X & 1 : (X << (_FP_W_TYPE_SIZE - (N))) != 0)))
-
-#define _FP_FRAC_ADD_1(R,X,Y)	(R##_f = X##_f + Y##_f)
-#define _FP_FRAC_SUB_1(R,X,Y)	(R##_f = X##_f - Y##_f)
-#define _FP_FRAC_CLZ_1(z, X)	__FP_CLZ(z, X##_f)
-
-/* Predicates */
-#define _FP_FRAC_NEGP_1(X)	((_FP_WS_TYPE)X##_f < 0)
-#define _FP_FRAC_ZEROP_1(X)	(X##_f == 0)
-#define _FP_FRAC_OVERP_1(fs,X)	(X##_f & _FP_OVERFLOW_##fs)
-#define _FP_FRAC_EQ_1(X, Y)	(X##_f == Y##_f)
-#define _FP_FRAC_GE_1(X, Y)	(X##_f >= Y##_f)
-#define _FP_FRAC_GT_1(X, Y)	(X##_f > Y##_f)
-
-#define _FP_ZEROFRAC_1		0
-#define _FP_MINFRAC_1		1
-
-/*
- * Unpack the raw bits of a native fp value.  Do not classify or
- * normalize the data.
- */
-
-#define _FP_UNPACK_RAW_1(fs, X, val)				\
-  do {								\
-    union _FP_UNION_##fs _flo; _flo.flt = (val);		\
-								\
-    X##_f = _flo.bits.frac;					\
-    X##_e = _flo.bits.exp;					\
-    X##_s = _flo.bits.sign;					\
-  } while (0)
-
-
-/*
- * Repack the raw bits of a native fp value.
- */
-
-#define _FP_PACK_RAW_1(fs, val, X)				\
-  do {								\
-    union _FP_UNION_##fs _flo;					\
-								\
-    _flo.bits.frac = X##_f;					\
-    _flo.bits.exp  = X##_e;					\
-    _flo.bits.sign = X##_s;					\
-								\
-    (val) = _flo.flt;						\
-  } while (0)
-
-
-/*
- * Multiplication algorithms:
- */
-
-/* Basic.  Assuming the host word size is >= 2*FRACBITS, we can do the
-   multiplication immediately.  */
-
-#define _FP_MUL_MEAT_1_imm(fs, R, X, Y)					\
-  do {									\
-    R##_f = X##_f * Y##_f;						\
-    /* Normalize since we know where the msb of the multiplicands	\
-       were (bit B), we know that the msb of the of the product is	\
-       at either 2B or 2B-1.  */					\
-    _FP_FRAC_SRS_1(R, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs);	\
-  } while (0)
-
-/* Given a 1W * 1W => 2W primitive, do the extended multiplication.  */
-
-#define _FP_MUL_MEAT_1_wide(fs, R, X, Y, doit)				\
-  do {									\
-    _FP_W_TYPE _Z_f0, _Z_f1;						\
-    doit(_Z_f1, _Z_f0, X##_f, Y##_f);					\
-    /* Normalize since we know where the msb of the multiplicands	\
-       were (bit B), we know that the msb of the of the product is	\
-       at either 2B or 2B-1.  */					\
-    _FP_FRAC_SRS_2(_Z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs);	\
-    R##_f = _Z_f0;							\
-  } while (0)
-
-/* Finally, a simple widening multiply algorithm.  What fun!  */
-
-#define _FP_MUL_MEAT_1_hard(fs, R, X, Y)				\
-  do {									\
-    _FP_W_TYPE _xh, _xl, _yh, _yl, _z_f0, _z_f1, _a_f0, _a_f1;		\
-									\
-    /* split the words in half */					\
-    _xh = X##_f >> (_FP_W_TYPE_SIZE/2);					\
-    _xl = X##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1);		\
-    _yh = Y##_f >> (_FP_W_TYPE_SIZE/2);					\
-    _yl = Y##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1);		\
-									\
-    /* multiply the pieces */						\
-    _z_f0 = _xl * _yl;							\
-    _a_f0 = _xh * _yl;							\
-    _a_f1 = _xl * _yh;							\
-    _z_f1 = _xh * _yh;							\
-									\
-    /* reassemble into two full words */				\
-    if ((_a_f0 += _a_f1) < _a_f1)					\
-      _z_f1 += (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2);			\
-    _a_f1 = _a_f0 >> (_FP_W_TYPE_SIZE/2);				\
-    _a_f0 = _a_f0 << (_FP_W_TYPE_SIZE/2);				\
-    _FP_FRAC_ADD_2(_z, _z, _a);						\
-									\
-    /* normalize */							\
-    _FP_FRAC_SRS_2(_z, _FP_WFRACBITS_##fs - 1, 2*_FP_WFRACBITS_##fs);	\
-    R##_f = _z_f0;							\
-  } while (0)
-
-
-/*
- * Division algorithms:
- */
-
-/* Basic.  Assuming the host word size is >= 2*FRACBITS, we can do the
-   division immediately.  Give this macro either _FP_DIV_HELP_imm for
-   C primitives or _FP_DIV_HELP_ldiv for the ISO function.  Which you
-   choose will depend on what the compiler does with divrem4.  */
-
-#define _FP_DIV_MEAT_1_imm(fs, R, X, Y, doit)		\
-  do {							\
-    _FP_W_TYPE _q, _r;					\
-    X##_f <<= (X##_f < Y##_f				\
-	       ? R##_e--, _FP_WFRACBITS_##fs		\
-	       : _FP_WFRACBITS_##fs - 1);		\
-    doit(_q, _r, X##_f, Y##_f);				\
-    R##_f = _q | (_r != 0);				\
-  } while (0)
-
-/* GCC's longlong.h defines a 2W / 1W => (1W,1W) primitive udiv_qrnnd
-   that may be useful in this situation.  This first is for a primitive
-   that requires normalization, the second for one that does not.  Look
-   for UDIV_NEEDS_NORMALIZATION to tell which your machine needs.  */
-
-#define _FP_DIV_MEAT_1_udiv_norm(fs, R, X, Y)				\
-  do {									\
-    _FP_W_TYPE _nh, _nl, _q, _r;					\
-									\
-    /* Normalize Y -- i.e. make the most significant bit set.  */	\
-    Y##_f <<= _FP_WFRACXBITS_##fs - 1;					\
-									\
-    /* Shift X op correspondingly high, that is, up one full word.  */	\
-    if (X##_f <= Y##_f)							\
-      {									\
-	_nl = 0;							\
-	_nh = X##_f;							\
-      }									\
-    else								\
-      {									\
-	R##_e++;							\
-	_nl = X##_f << (_FP_W_TYPE_SIZE-1);				\
-	_nh = X##_f >> 1;						\
-      }									\
-    									\
-    udiv_qrnnd(_q, _r, _nh, _nl, Y##_f);				\
-    R##_f = _q | (_r != 0);						\
-  } while (0)
-
-#define _FP_DIV_MEAT_1_udiv(fs, R, X, Y)		\
-  do {							\
-    _FP_W_TYPE _nh, _nl, _q, _r;			\
-    if (X##_f < Y##_f)					\
-      {							\
-	R##_e--;					\
-	_nl = X##_f << _FP_WFRACBITS_##fs;		\
-	_nh = X##_f >> _FP_WFRACXBITS_##fs;		\
-      }							\
-    else						\
-      {							\
-	_nl = X##_f << (_FP_WFRACBITS_##fs - 1);	\
-	_nh = X##_f >> (_FP_WFRACXBITS_##fs + 1);	\
-      }							\
-    udiv_qrnnd(_q, _r, _nh, _nl, Y##_f);		\
-    R##_f = _q | (_r != 0);				\
-  } while (0)
-  
-  
-/*
- * Square root algorithms:
- * We have just one right now, maybe Newton approximation
- * should be added for those machines where division is fast.
- */
- 
-#define _FP_SQRT_MEAT_1(R, S, T, X, q)			\
-  do {							\
-    while (q)						\
-      {							\
-        T##_f = S##_f + q;				\
-        if (T##_f <= X##_f)				\
-          {						\
-            S##_f = T##_f + q;				\
-            X##_f -= T##_f;				\
-            R##_f += q;					\
-          }						\
-        _FP_FRAC_SLL_1(X, 1);				\
-        q >>= 1;					\
-      }							\
-  } while (0)
-
-/*
- * Assembly/disassembly for converting to/from integral types.  
- * No shifting or overflow handled here.
- */
-
-#define _FP_FRAC_ASSEMBLE_1(r, X, rsize)	(r = X##_f)
-#define _FP_FRAC_DISASSEMBLE_1(X, r, rsize)	(X##_f = r)
-
-
-/*
- * Convert FP values between word sizes
- */
-
-#define _FP_FRAC_CONV_1_1(dfs, sfs, D, S)				\
-  do {									\
-    D##_f = S##_f;							\
-    if (_FP_WFRACBITS_##sfs > _FP_WFRACBITS_##dfs)			\
-      _FP_FRAC_SRS_1(D, (_FP_WFRACBITS_##sfs-_FP_WFRACBITS_##dfs),	\
-		     _FP_WFRACBITS_##sfs);				\
-    else								\
-      D##_f <<= _FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs;		\
-  } while (0)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/op-2.h linux.14p16/arch/sparc64/math-emu/op-2.h
--- linux.vanilla/arch/sparc64/math-emu/op-2.h	Sat Aug 28 20:00:54 1999
+++ linux.14p16/arch/sparc64/math-emu/op-2.h	Thu Jan  1 01:00:00 1970
@@ -1,433 +0,0 @@
-/*
- * Basic two-word fraction declaration and manipulation.
- */
-
-#define _FP_FRAC_DECL_2(X)	_FP_W_TYPE X##_f0, X##_f1
-#define _FP_FRAC_COPY_2(D,S)	(D##_f0 = S##_f0, D##_f1 = S##_f1)
-#define _FP_FRAC_SET_2(X,I)	__FP_FRAC_SET_2(X, I)
-#define _FP_FRAC_HIGH_2(X)	(X##_f1)
-#define _FP_FRAC_LOW_2(X)	(X##_f0)
-#define _FP_FRAC_WORD_2(X,w)	(X##_f##w)
-
-#define _FP_FRAC_SLL_2(X,N)						\
-  do {									\
-    if ((N) < _FP_W_TYPE_SIZE)						\
-      {									\
-        if (__builtin_constant_p(N) && (N) == 1) 			\
-          {								\
-            X##_f1 = X##_f1 + X##_f1 + (((_FP_WS_TYPE)(X##_f0)) < 0);	\
-            X##_f0 += X##_f0;						\
-          }								\
-        else								\
-          {								\
-	    X##_f1 = X##_f1 << (N) | X##_f0 >> (_FP_W_TYPE_SIZE - (N));	\
-	    X##_f0 <<= (N);						\
-	  }								\
-      }									\
-    else								\
-      {									\
-	X##_f1 = X##_f0 << ((N) - _FP_W_TYPE_SIZE);			\
-	X##_f0 = 0;							\
-      }									\
-  } while (0)
-
-#define _FP_FRAC_SRL_2(X,N)						\
-  do {									\
-    if ((N) < _FP_W_TYPE_SIZE)						\
-      {									\
-	X##_f0 = X##_f0 >> (N) | X##_f1 << (_FP_W_TYPE_SIZE - (N));	\
-	X##_f1 >>= (N);							\
-      }									\
-    else								\
-      {									\
-	X##_f0 = X##_f1 >> ((N) - _FP_W_TYPE_SIZE);			\
-	X##_f1 = 0;							\
-      }									\
-  } while (0)
-
-/* Right shift with sticky-lsb.  */
-#define _FP_FRAC_SRS_2(X,N,sz)						\
-  do {									\
-    if ((N) < _FP_W_TYPE_SIZE)						\
-      {									\
-	X##_f0 = (X##_f1 << (_FP_W_TYPE_SIZE - (N)) | X##_f0 >> (N) |	\
-		  (__builtin_constant_p(N) && (N) == 1			\
-		   ? X##_f0 & 1						\
-		   : (X##_f0 << (_FP_W_TYPE_SIZE - (N))) != 0));	\
-	X##_f1 >>= (N);							\
-      }									\
-    else								\
-      {									\
-	X##_f0 = (X##_f1 >> ((N) - _FP_W_TYPE_SIZE) |			\
-	          (((X##_f1 << (sz - (N))) | X##_f0) != 0));		\
-	X##_f1 = 0;							\
-      }									\
-  } while (0)
-
-#define _FP_FRAC_ADDI_2(X,I) \
-  __FP_FRAC_ADDI_2(X##_f1, X##_f0, I)
-
-#define _FP_FRAC_ADD_2(R,X,Y) \
-  __FP_FRAC_ADD_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0)
-
-#define _FP_FRAC_SUB_2(R,X,Y) \
-  __FP_FRAC_SUB_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0)
-
-#define _FP_FRAC_CLZ_2(R,X)	\
-  do {				\
-    if (X##_f1)			\
-      __FP_CLZ(R,X##_f1);	\
-    else 			\
-    {				\
-      __FP_CLZ(R,X##_f0);	\
-      R += _FP_W_TYPE_SIZE;	\
-    }				\
-  } while(0)
-
-/* Predicates */
-#define _FP_FRAC_NEGP_2(X)	((_FP_WS_TYPE)X##_f1 < 0)
-#define _FP_FRAC_ZEROP_2(X)	((X##_f1 | X##_f0) == 0)
-#define _FP_FRAC_OVERP_2(fs,X)	(X##_f1 & _FP_OVERFLOW_##fs)
-#define _FP_FRAC_EQ_2(X, Y)	(X##_f1 == Y##_f1 && X##_f0 == Y##_f0)
-#define _FP_FRAC_GT_2(X, Y)	\
-  (X##_f1 > Y##_f1 || (X##_f1 == Y##_f1 && X##_f0 > Y##_f0))
-#define _FP_FRAC_GE_2(X, Y)	\
-  (X##_f1 > Y##_f1 || (X##_f1 == Y##_f1 && X##_f0 >= Y##_f0))
-
-#define _FP_ZEROFRAC_2		0, 0
-#define _FP_MINFRAC_2		0, 1
-
-/*
- * Internals 
- */
-
-#define __FP_FRAC_SET_2(X,I1,I0)	(X##_f0 = I0, X##_f1 = I1)
-
-#define __FP_CLZ_2(R, xh, xl)	\
-  do {				\
-    if (xh)			\
-      __FP_CLZ(R,xl);		\
-    else 			\
-    {				\
-      __FP_CLZ(R,xl);		\
-      R += _FP_W_TYPE_SIZE;	\
-    }				\
-  } while(0)
-
-#if 0
-
-#ifndef __FP_FRAC_ADDI_2
-#define __FP_FRAC_ADDI_2(xh, xl, i) \
-  (xh += ((xl += i) < i))
-#endif
-#ifndef __FP_FRAC_ADD_2
-#define __FP_FRAC_ADD_2(rh, rl, xh, xl, yh, yl) \
-  (rh = xh + yh + ((rl = xl + yl) < xl))
-#endif
-#ifndef __FP_FRAC_SUB_2
-#define __FP_FRAC_SUB_2(rh, rl, xh, xl, yh, yl) \
-  (rh = xh - yh - ((rl = xl - yl) > xl))
-#endif
-
-#else
-
-#undef __FP_FRAC_ADDI_2
-#define __FP_FRAC_ADDI_2(xh, xl, i)	add_ssaaaa(xh, xl, xh, xl, 0, i)
-#undef __FP_FRAC_ADD_2
-#define __FP_FRAC_ADD_2			add_ssaaaa
-#undef __FP_FRAC_SUB_2
-#define __FP_FRAC_SUB_2			sub_ddmmss
-
-#endif
-
-/*
- * Unpack the raw bits of a native fp value.  Do not classify or
- * normalize the data.
- */
-
-#define _FP_UNPACK_RAW_2(fs, X, val)			\
-  do {							\
-    union _FP_UNION_##fs _flo; _flo.flt = (val);	\
-							\
-    X##_f0 = _flo.bits.frac0;				\
-    X##_f1 = _flo.bits.frac1;				\
-    X##_e  = _flo.bits.exp;				\
-    X##_s  = _flo.bits.sign;				\
-  } while (0)
-
-
-/*
- * Repack the raw bits of a native fp value.
- */
-
-#define _FP_PACK_RAW_2(fs, val, X)			\
-  do {							\
-    union _FP_UNION_##fs _flo;				\
-							\
-    _flo.bits.frac0 = X##_f0;				\
-    _flo.bits.frac1 = X##_f1;				\
-    _flo.bits.exp   = X##_e;				\
-    _flo.bits.sign  = X##_s;				\
-							\
-    (val) = _flo.flt;					\
-  } while (0)
-
-
-/*
- * Multiplication algorithms:
- */
-
-/* Given a 1W * 1W => 2W primitive, do the extended multiplication.  */
-
-#define _FP_MUL_MEAT_2_wide(fs, R, X, Y, doit)				\
-  do {									\
-    _FP_FRAC_DECL_4(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c);	\
-									\
-    doit(_FP_FRAC_WORD_4(_z,1), _FP_FRAC_WORD_4(_z,0), X##_f0, Y##_f0); \
-    doit(_b_f1, _b_f0, X##_f0, Y##_f1);					\
-    doit(_c_f1, _c_f0, X##_f1, Y##_f0);					\
-    doit(_FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2), X##_f1, Y##_f1); \
-									\
-    __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),	\
-		    _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0),	\
-		    0, _b_f1, _b_f0, 0,					\
-		    _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),	\
-		    _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0));	\
-    __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),	\
-		    _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0),	\
-		    0, _c_f1, _c_f0, 0,					\
-		    _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),	\
-		    _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0));	\
-									\
-    /* Normalize since we know where the msb of the multiplicands	\
-       were (bit B), we know that the msb of the of the product is	\
-       at either 2B or 2B-1.  */					\
-    _FP_FRAC_SRS_4(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs);	\
-    R##_f0 = _FP_FRAC_WORD_4(_z,0);					\
-    R##_f1 = _FP_FRAC_WORD_4(_z,1);					\
-  } while (0)
-
-/* This next macro appears to be totally broken. Fortunately nowhere
- * seems to use it :-> The problem is that we define _z[4] but
- * then use it in _FP_FRAC_SRS_4, which will attempt to access
- * _z_f[n] which will cause an error. The fix probably involves 
- * declaring it with _FP_FRAC_DECL_4, see previous macro. -- PMM 02/1998 
- */
-#define _FP_MUL_MEAT_2_gmp(fs, R, X, Y)					\
-  do {									\
-    _FP_W_TYPE _x[2], _y[2], _z[4];					\
-    _x[0] = X##_f0; _x[1] = X##_f1;					\
-    _y[0] = Y##_f0; _y[1] = Y##_f1;					\
-									\
-    mpn_mul_n(_z, _x, _y, 2);						\
-									\
-    /* Normalize since we know where the msb of the multiplicands	\
-       were (bit B), we know that the msb of the of the product is	\
-       at either 2B or 2B-1.  */					\
-    _FP_FRAC_SRS_4(_z, _FP_WFRACBITS##_fs-1, 2*_FP_WFRACBITS_##fs);	\
-    R##_f0 = _z[0];							\
-    R##_f1 = _z[1];							\
-  } while (0)
-
-
-/*
- * Division algorithms:
- * This seems to be giving me difficulties -- PMM 
- * Look, NetBSD seems to be able to comment algorithms. Can't you?
- * I've thrown printks at the problem.
- * This now appears to work, but I still don't really know why.
- * Also, I don't think the result is properly normalised...
- */
-
-#define _FP_DIV_MEAT_2_udiv_64(fs, R, X, Y)				\
-  do {									\
-    extern void _fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2],	\
-			       _FP_W_TYPE n1, _FP_W_TYPE n0,		\
-			       _FP_W_TYPE d1, _FP_W_TYPE d0);		\
-    _FP_W_TYPE _n_f3, _n_f2, _n_f1, _n_f0, _r_f1, _r_f0;		\
-    _FP_W_TYPE _q_f1, _q_f0, _m_f1, _m_f0;				\
-    _FP_W_TYPE _rmem[2], _qmem[2];					\
-    /* I think this check is to ensure that the result is normalised.   \
-     * Assuming X,Y normalised (ie in [1.0,2.0)) X/Y will be in         \
-     * [0.5,2.0). Furthermore, it will be less than 1.0 iff X < Y.      \
-     * In this case we tweak things. (this is based on comments in      \
-     * the NetBSD FPU emulation code. )                                 \
-     * We know X,Y are normalised because we ensure this as part of     \
-     * the unpacking process. -- PMM                                    \
-     */									\
-    if (_FP_FRAC_GT_2(X, Y))						\
-      {									\
-/*	R##_e++; */							\
-	_n_f3 = X##_f1 >> 1;						\
-	_n_f2 = X##_f1 << (_FP_W_TYPE_SIZE - 1) | X##_f0 >> 1;		\
-	_n_f1 = X##_f0 << (_FP_W_TYPE_SIZE - 1);			\
-	_n_f0 = 0;							\
-      }									\
-    else								\
-      {									\
-	R##_e--;							\
-	_n_f3 = X##_f1;							\
-	_n_f2 = X##_f0;							\
-	_n_f1 = _n_f0 = 0;						\
-      }									\
-									\
-    /* Normalize, i.e. make the most significant bit of the 		\
-       denominator set.  CHANGED: - 1 to nothing -- PMM */		\
-    _FP_FRAC_SLL_2(Y, _FP_WFRACXBITS_##fs /* -1 */);			\
-									\
-    /* Do the 256/128 bit division given the 128-bit _fp_udivmodtf4 	\
-       primitive snagged from libgcc2.c.  */				\
-									\
-    _fp_udivmodti4(_qmem, _rmem, _n_f3, _n_f2, 0, Y##_f1);		\
-    _q_f1 = _qmem[0];							\
-    umul_ppmm(_m_f1, _m_f0, _q_f1, Y##_f0);				\
-    _r_f1 = _rmem[0];							\
-    _r_f0 = _n_f1;							\
-    if (_FP_FRAC_GT_2(_m, _r))						\
-      {									\
-	_q_f1--;							\
-	_FP_FRAC_ADD_2(_r, _r, Y);					\
-	if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r))		\
-	  {								\
-	    _q_f1--;							\
-	    _FP_FRAC_ADD_2(_r, _r, Y);					\
-	  }								\
-      }									\
-    _FP_FRAC_SUB_2(_r, _r, _m);						\
-									\
-    _fp_udivmodti4(_qmem, _rmem, _r_f1, _r_f0, 0, Y##_f1);		\
-    _q_f0 = _qmem[0];							\
-    umul_ppmm(_m_f1, _m_f0, _q_f0, Y##_f0);				\
-    _r_f1 = _rmem[0];							\
-    _r_f0 = _n_f0;							\
-    if (_FP_FRAC_GT_2(_m, _r))						\
-      {									\
-	_q_f0--;							\
-	_FP_FRAC_ADD_2(_r, _r, Y);					\
-	if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r))		\
-	  {								\
-	    _q_f0--;							\
-	    _FP_FRAC_ADD_2(_r, _r, Y);					\
-	  }								\
-      }									\
-    _FP_FRAC_SUB_2(_r, _r, _m);						\
-									\
-    R##_f1 = _q_f1;							\
-    R##_f0 = _q_f0 | ((_r_f1 | _r_f0) != 0);				\
-    /* adjust so answer is normalized again. I'm not sure what the 	\
-     * final sz param should be. In practice it's never used since      \
-     * N is 1 which is always going to be < _FP_W_TYPE_SIZE...		\
-     */									\
-    /* _FP_FRAC_SRS_2(R,1,_FP_WFRACBITS_##fs);	*/			\
-  } while (0)
-
-
-#define _FP_DIV_MEAT_2_gmp(fs, R, X, Y)					\
-  do {									\
-    _FP_W_TYPE _x[4], _y[2], _z[4];					\
-    _y[0] = Y##_f0; _y[1] = Y##_f1;					\
-    _x[0] = _x[3] = 0;							\
-    if (_FP_FRAC_GT_2(X, Y))						\
-      {									\
-	R##_e++;							\
-	_x[1] = (X##_f0 << (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE) |	\
-		 X##_f1 >> (_FP_W_TYPE_SIZE -				\
-			    (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE)));	\
-	_x[2] = X##_f1 << (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE);		\
-      }									\
-    else								\
-      {									\
-	_x[1] = (X##_f0 << (_FP_WFRACBITS - _FP_W_TYPE_SIZE) |		\
-		 X##_f1 >> (_FP_W_TYPE_SIZE -				\
-			    (_FP_WFRACBITS - _FP_W_TYPE_SIZE)));	\
-	_x[2] = X##_f1 << (_FP_WFRACBITS - _FP_W_TYPE_SIZE);		\
-      }									\
-									\
-    (void) mpn_divrem (_z, 0, _x, 4, _y, 2);				\
-    R##_f1 = _z[1];							\
-    R##_f0 = _z[0] | ((_x[0] | _x[1]) != 0);				\
-  } while (0)
-
-
-/*
- * Square root algorithms:
- * We have just one right now, maybe Newton approximation
- * should be added for those machines where division is fast.
- */
- 
-#define _FP_SQRT_MEAT_2(R, S, T, X, q)			\
-  do {							\
-    while (q)						\
-      {							\
-        T##_f1 = S##_f1 + q;				\
-        if (T##_f1 <= X##_f1)				\
-          {						\
-            S##_f1 = T##_f1 + q;			\
-            X##_f1 -= T##_f1;				\
-            R##_f1 += q;				\
-          }						\
-        _FP_FRAC_SLL_2(X, 1);				\
-        q >>= 1;					\
-      }							\
-    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);		\
-    while (q)						\
-      {							\
-        T##_f0 = S##_f0 + q;				\
-        T##_f1 = S##_f1;				\
-        if (T##_f1 < X##_f1 || 				\
-            (T##_f1 == X##_f1 && T##_f0 < X##_f0))	\
-          {						\
-            S##_f0 = T##_f0 + q;			\
-            if (((_FP_WS_TYPE)T##_f0) < 0 &&		\
-                ((_FP_WS_TYPE)S##_f0) >= 0)		\
-              S##_f1++;					\
-            _FP_FRAC_SUB_2(X, X, T);			\
-            R##_f0 += q;				\
-          }						\
-        _FP_FRAC_SLL_2(X, 1);				\
-        q >>= 1;					\
-      }							\
-  } while (0)
-
-
-/*
- * Assembly/disassembly for converting to/from integral types.  
- * No shifting or overflow handled here.
- */
-
-#define _FP_FRAC_ASSEMBLE_2(r, X, rsize)	\
-  do {						\
-    if (rsize <= _FP_W_TYPE_SIZE)		\
-      r = X##_f0;				\
-    else					\
-      {						\
-	r = X##_f1;				\
-	r <<= _FP_W_TYPE_SIZE;			\
-	r += X##_f0;				\
-      }						\
-  } while (0)
-
-#define _FP_FRAC_DISASSEMBLE_2(X, r, rsize)				\
-  do {									\
-    X##_f0 = r;								\
-    X##_f1 = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE);	\
-  } while (0)
-
-/*
- * Convert FP values between word sizes
- */
-
-#define _FP_FRAC_CONV_1_2(dfs, sfs, D, S)				\
-  do {									\
-    _FP_FRAC_SRS_2(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),	\
-		   _FP_WFRACBITS_##sfs);				\
-    D##_f = S##_f0;							\
-  } while (0)
-
-#define _FP_FRAC_CONV_2_1(dfs, sfs, D, S)				\
-  do {									\
-    D##_f0 = S##_f;							\
-    D##_f1 = 0;								\
-    _FP_FRAC_SLL_2(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));	\
-  } while (0)
-
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/op-4.h linux.14p16/arch/sparc64/math-emu/op-4.h
--- linux.vanilla/arch/sparc64/math-emu/op-4.h	Wed Apr 15 01:44:21 1998
+++ linux.14p16/arch/sparc64/math-emu/op-4.h	Thu Jan  1 01:00:00 1970
@@ -1,297 +0,0 @@
-/*
- * Basic four-word fraction declaration and manipulation.
- *
- * When adding quadword support for 32 bit machines, we need
- * to be a little careful as double multiply uses some of these
- * macros: (in op-2.h)
- * _FP_MUL_MEAT_2_wide() uses _FP_FRAC_DECL_4, _FP_FRAC_WORD_4,
- * _FP_FRAC_ADD_4, _FP_FRAC_SRS_4
- * _FP_MUL_MEAT_2_gmp() uses _FP_FRAC_SRS_4 (and should use
- * _FP_FRAC_DECL_4: it appears to be broken and is not used 
- * anywhere anyway. )
- *
- * I've now fixed all the macros that were here from the sparc64 code.
- * [*none* of the shift macros were correct!] -- PMM 02/1998
- * 
- * The only quadword stuff that remains to be coded is: 
- * 1) the conversion to/from ints, which requires 
- * that we check (in op-common.h) that the following do the right thing
- * for quadwords: _FP_TO_INT(Q,4,r,X,rsz,rsg), _FP_FROM_INT(Q,4,X,r,rs,rt)
- * 2) multiply, divide and sqrt, which require:
- * _FP_MUL_MEAT_4_*(R,X,Y), _FP_DIV_MEAT_4_*(R,X,Y), _FP_SQRT_MEAT_4(R,S,T,X,q),
- * This also needs _FP_MUL_MEAT_Q and _FP_DIV_MEAT_Q to be defined to
- * some suitable _FP_MUL_MEAT_4_* macros in sfp-machine.h.
- * [we're free to choose whatever FP_MUL_MEAT_4_* macros we need for
- * these; they are used nowhere else. ]
- */
-
-#define _FP_FRAC_DECL_4(X)	_FP_W_TYPE X##_f[4]
-#define _FP_FRAC_COPY_4(D,S)			\
-  (D##_f[0] = S##_f[0], D##_f[1] = S##_f[1],	\
-   D##_f[2] = S##_f[2], D##_f[3] = S##_f[3])
-/* The _FP_FRAC_SET_n(X,I) macro is intended for use with another
- * macro such as _FP_ZEROFRAC_n which returns n comma separated values.
- * The result is that we get an expansion of __FP_FRAC_SET_n(X,I0,I1,I2,I3)
- * which just assigns the In values to the array X##_f[]. 
- * This is why the number of parameters doesn't appear to match
- * at first glance...      -- PMM 
- */
-#define _FP_FRAC_SET_4(X,I)	__FP_FRAC_SET_4(X, I)
-#define _FP_FRAC_HIGH_4(X)	(X##_f[3])
-#define _FP_FRAC_LOW_4(X)	(X##_f[0])
-#define _FP_FRAC_WORD_4(X,w)	(X##_f[w])
-
-#define _FP_FRAC_SLL_4(X,N)						\
-  do {									\
-    _FP_I_TYPE _up, _down, _skip, _i;					\
-    _skip = (N) / _FP_W_TYPE_SIZE;					\
-    _up = (N) % _FP_W_TYPE_SIZE;					\
-    _down = _FP_W_TYPE_SIZE - _up;					\
-    for (_i = 3; _i > _skip; --_i)					\
-      X##_f[_i] = X##_f[_i-_skip] << _up | X##_f[_i-_skip-1] >> _down;	\
-/* bugfixed: was X##_f[_i] <<= _up;  -- PMM 02/1998 */                  \
-    X##_f[_i] = X##_f[0] << _up; 	                                \
-    for (--_i; _i >= 0; --_i)						\
-      X##_f[_i] = 0;							\
-  } while (0)
-
-/* This one was broken too */
-#define _FP_FRAC_SRL_4(X,N)						\
-  do {									\
-    _FP_I_TYPE _up, _down, _skip, _i;					\
-    _skip = (N) / _FP_W_TYPE_SIZE;					\
-    _down = (N) % _FP_W_TYPE_SIZE;					\
-    _up = _FP_W_TYPE_SIZE - _down;					\
-    for (_i = 0; _i < 3-_skip; ++_i)					\
-      X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up;	\
-    X##_f[_i] = X##_f[3] >> _down;			         	\
-    for (++_i; _i < 4; ++_i)						\
-      X##_f[_i] = 0;							\
-  } while (0)
-
-
-/* Right shift with sticky-lsb. 
- * What this actually means is that we do a standard right-shift,
- * but that if any of the bits that fall off the right hand side
- * were one then we always set the LSbit.
- */
-#define _FP_FRAC_SRS_4(X,N,size)					\
-  do {									\
-    _FP_I_TYPE _up, _down, _skip, _i;					\
-    _FP_W_TYPE _s;							\
-    _skip = (N) / _FP_W_TYPE_SIZE;					\
-    _down = (N) % _FP_W_TYPE_SIZE;					\
-    _up = _FP_W_TYPE_SIZE - _down;					\
-    for (_s = _i = 0; _i < _skip; ++_i)					\
-      _s |= X##_f[_i];							\
-    _s |= X##_f[_i] << _up;						\
-/* s is now != 0 if we want to set the LSbit */                         \
-    for (_i = 0; _i < 3-_skip; ++_i)					\
-      X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up;	\
-    X##_f[_i] = X##_f[3] >> _down;					\
-    for (++_i; _i < 4; ++_i)						\
-      X##_f[_i] = 0;							\
-    /* don't fix the LSB until the very end when we're sure f[0] is stable */ \
-    X##_f[0] |= (_s != 0);                                              \
-  } while (0)
-
-#define _FP_FRAC_ADD_4(R,X,Y)						\
-  __FP_FRAC_ADD_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0],		\
-		  X##_f[3], X##_f[2], X##_f[1], X##_f[0],		\
-		  Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
-
-#define _FP_FRAC_SUB_4(R,X,Y)                                           \
-  __FP_FRAC_SUB_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0],		\
-		  X##_f[3], X##_f[2], X##_f[1], X##_f[0],		\
-		  Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
-
-#define _FP_FRAC_ADDI_4(X,I)                                            \
-  __FP_FRAC_ADDI_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], I)
-
-#define _FP_ZEROFRAC_4  0,0,0,0
-#define _FP_MINFRAC_4   0,0,0,1
-
-#define _FP_FRAC_ZEROP_4(X)     ((X##_f[0] | X##_f[1] | X##_f[2] | X##_f[3]) == 0)
-#define _FP_FRAC_NEGP_4(X)      ((_FP_WS_TYPE)X##_f[3] < 0)
-#define _FP_FRAC_OVERP_4(fs,X)  (X##_f[0] & _FP_OVERFLOW_##fs)
-
-#define _FP_FRAC_EQ_4(X,Y)                              \
- (X##_f[0] == Y##_f[0] && X##_f[1] == Y##_f[1]          \
-  && X##_f[2] == Y##_f[2] && X##_f[3] == Y##_f[3])
-
-#define _FP_FRAC_GT_4(X,Y)                              \
- (X##_f[3] > Y##_f[3] ||                                \
-  (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] ||      \
-   (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] ||     \
-    (X##_f[1] == Y##_f[1] && X##_f[0] > Y##_f[0])       \
-   ))                                                   \
-  ))                                                    \
- )
-
-#define _FP_FRAC_GE_4(X,Y)                              \
- (X##_f[3] > Y##_f[3] ||                                \
-  (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] ||      \
-   (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] ||     \
-    (X##_f[1] == Y##_f[1] && X##_f[0] >= Y##_f[0])      \
-   ))                                                   \
-  ))                                                    \
- )
-
-
-#define _FP_FRAC_CLZ_4(R,X)             \
-  do {                                  \
-    if (X##_f[3])                       \
-    {                                   \
-        __FP_CLZ(R,X##_f[3]);           \
-    }                                   \
-    else if (X##_f[2])                  \
-    {                                   \
-        __FP_CLZ(R,X##_f[2]);           \
-        R += _FP_W_TYPE_SIZE;           \
-    }                                   \
-    else if (X##_f[1])                  \
-    {                                   \
-        __FP_CLZ(R,X##_f[2]);           \
-        R += _FP_W_TYPE_SIZE*2;         \
-    }                                   \
-    else                                \
-    {                                   \
-        __FP_CLZ(R,X##_f[0]);           \
-        R += _FP_W_TYPE_SIZE*3;         \
-    }                                   \
-  } while(0)
-
-
-#define _FP_UNPACK_RAW_4(fs, X, val)                            \
-  do {                                                          \
-    union _FP_UNION_##fs _flo; _flo.flt = (val);        	\
-    X##_f[0] = _flo.bits.frac0;                                 \
-    X##_f[1] = _flo.bits.frac1;                                 \
-    X##_f[2] = _flo.bits.frac2;                                 \
-    X##_f[3] = _flo.bits.frac3;                                 \
-    X##_e  = _flo.bits.exp;                                     \
-    X##_s  = _flo.bits.sign;                                    \
-  } while (0)
-
-#define _FP_PACK_RAW_4(fs, val, X)                              \
-  do {                                                          \
-    union _FP_UNION_##fs _flo;					\
-    _flo.bits.frac0 = X##_f[0];                                 \
-    _flo.bits.frac1 = X##_f[1];                                 \
-    _flo.bits.frac2 = X##_f[2];                                 \
-    _flo.bits.frac3 = X##_f[3];                                 \
-    _flo.bits.exp   = X##_e;                                    \
-    _flo.bits.sign  = X##_s;                                    \
-    (val) = _flo.flt;                                   	\
-  } while (0)
-
-
-/*
- * Internals 
- */
-
-#define __FP_FRAC_SET_4(X,I3,I2,I1,I0)					\
-  (X##_f[3] = I3, X##_f[2] = I2, X##_f[1] = I1, X##_f[0] = I0)
-
-#ifndef __FP_FRAC_ADD_4
-#define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)		\
-  (r0 = x0 + y0,							\
-   r1 = x1 + y1 + (r0 < x0),						\
-   r2 = x2 + y2 + (r1 < x1),						\
-   r3 = x3 + y3 + (r2 < x2))
-#endif
-
-#ifndef __FP_FRAC_SUB_4
-#define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)		\
-  (r0 = x0 - y0,                                                        \
-   r1 = x1 - y1 - (r0 > x0),                                            \
-   r2 = x2 - y2 - (r1 > x1),                                            \
-   r3 = x3 - y3 - (r2 > x2))
-#endif
-
-#ifndef __FP_FRAC_ADDI_4
-/* I always wanted to be a lisp programmer :-> */
-#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i)                                 \
-  (x3 += ((x2 += ((x1 += ((x0 += i) < x0)) < x1) < x2)))
-#endif
-
-/* Convert FP values between word sizes. This appears to be more
- * complicated than I'd have expected it to be, so these might be
- * wrong... These macros are in any case somewhat bogus because they
- * use information about what various FRAC_n variables look like 
- * internally [eg, that 2 word vars are X_f0 and x_f1]. But so do
- * the ones in op-2.h and op-1.h. 
- */
-#define _FP_FRAC_CONV_1_4(dfs, sfs, D, S)                               \
-   do {                                                                 \
-     _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),     \
-                        _FP_WFRACBITS_##sfs);                           \
-     D##_f = S##_f[0];                                                   \
-  } while (0)
-
-#define _FP_FRAC_CONV_2_4(dfs, sfs, D, S)                               \
-   do {                                                                 \
-     _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),     \
-                        _FP_WFRACBITS_##sfs);                           \
-     D##_f0 = S##_f[0];                                                  \
-     D##_f1 = S##_f[1];                                                  \
-  } while (0)
-
-/* Assembly/disassembly for converting to/from integral types.  
- * No shifting or overflow handled here.
- */
-/* Put the FP value X into r, which is an integer of size rsize. */
-#define _FP_FRAC_ASSEMBLE_4(r, X, rsize)                                \
-  do {                                                                  \
-    if (rsize <= _FP_W_TYPE_SIZE)                                       \
-      r = X##_f[0];                                                     \
-    else if (rsize <= 2*_FP_W_TYPE_SIZE)                                \
-    {                                                                   \
-      r = X##_f[1];                                                     \
-      r <<= _FP_W_TYPE_SIZE;                                            \
-      r += X##_f[0];                                                    \
-    }                                                                   \
-    else                                                                \
-    {                                                                   \
-      /* I'm feeling lazy so we deal with int == 3words (implausible)*/ \
-      /* and int == 4words as a single case.                         */ \
-      r = X##_f[3];                                                     \
-      r <<= _FP_W_TYPE_SIZE;                                            \
-      r += X##_f[2];                                                    \
-      r <<= _FP_W_TYPE_SIZE;                                            \
-      r += X##_f[1];                                                    \
-      r <<= _FP_W_TYPE_SIZE;                                            \
-      r += X##_f[0];                                                    \
-    }                                                                   \
-  } while (0)
-
-/* "No disassemble Number Five!" */
-/* move an integer of size rsize into X's fractional part. We rely on
- * the _f[] array consisting of words of size _FP_W_TYPE_SIZE to avoid
- * having to mask the values we store into it.
- */
-#define _FP_FRAC_DISASSEMBLE_4(X, r, rsize)                             \
-  do {                                                                  \
-    X##_f[0] = r;                                                       \
-    X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE);   \
-    X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \
-    X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \
-  } while (0);
-
-#define _FP_FRAC_CONV_4_1(dfs, sfs, D, S)                               \
-   do {                                                                 \
-     D##_f[0] = S##_f;                                                  \
-     D##_f[1] = D##_f[2] = D##_f[3] = 0;                                \
-     _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));    \
-   } while (0)
-
-#define _FP_FRAC_CONV_4_2(dfs, sfs, D, S)                               \
-   do {                                                                 \
-     D##_f[0] = S##_f0;                                                 \
-     D##_f[1] = S##_f1;                                                 \
-     D##_f[2] = D##_f[3] = 0;                                           \
-     _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));    \
-   } while (0)
-
-/* FIXME! This has to be written */
-#define _FP_SQRT_MEAT_4(R, S, T, X, q)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/op-common.h linux.14p16/arch/sparc64/math-emu/op-common.h
--- linux.vanilla/arch/sparc64/math-emu/op-common.h	Sat Aug 28 20:00:54 1999
+++ linux.14p16/arch/sparc64/math-emu/op-common.h	Thu Jan  1 01:00:00 1970
@@ -1,726 +0,0 @@
-#define _FP_DECL(wc, X)			\
-  _FP_I_TYPE X##_c, X##_s, X##_e, X##_r=0;	\
-  _FP_FRAC_DECL_##wc(X)
-
-/*
- * Finish truely unpacking a native fp value by classifying the kind
- * of fp value and normalizing both the exponent and the fraction.
- */
-
-#ifndef _FP_UNPACK_CANONICAL
-#define _FP_UNPACK_CANONICAL(fs, wc, X)					\
-do {									\
-  switch (X##_e)							\
-  {									\
-  default:								\
-    _FP_FRAC_HIGH_##wc(X) |= _FP_IMPLBIT_##fs;				\
-    _FP_FRAC_SLL_##wc(X, _FP_WORKBITS);					\
-    X##_e -= _FP_EXPBIAS_##fs;						\
-    X##_c = FP_CLS_NORMAL;						\
-    break;								\
-									\
-  case 0:								\
-    if (_FP_FRAC_ZEROP_##wc(X))						\
-      X##_c = FP_CLS_ZERO;						\
-    else								\
-      /* A denormalized number.  */					\
-      __FP_UNPACK_DENORM(fs, wc, X);					\
-    break;								\
-									\
-  case _FP_EXPMAX_##fs:							\
-    if (_FP_FRAC_ZEROP_##wc(X))						\
-      X##_c = FP_CLS_INF;						\
-    else								\
-      /* We don't differentiate between signaling and quiet nans.  */	\
-      X##_c = FP_CLS_NAN;						\
-    break;								\
-  }									\
-} while (0)
-#endif /* _FP_UNPACK_CANONICAL */
-
-
-/*
- * Before packing the bits back into the native fp result, take care
- * of such mundane things as rounding and overflow.  Also, for some
- * kinds of fp values, the original parts may not have been fully
- * extracted -- but that is ok, we can regenerate them now.
- */
-
-#ifndef _FP_PACK_CANONICAL
-#define _FP_PACK_CANONICAL(fs, wc, X)				\
-({int __pk__ret = X##_r;					\
-  switch (X##_c)						\
-  {								\
-  case FP_CLS_NORMAL:						\
-    X##_e += _FP_EXPBIAS_##fs;					\
-    if (X##_e > 0)						\
-      {								\
-	__pk__ret |= _FP_ROUND(wc, X);				\
-	if (_FP_FRAC_OVERP_##wc(fs, X))				\
-	  {							\
-	    _FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1));		\
-	    X##_e++;						\
-	  }							\
-	else							\
-	  _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);			\
-	if (X##_e >= _FP_EXPMAX_##fs)				\
-	  {							\
-	    /* overflow to infinity */				\
-	    X##_e = _FP_EXPMAX_##fs;				\
-	    _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);		\
-            __pk__ret |= EFLAG_OVERFLOW;			\
-	  }							\
-      }								\
-    else							\
-      {								\
-	/* we've got a denormalized number */			\
-	X##_e = -X##_e + 1;					\
-	if (X##_e <= _FP_WFRACBITS_##fs)			\
-	  {							\
-	    _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs);	\
-	    __pk__ret |= _FP_ROUND(wc, X);			\
-	    _FP_FRAC_SLL_##wc(X, 1);				\
-	    if (_FP_FRAC_OVERP_##wc(fs, X))			\
-	      {							\
-	        X##_e = 1;					\
-	        _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);	\
-	      }							\
-	    else						\
-	      {							\
-		X##_e = 0;					\
-		_FP_FRAC_SRL_##wc(X, _FP_WORKBITS+1);		\
-                __pk__ret |= EFLAG_UNDERFLOW;			\
-	      }							\
-	  }							\
-	else							\
-	  {							\
-	    /* underflow to zero */				\
-	    X##_e = 0;						\
-	    _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);		\
-            __pk__ret |= EFLAG_UNDERFLOW;			\
-	  }							\
-      }								\
-    break;							\
-								\
-  case FP_CLS_ZERO:						\
-    X##_e = 0;							\
-    _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);			\
-    break;							\
-								\
-  case FP_CLS_INF:						\
-    X##_e = _FP_EXPMAX_##fs;					\
-    _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);			\
-    break;							\
-								\
-  case FP_CLS_NAN:						\
-    X##_e = _FP_EXPMAX_##fs;					\
-    if (!_FP_KEEPNANFRACP)					\
-      {								\
-	_FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs);			\
-	X##_s = 0;						\
-      }								\
-    else							\
-      _FP_FRAC_HIGH_##wc(X) |= _FP_QNANBIT_##fs;		\
-    break;							\
-  }								\
-  __pk__ret;							\
-})
-#endif /* _FP_PACK_CANONICAL */
-
-/*
- * Main addition routine.  The input values should be cooked.
- */
-#ifndef _FP_ADD
-#define _FP_ADD(fs, wc, R, X, Y)					     \
-do {									     \
-  /* Propagate any flags that may have been set during unpacking */	     \
-  R##_r |= (X##_r | Y##_r);						     \
-  switch (_FP_CLS_COMBINE(X##_c, Y##_c))				     \
-  {									     \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):			     \
-    {									     \
-      /* shift the smaller number so that its exponent matches the larger */ \
-      _FP_I_TYPE diff = X##_e - Y##_e;					     \
-									     \
-      if (diff < 0)							     \
-	{								     \
-	  diff = -diff;							     \
-	  if (diff <= _FP_WFRACBITS_##fs)				     \
-	    _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs);		     \
-	  else if (!_FP_FRAC_ZEROP_##wc(X)) {				     \
-	    _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);			     \
-	    R_r |= EFLAG_INEXACT;					     \
-	  }								     \
-	  else								     \
-	    _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);			     \
-	  R##_e = Y##_e;						     \
-	}								     \
-      else								     \
-	{								     \
-	  if (diff > 0)							     \
-	    {								     \
-	      if (diff <= _FP_WFRACBITS_##fs)				     \
-	        _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs);		     \
-	      else if (!_FP_FRAC_ZEROP_##wc(Y))	{			     \
-	        _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc);			     \
-	         R_r |= EFLAG_INEXACT;					     \
-	      }								     \
-	      else							     \
-	        _FP_FRAC_SET_##wc(Y, _FP_ZEROFRAC_##wc);		     \
-	    }								     \
-	  R##_e = X##_e;						     \
-	}								     \
-									     \
-      R##_c = FP_CLS_NORMAL;						     \
-									     \
-      if (X##_s == Y##_s)						     \
-	{								     \
-	  R##_s = X##_s;						     \
-	  _FP_FRAC_ADD_##wc(R, X, Y);					     \
-	  if (_FP_FRAC_OVERP_##wc(fs, R))				     \
-	    {								     \
-	      _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs);		     \
-	      R##_e++;							     \
-	    }								     \
-	}								     \
-      else								     \
-	{								     \
-	  R##_s = X##_s;						     \
-	  _FP_FRAC_SUB_##wc(R, X, Y);					     \
-	  if (_FP_FRAC_ZEROP_##wc(R))					     \
-	    {								     \
-	      /* return an exact zero */				     \
-	      if (FP_ROUNDMODE == FP_RND_MINF)				     \
-		R##_s |= Y##_s;						     \
-	      else							     \
-		R##_s &= Y##_s;						     \
-	      R##_c = FP_CLS_ZERO;					     \
-	    }								     \
-	  else								     \
-	    {								     \
-	      if (_FP_FRAC_NEGP_##wc(R))				     \
-		{							     \
-		  _FP_FRAC_SUB_##wc(R, Y, X);				     \
-		  R##_s = Y##_s;					     \
-		}							     \
-									     \
-	      /* renormalize after subtraction */			     \
-	      _FP_FRAC_CLZ_##wc(diff, R);				     \
-	      diff -= _FP_WFRACXBITS_##fs;				     \
-	      if (diff)							     \
-		{							     \
-		  R##_e -= diff;					     \
-		  _FP_FRAC_SLL_##wc(R, diff);				     \
-		}							     \
-	    }								     \
-	}								     \
-      break;								     \
-    }									     \
-									     \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):				     \
-    _FP_CHOOSENAN(fs, wc, R, X, Y);					     \
-    break;								     \
-									     \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):			     \
-    R##_e = X##_e;							     \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):			     \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):				     \
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):				     \
-    _FP_FRAC_COPY_##wc(R, X);						     \
-    R##_s = X##_s;							     \
-    R##_c = X##_c;							     \
-    break;								     \
-									     \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):			     \
-    R##_e = Y##_e;							     \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):			     \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):				     \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):				     \
-    _FP_FRAC_COPY_##wc(R, Y);						     \
-    R##_s = Y##_s;							     \
-    R##_c = Y##_c;							     \
-    break;								     \
-									     \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):				     \
-    if (X##_s != Y##_s)							     \
-      {									     \
-	/* +INF + -INF => NAN */					     \
-	_FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);				     \
-	R##_s = X##_s ^ Y##_s;						     \
-	R##_c = FP_CLS_NAN;						     \
-	R##_r |= EFLAG_INVALID;						     \
-	break;								     \
-      }									     \
-    /* FALLTHRU */							     \
-									     \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):			     \
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):				     \
-    R##_s = X##_s;							     \
-    R##_c = FP_CLS_INF;							     \
-    break;								     \
-									     \
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):			     \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):				     \
-    R##_s = Y##_s;							     \
-    R##_c = FP_CLS_INF;							     \
-    break;								     \
-									     \
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):			     \
-    /* make sure the sign is correct */					     \
-    if (FP_ROUNDMODE == FP_RND_MINF)					     \
-      R##_s = X##_s | Y##_s;						     \
-    else								     \
-      R##_s = X##_s & Y##_s;						     \
-    R##_c = FP_CLS_ZERO;						     \
-    break;								     \
-									     \
-  default:								     \
-    abort();								     \
-  }									     \
-} while (0)
-#endif /* _FP_ADD */
-
-
-/*
- * Main negation routine.  FIXME -- when we care about setting exception
- * bits reliably, this will not do.  We should examine all of the fp classes.
- */
-#ifndef _FP_NEG
-#define _FP_NEG(fs, wc, R, X)		\
-  do {					\
-    R##_r |= X##_r;			\
-    _FP_FRAC_COPY_##wc(R, X);		\
-    R##_c = X##_c;			\
-    R##_e = X##_e;			\
-    R##_s = 1 ^ X##_s;			\
-  } while (0)
-#endif /* _FP_NEG */
-
-
-/*
- * Main multiplication routine.  The input values should be cooked.
- */
-#ifndef _FP_MUL
-#define _FP_MUL(fs, wc, R, X, Y)			\
-do {							\
-  /* Propagate any flags that may have been set during unpacking */	     \
-  R##_r |= (X##_r | Y##_r);						     \
-  R##_s = X##_s ^ Y##_s;				\
-  switch (_FP_CLS_COMBINE(X##_c, Y##_c))		\
-  {							\
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):	\
-    R##_c = FP_CLS_NORMAL;				\
-    R##_e = X##_e + Y##_e + 1;				\
-							\
-    _FP_MUL_MEAT_##fs(R,X,Y);				\
-							\
-    if (_FP_FRAC_OVERP_##wc(fs, R))			\
-      _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs);	\
-    else						\
-      R##_e--;						\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):		\
-    _FP_CHOOSENAN(fs, wc, R, X, Y);			\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):	\
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):		\
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):		\
-    R##_s = X##_s;					\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):		\
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):	\
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):	\
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):	\
-    _FP_FRAC_COPY_##wc(R, X);				\
-    R##_c = X##_c;					\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):	\
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):		\
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):		\
-    R##_s = Y##_s;					\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):	\
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):	\
-    _FP_FRAC_COPY_##wc(R, Y);				\
-    R##_c = Y##_c;					\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):		\
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):		\
-    R##_c = FP_CLS_NAN;					\
-    _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);		\
-    break;						\
-							\
-  default:						\
-    abort();						\
-  }							\
-} while (0)
-#endif /* _FP_MUL */
-
-
-/*
- * Main division routine.  The input values should be cooked.
- */
-#ifndef _FP_DIV
-#define _FP_DIV(fs, wc, R, X, Y)			\
-do {							\
-  /* Propagate any flags that may have been set during unpacking */	     \
-  R##_r |= (X##_r | Y##_r);						     \
-  R##_s = X##_s ^ Y##_s;				\
-  switch (_FP_CLS_COMBINE(X##_c, Y##_c))		\
-  {							\
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):	\
-    R##_c = FP_CLS_NORMAL;				\
-    R##_e = X##_e - Y##_e;				\
-							\
-    _FP_DIV_MEAT_##fs(R,X,Y);				\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):		\
-    _FP_CHOOSENAN(fs, wc, R, X, Y);			\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):	\
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):		\
-  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):		\
-    R##_s = X##_s;					\
-    _FP_FRAC_COPY_##wc(R, X);				\
-    R##_c = X##_c;					\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):	\
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):		\
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):		\
-    R##_s = Y##_s;					\
-    _FP_FRAC_COPY_##wc(R, Y);				\
-    R##_c = Y##_c;					\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):	\
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):		\
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):	\
-    R##_c = FP_CLS_ZERO;				\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):	\
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):		\
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):	\
-    R##_c = FP_CLS_INF;					\
-    break;						\
-							\
-  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):		\
-  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):	\
-    R##_c = FP_CLS_NAN;					\
-    _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);		\
-    break;						\
-							\
-  default:						\
-    abort();						\
-  }							\
-} while (0)
-#endif _FP_DIV
-
-
-/*
- * Main differential comparison routine.  The inputs should be raw not
- * cooked.  The return is -1,0,1 for normal values, 2 otherwise.
- */
-#ifndef _FP_CMP
-#define _FP_CMP(fs, wc, ret, X, Y, un)					\
-  do {									\
-    /* NANs are unordered */						\
-    if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X))		\
-	|| (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y)))	\
-      {									\
-	ret = un;							\
-      }									\
-    /* Deal with infinities */						\
-    else if (X##_c == FP_CLS_INF) {					\
-	if(Y##_c == FP_CLS_INF) {					\
-	    ret = Y##_s - X##_s;					\
-	}								\
-	else {								\
-	    ret = X##_s ? -1 : 1; 					\
-	}								\
-    }									\
-    else if(Y##_c == FP_CLS_INF) {					\
-	ret = Y##_s ? 1 : -1;						\
-    }									\
-    else								\
-      {									\
-	int __is_zero_x;						\
-	int __is_zero_y;						\
-									\
-	__is_zero_x = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0;	\
-	__is_zero_y = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0;	\
-									\
-	if (__is_zero_x && __is_zero_y)					\
-		ret = 0;						\
-	else if (__is_zero_x)						\
-		ret = Y##_s ? 1 : -1;					\
-	else if (__is_zero_y)						\
-		ret = X##_s ? -1 : 1;					\
-	else if (X##_s != Y##_s)					\
-	  ret = X##_s ? -1 : 1;						\
-	else if (X##_e > Y##_e)						\
-	  ret = X##_s ? -1 : 1;						\
-	else if (X##_e < Y##_e)						\
-	  ret = X##_s ? 1 : -1;						\
-	else if (_FP_FRAC_GT_##wc(X, Y))				\
-	  ret = X##_s ? -1 : 1;						\
-	else if (_FP_FRAC_GT_##wc(Y, X))				\
-	  ret = X##_s ? 1 : -1;						\
-	else								\
-	  ret = 0;							\
-      }									\
-  } while (0)
-#endif /* _FP_CMP */
-
-
-/* Simplification for strict equality.  */
-
-#ifndef _FP_CMP_EQ
-#define _FP_CMP_EQ(fs, wc, ret, X, Y)					  \
-  do {									  \
-    /* NANs are unordered */						  \
-    if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X))		  \
-	|| (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y)))	  \
-      {									  \
-	ret = 1;							  \
-      }									  \
-    else								  \
-      {									  \
-	ret = !(X##_e == Y##_e						  \
-		&& _FP_FRAC_EQ_##wc(X, Y)				  \
-		&& (X##_s == Y##_s || !X##_e && _FP_FRAC_ZEROP_##wc(X))); \
-      }									  \
-  } while (0)
-#endif /* _FP_CMP_EQ */
-
-/*
- * Main square root routine.  The input value should be cooked.
- */
-#ifndef _FP_SQRT
-#define _FP_SQRT(fs, wc, R, X)						\
-do {									\
-    _FP_FRAC_DECL_##wc(T); _FP_FRAC_DECL_##wc(S);			\
-    _FP_W_TYPE q;							\
-    R##_r |= X##_r;							\
-    switch (X##_c)							\
-    {									\
-    case FP_CLS_NAN:							\
-        _FP_CHOOSENAN_SQRT(fs, wc, R, X);			        \
-    	break;								\
-    case FP_CLS_INF:							\
-    	if (X##_s)							\
-    	  {								\
-    	    R##_s = 0;							\
-	    R##_c = FP_CLS_NAN; /* sNAN */				\
-    	  }								\
-    	else								\
-    	  {								\
-    	    R##_s = 0;							\
-    	    R##_c = FP_CLS_INF; /* sqrt(+inf) = +inf */			\
-    	  }								\
-    	break;								\
-    case FP_CLS_ZERO:							\
-	R##_s = X##_s;							\
-    	R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */			\
-	break;								\
-    case FP_CLS_NORMAL:							\
-    	R##_s = 0;							\
-        if (X##_s)							\
-          {								\
-	    R##_c = FP_CLS_NAN; /* sNAN */				\
-	    break;							\
-          }								\
-    	R##_c = FP_CLS_NORMAL;						\
-        if (X##_e & 1)							\
-          _FP_FRAC_SLL_##wc(X, 1);					\
-        R##_e = X##_e >> 1;						\
-        _FP_FRAC_SET_##wc(S, _FP_ZEROFRAC_##wc);			\
-        _FP_FRAC_SET_##wc(R, _FP_ZEROFRAC_##wc);			\
-        q = _FP_OVERFLOW_##fs;						\
-        _FP_FRAC_SLL_##wc(X, 1);					\
-        _FP_SQRT_MEAT_##wc(R, S, T, X, q);				\
-        _FP_FRAC_SRL_##wc(R, 1);					\
-    }									\
-  } while (0)
-#endif /* FP_SQRT */
-
-/*
- * Convert from FP to integer
- */
-
-/* "When a NaN, infinity, large positive argument >= 2147483648.0, or 
- * large negative argument <= -2147483649.0 is converted to an integer,
- * the invalid_current bit...should be set and fp_exception_IEEE_754 should
- * be raised. If the floating point invalid trap is disabled, no trap occurs
- * and a numerical result is generated: if the sign bit of the operand
- * is 0, the result is 2147483647; if the sign bit of the operand is 1,
- * the result is -2147483648."
- * Similarly for conversion to extended ints, except that the boundaries
- * are >= 2^63, <= -(2^63 + 1), and the results are 2^63 + 1 for s=0 and
- * -2^63 for s=1.
- * -- SPARC Architecture Manual V9, Appendix B, which specifies how
- * SPARCs resolve implementation dependencies in the IEEE-754 spec.
- * I don't believe that the code below follows this. I'm not even sure
- * it's right! 
- * It doesn't cope with needing to convert to an n bit integer when there
- * is no n bit integer type. Fortunately gcc provides long long so this
- * isn't a problem for sparc32.
- * I have, however, fixed its NaN handling to conform as above.
- *         -- PMM 02/1998
- * NB: rsigned is not 'is r declared signed?' but 'should the value stored
- * in r be signed or unsigned?'. r is always(?) declared unsigned.
- * Comments below are mine, BTW -- PMM 
- */
-#ifndef _FP_TO_INT
-#define _FP_TO_INT(fs, wc, r, X, rsize, rsigned)		\
-  do {								\
-    switch (X##_c)						\
-      {								\
-      case FP_CLS_NORMAL:					\
-	if (X##_e < 0)						\
-	  {							\
-	  /* case FP_CLS_NAN: see above! */			\
-	  case FP_CLS_ZERO:					\
-	    r = 0;						\
-	  }							\
-	else if (X##_e >= rsize - (rsigned != 0))		\
-	  {	/* overflow */					\
-	  case FP_CLS_NAN:                                      \
-          case FP_CLS_INF:					\
-	    if (rsigned)					\
-	      {							\
-		r = 1;						\
-		r <<= rsize - 1;				\
-		r -= 1 - X##_s;					\
-	      }							\
-	    else						\
-	      {							\
-		r = 0;						\
-		if (!X##_s)					\
-		  r = ~r;					\
-	      }							\
-	  }							\
-	else							\
-	  {							\
-	    if (_FP_W_TYPE_SIZE*wc < rsize)			\
-	      {							\
-		_FP_FRAC_ASSEMBLE_##wc(r, X, rsize);		\
-		r <<= X##_e - _FP_WFRACBITS_##fs;		\
-	      }							\
-	    else						\
-	      {							\
-		if (X##_e >= _FP_WFRACBITS_##fs)		\
-		  _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1)); \
-		else						\
-		  _FP_FRAC_SRL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1)); \
-		_FP_FRAC_ASSEMBLE_##wc(r, X, rsize);		\
-	      }							\
-	    if (rsigned && X##_s)				\
-	      r = -r;						\
-	  }							\
-	break;							\
-      }								\
-  } while (0)
-
-#endif /* _FP_TO_INT */
-
-#ifndef _FP_FROM_INT
-#define _FP_FROM_INT(fs, wc, X, r, rsize, rtype)			\
-  do {									\
-    if (r)								\
-      {									\
-	X##_c = FP_CLS_NORMAL;						\
-									\
-	if ((X##_s = (r < 0)))						\
-	  r = -r;							\
-	/* Note that `r' is now considered unsigned, so we don't have	\
-	   to worry about the single signed overflow case.  */		\
-									\
-	if (rsize <= _FP_W_TYPE_SIZE)					\
-	  __FP_CLZ(X##_e, r);						\
-	else								\
-	  __FP_CLZ_2(X##_e, (_FP_W_TYPE)(r >> _FP_W_TYPE_SIZE), 	\
-		     (_FP_W_TYPE)r);					\
-	if (rsize < _FP_W_TYPE_SIZE)					\
-		X##_e -= (_FP_W_TYPE_SIZE - rsize);			\
-	X##_e = rsize - X##_e - 1;					\
-									\
-	if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e)	\
-	  __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs), rsize);	\
-	r &= ~((_FP_W_TYPE)1 << X##_e);					\
-	_FP_FRAC_DISASSEMBLE_##wc(X, ((unsigned rtype)r), rsize);	\
-	_FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));		\
-      }									\
-    else								\
-      {									\
-	X##_c = FP_CLS_ZERO, X##_s = 0;					\
-      }									\
-  } while (0)
-#endif /* FP_FROM_INT */
-
-#ifndef FP_CONV
-#define FP_CONV(dfs,sfs,dwc,swc,D,S)			\
-  do {							\
-    _FP_FRAC_CONV_##dwc##_##swc(dfs, sfs, D, S);	\
-    D##_e = S##_e;					\
-    D##_c = S##_c;					\
-    D##_s = S##_s;					\
-    D##_r |= S##_r;					\
-  } while (0)
-#endif FP_CONV
-
-/*
- * Helper primitives.
- */
-
-/* Count leading zeros in a word.  */
-
-#ifndef __FP_CLZ
-#if _FP_W_TYPE_SIZE < 64
-/* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */
-#define __FP_CLZ(r, x)				\
-  do {						\
-    _FP_W_TYPE _t = (x);			\
-    r = _FP_W_TYPE_SIZE - 1;			\
-    if (_t > 0xffff) r -= 16;			\
-    if (_t > 0xffff) _t >>= 16;			\
-    if (_t > 0xff) r -= 8;			\
-    if (_t > 0xff) _t >>= 8;			\
-    if (_t & 0xf0) r -= 4;			\
-    if (_t & 0xf0) _t >>= 4;			\
-    if (_t & 0xc) r -= 2;			\
-    if (_t & 0xc) _t >>= 2;			\
-    if (_t & 0x2) r -= 1;			\
-  } while (0)
-#else /* not _FP_W_TYPE_SIZE < 64 */
-#define __FP_CLZ(r, x)				\
-  do {						\
-    _FP_W_TYPE _t = (x);			\
-    r = _FP_W_TYPE_SIZE - 1;			\
-    if (_t > 0xffffffff) r -= 32;		\
-    if (_t > 0xffffffff) _t >>= 32;		\
-    if (_t > 0xffff) r -= 16;			\
-    if (_t > 0xffff) _t >>= 16;			\
-    if (_t > 0xff) r -= 8;			\
-    if (_t > 0xff) _t >>= 8;			\
-    if (_t & 0xf0) r -= 4;			\
-    if (_t & 0xf0) _t >>= 4;			\
-    if (_t & 0xc) r -= 2;			\
-    if (_t & 0xc) _t >>= 2;			\
-    if (_t & 0x2) r -= 1;			\
-  } while (0)
-#endif /* not _FP_W_TYPE_SIZE < 64 */
-#endif /* ndef __FP_CLZ */
-
-#define _FP_DIV_HELP_imm(q, r, n, d)		\
-  do {						\
-    q = n / d, r = n % d;			\
-  } while (0)
-
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/quad.h linux.14p16/arch/sparc64/math-emu/quad.h
--- linux.vanilla/arch/sparc64/math-emu/quad.h	Wed Apr 15 01:44:21 1998
+++ linux.14p16/arch/sparc64/math-emu/quad.h	Thu Jan  1 01:00:00 1970
@@ -1,138 +0,0 @@
-/*
- * Definitions for IEEE Quad Precision
- */
-#if _FP_W_TYPE_SIZE < 32
-/* It appears to be traditional to abuse 16bitters in these header files... */
-#error "Here's a nickel, kid. Go buy yourself a real computer."
-#endif
-
-#if _FP_W_TYPE_SIZE < 64
-/* This is all terribly experimental and I don't know if it'll work properly -- PMM 02/1998 */
-#define _FP_FRACTBITS_Q         (4*_FP_W_TYPE_SIZE)
-#else
-#define _FP_FRACTBITS_Q		(2*_FP_W_TYPE_SIZE)
-#endif
-
-#define _FP_FRACBITS_Q		113
-#define _FP_FRACXBITS_Q		(_FP_FRACTBITS_Q - _FP_FRACBITS_Q)
-#define _FP_WFRACBITS_Q		(_FP_WORKBITS + _FP_FRACBITS_Q)
-#define _FP_WFRACXBITS_Q	(_FP_FRACTBITS_Q - _FP_WFRACBITS_Q)
-#define _FP_EXPBITS_Q		15
-#define _FP_EXPBIAS_Q		16383
-#define _FP_EXPMAX_Q		32767
-
-#define _FP_QNANBIT_Q		\
-	((_FP_W_TYPE)1 << (_FP_FRACBITS_Q-2) % _FP_W_TYPE_SIZE)
-#define _FP_IMPLBIT_Q		\
-	((_FP_W_TYPE)1 << (_FP_FRACBITS_Q-1) % _FP_W_TYPE_SIZE)
-#define _FP_OVERFLOW_Q		\
-	((_FP_W_TYPE)1 << (_FP_WFRACBITS_Q % _FP_W_TYPE_SIZE))
-
-#if _FP_W_TYPE_SIZE < 64
-
-union _FP_UNION_Q
-{
-   long double flt;
-   struct 
-   {
-#if __BYTE_ORDER == __BIG_ENDIAN
-      unsigned sign : 1;
-      unsigned exp : _FP_EXPBITS_Q;
-      unsigned long frac3 : _FP_FRACBITS_Q - (_FP_IMPLBIT_Q != 0)-(_FP_W_TYPE_SIZE * 3);
-      unsigned long frac2 : _FP_W_TYPE_SIZE;
-      unsigned long frac1 : _FP_W_TYPE_SIZE;
-      unsigned long frac0 : _FP_W_TYPE_SIZE;
-#else
-      unsigned long frac0 : _FP_W_TYPE_SIZE;
-      unsigned long frac1 : _FP_W_TYPE_SIZE;
-      unsigned long frac2 : _FP_W_TYPE_SIZE;
-      unsigned long frac3 : _FP_FRACBITS_Q - (_FP_IMPLBIT_Q != 0)-(_FP_W_TYPE_SIZE * 3);
-      unsigned exp : _FP_EXPBITS_Q;
-      unsigned sign : 1;
-#endif /* not bigendian */
-   } bits __attribute__((packed));
-};
-
-
-#define FP_DECL_Q(X)		_FP_DECL(4,X)
-#define FP_UNPACK_RAW_Q(X,val)	_FP_UNPACK_RAW_4(Q,X,val)
-#define FP_PACK_RAW_Q(val,X)	_FP_PACK_RAW_4(Q,val,X)
-
-#define FP_UNPACK_Q(X,val)		\
-  do {					\
-    _FP_UNPACK_RAW_4(Q,X,val);		\
-    _FP_UNPACK_CANONICAL(Q,4,X);	\
-  } while (0)
-
-#define FP_PACK_Q(val,X)		\
-  do {					\
-    _FP_PACK_CANONICAL(Q,4,X);		\
-    _FP_PACK_RAW_4(Q,val,X);		\
-  } while (0)
-
-#define FP_NEG_Q(R,X)		_FP_NEG(Q,4,R,X)
-#define FP_ADD_Q(R,X,Y)		_FP_ADD(Q,4,R,X,Y)
-/* single.h and double.h define FP_SUB_t this way too. However, _FP_SUB is
- * never defined in op-common.h! Fortunately nobody seems to use the FP_SUB_t 
- * macros: I suggest a combination of FP_NEG and FP_ADD :-> -- PMM 02/1998
- */
-#define FP_SUB_Q(R,X,Y)		_FP_SUB(Q,4,R,X,Y)
-#define FP_MUL_Q(R,X,Y)		_FP_MUL(Q,4,R,X,Y)
-#define FP_DIV_Q(R,X,Y)		_FP_DIV(Q,4,R,X,Y)
-#define FP_SQRT_Q(R,X)		_FP_SQRT(Q,4,R,X)
-
-#define FP_CMP_Q(r,X,Y,un)	_FP_CMP(Q,4,r,X,Y,un)
-#define FP_CMP_EQ_Q(r,X,Y)	_FP_CMP_EQ(Q,4,r,X,Y)
-
-#define FP_TO_INT_Q(r,X,rsz,rsg)  _FP_TO_INT(Q,4,r,X,rsz,rsg)
-#define FP_FROM_INT_Q(X,r,rs,rt)  _FP_FROM_INT(Q,4,X,r,rs,rt)
-
-#else   /* not _FP_W_TYPE_SIZE < 64 */
-union _FP_UNION_Q
-{
-  long double flt /* __attribute__((mode(TF))) */ ;
-  struct {
-#if __BYTE_ORDER == __BIG_ENDIAN
-    unsigned sign  : 1;
-    unsigned exp   : _FP_EXPBITS_Q;
-    unsigned long frac1 : _FP_FRACBITS_Q-(_FP_IMPLBIT_Q != 0)-_FP_W_TYPE_SIZE;
-    unsigned long frac0 : _FP_W_TYPE_SIZE;
-#else
-    unsigned long frac0 : _FP_W_TYPE_SIZE;
-    unsigned long frac1 : _FP_FRACBITS_Q-(_FP_IMPLBIT_Q != 0)-_FP_W_TYPE_SIZE;
-    unsigned exp   : _FP_EXPBITS_Q;
-    unsigned sign  : 1;
-#endif
-  } bits;
-};
-
-#define FP_DECL_Q(X)		_FP_DECL(2,X)
-#define FP_UNPACK_RAW_Q(X,val)	_FP_UNPACK_RAW_2(Q,X,val)
-#define FP_PACK_RAW_Q(val,X)	_FP_PACK_RAW_2(Q,val,X)
-
-#define FP_UNPACK_Q(X,val)		\
-  do {					\
-    _FP_UNPACK_RAW_2(Q,X,val);		\
-    _FP_UNPACK_CANONICAL(Q,2,X);	\
-  } while (0)
-
-#define FP_PACK_Q(val,X)		\
-  do {					\
-    _FP_PACK_CANONICAL(Q,2,X);		\
-    _FP_PACK_RAW_2(Q,val,X);		\
-  } while (0)
-
-#define FP_NEG_Q(R,X)		_FP_NEG(Q,2,R,X)
-#define FP_ADD_Q(R,X,Y)		_FP_ADD(Q,2,R,X,Y)
-#define FP_SUB_Q(R,X,Y)		_FP_SUB(Q,2,R,X,Y)
-#define FP_MUL_Q(R,X,Y)		_FP_MUL(Q,2,R,X,Y)
-#define FP_DIV_Q(R,X,Y)		_FP_DIV(Q,2,R,X,Y)
-#define FP_SQRT_Q(R,X)		_FP_SQRT(Q,2,R,X)
-
-#define FP_CMP_Q(r,X,Y,un)	_FP_CMP(Q,2,r,X,Y,un)
-#define FP_CMP_EQ_Q(r,X,Y)	_FP_CMP_EQ(Q,2,r,X,Y)
-
-#define FP_TO_INT_Q(r,X,rsz,rsg)  _FP_TO_INT(Q,2,r,X,rsz,rsg)
-#define FP_FROM_INT_Q(X,r,rs,rt)  _FP_FROM_INT(Q,2,X,r,rs,rt)
-
-#endif /* not _FP_W_TYPE_SIZE < 64 */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/sfp-machine.h linux.14p16/arch/sparc64/math-emu/sfp-machine.h
--- linux.vanilla/arch/sparc64/math-emu/sfp-machine.h	Sat Aug 14 02:27:16 1999
+++ linux.14p16/arch/sparc64/math-emu/sfp-machine.h	Thu Dec  9 15:34:37 1999
@@ -1,6 +1,10 @@
-/* Machine-dependent software floating-point definitions.  Sparc64 version.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+/* Machine-dependent software floating-point definitions.
+   Sparc64 kernel version.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+		  Jakub Jelinek (jj@ultra.linux.cz) and
+		  David S. Miller (davem@redhat.com).
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public License as
@@ -17,253 +21,71 @@
    not, write to the Free Software Foundation, Inc.,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
+#ifndef _SFP_MACHINE_H
+#define _SFP_MACHINE_H
+   
 #define _FP_W_TYPE_SIZE		64
 #define _FP_W_TYPE		unsigned long
 #define _FP_WS_TYPE		signed long
 #define _FP_I_TYPE		long
 
-#define _FP_MUL_MEAT_S(R,X,Y)	_FP_MUL_MEAT_1_imm(S,R,X,Y)
-#define _FP_MUL_MEAT_D(R,X,Y)	_FP_MUL_MEAT_1_wide(D,R,X,Y,umul_ppmm)
-#define _FP_MUL_MEAT_Q(R,X,Y)	_FP_MUL_MEAT_2_wide(Q,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_S(R,X,Y)					\
+  _FP_MUL_MEAT_1_imm(_FP_WFRACBITS_S,R,X,Y)
+#define _FP_MUL_MEAT_D(R,X,Y)					\
+  _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y)					\
+  _FP_MUL_MEAT_2_wide_3mul(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
 
 #define _FP_DIV_MEAT_S(R,X,Y)	_FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm)
 #define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_1_udiv(D,R,X,Y)
-#define _FP_DIV_MEAT_Q(R,X,Y)	_FP_DIV_MEAT_2_udiv_64(Q,R,X,Y)
+#define _FP_DIV_MEAT_Q(R,X,Y)	_FP_DIV_MEAT_2_udiv(Q,R,X,Y)
 
-#define _FP_NANFRAC_S		_FP_QNANBIT_S
-#define _FP_NANFRAC_D		_FP_QNANBIT_D
-#define _FP_NANFRAC_Q		_FP_QNANBIT_Q, 0
-
-/* On some architectures float-to-int conversions return a result
- * code.  On others (e.g. Sparc) they return 0
- */
-#define _FTOI_RESULT		0
+#define _FP_NANFRAC_S		((_FP_QNANBIT_S << 1) - 1)
+#define _FP_NANFRAC_D		((_FP_QNANBIT_D << 1) - 1)
+#define _FP_NANFRAC_Q		((_FP_QNANBIT_Q << 1) - 1), -1
+#define _FP_NANSIGN_S		0
+#define _FP_NANSIGN_D		0
+#define _FP_NANSIGN_Q		0
 
 #define _FP_KEEPNANFRACP 1
-#define _FP_CHOOSENAN(fs, wc, R, X, Y)				\
-  do {								\
-    R##_s = Y##_s;						\
-    _FP_FRAC_COPY_##wc(R,Y);					\
-    R##_c = FP_CLS_NAN;						\
-  } while (0)
-
-#define _FP_CHOOSENAN_SQRT(fs, wc, R, X)			\
-  do {								\
-    	R##_s = 0;						\
-    	R##_c = FP_CLS_NAN;					\
-    	_FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);		\
-  } while (0)
-
-
-#define __FP_UNPACK_DENORM(fs, wc, X)				\
-    {								\
-	_FP_I_TYPE _shift;					\
-	_FP_FRAC_CLZ_##wc(_shift, X);				\
-	_shift -= _FP_FRACXBITS_##fs;				\
-	_FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS));		\
-	X##_e -= _FP_EXPBIAS_##fs - 1 + _shift;			\
-	X##_c = FP_CLS_NORMAL;					\
-    }
-
-
-#define __FP_UNPACK_RAW_1(fs, X, val)				\
-  do {								\
-    union _FP_UNION_##fs *_flo =				\
-    	(union _FP_UNION_##fs *)val;				\
-								\
-    X##_f = _flo->bits.frac;					\
-    X##_e = _flo->bits.exp;					\
-    X##_s = _flo->bits.sign;					\
-  } while (0)
-
-#define __FP_UNPACK_RAW_2(fs, X, val)			\
-  do {							\
-    union _FP_UNION_##fs *_flo =			\
-    	(union _FP_UNION_##fs *)val;			\
-							\
-    X##_f0 = _flo->bits.frac0;				\
-    X##_f1 = _flo->bits.frac1;				\
-    X##_e  = _flo->bits.exp;				\
-    X##_s  = _flo->bits.sign;				\
-  } while (0)
-
-#define __FP_UNPACK_S(X,val)		\
-  do {					\
-    __FP_UNPACK_RAW_1(S,X,val);		\
-    _FP_UNPACK_CANONICAL(S,1,X);	\
-  } while (0)
 
-#define __FP_UNPACK_D(X,val)		\
-  do {					\
-    __FP_UNPACK_RAW_1(D,X,val);		\
-    _FP_UNPACK_CANONICAL(D,1,X);	\
-  } while (0)
-
-#define __FP_UNPACK_Q(X,val)		\
-  do {					\
-    __FP_UNPACK_RAW_2(Q,X,val);		\
-    _FP_UNPACK_CANONICAL(Q,2,X);	\
-  } while (0)
-
-#define __FP_PACK_RAW_1(fs, val, X)				\
+/* If one NaN is signaling and the other is not,
+ * we choose that one, otherwise we choose X.
+ */
+/* For _Qp_* and _Q_*, this should prefer X, for
+ * CPU instruction emulation this should prefer Y.
+ * (see SPAMv9 B.2.2 section).
+ */
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)			\
   do {								\
-    union _FP_UNION_##fs *_flo =				\
-    	(union _FP_UNION_##fs *)val;				\
-								\
-    _flo->bits.frac = X##_f;					\
-    _flo->bits.exp  = X##_e;					\
-    _flo->bits.sign = X##_s;					\
-  } while (0)
-  
-#define __FP_PACK_RAW_2(fs, val, X)			\
-  do {							\
-    union _FP_UNION_##fs *_flo =			\
-    	(union _FP_UNION_##fs *)val;			\
-							\
-    _flo->bits.frac0 = X##_f0;				\
-    _flo->bits.frac1 = X##_f1;				\
-    _flo->bits.exp   = X##_e;				\
-    _flo->bits.sign  = X##_s;				\
+    if ((_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)		\
+	&& !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))	\
+      {								\
+	R##_s = X##_s;						\
+	_FP_FRAC_COPY_##wc(R,X);				\
+      }								\
+    else							\
+      {								\
+	R##_s = Y##_s;						\
+	_FP_FRAC_COPY_##wc(R,Y);				\
+      }								\
+    R##_c = FP_CLS_NAN;						\
   } while (0)
 
-#include <linux/kernel.h>
-#include <linux/sched.h>
-
-/* We only actually write to the destination register
- * if exceptions signalled (if any) will not trap.
- */
-#define __FPU_TEM \
-	(((current->tss.xfsr[0])>>23)&0x1f)
-#define __FPU_TRAP_P(bits) \
-	((__FPU_TEM & (bits)) != 0)
-
-#define __FP_PACK_S(val,X)			\
-({  int __exc = _FP_PACK_CANONICAL(S,1,X);	\
-    if(!__exc || !__FPU_TRAP_P(__exc))		\
-        __FP_PACK_RAW_1(S,val,X);		\
-    __exc;					\
-})
-
-#define __FP_PACK_D(val,X)			\
-({  int __exc = _FP_PACK_CANONICAL(D,1,X);	\
-    if(!__exc || !__FPU_TRAP_P(__exc))		\
-        __FP_PACK_RAW_1(D,val,X);		\
-    __exc;					\
-})
-
-#define __FP_PACK_Q(val,X)			\
-({  int __exc = _FP_PACK_CANONICAL(Q,2,X);	\
-    if(!__exc || !__FPU_TRAP_P(__exc))		\
-        __FP_PACK_RAW_2(Q,val,X);		\
-    __exc;					\
-})
-
 /* Obtain the current rounding mode. */
+#ifndef FP_ROUNDMODE
 #define FP_ROUNDMODE	((current->tss.xfsr[0] >> 30) & 0x3)
+#endif
 
-#include <linux/types.h>
-#include <asm/byteorder.h>
-
-#define add_ssaaaa(sh, sl, ah, al, bh, bl) 						\
-  __asm__ ("addcc %4,%5,%1
-  	    add %2,%3,%0
-  	    bcs,a,pn %%xcc, 1f
-  	    add %0, 1, %0
-  	    1:"										\
-	   : "=r" ((UDItype)(sh)),				      			\
-	     "=&r" ((UDItype)(sl))				      			\
-	   : "r" ((UDItype)(ah)),				     			\
-	     "r" ((UDItype)(bh)),				      			\
-	     "r" ((UDItype)(al)),				     			\
-	     "r" ((UDItype)(bl))				       			\
-	   : "cc")
-	   
-#define sub_ddmmss(sh, sl, ah, al, bh, bl) 						\
-  __asm__ ("subcc %4,%5,%1
-  	    sub %2,%3,%0
-  	    bcs,a,pn %%xcc, 1f
-  	    sub %0, 1, %0
-  	    1:"										\
-	   : "=r" ((UDItype)(sh)),				      			\
-	     "=&r" ((UDItype)(sl))				      			\
-	   : "r" ((UDItype)(ah)),				     			\
-	     "r" ((UDItype)(bh)),				      			\
-	     "r" ((UDItype)(al)),				     			\
-	     "r" ((UDItype)(bl))				       			\
-	   : "cc")
-	   
-#define umul_ppmm(wh, wl, u, v) 							\
-  do {											\
-	  __asm__ ("mulx %2,%3,%1
-  		    srlx %2,32,%%g1
-	  	    srl %3,0,%%g2
-  		    mulx %%g1,%%g2,%%g3
-  		    srlx %3,32,%%g1
-  		    srl %2,0,%%g2
-  		    mulx %%g1,%%g2,%%g2
-  		    srlx %2,32,%%g1
-  		    add %%g2,%%g3,%%g3
-  		    srlx %3,32,%%g2
-  		    mulx %%g1,%%g2,%%g1
-  		    srlx %%g3,32,%%g2
-  		    add %%g1,%%g2,%0"							\
-	   : "=r" ((UDItype)(wh)),				      			\
-	     "=&r" ((UDItype)(wl))				      			\
-	   : "r" ((UDItype)(u)),				     			\
-	     "r" ((UDItype)(v))				      				\
-	   : "g1", "g2", "g3", "cc");							\
-  } while (0)
-  
-#define udiv_qrnnd(q, r, n1, n0, d) 							\
-  do {                                                                  		\
-    UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m;                     		\
-    __d1 = (d >> 32);                                           			\
-    __d0 = (USItype)d;                                            			\
-                                                                        		\
-    __r1 = (n1) % __d1;                                                 		\
-    __q1 = (n1) / __d1;                                                 		\
-    __m = (UWtype) __q1 * __d0;                                         		\
-    __r1 = (__r1 << 32) | (n0 >> 32);                          				\
-    if (__r1 < __m)                                                     		\
-      {                                                                 		\
-        __q1--, __r1 += (d);                                            		\
-        if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */		\
-          if (__r1 < __m)                                               		\
-            __q1--, __r1 += (d);                                        		\
-      }                                                                 		\
-    __r1 -= __m;                                                        		\
-                                                                        		\
-    __r0 = __r1 % __d1;                                                 		\
-    __q0 = __r1 / __d1;                                                 		\
-    __m = (UWtype) __q0 * __d0;                                         		\
-    __r0 = (__r0 << 32) | ((USItype)n0);                           			\
-    if (__r0 < __m)                                                     		\
-      {                                                                 		\
-        __q0--, __r0 += (d);                                            		\
-        if (__r0 >= (d))                                                		\
-          if (__r0 < __m)                                               		\
-            __q0--, __r0 += (d);                                        		\
-      }                                                                 		\
-    __r0 -= __m;                                                        		\
-                                                                        		\
-    (q) = (UWtype) (__q1 << 32)  | __q0;                                		\
-    (r) = __r0;                                                         		\
-  } while (0)
+/* Exception flags. */
+#define FP_EX_INVALID		(1 << 4)
+#define FP_EX_OVERFLOW		(1 << 3)
+#define FP_EX_UNDERFLOW		(1 << 2)
+#define FP_EX_DIVZERO		(1 << 1)
+#define FP_EX_INEXACT		(1 << 0)
 
-#define UDIV_NEEDS_NORMALIZATION 1  
+#define FP_HANDLE_EXCEPTIONS return _fex
 
-#define abort()										\
-	return 0
+#define FP_INHIBIT_RESULTS ((current->tss.xfsr[0] >> 23) & _fex)
 
-#ifdef __BIG_ENDIAN
-#define __BYTE_ORDER __BIG_ENDIAN
-#else
-#define __BYTE_ORDER __LITTLE_ENDIAN
 #endif
-
-/* Exception flags. */
-#define EFLAG_INVALID		(1 << 4)
-#define EFLAG_OVERFLOW		(1 << 3)
-#define EFLAG_UNDERFLOW		(1 << 2)
-#define EFLAG_DIVZERO		(1 << 1)
-#define EFLAG_INEXACT		(1 << 0)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/sfp-util.h linux.14p16/arch/sparc64/math-emu/sfp-util.h
--- linux.vanilla/arch/sparc64/math-emu/sfp-util.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/sparc64/math-emu/sfp-util.h	Thu Dec  9 15:34:37 1999
@@ -0,0 +1,120 @@
+/* $Id: sfp-util.h,v 1.3.2.1 1999/09/20 12:06:23 jj Exp $
+ * arch/sparc64/math-emu/sfp-util.h
+ *
+ * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) 						\
+  __asm__ ("addcc %4,%5,%1
+  	    add %2,%3,%0
+  	    bcs,a,pn %%xcc, 1f
+  	    add %0, 1, %0
+  	    1:"										\
+	   : "=r" ((UDItype)(sh)),				      			\
+	     "=&r" ((UDItype)(sl))				      			\
+	   : "r" ((UDItype)(ah)),				     			\
+	     "r" ((UDItype)(bh)),				      			\
+	     "r" ((UDItype)(al)),				     			\
+	     "r" ((UDItype)(bl))				       			\
+	   : "cc")
+	   
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) 						\
+  __asm__ ("subcc %4,%5,%1
+  	    sub %2,%3,%0
+  	    bcs,a,pn %%xcc, 1f
+  	    sub %0, 1, %0
+  	    1:"										\
+	   : "=r" ((UDItype)(sh)),				      			\
+	     "=&r" ((UDItype)(sl))				      			\
+	   : "r" ((UDItype)(ah)),				     			\
+	     "r" ((UDItype)(bh)),				      			\
+	     "r" ((UDItype)(al)),				     			\
+	     "r" ((UDItype)(bl))				       			\
+	   : "cc")
+
+#define umul_ppmm(wh, wl, u, v)								\
+  do {											\
+	  UDItype tmp1, tmp2, tmp3, tmp4;						\
+	  __asm__ __volatile__ (							\
+		   "srl %7,0,%3
+		    mulx %3,%6,%1
+		    srlx %6,32,%2
+		    mulx %2,%3,%4
+		    sllx %4,32,%5
+		    srl %6,0,%3
+		    sub %1,%5,%5
+		    srlx %5,32,%5
+		    addcc %4,%5,%4
+		    srlx %7,32,%5
+		    mulx %3,%5,%3
+		    mulx %2,%5,%5
+		    sethi %%hi(0x80000000),%2
+		    addcc %4,%3,%4
+		    srlx %4,32,%4
+		    add %2,%2,%2
+		    movcc %%xcc,%%g0,%2
+		    addcc %5,%4,%5
+		    sllx %3,32,%3
+		    add %1,%3,%1
+		    add %5,%2,%0"							\
+	   : "=r" ((UDItype)(wh)),							\
+	     "=&r" ((UDItype)(wl)),							\
+	     "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4)			\
+	   : "r" ((UDItype)(u)),							\
+	     "r" ((UDItype)(v))								\
+	   : "cc");									\
+  } while (0)
+  
+#define udiv_qrnnd(q, r, n1, n0, d) 							\
+  do {                                                                  		\
+    UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m;                     		\
+    __d1 = (d >> 32);                                           			\
+    __d0 = (USItype)d;                                            			\
+                                                                        		\
+    __r1 = (n1) % __d1;                                                 		\
+    __q1 = (n1) / __d1;                                                 		\
+    __m = (UWtype) __q1 * __d0;                                         		\
+    __r1 = (__r1 << 32) | (n0 >> 32);                          				\
+    if (__r1 < __m)                                                     		\
+      {                                                                 		\
+        __q1--, __r1 += (d);                                            		\
+        if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */		\
+          if (__r1 < __m)                                               		\
+            __q1--, __r1 += (d);                                        		\
+      }                                                                 		\
+    __r1 -= __m;                                                        		\
+                                                                        		\
+    __r0 = __r1 % __d1;                                                 		\
+    __q0 = __r1 / __d1;                                                 		\
+    __m = (UWtype) __q0 * __d0;                                         		\
+    __r0 = (__r0 << 32) | ((USItype)n0);                           			\
+    if (__r0 < __m)                                                     		\
+      {                                                                 		\
+        __q0--, __r0 += (d);                                            		\
+        if (__r0 >= (d))                                                		\
+          if (__r0 < __m)                                               		\
+            __q0--, __r0 += (d);                                        		\
+      }                                                                 		\
+    __r0 -= __m;                                                        		\
+                                                                        		\
+    (q) = (UWtype) (__q1 << 32)  | __q0;                                		\
+    (r) = __r0;                                                         		\
+  } while (0)
+
+#define UDIV_NEEDS_NORMALIZATION 1  
+
+#define abort()										\
+	return 0
+
+#ifdef __BIG_ENDIAN
+#define __BYTE_ORDER __BIG_ENDIAN
+#else
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/single.h linux.14p16/arch/sparc64/math-emu/single.h
--- linux.vanilla/arch/sparc64/math-emu/single.h	Wed Apr 15 01:44:21 1998
+++ linux.14p16/arch/sparc64/math-emu/single.h	Thu Jan  1 01:00:00 1970
@@ -1,66 +0,0 @@
-/*
- * Definitions for IEEE Single Precision
- */
-
-#if _FP_W_TYPE_SIZE < 32
-#error "Here's a nickel kid.  Go buy yourself a real computer."
-#endif
-
-#define _FP_FRACBITS_S		24
-#define _FP_FRACXBITS_S		(_FP_W_TYPE_SIZE - _FP_FRACBITS_S)
-#define _FP_WFRACBITS_S		(_FP_WORKBITS + _FP_FRACBITS_S)
-#define _FP_WFRACXBITS_S	(_FP_W_TYPE_SIZE - _FP_WFRACBITS_S)
-#define _FP_EXPBITS_S		8
-#define _FP_EXPBIAS_S		127
-#define _FP_EXPMAX_S		255
-#define _FP_QNANBIT_S		((_FP_W_TYPE)1 << (_FP_FRACBITS_S-2))
-#define _FP_IMPLBIT_S		((_FP_W_TYPE)1 << (_FP_FRACBITS_S-1))
-#define _FP_OVERFLOW_S		((_FP_W_TYPE)1 << (_FP_WFRACBITS_S))
-
-/* The implementation of _FP_MUL_MEAT_S and _FP_DIV_MEAT_S should be
-   chosen by the target machine.  */
-
-union _FP_UNION_S
-{
-  float flt;
-  struct {
-#if __BYTE_ORDER == __BIG_ENDIAN
-    unsigned sign : 1;
-    unsigned exp  : _FP_EXPBITS_S;
-    unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0);
-#else
-    unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0);
-    unsigned exp  : _FP_EXPBITS_S;
-    unsigned sign : 1;
-#endif
-  } bits __attribute__((packed));
-};
-
-#define FP_DECL_S(X)		_FP_DECL(1,X)
-#define FP_UNPACK_RAW_S(X,val)	_FP_UNPACK_RAW_1(S,X,val)
-#define FP_PACK_RAW_S(val,X)	_FP_PACK_RAW_1(S,val,X)
-
-#define FP_UNPACK_S(X,val)		\
-  do {					\
-    _FP_UNPACK_RAW_1(S,X,val);		\
-    _FP_UNPACK_CANONICAL(S,1,X);	\
-  } while (0)
-
-#define FP_PACK_S(val,X)		\
-  do {					\
-    _FP_PACK_CANONICAL(S,1,X);		\
-    _FP_PACK_RAW_1(S,val,X);		\
-  } while (0)
-
-#define FP_NEG_S(R,X)		_FP_NEG(S,1,R,X)
-#define FP_ADD_S(R,X,Y)		_FP_ADD(S,1,R,X,Y)
-#define FP_SUB_S(R,X,Y)		_FP_SUB(S,1,R,X,Y)
-#define FP_MUL_S(R,X,Y)		_FP_MUL(S,1,R,X,Y)
-#define FP_DIV_S(R,X,Y)		_FP_DIV(S,1,R,X,Y)
-#define FP_SQRT_S(R,X)		_FP_SQRT(S,1,R,X)
-
-#define FP_CMP_S(r,X,Y,un)	_FP_CMP(S,1,r,X,Y,un)
-#define FP_CMP_EQ_S(r,X,Y)	_FP_CMP_EQ(S,1,r,X,Y)
-
-#define FP_TO_INT_S(r,X,rsz,rsg)  _FP_TO_INT(S,1,r,X,rsz,rsg)
-#define FP_FROM_INT_S(X,r,rs,rt)  _FP_FROM_INT(S,1,X,r,rs,rt)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/soft-fp.h linux.14p16/arch/sparc64/math-emu/soft-fp.h
--- linux.vanilla/arch/sparc64/math-emu/soft-fp.h	Thu Mar 11 00:53:37 1999
+++ linux.14p16/arch/sparc64/math-emu/soft-fp.h	Thu Jan  1 01:00:00 1970
@@ -1,94 +0,0 @@
-#ifndef SOFT_FP_H
-#define SOFT_FP_H
-
-#include "sfp-machine.h"
-
-#define _FP_WORKBITS		3
-#define _FP_WORK_LSB		((_FP_W_TYPE)1 << 3)
-#define _FP_WORK_ROUND		((_FP_W_TYPE)1 << 2)
-#define _FP_WORK_GUARD		((_FP_W_TYPE)1 << 1)
-#define _FP_WORK_STICKY		((_FP_W_TYPE)1 << 0)
-
-#ifndef FP_RND_NEAREST
-# define FP_RND_NEAREST		0
-# define FP_RND_ZERO		1
-# define FP_RND_PINF		2
-# define FP_RND_MINF		3
-#ifndef FP_ROUNDMODE
-# define FP_ROUNDMODE		FP_RND_NEAREST
-#endif
-#endif
-
-#define _FP_ROUND_NEAREST(wc, X)			\
-({  int __ret = EFLAG_INEXACT;				\
-    if ((_FP_FRAC_LOW_##wc(X) & 15) != _FP_WORK_ROUND)	\
-      _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND);		\
-    else __ret = 0;					\
-    __ret;						\
-})
-
-#define _FP_ROUND_ZERO(wc, X)		0 /* XXX */
-
-#define _FP_ROUND_PINF(wc, X)				\
-({  int __ret = EFLAG_INEXACT;				\
-    if (!X##_s && (_FP_FRAC_LOW_##wc(X) & 7))		\
-      _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB);		\
-    else __ret = 0;					\
-    __ret;						\
-})
-
-#define _FP_ROUND_MINF(wc, X)				\
-({  int __ret = EFLAG_INEXACT;				\
-    if (X##_s && (_FP_FRAC_LOW_##wc(X) & 7))		\
-      _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB);		\
-    else __ret = 0;					\
-    __ret;						\
-})
-
-#define _FP_ROUND(wc, X)			\
-({	int __ret = 0;				\
-	switch (FP_ROUNDMODE)			\
-	{					\
-	  case FP_RND_NEAREST:			\
-	    __ret |= _FP_ROUND_NEAREST(wc,X);	\
-	    break;				\
-	  case FP_RND_ZERO:			\
-	    __ret |= _FP_ROUND_ZERO(wc,X);	\
-	    break;				\
-	  case FP_RND_PINF:			\
-	    __ret |= _FP_ROUND_PINF(wc,X);	\
-	    break;				\
-	  case FP_RND_MINF:			\
-	    __ret |= _FP_ROUND_MINF(wc,X);	\
-	    break;				\
-	};					\
-	__ret;					\
-})
-
-#define FP_CLS_NORMAL		0
-#define FP_CLS_ZERO		1
-#define FP_CLS_INF		2
-#define FP_CLS_NAN		3
-
-#define _FP_CLS_COMBINE(x,y)	(((x) << 2) | (y))
-
-#include "op-1.h"
-#include "op-2.h"
-#include "op-4.h"
-#include "op-common.h"
-
-/* Sigh.  Silly things longlong.h needs.  */
-#define UWtype		_FP_W_TYPE
-#define W_TYPE_SIZE	_FP_W_TYPE_SIZE
-
-typedef int SItype __attribute__((mode(SI)));
-typedef int DItype __attribute__((mode(DI)));
-typedef unsigned int USItype __attribute__((mode(SI)));
-typedef unsigned int UDItype __attribute__((mode(DI)));
-#if _FP_W_TYPE_SIZE == 32
-typedef unsigned int UHWtype __attribute__((mode(HI)));
-#elif _FP_W_TYPE_SIZE == 64
-typedef USItype UHWtype;
-#endif
-
-#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/math-emu/udivmodti4.c linux.14p16/arch/sparc64/math-emu/udivmodti4.c
--- linux.vanilla/arch/sparc64/math-emu/udivmodti4.c	Mon Jan 12 23:15:44 1998
+++ linux.14p16/arch/sparc64/math-emu/udivmodti4.c	Thu Jan  1 01:00:00 1970
@@ -1,191 +0,0 @@
-/* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny.  */
-
-#include "soft-fp.h"
-
-#undef count_leading_zeros
-#define count_leading_zeros  __FP_CLZ
-
-void
-_fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2],
-	       _FP_W_TYPE n1, _FP_W_TYPE n0,
-	       _FP_W_TYPE d1, _FP_W_TYPE d0)
-{
-  _FP_W_TYPE q0, q1, r0, r1;
-  _FP_I_TYPE b, bm;
-
-  if (d1 == 0)
-    {
-#if !UDIV_NEEDS_NORMALIZATION
-      if (d0 > n1)
-	{
-	  /* 0q = nn / 0D */
-
-	  udiv_qrnnd (q0, n0, n1, n0, d0);
-	  q1 = 0;
-
-	  /* Remainder in n0.  */
-	}
-      else
-	{
-	  /* qq = NN / 0d */
-
-	  if (d0 == 0)
-	    d0 = 1 / d0;	/* Divide intentionally by zero.  */
-
-	  udiv_qrnnd (q1, n1, 0, n1, d0);
-	  udiv_qrnnd (q0, n0, n1, n0, d0);
-
-	  /* Remainder in n0.  */
-	}
-
-      r0 = n0;
-      r1 = 0;
-
-#else /* UDIV_NEEDS_NORMALIZATION */
-
-      if (d0 > n1)
-	{
-	  /* 0q = nn / 0D */
-
-	  count_leading_zeros (bm, d0);
-
-	  if (bm != 0)
-	    {
-	      /* Normalize, i.e. make the most significant bit of the
-		 denominator set.  */
-
-	      d0 = d0 << bm;
-	      n1 = (n1 << bm) | (n0 >> (_FP_W_TYPE_SIZE - bm));
-	      n0 = n0 << bm;
-	    }
-
-	  udiv_qrnnd (q0, n0, n1, n0, d0);
-	  q1 = 0;
-
-	  /* Remainder in n0 >> bm.  */
-	}
-      else
-	{
-	  /* qq = NN / 0d */
-
-	  if (d0 == 0)
-	    d0 = 1 / d0;	/* Divide intentionally by zero.  */
-
-	  count_leading_zeros (bm, d0);
-
-	  if (bm == 0)
-	    {
-	      /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
-		 conclude (the most significant bit of n1 is set) /\ (the
-		 leading quotient digit q1 = 1).
-
-		 This special case is necessary, not an optimization.
-		 (Shifts counts of SI_TYPE_SIZE are undefined.)  */
-
-	      n1 -= d0;
-	      q1 = 1;
-	    }
-	  else
-	    {
-	      _FP_W_TYPE n2;
-
-	      /* Normalize.  */
-
-	      b = _FP_W_TYPE_SIZE - bm;
-
-	      d0 = d0 << bm;
-	      n2 = n1 >> b;
-	      n1 = (n1 << bm) | (n0 >> b);
-	      n0 = n0 << bm;
-
-	      udiv_qrnnd (q1, n1, n2, n1, d0);
-	    }
-
-	  /* n1 != d0...  */
-
-	  udiv_qrnnd (q0, n0, n1, n0, d0);
-
-	  /* Remainder in n0 >> bm.  */
-	}
-
-      r0 = n0 >> bm;
-      r1 = 0;
-#endif /* UDIV_NEEDS_NORMALIZATION */
-    }
-  else
-    {
-      if (d1 > n1)
-	{
-	  /* 00 = nn / DD */
-
-	  q0 = 0;
-	  q1 = 0;
-
-	  /* Remainder in n1n0.  */
-	  r0 = n0;
-	  r1 = n1;
-	}
-      else
-	{
-	  /* 0q = NN / dd */
-
-	  count_leading_zeros (bm, d1);
-	  if (bm == 0)
-	    {
-	      /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
-		 conclude (the most significant bit of n1 is set) /\ (the
-		 quotient digit q0 = 0 or 1).
-
-		 This special case is necessary, not an optimization.  */
-
-	      /* The condition on the next line takes advantage of that
-		 n1 >= d1 (true due to program flow).  */
-	      if (n1 > d1 || n0 >= d0)
-		{
-		  q0 = 1;
-		  sub_ddmmss (n1, n0, n1, n0, d1, d0);
-		}
-	      else
-		q0 = 0;
-
-	      q1 = 0;
-
-	      r0 = n0;
-	      r1 = n1;
-	    }
-	  else
-	    {
-	      _FP_W_TYPE m1, m0, n2;
-
-	      /* Normalize.  */
-
-	      b = _FP_W_TYPE_SIZE - bm;
-
-	      d1 = (d1 << bm) | (d0 >> b);
-	      d0 = d0 << bm;
-	      n2 = n1 >> b;
-	      n1 = (n1 << bm) | (n0 >> b);
-	      n0 = n0 << bm;
-
-	      udiv_qrnnd (q0, n1, n2, n1, d1);
-	      umul_ppmm (m1, m0, q0, d0);
-
-	      if (m1 > n1 || (m1 == n1 && m0 > n0))
-		{
-		  q0--;
-		  sub_ddmmss (m1, m0, m1, m0, d1, d0);
-		}
-
-	      q1 = 0;
-
-	      /* Remainder in (n1n0 - m1m0) >> bm.  */
-	      sub_ddmmss (n1, n0, n1, n0, m1, m0);
-	      r0 = (n1 << b) | (n0 >> bm);
-	      r1 = n1 >> bm;
-	    }
-	}
-    }
-
-  q[0] = q0; q[1] = q1;
-  r[0] = r0, r[1] = r1;
-}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/mm/asyncd.c linux.14p16/arch/sparc64/mm/asyncd.c
--- linux.vanilla/arch/sparc64/mm/asyncd.c	Sun Oct  4 18:22:43 1998
+++ linux.14p16/arch/sparc64/mm/asyncd.c	Thu Dec  9 15:34:36 1999
@@ -1,4 +1,4 @@
-/*  $Id: asyncd.c,v 1.5 1998/09/13 04:30:33 davem Exp $
+/*  $Id: asyncd.c,v 1.5.2.1 1999/11/16 06:29:53 davem Exp $
  *  The asyncd kernel daemon. This handles paging on behalf of 
  *  processes that receive page faults due to remote (async) memory
  *  accesses. 
@@ -152,7 +152,9 @@
 	if(!pte)
 		goto no_memory;
 	if(!pte_present(*pte)) {
-		handle_mm_fault(tsk, vma, address, write);
+		int fault = handle_mm_fault(tsk, vma, address, write);
+		if (fault < 0)
+			goto no_memory;
 		goto finish_up;
 	}
 	set_pte(pte, pte_mkyoung(*pte));
@@ -164,7 +166,11 @@
 		flush_tlb_page(vma, address);
 		goto finish_up;
 	}
-	handle_mm_fault(tsk, vma, address, write);
+	{
+		int fault = handle_mm_fault(tsk, vma, address, write);
+		if (fault < 0)
+			goto no_memory;
+	}
 
 	/* Fall through for do_wp_page */
 finish_up:
@@ -173,7 +179,7 @@
 
 no_memory:
 	stats.failure++;
-	oom(tsk);
+	force_sig(SIGKILL, tsk);
 	return 1;
 	
 bad_area:	  
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/mm/fault.c linux.14p16/arch/sparc64/mm/fault.c
--- linux.vanilla/arch/sparc64/mm/fault.c	Wed Mar 17 05:52:06 1999
+++ linux.14p16/arch/sparc64/mm/fault.c	Thu Dec  9 15:34:36 1999
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.34 1999/03/16 12:12:28 jj Exp $
+/* $Id: fault.c,v 1.34.2.1 1999/11/16 06:29:56 davem Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -210,8 +210,15 @@
 			goto bad_area;
 	}
 	current->mm->segments = (void *) (address & PAGE_SIZE);
-	if (!handle_mm_fault(current, vma, address, write))
-		goto do_sigbus;
+survive:
+	{
+		int fault = handle_mm_fault(current, vma, address, write);
+		if (!fault)
+			goto do_sigbus;
+		if (fault < 0)
+			goto out_of_memory;
+	}
+
 	up(&mm->mmap_sem);
 	return;
 	/*
@@ -289,6 +296,17 @@
 		}
 		unhandled_fault (address, current, regs);
 	}
+	return;
+
+out_of_memory:
+	if (current->pid == 1) {
+		current->policy |= SCHED_YIELD;
+		schedule();
+		goto survive;
+	}
+	up(&mm->mmap_sem);
+	printk("VM: killing process %s\n", current->comm);
+	do_exit(SIGKILL);
 	return;
 
 do_sigbus:
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/mm/init.c linux.14p16/arch/sparc64/mm/init.c
--- linux.vanilla/arch/sparc64/mm/init.c	Sat Aug 14 02:27:16 1999
+++ linux.14p16/arch/sparc64/mm/init.c	Thu Dec  9 15:34:36 1999
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.127.2.1 1999/06/25 10:42:10 davem Exp $
+/*  $Id: init.c,v 1.127.2.6 1999/12/05 07:24:42 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -40,9 +40,6 @@
 /* Ugly, but necessary... -DaveM */
 unsigned long phys_base;
 
-/* get_new_mmu_context() uses "cache + 1".  */
-unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
-
 /* References to section boundaries */
 extern char __init_begin, __init_end, etext, __bss_start;
 
@@ -56,8 +53,10 @@
 			if(pgd_quicklist)
 				free_pgd_slow(get_pgd_fast()), freed++;
 #endif
-			if(pte_quicklist)
-				free_pte_slow(get_pte_fast()), freed++;
+			if(pte_quicklist[0])
+				free_pte_slow(get_pte_fast(0)), freed++;
+			if(pte_quicklist[1])
+				free_pte_slow(get_pte_fast(1)), freed++;
 		} while(pgtable_cache_size > low);
 	}
 #ifndef __SMP__ 
@@ -646,13 +645,23 @@
 	unsigned long data;
 };
 
-static inline void inherit_prom_mappings(void)
+extern unsigned long prom_boot_page;
+extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle);
+extern int prom_get_mmu_ihandle(void);
+extern void register_prom_callbacks(void);
+
+/* Exported for SMP bootup purposes. */
+unsigned long kern_locked_tte_data;
+
+static void inherit_prom_mappings(void)
 {
 	struct linux_prom_translation *trans;
+	unsigned long phys_page, tte_vaddr, tte_data;
+	void (*remap_func)(unsigned long, unsigned long, int);
 	pgd_t *pgdp;
 	pmd_t *pmdp;
 	pte_t *ptep;
-	int node, n, i;
+	int node, n, i, tsz;
 
 	node = prom_finddevice("/virtual-memory");
 	n = prom_getproplen(node, "translations");
@@ -660,11 +669,12 @@
 		prom_printf("Couldn't get translation property\n");
 		prom_halt();
 	}
+	n += 5 * sizeof(struct linux_prom_translation);
+	for (tsz = 1; tsz < n; tsz <<= 1)
+		/* empty */;
+	trans = sparc_init_alloc(&mempool, tsz);
 
-	for (i = 1; i < n; i <<= 1) /* empty */;
-	trans = sparc_init_alloc(&mempool, i);
-
-	if (prom_getproperty(node, "translations", (char *)trans, i) == -1) {
+	if ((n = prom_getproperty(node, "translations", (char *)trans, tsz)) == -1) {
 		prom_printf("Couldn't get translation property\n");
 		prom_halt();
 	}
@@ -696,6 +706,83 @@
 			}
 		}
 	}
+
+	/* Now fixup OBP's idea about where we really are mapped. */
+	prom_printf("Remapping the kernel... ");
+	phys_page = spitfire_get_dtlb_data(63) & _PAGE_PADDR;
+	phys_page += ((unsigned long)&prom_boot_page -
+		      (unsigned long)&empty_zero_page);
+
+	/* Lock this into i/d tlb entry 59 */
+	__asm__ __volatile__(
+		"stxa	%%g0, [%2] %3\n\t"
+		"stxa	%0, [%1] %4\n\t"
+		"membar	#Sync\n\t"
+		"flush	%%g6\n\t"
+		"stxa	%%g0, [%2] %5\n\t"
+		"stxa	%0, [%1] %6\n\t"
+		"membar	#Sync\n\t"
+		"flush	%%g6"
+		: : "r" (phys_page | _PAGE_VALID | _PAGE_SZ8K | _PAGE_CP |
+			 _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W),
+		    "r" (59 << 3), "r" (TLB_TAG_ACCESS),
+		    "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS),
+		    "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS)
+		: "memory");
+
+	tte_vaddr = (unsigned long) &empty_zero_page;
+	kern_locked_tte_data = tte_data = spitfire_get_dtlb_data(63);
+
+	remap_func = (void *)  ((unsigned long) &prom_remap -
+				(unsigned long) &prom_boot_page);
+
+	remap_func(spitfire_get_dtlb_data(63) & _PAGE_PADDR,
+		   (unsigned long) &empty_zero_page,
+		   prom_get_mmu_ihandle());
+
+	/* Flush out that temporary mapping. */
+	spitfire_flush_dtlb_nucleus_page(0x0);
+	spitfire_flush_itlb_nucleus_page(0x0);
+
+	/* Now lock us back into the TLBs via OBP. */
+	prom_dtlb_load(63, tte_data, tte_vaddr);
+	prom_itlb_load(63, tte_data, tte_vaddr);
+
+	/* Re-read translations property. */
+	if ((n = prom_getproperty(node, "translations", (char *)trans, tsz)) == -1) {
+		prom_printf("Couldn't get translation property\n");
+		prom_halt();
+	}
+	n = n / sizeof(*trans);
+
+	for (i = 0; i < n; i++) {
+		unsigned long vaddr = trans[i].virt;
+		unsigned long size = trans[i].size;
+
+		if (vaddr < 0xf0000000UL) {
+			unsigned long avoid_start = (unsigned long) &empty_zero_page;
+			unsigned long avoid_end = avoid_start + (4 * 1024 * 1024);
+
+			if (vaddr < avoid_start) {
+				unsigned long top = vaddr + size;
+
+				if (top > avoid_start)
+					top = avoid_start;
+				prom_unmap(top - vaddr, vaddr);
+			}
+			if ((vaddr + size) > avoid_end) {
+				unsigned long bottom = vaddr;
+
+				if (bottom < avoid_end)
+					bottom = avoid_end;
+				prom_unmap((vaddr + size) - bottom, bottom);
+			}
+		}
+	}
+
+	prom_printf("done.\n");
+
+	register_prom_callbacks();
 }
 
 /* The OBP specifications for sun4u mark 0xfffffffc00000000 and
@@ -956,6 +1043,8 @@
 
 #define CTX_BMAP_SLOTS (1UL << (CTX_VERSION_SHIFT - 6))
 unsigned long mmu_context_bmap[CTX_BMAP_SLOTS];
+spinlock_t ctx_alloc_lock = SPIN_LOCK_UNLOCKED;
+unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
 
 /* Caller does TLB context flushing on local CPU if necessary.
  *
@@ -966,14 +1055,17 @@
  */
 void get_new_mmu_context(struct mm_struct *mm)
 {
-	unsigned long ctx = (tlb_context_cache + 1) & ~(CTX_VERSION_MASK);
-	unsigned long new_ctx;
+	unsigned long ctx, new_ctx;
 	
+	spin_lock(&ctx_alloc_lock);
+	ctx = (tlb_context_cache + 1) & ~(CTX_VERSION_MASK);
 	if (ctx == 0)
 		ctx = 1;
 	if ((mm->context != NO_CONTEXT) &&
-	    !((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK))
-		clear_bit(mm->context & ~(CTX_VERSION_MASK), mmu_context_bmap);
+	    !((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK)) {
+		unsigned long nr = mm->context & ~(CTX_VERSION_MASK);
+		mmu_context_bmap[nr >> 6] &= ~(1UL << (nr & 63));
+	}
 	new_ctx = find_next_zero_bit(mmu_context_bmap, 1UL << CTX_VERSION_SHIFT, ctx);
 	if (new_ctx >= (1UL << CTX_VERSION_SHIFT)) {
 		new_ctx = find_next_zero_bit(mmu_context_bmap, ctx, 1);
@@ -1000,10 +1092,12 @@
 			goto out;
 		}
 	}
-	set_bit(new_ctx, mmu_context_bmap);
+	mmu_context_bmap[new_ctx >> 6] |= (1UL << (new_ctx & 63));
 	new_ctx |= (tlb_context_cache & CTX_VERSION_MASK);
 out:
 	tlb_context_cache = new_ctx;
+	spin_unlock(&ctx_alloc_lock);
+
 	mm->context = new_ctx;
 	mm->cpu_vm_mask = 0;
 }
@@ -1012,6 +1106,10 @@
 struct pgtable_cache_struct pgt_quicklists;
 #endif
 
+/* For PMDs we don't care about the color, writes are
+ * only done via Dcache which is write-thru, so non-Dcache
+ * reads will always see correct data.
+ */
 pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
 {
 	pmd_t *pmd;
@@ -1025,13 +1123,51 @@
 	return NULL;
 }
 
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+/* OK, we have to color these pages because during DTLB
+ * protection faults we set the dirty bit via a non-Dcache
+ * enabled mapping in the VPTE area.  The kernel can end
+ * up missing the dirty bit resulting in processes crashing
+ * _iff_ the VPTE mapping of the ptes have a virtual address
+ * bit 13 which is different from bit 13 of the physical address.
+ *
+ * The sequence is:
+ *	1) DTLB protection fault, write dirty bit into pte via VPTE
+ *	   mappings.
+ *	2) Swapper checks pte, does not see dirty bit, frees page.
+ *	3) Process faults back in the page, the old pre-dirtied copy
+ *	   is provided and here is the corruption.
+ */
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset, unsigned long color)
 {
-	pte_t *pte;
+	unsigned long paddr = __get_free_pages(GFP_KERNEL, 1);
+
+	if (paddr) {
+		struct page *page2 = mem_map + MAP_NR(paddr + PAGE_SIZE);
+		unsigned long *to_free;
+		pte_t *pte;
+
+		/* Set count of second page, so we can free it
+		 * seperately later on.
+		 */
+		atomic_set(&page2->count, 1);
+
+		/* Clear out both pages now. */
+		memset((char *)paddr, 0, (PAGE_SIZE << 1));
+
+		/* Determine which page we give to this request. */
+		if (!color) {
+			pte = (pte_t *) paddr;
+			to_free = (unsigned long *) (paddr + PAGE_SIZE);
+		} else {
+			pte = (pte_t *) (paddr + PAGE_SIZE);
+			to_free = (unsigned long *) paddr;
+		}
+
+		/* Now free the other one up, adjust cache size. */
+		*to_free = (unsigned long) pte_quicklist[color ^ 0x1];
+		pte_quicklist[color ^ 0x1] = to_free;
+		pgtable_cache_size++;
 
-	pte = (pte_t *) __get_free_page(GFP_KERNEL);
-	if(pte) {
-		memset(pte, 0, PAGE_SIZE);
 		pmd_set(pmd, pte);
 		return pte + offset;
 	}
@@ -1214,7 +1350,7 @@
 	/* Allocate 64M for dynamic DVMA mapping area. */
 	allocate_ptable_skeleton(DVMA_VADDR, DVMA_VADDR + 0x4000000);
 	inherit_prom_mappings();
-	
+
 	/* Ok, we can use our TLB miss and window trap handlers safely.
 	 * We need to do a quick peek here to see if we are on StarFire
 	 * or not, so setup_tba can setup the IRQ globals correctly (it
@@ -1230,24 +1366,12 @@
 		setup_tba(is_starfire);
 	}
 
-	/* Really paranoid. */
-	flushi((long)&empty_zero_page);
-	membar("#Sync");
-
-	/* Cleanup the extra locked TLB entry we created since we have the
-	 * nice TLB miss handlers of ours installed now.
-	 */
+	inherit_locked_prom_mappings(1);
+	
 	/* We only created DTLB mapping of this stuff. */
 	spitfire_flush_dtlb_nucleus_page(alias_base);
 	if (second_alias_page)
 		spitfire_flush_dtlb_nucleus_page(second_alias_page);
-	membar("#Sync");
-
-	/* Paranoid */
-	flushi((long)&empty_zero_page);
-	membar("#Sync");
-
-	inherit_locked_prom_mappings(1);
 
 	flush_tlb_all();
 
@@ -1256,11 +1380,97 @@
 	return device_scan (PAGE_ALIGN (start_mem));
 }
 
+/* Ok, it seems that the prom can allocate some more memory chunks
+ * as a side effect of some prom calls we perform during the
+ * boot sequence.  My most likely theory is that it is from the
+ * prom_set_traptable() call, and OBP is allocating a scratchpad
+ * for saving client program register state etc.
+ */
+__initfunc(static void sort_memlist(struct linux_mlist_p1275 *thislist))
+{
+	int swapi = 0;
+	int i, mitr;
+	unsigned long tmpaddr, tmpsize;
+	unsigned long lowest;
+
+	for(i=0; thislist[i].theres_more != 0; i++) {
+		lowest = thislist[i].start_adr;
+		for(mitr = i+1; thislist[mitr-1].theres_more != 0; mitr++)
+			if(thislist[mitr].start_adr < lowest) {
+				lowest = thislist[mitr].start_adr;
+				swapi = mitr;
+			}
+		if(lowest == thislist[i].start_adr) continue;
+		tmpaddr = thislist[swapi].start_adr;
+		tmpsize = thislist[swapi].num_bytes;
+		for(mitr = swapi; mitr > i; mitr--) {
+			thislist[mitr].start_adr = thislist[mitr-1].start_adr;
+			thislist[mitr].num_bytes = thislist[mitr-1].num_bytes;
+		}
+		thislist[i].start_adr = tmpaddr;
+		thislist[i].num_bytes = tmpsize;
+	}
+}
+
+__initfunc(static void rescan_sp_banks(void))
+{
+	struct linux_prom64_registers memlist[64];
+	struct linux_mlist_p1275 avail[64], *mlist;
+	unsigned long bytes, base_paddr;
+	int num_regs, node = prom_finddevice("/memory");
+	int i;
+
+	num_regs = prom_getproperty(node, "available",
+				    (char *) memlist, sizeof(memlist));
+	num_regs = (num_regs / sizeof(struct linux_prom64_registers));
+	for (i = 0; i < num_regs; i++) {
+		avail[i].start_adr = memlist[i].phys_addr;
+		avail[i].num_bytes = memlist[i].reg_size;
+		avail[i].theres_more = &avail[i + 1];
+	}
+	avail[i - 1].theres_more = NULL;
+	sort_memlist(avail);
+
+	mlist = &avail[0];
+	i = 0;
+	bytes = mlist->num_bytes;
+	base_paddr = mlist->start_adr;
+  
+	sp_banks[0].base_addr = base_paddr;
+	sp_banks[0].num_bytes = bytes;
+
+	while (mlist->theres_more != NULL){
+		i++;
+		mlist = mlist->theres_more;
+		bytes = mlist->num_bytes;
+		if (i >= SPARC_PHYS_BANKS-1) {
+			printk ("The machine has more banks than "
+				"this kernel can support\n"
+				"Increase the SPARC_PHYS_BANKS "
+				"setting (currently %d)\n",
+				SPARC_PHYS_BANKS);
+			i = SPARC_PHYS_BANKS-1;
+			break;
+		}
+    
+		sp_banks[i].base_addr = mlist->start_adr;
+		sp_banks[i].num_bytes = mlist->num_bytes;
+	}
+
+	i++;
+	sp_banks[i].base_addr = 0xdeadbeefbeefdeadUL;
+	sp_banks[i].num_bytes = 0;
+
+	for (i = 0; sp_banks[i].num_bytes != 0; i++)
+		sp_banks[i].num_bytes &= PAGE_MASK;
+}
+
 __initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long end_mem))
 {
 	unsigned long tmp = 0, paddr, endaddr;
 	unsigned long end = __pa(end_mem);
 
+	rescan_sp_banks();
 	dvmaio_init();
 	for (paddr = __pa(start_mem); paddr < end; ) {
 		for (; sp_banks[tmp].num_bytes != 0; tmp++)
@@ -1316,6 +1526,7 @@
 	max_mapnr = MAP_NR(end_mem);
 	high_memory = (void *) end_mem;
 	
+	start_mem = ((start_mem + 7UL) & ~7UL);
 	sparc64_valid_addr_bitmap = (unsigned long *)start_mem;
 	i = max_mapnr >> ((22 - PAGE_SHIFT) + 6);
 	i += 1;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/mm/ultra.S linux.14p16/arch/sparc64/mm/ultra.S
--- linux.vanilla/arch/sparc64/mm/ultra.S	Sun Mar 28 18:07:47 1999
+++ linux.14p16/arch/sparc64/mm/ultra.S	Thu Dec  9 15:34:36 1999
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.32 1999/03/28 08:39:34 davem Exp $
+/* $Id: ultra.S,v 1.32.2.1 1999/10/24 17:29:34 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -173,10 +173,10 @@
 	 *
 	 * Register usage:
 	 *   %g5	mm->context	(all tlb flushes)
-	 *   %g6	address arg 1	(tlb page and range flushes)
+	 *   %g1	address arg 1	(tlb page and range flushes)
 	 *   %g7	address arg 2	(tlb range flush only)
 	 *
-	 *   %g1	ivector table, don't touch
+	 *   %g6	ivector table, don't touch
 	 *   %g2	scratch 1
 	 *   %g3	scratch 2
 	 *   %g4	scratch 3
@@ -187,7 +187,7 @@
 	.globl		xcall_flush_tlb_page, xcall_flush_tlb_mm, xcall_flush_tlb_range
 xcall_flush_tlb_page:
 	mov		SECONDARY_CONTEXT, %g2
-	or		%g6, 0x10, %g4
+	or		%g1, 0x10, %g4
 	ldxa		[%g2] ASI_DMMU, %g3
 	stxa		%g5, [%g2] ASI_DMMU
 	stxa		%g0, [%g4] ASI_DMMU_DEMAP
@@ -208,11 +208,11 @@
 xcall_flush_tlb_range:
 	sethi		%hi(8192 - 1), %g2
 	or		%g2, %lo(8192 - 1), %g2
-	andn		%g6, %g2, %g6
+	andn		%g1, %g2, %g1
 	andn		%g7, %g2, %g7
-	sub		%g7, %g6, %g3
+	sub		%g7, %g1, %g3
 	add		%g2, 1, %g2
-	orcc		%g6, 0x10, %g6
+	orcc		%g1, 0x10, %g1
 	srlx		%g3, 13, %g4
 
 	cmp		%g4, 96
@@ -224,8 +224,8 @@
 	nop
 	nop
 
-1:	stxa		%g0, [%g6 + %g3] ASI_DMMU_DEMAP
-	stxa		%g0, [%g6 + %g3] ASI_IMMU_DEMAP
+1:	stxa		%g0, [%g1 + %g3] ASI_DMMU_DEMAP
+	stxa		%g0, [%g1 + %g3] ASI_IMMU_DEMAP
 	brnz,pt		%g3, 1b
 	 sub		%g3, %g2, %g3
 	stxa		%g7, [%g4] ASI_DMMU
@@ -261,6 +261,22 @@
 	b,pt		%xcc, rtrap
 	 clr		%l6
 
+	.globl		xcall_promstop
+xcall_promstop:
+	rdpr		%pstate, %g2
+	wrpr		%g2, PSTATE_IG | PSTATE_AG, %pstate
+	rdpr		%pil, %g2
+	wrpr		%g0, 15, %pil
+	sethi		%hi(109f), %g7
+	b,pt		%xcc, etrap_irq
+109:	 or		%g7, %lo(109b), %g7
+	flushw
+	call		prom_stopself
+	 nop
+	/* We should not return, just spin if we do... */
+1:	b,a,pt		%xcc, 1b
+	nop
+
 	.globl		xcall_receive_signal
 xcall_receive_signal:
 	rdpr		%pstate, %g2
@@ -302,7 +318,7 @@
 	cmp		%g2, 63
 	ble,pt		%icc, 1b
 	 sll		%g2, 3, %g3
-	flush		%g1
+	flush		%g6
 	retry
 
 	.globl		xcall_flush_cache_all
@@ -315,6 +331,6 @@
 	cmp		%g3, %g2
 	bleu,pt		%xcc, 1b
 	 nop
-	flush		%g1
+	flush		%g6
 	retry
 #endif /* __SMP__ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/prom/Makefile linux.14p16/arch/sparc64/prom/Makefile
--- linux.vanilla/arch/sparc64/prom/Makefile	Mon Mar 17 22:54:23 1997
+++ linux.14p16/arch/sparc64/prom/Makefile	Thu Dec  9 15:34:37 1999
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.2 1997/02/25 12:40:25 jj Exp $
+# $Id: Makefile,v 1.2.6.1 1999/10/24 17:29:02 davem Exp $
 # Makefile for the Sun Boot PROM interface library under
 # Linux.
 #
@@ -9,13 +9,19 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 OBJS  = bootstr.o devops.o init.o memory.o misc.o \
-        ranges.o tree.o console.o printf.o p1275.o
+        ranges.o tree.o console.o printf.o p1275.o map.o
 
 all: promlib.a
 
 promlib.a: $(OBJS)
 	$(AR) rcs promlib.a $(OBJS)
 	sync
+
+.S.s:
+	$(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+
+.S.o:
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
 
 dep:
 	$(CPP) -M *.c > .depend
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/prom/map.S linux.14p16/arch/sparc64/prom/map.S
--- linux.vanilla/arch/sparc64/prom/map.S	Thu Jan  1 01:00:00 1970
+++ linux.14p16/arch/sparc64/prom/map.S	Thu Dec  9 15:34:37 1999
@@ -0,0 +1,70 @@
+/* $Id: map.S,v 1.1.2.1 1999/10/24 17:28:59 davem Exp $
+ * map.S: Tricky coding required to fixup the kernel OBP maps
+ *	  properly.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+	.text
+	.align	8192
+	.globl	prom_boot_page
+prom_boot_page:
+call_method:
+	.asciz	"call-method"
+	.align	8
+map:
+	.asciz	"map"
+	.align	8
+
+	/* When we are invoked, our caller has remapped us to
+	 * page zero, therefore we must use PC relative addressing
+	 * for everything after we begin performing the unmap/map
+	 * calls.
+	 */
+	.globl	prom_remap
+prom_remap:	/* %o0 = physpage, %o1 = virtpage, %o2 = mmu_ihandle */
+	rd	%pc, %g1
+	srl	%o2, 0, %o2			! kill sign extension
+	sethi	%hi(p1275buf), %g2
+	or	%g2, %lo(p1275buf), %g2
+	ldx	[%g2 + 0x10], %g3		! prom_cif_stack
+	save	%g3, -(192 + 128), %sp
+	ldx	[%g2 + 0x08], %l0		! prom_cif_handler
+	mov	%g6, %i3
+	mov	%g4, %i4
+	flushw
+
+	sethi	%hi(prom_remap - call_method), %g7
+	or	%g7, %lo(prom_remap - call_method), %g7
+	sub	%g1, %g7, %l2			! call-method string
+	sethi	%hi(prom_remap - map), %g7
+	or	%g7, %lo(prom_remap - map), %g7
+	sub	%g1, %g7, %l4			! map string
+
+	/* OK, map the 4MB region we really live at. */
+	stx	%l2, [%sp + 2047 + 128 + 0x00]	! call-method
+	mov	7, %l5
+	stx	%l5, [%sp + 2047 + 128 + 0x08]	! num_args
+	mov	1, %l5
+	stx	%l5, [%sp + 2047 + 128 + 0x10]	! num_rets
+	stx	%l4, [%sp + 2047 + 128 + 0x18]	! map
+	stx	%i2, [%sp + 2047 + 128 + 0x20]	! mmu_ihandle
+	mov	-1, %l5
+	stx	%l5, [%sp + 2047 + 128 + 0x28]	! mode == default
+	sethi	%hi(4 * 1024 * 1024), %l5
+	stx	%l5, [%sp + 2047 + 128 + 0x30]	! size
+	stx	%i1, [%sp + 2047 + 128 + 0x38]	! vaddr
+	stx	%g0, [%sp + 2047 + 128 + 0x40]	! filler
+	stx	%i0, [%sp + 2047 + 128 + 0x48]	! paddr
+	call	%l0
+	 add	%sp, (2047 + 128), %o0		! argument array
+
+	/* Restore hard-coded globals. */
+	mov	%i3, %g6
+	mov	%i4, %g4
+
+	/* Wheee.... we are done. */
+	ret
+	restore
+
+	.align	8192
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/prom/misc.c linux.14p16/arch/sparc64/prom/misc.c
--- linux.vanilla/arch/sparc64/prom/misc.c	Wed Oct 20 01:12:34 1999
+++ linux.14p16/arch/sparc64/prom/misc.c	Thu Dec  9 15:34:37 1999
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.14.2.1 1999/08/19 01:11:18 davem Exp $
+/* $Id: misc.c,v 1.14.2.3 1999/10/27 00:22:26 davem Exp $
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
@@ -10,6 +10,8 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 
@@ -37,6 +39,11 @@
 extern int serial_console;
 #endif
 
+#ifdef __SMP__
+extern void smp_capture(void);
+extern void smp_release(void);
+#endif
+
 /* Drop into the prom, with the chance to continue with the 'go'
  * prom command.
  */
@@ -44,26 +51,57 @@
 prom_cmdline(void)
 {
 	unsigned long flags;
-    
+
+	__save_and_cli(flags);
+
 #ifdef CONFIG_SUN_CONSOLE
 	if(!serial_console && prom_palette)
 		prom_palette (1);
 #endif
-	__save_and_cli(flags);
+
+	/* We always arrive here via a serial interrupt.
+	 * So in order for everything to work reliably, even
+	 * on SMP, we need to drop the IRQ locks we hold.
+	 */
+#ifdef __SMP__
+	hardirq_exit(smp_processor_id());
+	smp_capture();
+#else
+	local_irq_count--;
+#endif
+
 	p1275_cmd ("enter", P1275_INOUT(0,0));
-	__restore_flags(flags);
+
+#ifdef __SMP__
+	smp_release();
+	hardirq_enter(smp_processor_id());
+	spin_unlock_wait(&global_irq_lock);
+#else
+	local_irq_count++;
+#endif
+
 #ifdef CONFIG_SUN_CONSOLE
 	if(!serial_console && prom_palette)
 		prom_palette (0);
 #endif
+
+	__restore_flags(flags);
 }
 
+#ifdef __SMP__
+extern void smp_promstop_others(void);
+#endif
+
 /* Drop into the prom, but completely terminate the program.
  * No chance of continuing.
  */
 void
 prom_halt(void)
 {
+#ifdef __SMP__
+	smp_promstop_others();
+	udelay(8000);
+#endif
 again:
 	p1275_cmd ("exit", P1275_INOUT(0,0));
 	goto again; /* PROM is out to get me -DaveM */
@@ -122,10 +160,10 @@
 	p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba);
 }
 
-/* This is only used internally below. */
-static int prom_get_mmu_ihandle(void)
+int mmu_ihandle_cache = 0;
+
+int prom_get_mmu_ihandle(void)
 {
-	static int mmu_ihandle_cache = 0;
 	int node, ret;
 
 	if (mmu_ihandle_cache != 0)
@@ -165,7 +203,10 @@
 		    unsigned long vaddr)
 {
 	return p1275_cmd("call-method",
-			 (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 1)),
+			 (P1275_ARG(0, P1275_ARG_IN_STRING) |
+			  P1275_ARG(2, P1275_ARG_IN_64B) |
+			  P1275_ARG(3, P1275_ARG_IN_64B) |
+			  P1275_INOUT(5, 1)),
 			 "SUNW,itlb-load",
 			 prom_get_mmu_ihandle(),
 			 /* And then our actual args are pushed backwards. */
@@ -179,7 +220,10 @@
 		    unsigned long vaddr)
 {
 	return p1275_cmd("call-method",
-			 (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 1)),
+			 (P1275_ARG(0, P1275_ARG_IN_STRING) |
+			  P1275_ARG(2, P1275_ARG_IN_64B) |
+			  P1275_ARG(3, P1275_ARG_IN_64B) |
+			  P1275_INOUT(5, 1)),
 			 "SUNW,dtlb-load",
 			 prom_get_mmu_ihandle(),
 			 /* And then our actual args are pushed backwards. */
@@ -188,6 +232,41 @@
 			 index);
 }
 
+int prom_map(int mode, unsigned long size,
+	     unsigned long vaddr, unsigned long paddr)
+{
+	int ret = p1275_cmd("call-method",
+			    (P1275_ARG(0, P1275_ARG_IN_STRING) |
+			     P1275_ARG(3, P1275_ARG_IN_64B) |
+			     P1275_ARG(4, P1275_ARG_IN_64B) |
+			     P1275_ARG(6, P1275_ARG_IN_64B) |
+			     P1275_INOUT(7, 1)),
+			    "map",
+			    prom_get_mmu_ihandle(),
+			    mode,
+			    size,
+			    vaddr,
+			    0,
+			    paddr);
+
+	if (ret == 0)
+		ret = -1;
+	return ret;
+}
+
+void prom_unmap(unsigned long size, unsigned long vaddr)
+{
+	p1275_cmd("call-method",
+		  (P1275_ARG(0, P1275_ARG_IN_STRING) |
+		   P1275_ARG(2, P1275_ARG_IN_64B) |
+		   P1275_ARG(3, P1275_ARG_IN_64B) |
+		   P1275_INOUT(4, 0)),
+		  "unmap",
+		  prom_get_mmu_ihandle(),
+		  size,
+		  vaddr);
+}
+
 /* Set aside physical memory which is not touched or modified
  * across soft resets.
  */
@@ -226,7 +305,7 @@
 	return p1275_cmd("call-method",
 			 (P1275_ARG(0, P1275_ARG_IN_STRING)	|
 			  P1275_ARG(3, P1275_ARG_OUT_BUF)	|
-			  P1275_ARG(5, P1275_ARG_IN_64B)	|
+			  P1275_ARG(6, P1275_ARG_IN_64B)	|
 			  P1275_INOUT(8, 2)),
 			 "SUNW,get-unumber", prom_get_memory_ihandle(),
 			 buflen, buf, P1275_SIZE(buflen),
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/prom/p1275.c linux.14p16/arch/sparc64/prom/p1275.c
--- linux.vanilla/arch/sparc64/prom/p1275.c	Wed Oct 20 01:12:34 1999
+++ linux.14p16/arch/sparc64/prom/p1275.c	Thu Dec  9 15:34:37 1999
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.15.2.1 1999/08/19 01:11:19 davem Exp $
+/* $Id: p1275.c,v 1.15.2.3 1999/10/27 00:22:27 davem Exp $
  * p1275.c: Sun IEEE 1275 PROM low level interface routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -253,9 +253,7 @@
  */
 static int prom_entry_depth = 0;
 #ifdef __SMP__
-static spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED;
-extern void smp_capture(void);
-extern void smp_release(void);
+spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED;
 #endif
 
 static __inline__ unsigned long prom_get_lock(void)
@@ -270,9 +268,6 @@
 		if (prom_entry_depth != 0)
 			panic("prom_get_lock");
 #endif
-#ifdef __SMP__
-		smp_capture();
-#endif
 	}
 	prom_entry_depth++;
 
@@ -281,12 +276,9 @@
 
 static __inline__ void prom_release_lock(unsigned long flags)
 {
-	if (--prom_entry_depth == 0) {
-#ifdef __SMP__
-		smp_release();
-#endif
+	if (--prom_entry_depth == 0)
 		spin_unlock(&prom_entry_lock);
-	}
+
 	__restore_flags(flags);
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/Makefile linux.14p16/drivers/Makefile
--- linux.vanilla/drivers/Makefile	Sat Aug 14 02:27:16 1999
+++ linux.14p16/drivers/Makefile	Fri Dec 17 18:52:20 1999
@@ -10,7 +10,7 @@
 SUB_DIRS     := block char net misc sound
 MOD_SUB_DIRS := $(SUB_DIRS)
 ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp \
-				macintosh video dio zorro fc4 usb
+				macintosh video dio zorro fc4 usb telephony
 
 ifdef CONFIG_DIO
 SUB_DIRS += dio
@@ -109,6 +109,16 @@
   MOD_SUB_DIRS += fc4
   endif
 endif
+
+ifeq ($(CONFIG_PHONE),y)
+SUB_DIRS += telephony
+MOD_SUB_DIRS += telephony
+else
+  ifeq ($(CONFIG_PHONE),m)
+  MOD_SUB_DIRS += telephony
+  endif
+endif
+
 
 # When MOD_LIST_NAME is set, make will try to add $(MOD_SUB_DIRS).o to
 # modules/MOD_LIST_NAME.  We don't have hamradio.o and Linus
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/Config.in linux.14p16/drivers/block/Config.in
--- linux.vanilla/drivers/block/Config.in	Sat Aug 14 02:27:16 1999
+++ linux.14p16/drivers/block/Config.in	Tue Dec 14 16:18:59 1999
@@ -131,7 +131,9 @@
 if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then
   source drivers/block/paride/Config.in
 fi
-tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
+if [ "$CONFIG_PCI" = "y" ]; then
+  tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
+fi
 
 if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then
   define_bool CONFIG_BLK_DEV_HD y
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/genhd.c linux.14p16/drivers/block/genhd.c
--- linux.vanilla/drivers/block/genhd.c	Wed Oct 20 01:12:34 1999
+++ linux.14p16/drivers/block/genhd.c	Thu Dec  9 15:33:39 1999
@@ -784,8 +784,11 @@
 	label = (struct sun_disklabel *) bh->b_data;
 	p = label->partitions;
 	if (be16_to_cpu(label->magic) != SUN_LABEL_MAGIC) {
+#if 0
+		/* There is no error here - it is just not a sunlabel. */
 		printk("Dev %s Sun disklabel: bad magic %04x\n",
 		       kdevname(dev), be16_to_cpu(label->magic));
+#endif
 		brelse(bh);
 		return 0;
 	}
@@ -856,8 +859,11 @@
 	p = &label->partitions[0];
 	magic = label->magic_mushroom;
 	if(be32_to_cpu(magic) != SGI_LABEL_MAGIC) {
+#if 0
+		/* There is no error here - it is just not an sgilabel. */
 		printk("Dev %s SGI disklabel: bad magic %08x\n",
 		       kdevname(dev), magic);
+#endif
 		brelse(bh);
 		return 0;
 	}
@@ -1049,7 +1055,8 @@
 	int dev_bsize, dev_pos, pos;
 	unsigned secsize;
 #ifdef CONFIG_PPC
-	int first_bootable = 1;
+	int found_root = 0;
+	int found_root_goodness = 0;
 #endif
 	struct mac_partition *part;
 	struct mac_driver_desc *md;
@@ -1107,16 +1114,36 @@
 		 * If this is the first bootable partition, tell the
 		 * setup code, in case it wants to make this the root.
 		 */
-		if ( (_machine == _MACH_Pmac) && first_bootable
-		    && (be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
-		    && strcasecmp(part->processor, "powerpc") == 0) {
-			note_bootable_part(dev, blk);
-			first_bootable = 0;
+		if (_machine == _MACH_Pmac) {
+			int goodness = 0;
+		    
+			if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
+			    && strcasecmp(part->processor, "powerpc") == 0)
+				goodness++;
+
+			if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0) {
+				goodness++;
+				if ((strcmp(part->name, "/") == 0) ||
+				    (strstr(part->name, "root") != 0)) {
+					goodness++;
+				}
+				if (strncmp(part->name, "swap", 4) == 0)
+					goodness--;
+			}
+
+			if (goodness > found_root_goodness) {
+				found_root = blk;
+				found_root_goodness = goodness;
+			}
 		}
 #endif /* CONFIG_PPC */
 
 		++current_minor;
 	}
+#ifdef CONFIG_PPC
+	if (found_root_goodness)
+		note_bootable_part(dev, found_root);
+#endif
 	brelse(bh);
 	printk("\n");
 	return 1;
@@ -1450,7 +1477,7 @@
 #ifdef CONFIG_BLK_CPQ_DA
 	cpqarray_init();
 #endif
-#ifdef CONFIG_INET
+#ifdef CONFIG_NET
 	net_dev_init();
 #endif
 #ifdef CONFIG_VT
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide-cd.c linux.14p16/drivers/block/ide-cd.c
--- linux.vanilla/drivers/block/ide-cd.c	Wed Oct 20 01:12:34 1999
+++ linux.14p16/drivers/block/ide-cd.c	Thu Dec  9 15:33:39 1999
@@ -139,7 +139,7 @@
  * 3.15  July 2, 1996 -- Added support for Sanyo 3 CD changers
  *                        from Ben Galliart <bgallia@luc.edu> with 
  *                        special help from Jeff Lightfoot 
- *                        <jeffml@netcom.com>
+ *                        <jeffml@pobox.com>
  * 3.15a July 9, 1996 -- Improved Sanyo 3 CD changer identification
  * 3.16  Jul 28, 1996 -- Fix from Gadi to reduce kernel stack usage for ioctl.
  * 3.17  Sep 17, 1996 -- Tweak audio reads for some drives.
@@ -519,7 +519,7 @@
 
 /* Returns 0 if the request should be continued.
    Returns 1 if the request was ended. */
-static int cdrom_decode_status (ide_drive_t *drive, int good_stat,
+static int cdrom_decode_status (ide_startstop_t *startstop, ide_drive_t *drive, int good_stat,
 				int *stat_ret)
 {
 	struct request *rq = HWGROUP(drive)->rq;
@@ -551,7 +551,7 @@
 				                      rq->buffer;
 			pc->stat = 1;
 			cdrom_end_request (1, drive);
-			ide_error (drive, "request sense failure", stat);
+			*startstop = ide_error (drive, "request sense failure", stat);
 			return 1;
 
 		} else if (cmd == PACKET_COMMAND) {
@@ -633,7 +633,7 @@
 			} else if ((err & ~ABRT_ERR) != 0) {
 				/* Go to the default handler
 				   for other errors. */
-				ide_error (drive, "cdrom_decode_status", stat);
+				*startstop = ide_error (drive, "cdrom_decode_status", stat);
 				return 1;
 			} else if ((++rq->errors > ERROR_MAX)) {
 				/* We've racked up too many retries.  Abort. */
@@ -649,6 +649,7 @@
 	}
 
 	/* Retry, or handle the next request. */
+	*startstop = ide_stopped;
 	return 1;
 }
 
@@ -660,13 +661,15 @@
    called when the interrupt from the drive arrives.  Otherwise, HANDLER
    will be called immediately after the drive is prepared for the transfer. */
 
-static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen,
+static ide_startstop_t cdrom_start_packet_command (ide_drive_t *drive, int xferlen,
 				       ide_handler_t *handler)
 {
+	ide_startstop_t startstop;
 	struct cdrom_info *info = drive->driver_data;
 
 	/* Wait for the controller to be idle. */
-	if (ide_wait_stat (drive, 0, BUSY_STAT, WAIT_READY)) return 1;
+	if (ide_wait_stat (&startstop, drive, 0, BUSY_STAT, WAIT_READY))
+		return startstop;
 
 	if (info->dma)
 		info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
@@ -686,12 +689,11 @@
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
 		ide_set_handler (drive, handler, WAIT_CMD);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		return ide_started;
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
-		(*handler) (drive);
+		return (*handler) (drive);
 	}
-
-	return 0;
 }
 
 
@@ -700,7 +702,7 @@
    by cdrom_start_packet_command.
    HANDLER is the interrupt handler to call when the command completes
    or there's data ready. */
-static int cdrom_transfer_packet_command (ide_drive_t *drive,
+static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
                                           char *cmd_buf, int cmd_len,
 					  ide_handler_t *handler)
 {
@@ -708,14 +710,16 @@
 		/* Here we should have been called after receiving an interrupt
 		   from the device.  DRQ should how be set. */
 		int stat_dum;
+		ide_startstop_t startstop;
 
 		/* Check for errors. */
-		if (cdrom_decode_status (drive, DRQ_STAT, &stat_dum))
-			return 1;
+		if (cdrom_decode_status (&startstop, drive, DRQ_STAT, &stat_dum))
+			return startstop;
 	} else {
+		ide_startstop_t startstop;
 		/* Otherwise, we must wait for DRQ to get set. */
-		if (ide_wait_stat (drive, DRQ_STAT, BUSY_STAT, WAIT_READY))
-			return 1;
+		if (ide_wait_stat (&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY))
+			return startstop;
 	}
 
 	/* Arm the interrupt handler. */
@@ -724,7 +728,7 @@
 	/* Send the command to the device. */
 	atapi_output_bytes (drive, cmd_buf, cmd_len);
 
-	return 0;
+	return ide_started;
 }
 
 
@@ -826,12 +830,13 @@
 /*
  * Interrupt routine.  Called when a read request has completed.
  */
-static void cdrom_read_intr (ide_drive_t *drive)
+static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
 {
 	int stat;
 	int ireason, len, sectors_to_transfer, nskip;
 	struct cdrom_info *info = drive->driver_data;
 	int i, dma = info->dma, dma_error = 0;
+	ide_startstop_t startstop;
 
 	struct request *rq = HWGROUP(drive)->rq;
 
@@ -842,8 +847,8 @@
 			HWIF(drive)->dmaproc(ide_dma_off, drive);
 	}
 
-	if (cdrom_decode_status (drive, 0, &stat))
-		return;
+	if (cdrom_decode_status (&startstop, drive, 0, &stat))
+		return startstop;
  
 	if (dma) {
 		if (!dma_error) {
@@ -851,9 +856,9 @@
 				i -= rq->current_nr_sectors;
 				ide_end_request(1, HWGROUP(drive));
 			}
+			return ide_stopped;
 		} else
-			ide_error (drive, "dma error", stat);
-		return;
+			return ide_error (drive, "dma error", stat);
 	}
 
 	/* Read the interrupt reason and the transfer length. */
@@ -870,11 +875,12 @@
 			cdrom_end_request (0, drive);
 		} else
 			cdrom_end_request (1, drive);
-		return;
+		return ide_stopped;
 	}
 
 	/* Check that the drive is expecting to do the same thing we are. */
-	if (cdrom_read_check_ireason (drive, len, ireason)) return;
+	if (cdrom_read_check_ireason (drive, len, ireason))
+		return ide_stopped;
 
 	/* Assume that the drive will always provide data in multiples
 	   of at least SECTOR_SIZE, as it gets hairy to keep track
@@ -889,7 +895,7 @@
 			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
 		}
 		cdrom_end_request (0, drive);
-		return;
+		return ide_stopped;
 	}
 
 	/* The number of sectors we need to read from the drive. */
@@ -952,6 +958,7 @@
 	/* Done moving data!
 	   Wait for another interrupt. */
 	ide_set_handler (drive, &cdrom_read_intr, WAIT_CMD);
+	return ide_started;
 }
 
 
@@ -1019,7 +1026,7 @@
  * However, for drq_interrupt devices, it is called from an interrupt
  * when the drive is ready to accept the command.
  */
-static void cdrom_start_read_continuation (ide_drive_t *drive)
+static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive)
 {
 	struct packet_command pc;
 	struct request *rq = HWGROUP(drive)->rq;
@@ -1046,7 +1053,7 @@
 			printk ("%s: cdrom_start_read_continuation: buffer botch (%ld)\n",
 				drive->name, rq->current_nr_sectors);
 			cdrom_end_request (0, drive);
-			return;
+			return ide_stopped;
 		}
 
 		sector -= nskip;
@@ -1072,22 +1079,22 @@
 	put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]);
 
 	/* Send the command to the drive and return. */
-	(void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c),
-					      &cdrom_read_intr);
+	return cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_read_intr);
 }
 
 #define IDECD_SEEK_THRESHOLD	(1000)			/* 1000 blocks */
 #define IDECD_SEEK_TIMER	(2 * WAIT_MIN_SLEEP)	/* 40 ms */
 #define IDECD_SEEK_TIMEOUT     WAIT_CMD                /* 10 sec */
 
-static void cdrom_seek_intr (ide_drive_t *drive)
+static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive)
 {
 	struct cdrom_info *info = drive->driver_data;
 	int stat;
 	static int retry = 10;
+	ide_startstop_t startstop;
 
-	if (cdrom_decode_status (drive, 0, &stat))
-		return;
+	if (cdrom_decode_status (&startstop, drive, 0, &stat))
+		return startstop;
 	CDROM_CONFIG_FLAGS(drive)->seeking = 1;
 
 	if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) {
@@ -1096,9 +1103,10 @@
 			drive->dsc_overlap = 0;
 		}
 	}
+	return ide_stopped;
 }
 
-static void cdrom_start_seek_continuation (ide_drive_t *drive)
+static ide_startstop_t cdrom_start_seek_continuation (ide_drive_t *drive)
 {
 	struct packet_command pc;
 	struct request *rq = HWGROUP(drive)->rq;
@@ -1113,22 +1121,22 @@
 	memset (&pc.c, 0, sizeof (pc.c));
 	pc.c[0] = SEEK;
 	put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]);
-	(void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_seek_intr);
+	return cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_seek_intr);
 }
 
-static void cdrom_start_seek (ide_drive_t *drive, unsigned int block)
+static ide_startstop_t cdrom_start_seek (ide_drive_t *drive, unsigned int block)
 {
 	struct cdrom_info *info = drive->driver_data;
 
 	info->dma = 0;
 	info->start_seek = jiffies;
-	cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation);
+	return cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation);
 }
 
 /*
  * Start a read request from the CD-ROM.
  */
-static void cdrom_start_read (ide_drive_t *drive, unsigned int block)
+static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block)
 {
 	struct cdrom_info *info = drive->driver_data;
 	struct request *rq = HWGROUP(drive)->rq;
@@ -1148,7 +1156,7 @@
 
 	/* Satisfy whatever we can of this request from our cached sector. */
 	if (cdrom_read_from_buffer (drive))
-		return;
+		return ide_stopped;
 
 	/* Clear the local sector buffer. */
 	info->nsectors_buffered = 0;
@@ -1159,8 +1167,7 @@
 		info->dma = 0;
 
 	/* Start sending the read request to the drive. */
-	cdrom_start_packet_command (drive, 32768,
-				    cdrom_start_read_continuation);
+	return cdrom_start_packet_command (drive, 32768, cdrom_start_read_continuation);
 }
 
 
@@ -1178,15 +1185,16 @@
 
 
 /* Interrupt routine for packet command completion. */
-static void cdrom_pc_intr (ide_drive_t *drive)
+static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
 {
 	int ireason, len, stat, thislen;
 	struct request *rq = HWGROUP(drive)->rq;
 	struct packet_command *pc = (struct packet_command *)rq->buffer;
+	ide_startstop_t startstop;
 
 	/* Check for errors. */
-	if (cdrom_decode_status (drive, 0, &stat))
-		return;
+	if (cdrom_decode_status (&startstop, drive, 0, &stat))
+		return startstop;
 
 	/* Read the interrupt reason and the transfer length. */
 	ireason = IN_BYTE (IDE_NSECTOR_REG);
@@ -1219,7 +1227,7 @@
 			pc->stat = 1;
 			cdrom_end_request (1, drive);
 		}
-		return;
+		return ide_stopped;
 	}
 
 	/* Figure out how much data to transfer. */
@@ -1288,21 +1296,21 @@
 
 	/* Now we wait for another interrupt. */
 	ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD);
+	return ide_started;
 }
 
 
-static void cdrom_do_pc_continuation (ide_drive_t *drive)
+static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive)
 {
 	struct request *rq = HWGROUP(drive)->rq;
 	struct packet_command *pc = (struct packet_command *)rq->buffer;
 
 	/* Send the command to the drive and return. */
-	cdrom_transfer_packet_command (drive, pc->c,
-				       sizeof (pc->c), &cdrom_pc_intr);
+	return cdrom_transfer_packet_command (drive, pc->c, sizeof (pc->c), &cdrom_pc_intr);
 }
 
 
-static void cdrom_do_packet_command (ide_drive_t *drive)
+static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive)
 {
 	int len;
 	struct request *rq = HWGROUP(drive)->rq;
@@ -1317,7 +1325,7 @@
 	pc->stat = 0;
 
 	/* Start sending the command to the drive. */
-	cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
+	return cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
 }
 
 
@@ -1401,19 +1409,20 @@
 /****************************************************************************
  * cdrom driver request routine.
  */
-static
-void ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t
+ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 	if (rq -> cmd == PACKET_COMMAND || rq -> cmd == REQUEST_SENSE_COMMAND)
-		cdrom_do_packet_command (drive);
+		return cdrom_do_packet_command (drive);
 	else if (rq -> cmd == RESET_DRIVE_COMMAND) {
 		cdrom_end_request (1, drive);
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	} else if (rq -> cmd != READ) {
 		printk ("ide-cd: bad cmd %d\n", rq -> cmd);
 		cdrom_end_request (0, drive);
+		return ide_stopped;
 	} else {
+		ide_startstop_t action;
 		struct cdrom_info *info = drive->driver_data;
 
 		if (CDROM_CONFIG_FLAGS(drive)->seeking) {
@@ -1423,17 +1432,18 @@
 			if ((stat & SEEK_STAT) != SEEK_STAT) {
 				if (elpased < IDECD_SEEK_TIMEOUT) {
 					ide_stall_queue (drive, IDECD_SEEK_TIMER);
-					return;
+					return ide_stopped;
 				}
 				printk ("%s: DSC timeout\n", drive->name);
 			}
 			CDROM_CONFIG_FLAGS(drive)->seeking = 0;
 		}
 		if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap)
-			cdrom_start_seek (drive, block);
+			action = cdrom_start_seek (drive, block);
 		else
-			cdrom_start_read (drive, block);
+			action = cdrom_start_read (drive, block);
 		info->last_block = block;
+		return action;
 	}
 }
 
@@ -2890,8 +2900,11 @@
 		struct atapi_capabilities_page cap;
 	} buf;
 
-	if (CDROM_CONFIG_FLAGS (drive)->nec260)
+	if (CDROM_CONFIG_FLAGS (drive)->nec260) {
+		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;
+		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
 		return nslots;
+	}
 
 	do {	/* we seem to get stat=0x01,err=0x00 the first time (??) */
 		if (attempts-- <= 0)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide-disk.c linux.14p16/drivers/block/ide-disk.c
--- linux.vanilla/drivers/block/ide-disk.c	Thu Mar 11 01:49:43 1999
+++ linux.14p16/drivers/block/ide-disk.c	Tue Dec 21 00:37:42 1999
@@ -88,46 +88,60 @@
  */
 static int lba_capacity_is_ok (struct hd_driveid *id)
 {
-	unsigned long lba_sects   = id->lba_capacity;
-	unsigned long chs_sects   = id->cyls * id->heads * id->sectors;
-	unsigned long _10_percent = chs_sects / 10;
+	unsigned long lba_sects, chs_sects, head, tail;
 
 	/*
-	 * very large drives (8GB+) may lie about the number of cylinders
-	 * This is a split test for drives 8 Gig and Bigger only.
+	 * The ATA spec tells large drives to return
+	 * C/H/S = 16383/16/63 independent of their size.
+	 * Some drives can be jumpered to use 15 heads instead of 16.
 	 */
-	if ((id->lba_capacity >= 16514064) && (id->cyls == 0x3fff) &&
-	    (id->heads == 16) && (id->sectors == 63)) {
-		id->cyls = lba_sects / (16 * 63); /* correct cyls */
-		return 1;	/* lba_capacity is our only option */
-	}
+	if (id->cyls == 16383 && id->sectors == 63 &&
+	    (id->heads == 15 || id->heads == 16) &&
+	    id->lba_capacity >= 16383*63*id->heads)
+		return 1;
+
+	lba_sects   = id->lba_capacity;
+	chs_sects   = id->cyls * id->heads * id->sectors;
+
 	/* perform a rough sanity check on lba_sects:  within 10% is "okay" */
-	if ((lba_sects - chs_sects) < _10_percent) {
-		return 1;	/* lba_capacity is good */
-	}
+	if ((lba_sects - chs_sects) < chs_sects/10)
+		return 1;
+
 	/* some drives have the word order reversed */
-	lba_sects = (lba_sects << 16) | (lba_sects >> 16);
-	if ((lba_sects - chs_sects) < _10_percent) {
-		id->lba_capacity = lba_sects;	/* fix it */
+	head = ((lba_sects >> 16) & 0xffff);
+	tail = (lba_sects & 0xffff);
+	lba_sects = (head | (tail << 16));
+	if ((lba_sects - chs_sects) < chs_sects/10) {
+		id->lba_capacity = lba_sects;
 		return 1;	/* lba_capacity is (now) good */
 	}
-	return 0;	/* lba_capacity value is bad */
+
+	return 0;	/* lba_capacity value may be bad */
 }
 
 /*
  * read_intr() is the handler for disk read/multread interrupts
  */
-static void read_intr (ide_drive_t *drive)
+static ide_startstop_t read_intr (ide_drive_t *drive)
 {
 	byte stat;
 	int i;
 	unsigned int msect, nsect;
 	struct request *rq;
-
+#if 0
 	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
-		ide_error(drive, "read_intr", stat);
-		return;
+		return ide_error(drive, "read_intr", stat);
+	}
+#else	/* new way for dealing with premature shared PCI interrupts */
+	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			return ide_error(drive, "read_intr", stat);
+		}
+		/* no data yet, so wait for another interrupt */
+		ide_set_handler(drive, &read_intr, WAIT_CMD);
+		return ide_started;
 	}
+#endif
 	msect = drive->mult_count;
 	
 read_next:
@@ -138,12 +152,6 @@
 		msect -= nsect;
 	} else
 		nsect = 1;
-	/*
-	 * PIO input can take longish times, so we drop the spinlock.
-	 * On SMP, bad things might happen if syscall level code adds
-	 * a new request while we do this PIO, so we just freeze all
-	 * request queue handling while doing the PIO. FIXME
-	 */
 	idedisk_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
 #ifdef DEBUG
 	printk("%s:  read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
@@ -154,27 +162,30 @@
 	rq->buffer += nsect<<9;
 	rq->errors = 0;
 	i = (rq->nr_sectors -= nsect);
-	if ((rq->current_nr_sectors -= nsect) <= 0)
+	if (((long)(rq->current_nr_sectors -= nsect)) <= 0)
 		ide_end_request(1, HWGROUP(drive));
 	if (i > 0) {
 		if (msect)
 			goto read_next;
 		ide_set_handler (drive, &read_intr, WAIT_CMD);
+		return ide_started;
 	}
+	return ide_stopped;
 }
 
 /*
  * write_intr() is the handler for disk write interrupts
  */
-static void write_intr (ide_drive_t *drive)
+static ide_startstop_t write_intr (ide_drive_t *drive)
 {
 	byte stat;
 	int i;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	struct request *rq = hwgroup->rq;
-	int error = 0;
 
-	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
+	if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
+		printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat);
+	} else {
 #ifdef DEBUG
 		printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n",
 			drive->name, rq->sector, (unsigned long) rq->buffer,
@@ -186,30 +197,44 @@
 			rq->errors = 0;
 			i = --rq->nr_sectors;
 			--rq->current_nr_sectors;
-			if (rq->current_nr_sectors <= 0)
+			if (((long)rq->current_nr_sectors) <= 0)
 				ide_end_request(1, hwgroup);
 			if (i > 0) {
 				idedisk_output_data (drive, rq->buffer, SECTOR_WORDS);
 				ide_set_handler (drive, &write_intr, WAIT_CMD);
+				return ide_started;
 			}
-			goto out;
+			return ide_stopped;
 		}
-	} else
-		error = 1;
-out:
-	if (error)
-		ide_error(drive, "write_intr", stat);
+		return ide_stopped;     /* the original code did this here (?) */ 
+	}
+	return ide_error(drive, "write_intr", stat);
 }
 
 /*
  * ide_multwrite() transfers a block of up to mcount sectors of data
  * to a drive as part of a disk multiple-sector write operation.
+ *
+ * Returns 0 if successful;  returns 1 if request had to be aborted due to corrupted buffer list.
  */
-void ide_multwrite (ide_drive_t *drive, unsigned int mcount)
+int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
 {
-	struct request *rq = &HWGROUP(drive)->wrq;
+	ide_hwgroup_t	*hwgroup= HWGROUP(drive);
+	
+	/*
+	 *	This may look a bit odd, but remember wrq is a copy of the 
+	 *	request not the original. The pointers are real however so the
+	 *	bh's are not copies. Remember that or bad stuff will happen
+	 *
+	 *	At the point we are called the drive has asked us for the
+	 *	data, and its our job to feed it, walking across bh boundaries
+	 *	if need be.
+	 */
+	 
+	struct request *rq = &hwgroup->wrq;
 
 	do {
+		unsigned long flags;
 		unsigned int nsect = rq->current_nr_sectors;
 		if (nsect > mcount)
 			nsect = mcount;
@@ -221,61 +246,95 @@
 			drive->name, rq->sector, (unsigned long) rq->buffer,
 			nsect, rq->nr_sectors - nsect);
 #endif
-		if ((rq->nr_sectors -= nsect) <= 0)
+		spin_lock_irqsave(&io_request_lock, flags);	/* Is this really necessary? */
+		
+		/*
+		 *	Completed ?
+		 */
+		 
+		if (((long)(rq->nr_sectors -= nsect)) <= 0)
+		{
+			spin_unlock_irqrestore(&io_request_lock, flags);
 			break;
+		}
+		
+		/*
+		 *	Take off the sectors transferred
+		 */
+		 
 		if ((rq->current_nr_sectors -= nsect) == 0) {
+			/*
+			 *	If there are no sectors left then move on to
+			 *	the next buffer.
+			 */
 			if ((rq->bh = rq->bh->b_reqnext) != NULL) {
 				rq->current_nr_sectors = rq->bh->b_size>>9;
 				rq->buffer             = rq->bh->b_data;
 			} else {
-				panic("%s: buffer list corrupted\n", drive->name);
-				break;
+				/*
+				 *	Excuse me boss.. nr_sectors doesnt tally
+				 *	deep crap
+				 */
+				spin_unlock_irqrestore(&io_request_lock, flags);
+				printk("%s: buffer list corrupted (%ld, %ld, %d)\n", drive->name,
+					rq->current_nr_sectors, rq->nr_sectors, nsect);
+				ide_end_request(0, hwgroup);
+				return 1;
 			}
 		} else {
+			/* Fix the pointer.. we ate data */
 			rq->buffer += nsect << 9;
 		}
+		spin_unlock_irqrestore(&io_request_lock, flags);
 	} while (mcount);
+	return 0;
 }
 
 /*
  * multwrite_intr() is the handler for disk multwrite interrupts
  */
-static void multwrite_intr (ide_drive_t *drive)
+static ide_startstop_t multwrite_intr (ide_drive_t *drive)
 {
 	byte stat;
 	int i;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	struct request *rq = &hwgroup->wrq;
-	int error = 0;
 
 	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
 		if (stat & DRQ_STAT) {
+			/*
+			 *	The drive wants data. Remember rq is the copy
+			 *	of the request
+			 */
 			if (rq->nr_sectors) {
-				ide_multwrite(drive, drive->mult_count);
+				if (ide_multwrite(drive, drive->mult_count))
+					return ide_stopped;
 				ide_set_handler (drive, &multwrite_intr, WAIT_CMD);
-				goto out;
+				return ide_started;
 			}
 		} else {
+			/*
+			 *	If the copy has all the blocks completed then
+			 *	we can end the original request.
+			 */
 			if (!rq->nr_sectors) {	/* all done? */
 				rq = hwgroup->rq;
 				for (i = rq->nr_sectors; i > 0;){
 					i -= rq->current_nr_sectors;
 					ide_end_request(1, hwgroup);
 				}
-				goto out;
+				return ide_stopped;
 			}
 		}
-	} else
-		error = 1;
-out:
-	if (error)
-		ide_error(drive, "multwrite_intr", stat);
+		return ide_stopped;     /* the original code did this here (?) */ 
+	}
+	return ide_error(drive, "multwrite_intr", stat);
 }
 
 /*
  * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
  */
-static void set_multmode_intr (ide_drive_t *drive)
+static ide_startstop_t set_multmode_intr (ide_drive_t *drive)
 {
 	byte stat = GET_STAT();
 
@@ -286,28 +345,31 @@
 		drive->special.b.recalibrate = 1;
 		(void) ide_dump_status(drive, "set_multmode", stat);
 	}
+	return ide_stopped;
 }
 
 /*
  * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
  */
-static void set_geometry_intr (ide_drive_t *drive)
+static ide_startstop_t set_geometry_intr (ide_drive_t *drive)
 {
 	byte stat = GET_STAT();
 
 	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
-		ide_error(drive, "set_geometry_intr", stat);
+		return ide_error(drive, "set_geometry_intr", stat);
+	return ide_stopped;
 }
 
 /*
  * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
  */
-static void recal_intr (ide_drive_t *drive)
+static ide_startstop_t recal_intr (ide_drive_t *drive)
 {
 	byte stat = GET_STAT();
 
 	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
-		ide_error(drive, "recal_intr", stat);
+		return ide_error(drive, "recal_intr", stat);
+	return ide_stopped;
 }
 
 /*
@@ -315,7 +377,7 @@
  * using LBA if supported, or CHS otherwise, to address sectors.
  * It also takes care of issuing special DRIVE_CMDs.
  */
-static void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 #ifdef CONFIG_BLK_DEV_PDC4030
 	ide_hwif_t *hwif = HWIF(drive);
@@ -361,45 +423,63 @@
 	}
 #ifdef CONFIG_BLK_DEV_PDC4030
 	if (use_pdc4030_io) {
-		extern void do_pdc4030_io(ide_drive_t *, struct request *);
-		do_pdc4030_io (drive, rq);
-		return;
+		extern ide_startstop_t do_pdc4030_io(ide_drive_t *, struct request *);
+		return do_pdc4030_io (drive, rq);
 	}
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 	if (rq->cmd == READ) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
-			return;
+			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 		ide_set_handler(drive, &read_intr, WAIT_CMD);
 		OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
-		return;
+		return ide_started;
 	}
 	if (rq->cmd == WRITE) {
+		ide_startstop_t startstop;
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
-			return;
+			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 		OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
-		if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
+		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
 			printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name,
 				drive->mult_count ? "MULTWRITE" : "WRITE");
-			return;
+			return startstop;
 		}
 		if (!drive->unmask)
 			__cli();	/* local CPU only */
 		if (drive->mult_count) {
-			HWGROUP(drive)->wrq = *rq; /* scratchpad */
+			ide_hwgroup_t *hwgroup = HWGROUP(drive);
+			/*
+			 * Ugh.. this part looks ugly because we MUST set up
+			 * the interrupt handler before outputting the first block
+			 * of data to be written.  If we hit an error (corrupted buffer list)
+			 * in ide_multwrite(), then we need to remove the handler/timer
+			 * before returning.  Fortunately, this NEVER happens (right?).
+			 *
+			 * Except when you get an error it seems...
+			 */
+			hwgroup->wrq = *rq; /* scratchpad */
 			ide_set_handler (drive, &multwrite_intr, WAIT_CMD);
-			ide_multwrite(drive, drive->mult_count);
+			if (ide_multwrite(drive, drive->mult_count)) {
+				unsigned long flags;
+				spin_lock_irqsave(&io_request_lock, flags);
+				hwgroup->handler = NULL;
+				del_timer(&hwgroup->timer);
+				spin_unlock_irqrestore(&io_request_lock, flags);
+				return ide_stopped;
+			}
 		} else {
 			ide_set_handler (drive, &write_intr, WAIT_CMD);
 			idedisk_output_data(drive, rq->buffer, SECTOR_WORDS);
 		}
-		return;
+		return ide_started;
 	}
 	printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
 	ide_end_request(0, HWGROUP(drive));
+	return ide_stopped;
 }
 
 static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
@@ -446,7 +526,6 @@
 	/* Determine capacity, and use LBA if the drive properly supports it */
 	if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) {
 		if (id->lba_capacity >= capacity) {
-			drive->cyl = id->lba_capacity / (drive->head * drive->sect);
 			capacity = id->lba_capacity;
 			drive->select.b.lba = 1;
 		}
@@ -454,7 +533,7 @@
 	return (capacity - drive->sect0);
 }
 
-static void idedisk_special (ide_drive_t *drive)
+static ide_startstop_t idedisk_special (ide_drive_t *drive)
 {
 	special_t *s = &drive->special;
 
@@ -480,7 +559,9 @@
 		int special = s->all;
 		s->all = 0;
 		printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special);
+		return ide_stopped;
 	}
+	return IS_PDC4030_DRIVE ? ide_stopped : ide_started;
 }
 
 static void idedisk_pre_reset (ide_drive_t *drive)
@@ -602,7 +683,7 @@
 		return -EBUSY;
 	drive->nowerr = arg;
 	drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
-	spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	return 0;
 }
 
@@ -721,9 +802,9 @@
 		if ((id->lba_capacity > 16514064) || (id->cyls == 0x3fff)) {
 			id->cyls = ((int)(id->lba_capacity/(id->heads * id->sectors)));
 		}
-		drive->cyl  = id->cur_cyls    = id->cyls;
-		drive->head = id->cur_heads   = id->heads;
-		drive->sect = id->cur_sectors = id->sectors;
+		drive->cyl  = id->cyls;
+		drive->head = id->heads;
+		drive->sect = id->sectors;
 	}
 
 	/* calculate drive capacity, and select LBA if possible */
@@ -733,21 +814,19 @@
 	 * if possible, give fdisk access to more of the drive,
 	 * by correcting bios_cyls:
 	 */
-	if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) &&
-	    (!drive->forced_geom) && drive->bios_sect && drive->bios_head) {
-		drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
-#ifdef DEBUG
-		printk("Fixing Geometry :: CHS=%d/%d/%d to CHS=%d/%d/%d\n",
-			drive->id->cur_cyls,
-			drive->id->cur_heads,
-			drive->id->cur_sectors,
-			drive->bios_cyl,
-			drive->bios_head,
-			drive->bios_sect);
-#endif
-		drive->id->cur_cyls    = drive->bios_cyl;
-		drive->id->cur_heads   = drive->bios_head;
-		drive->id->cur_sectors = drive->bios_sect;
+	if (!drive->forced_geom &&
+	    capacity > drive->bios_cyl * drive->bios_sect * drive->bios_head) {
+		unsigned long cylsize;
+		cylsize = drive->bios_sect * drive->bios_head;
+		if (cylsize == 0 || capacity/cylsize > 65535) {
+			drive->bios_sect = 63;
+			drive->bios_head = 255;
+			cylsize = 63*255;
+		}
+		if (capacity/cylsize > 65535)
+			drive->bios_cyl = 65535;
+		else
+			drive->bios_cyl = capacity/cylsize;
 	}
 
 #if 0	/* done instead for entire identify block in arch/ide.h stuff */
@@ -762,7 +841,7 @@
 	if (drive->using_dma) {
 		if ((id->field_valid & 4) &&
 		    (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
-			printk(", UDMA");	/* UDMA BIOS-enabled! */
+			printk(", UDMA");       /* UDMA BIOS-enabled! */
 		} else if (id->field_valid & 4) {
 			printk(", (U)DMA");	/* Can be BIOS-enabled! */
 		} else {
@@ -770,19 +849,6 @@
 		}
 	}
 	printk("\n");
-
-	if (drive->select.b.lba) {
-		if (*(int *)&id->cur_capacity0 < id->lba_capacity) {
-#ifdef DEBUG
-			printk("     CurSects=%d, LBASects=%d, ",
-				*(int *)&id->cur_capacity0, id->lba_capacity);
-#endif
-			*(int *)&id->cur_capacity0 = id->lba_capacity;
-#ifdef DEBUG
-			printk( "Fixed CurSects=%d\n", *(int *)&id->cur_capacity0);
-#endif
-		}
-	}
 
 	drive->mult_count = 0;
 	if (id->max_multsect) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide-dma.c linux.14p16/drivers/block/ide-dma.c
--- linux.vanilla/drivers/block/ide-dma.c	Sat Aug 14 02:26:27 1999
+++ linux.14p16/drivers/block/ide-dma.c	Thu Dec  9 15:33:39 1999
@@ -136,7 +136,7 @@
 /*
  * dma_intr() is the handler for disk read/write DMA interrupts
  */
-void ide_dma_intr (ide_drive_t *drive)
+ide_startstop_t ide_dma_intr (ide_drive_t *drive)
 {
 	int i;
 	byte stat, dma_stat;
@@ -151,12 +151,11 @@
 				i -= rq->current_nr_sectors;
 				ide_end_request(1, HWGROUP(drive));
 			}
-			return;
+			return ide_stopped;
 		}
 		printk("%s: dma_intr: bad DMA status\n", drive->name);
 	}
-	ide__sti();	/* local CPU only */
-	ide_error(drive, "dma_intr", stat);
+	return ide_error(drive, "dma_intr", stat);
 }
 
 /*
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide-floppy.c linux.14p16/drivers/block/ide-floppy.c
--- linux.vanilla/drivers/block/ide-floppy.c	Sat Aug 14 02:27:16 1999
+++ linux.14p16/drivers/block/ide-floppy.c	Thu Dec  9 15:33:39 1999
@@ -834,7 +834,7 @@
  *	idefloppy_pc_intr is the usual interrupt handler which will be called
  *	during a packet command.
  */
-static void idefloppy_pc_intr (ide_drive_t *drive)
+static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_status_reg_t status;
@@ -879,24 +879,22 @@
 			rq->errors++;
 			if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
 				printk (KERN_ERR "ide-floppy: I/O error in request sense command\n");
-				ide_do_reset (drive);
-				return;
+				return ide_do_reset (drive);
 			}
 			idefloppy_retry_pc (drive);				/* Retry operation */
-			return;
+			return ide_stopped; /* queued, but not started */
 		}
 		pc->error = 0;
 		if (floppy->failed_pc == pc)
 			floppy->failed_pc=NULL;
 		pc->callback(drive);			/* Command finished - Call the callback function */
-		return;
+		return ide_stopped;
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
 		printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
 		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
@@ -905,14 +903,12 @@
 
 	if (ireason.b.cod) {
 		printk (KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 	if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
 		printk (KERN_ERR "ide-floppy: We wanted to %s, ", ireason.b.io ? "Write":"Read");
 		printk (KERN_ERR "but the floppy wants us to %s !\n",ireason.b.io ? "Read":"Write");
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 	if (!test_bit (PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
 		temp = pc->actually_transferred + bcount.all;
@@ -921,7 +917,7 @@
 				printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
 				idefloppy_discard_data (drive,bcount.all);
 				ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD);
-				return;
+				return ide_started;
 			}
 #if IDEFLOPPY_DEBUG_LOG
 			printk (KERN_NOTICE "ide-floppy: The floppy wants to send us more data than expected - allowing transfer\n");
@@ -943,31 +939,33 @@
 	pc->current_position+=bcount.all;
 
 	ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD);		/* And set the interrupt handler again */
+	return ide_started;
 }
 
-static void idefloppy_transfer_pc (ide_drive_t *drive)
+static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
 {
+	ide_startstop_t startstop;
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_ireason_reg_t ireason;
 
-	if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
 		printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n");
-		return;
+		return startstop;
 	}
 	ireason.all=IN_BYTE (IDE_IREASON_REG);
 	if (!ireason.b.cod || ireason.b.io) {
 		printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 	ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD);	/* Set the interrupt routine */
 	atapi_output_bytes (drive, floppy->pc->c, 12);		/* Send the actual packet */
+	return ide_started;
 }
 
 /*
  *	Issue a packet command
  */
-static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
+static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_bcount_reg_t bcount;
@@ -995,7 +993,7 @@
 		}
 		floppy->failed_pc=NULL;
 		pc->callback(drive);
-		return;
+		return ide_stopped;
 	}
 #if IDEFLOPPY_DEBUG_LOG
 	printk (KERN_INFO "Retry number - %d\n",pc->retries);
@@ -1030,9 +1028,10 @@
 	if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
 		ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
+		return ide_started;
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
-		idefloppy_transfer_pc (drive);
+		return idefloppy_transfer_pc (drive);
 	}
 }
 
@@ -1138,7 +1137,7 @@
 /*
  *	idefloppy_do_request is our request handling function.	
  */
-static void idefloppy_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_pc_t *pc;
@@ -1155,7 +1154,7 @@
 		else
 			printk (KERN_ERR "ide-floppy: %s: I/O error\n", drive->name);
 		idefloppy_end_request (0, HWGROUP(drive));
-		return;
+		return ide_stopped;
 	}
 	switch (rq->cmd) {
 		case READ:
@@ -1163,7 +1162,7 @@
 			if (rq->sector % floppy->bs_factor || rq->nr_sectors % floppy->bs_factor) {
 				printk ("%s: unsupported r/w request size\n", drive->name);
 				idefloppy_end_request (0, HWGROUP(drive));
-				return;
+				return ide_stopped;
 			}
 			pc = idefloppy_next_pc_storage (drive);
 			idefloppy_create_rw_cmd (floppy, pc, rq, block);
@@ -1174,10 +1173,10 @@
 		default:
 			printk (KERN_ERR "ide-floppy: unsupported command %x in request queue\n", rq->cmd);
 			idefloppy_end_request (0,HWGROUP (drive));
-			return;
+			return ide_stopped;
 	}
 	pc->rq = rq;
-	idefloppy_issue_pc (drive, pc);
+	return idefloppy_issue_pc (drive, pc);
 }
 
 /*
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide-probe.c linux.14p16/drivers/block/ide-probe.c
--- linux.vanilla/drivers/block/ide-probe.c	Mon Mar 22 20:44:18 1999
+++ linux.14p16/drivers/block/ide-probe.c	Tue Dec 21 00:35:45 1999
@@ -386,12 +386,20 @@
 	/* Extract drive geometry from CMOS+BIOS if not already setup */
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
-		if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present && !drive->nobios) {
-			drive->cyl   = drive->bios_cyl  = *(unsigned short *)BIOS;
-			drive->head  = drive->bios_head = *(BIOS+2);
-			drive->sect  = drive->bios_sect = *(BIOS+14);
-			drive->ctl   = *(BIOS+8);
-			drive->present = 1;
+		if ((cmos_disks & (0xf0 >> (unit*4)))
+		    && !drive->present && !drive->nobios) {
+			unsigned short cyl = *(unsigned short *)BIOS;
+			unsigned char head = *(BIOS+2);
+			unsigned char sect = *(BIOS+14);
+			if (cyl > 0 && head > 0 && sect > 0 && sect < 64) {
+				drive->cyl   = drive->bios_cyl  = cyl;
+				drive->head  = drive->bios_head = head;
+				drive->sect  = drive->bios_sect = sect;
+				drive->ctl   = *(BIOS+8);
+				drive->present = 1;
+			} else
+				printk("hd%d: C/H/S=%d/%d/%d from BIOS ignored\n",
+				       cyl, head, sect);
 		}
 		BIOS += 16;
 	}
@@ -560,10 +568,6 @@
 		hwgroup->handler  = NULL;
 		hwgroup->drive    = NULL;
 		hwgroup->busy     = 0;
-		hwgroup->spinlock = (spinlock_t)SPIN_LOCK_UNLOCKED;
-#if (DEBUG_SPINLOCK > 0)
-		printk("hwgroup(%s) spinlock is %p\n", hwif->name,  &hwgroup->spinlock);	/* FIXME */
-#endif
 		init_timer(&hwgroup->timer);
 		hwgroup->timer.function = &ide_timer_expiry;
 		hwgroup->timer.data = (unsigned long) hwgroup;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide-proc.c linux.14p16/drivers/block/ide-proc.c
--- linux.vanilla/drivers/block/ide-proc.c	Wed May  6 22:42:53 1998
+++ linux.14p16/drivers/block/ide-proc.c	Thu Dec  9 15:33:40 1999
@@ -516,8 +516,10 @@
 	char		*out = page;
 	int		len;
 
-	out += sprintf(out,"physical     %hi/%hi/%hi\n", drive->cyl, drive->head, drive->sect);
-	out += sprintf(out,"logical      %hi/%hi/%hi\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
+	out += sprintf(out,"physical     %d/%d/%d\n",
+		       drive->cyl, drive->head, drive->sect);
+	out += sprintf(out,"logical      %d/%d/%d\n",
+		       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 	len = out - page;
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide-tape.c linux.14p16/drivers/block/ide-tape.c
--- linux.vanilla/drivers/block/ide-tape.c	Sat Aug 14 02:27:16 1999
+++ linux.14p16/drivers/block/ide-tape.c	Thu Dec  9 15:33:39 1999
@@ -346,6 +346,7 @@
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
+#include <asm/byteorder.h>
 #include <asm/unaligned.h>
 #include <asm/bitops.h>
 
@@ -522,9 +523,9 @@
 	int b_count;
 	byte *buffer;				/* Data buffer */
 	byte *current_position;			/* Pointer into the above buffer */
-	void (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
+	ide_startstop_t (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
 	byte pc_buffer[IDETAPE_PC_BUFFER_SIZE];	/* Temporary buffer */
-	unsigned int flags;			/* Status/Action bit flags */
+	unsigned long flags;			/* Status/Action bit flags */
 } idetape_pc_t;
 
 /*
@@ -541,19 +542,55 @@
  *	Capabilities and Mechanical Status Page
  */
 typedef struct {
-	unsigned	page_code	:6;	/* Page code - Should be 0x2a */
-	unsigned	reserved1_67	:2;
+#if defined(__BIG_ENDIAN_BITFIELD)
+	u8	reserved1_67	:2;
+	u8	page_code	:6;	/* Page code - Should be 0x2a */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	u8	page_code	:6;	/* Page code - Should be 0x2a */
+	u8	reserved1_67	:2;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
 	u8		page_length;		/* Page Length - Should be 0x12 */
 	u8		reserved2, reserved3;
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	reserved4_67	:2;
+	unsigned	sprev		:1;	/* Supports SPACE in the reverse direction */
+	unsigned	reserved4_1234	:4;
+	unsigned	ro		:1;	/* Read Only Mode */
+
+	unsigned	reserved5_67	:2;
+	unsigned	qfa		:1;	/* Supports the QFA two partition formats */
+	unsigned	reserved5_4	:1;
+	unsigned	efmt		:1;	/* Supports ERASE command initiated formatting */
+	unsigned	reserved5_012	:3;
+
+	unsigned	cmprs		:1;	/* Supports data compression */
+	unsigned	ecc		:1;	/* Supports error correction */
+	unsigned	reserved6_45	:2;	/* Reserved */	
+	unsigned	eject		:1;	/* The device can eject the volume */
+	unsigned	prevent		:1;	/* The device defaults in the prevent state after power up */	
+	unsigned	locked		:1;	/* The volume is locked */
+	unsigned	lock		:1;	/* Supports locking the volume */
+
+	unsigned	slowb		:1;	/* The device restricts the byte count for PIO */
+	unsigned	reserved7_3_6	:4;
+	unsigned	blk1024		:1;	/* Supports 1024 bytes block size */
+	unsigned	blk512		:1;	/* Supports 512 bytes block size */
+	unsigned	reserved7_0	:1;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	ro		:1;	/* Read Only Mode */
 	unsigned	reserved4_1234	:4;
 	unsigned	sprev		:1;	/* Supports SPACE in the reverse direction */
 	unsigned	reserved4_67	:2;
+
 	unsigned	reserved5_012	:3;
 	unsigned	efmt		:1;	/* Supports ERASE command initiated formatting */
 	unsigned	reserved5_4	:1;
 	unsigned	qfa		:1;	/* Supports the QFA two partition formats */
 	unsigned	reserved5_67	:2;
+
 	unsigned	lock		:1;	/* Supports locking the volume */
 	unsigned	locked		:1;	/* The volume is locked */
 	unsigned	prevent		:1;	/* The device defaults in the prevent state after power up */	
@@ -561,11 +598,13 @@
 	unsigned	reserved6_45	:2;	/* Reserved */	
 	unsigned	ecc		:1;	/* Supports error correction */
 	unsigned	cmprs		:1;	/* Supports data compression */
+
 	unsigned	reserved7_0	:1;
 	unsigned	blk512		:1;	/* Supports 512 bytes block size */
 	unsigned	blk1024		:1;	/* Supports 1024 bytes block size */
 	unsigned	reserved7_3_6	:4;
 	unsigned	slowb		:1;	/* The device restricts the byte count for PIO */
+#endif
 						/* transfers for slow buffer memory ??? */
 	u16		max_speed;		/* Maximum speed supported in KBps */
 	u8		reserved10, reserved11;
@@ -695,7 +734,7 @@
 	int pages_per_stage;
 	int excess_bh_size;			/* Wasted space in each stage */
 
-	unsigned int flags;			/* Status/Action flags */
+	unsigned long flags;			/* Status/Action flags */
 	spinlock_t spinlock;			/* protects the ide-tape queue */
 } idetape_tape_t;
 
@@ -787,6 +826,16 @@
 typedef union {
 	unsigned all			:8;
 	struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+		unsigned bsy		:1;	/* The device has access to the command block */
+		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
+		unsigned reserved5	:1;	/* Reserved */
+		unsigned dsc		:1;	/* Buffer availability / Media access command finished */
+		unsigned drq		:1;	/* Data is request by the device */
+		unsigned corr		:1;	/* Correctable error occurred */
+		unsigned idx		:1;	/* Reserved */
+		unsigned check		:1;	/* Error occurred */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 		unsigned check		:1;	/* Error occurred */
 		unsigned idx		:1;	/* Reserved */
 		unsigned corr		:1;	/* Correctable error occurred */
@@ -795,6 +844,7 @@
 		unsigned reserved5	:1;	/* Reserved */
 		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
 		unsigned bsy		:1;	/* The device has access to the command block */
+#endif
 	} b;
 } idetape_status_reg_t;
 
@@ -804,11 +854,19 @@
 typedef union {
 	unsigned all			:8;
 	struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
+		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
+		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
+		unsigned eom		:1;	/* End Of Media Detected */
+		unsigned ili		:1;	/* Illegal Length Indication */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 		unsigned ili		:1;	/* Illegal Length Indication */
 		unsigned eom		:1;	/* End Of Media Detected */
 		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
 		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
 		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
+#endif
 	} b;
 } idetape_error_reg_t;
 
@@ -818,10 +876,17 @@
 typedef union {
 	unsigned all			:8;
 	struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+		unsigned reserved7	:1;	/* Reserved */
+		unsigned reserved654	:3;	/* Reserved (Tag Type) */
+		unsigned reserved321	:3;	/* Reserved */
+		unsigned dma		:1;	/* Using DMA of PIO */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 		unsigned dma		:1;	/* Using DMA of PIO */
 		unsigned reserved321	:3;	/* Reserved */
 		unsigned reserved654	:3;	/* Reserved (Tag Type) */
 		unsigned reserved7	:1;	/* Reserved */
+#endif
 	} b;
 } idetape_feature_reg_t;
 
@@ -831,8 +896,13 @@
 typedef union {
 	unsigned all			:16;
 	struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+		unsigned high		:8;	/* MSB */
+		unsigned low		:8;	/* LSB */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 		unsigned low		:8;	/* LSB */
 		unsigned high		:8;	/* MSB */
+#endif
 	} b;
 } idetape_bcount_reg_t;
 
@@ -842,9 +912,15 @@
 typedef union {
 	unsigned all			:8;
 	struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+		unsigned reserved	:6;	/* Reserved */
+		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
+		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
 		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
 		unsigned reserved	:6;	/* Reserved */
+#endif
 	} b;
 } idetape_ireason_reg_t;
 
@@ -854,11 +930,19 @@
 typedef union {	
 	unsigned all			:8;
 	struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+		unsigned one7		:1;	/* Should be set to 1 */
+		unsigned reserved6	:1;	/* Reserved */
+		unsigned one5		:1;	/* Should be set to 1 */
+		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
+		unsigned sam_lun	:4;	/* Should be zero with ATAPI (not used) */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 		unsigned sam_lun	:4;	/* Should be zero with ATAPI (not used) */
 		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
 		unsigned one5		:1;	/* Should be set to 1 */
 		unsigned reserved6	:1;	/* Reserved */
 		unsigned one7		:1;	/* Should be set to 1 */
+#endif
 	} b;
 } idetape_drivesel_reg_t;
 
@@ -868,11 +952,19 @@
 typedef union {			
 	unsigned all			:8;
 	struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+		unsigned reserved4567	:4;	/* Reserved */
+		unsigned one3		:1;	/* Should be set to 1 */
+		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
+		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
+		unsigned zero0		:1;	/* Should be set to zero */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 		unsigned zero0		:1;	/* Should be set to zero */
 		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
 		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
 		unsigned one3		:1;	/* Should be set to 1 */
 		unsigned reserved4567	:4;	/* Reserved */
+#endif
 	} b;
 } idetape_control_reg_t;
 
@@ -890,6 +982,15 @@
  *	the ATAPI IDENTIFY DEVICE command.
  */
 struct idetape_id_gcw {	
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned protocol		:2;	/* Protocol type */
+	unsigned reserved13		:1;	/* Reserved */
+	unsigned device_type		:5;	/* Device type */
+	unsigned removable		:1;	/* Removable media */
+	unsigned drq_type		:2;	/* Command packet DRQ type */
+	unsigned reserved234		:3;	/* Reserved */
+	unsigned packet_size		:2;	/* Packet Size */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned packet_size		:2;	/* Packet Size */
 	unsigned reserved234		:3;	/* Reserved */
 	unsigned drq_type		:2;	/* Command packet DRQ type */
@@ -897,23 +998,50 @@
 	unsigned device_type		:5;	/* Device type */
 	unsigned reserved13		:1;	/* Reserved */
 	unsigned protocol		:2;	/* Protocol type */
+#endif
 };
 
 /*
  *	INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C)
  */
 typedef struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	reserved0_765	:3;	/* Peripheral Qualifier - Reserved */
+	unsigned	device_type	:5;	/* Peripheral Device Type */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	device_type	:5;	/* Peripheral Device Type */
 	unsigned	reserved0_765	:3;	/* Peripheral Qualifier - Reserved */
+#endif
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	rmb		:1;	/* Removable Medium Bit */
+	unsigned	reserved1_6t0	:7;	/* Reserved */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	reserved1_6t0	:7;	/* Reserved */
 	unsigned	rmb		:1;	/* Removable Medium Bit */
+#endif
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	iso_version	:2;	/* ISO Version */
+	unsigned	ecma_version	:3;	/* ECMA Version */
+	unsigned	ansi_version	:3;	/* ANSI Version */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	ansi_version	:3;	/* ANSI Version */
 	unsigned	ecma_version	:3;	/* ECMA Version */
 	unsigned	iso_version	:2;	/* ISO Version */
+#endif
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	reserved3_7	:1;	/* AENC - Reserved */
+	unsigned	reserved3_6	:1;	/* TrmIOP - Reserved */
+	unsigned	reserved3_45	:2;	/* Reserved */
+	unsigned	response_format :4;	/* Response Data Format */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	response_format :4;	/* Response Data Format */
 	unsigned	reserved3_45	:2;	/* Reserved */
 	unsigned	reserved3_6	:1;	/* TrmIOP - Reserved */
 	unsigned	reserved3_7	:1;	/* AENC - Reserved */
+#endif
 	u8		additional_length;	/* Additional Length (total_length-4) */
 	u8		rsv5, rsv6, rsv7;	/* Reserved */
 	u8		vendor_id[8];		/* Vendor Identification */
@@ -928,11 +1056,19 @@
  *	READ POSITION packet command - Data Format (From Table 6-57)
  */
 typedef struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	bop		:1;	/* Beginning Of Partition */
+	unsigned	eop		:1;	/* End Of Partition */
+	unsigned	reserved0_543	:3;	/* Reserved */
+	unsigned	bpu		:1;	/* Block Position Unknown */	
+	unsigned	reserved0_10	:2;	/* Reserved */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	reserved0_10	:2;	/* Reserved */
 	unsigned	bpu		:1;	/* Block Position Unknown */	
 	unsigned	reserved0_543	:3;	/* Reserved */
 	unsigned	eop		:1;	/* End Of Partition */
 	unsigned	bop		:1;	/* Beginning Of Partition */
+#endif
 	u8		partition;		/* Partition Number */
 	u8		reserved2, reserved3;	/* Reserved */
 	u32		first_block;		/* First Block Location */
@@ -946,22 +1082,41 @@
  *	REQUEST SENSE packet command result - Data Format.
  */
 typedef struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	valid		:1;	/* The information field conforms to QIC-157C */
+	unsigned	error_code	:7;	/* Current of deferred errors */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	error_code	:7;	/* Current of deferred errors */
 	unsigned	valid		:1;	/* The information field conforms to QIC-157C */
+#endif
+
 	u8		reserved1	:8;	/* Segment Number - Reserved */
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	filemark 	:1;	/* Filemark */
+	unsigned	eom		:1;	/* End Of Medium */
+	unsigned	ili		:1;	/* Incorrect Length Indicator */
+	unsigned	reserved2_4	:1;	/* Reserved */
+	unsigned	sense_key	:4;	/* Sense Key */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	sense_key	:4;	/* Sense Key */
 	unsigned	reserved2_4	:1;	/* Reserved */
 	unsigned	ili		:1;	/* Incorrect Length Indicator */
 	unsigned	eom		:1;	/* End Of Medium */
 	unsigned	filemark 	:1;	/* Filemark */
+#endif
 	u32		information __attribute__ ((packed));
 	u8		asl;			/* Additional sense length (n-7) */
 	u32		command_specific;	/* Additional command specific information */
 	u8		asc;			/* Additional Sense Code */
 	u8		ascq;			/* Additional Sense Code Qualifier */
 	u8		replaceable_unit_code;	/* Field Replaceable Unit Code */
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	sksv		:1;	/* Sense Key Specific information is valid */
+	unsigned	sk_specific1 	:7;	/* Sense Key Specific */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	sk_specific1 	:7;	/* Sense Key Specific */
 	unsigned	sksv		:1;	/* Sense Key Specific information is valid */
+#endif
 	u8		sk_specific2;		/* Sense Key Specific */
 	u8		sk_specific3;		/* Sense Key Specific */
 	u8		pad[2];			/* Padding to 20 bytes */
@@ -1000,16 +1155,35 @@
  *	The Data Compression Page, as returned by the MODE SENSE packet command.
  */
 typedef struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	ps		:1;
+	unsigned	reserved0	:1;	/* Reserved */
+	unsigned	page_code	:6;	/* Page Code - Should be 0xf */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	page_code	:6;	/* Page Code - Should be 0xf */
 	unsigned	reserved0	:1;	/* Reserved */
 	unsigned	ps		:1;
+#endif
 	u8		page_length;		/* Page Length - Should be 14 */
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	dce		:1;	/* Data Compression Enable */
+	unsigned	dcc		:1;	/* Data Compression Capable */
+	unsigned	reserved2	:6;	/* Reserved */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	reserved2	:6;	/* Reserved */
 	unsigned	dcc		:1;	/* Data Compression Capable */
 	unsigned	dce		:1;	/* Data Compression Enable */
+#endif
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	dde		:1;	/* Data Decompression Enable */
+	unsigned	red		:2;	/* Report Exception on Decompression */
+	unsigned	reserved3	:5;	/* Reserved */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	reserved3	:5;	/* Reserved */
 	unsigned	red		:2;	/* Report Exception on Decompression */
 	unsigned	dde		:1;	/* Data Decompression Enable */
+#endif
 	u32		ca;			/* Compression Algorithm */
 	u32		da;			/* Decompression Algorithm */
 	u8		reserved[4];		/* Reserved */
@@ -1019,17 +1193,31 @@
  *	The Medium Partition Page, as returned by the MODE SENSE packet command.
  */
 typedef struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	ps		:1;
+	unsigned	reserved1_6	:1;	/* Reserved */
+	unsigned	page_code	:6;	/* Page Code - Should be 0x11 */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	page_code	:6;	/* Page Code - Should be 0x11 */
 	unsigned	reserved1_6	:1;	/* Reserved */
 	unsigned	ps		:1;
+#endif
 	u8		page_length;		/* Page Length - Should be 6 */
 	u8		map;			/* Maximum Additional Partitions - Should be 0 */
 	u8		apd;			/* Additional Partitions Defined - Should be 0 */
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	fdp		:1;	/* Fixed Data Partitions */
+	unsigned	sdp		:1;	/* Should be 0 */
+	unsigned	idp		:1;	/* Should be 0 */
+	unsigned	psum		:2;	/* Should be 0 */
+	unsigned	reserved4_012	:3;	/* Reserved */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	reserved4_012	:3;	/* Reserved */
 	unsigned	psum		:2;	/* Should be 0 */
 	unsigned	idp		:1;	/* Should be 0 */
 	unsigned	sdp		:1;	/* Should be 0 */
 	unsigned	fdp		:1;	/* Fixed Data Partitions */
+#endif
 	u8		mfr;			/* Medium Format Recognition */
 	u8		reserved[2];		/* Reserved */
 } idetape_medium_partition_page_t;
@@ -1656,7 +1844,7 @@
 	}
 }
 
-static void idetape_request_sense_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
@@ -1670,6 +1858,7 @@
 		printk (KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
 		idetape_end_request (0,HWGROUP (drive));
 	}
+	return ide_stopped;
 }
 
 /*
@@ -1701,7 +1890,7 @@
  *	last packet command. We queue a request sense packet command in
  *	the head of the request list.
  */
-static void idetape_retry_pc (ide_drive_t *drive)
+static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc;
@@ -1714,6 +1903,7 @@
 	idetape_create_request_sense_cmd (pc);
 	set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
 	idetape_queue_pc_head (drive, pc, rq);
+	return ide_stopped;
 }
 
 /*
@@ -1724,7 +1914,7 @@
  *	algorithm described before idetape_issue_packet_command.
  *
  */
-static void idetape_pc_intr (ide_drive_t *drive)
+static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_status_reg_t status;
@@ -1780,11 +1970,9 @@
 #endif /* IDETAPE_DEBUG_LOG */
 			if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
 				printk (KERN_ERR "ide-tape: I/O error in request sense command\n");
-				ide_do_reset (drive);
-				return;
+				return ide_do_reset (drive);
 			}
-			idetape_retry_pc (drive);				/* Retry operation */
-			return;
+			return idetape_retry_pc (drive);		/* Retry operation */
 		}
 		pc->error = 0;
 		if (test_bit (PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) {	/* Media access command */
@@ -1792,20 +1980,18 @@
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
 			idetape_postpone_request (drive);		/* Allow ide.c to handle other requests */
-			return;
+			return ide_stopped;
 		}
 		if (tape->failed_pc == pc)
 			tape->failed_pc=NULL;
-		pc->callback(drive);			/* Command finished - Call the callback function */
-		return;
+		return pc->callback(drive);			/* Command finished - Call the callback function */
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
 		printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
 		printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
 		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
@@ -1814,14 +2000,12 @@
 
 	if (ireason.b.cod) {
 		printk (KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 	if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
 		printk (KERN_ERR "ide-tape: We wanted to %s, ", ireason.b.io ? "Write":"Read");
 		printk (KERN_ERR "but the tape wants us to %s !\n",ireason.b.io ? "Read":"Write");
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 	if (!test_bit (PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
 		temp = pc->actually_transferred + bcount.all;
@@ -1830,7 +2014,7 @@
 				printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
 				idetape_discard_data (drive,bcount.all);
 				ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD);
-				return;
+				return ide_started;
 			}
 #if IDETAPE_DEBUG_LOG
 			printk (KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n");
@@ -1852,6 +2036,7 @@
 	pc->current_position+=bcount.all;
 
 	ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD);		/* And set the interrupt handler again */
+	return ide_started;
 }
 
 /*
@@ -1897,16 +2082,17 @@
  *
  */
 
-static void idetape_transfer_pc(ide_drive_t *drive)
+static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->pc;
 	idetape_ireason_reg_t ireason;
 	int retries = 100;
+	ide_startstop_t startstop;
 
-	if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
 		printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
-		return;
+		return startstop;
 	}
 	ireason.all=IN_BYTE (IDE_IREASON_REG);
 	while (retries-- && (!ireason.b.cod || ireason.b.io)) {
@@ -1921,14 +2107,14 @@
 	}
 	if (!ireason.b.cod || ireason.b.io) {
 		printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD);	/* Set the interrupt routine */
 	atapi_output_bytes (drive,pc->c,12);			/* Send the actual packet */
+	return ide_started;
 }
 
-static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
+static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_bcount_reg_t bcount;
@@ -1957,8 +2143,7 @@
 			pc->error = IDETAPE_ERROR_GENERAL;		/* Giving up */
 		}
 		tape->failed_pc=NULL;
-		pc->callback(drive);
-		return;
+		return pc->callback(drive);
 	}
 #if IDETAPE_DEBUG_LOG
 	printk (KERN_INFO "Retry number - %d\n",pc->retries);
@@ -1992,13 +2177,14 @@
 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
 		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD);
 		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		return ide_started;
 	} else {
 		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
-		idetape_transfer_pc(drive);
+		return idetape_transfer_pc(drive);
 	}
 }
 
-static void idetape_media_access_finished (ide_drive_t *drive)
+static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->pc;
@@ -2008,8 +2194,7 @@
 	if (status.b.dsc) {
 		if (status.b.check) {					/* Error detected */
 			printk (KERN_ERR "ide-tape: %s: I/O error, ",tape->name);
-			idetape_retry_pc (drive);			/* Retry operation */
-			return;
+			return idetape_retry_pc (drive);		/* Retry operation */
 		}
 		pc->error = 0;
 		if (tape->failed_pc == pc)
@@ -2018,13 +2203,13 @@
 		pc->error = IDETAPE_ERROR_GENERAL;
 		tape->failed_pc = NULL;
 	}
-	pc->callback (drive);
+	return pc->callback (drive);
 }
 
 /*
  *	General packet command callback function.
  */
-static void idetape_pc_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_pc_callback (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	
@@ -2033,9 +2218,10 @@
 #endif /* IDETAPE_DEBUG_LOG */
 
 	idetape_end_request (tape->pc->error ? 0:1, HWGROUP(drive));
+	return ide_stopped;
 }
 
-static void idetape_rw_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	struct request *rq = HWGROUP(drive)->rq;
@@ -2052,6 +2238,7 @@
 		idetape_end_request (1, HWGROUP (drive));
 	else
 		idetape_end_request (tape->pc->error, HWGROUP (drive));
+	return ide_stopped;
 }
 
 static void idetape_create_locate_cmd (idetape_pc_t *pc, unsigned int block, byte partition)
@@ -2170,7 +2357,7 @@
 		set_bit (PC_DMA_RECOMMENDED, &pc->flags);
 }
 
-static void idetape_read_position_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_read_position_result_t *result;
@@ -2200,6 +2387,7 @@
 		}
 	} else
 		idetape_end_request (0,HWGROUP (drive));
+	return ide_stopped;
 }
 
 static void idetape_create_read_position_cmd (idetape_pc_t *pc)
@@ -2213,7 +2401,7 @@
 /*
  *	idetape_do_request is our request handling function.	
  */
-static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc;
@@ -2229,24 +2417,23 @@
 		/*
 		 *	We do not support buffer cache originated requests.
 		 */
-		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue\n", drive->name);
+		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%d)\n", drive->name, rq->cmd);
 		ide_end_request (0,HWGROUP (drive));			/* Let the common code handle it */
-		return;
+		return ide_stopped;
 	}
 
 	/*
 	 *	Retry a failed packet command
 	 */
 	if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-		idetape_issue_packet_command (drive, tape->failed_pc);
-		return;
+		return idetape_issue_packet_command (drive, tape->failed_pc);
 	}
 #if IDETAPE_DEBUG_BUGS
 	if (postponed_rq != NULL)
 		if (rq != postponed_rq) {
 			printk (KERN_ERR "ide-tape: ide-tape.c bug - Two DSC requests were queued\n");
 			idetape_end_request (0,HWGROUP (drive));
-			return;
+			return ide_stopped;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
 
@@ -2266,15 +2453,16 @@
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
 		} else if ((signed long) (jiffies - tape->dsc_timeout) > 0) {
 			printk (KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name);
-			if (rq->cmd == IDETAPE_PC_RQ2)
+			if (rq->cmd == IDETAPE_PC_RQ2) {
 				idetape_media_access_finished (drive);
-			else
-				ide_do_reset (drive);
-			return;
+				return ide_stopped;
+			} else {
+				return ide_do_reset (drive);
+			}
 		} else if (jiffies - tape->dsc_polling_start > IDETAPE_DSC_MA_THRESHOLD)
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
 		idetape_postpone_request (drive);
-		return;
+		return ide_stopped;
 	}
 	switch (rq->cmd) {
 		case IDETAPE_READ_RQ:
@@ -2289,20 +2477,20 @@
 			rq->cmd = IDETAPE_WRITE_RQ;
 			rq->errors = IDETAPE_ERROR_EOD;
 			idetape_end_request (1, HWGROUP(drive));
-			return;
+			return ide_stopped;
 		case IDETAPE_PC_RQ1:
 			pc=(idetape_pc_t *) rq->buffer;
 			rq->cmd = IDETAPE_PC_RQ2;
 			break;
 		case IDETAPE_PC_RQ2:
 			idetape_media_access_finished (drive);
-			return;
+			return ide_stopped;
 		default:
 			printk (KERN_ERR "ide-tape: bug in IDETAPE_RQ_CMD macro\n");
 			idetape_end_request (0,HWGROUP (drive));
-			return;
+			return ide_stopped;
 	}
-	idetape_issue_packet_command (drive, pc);
+	return idetape_issue_packet_command (drive, pc);
 }
 
 /*
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide.c linux.14p16/drivers/block/ide.c
--- linux.vanilla/drivers/block/ide.c	Wed Oct 20 01:12:34 1999
+++ linux.14p16/drivers/block/ide.c	Tue Dec 21 00:35:46 1999
@@ -433,7 +433,7 @@
 #if 0
 	udelay(1);	/* need to guarantee 400ns since last command was issued */
 #endif
-	if (GET_STAT() & BUSY_STAT)
+	if (GET_STAT() & BUSY_STAT)	/* Note: this may clear a pending IRQ!! */
 		return 0;	/* drive busy:  definitely not interrupting */
 	return 1;		/* drive ready: *might* be interrupting */
 }
@@ -471,17 +471,15 @@
 	unsigned long flags;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 
-	spin_lock_irqsave(&hwgroup->spinlock, flags);
-#ifdef DEBUG
+	spin_lock_irqsave(&io_request_lock, flags);
 	if (hwgroup->handler != NULL) {
 		printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",
 			drive->name, hwgroup->handler, handler);
 	}
-#endif
 	hwgroup->handler       = handler;
 	hwgroup->timer.expires = jiffies + timeout;
-	add_timer(&(hwgroup->timer));
-	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+	add_timer(&hwgroup->timer);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 /*
@@ -516,7 +514,7 @@
 	}
 }
 
-static void do_reset1 (ide_drive_t *, int);		/* needed below */
+static ide_startstop_t do_reset1 (ide_drive_t *, int);		/* needed below */
 
 /*
  * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
@@ -524,7 +522,7 @@
  * and we have not yet hit our maximum waiting time, then the timer is restarted
  * for another 50ms.
  */
-static void atapi_reset_pollfunc (ide_drive_t *drive)
+static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	byte stat;
@@ -537,14 +535,14 @@
 	} else {
 		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
 			ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);
-			return;	/* continue polling */
+			return ide_started;	/* continue polling */
 		}
 		hwgroup->poll_timeout = 0;	/* end of polling */
 		printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
-		do_reset1 (drive, 1);	/* do it the old fashioned way */
-		return;
+		return do_reset1 (drive, 1);	/* do it the old fashioned way */
 	}
 	hwgroup->poll_timeout = 0;	/* done polling */
+	return ide_stopped;
 }
 
 /*
@@ -553,7 +551,7 @@
  * and we have not yet hit our maximum waiting time, then the timer is restarted
  * for another 50ms.
  */
-static void reset_pollfunc (ide_drive_t *drive)
+static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	ide_hwif_t *hwif = HWIF(drive);
@@ -562,7 +560,7 @@
 	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
 		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
 			ide_set_handler (drive, &reset_pollfunc, HZ/20);
-			return;	/* continue polling */
+			return ide_started;	/* continue polling */
 		}
 		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
 	} else  {
@@ -594,6 +592,7 @@
 		}
 	}
 	hwgroup->poll_timeout = 0;	/* done polling */
+	return ide_stopped;
 }
 
 static void pre_reset (ide_drive_t *drive)
@@ -623,7 +622,7 @@
  * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it,
  * we set a timer to poll at 50ms intervals.
  */
-static void do_reset1 (ide_drive_t *drive, int  do_not_try_atapi)
+static ide_startstop_t do_reset1 (ide_drive_t *drive, int  do_not_try_atapi)
 {
 	unsigned int unit;
 	unsigned long flags;
@@ -642,7 +641,7 @@
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 		ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);
 		__restore_flags (flags);	/* local CPU only */
-		return;
+		return ide_started;
 	}
 
 	/*
@@ -670,14 +669,15 @@
 #endif	/* OK_TO_RESET_CONTROLLER */
 
 	__restore_flags (flags);	/* local CPU only */
+	return ide_started;
 }
 
 /*
  * ide_do_reset() is the entry point to the drive/interface reset code.
  */
-void ide_do_reset (ide_drive_t *drive)
+ide_startstop_t ide_do_reset (ide_drive_t *drive)
 {
-	do_reset1 (drive, 0);
+	return do_reset1 (drive, 0);
 }
 
 /*
@@ -703,11 +703,8 @@
 	HWGROUP(drive)->rq = NULL;
 	rq->rq_status = RQ_INACTIVE;
 	spin_unlock_irqrestore(&io_request_lock, flags);
-	save_flags(flags);	/* all CPUs; overkill? */
-	cli();			/* all CPUs; overkill? */
 	if (rq->sem != NULL)
 		up(rq->sem);	/* inform originator that rq has been serviced */
-	restore_flags(flags);	/* all CPUs; overkill? */
 }
 
 /*
@@ -800,19 +797,19 @@
 /*
  * ide_error() takes action based on the error returned by the drive.
  */
-void ide_error (ide_drive_t *drive, const char *msg, byte stat)
+ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
 {
 	struct request *rq;
 	byte err;
 
 	err = ide_dump_status(drive, msg, stat);
 	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
-		return;
+		return ide_stopped;
 	/* retry only "normal" I/O: */
 	if (rq->cmd == IDE_DRIVE_CMD) {
 		rq->errors = 1;
 		ide_end_drive_cmd(drive, stat, err);
-		return;
+		return ide_stopped;
 	}
 	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
 		rq->errors |= ERROR_RESET;
@@ -821,7 +818,7 @@
 			/* err has different meaning on cdrom and tape */
 			if (err == ABRT_ERR) {
 				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
-					return;	/* some newer drives don't support WIN_SPECIFY */
+					return ide_stopped; /* some newer drives don't support WIN_SPECIFY */
 			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR))
 				; /* UDMA crc error -- just retry the operation */
 			else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
@@ -843,12 +840,13 @@
 	} else {
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
 			++rq->errors;
-			ide_do_reset(drive);
-			return;
-		} else if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+			return ide_do_reset(drive);
+		}
+		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
 			drive->special.b.recalibrate = 1;
 		++rq->errors;
 	}
+	return ide_stopped;
 }
 
 /*
@@ -866,7 +864,7 @@
 /*
  * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
  */
-static void drive_cmd_intr (ide_drive_t *drive)
+static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
 {
 	struct request *rq = HWGROUP(drive)->rq;
 	byte *args = (byte *) rq->buffer;
@@ -883,17 +881,17 @@
 			udelay(100);
 	}
 
-	if (OK_STAT(stat, READY_STAT, BAD_STAT))
-		ide_end_drive_cmd (drive, stat, GET_ERR());
-	else
-		ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
+	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
+		return ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
+	ide_end_drive_cmd (drive, stat, GET_ERR());
+	return ide_stopped;
 }
 
 /*
  * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
  * commands to a drive.  It used to do much more, but has been scaled back.
  */
-static inline void do_special (ide_drive_t *drive)
+static ide_startstop_t do_special (ide_drive_t *drive)
 {
 	special_t *s = &drive->special;
 
@@ -906,11 +904,12 @@
 		if (tuneproc != NULL)
 			tuneproc(drive, drive->tune_req);
 	} else if (drive->driver != NULL) {
-		DRIVER(drive)->special(drive);
+		return DRIVER(drive)->special(drive);
 	} else if (s->all) {
 		printk("%s: bad special flag: 0x%02x\n", drive->name, s->all);
 		s->all = 0;
 	}
+	return ide_stopped;
 }
 
 /*
@@ -924,12 +923,12 @@
  * setting a timer to wake up at half second intervals thereafter,
  * until timeout is achieved, before timing out.
  */
-int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout)
+int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout)
 {
 	byte stat;
 	int i;
 	unsigned long flags;
-
+ 
 	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
 	if ((stat = GET_STAT()) & BUSY_STAT) {
 		__save_flags(flags);	/* local CPU only */
@@ -938,7 +937,7 @@
 		while ((stat = GET_STAT()) & BUSY_STAT) {
 			if (0 < (signed long)(jiffies - timeout)) {
 				__restore_flags(flags);	/* local CPU only */
-				ide_error(drive, "status timeout", stat);
+				*startstop = ide_error(drive, "status timeout", stat);
 				return 1;
 			}
 		}
@@ -956,7 +955,7 @@
 		if (OK_STAT((stat = GET_STAT()), good, bad))
 			return 0;
 	}
-	ide_error(drive, "status error", stat);
+	*startstop = ide_error(drive, "status error", stat);
 	return 1;
 }
 
@@ -964,7 +963,7 @@
  * execute_drive_cmd() issues a special drive command,
  * usually initiated by ioctl() from the external hdparm program.
  */
-static void execute_drive_cmd (ide_drive_t *drive, struct request *rq)
+static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
 {
 	byte *args = rq->buffer;
 	if (args) {
@@ -978,7 +977,7 @@
 		}
 		OUT_BYTE(args[2],IDE_FEATURE_REG);
 		ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
-		return;
+		return ide_started;
 	} else {
 		/*
 		 * NULL is actually a valid way of waiting for
@@ -988,21 +987,21 @@
 		printk("%s: DRIVE_CMD (null)\n", drive->name);
 #endif
 		ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
-		return;
+		return ide_stopped;
 	}
 }
 
 /*
  * start_request() initiates handling of a new I/O request
  */
-static inline void start_request (ide_drive_t *drive)
+static ide_startstop_t start_request (ide_drive_t *drive)
 {
+	ide_startstop_t startstop;
 	unsigned long block, blockend;
 	struct request *rq = drive->queue;
 	unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
 	ide_hwif_t *hwif = HWIF(drive);
 
-	ide__sti();	/* local CPU only */
 #ifdef DEBUG
 	printk("%s: start_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);
 #endif
@@ -1032,29 +1031,27 @@
 	while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
 #endif
 	SELECT_DRIVE(hwif, drive);
-	if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
+	if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
 		printk("%s: drive not ready for command\n", drive->name);
-		return;
+		return startstop;
 	}
 	if (!drive->special.all) {
 		if (rq->cmd == IDE_DRIVE_CMD) {
-			execute_drive_cmd(drive, rq);
-			return;
+			return execute_drive_cmd(drive, rq);
 		}
 		if (drive->driver != NULL) {
-			DRIVER(drive)->do_request(drive, rq, block);
-			return;
+			return (DRIVER(drive)->do_request(drive, rq, block));
 		}
 		printk("%s: media type %d not supported\n", drive->name, drive->media);
 		goto kill_rq;
 	}
-	do_special(drive);
-	return;
+	return do_special(drive);
 kill_rq:
 	if (drive->driver != NULL)
 		DRIVER(drive)->end_request(0, HWGROUP(drive));
 	else
 		ide_end_request(0, HWGROUP(drive));
+	return ide_stopped;
 }
 
 /*
@@ -1115,22 +1112,54 @@
 }
 
 /*
- * Caller must have already acquired spinlock using *spinflags 
+ * Issue a new request to a drive from hwgroup
+ * Caller must have already done spin_lock_irqsave(&io_request_lock, ..);
+ *
+ * A hwgroup is a serialized group of IDE interfaces.  Usually there is
+ * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
+ * may have both interfaces in a single hwgroup to "serialize" access.
+ * Or possibly multiple ISA interfaces can share a common IRQ by being grouped
+ * together into one hwgroup for serialized access.
+ *
+ * Note also that several hwgroups can end up sharing a single IRQ,
+ * possibly along with many other devices.  This is especially common in
+ * PCI-based systems with off-board IDE controller cards.
+ *
+ * The IDE driver uses the single global io_request_lock spinlock to protect
+ * access to the request queues, and to protect the hwgroup->busy flag.
+ *
+ * The first thread into the driver for a particular hwgroup sets the
+ * hwgroup->busy flag to indicate that this hwgroup is now active,
+ * and then initiates processing of the top request from the request queue.
+ *
+ * Other threads attempting entry notice the busy setting, and will simply
+ * queue their new requests and exit immediately.  Note that hwgroup->busy
+ * remains set even when the driver is merely awaiting the next interrupt.
+ * Thus, the meaning is "this hwgroup is busy processing a request".
+ *
+ * When processing of a request completes, the completing thread or IRQ-handler
+ * will start the next request from the queue.  If no more work remains,
+ * the driver will clear the hwgroup->busy flag and exit.
+ *
+ * The io_request_lock (spinlock) is used to protect all access to the
+ * hwgroup->busy flag, but is otherwise not needed for most processing in
+ * the driver.  This makes the driver much more friendlier to shared IRQs
+ * than previous designs, while remaining 100% (?) SMP safe and capable.
  */
-static void ide_do_request (ide_hwgroup_t *hwgroup, unsigned long *hwgroup_flags, int masked_irq)
+static void ide_do_request (ide_hwgroup_t *hwgroup)
 {
 	struct blk_dev_struct *bdev;
 	ide_drive_t	*drive;
 	ide_hwif_t	*hwif;
-	unsigned long	io_flags;
+	ide_startstop_t	startstop;
 
-	hwgroup->busy = 1;
-	while (hwgroup->handler == NULL) {
-		spin_lock_irqsave(&io_request_lock, io_flags);
+	ide_get_lock(&ide_lock, ide_intr, hwgroup);	/* for atari only: POSSIBLY BROKEN HERE(?) */
+
+	while (!hwgroup->busy) {
+		hwgroup->busy = 1;
 		drive = choose_drive(hwgroup);
 		if (drive == NULL) {
 			unsigned long sleep = 0;
-
 			hwgroup->rq = NULL;
 			drive = hwgroup->drive;
 			do {
@@ -1140,24 +1169,31 @@
 				if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep)))
 					sleep = drive->sleep;
 			} while ((drive = drive->next) != hwgroup->drive);
-			spin_unlock_irqrestore(&io_request_lock, io_flags);
 			if (sleep) {
+				/*
+				 * Take a short snooze, and then wake up this hwgroup again.
+				 * This gives other hwgroups on the same a chance to
+				 * play fairly with us, just in case there are big differences
+				 * in relative throughputs.. don't want to hog the cpu too much.
+				 */
 				if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) 
 					sleep = jiffies + WAIT_MIN_SLEEP;
-#if 1
+				hwgroup->sleeping = 1;	/* so that ide_timer_expiry knows what to do */
+#if 1	/* paranoia */
 				if (hwgroup->timer.next || hwgroup->timer.prev)
-					printk("ide_set_handler: timer already active\n");
+					printk("ide_set_handler: timer was already active\n");
 #endif
 				mod_timer(&hwgroup->timer, sleep);
+				/* we purposely leave hwgroup->busy==1 while sleeping */
 			} else {
 				/* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_scheduler? */
 				ide_release_lock(&ide_lock);	/* for atari only */
+				hwgroup->busy = 0;
 			}
-			hwgroup->busy = 0;
-			return;
+			return;		/* no more work for this hwgroup (for now) */
 		}
 		hwif = HWIF(drive);
-		if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif) /* set nIEN for previous hwif */
+		if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif)	/* set nIEN for previous hwif */
 			OUT_BYTE(hwgroup->drive->ctl|2, hwgroup->hwif->io_ports[IDE_CONTROL_OFFSET]);
 		hwgroup->hwif = hwif;
 		hwgroup->drive = drive;
@@ -1168,15 +1204,13 @@
 		if (bdev->current_request == &bdev->plug)	/* FIXME: paranoia */
 			printk("%s: Huh? nuking plugged queue\n", drive->name);
 		bdev->current_request = hwgroup->rq = drive->queue;
-		spin_unlock_irqrestore(&io_request_lock, io_flags);
-
-		if (hwif->irq != masked_irq)
-			disable_irq_nosync(hwif->irq);
-		spin_unlock_irqrestore(&hwgroup->spinlock, *hwgroup_flags);
-		start_request(drive);
-		spin_lock_irqsave(&hwgroup->spinlock, *hwgroup_flags);
-		if (hwif->irq != masked_irq)
-			enable_irq(hwif->irq);
+		spin_unlock(&io_request_lock);
+		if (!hwif->serialized)	/* play it safe with buggy hardware */
+			ide__sti();
+		startstop = start_request(drive);
+		spin_lock_irq(&io_request_lock);
+		if (startstop == ide_stopped)
+			hwgroup->busy = 0;
 	}
 }
 
@@ -1190,134 +1224,112 @@
 	return &hwif->drives[DEVICE_NR(dev) & 1].queue;
 }
 
-/*
- * do_hwgroup_request() invokes ide_do_request() after claiming hwgroup->busy.
- */
-static void do_hwgroup_request (ide_hwgroup_t *hwgroup)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&hwgroup->spinlock, flags);
-	if (hwgroup->busy) {
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-		return;
-	}
-	del_timer(&hwgroup->timer);
-	ide_get_lock(&ide_lock, ide_intr, hwgroup);	/* for atari only */
-	ide_do_request(hwgroup, &flags, 0);
-	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-}
-
-/*
- * ll_rw_blk.c invokes our do_idex_request() function
- * with the io_request_spinlock already grabbed.
- * Since we need to do our own spinlock's internally,
- * on paths that don't necessarily originate through the
- * do_idex_request() path, we have to undo the spinlock on entry,
- * and restore it again on exit.
- * Fortunately, this is mostly a nop for non-SMP kernels.
- */
-static inline void unlock_do_hwgroup_request (ide_hwgroup_t *hwgroup)
-{
-	spin_unlock(&io_request_lock);
-	do_hwgroup_request (hwgroup);
-	spin_lock_irq(&io_request_lock);
-}
-
 void do_ide0_request (void)
 {
-	unlock_do_hwgroup_request (ide_hwifs[0].hwgroup);
+	ide_do_request (ide_hwifs[0].hwgroup);
 }
 
 #if MAX_HWIFS > 1
 void do_ide1_request (void)
 {
-	unlock_do_hwgroup_request (ide_hwifs[1].hwgroup);
+	ide_do_request (ide_hwifs[1].hwgroup);
 }
 #endif /* MAX_HWIFS > 1 */
 
 #if MAX_HWIFS > 2
 void do_ide2_request (void)
 {
-	unlock_do_hwgroup_request (ide_hwifs[2].hwgroup);
+	ide_do_request (ide_hwifs[2].hwgroup);
 }
 #endif /* MAX_HWIFS > 2 */
 
 #if MAX_HWIFS > 3
 void do_ide3_request (void)
 {
-	unlock_do_hwgroup_request (ide_hwifs[3].hwgroup);
+	ide_do_request (ide_hwifs[3].hwgroup);
 }
 #endif /* MAX_HWIFS > 3 */
 
 #if MAX_HWIFS > 4
 void do_ide4_request (void)
 {
-	unlock_do_hwgroup_request (ide_hwifs[4].hwgroup);
+	ide_do_request (ide_hwifs[4].hwgroup);
 }
 #endif /* MAX_HWIFS > 4 */
 
 #if MAX_HWIFS > 5
 void do_ide5_request (void)
 {
-	unlock_do_hwgroup_request (ide_hwifs[5].hwgroup);
+	ide_do_request (ide_hwifs[5].hwgroup);
 }
 #endif /* MAX_HWIFS > 5 */
 
-static void start_next_request (ide_hwgroup_t *hwgroup, int masked_irq)
-{
-	unsigned long	flags;
-	ide_drive_t	*drive;
-
-	spin_lock_irqsave(&hwgroup->spinlock, flags);
-	if (hwgroup->handler != NULL) {
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-		return;
-	}
-	drive = hwgroup->drive;
-	set_recovery_timer(HWIF(drive));
-	drive->service_time = jiffies - drive->service_start;
-	ide_do_request(hwgroup, &flags, masked_irq);
-	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-}
-
+/*
+ * ide_timer_expiry() is our timeout function for all drive operations.
+ * But note that it can also be invoked as a result of a "sleep" operation
+ * triggered by the mod_timer() call in ide_do_request.
+ */
 void ide_timer_expiry (unsigned long data)
 {
-	ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;
-	ide_drive_t   *drive;
-	ide_handler_t *handler;
-	unsigned long flags;
+	ide_hwgroup_t	*hwgroup = (ide_hwgroup_t *) data;
+	ide_handler_t	*handler;
+	unsigned long	flags;
 
-	spin_lock_irqsave(&hwgroup->spinlock, flags);
-	drive = hwgroup->drive;
+	spin_lock_irqsave(&io_request_lock, flags);
+	del_timer(&hwgroup->timer);
 	if ((handler = hwgroup->handler) == NULL) {
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-		do_hwgroup_request(hwgroup);
-		return;
-	}
-	hwgroup->busy = 1;	/* should already be "1" */
-	hwgroup->handler = NULL;
-	del_timer(&hwgroup->timer);	/* Is this needed?? */
-	if (hwgroup->poll_timeout != 0) {	/* polling in progress? */
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-		handler(drive);
-	} else if (drive_is_ready(drive)) {
-		printk("%s: lost interrupt\n", drive->name);
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-		handler(drive);
+		/*
+		 * Either a marginal timeout occured (got the interrupt just as timer expired),
+		 * or we were "sleeping" to give other devices a chance.  Either way, we don't
+		 * really want to complain about anything.
+		 */
+		if (hwgroup->sleeping) {
+			hwgroup->sleeping = 0;
+			hwgroup->busy = 0;
+		}
 	} else {
-		if (drive->waiting_for_dma) {
-			(void) hwgroup->hwif->dmaproc(ide_dma_end, drive);
-			printk("%s: timeout waiting for DMA\n", drive->name);
-	/*
-	 *  need something here for HX PIIX3 UDMA and HPT343.......AMH
-	 *  irq timeout: status=0x58 { DriveReady SeekComplete DataRequest }
-	 */
+		ide_drive_t *drive = hwgroup->drive;
+		hwgroup->handler = NULL;
+		if (!drive) {
+			printk("ide_timer_expiry: hwgroup->drive was NULL\n");
+		} else {
+			ide_hwif_t *hwif;
+			ide_startstop_t startstop;
+			if (!hwgroup->busy) {
+				hwgroup->busy = 1;	/* paranoia */
+				printk("%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);
+			}
+			/*
+			 * We need to simulate a real interrupt when invoking the handler()
+			 * function, which means we need to globally mask the specific IRQ:
+			 */
+			spin_unlock(&io_request_lock);
+			hwif  = HWIF(drive);
+			disable_irq(hwif->irq);
+			__cli();	/* local CPU only, as if we were handling an interrupt */
+			if (hwgroup->poll_timeout != 0 || drive_is_ready(drive)) {
+				if (hwgroup->poll_timeout == 0) {
+					printk("%s: lost interrupt\n", drive->name);
+					(void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]);
+				}
+				startstop = handler(drive);
+			} else {
+				if (drive->waiting_for_dma) {
+					(void) hwgroup->hwif->dmaproc(ide_dma_end, drive);
+					printk("%s: timeout waiting for DMA\n", drive->name);
+				}
+				startstop = ide_error(drive, "irq timeout", GET_STAT());
+			}
+			set_recovery_timer(hwif);
+			drive->service_time = jiffies - drive->service_start;
+			enable_irq(hwif->irq);
+			spin_lock_irq(&io_request_lock);
+			if (startstop == ide_stopped)
+				hwgroup->busy = 0;
 		}
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-		ide_error(drive, "irq timeout", GET_STAT());
 	}
-	start_next_request(hwgroup, 0);
+	ide_do_request(hwgroup);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 /*
@@ -1377,9 +1389,9 @@
 	ide_hwif_t *hwif;
 	ide_drive_t *drive;
 	ide_handler_t *handler;
+	ide_startstop_t startstop;
 
-	__cli();	/* local CPU only */
-	spin_lock_irqsave(&hwgroup->spinlock, flags);
+	spin_lock_irqsave(&io_request_lock, flags);
 	hwif = hwgroup->hwif;
 	if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) {
 		/*
@@ -1404,41 +1416,67 @@
 			 */
 			(void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]);
 			unexpected_intr(irq, hwgroup);
+		} 
+#ifdef CONFIG_BLK_DEV_IDEPCI		
+		else 
+		{
+			/*
+			 * Whack the status register, just in case we have a leftover pending IRQ.
+			 */
+			(void)IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
 		}
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+#endif		
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return;
 	}
 	drive = hwgroup->drive;
-	if (!drive || !drive_is_ready(drive)) {
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+	if (!drive) {
+		/*
+		 * This should NEVER happen, and there isn't much we could do about it here.
+		 */
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	if (!drive_is_ready(drive)) {
+		/*
+		 * This happens regularly when we share a PCI IRQ with another device.
+		 * Unfortunately, it can also happen with some buggy drives that trigger
+		 * the IRQ before their status register is up to date.  Hopefully we have
+		 * enough advance overhead that the latter isn't a problem.
+		 */
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return;
 	}
+	if (!hwgroup->busy) {
+		hwgroup->busy = 1;	/* paranoia */
+		printk("%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);
+	}
 	hwgroup->handler = NULL;
+	del_timer(&hwgroup->timer);
 	(void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]);
-	del_timer(&(hwgroup->timer));
-	{
-		struct request *rq;
-		unsigned long block, sectors;
-
-		if ((rq = hwgroup->rq) != NULL) {
-			block = rq->sector;
-			block += drive->part[MINOR(rq->rq_dev)&PARTN_MASK].start_sect + drive->sect0;
-			sectors = drive->using_dma ? rq->nr_sectors : drive->mult_count ? drive->mult_count : 1;
-		}
-	}
-
-	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+	spin_unlock(&io_request_lock);
 	if (drive->unmask)
 		ide__sti();	/* local CPU only */
-	handler(drive);		/* service this interrupt, may set handler for next interrupt */
+	startstop = handler(drive);	/* service this interrupt, may set handler for next interrupt */
+	spin_lock_irq(&io_request_lock);
 	/*
 	 * Note that handler() may have set things up for another
 	 * interrupt to occur soon, but it cannot happen until
 	 * we exit from this routine, because it will be the
-	 * same irq as is currently being serviced here,
-	 * and Linux won't allow another (on any CPU) until we return.
+	 * same irq as is currently being serviced here, and Linux
+	 * won't allow another of the same (on any CPU) until we return.
 	 */
-	start_next_request(hwgroup, hwif->irq);
+	set_recovery_timer(HWIF(drive));
+	drive->service_time = jiffies - drive->service_start;
+	if (startstop == ide_stopped) {
+		if (hwgroup->handler == NULL) {	/* paranoia */
+			hwgroup->busy = 0;
+			ide_do_request(hwgroup);
+		} else {
+			printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name);
+		}
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 /*
@@ -1521,7 +1559,6 @@
 	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
 	if (action == ide_wait)
 		rq->sem = &sem;
-
 	spin_lock_irqsave(&io_request_lock, flags);
 	cur_rq = drive->queue;
 	if (cur_rq == NULL || action == ide_preempt) {
@@ -1537,16 +1574,13 @@
 		rq->next = cur_rq->next;
 		cur_rq->next = rq;
 	}
+	ide_do_request(hwgroup);
 	spin_unlock_irqrestore(&io_request_lock, flags);
-	do_hwgroup_request(hwgroup);
-	save_flags(flags);	/* all CPUs; overkill? */
-	cli();			/* all CPUs; overkill? */
-	if (action == ide_wait)
-	{
-		down(&sem);	/* wait for it to be serviced */
+	if (action == ide_wait) {
+		down(&sem);			/* wait for it to be serviced */
+		return rq->errors ? -EIO : 0;	/* return -EIO if errors */
 	}
-	restore_flags(flags);	/* all CPUs; overkill? */
-	return rq->errors ? -EIO : 0;	/* return -EIO if errors */
+	return 0;
 }
 
 /*
@@ -1569,14 +1603,14 @@
 	major = MAJOR(i_rdev);
 	minor = drive->select.b.unit << PARTN_BITS;
 	hwgroup = HWGROUP(drive);
-	spin_lock_irqsave(&hwgroup->spinlock, flags);
+	spin_lock_irqsave(&io_request_lock, flags);
 	if (drive->busy || (drive->usage > 1)) {
-		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return -EBUSY;
 	};
 	drive->busy = 1;
 	MOD_INC_USE_COUNT;
-	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 
 	for (p = 0; p < (1<<PARTN_BITS); ++p) {
 		if (drive->part[p].nr_sects > 0) {
@@ -1962,7 +1996,7 @@
 	unsigned long	flags;
 
 	if ((setting->rw & SETTING_READ)) {
-		spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
+		spin_lock_irqsave(&io_request_lock, flags);
 		switch(setting->data_type) {
 			case TYPE_BYTE:
 				val = *((u8 *) setting->data);
@@ -1975,7 +2009,7 @@
 				val = *((u32 *) setting->data);
 				break;
 		}
-		spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+		spin_unlock_irqrestore(&io_request_lock, flags);
 	}
 	return val;
 }
@@ -1985,19 +2019,28 @@
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	unsigned long timeout = jiffies + (3 * HZ);
 
-	spin_lock_irqsave(&hwgroup->spinlock, *flags);
+	spin_lock_irqsave(&io_request_lock, *flags);
 	while (hwgroup->busy) {
-		spin_unlock_irqrestore(&hwgroup->spinlock, *flags);
-		__sti();	/* local CPU only; needed for jiffies */
+		unsigned long lflags;
+		spin_unlock_irqrestore(&io_request_lock, *flags);
+		__save_flags(lflags);	/* local CPU only */
+		__sti();		/* local CPU only; needed for jiffies */
 		if (0 < (signed long)(jiffies - timeout)) {
+			__restore_flags(lflags);	/* local CPU only */
 			printk("%s: channel busy\n", drive->name);
 			return -EBUSY;
 		}
-		spin_lock_irqsave(&hwgroup->spinlock, *flags);
+		__restore_flags(lflags);	/* local CPU only */
+		spin_lock_irqsave(&io_request_lock, *flags);
 	}
 	return 0;
 }
 
+/*
+ * FIXME:  This should be changed to enqueue a special request
+ * to the driver to change settings, and then wait on a sema for completion.
+ * The current scheme of polling is kludgey, though safe enough.
+ */
 int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val)
 {
 	unsigned long flags;
@@ -2030,7 +2073,7 @@
 				*p = val;
 			break;
 	}
-	spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	return 0;
 }
 
@@ -2668,47 +2711,16 @@
 	if (!drive)
 		return 0;
 
-	if (drive->forced_geom) {
-		/*
-		 * Update the current 3D drive values.
-		 */
-		drive->id->cur_cyls	= drive->bios_cyl;
-		drive->id->cur_heads	= drive->bios_head;
-		drive->id->cur_sectors	= drive->bios_sect;
+	if (drive->forced_geom)
 		return 0;
-	}
 
-	if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63) {
-		/*
-		 * Update the current 3D drive values.
-		 */
-		drive->id->cur_cyls	= drive->bios_cyl;
-		drive->id->cur_heads	= drive->bios_head;
-		drive->id->cur_sectors	= drive->bios_sect;
+	if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63)
 		return 0;		/* we already have a translation */
-	}
 
 	printk("%s ", msg);
 
-	if (xparm < 0 && (drive->bios_cyl * drive->bios_head * drive->bios_sect) < (1024 * 16 * 63)) {
-		/*
-		 * Update the current 3D drive values.
-		 */
-		drive->id->cur_cyls	= drive->bios_cyl;
-		drive->id->cur_heads	= drive->bios_head;
-		drive->id->cur_sectors	= drive->bios_sect;
+	if (xparm < 0 && (drive->bios_cyl * drive->bios_head * drive->bios_sect) < (1024 * 16 * 63))
 		return 0;		/* small disk: no translation needed */
-	}
-
-	if (drive->id) {
-		drive->cyl  = drive->id->cyls;
-		drive->head = drive->id->heads;
-		drive->sect = drive->id->sectors;
-	}
-	drive->bios_cyl  = drive->cyl;
-	drive->bios_head = drive->head;
-	drive->bios_sect = drive->sect;
-	drive->special.b.set_geometry = 1;
 
 	tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63;
 	drive->bios_sect = 63;
@@ -2736,12 +2748,7 @@
 	}
 	drive->part[0].nr_sects = current_capacity(drive);
 	printk("[%d/%d/%d]", drive->bios_cyl, drive->bios_head, drive->bios_sect);
-	/*
-	 * Update the current 3D drive values.
-	 */
-	drive->id->cur_cyls    = drive->bios_cyl;
-	drive->id->cur_heads   = drive->bios_head;
-	drive->id->cur_sectors = drive->bios_sect;
+
 	return 1;
 }
 
@@ -2844,9 +2851,10 @@
 	return ide_unregister_subdriver(drive);
 }
 
-static void default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 	ide_end_request(0, HWGROUP(drive));
+	return ide_stopped;
 }
  
 static void default_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
@@ -2884,12 +2892,13 @@
 	return 0x7fffffff;	/* cdrom or tape */
 }
 
-static void default_special (ide_drive_t *drive)
+static ide_startstop_t default_special (ide_drive_t *drive)
 {
 	special_t *s = &drive->special;
 
 	s->all = 0;
 	drive->mult_req = 0;
+	return ide_stopped;
 }
 
 static void setup_driver_defaults (ide_drive_t *drive)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide.h linux.14p16/drivers/block/ide.h
--- linux.vanilla/drivers/block/ide.h	Sun Mar 28 19:03:35 1999
+++ linux.14p16/drivers/block/ide.h	Wed Dec 15 23:13:23 1999
@@ -353,14 +353,22 @@
 	} ide_hwif_t;
 
 /*
+ * Status returned from various ide_ functions
+ */
+typedef enum {
+	ide_stopped,	/* no drive operation was started */
+	ide_started	/* a drive operation was started, and a handler was set up */
+} ide_startstop_t;
+
+/*
  *  internal ide interrupt handler type
  */
-typedef void (ide_handler_t)(ide_drive_t *);
+typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
 
 typedef struct hwgroup_s {
-	spinlock_t		spinlock; /* protects "busy" and "handler" */
 	ide_handler_t		*handler;/* irq handler, if active */
-	int			busy;	/* BOOL: protects all fields below */
+	volatile int		busy;	/* BOOL: protects all fields below */
+	int			sleeping; /* BOOL: wake us up on timer expiry */
 	ide_drive_t		*drive;	/* current drive */
 	ide_hwif_t		*hwif;	/* ptr to current hwif in linked-list */
 	struct request		*rq;	/* current request */
@@ -443,13 +451,14 @@
 #define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0;
 #endif
 
+
 /*
  * Subdrivers support.
  */
 #define IDE_SUBDRIVER_VERSION	1
 
 typedef int	(ide_cleanup_proc)(ide_drive_t *);
-typedef void 	(ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long);
+typedef ide_startstop_t (ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long);
 typedef void	(ide_end_request_proc)(byte, ide_hwgroup_t *);
 typedef int 	(ide_ioctl_proc)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
 typedef int	(ide_open_proc)(struct inode *, struct file *, ide_drive_t *);
@@ -457,7 +466,7 @@
 typedef int	(ide_check_media_change_proc)(ide_drive_t *);
 typedef void	(ide_pre_reset_proc)(ide_drive_t *);
 typedef unsigned long (ide_capacity_proc)(ide_drive_t *);
-typedef void	(ide_special_proc)(ide_drive_t *);
+typedef ide_startstop_t (ide_special_proc)(ide_drive_t *);
 typedef void	(ide_setting_proc)(ide_drive_t *);
 
 typedef struct ide_driver_s {
@@ -545,9 +554,9 @@
 
 /*
  * ide_error() takes action based on the error returned by the controller.
- * The calling function must return afterwards, to restart the request.
+ * The caller should return immediately after invoking this.
  */
-void ide_error (ide_drive_t *drive, const char *msg, byte stat);
+ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat);
 
 /*
  * Issue a simple drive command
@@ -567,10 +576,11 @@
  * This routine busy-waits for the drive status to be not "busy".
  * It then checks the status for all of the "good" bits and none
  * of the "bad" bits, and if all is okay it returns 0.  All other
- * cases return 1 after invoking ide_error() -- caller should return.
- *
+ * cases return 1 after doing "*startstop = ide_error()", and the
+ * caller should return the updated value of "startstop" in this case.
+ * "startstop" is unchanged when the function returns 0;
  */
-int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
+int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
 
 /*
  * This routine is called from the partition-table code in genhd.c
@@ -594,7 +604,7 @@
  * Start a reset operation for an IDE interface.
  * The caller should return immediately after invoking this.
  */
-void ide_do_reset (ide_drive_t *);
+ide_startstop_t ide_do_reset (ide_drive_t *);
 
 /*
  * This function is intended to be used prior to invoking ide_do_drive_cmd().
@@ -661,7 +671,7 @@
  * ide_multwrite() transfers a block of up to mcount sectors of data
  * to a drive as part of a disk multwrite operation.
  */
-void ide_multwrite (ide_drive_t *drive, unsigned int mcount);
+int ide_multwrite (ide_drive_t *drive, unsigned int mcount);
 
 /*
  * ide_stall_queue() can be used by a drive to give excess bandwidth back
@@ -751,7 +761,7 @@
 #define BAD_DMA_DRIVE		0
 #define GOOD_DMA_DRIVE		1
 int ide_build_dmatable (ide_drive_t *drive);
-void ide_dma_intr  (ide_drive_t *drive);
+ide_startstop_t ide_dma_intr  (ide_drive_t *drive);
 int check_drive_lists (ide_drive_t *drive, int good_bad);
 int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
 int ide_release_dma (ide_hwif_t *hwif);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ll_rw_blk.c linux.14p16/drivers/block/ll_rw_blk.c
--- linux.vanilla/drivers/block/ll_rw_blk.c	Sat Aug 14 02:27:16 1999
+++ linux.14p16/drivers/block/ll_rw_blk.c	Wed Dec 15 22:16:40 1999
@@ -422,7 +422,6 @@
 	if (buffer_locked(bh))
 		return;
 	/* Maybe the above fixes it, and maybe it doesn't boot. Life is interesting */
-
 	lock_buffer(bh);
 
 	if (blk_size[major]) {
@@ -512,6 +511,8 @@
 	     case IDE5_MAJOR:
 	     case ACSI_MAJOR:
 	     case MFM_ACORN_MAJOR:
+             case MDISK_MAJOR:
+             case DASD_MAJOR:
 		/*
 		 * The scsi disk and cdrom drivers completely remove the request
 		 * from the queue when they start processing an entry.  For this
@@ -657,7 +658,6 @@
 		kdevname(bh[0]->b_dev), bh[0]->b_blocknr);
 		goto sorry;
 	}
-
 	/* Determine correct block size for this device.  */
 	correct_size = BLOCK_SIZE;
 	if (blksize_size[major]) {
@@ -896,6 +896,12 @@
 #endif
 #ifdef CONFIG_BLK_DEV_NBD
 	nbd_init();
+#endif
+#ifdef CONFIG_MDISK
+	mdisk_init();
+#endif
+#ifdef CONFIG_DASD
+	dasd_init();
 #endif
 	return 0;
 };
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/loop.c linux.14p16/drivers/block/loop.c
--- linux.vanilla/drivers/block/loop.c	Sat Aug 14 02:27:16 1999
+++ linux.14p16/drivers/block/loop.c	Mon Dec 13 21:16:32 1999
@@ -315,7 +315,7 @@
 		/* Do what the default llseek() code would have done */
 		file->f_pos = new_offset;
 		file->f_reada = 0;
-		file->f_version = ++event;
+		file->f_version = ++global_event;
 	}
 
 	if (file->f_op->write == NULL) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ns87415.c linux.14p16/drivers/block/ns87415.c
--- linux.vanilla/drivers/block/ns87415.c	Sat Aug 14 02:26:47 1999
+++ linux.14p16/drivers/block/ns87415.c	Thu Dec  9 15:33:40 1999
@@ -97,6 +97,10 @@
 				return 0;
 			ns87415_prepare_drive(drive, 0);	/* DMA failed: select PIO xfer */
 			return 1;
+		case ide_dma_check:
+			if (drive->media != ide_disk)
+				return ide_dmaproc(ide_dma_off_quietly, drive);
+			/* Fallthrough... */
 		default:
 			return ide_dmaproc(func, drive);	/* use standard DMA stuff */
 	}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/pdc4030.c linux.14p16/drivers/block/pdc4030.c
--- linux.vanilla/drivers/block/pdc4030.c	Tue Dec 29 19:24:57 1998
+++ linux.14p16/drivers/block/pdc4030.c	Thu Dec  9 15:33:40 1999
@@ -122,6 +122,7 @@
 */
 int init_pdc4030 (void)
 {
+	ide_startstop_t startstop;
 	ide_hwif_t *hwif = hwif_required;
         ide_drive_t *drive;
 	ide_hwif_t *second_hwif;
@@ -143,7 +144,7 @@
 	if(pdc4030_cmd(drive,PROMISE_GET_CONFIG)) {
 	    return 0;
 	}
-	if(ide_wait_stat(drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
+	if(ide_wait_stat(&startstop,drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
 	    printk("%s: Failed Promise read config!\n",hwif->name);
 	    return 0;
 	}
@@ -195,7 +196,7 @@
 /*
  * promise_read_intr() is the handler for disk read/multread interrupts
  */
-static void promise_read_intr (ide_drive_t *drive)
+static ide_startstop_t promise_read_intr (ide_drive_t *drive)
 {
 	byte stat;
 	int i;
@@ -203,8 +204,7 @@
 	struct request *rq;
 
 	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
-		ide_error(drive, "promise_read_intr", stat);
-		return;
+		return ide_error(drive, "promise_read_intr", stat);
 	}
 
 read_again:
@@ -240,17 +240,18 @@
 		    goto read_again;
 		if(stat & BUSY_STAT) {
 		    ide_set_handler (drive, &promise_read_intr, WAIT_CMD);
-		    return;
+		    return ide_started;;
 		}
 		printk("Ah! promise read intr: sectors left !DRQ !BUSY\n");
-		ide_error(drive, "promise read intr", stat);
+		return ide_error(drive, "promise read intr", stat);
 	}
+	return ide_stopped;
 }
 
 /*
  * promise_write_pollfunc() is the handler for disk write completion polling.
  */
-static void promise_write_pollfunc (ide_drive_t *drive)
+static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
 {
 	int i;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
@@ -259,20 +260,20 @@
         if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
             if (time_before(jiffies, hwgroup->poll_timeout)) {
                 ide_set_handler (drive, &promise_write_pollfunc, 1);
-                return; /* continue polling... */
+                return ide_started; /* continue polling... */
             }
             printk("%s: write timed-out!\n",drive->name);
-            ide_error (drive, "write timeout", GET_STAT());
-            return;
+            return ide_error (drive, "write timeout", GET_STAT());
         }
         
-	ide_multwrite(drive, 4);
+	if (ide_multwrite(drive, 4))
+		return ide_stopped;
         rq = hwgroup->rq;
         for (i = rq->nr_sectors; i > 0;) {
             i -= rq->current_nr_sectors;
             ide_end_request(1, hwgroup);
         }
-        return;
+        return ide_stopped;
 }
 
 /*
@@ -283,24 +284,27 @@
  * how it's done in the drivers for other O/Ses. There is no interrupt
  * generated on writes, which is why we have to do it like this.
  */
-static void promise_write (ide_drive_t *drive)
+static ide_startstop_t promise_write (ide_drive_t *drive)
 {
     ide_hwgroup_t *hwgroup = HWGROUP(drive);
     struct request *rq = &hwgroup->wrq;
     int i;
 
     if (rq->nr_sectors > 4) {
-        ide_multwrite(drive, rq->nr_sectors - 4);
+        if (ide_multwrite(drive, rq->nr_sectors - 4))
+		return ide_stopped;
         hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
         ide_set_handler (drive, &promise_write_pollfunc, 1);
-        return;
+        return ide_started;
     } else {
-        ide_multwrite(drive, rq->nr_sectors);
+        if (ide_multwrite(drive, rq->nr_sectors))
+		return ide_stopped;
         rq = hwgroup->rq;
         for (i = rq->nr_sectors; i > 0;) {
             i -= rq->current_nr_sectors;
             ide_end_request(1, hwgroup);
         }
+	return ide_stopped;
     }
 }
 
@@ -309,7 +313,7 @@
  * already set up. It issues a READ or WRITE command to the Promise
  * controller, assuming LBA has been used to set up the block number.
  */
-void do_pdc4030_io (ide_drive_t *drive, struct request *rq)
+ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
 {
 	unsigned long timeout;
 	byte stat;
@@ -330,28 +334,29 @@
                     disable_irq(HWIF(drive)->irq);
 		    ide_intr(HWIF(drive)->irq,HWGROUP(drive),NULL);
                     enable_irq(HWIF(drive)->irq);
-		    return;
+		    return ide_stopped;
 		}
 		if(IN_BYTE(IDE_SELECT_REG) & 0x01)
-		    return;
+		    return ide_started;
 		udelay(1);
 	    } while (time_before(jiffies, timeout));
 	    printk("%s: reading: No DRQ and not waiting - Odd!\n",
 		   drive->name);
-	    return;
+	    return ide_started;
 	}
 	if (rq->cmd == WRITE) {
+	    ide_startstop_t startstop;
 	    OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
-	    if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
+	    if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
 		printk("%s: no DRQ after issuing PROMISE_WRITE\n", drive->name);
-		return;
+		return startstop;
 	    }
 	    if (!drive->unmask)
 		__cli();	/* local CPU only */
 	    HWGROUP(drive)->wrq = *rq; /* scratchpad */
-	    promise_write(drive);
-	    return;
+	    return promise_write(drive);
 	}
 	printk("%s: bad command: %d\n", drive->name, rq->cmd);
 	ide_end_request(0, HWGROUP(drive));
+	return ide_stopped;
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/raid0.c linux.14p16/drivers/block/raid0.c
--- linux.vanilla/drivers/block/raid0.c	Fri May  8 08:17:13 1998
+++ linux.14p16/drivers/block/raid0.c	Wed Dec 15 16:43:06 1999
@@ -182,6 +182,12 @@
   block=*rsector >> 1;
   hash=data->hash_table+(block/data->smallest->size);
 
+  if (hash - data->hash_table > data->nr_zones) 
+  { 
+	  printk(KERN_DEBUG "raid0_map: invalid block %ul\n", block);
+	  return -1;
+  }
+
   /* Sanity check */
   if ((chunk_size*2)<(*rsector % (chunk_size*2))+size)
   {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/rd.c linux.14p16/drivers/block/rd.c
--- linux.vanilla/drivers/block/rd.c	Sat Aug 14 02:27:16 1999
+++ linux.14p16/drivers/block/rd.c	Wed Dec 15 22:27:06 1999
@@ -112,7 +112,11 @@
  * architecture-specific setup routine (from the stored boot sector
  * information). 
  */
+#ifdef CONFIG_ARCH_S390
+int rd_size = 8192;		/* Size of the RAM disks */
+#else
 int rd_size = 4096;		/* Size of the RAM disks */
+#endif
 
 #ifndef MODULE
 int rd_doload = 0;		/* 1 = load RAM disk, 0 = don't load */
@@ -191,7 +195,10 @@
 	switch (cmd) {
 		case BLKFLSBUF:
 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-			invalidate_buffers(inode->i_rdev);
+			/* special: we want to release the ramdisk memory,
+			   it's not like with the other blockdevices where
+			   this ioctl only flushes away the buffer cache. */
+			destroy_buffers(inode->i_rdev);
 			break;
 
          	case BLKGETSIZE:   /* Return device size */
@@ -347,7 +354,7 @@
 	int i;
 
 	for (i = 0 ; i < NUM_RAMDISKS; i++)
-		invalidate_buffers(MKDEV(MAJOR_NR, i));
+		destroy_buffers(MKDEV(MAJOR_NR, i));
 
 	unregister_blkdev( MAJOR_NR, "ramdisk" );
 	blk_dev[MAJOR_NR].request_fn = 0;
@@ -564,10 +571,12 @@
 		}
 		infile.f_op->read(&infile, buf, BLOCK_SIZE, &infile.f_pos);
 		outfile.f_op->write(&outfile, buf, BLOCK_SIZE, &outfile.f_pos);
+#ifndef CONFIG_ARCH_S390
 		if (!(i % 16)) {
 			printk("%c\b", rotator[rotate & 0x3]);
 			rotate++;
 		}
+#endif
 	}
 	printk("done.\n");
 	kfree(buf);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/cdrom/cdrom.c linux.14p16/drivers/cdrom/cdrom.c
--- linux.vanilla/drivers/cdrom/cdrom.c	Wed Oct 20 01:12:34 1999
+++ linux.14p16/drivers/cdrom/cdrom.c	Thu Dec  9 15:34:06 1999
@@ -842,12 +842,13 @@
 
 	case CDROM_LOCKDOOR: {
 		cdinfo(CD_DO_IOCTL, "%socking door.\n",arg?"L":"Unl");
-		if (!CDROM_CAN(CDC_LOCK)) {
+		if (!CDROM_CAN(CDC_LOCK))
 			return -EDRIVE_CANT_DO_THIS;
-		} else {
-			keeplocked = arg ? 1 : 0;
-			return cdo->lock_door(cdi, arg);
-		}
+		keeplocked = arg ? 1 : 0;
+		/* don't unlock the door on multiple opens */
+		if ((cdi->use_count != 1) && !arg)
+			return -EBUSY;
+		return cdo->lock_door(cdi, arg);
 		}
 
 	case CDROM_DEBUG: {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/Config.in linux.14p16/drivers/char/Config.in
--- linux.vanilla/drivers/char/Config.in	Wed Oct 20 01:12:34 1999
+++ linux.14p16/drivers/char/Config.in	Tue Dec 21 00:31:11 1999
@@ -74,6 +74,8 @@
 	endmenu
 fi
 
+source drivers/char/joystick/Config.in
+
 tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE
 if [ "$CONFIG_QIC02_TAPE" != "n" ]; then
   bool 'Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF
@@ -101,6 +103,7 @@
   tristate '   Software Watchdog' CONFIG_SOFT_WATCHDOG
   tristate '   Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
   tristate '   Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
+  tristate '   Mixcom Watchdog' CONFIG_MIXCOMWD 
   endmenu
 fi
 
@@ -178,15 +181,6 @@
   #dep_tristate '  Include support for LML33' CONFIG_VIDEO_LML33 $CONFIG_VIDEO_ZORAN
 fi
 
-endmenu
-
-mainmenu_option next_comment
-comment 'Joystick support'
-
-tristate 'Joystick support' CONFIG_JOYSTICK
-if [ "$CONFIG_JOYSTICK" != "n" ]; then
-  source drivers/char/joystick/Config.in
-fi
 endmenu
 
 tristate 'Double Talk PC internal speech card support' CONFIG_DTLK
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/Makefile linux.14p16/drivers/char/Makefile
--- linux.vanilla/drivers/char/Makefile	Wed Oct 20 01:12:34 1999
+++ linux.14p16/drivers/char/Makefile	Wed Dec 15 22:16:50 1999
@@ -59,8 +59,10 @@
 LX_OBJS += keyboard.o
 endif
  ifneq ($(ARCH),m68k)
+  ifneq ($(ARCH),s390)
    L_OBJS += pc_keyb.o defkeymap.o
  endif
+ endif
 else
 ifdef CONFIG_PCI
 L_OBJS += defkeymap.o
@@ -270,6 +272,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_MIXCOMWD),y)
+L_OBJS += mixcomwd.o
+else
+  ifeq ($(CONFIG_MIXCOMWD),m)
+  M_OBJS += mixcomwd.o
+  endif
+endif
+
 ifeq ($(CONFIG_AMIGAMOUSE),y)
 L_OBJS += amigamouse.o
 else
@@ -343,11 +353,21 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_BT848),y)
-L_OBJS += bttv.o msp3400.o tuner.o
+L_OBJS += bttv.o tuner.o
 L_I2C=y
 else
   ifeq ($(CONFIG_VIDEO_BT848),m)
-    M_OBJS += bttv.o msp3400.o tuner.o
+    M_OBJS += bttv.o tuner.o
+    M_I2C=y
+  endif
+endif
+
+ifeq ($(CONFIG_VIDEO_MSP3400),y)
+L_OBJS += msp3400.o 
+L_I2C=y
+else
+  ifeq ($(CONFIG_VIDEO_MSP3400),m)
+    M_OBJS += msp3400.o
     M_I2C=y
   endif
 endif
@@ -380,9 +400,11 @@
 
 ifeq ($(CONFIG_VIDEO_ZORAN),y)
 L_OBJS += buz.o
+L_I2C=y
 else
   ifeq ($(CONFIG_VIDEO_ZORAN),m)
     M_OBJS += buz.o
+    M_I2C=y
   endif
 endif
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/acquirewdt.c linux.14p16/drivers/char/acquirewdt.c
--- linux.vanilla/drivers/char/acquirewdt.c	Sat Aug 14 02:26:47 1999
+++ linux.14p16/drivers/char/acquirewdt.c	Wed Dec 15 16:35:21 1999
@@ -219,7 +219,7 @@
 	misc_register(&acq_miscdev);
 	request_region(WDT_STOP, 1, "Acquire WDT");
 	request_region(WDT_START, 1, "Acquire WDT");
-	unregister_reboot_notifier(&acq_notifier);
+	register_reboot_notifier(&acq_notifier);
 	return 0;
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/bttv.c linux.14p16/drivers/char/bttv.c
--- linux.vanilla/drivers/char/bttv.c	Wed Oct 20 01:12:35 1999
+++ linux.14p16/drivers/char/bttv.c	Thu Dec  9 15:33:44 1999
@@ -403,7 +403,7 @@
 	}
 }
 
-void attach_inform(struct i2c_bus *bus, int id)
+static void attach_inform(struct i2c_bus *bus, int id)
 {
         struct bttv *btv = (struct bttv*)bus->data;
         
@@ -422,7 +422,7 @@
 	}
 }
 
-void detach_inform(struct i2c_bus *bus, int id)
+static void detach_inform(struct i2c_bus *bus, int id)
 {
         struct bttv *btv = (struct bttv*)bus->data;
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/busmouse.c linux.14p16/drivers/char/busmouse.c
--- linux.vanilla/drivers/char/busmouse.c	Wed Dec 16 21:38:18 1998
+++ linux.14p16/drivers/char/busmouse.c	Thu Dec  9 15:33:42 1999
@@ -210,7 +210,8 @@
 	buttons = mouse.buttons;
 	mouse.dx -= dx;
 	mouse.dy -= dy;
-	mouse.ready = 0;
+	if(mouse.dx==0 && mouse.dy==0)
+		mouse.ready = 0;
 	enable_irq(mouse_irq);
 	/* restore_flags(flags); */
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/buz.c linux.14p16/drivers/char/buz.c
--- linux.vanilla/drivers/char/buz.c	Wed Oct 20 01:12:35 1999
+++ linux.14p16/drivers/char/buz.c	Thu Dec  9 15:33:48 1999
@@ -374,13 +374,13 @@
 	return (btread(ZR36057_I2CBR) >> 1) & 1;
 }
 
-void attach_inform(struct i2c_bus *bus, int id)
+static void attach_inform(struct i2c_bus *bus, int id)
 {
 	DEBUG(struct zoran *zr = (struct zoran *) bus->data);
 	DEBUG(printk(BUZ_DEBUG "-%u: i2c attach %02x\n", zr->id, id));
 }
 
-void detach_inform(struct i2c_bus *bus, int id)
+static void detach_inform(struct i2c_bus *bus, int id)
 {
 	DEBUG(struct zoran *zr = (struct zoran *) bus->data);
 	DEBUG(printk(BUZ_DEBUG "-%u: i2c detach %02x\n", zr->id, id));
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/console.c linux.14p16/drivers/char/console.c
--- linux.vanilla/drivers/char/console.c	Wed Oct 20 01:12:35 1999
+++ linux.14p16/drivers/char/console.c	Thu Dec  9 15:33:42 1999
@@ -2820,6 +2820,7 @@
 EXPORT_SYMBOL(video_font_height);
 EXPORT_SYMBOL(video_scan_lines);
 EXPORT_SYMBOL(vc_resize);
+EXPORT_SYMBOL(fg_console);
 
 #ifndef VT_SINGLE_DRIVER
 EXPORT_SYMBOL(take_over_console);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/hfmodem/refclock.c linux.14p16/drivers/char/hfmodem/refclock.c
--- linux.vanilla/drivers/char/hfmodem/refclock.c	Sat Jul 18 19:47:49 1998
+++ linux.14p16/drivers/char/hfmodem/refclock.c	Thu Dec  9 15:33:46 1999
@@ -127,14 +127,13 @@
 
 #ifdef __i386__
 	if (rdtsc_ok) {
-		unsigned int tmp0, tmp1;
-		unsigned int tmp2, tmp3;
+		unsigned int tmp0, tmp1, tmp2, tmp3, tmp4;
 		
 		__asm__("rdtsc;\n\t"
 			"subl %2,%%eax\n\t"
 			"sbbl %3,%%edx\n\t" : "=&a" (tmp0), "=&d" (tmp1) 
-			: "m" (dev->clk.starttime_lo), "m" (dev->clk.starttime_hi) : "ax", "dx");
-		__asm__("mull %1" : "=d" (tmp2) : "m" (scale_rdtsc), "a" (tmp0) : "ax");
+			: "m" (dev->clk.starttime_lo), "m" (dev->clk.starttime_hi));
+		__asm__("mull %2" : "=d" (tmp2), "=a" (tmp4) : "m" (scale_rdtsc), "1" (tmp0) : "ax");
 		__asm__("mull %1" : "=a" (tmp3) : "m" (scale_rdtsc), "a" (tmp1) : "dx");
 		curtime = tmp2 + tmp3;
 		goto time_known;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/i2c.c linux.14p16/drivers/char/i2c.c
--- linux.vanilla/drivers/char/i2c.c	Sat Aug 28 20:00:55 1999
+++ linux.14p16/drivers/char/i2c.c	Thu Dec  9 15:33:44 1999
@@ -56,6 +56,8 @@
 	/* anything to do here ? */
 #ifdef CONFIG_VIDEO_BT848
 	i2c_tuner_init();
+#endif	
+#ifdef CONFIG_VIDEO_MSP3400
 	msp3400c_init();
 #endif	
 #ifdef CONFIG_VIDEO_BUZ
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/Config.in linux.14p16/drivers/char/joystick/Config.in
--- linux.vanilla/drivers/char/joystick/Config.in	Wed Dec 16 21:38:18 1998
+++ linux.14p16/drivers/char/joystick/Config.in	Tue Dec 21 00:31:11 1999
@@ -1,19 +1,34 @@
 #
-# Joystick lowlevel driver configuration
+# Joystick driver
 #
 
-dep_tristate '   Classic PC analog joysticks and gamepads' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK
-dep_tristate '   FPGaming and MadCatz A3D controllers' CONFIG_JOY_ASSASIN $CONFIG_JOYSTICK
-dep_tristate '   Gravis GrIP joysticks and gamepads' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK
-dep_tristate '   Logitech Digital joysticks and gamepads' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK
-dep_tristate '   Microsoft SideWinder, Genius Digital joysticks and gamepads' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK
-dep_tristate '   ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK
-dep_tristate '   PDPI Lightning 4 gamecards' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK
-if [ "$CONFIG_PARPORT" != "n" ]; then
-  dep_tristate '   NES, SNES, PSX, Multisystem joysticks and gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK $CONFIG_PARPORT
-  dep_tristate '   Sega, Multisystem joysticks and gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT
-  dep_tristate '   TurboGraFX Multisystem joystick interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT
-fi  
-if [ "$CONFIG_AMIGA" = "y" ]; then
-  dep_tristate '   Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK
+mainmenu_option next_comment
+comment 'Joysticks'
+
+tristate 'Joystick support' CONFIG_JOYSTICK
+
+if [ "$CONFIG_JOYSTICK" != "n" ]; then
+   dep_tristate '  Classic PC analog' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK
+   dep_tristate '  FPGaming and MadCatz A3D' CONFIG_JOY_ASSASSIN $CONFIG_JOYSTICK
+   dep_tristate '  Gravis GrIP' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK
+   dep_tristate '  Logitech ADI' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK
+   dep_tristate '  Microsoft SideWinder' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK
+   dep_tristate '  ThrustMaster DirectConnect' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK
+   dep_tristate '  Creative Labs Blaster' CONFIG_JOY_CREATIVE $CONFIG_JOYSTICK
+   dep_tristate '  PDPI Lightning 4 card' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK
+   dep_tristate '  Trident 4DWave and Aureal Vortex gameport' CONFIG_JOY_PCI $CONFIG_JOYSTICK
+   dep_tristate '  Magellan and Space Mouse' CONFIG_JOY_MAGELLAN $CONFIG_JOYSTICK
+   dep_tristate '  SpaceTec SpaceOrb 360 and SpaceBall Avenger' CONFIG_JOY_SPACEORB $CONFIG_JOYSTICK
+   dep_tristate '  SpaceTec SpaceBall 4000 FLX' CONFIG_JOY_SPACEBALL $CONFIG_JOYSTICK
+   dep_tristate '  Logitech WingMan Warrior' CONFIG_JOY_WARRIOR $CONFIG_JOYSTICK
+   if [ "$CONFIG_PARPORT" != "n" ]; then
+      dep_tristate '  NES, SNES, PSX, N64, Multi' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK $CONFIG_PARPORT
+      dep_tristate '  Sega, Multi' CONFIG_JOY_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT
+      dep_tristate '  TurboGraFX interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT
+   fi  
+   if [ "$CONFIG_AMIGA" = "y" ]; then
+      dep_tristate '  Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK
+   fi
 fi
+
+endmenu
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/Makefile linux.14p16/drivers/char/joystick/Makefile
--- linux.vanilla/drivers/char/joystick/Makefile	Fri Oct  9 01:25:16 1998
+++ linux.14p16/drivers/char/joystick/Makefile	Tue Dec 21 00:31:11 1999
@@ -1,23 +1,18 @@
 #
 # Makefile for the joystick drivers.
 #
-# 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 definitions are now inherited from the
-# parent makes..
-#
 
 O_TARGET := js.o
+OX_OBJS  :=
 O_OBJS   :=
+MX_OBJS  :=
 M_OBJS   :=
 
 ifeq ($(CONFIG_JOYSTICK),y)
-O_OBJS += joystick.o
+OX_OBJS += joystick.o
 else
   ifeq ($(CONFIG_JOYSTICK),m)
-  M_OBJS += joystick.o
+  MX_OBJS += joystick.o
   endif
 endif
 
@@ -37,11 +32,11 @@
   endif
 endif
 
-ifeq ($(CONFIG_JOY_ASSASIN),y)
-O_OBJS += joy-assasin.o
+ifeq ($(CONFIG_JOY_ASSASSIN),y)
+O_OBJS += joy-assassin.o
 else
-  ifeq ($(CONFIG_JOY_ASSASIN),m)
-  M_OBJS += joy-assasin.o
+  ifeq ($(CONFIG_JOY_ASSASSIN),m)
+  M_OBJS += joy-assassin.o
   endif
 endif
 
@@ -53,6 +48,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_JOY_CREATIVE),y)
+O_OBJS += joy-creative.o
+else
+  ifeq ($(CONFIG_JOY_CREATIVE),m)
+  M_OBJS += joy-creative.o
+  endif
+endif
+
 ifeq ($(CONFIG_JOY_DB9),y)
 O_OBJS += joy-db9.o
 else
@@ -85,6 +88,22 @@
   endif
 endif
 
+ifeq ($(CONFIG_JOY_MAGELLAN),y)
+O_OBJS += joy-magellan.o
+else
+  ifeq ($(CONFIG_JOY_MAGELLAN),m)
+  M_OBJS += joy-magellan.o
+  endif
+endif
+
+ifeq ($(CONFIG_JOY_PCI),y)
+O_OBJS += joy-pci.o
+else
+  ifeq ($(CONFIG_JOY_PCI),m)
+  M_OBJS += joy-pci.o
+  endif
+endif
+
 ifeq ($(CONFIG_JOY_SIDEWINDER),y)
 O_OBJS += joy-sidewinder.o
 else
@@ -93,6 +112,22 @@
   endif
 endif
 
+ifeq ($(CONFIG_JOY_SPACEORB),y)
+O_OBJS += joy-spaceorb.o
+else
+  ifeq ($(CONFIG_JOY_SPACEORB),m)
+  M_OBJS += joy-spaceorb.o
+  endif
+endif
+
+ifeq ($(CONFIG_JOY_SPACEBALL),y)
+O_OBJS += joy-spaceball.o
+else
+  ifeq ($(CONFIG_JOY_SPACEBALL),m)
+  M_OBJS += joy-spaceball.o
+  endif
+endif
+
 ifeq ($(CONFIG_JOY_THRUSTMASTER),y)
 O_OBJS += joy-thrustmaster.o
 else 
@@ -106,6 +141,14 @@
 else 
   ifeq ($(CONFIG_JOY_TURBOGRAFX),m)
   M_OBJS += joy-turbografx.o
+  endif
+endif
+
+ifeq ($(CONFIG_JOY_WARRIOR),y)
+O_OBJS += joy-warrior.o
+else
+  ifeq ($(CONFIG_JOY_WARRIOR),m)
+  M_OBJS += joy-warrior.o
   endif
 endif
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-amiga.c linux.14p16/drivers/char/joystick/joy-amiga.c
--- linux.vanilla/drivers/char/joystick/joy-amiga.c	Wed Dec  2 03:05:05 1998
+++ linux.14p16/drivers/char/joystick/joy-amiga.c	Tue Dec 21 00:31:11 1999
@@ -1,7 +1,9 @@
 /*
  *  joy-amiga.c  Version 1.2
  *
- *  Copyright (c) 1998 Vojtech Pavlik
+ *  Copyright (c) 1998-1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
  */
 
 /*
@@ -25,7 +27,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  */
 
@@ -36,13 +38,14 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <asm/amigahw.h>
+#include <linux/init.h>
 
 static struct js_port* js_am_port __initdata = NULL;
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_PARM(js_am, "1-2i");
 
-static int js_am[]={0,0};
+static int __initdata js_am[] = { 0, 0 };
 
 /*
  * js_am_read() reads and Amiga joystick data.
@@ -69,7 +72,7 @@
 
 	axes[0][0] = ((data >> 1) & 1) - ((data >> 9) & 1);
 	data = ~(data ^ (data << 1));
-	axes[0][0] = ((data >> 1) & 1) - ((data >> 9) & 1);
+	axes[0][1] = ((data >> 1) & 1) - ((data >> 9) & 1);
 
 	return 0;
 }
@@ -114,11 +117,14 @@
 }
 
 #ifndef MODULE
-void __init js_am_setup(char *str, int *ints)
+int __init js_am_setup(SETUP_PARAM)
 {
 	int i;
+	SETUP_PARSE(2);
 	for (i = 0; i <= ints[0] && i < 2; i++) js_am[i] = ints[i+1];
+	return 1;
 }
+__setup("js_am=", js_am_setup);
 #endif
 
 #ifdef MODULE
@@ -148,8 +154,8 @@
 #ifdef MODULE
 void cleanup_module(void)
 {
-	while (js_am_port != NULL) {
-		if (js_am_port->devs[0] != NULL)
+	while (js_am_port) {
+		if (js_am_port->devs[0])
 			js_unregister_device(js_am_port->devs[0]);
 		js_am_port = js_unregister_port(js_am_port);
 	}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-analog.c linux.14p16/drivers/char/joystick/joy-analog.c
--- linux.vanilla/drivers/char/joystick/joy-analog.c	Wed Dec  2 03:05:05 1998
+++ linux.14p16/drivers/char/joystick/joy-analog.c	Tue Dec 21 00:31:11 1999
@@ -1,7 +1,9 @@
 /*
  *  joy-analog.c  Version 1.2
  *
- *  Copyright (c) 1996-1998 Vojtech Pavlik
+ *  Copyright (c) 1996-1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
  */
 
 /*
@@ -25,74 +27,129 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  */
 
 #include <asm/io.h>
+#include <asm/param.h>
+#include <asm/system.h>
+#include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/joystick.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/sched.h>
 #include <linux/string.h>
+#include <linux/init.h>
 
-#define JS_AN_MAX_TIME 3000
+#define JS_AN_MAX_TIME		3000	/* 3 ms */
+#define JS_AN_LOOP_TIME		2000	/* 2 t */
 
 static int js_an_port_list[] __initdata = {0x201, 0};
 static struct js_port* js_an_port __initdata = NULL;
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_PARM(js_an, "2-24i");
 
-static int js_an[]={-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0};
+static int __initdata js_an[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 };
 
 #include "joy-analog.h"
 
+struct js_ax_info {
+        int io;
+	int speed;
+	int loop;
+	int timeout;
+        struct js_an_info an;
+};
+
+/*
+ * Time macros.
+ */
+
+#ifdef __i386__
+#ifdef CONFIG_X86_TSC
+#define GET_TIME(x)	__asm__ __volatile__ ( "rdtsc" : "=a" (x) : : "dx" )
+#define DELTA(x,y)	((x)-(y))
+#define TIME_NAME "TSC"
+#else
+#define GET_TIME(x)	do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
+#define DELTA(x,y)	((y)-(x)+((y)<(x)?1193180L/HZ:0))
+#define TIME_NAME "PIT"
+#endif
+#elif __alpha__
+#define GET_TIME(x)	__asm__ __volatile__ ( "rpcc %0" : "=r" (x) )
+#define DELTA(x,y)	((x)-(y))
+#define TIME_NAME "PCC"
+#endif
+
+#ifndef GET_TIME
+#define FAKE_TIME
+static unsigned long js_an_faketime = 0;
+#define GET_TIME(x)     do { x = js_an_faketime++; } while(0)
+#define DELTA(x,y)	((x)-(y))
+#define TIME_NAME "Unreliable"
+#endif
+
 /*
  * js_an_read() reads analog joystick data.
  */
 
 static int js_an_read(void *xinfo, int **axes, int **buttons)
 {
-	struct js_an_info *info = xinfo;
+	struct js_ax_info *info = xinfo;
+	struct js_an_info *an = &info->an;
+	int io = info->io;
+	unsigned long flags;
 	unsigned char buf[4];
-	int time[4];
-	unsigned char u, v, a;
-	unsigned int t, t1;
+	unsigned int time[4];
+	unsigned char u, v, w;
+	unsigned int p, q, r, s, t;
 	int i, j;
-	int timeout;
-	int io = info->io;
 
-	timeout = (JS_AN_MAX_TIME * js_time_speed_a) >> 10;
-
-	info->buttons = (~inb(io) & JS_AN_BUTTONS_STD) >> 4;
+	an->buttons = ~inb(io) >> 4;
 
 	i = 0;
-	u = a = ((info->mask[0] | info->mask[1]) & JS_AN_AXES_STD) | (info->extensions & JS_AN_HAT_FCS)
-	      | ((info->extensions & JS_AN_BUTTONS_PXY_XY) >> 2) | ((info->extensions & JS_AN_BUTTONS_PXY_UV) >> 4);
-
+	w = ((an->mask[0] | an->mask[1]) & JS_AN_AXES_STD) | (an->extensions & JS_AN_HAT_FCS)
+	  | ((an->extensions & JS_AN_BUTTONS_PXY_XY) >> 2) | ((an->extensions & JS_AN_BUTTONS_PXY_UV) >> 4);
+	p = info->loop;
+	q = info->timeout;
+	
+	__save_flags(flags);
+	__cli();
 	outb(0xff,io);
-	t = js_get_time_a();
+	GET_TIME(r);
+	__restore_flags(flags);
+	t = r;
+	v = w;
 	do {
-		v = inb(io) & a;
-		t1 = js_get_time_a();
-		if (u ^ v) {
-			time[i] = js_delta_a(t1,t);
+		s = t;
+		u = v;
+		__cli();
+		v = inb(io) & w;
+		GET_TIME(t);
+		__restore_flags(flags);
+		if ((u ^ v) && (DELTA(t,s) < p)) {
+			time[i] = t;
 			buf[i] = u ^ v;
-			u = v;
 			i++;
 		}
-	} while (v && js_delta_a(t1,t) < timeout);
+	} while (v && (i < 4) && (DELTA(t,r) < q));
 
-	for (--i; i >= 0; i--)
+	v <<= 4;
+
+	for (--i; i >= 0; i--) {
+		v |= buf[i];
 		for (j = 0; j < 4; j++)
-			if (buf[i] & (1 << j)) info->axes[j] = (time[i] << 10) / js_time_speed_a;
+			if (buf[i] & (1 << j)) an->axes[j] = (DELTA(time[i],r) << 10) / info->speed;
+	}
 
-	js_an_decode(info, axes, buttons);
+	js_an_decode(an, axes, buttons);
 
-	return 0;
+	return -(v != w);
 }
 
 /*
@@ -116,12 +173,53 @@
 }
 
 /*
+ * js_an_calibrate_timer() calibrates the timer and computes loop
+ * and timeout values for a joystick port.
+ */
+
+static void __init js_an_calibrate_timer(struct js_ax_info *info)
+{
+	unsigned int i, t, tx, t1, t2, t3;
+	unsigned long flags;
+	int io = info->io;
+
+	save_flags(flags);
+	cli();
+	GET_TIME(t1);
+#ifdef FAKE_TIME
+	js_an_faketime += 830;
+#endif
+	udelay(1000);
+	GET_TIME(t2);
+	GET_TIME(t3);
+	restore_flags(flags);
+
+	info->speed = DELTA(t2, t1) - DELTA(t3, t2);
+
+	tx = 1 << 30;
+
+	for(i = 0; i < 50; i++) {
+		save_flags(flags);
+		cli();
+		GET_TIME(t1);
+		for(t = 0; t < 50; t++) { inb(io); GET_TIME(t2); }
+		GET_TIME(t3);
+		restore_flags(flags);
+		udelay(i);
+		if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
+	}
+
+        info->loop = (JS_AN_LOOP_TIME * t) / 50000;
+	info->timeout = (JS_AN_MAX_TIME * info->speed) / 1000;
+}
+
+/*
  * js_an_probe() probes for analog joysticks.
  */
 
 static struct js_port __init *js_an_probe(int io, int mask0, int mask1, struct js_port *port)
 {
-	struct js_an_info info;
+	struct js_ax_info info, *ax;
 	int i, numdev;
 	unsigned char u;
 
@@ -129,7 +227,6 @@
 
 	if (check_region(io, 1)) return port;
 
-	if (((u = inb(io)) & 3) == 3) return port;
 	outb(0xff,io);
 	u = inb(io);
 	udelay(JS_AN_MAX_TIME);
@@ -138,31 +235,41 @@
 	if (!u) return port;
 	if (u & 0xf0) return port;
 
-	if ((numdev = js_an_probe_devs(&info, u, mask0, mask1, port)) <= 0)
+	if ((numdev = js_an_probe_devs(&info.an, u, mask0, mask1, port)) <= 0)
 		return port;
 
 	info.io = io;
+	js_an_calibrate_timer(&info);
+
 	request_region(info.io, 1, "joystick (analog)");
-	port = js_register_port(port, &info, numdev, sizeof(struct js_an_info), js_an_read);
+	port = js_register_port(port, &info, numdev, sizeof(struct js_ax_info), js_an_read);
+	ax = port->info;	
 
 	for (i = 0; i < numdev; i++)
-		printk(KERN_INFO "js%d: %s at %#x\n",
-			js_register_device(port, i, js_an_axes(i, &info), js_an_buttons(i, &info),
-				js_an_name(i, &info), js_an_open, js_an_close),
-			js_an_name(i, &info), info.io);
+		printk(KERN_INFO "js%d: %s at %#x ["TIME_NAME" timer, %d %sHz clock, %d ns res]\n",
+			js_register_device(port, i, js_an_axes(i, &ax->an), js_an_buttons(i, &ax->an),
+				js_an_name(i, &ax->an), js_an_open, js_an_close),
+			js_an_name(i, &ax->an),
+			ax->io,
+			ax->speed > 10000 ? (ax->speed + 800) / 1000 : ax->speed,
+			ax->speed > 10000 ? "M" : "k",
+			ax->loop * 1000000000 / JS_AN_LOOP_TIME / ax->speed);
 
-	js_an_read(port->info, port->axes, port->buttons);
-	js_an_init_corr(port->info, port->axes, port->corr, 8);
+	js_an_read(ax, port->axes, port->buttons);
+	js_an_init_corr(&ax->an, port->axes, port->corr, 8);
 
 	return port;
 }
 
 #ifndef MODULE
-void __init js_an_setup(char *str, int *ints)
+int __init js_an_setup(SETUP_PARAM)
 {
 	int i;
+	SETUP_PARSE(24);
 	for (i = 0; i <= ints[0] && i < 24; i++) js_an[i] = ints[i+1];
+	return 1;
 }
+__setup("js_an=", js_an_setup);
 #endif
 
 #ifdef MODULE
@@ -193,11 +300,11 @@
 void cleanup_module(void)
 {
 	int i;
-	struct js_an_info *info;
+	struct js_ax_info *info;
 
-	while (js_an_port != NULL) {
+	while (js_an_port) {
 		for (i = 0; i < js_an_port->ndevs; i++)
-			if (js_an_port->devs[i] != NULL)
+			if (js_an_port->devs[i])
 				js_unregister_device(js_an_port->devs[i]);
 		info = js_an_port->info;
 		release_region(info->io, 1);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-analog.h linux.14p16/drivers/char/joystick/joy-analog.h
--- linux.vanilla/drivers/char/joystick/joy-analog.h	Fri Oct  9 01:25:16 1998
+++ linux.14p16/drivers/char/joystick/joy-analog.h	Tue Dec 21 00:31:11 1999
@@ -1,13 +1,15 @@
 /*
  *  joy-analog.h  Version 1.2
  *
- *  Copyright (c) 1996-1998 Vojtech Pavlik
+ *  Copyright (c) 1996-1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
  */
 
 /*
  * This file is designed to be included in any joystick driver
  * that communicates with standard analog joysticks. This currently
- * is: joy-analog.c, joy-assasin.c, and joy-lightning.c
+ * is: joy-analog.c, joy-assassin.c, and joy-lightning.c
  */
 
 /*
@@ -26,10 +28,12 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  */
 
+#include <linux/bitops.h>
+
 #define JS_AN_AXES_STD		0x0f
 #define JS_AN_BUTTONS_STD	0xf0
 
@@ -53,7 +57,6 @@
 } js_an_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1, 0}, { 0, 1}, {-1, 0}};
 
 struct js_an_info {
-	int io;
 	unsigned char mask[2];
 	unsigned int extensions;
 	int axes[4];
@@ -75,7 +78,7 @@
 	if (info->mask[1] & JS_AN_BUTTONS_STD) buttons[1][0] = 0;
 
 	if (info->extensions & JS_AN_ANY_CHF) {
-		switch (info->buttons) {
+		switch (info->buttons & 0xf) {
 			case 0x1: buttons[0][0] = 0x01; break;
 			case 0x2: buttons[0][0] = 0x02; break;
 			case 0x4: buttons[0][0] = 0x04; break;
@@ -134,19 +137,6 @@
 	}
 }
 
-/*
- * js_an_count_bits() counts set bits in a byte.
- */
-
-static inline int js_an_count_bits(unsigned long c)
-{
-	int i = 0;
-	while (c) {
-		i += c & 1;
-		c >>= 1;
-	}
-	return i;
-}
 
 /*
  * js_an_init_corr() initializes the correction values for
@@ -158,7 +148,7 @@
 	int i, j, t;
 
 	for (i = 0; i < 2; i++)
-	for (j = 0; j < js_an_count_bits(info->mask[i] & 0xf); j++) {
+	for (j = 0; j < hweight8(info->mask[i] & 0xf); j++) {
 
 		if ((j == 2 && (info->mask[i] & 0xb) == 0xb) ||
 		    (j == 3 && (info->mask[i] & 0xf) == 0xf)) {
@@ -175,9 +165,9 @@
 		corr[i][j].coef[3] = (1 << 29) / (t - (t >> 2) + 1);
 	}
 
-	i = js_an_count_bits(info->mask[0] & 0xf);
+	i = hweight8(info->mask[0] & 0xf);
 
-	for (j = i; j < i + (js_an_count_bits(info->extensions & JS_AN_HATS_ALL) << 1); j++) {
+	for (j = i; j < i + (hweight8(info->extensions & JS_AN_HATS_ALL) << 1); j++) {
 		corr[0][j].type = JS_CORR_BROKEN;
 		corr[0][j].prec = 0;
 		corr[0][j].coef[0] = 0;
@@ -204,6 +194,7 @@
 		info->mask[1] = mask1 & (exist | 0xf0) & ~info->mask[0];
 		info->extensions = (mask0 >> 8) & ((exist & JS_AN_HAT_FCS) | ((exist << 2) & JS_AN_BUTTONS_PXY_XY) |
 					((exist << 4) & JS_AN_BUTTONS_PXY_UV) | JS_AN_ANY_CHF);
+
 		if (info->extensions & JS_AN_BUTTONS_PXY) {
 			info->mask[0] &= ~((info->extensions & JS_AN_BUTTONS_PXY_XY) >> 2);
 			info->mask[0] &= ~((info->extensions & JS_AN_BUTTONS_PXY_UV) >> 4);
@@ -212,7 +203,7 @@
 		if (info->extensions & JS_AN_HAT_FCS) {
 			info->mask[0] &= ~JS_AN_HAT_FCS;
 			info->mask[1] = 0;
-			info->extensions &= ~(JS_AN_BUTTON_PXY_Y | JS_AN_BUTTON_PXY_U);
+			info->extensions &= ~(JS_AN_BUTTON_PXY_Y | JS_AN_BUTTON_PXY_V);
 		}
 		if (info->extensions & JS_AN_ANY_CHF) {
 			info->mask[0] |= 0xf0;
@@ -233,12 +224,11 @@
 				info->mask[0] = 0xcc; /* joystick 1 */
 				break;
 			case 0xf:
-				info->mask[0] = 0x33; /* joysticks 0 and 1 */
-				info->mask[1] = 0xcc;
+				info->mask[0] = 0xff; /* 4-axis 4-button joystick */
 				break;
 			default:
 				printk(KERN_WARNING "joy-analog: Unknown joystick device detected "
-					"(data=%#x), contact <vojtech@ucw.cz>\n", exist);
+					"(data=%#x), contact <vojtech@suse.cz>\n", exist);
 				return -1;
 		}
 	}
@@ -252,7 +242,7 @@
 
 static inline int js_an_axes(int i, struct js_an_info *info)
 {
-	return js_an_count_bits(info->mask[i] & 0x0f) + js_an_count_bits(info->extensions & JS_AN_HATS_ALL) * 2;
+	return hweight8(info->mask[i] & 0x0f) + hweight8(info->extensions & JS_AN_HATS_ALL) * 2;
 }
 
 /*
@@ -261,9 +251,9 @@
 
 static inline int js_an_buttons(int i, struct js_an_info *info)
 {
-	return js_an_count_bits(info->mask[i] & 0xf0) +
+	return hweight8(info->mask[i] & 0xf0) +
 	       (info->extensions & JS_AN_BUTTONS_CHF) * 2 +
-	       js_an_count_bits(info->extensions & JS_AN_BUTTONS_PXY);
+	       hweight8(info->extensions & JS_AN_BUTTONS_PXY);
 }
 
 /*
@@ -276,13 +266,13 @@
 {
 
 	sprintf(js_an_name_buf, "Analog %d-axis %d-button",
-		js_an_count_bits(info->mask[i] & 0x0f),
+		hweight8(info->mask[i] & 0x0f),
 		js_an_buttons(i, info));
 
 	if (info->extensions & JS_AN_HATS_ALL)
 		sprintf(js_an_name_buf, "%s %d-hat",
 			js_an_name_buf,
-			js_an_count_bits(info->extensions & JS_AN_HATS_ALL));
+			hweight8(info->extensions & JS_AN_HATS_ALL));
 
 	strcat(js_an_name_buf, " joystick");
 
@@ -291,7 +281,7 @@
 			js_an_name_buf,
 			info->extensions & JS_AN_ANY_CHF ? " CHF" : "",
 			info->extensions & JS_AN_HAT_FCS ? " FCS" : "",
-			info->extensions & JS_AN_BUTTONS_PXY ? " XY-button" : "");
+			info->extensions & JS_AN_BUTTONS_PXY ? " XY/UV" : "");
 
 	return js_an_name_buf;
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-assasin.c linux.14p16/drivers/char/joystick/joy-assasin.c
--- linux.vanilla/drivers/char/joystick/joy-assasin.c	Wed Dec  2 03:05:05 1998
+++ linux.14p16/drivers/char/joystick/joy-assasin.c	Thu Jan  1 01:00:00 1970
@@ -1,423 +0,0 @@
-/*
- *  joy-assasin.c  Version 1.2
- *
- *  Copyright (c) 1998 Vojtech Pavlik
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * joysticks using FP-Gaming's Assasin 3D protocol.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
- * (at your option) any later version.
- * 
- * This program is 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-
-#define JS_AS_MAX_START		250
-#define JS_AS_MAX_STROBE	50
-#define JS_AS_MAX_TIME		2400
-#define JS_AS_MAX_LENGTH	40
-
-#define JS_AS_MODE_A3D		1	/* Assasin 3D */
-#define JS_AS_MODE_PAN		2	/* Panther */
-#define JS_AS_MODE_OEM		3	/* Panther OEM version */
-#define JS_AS_MODE_PXL		4	/* Panther XL */
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_PARM(js_as, "2-24i");
-
-static int js_as[]={-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0};
-
-static int js_as_port_list[] __initdata = {0x201, 0};
-static struct js_port* js_as_port __initdata = NULL;
-
-#include "joy-analog.h"
-
-struct js_as_info {
-	int io;
-	char mode;
-	char rudder;
-	struct js_an_info an;
-};
-
-/*
- * js_as_read_packet() reads an Assasin 3D packet.
- */
-
-static int js_as_read_packet(int io, int length, char *data)
-{
-	unsigned char u, v;
-	int i;
-	unsigned int t, t1;
-	unsigned long flags;
-
-	int start = (js_time_speed * JS_AS_MAX_START) >> 10;
-	int strobe = (js_time_speed * JS_AS_MAX_STROBE) >> 10;
-
-	i = 0;
-
-	__save_flags(flags);
-	__cli();
-	outb(0xff,io);
-
-	u = inb(io);
-	t = js_get_time();
-
-	do {
-		v = inb(io);
-		t1 = js_get_time();
-	} while (u == v && js_delta(t1, t) < start);
-
-	t = t1;
-
-	do {
-		v = inb(io);
-		t1 = js_get_time();
-		if ((u ^ v) & u & 0x10) {
-			data[i++] = v >> 5;
-			t = t1;
-		}
-		u = v;
-	} while (i < length && js_delta(t1,t) < strobe);
-
-	__restore_flags(flags);
-
-	return i;
-}
-
-/*
- * js_as_csum() computes checksum of triplet packet
- */
-
-static int js_as_csum(char *data, int count)
-{
-	int i, csum = 0;
-	for (i = 0; i < count - 2; i++) csum += data[i];
-	return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]);
-}
-
-/*
- * js_as_read() reads and analyzes A3D joystick data.
- */
-
-static int js_as_read(void *xinfo, int **axes, int **buttons)
-{
-	struct js_as_info *info = xinfo;
-	char data[JS_AS_MAX_LENGTH];
-
-	switch (info->mode) {
-
-		case JS_AS_MODE_A3D:
-		case JS_AS_MODE_OEM:
-		case JS_AS_MODE_PAN:
-
-			if (js_as_read_packet(info->io, 29, data) != 29) return -1;
-			if (data[0] != info->mode) return -1;
-			if (js_as_csum(data, 29)) return -1;
-
-			axes[0][0] = ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7);
-			axes[0][1] = ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7);
-
-			buttons[0][0] = (data[2] << 2) | (data[3] >> 1);
-
-			info->an.axes[0] = ((char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128;
-			info->an.axes[1] = ((char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128;
-			info->an.axes[2] = ((char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128;
-			info->an.axes[3] = ((char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128;
-
-			info->an.buttons = ((data[3] << 3) | data[4]) & 0xf;
-
-			js_an_decode(&info->an, axes + 1, buttons + 1);
-
-			return 0;
-
-		case JS_AS_MODE_PXL:
-
-			if (js_as_read_packet(info->io, 33, data) != 33) return -1;
-			if (data[0] != info->mode) return -1;
-			if (js_as_csum(data, 33)) return -1;
-
-			axes[0][0] = ((char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128;
-			axes[0][1] = ((char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128;
-			info->an.axes[0] = ((char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128;
-			axes[0][2] = ((char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128;
-
-			axes[0][3] = ( data[5]       & 1) - ((data[5] >> 2) & 1);
-			axes[0][4] = ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1);
-			axes[0][5] = ((data[4] >> 1) & 1) - ( data[3]       & 1);
-			axes[0][6] = ((data[4] >> 2) & 1) - ( data[4]       & 1);
-
-			axes[0][7] = ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7);
-			axes[0][8] = ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7);
-
-			buttons[0][0] = (data[2] << 8) | ((data[3] & 6) << 5) | (data[7] << 3) | data[8];
-
-			if (info->rudder) axes[1][0] = info->an.axes[0];
-
-			return 0;
-
-		default:
-			printk("Error.\n");
-			return -1;
-	}
-}
-
-/*
- * js_as_open() is a callback from the file open routine.
- */
-
-static int js_as_open(struct js_dev *jd)
-{
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-
-/*
- * js_as_close() is a callback from the file release routine.
- */
-
-static int js_as_close(struct js_dev *jd)
-{
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-/*
- * js_as_pxl_init_corr() initializes the correction values for
- * the Panther XL.
- */
-
-static void __init js_as_pxl_init_corr(struct js_corr **corr, int **axes)
-{
-	int i;
-
-	for (i = 0; i < 2; i++) {
-		corr[0][i].type = JS_CORR_BROKEN;
-		corr[0][i].prec = 0;
-		corr[0][i].coef[0] = axes[0][i] - 4;
-		corr[0][i].coef[1] = axes[0][i] + 4;
-		corr[0][i].coef[2] = (1 << 29) / (127 - 32);
-		corr[0][i].coef[3] = (1 << 29) / (127 - 32);
-	}
-
-	corr[0][2].type = JS_CORR_BROKEN;
-	corr[0][2].prec = 0;
-	corr[0][2].coef[0] = 127 - 4;
-	corr[0][2].coef[1] = 128 + 4;
-	corr[0][2].coef[2] = (1 << 29) / (127 - 6);
-	corr[0][2].coef[3] = (1 << 29) / (127 - 6);
-
-	for (i = 3; i < 7; i++) {
-		corr[0][i].type = JS_CORR_BROKEN;
-		corr[0][i].prec = 0;
-		corr[0][i].coef[0] = 0;
-		corr[0][i].coef[1] = 0;
-		corr[0][i].coef[2] = (1 << 29);
-		corr[0][i].coef[3] = (1 << 29);
-	}
-
-	for (i = 7; i < 9; i++) {
-		corr[0][i].type = JS_CORR_BROKEN;
-		corr[0][i].prec = -1;
-		corr[0][i].coef[0] = 0;
-		corr[0][i].coef[1] = 0;
-		corr[0][i].coef[2] = (104 << 14);
-		corr[0][i].coef[3] = (104 << 14);
-	}
-}
-
-/*
- * js_as_as_init_corr() initializes the correction values for
- * the Panther and Assasin.
- */
-
-static void __init js_as_as_init_corr(struct js_corr **corr)
-{
-	int i;
-
-	for (i = 0; i < 2; i++) {
-		corr[0][i].type = JS_CORR_BROKEN;
-		corr[0][i].prec = -1;
-		corr[0][i].coef[0] = 0;
-		corr[0][i].coef[1] = 0;
-		corr[0][i].coef[2] = (104 << 14);
-		corr[0][i].coef[3] = (104 << 14);
-	}
-}
-
-/*
- * js_as_rudder_init_corr() initializes the correction values for
- * the Panther XL connected rudder.
- */
-
-static void __init js_as_rudder_init_corr(struct js_corr **corr, int **axes)
-{
-	corr[1][0].type = JS_CORR_BROKEN;
-	corr[1][0].prec = 0;
-	corr[1][0].coef[0] = axes[1][0] - (axes[1][0] >> 3);
-	corr[1][0].coef[1] = axes[1][0] + (axes[1][0] >> 3);
-	corr[1][0].coef[2] = (1 << 29) / (axes[1][0] - (axes[1][0] >> 2) + 1);
-	corr[1][0].coef[3] = (1 << 29) / (axes[1][0] - (axes[1][0] >> 2) + 1);
-}
-
-/*
- * js_as_probe() probes for A3D joysticks.
- */
-
-static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct js_port *port)
-{
-	struct js_as_info iniinfo;
-	struct js_as_info *info = &iniinfo;
-	char *name;
-	char data[JS_AS_MAX_LENGTH];
-	unsigned char u;
-	int i;
-	int numdev;
-
-	memset(info, 0, sizeof(struct js_as_info));
-
-	if (io < 0) return port;
-
-	if (check_region(io, 1)) return port;
-	if (((u = inb(io)) & 3) == 3) return port;
-	outb(0xff,io);
-	if (!((inb(io) ^ u) & ~u & 0xf)) return port;
-
-	if (js_as_read_packet(io, 1, data) != 1) return port;
-
-	if (data[0] && data[0] <= 4) {
-		info->mode = data[0];
-		info->io = io;
-		request_region(io, 1, "joystick (assasin)");
-		port = js_register_port(port, info, 3, sizeof(struct js_as_info), js_as_read);
-		info = port->info;
-	} else {
-		printk(KERN_WARNING "joy-assasin: unknown joystick device detected "
-			"(io=%#x, id=%d), contact <vojtech@ucw.cz>\n", io, data[0]);
-		return port;
-	}
-
-	udelay(JS_AS_MAX_TIME);
-
-	if (info->mode == JS_AS_MODE_PXL) {
-			printk(KERN_INFO "js%d: MadCatz Panther XL at %#x\n",
-				js_register_device(port, 0, 9, 9, "MadCatz Panther XL", js_as_open, js_as_close),
-				info->io);
-			js_as_read(port->info, port->axes, port->buttons);
-			js_as_pxl_init_corr(port->corr, port->axes);
-			if (info->an.axes[0] < 254) {
-			printk(KERN_INFO "js%d: Analog rudder on MadCatz Panther XL\n",
-				js_register_device(port, 1, 1, 0, "Analog rudder", js_as_open, js_as_close));
-				info->rudder = 1;
-				port->axes[1][0] = info->an.axes[0];
-				js_as_rudder_init_corr(port->corr, port->axes);
-			}
-			return port;
-	}
-
-	switch (info->mode) {
-		case JS_AS_MODE_A3D: name = "FP-Gaming Assasin 3D"; break;
-		case JS_AS_MODE_PAN: name = "MadCatz Panther"; break;
-		case JS_AS_MODE_OEM: name = "OEM Assasin 3D"; break;
-		default: name = "This cannot happen"; break;
-	}
-
-	printk(KERN_INFO "js%d: %s at %#x\n",
-		js_register_device(port, 0, 2, 3, name, js_as_open, js_as_close),
-		name, info->io);
-
-	js_as_as_init_corr(port->corr);
-
-	js_as_read(port->info, port->axes, port->buttons);
-
-	for (i = u = 0; i < 4; i++) if (info->an.axes[i] < 254) u |= 1 << i;
-
-	if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0)
-		return port;
-
-	for (i = 0; i < numdev; i++)
-		printk(KERN_INFO "js%d: %s on %s\n",
-			js_register_device(port, i + 1, js_an_axes(i, &info->an), js_an_buttons(i, &info->an),
-				js_an_name(i, &info->an), js_as_open, js_as_close),
-			js_an_name(i, &info->an), name);
-
-	js_an_decode(&info->an, port->axes + 1, port->buttons + 1);
-	js_an_init_corr(&info->an, port->axes + 1, port->corr + 1, 0);
-
-	return port;
-}
-
-#ifndef MODULE
-void __init js_as_setup(char *str, int *ints)
-{
-	int i;
-	for (i = 0; i <= ints[0] && i < 24; i++) js_as[i] = ints[i+1];
-}
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_as_init(void)
-#endif
-{
-	int i;
-
-	if (js_as[0] >= 0) {
-		for (i = 0; (js_as[i*3] >= 0) && i < 8; i++)
-			js_as_port = js_as_probe(js_as[i*3], js_as[i*3+1], js_as[i*3+2], js_as_port);
-	} else {
-		for (i = 0; js_as_port_list[i]; i++) js_as_port = js_as_probe(js_as_port_list[i], 0, 0, js_as_port);
-	}
-	if (js_as_port) return 0;
-
-#ifdef MODULE
-	printk(KERN_WARNING "joy-assasin: no joysticks found\n");
-#endif
-
-	return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
-	int i;
-	struct js_as_info *info;
-
-	while (js_as_port != NULL) {
-		for (i = 0; i < js_as_port->ndevs; i++)
-			if (js_as_port->devs[i] != NULL)
-				js_unregister_device(js_as_port->devs[i]);
-		info = js_as_port->info;
-		release_region(info->io, 1);
-		js_as_port = js_unregister_port(js_as_port);
-	}
-
-}
-#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-assassin.c linux.14p16/drivers/char/joystick/joy-assassin.c
--- linux.vanilla/drivers/char/joystick/joy-assassin.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/char/joystick/joy-assassin.c	Tue Dec 21 00:31:12 1999
@@ -0,0 +1,416 @@
+/*
+ *  joy-assassin.c  Version 1.2
+ *
+ *  Copyright (c) 1998-1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This is a module for the Linux joystick driver, supporting
+ * joysticks using FP-Gaming's Assassin 3D protocol.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/joystick.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#define JS_AS_MAX_START		1000
+#define JS_AS_DELAY_READ	3000
+#define JS_AS_MAX_LENGTH	40
+
+#define JS_AS_MODE_A3D		1	/* Assassin 3D */
+#define JS_AS_MODE_PAN		2	/* Panther */
+#define JS_AS_MODE_OEM		3	/* Panther OEM version */
+#define JS_AS_MODE_PXL		4	/* Panther XL */
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_PARM(js_as, "2-24i");
+
+static int __initdata js_as[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 };
+
+static int js_as_port_list[] __initdata = {0x201, 0};
+static struct js_port* js_as_port __initdata = NULL;
+
+#include "joy-analog.h"
+
+struct js_as_info {
+	int io;
+	char mode;
+	char rudder;
+	struct js_an_info an;
+};
+
+/*
+ * js_as_read_packet() reads an Assassin 3D packet.
+ */
+
+static int js_as_read_packet(int io, int length, char *data)
+{
+	unsigned char u, v;
+	int i;
+	unsigned int t, p;
+	unsigned long flags;
+
+	i = 0;
+
+	__save_flags(flags);
+	__cli();
+
+	outb(0xff,io);
+	v = inb(io);
+	t = p = JS_AS_MAX_START;
+
+	while (t > 0 && i < length) {
+		t--;
+		u = v; v = inb(io);
+		if (~v & u & 0x10) {
+			data[i++] = v >> 5;
+			p = t = (p - t) << 3;
+		}
+	}
+
+	__restore_flags(flags);
+
+	return i;
+}
+
+/*
+ * js_as_csum() computes checksum of triplet packet
+ */
+
+static int js_as_csum(char *data, int count)
+{
+	int i, csum = 0;
+	for (i = 0; i < count - 2; i++) csum += data[i];
+	return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]);
+}
+
+/*
+ * js_as_read() reads and analyzes A3D joystick data.
+ */
+
+static int js_as_read(void *xinfo, int **axes, int **buttons)
+{
+	struct js_as_info *info = xinfo;
+	char data[JS_AS_MAX_LENGTH];
+
+	switch (info->mode) {
+
+		case JS_AS_MODE_A3D:
+		case JS_AS_MODE_OEM:
+		case JS_AS_MODE_PAN:
+
+			if (js_as_read_packet(info->io, 29, data) != 29) return -1;
+			if (data[0] != info->mode) return -1;
+			if (js_as_csum(data, 29)) return -1;
+
+			axes[0][0] = ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7);
+			axes[0][1] = ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7);
+
+			buttons[0][0] = (data[2] << 2) | (data[3] >> 1);
+
+			info->an.axes[0] = ((char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128;
+			info->an.axes[1] = ((char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128;
+			info->an.axes[2] = ((char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128;
+			info->an.axes[3] = ((char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128;
+
+			info->an.buttons = ((data[3] << 3) | data[4]) & 0xf;
+
+			js_an_decode(&info->an, axes + 1, buttons + 1);
+
+			return 0;
+
+		case JS_AS_MODE_PXL:
+
+			if (js_as_read_packet(info->io, 33, data) != 33) return -1;
+			if (data[0] != info->mode) return -1;
+			if (js_as_csum(data, 33)) return -1;
+
+			axes[0][0] = ((char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128;
+			axes[0][1] = ((char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128;
+			info->an.axes[0] = ((char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128;
+			axes[0][2] = ((char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128;
+
+			axes[0][3] = ( data[5]       & 1) - ((data[5] >> 2) & 1);
+			axes[0][4] = ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1);
+			axes[0][5] = ((data[4] >> 1) & 1) - ( data[3]       & 1);
+			axes[0][6] = ((data[4] >> 2) & 1) - ( data[4]       & 1);
+
+			axes[0][7] = ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7);
+			axes[0][8] = ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7);
+
+			buttons[0][0] = (data[2] << 8) | ((data[3] & 6) << 5) | (data[7] << 3) | data[8];
+
+			if (info->rudder) axes[1][0] = info->an.axes[0];
+
+			return 0;
+	}
+	return -1;
+}
+
+/*
+ * js_as_open() is a callback from the file open routine.
+ */
+
+static int js_as_open(struct js_dev *jd)
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * js_as_close() is a callback from the file release routine.
+ */
+
+static int js_as_close(struct js_dev *jd)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * js_as_pxl_init_corr() initializes the correction values for
+ * the Panther XL.
+ */
+
+static void __init js_as_pxl_init_corr(struct js_corr **corr, int **axes)
+{
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		corr[0][i].type = JS_CORR_BROKEN;
+		corr[0][i].prec = 0;
+		corr[0][i].coef[0] = axes[0][i] - 4;
+		corr[0][i].coef[1] = axes[0][i] + 4;
+		corr[0][i].coef[2] = (1 << 29) / (127 - 32);
+		corr[0][i].coef[3] = (1 << 29) / (127 - 32);
+	}
+
+	corr[0][2].type = JS_CORR_BROKEN;
+	corr[0][2].prec = 0;
+	corr[0][2].coef[0] = 127 - 4;
+	corr[0][2].coef[1] = 128 + 4;
+	corr[0][2].coef[2] = (1 << 29) / (127 - 6);
+	corr[0][2].coef[3] = (1 << 29) / (127 - 6);
+
+	for (i = 3; i < 7; i++) {
+		corr[0][i].type = JS_CORR_BROKEN;
+		corr[0][i].prec = 0;
+		corr[0][i].coef[0] = 0;
+		corr[0][i].coef[1] = 0;
+		corr[0][i].coef[2] = (1 << 29);
+		corr[0][i].coef[3] = (1 << 29);
+	}
+
+	for (i = 7; i < 9; i++) {
+		corr[0][i].type = JS_CORR_BROKEN;
+		corr[0][i].prec = -1;
+		corr[0][i].coef[0] = 0;
+		corr[0][i].coef[1] = 0;
+		corr[0][i].coef[2] = (104 << 14);
+		corr[0][i].coef[3] = (104 << 14);
+	}
+}
+
+/*
+ * js_as_as_init_corr() initializes the correction values for
+ * the Panther and Assassin.
+ */
+
+static void __init js_as_as_init_corr(struct js_corr **corr)
+{
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		corr[0][i].type = JS_CORR_BROKEN;
+		corr[0][i].prec = -1;
+		corr[0][i].coef[0] = 0;
+		corr[0][i].coef[1] = 0;
+		corr[0][i].coef[2] = (104 << 14);
+		corr[0][i].coef[3] = (104 << 14);
+	}
+}
+
+/*
+ * js_as_rudder_init_corr() initializes the correction values for
+ * the Panther XL connected rudder.
+ */
+
+static void __init js_as_rudder_init_corr(struct js_corr **corr, int **axes)
+{
+	corr[1][0].type = JS_CORR_BROKEN;
+	corr[1][0].prec = 0;
+	corr[1][0].coef[0] = axes[1][0] - (axes[1][0] >> 3);
+	corr[1][0].coef[1] = axes[1][0] + (axes[1][0] >> 3);
+	corr[1][0].coef[2] = (1 << 29) / (axes[1][0] - (axes[1][0] >> 2) + 1);
+	corr[1][0].coef[3] = (1 << 29) / (axes[1][0] - (axes[1][0] >> 2) + 1);
+}
+
+/*
+ * js_as_probe() probes for A3D joysticks.
+ */
+
+static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct js_port *port)
+{
+	struct js_as_info iniinfo;
+	struct js_as_info *info = &iniinfo;
+	char *name;
+	char data[JS_AS_MAX_LENGTH];
+	unsigned char u;
+	int i;
+	int numdev;
+
+	memset(info, 0, sizeof(struct js_as_info));
+
+	if (io < 0) return port;
+
+	if (check_region(io, 1)) return port;
+
+	i = js_as_read_packet(io, JS_AS_MAX_LENGTH, data);
+
+	printk("%d\n", i);
+
+	if (!i) return port;
+	if (js_as_csum(data, i)) return port;
+
+	if (data[0] && data[0] <= 4) {
+		info->mode = data[0];
+		info->io = io;
+		request_region(io, 1, "joystick (assassin)");
+		port = js_register_port(port, info, 3, sizeof(struct js_as_info), js_as_read);
+		info = port->info;
+	} else {
+		printk(KERN_WARNING "joy-assassin: unknown joystick device detected "
+			"(io=%#x, id=%d), contact <vojtech@suse.cz>\n", io, data[0]);
+		return port;
+	}
+
+	udelay(JS_AS_DELAY_READ);
+
+	if (info->mode == JS_AS_MODE_PXL) {
+			printk(KERN_INFO "js%d: MadCatz Panther XL at %#x\n",
+				js_register_device(port, 0, 9, 9, "MadCatz Panther XL", js_as_open, js_as_close),
+				info->io);
+			js_as_read(port->info, port->axes, port->buttons);
+			js_as_pxl_init_corr(port->corr, port->axes);
+			if (info->an.axes[0] < 254) {
+			printk(KERN_INFO "js%d: Analog rudder on MadCatz Panther XL\n",
+				js_register_device(port, 1, 1, 0, "Analog rudder", js_as_open, js_as_close));
+				info->rudder = 1;
+				port->axes[1][0] = info->an.axes[0];
+				js_as_rudder_init_corr(port->corr, port->axes);
+			}
+			return port;
+	}
+
+	switch (info->mode) {
+		case JS_AS_MODE_A3D: name = "FP-Gaming Assassin 3D"; break;
+		case JS_AS_MODE_PAN: name = "MadCatz Panther"; break;
+		case JS_AS_MODE_OEM: name = "OEM Assassin 3D"; break;
+		default: name = "This cannot happen"; break;
+	}
+
+	printk(KERN_INFO "js%d: %s at %#x\n",
+		js_register_device(port, 0, 2, 3, name, js_as_open, js_as_close),
+		name, info->io);
+
+	js_as_as_init_corr(port->corr);
+
+	js_as_read(port->info, port->axes, port->buttons);
+
+	for (i = u = 0; i < 4; i++) if (info->an.axes[i] < 254) u |= 1 << i;
+
+	if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0)
+		return port;
+
+	for (i = 0; i < numdev; i++)
+		printk(KERN_INFO "js%d: %s on %s\n",
+			js_register_device(port, i + 1, js_an_axes(i, &info->an), js_an_buttons(i, &info->an),
+				js_an_name(i, &info->an), js_as_open, js_as_close),
+			js_an_name(i, &info->an), name);
+
+	js_an_decode(&info->an, port->axes + 1, port->buttons + 1);
+	js_an_init_corr(&info->an, port->axes + 1, port->corr + 1, 0);
+
+	return port;
+}
+
+#ifndef MODULE
+int __init js_as_setup(SETUP_PARAM)
+{
+	int i;
+	SETUP_PARSE(24);
+	for (i = 0; i <= ints[0] && i < 24; i++) js_as[i] = ints[i+1];
+	return 1;
+}
+__setup("js_as=", js_as_setup);
+#endif
+
+#ifdef MODULE
+int init_module(void)
+#else
+int __init js_as_init(void)
+#endif
+{
+	int i;
+
+	if (js_as[0] >= 0) {
+		for (i = 0; (js_as[i*3] >= 0) && i < 8; i++)
+			js_as_port = js_as_probe(js_as[i*3], js_as[i*3+1], js_as[i*3+2], js_as_port);
+	} else {
+		for (i = 0; js_as_port_list[i]; i++) js_as_port = js_as_probe(js_as_port_list[i], 0, 0, js_as_port);
+	}
+	if (js_as_port) return 0;
+
+#ifdef MODULE
+	printk(KERN_WARNING "joy-assassin: no joysticks found\n");
+#endif
+
+	return -ENODEV;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	int i;
+	struct js_as_info *info;
+
+	while (js_as_port) {
+		for (i = 0; i < js_as_port->ndevs; i++)
+			if (js_as_port->devs[i])
+				js_unregister_device(js_as_port->devs[i]);
+		info = js_as_port->info;
+		release_region(info->io, 1);
+		js_as_port = js_unregister_port(js_as_port);
+	}
+
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-console.c linux.14p16/drivers/char/joystick/joy-console.c
--- linux.vanilla/drivers/char/joystick/joy-console.c	Wed Dec  2 03:05:05 1998
+++ linux.14p16/drivers/char/joystick/joy-console.c	Tue Dec 21 00:31:12 1999
@@ -1,14 +1,19 @@
 /*
- * joy-console.c  Version 0.11V
+ *  joy-console.c  Version 0.14V
  *
- * Copyright (c) 1998 Andree Borrmann
+ *  Copyright (c) 1998 Andree Borrmann
+ *  Copyright (c) 1999 John Dahlstrom
+ *  Copyright (c) 1999 David Kuder
+ *  Copyright (c) 1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
  */
 
 /*
  * This is a module for the Linux joystick driver, supporting
- * console (NES, SNES, Multi1, Multi2, PSX) gamepads connected
- * via parallel port. Up to five such controllers can be
- * connected to one parallel port.
+ * console (NES, SNES, N64, Multi1, Multi2, PSX) gamepads 
+ * connected via parallel port. Up to five such controllers 
+ * can be connected to one parallel port.
  */
 
 /*
@@ -25,6 +30,10 @@
  * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  */
 
 #include <asm/io.h>
@@ -36,12 +45,13 @@
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 
-MODULE_AUTHOR("Andree Borrmann <A.Borrmann@tu-bs.de>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_PARM(js_console, "2-6i");
-MODULE_PARM(js_console2,"2-6i");
-MODULE_PARM(js_console3,"2-6i");
+MODULE_PARM(js_console_2,"2-6i");
+MODULE_PARM(js_console_3,"2-6i");
 
 
 #define JS_NO_PAD	0
@@ -51,29 +61,29 @@
 #define JS_MULTI_STICK	4
 #define JS_MULTI2_STICK	5
 #define JS_PSX_PAD	6
-
-#define JS_MAX_PAD	JS_PSX_PAD
+#define JS_N64_PAD	7	
+#define JS_N64_PAD_DPP	8	/* DirectPad Pro compatible layout */
+ 
+#define JS_MAX_PAD	JS_N64_PAD_DPP
 
 struct js_console_info {
-#ifdef USE_PARPORT
 	struct pardevice *port;	/* parport device */
-#else
-	int port;		/* hw port */
-#endif
 	int pads;		/* total number of pads */
+	int pad_to_device[5];   /* pad to js device mapping (js0, js1, etc.) */
 	int snes;		/* SNES pads */
 	int nes;		/* NES pads */
+	int n64;		/* N64 pads */
+	int n64_dpp;		/* bits indicate N64 pads treated 14 button, 2 axis */
 	int multi;		/* Multi joysticks */
 	int multi2;		/* Multi joysticks with 2 buttons */
-	int psx;		/* Normal PSX controllers */
-	int negcon;		/* PSX NEGCON controllers */
+	int psx;		/* PSX controllers */
 };
 
 static struct js_port* js_console_port = NULL;
 
 static int js_console[] __initdata = { -1, 0, 0, 0, 0, 0 };
-static int js_console2[] __initdata = { -1, 0, 0, 0, 0, 0 };
-static int js_console3[] __initdata = { -1, 0, 0, 0, 0, 0 };
+static int js_console_2[] __initdata = { -1, 0, 0, 0, 0, 0 };
+static int js_console_3[] __initdata = { -1, 0, 0, 0, 0, 0 };
 
 static int status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
 
@@ -109,7 +119,7 @@
 #define JS_SNES_L	10
 #define JS_SNES_R	11
 
-#define JS_NES_POWER	0xf8
+#define JS_NES_POWER	0xfc
 #define JS_NES_CLOCK	0x01
 #define JS_NES_LATCH	0x02
 
@@ -123,17 +133,99 @@
 {
 	int i;
 
-	JS_PAR_DATA_OUT(JS_NES_POWER + JS_NES_CLOCK + JS_NES_LATCH, info->port);
+	JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK | JS_NES_LATCH, info->port);
 	udelay(JS_NES_DELAY * 2);
-	JS_PAR_DATA_OUT(JS_NES_POWER + JS_NES_CLOCK, info->port);
+	JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK, info->port);
 
 	for (i = 0; i < length; i++) {
 		udelay(JS_NES_DELAY);
 		JS_PAR_DATA_OUT(JS_NES_POWER, info->port);
 		data[i] = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT;
 		udelay(JS_NES_DELAY);
-		JS_PAR_DATA_OUT(JS_NES_POWER + JS_NES_CLOCK, info->port);
+		JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK, info->port);
+	}
+}
+
+/*
+ * N64 support.
+ */
+
+#define JS_N64_A	0
+#define JS_N64_B	1
+#define JS_N64_Z	2
+#define JS_N64_START	3
+#define JS_N64_UP	4
+#define JS_N64_DOWN	5
+#define JS_N64_LEFT	6
+#define JS_N64_RIGHT	7
+#define JS_N64_UNUSED1	8
+#define JS_N64_UNUSED2	9
+#define JS_N64_L	10
+#define JS_N64_R	11
+#define JS_N64_CU	12
+#define JS_N64_CD	13
+#define JS_N64_CL	14
+#define JS_N64_CR	15
+#define JS_N64_X	23			/* 16 - 23, signed 8-bit int */
+#define JS_N64_Y	31			/* 24 - 31, signed 8-bit int */
+
+#define JS_N64_LENGTH		32		/* N64 bit length, not including stop bit */
+#define JS_N64_REQUEST_LENGTH	37		/* transmit request sequence is 9 bits long */
+#define JS_N64_DELAY		133		/* delay between transmit request, and response ready (us) */
+#define JS_N64_REQUEST		0x1dd1111111ULL /* the request data command (encoded for 000000011) */
+#define JS_N64_DWS		3		/* delay between write segments (required for sound playback because of ISA DMA) */
+						/* JS_N64_DWS > 24 is known to fail */ 
+#define JS_N64_POWER_W		0xe2		/* power during write (transmit request) */
+#define JS_N64_POWER_R		0xfd		/* power during read */
+#define JS_N64_OUT		0x1d		/* output bits to the 4 pads */
+						/* Reading the main axes of any N64 pad is known to fail if the corresponding bit */
+						/* in JS_N64_OUT is pulled low on the output port (by any routine) for more */
+						/* than 0.123 consecutive ms */
+#define JS_N64_CLOCK		0x02		/* clock bits for read */
+
+/* 
+ * js_n64_read_packet() reads an N64 packet. 
+ * Each pad uses one bit per byte. So all pads connected to this port are read in parallel.
+ */
+
+static void js_n64_read_packet(struct js_console_info *info, unsigned char *data)
+{
+	int i;
+	unsigned long flags;
+
+/*
+ * Request the pad to transmit data
+ */
+
+	save_flags(flags);
+	cli();
+	for (i = 0; i < JS_N64_REQUEST_LENGTH; i++) {
+		JS_PAR_DATA_OUT(JS_N64_POWER_W | ((JS_N64_REQUEST >> i) & 1 ? JS_N64_OUT : 0), info->port);
+		udelay(JS_N64_DWS);
 	}
+	restore_flags(flags);
+
+/*
+ * Wait for the pad response to be loaded into the 33-bit register of the adapter
+ */
+
+	udelay(JS_N64_DELAY);
+
+/*
+ * Grab data (ignoring the last bit, which is a stop bit)
+ */
+
+	for (i = 0; i < JS_N64_LENGTH; i++) {
+		JS_PAR_DATA_OUT(JS_N64_POWER_R, info->port);
+		data[i] = JS_PAR_STATUS(info->port);
+		JS_PAR_DATA_OUT(JS_N64_POWER_R | JS_N64_CLOCK, info->port);
+	 }
+
+/*
+ * We must wait ~0.2 ms here for the controller to reinitialize before the next read request.
+ * No worries as long as js_console_read is polled less frequently than this.
+ */
+
 }
 
 /*
@@ -161,7 +253,9 @@
 	for (i = 0; i < length; i++) {
 		JS_PAR_DATA_OUT(~(1 << i), info->port);
 		data[i] = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT;
+		printk(" %d", data[i]);
 	}
+	printk("\n");
 }
 
 /*
@@ -169,27 +263,28 @@
  */
 
 #define JS_PSX_DELAY	10
+#define JS_PSX_LENGTH	8    /* talk to the controller in bytes */
 
-#define JS_PSX_LENGTH	8
-
-#define JS_PSX_NORMAL	0x41
-#define JS_PSX_NEGCON	0x23
-#define JS_PSX_MOUSE	0x12
-
-#define JS_PSX_SELBUT	0x01
+#define JS_PSX_NORMAL	0x41 /* Standard Digital controller */
+#define JS_PSX_NEGCON	0x23 /* NegCon pad */
+#define JS_PSX_MOUSE	0x12 /* PSX Mouse */
+#define JS_PSX_ANALOGR	0x73 /* Analog controller in Red mode */
+#define JS_PSX_ANALOGG	0x53 /* Analog controller in Green mode */
+
+#define JS_PSX_JOYR	0x02 /* These are for the Analog/Dual Shock controller in RED mode */
+#define JS_PSX_JOYL	0x04 /* I'm not sure the exact purpose of these but its in the docs */
+#define JS_PSX_SELBUT	0x01 /* Standard buttons on almost all PSX controllers. */
 #define JS_PSX_START	0x08
-#define JS_PSX_UP	0x10
+#define JS_PSX_UP	0x10 /* Digital direction pad */
 #define JS_PSX_RIGHT	0x20
 #define JS_PSX_DOWN	0x40
 #define JS_PSX_LEFT	0x80
 
-#define JS_PSX_CLOCK	0x01
-#define JS_PSX_COMMAND	0x02
-#define JS_PSX_POWER	0xf8
-#define JS_PSX_NOPOWER	0x04
-#define JS_PSX_SELECT	0x08
-
-#define JS_PSX_CTRL_OUT(X,Y)	JS_PAR_CTRL_OUT((X)^0x0f, Y)
+#define JS_PSX_CLOCK	0x04 /* Pin 3 */
+#define JS_PSX_COMMAND	0x01 /* Pin 1 */
+#define JS_PSX_POWER	0xf8 /* Pins 5-9 */
+#define JS_PSX_SELECT	0x02 /* Pin 2 */
+#define JS_PSX_NOPOWER  0x04
 
 /*
  * js_psx_command() writes 8bit command and reads 8bit data from
@@ -202,11 +297,11 @@
 
 	cmd = (b&1)?JS_PSX_COMMAND:0;
 	for (i=0; i<8; i++) {
-		JS_PSX_CTRL_OUT(cmd, info->port);
+		JS_PAR_DATA_OUT(cmd | JS_PSX_POWER, info->port);
 		udelay(JS_PSX_DELAY);
 		ret |= ((JS_PAR_STATUS(info->port) ^ JS_PAR_STATUS_INVERT ) & info->psx) ? (1<<i) : 0;
 		cmd = (b&1)?JS_PSX_COMMAND:0;
-		JS_PSX_CTRL_OUT(JS_PSX_CLOCK | cmd, info->port);
+		JS_PAR_DATA_OUT(cmd | JS_PSX_CLOCK | JS_PSX_POWER, info->port);
 		udelay(JS_PSX_DELAY);
 		b >>= 1;
 	}
@@ -228,7 +323,7 @@
 
 	JS_PAR_DATA_OUT(JS_PSX_POWER, info->port);
 
-	JS_PSX_CTRL_OUT(JS_PSX_CLOCK | JS_PSX_SELECT, info->port);	/* Select pad */
+	JS_PAR_DATA_OUT(JS_PSX_CLOCK | JS_PSX_SELECT | JS_PSX_POWER, info->port);	/* Select pad */
 	udelay(JS_PSX_DELAY*2);
 	js_psx_command(info, 0x01);					/* Access pad */
 	ret = js_psx_command(info, 0x42);				/* Get device id */
@@ -237,7 +332,7 @@
 			data[i]=js_psx_command(info, 0);
 	else ret = -1;
 
-	JS_PSX_CTRL_OUT(JS_PSX_SELECT | JS_PSX_CLOCK, info->port);
+	JS_PAR_DATA_OUT(JS_PSX_SELECT | JS_PSX_CLOCK | JS_PSX_POWER, info->port);
 	__restore_flags(flags);
 
 	return ret;
@@ -248,14 +343,14 @@
  * js_console_read() reads and analyzes console pads data.
  */
 
-#define JS_MAX_LENGTH JS_SNES_LENGTH
+#define JS_MAX_LENGTH JS_N64_LENGTH
 
 static int js_console_read(void *xinfo, int **axes, int **buttons)
 {
 	struct js_console_info *info = xinfo;
 	unsigned char data[JS_MAX_LENGTH];
 
-	int i, s;
+	int i, j, s;
 	int n = 0;
 
 /*
@@ -268,24 +363,68 @@
 
 		for (i = 0; i < 5; i++) {
 			s = status_bit[i];
+			n = info->pad_to_device[i];
 			if (info->nes & s) {
 				axes[n][0] = (data[JS_SNES_RIGHT]&s?1:0) - (data[JS_SNES_LEFT]&s?1:0);
 				axes[n][1] = (data[JS_SNES_DOWN] &s?1:0) - (data[JS_SNES_UP]  &s?1:0);
 
-				buttons[n][0] = ((data[JS_NES_A]    &s)?1:0) | ((data[JS_NES_B]     &s)?2:0)
-					      | ((data[JS_NES_START]&s)?4:0) | ((data[JS_NES_SELECT]&s)?8:0);
-
-				n++;
+				buttons[n][0] = (data[JS_NES_A]    &s?1:0) | (data[JS_NES_B]     &s?2:0)
+					      | (data[JS_NES_START]&s?4:0) | (data[JS_NES_SELECT]&s?8:0);
 			} else
 			if (info->snes & s) {
 				axes[n][0] = (data[JS_SNES_RIGHT]&s?1:0) - (data[JS_SNES_LEFT]&s?1:0);
 				axes[n][1] = (data[JS_SNES_DOWN] &s?1:0) - (data[JS_SNES_UP]  &s?1:0);
 
-				buttons[n][0] = ((data[JS_SNES_A]    &s)?0x01:0) | ((data[JS_SNES_B]     &s)?0x02:0)
-					      | ((data[JS_SNES_X]    &s)?0x04:0) | ((data[JS_SNES_Y]     &s)?0x08:0)
-					      | ((data[JS_SNES_L]    &s)?0x10:0) | ((data[JS_SNES_R]     &s)?0x20:0)
-					      | ((data[JS_SNES_START]&s)?0x40:0) | ((data[JS_SNES_SELECT]&s)?0x80:0);
-				n++;
+				buttons[n][0] = (data[JS_SNES_A]    &s?0x01:0) | (data[JS_SNES_B]     &s?0x02:0)
+					      | (data[JS_SNES_X]    &s?0x04:0) | (data[JS_SNES_Y]     &s?0x08:0)
+					      | (data[JS_SNES_L]    &s?0x10:0) | (data[JS_SNES_R]     &s?0x20:0)
+					      | (data[JS_SNES_START]&s?0x40:0) | (data[JS_SNES_SELECT]&s?0x80:0);
+			}
+		}
+	}
+
+/*
+ * N64 pads
+ */
+
+	if (info->n64) {
+		if ( (info->nes || info->snes) && (info->n64 & status_bit[0]) ) {
+					/* SNES/NES compatibility */
+			udelay(240);	/* 200 us delay + 20% tolerance */
+		}
+
+		js_n64_read_packet(info, data);
+
+		for (i = 0; i < 5; i++) {
+			s = status_bit[i];
+			n = info->pad_to_device[i];
+			if (info->n64 & s & ~(data[JS_N64_UNUSED1] | data[JS_N64_UNUSED2])) {
+
+				buttons[n][0] = ( ((data[JS_N64_A]&s) ? 0x01:0) | ((data[JS_N64_B] & s ) ? 0x02:0) 
+						| ((data[JS_N64_Z]&s) ? 0x04:0) | ((data[JS_N64_L] & s ) ? 0x08:0) 
+						| ((data[JS_N64_R]&s) ? 0x10:0) | ((data[JS_N64_START]&s)? 0x20:0)
+						| ((data[JS_N64_CU]&s)? 0x40:0) | ((data[JS_N64_CR]&s)   ? 0x80:0)
+						| ((data[JS_N64_CD]&s)?0x100:0) | ((data[JS_N64_CL]&s)   ?0x200:0) );
+
+				if (info->n64_dpp & s) { 
+					buttons[n][0] |= ((data[JS_N64_LEFT]&s) ? 0x400:0) | ((data[JS_N64_UP] & s)? 0x800:0)
+							|((data[JS_N64_RIGHT]&s)?0x1000:0) | ((data[JS_N64_DOWN]&s)?0x2000:0);
+				} else {
+					axes[n][2] = (data[JS_N64_RIGHT]&s?1:0) - (data[JS_N64_LEFT]&s?1:0);
+					axes[n][3] = (data[JS_N64_DOWN] &s?1:0) - (data[JS_N64_UP]  &s?1:0);
+				}
+
+						/* build int from bits of signed 8-bit int's */
+				j = 7;
+				axes[n][0] = (data[JS_N64_X - j] & s) ? ~0x7f : 0;
+				axes[n][1] = (data[JS_N64_Y - j] & s) ? ~0x7f : 0;
+				while ( j-- > 0 ) {
+					axes[n][0] |= (data[JS_N64_X - j] & s) ? (1 << j) : 0; 
+					axes[n][1] |= (data[JS_N64_Y - j] & s) ? (1 << j) : 0; 
+				}
+						/* flip Y-axis for conformity */
+				axes[n][1] = -axes[n][1];
+
 			}
 		}
 	}
@@ -300,21 +439,18 @@
 
 		for (i = 0; i < 5; i++) {
 			s = status_bit[i];
+			n = info->pad_to_device[i];
 			if (info->multi & s) {
 				axes[n][0] = (data[JS_MULTI_RIGHT]&s?1:0) - (data[JS_MULTI_LEFT]&s?1:0);
 				axes[n][1] = (data[JS_MULTI_DOWN] &s?1:0) - (data[JS_MULTI_UP]  &s?1:0);
 
 				buttons[n][0] = (data[JS_MULTI_BUTTON]&s)?1:0;
-
-				n++;
 			} else
 			if (info->multi2 & s) {
 				axes[n][0] = (data[JS_MULTI_RIGHT]&s?1:0) - (data[JS_MULTI_LEFT]&s?1:0);
 				axes[n][1] = (data[JS_MULTI_DOWN] &s?1:0) - (data[JS_MULTI_UP]  &s?1:0);
 
 				buttons[n][0] = (data[JS_MULTI_BUTTON]&s)?1:0 | (data[JS_MULTI_BUTTON2]&s)?2:0;
-
-				n++;
 			}
 		}
 	}
@@ -323,18 +459,44 @@
  * PSX controllers
  */
 
-	if (info->psx && (js_psx_read_packet(info, 2, data) == JS_PSX_NORMAL)) {	/* FIXME? >1 PSX pads? */
+	if (info->psx) {
+
+		for ( i = 0; i < 5; i++ )
+	       		if ( info->psx & status_bit[i] ) {
+				n = info->pad_to_device[i];
+				break;
+			}
+
+		buttons[n][0] = 0;
+
+ 		switch (js_psx_read_packet(info, 6, data)) {
 
-		axes[n][0] = (data[0]&JS_PSX_RIGHT?0:1) - (data[0]&JS_PSX_LEFT?0:1);
-		axes[n][1] = (data[0]&JS_PSX_DOWN ?0:1) - (data[0]&JS_PSX_UP  ?0:1);
+			case JS_PSX_ANALOGR:
 
-		buttons[n][0] = ((~data[1]&0xf)<<4) | ((~data[1]&0xf0)>>4) |
-				(data[0]&JS_PSX_START?0:0x200) | (data[0]&JS_PSX_SELBUT?0:0x100);
+				buttons[n][0] |= (data[0]&JS_PSX_JOYL?0:0x800) | (data[0]&JS_PSX_JOYR?0:0x400);
 
-		n++;
+			case JS_PSX_ANALOGG:
+	
+				axes[n][2] = data[2];
+				axes[n][3] = data[3];
+				axes[n][4] = data[4];
+				axes[n][5] = data[5];
+
+			case JS_PSX_NORMAL:
+			case JS_PSX_NEGCON:
+
+				axes[n][0] = (data[0]&JS_PSX_RIGHT?0:1) - (data[0]&JS_PSX_LEFT?0:1);
+				axes[n][1] = (data[0]&JS_PSX_DOWN ?0:1) - (data[0]&JS_PSX_UP  ?0:1);
+
+				buttons[n][0] |= ((~data[1]&0xf)<<4) | ((~data[1]&0xf0)>>4) |
+					(data[0]&JS_PSX_START?0:0x200) | (data[0]&JS_PSX_SELBUT?0:0x100);
+		
+				break;
+
+		}
 	}
 
-	return -(n != info->pads);
+	return 0;
 }
 
 /*
@@ -343,10 +505,8 @@
 
 int js_console_open(struct js_dev *dev)
 {
-#ifdef USE_PARPORT
 	struct js_console_info *info = dev->port->info;
 	if (!MOD_IN_USE && parport_claim(info->port)) return -EBUSY;
-#endif
 	MOD_INC_USE_COUNT;
 	return 0;
 }
@@ -357,13 +517,9 @@
 
 int js_console_close(struct js_dev *dev)
 {
-#ifdef USE_PARPORT
 	struct js_console_info *info = dev->port->info;
-#endif
 	MOD_DEC_USE_COUNT;
-#ifdef USE_PARPORT
 	if (!MOD_IN_USE) parport_release(info->port);
-#endif
 	return 0;
 }
 
@@ -373,16 +529,12 @@
 	struct js_console_info *info;
 	int i;
 
-	while (js_console_port != NULL) {
+	while (js_console_port) {
 		for (i = 0; i < js_console_port->ndevs; i++)
-			if (js_console_port->devs[i] != NULL)
+			if (js_console_port->devs[i])
 				js_unregister_device(js_console_port->devs[i]);
 		info = js_console_port->info;
-#ifdef USE_PARPORT
 		parport_unregister_device(info->port);
-#else
-		release_region(info->port, 3);
-#endif
 		js_console_port = js_unregister_port(js_console_port);
 	}
 }
@@ -393,7 +545,7 @@
  * console gamepads.
  */
 
-static void __init js_console_init_corr(int num_axes, struct js_corr *corr)
+static void __init js_console_init_corr(int num_axes, int type, struct js_corr *corr)
 {
 	int i;
 
@@ -405,6 +557,28 @@
 		corr[i].coef[2] = (1 << 29);
 		corr[i].coef[3] = (1 << 29);
 	}
+
+	if (type == JS_N64_PAD || type == JS_N64_PAD_DPP) {
+		for (i = 0; i < 2; i++) {
+			corr[i].type = JS_CORR_BROKEN;
+			corr[i].prec = 0;
+			corr[i].coef[0] = 0;
+			corr[i].coef[1] = 0;
+			corr[i].coef[2] = (1 << 22);
+			corr[i].coef[3] = (1 << 22);
+		}
+	}
+
+	if (type == JS_PSX_ANALOGG || type == JS_PSX_ANALOGR) {
+		for (i = 2; i < 6; i++)  {
+			corr[i].type = JS_CORR_BROKEN;
+			corr[i].prec = 0;
+			corr[i].coef[0] = 127 - 2;
+			corr[i].coef[1] = 128 + 2;
+			corr[i].coef[2] = (1 << 29) / (127 - 4);
+			corr[i].coef[3] = (1 << 29) / (127 - 4);
+		}
+	}
 }
 
 /*
@@ -415,45 +589,40 @@
 static struct js_port __init *js_console_probe(int *config, struct js_port *port)
 {
 	char *name[5];
-	int i, psx, axes[5], buttons[5];
+	int i, psx, axes[5], buttons[5], type[5];
 	unsigned char data[2];			/* used for PSX probe */
 	struct js_console_info info;
+	struct parport *pp;
 
 	memset(&info, 0, sizeof(struct js_console_info));
 
 	if (config[0] < 0) return port;
 
-#ifdef USE_PARPORT
-	{
-		struct parport *pp;
-
-		if (config[0] > 0x10)
-			for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next);
-		else
-			for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) config[0]--;
-
-		if (pp == NULL) {
-			printk(KERN_ERR "joy-console: no such parport\n");
-			return port;
-		}
+	if (config[0] > 0x10)
+		for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next);
+	else
+		for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--;
 
-		info.port = parport_register_device(pp, "joystick (console)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
-		if (!info.port)
-			return port;
+	if (!pp) {
+		printk(KERN_ERR "joy-console: no such parport\n");
+		return port;
 	}
 
+	info.port = parport_register_device(pp, "joystick (console)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+	if (!info.port)
+		return port;
+
 	if (parport_claim(info.port))
 	{
 		parport_unregister_device(info.port);	/* port currently not available ... */
 		return port;
 	}
-#else
-	info.port = config[0];
-	if (check_region(info.port, 3)) return port;
-	request_region(info.port, 3, "joystick (console pad)");
-#endif
 
-	for (i = 0; i < 5; i++)
+	for (i = 0; i < 5; i++) {
+
+		type[info.pads] = config[i+1];
+		info.pad_to_device[i] = info.pads;
+
 		switch(config[i+1]) {
 
 			case JS_NO_PAD:
@@ -478,6 +647,23 @@
 				info.pads++;
 				break;
 
+			case JS_N64_PAD:
+				axes[info.pads]    = 4;
+				buttons[info.pads] = 10;
+				name[info.pads]    = "N64 pad";
+				info.n64 |= status_bit[i];
+				info.pads++;
+				break;
+
+			case JS_N64_PAD_DPP:
+				axes[info.pads]    = 2;
+				buttons[info.pads] = 14;
+				name[info.pads]    = "N64 pad (DPP mode)";
+				info.n64 |= status_bit[i];
+				info.n64_dpp |= status_bit[i];
+				info.pads++;
+				break;
+				
 			case JS_MULTI_STICK:
 
 				axes[info.pads]    = 2;
@@ -497,31 +683,58 @@
 				break;
 
 			case JS_PSX_PAD:
-
+				
 				info.psx |= status_bit[i];
 				psx = js_psx_read_packet(&info, 2, data);
 				psx = js_psx_read_packet(&info, 2, data);
 				info.psx &= ~status_bit[i];
 
+				type[i] = psx;
+
 				switch(psx) {
 					case JS_PSX_NORMAL:
 						axes[info.pads]    = 2;
 						buttons[info.pads] = 10;
-						name[info.pads]    = "PSX controller";
+						name[info.pads]    = "PSX pad";
 						info.psx |= status_bit[i];
 						info.pads++;
 						break;
+
+					case JS_PSX_ANALOGR:
+						axes[info.pads]    = 6;
+						buttons[info.pads] = 12;
+						name[info.pads]    = "Analog Red PSX pad";
+						info.psx |= status_bit[i];
+						info.pads++;
+						break;
+
+					case JS_PSX_ANALOGG:
+						axes[info.pads]    = 6;
+						buttons[info.pads] = 10;
+						name[info.pads]    = "Analog Green PSX pad";
+						info.psx |= status_bit[i];
+						info.pads++;
+						break;
+
 					case JS_PSX_NEGCON:
-						printk(KERN_WARNING "joy-console: NegCon not yet supported...\n");
+						axes[info.pads]    = 2;
+						buttons[info.pads] = 10;
+						name[info.pads]    = "NegCon PSX pad";
+						info.psx |= status_bit[i];
+						info.pads++;
 						break;
+
 					case JS_PSX_MOUSE:
-						printk(KERN_WARNING "joy-console: PSX mouse not supported...\n");
+						printk(KERN_WARNING "joy-psx: PSX mouse not supported...\n");
 						break;
+
 					case -1:
-						printk(KERN_ERR "joy-console: no PSX controller found...\n");
+						printk(KERN_ERR "joy-psx: no PSX controller found...\n");
 						break;
+
 					default:
-						printk(KERN_WARNING "joy-console: unknown PSX controller 0x%x\n", psx);
+						printk(KERN_WARNING "joy-psx: PSX controller unknown: 0x%x,"
+							" please report to <vojtech@suse.cz>.\n", psx);
 				}
 				break;
 
@@ -529,52 +742,53 @@
 
 				printk(KERN_WARNING "joy-console: pad type %d unknown\n", config[i+1]);
 		}
+	}
 
 	if (!info.pads) {
-#ifdef USE_PARPORT
 		parport_release(info.port);
 		parport_unregister_device(info.port);
-#else
-		release_region(info.port, 3);
-#endif
 		return port;
 	}
 
 	port = js_register_port(port, &info, info.pads, sizeof(struct js_console_info), js_console_read);
 
 	for (i = 0; i < info.pads; i++) {
-#ifdef USE_PARPORT
 		printk(KERN_INFO "js%d: %s on %s\n",
 			js_register_device(port, i, axes[i], buttons[i], name[i], js_console_open, js_console_close),
 			name[i], info.port->port->name);
-#else
-		printk(KERN_INFO "js%d: %s at %#x\n",
-			js_register_device(port, i, axes[i], buttons[i], name[i], js_console_open, js_console_close),
-			name[i], info.port);
-#endif
 
-		js_console_init_corr(axes[i], port->corr[i]);
+		js_console_init_corr(axes[i], type[i], port->corr[i]);
 	}
 
-#ifdef USE_PARPORT
 	parport_release(info.port);
-#endif
 	return port;
 }
 
 #ifndef MODULE
-void __init js_console_setup(char *str, int *ints)
+int __init js_console_setup(SETUP_PARAM)
 {
 	int i;
-
-	if (!strcmp(str,"js_console"))
-		for (i = 0; i <= ints[0] && i < 6; i++) js_console[i] = ints[i+1];
-	if (!strcmp(str,"js_console2"))
-		for (i = 0; i <= ints[0] && i < 6; i++) js_console2[i] = ints[i+1];
-	if (!strcmp(str,"js_console3"))
-		for (i = 0; i <= ints[0] && i < 6; i++) js_console3[i] = ints[i+1];
-
+	SETUP_PARSE(6);
+	for (i = 0; i <= ints[0] && i < 6; i++) js_console[i] = ints[i+1];
+	return 1;
 }
+int __init js_console_setup_2(SETUP_PARAM)
+{
+	int i;
+	SETUP_PARSE(6);
+	for (i = 0; i <= ints[0] && i < 6; i++) js_console_2[i] = ints[i+1];
+	return 1;
+}
+int __init js_console_setup_3(SETUP_PARAM)
+{
+	int i;
+	SETUP_PARSE(6);
+	for (i = 0; i <= ints[0] && i < 6; i++) js_console_3[i] = ints[i+1];
+	return 1;
+}
+__setup("js_console=", js_console_setup);
+__setup("js_console_2=", js_console_setup_2);
+__setup("js_console_3=", js_console_setup_3);
 #endif
 
 #ifdef MODULE
@@ -584,8 +798,8 @@
 #endif
 {
 	js_console_port = js_console_probe(js_console, js_console_port);
-	js_console_port = js_console_probe(js_console2, js_console_port);
-	js_console_port = js_console_probe(js_console3, js_console_port);
+	js_console_port = js_console_probe(js_console_2, js_console_port);
+	js_console_port = js_console_probe(js_console_3, js_console_port);
 
 	if (js_console_port) return 0;
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-creative.c linux.14p16/drivers/char/joystick/joy-creative.c
--- linux.vanilla/drivers/char/joystick/joy-creative.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/char/joystick/joy-creative.c	Tue Dec 21 00:31:12 1999
@@ -0,0 +1,287 @@
+/*
+ *  joy-creative.c  Version 1.2
+ *
+ *  Copyright (c) 1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This is a module for the Linux joystick driver, supporting
+ * Creative Labs Blaster gamepad family.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/joystick.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#define JS_CR_MAX_STROBE	100	/* 100 us max wait for first strobe */
+#define JS_CR_LENGTH		36
+
+#define JS_CR_MODE_BGPC		8
+
+static int js_cr_port_list[] __initdata = {0x201, 0};
+static struct js_port* js_cr_port __initdata = NULL;
+
+struct js_cr_info {
+	int io;
+	unsigned char mode[2];
+};
+
+/*
+ * js_cr_read_packet() reads a Blaster gamepad packet.
+ */
+
+static int js_cr_read_packet(int io, unsigned int *data)
+{
+	unsigned long flags;
+	unsigned char u, v, w;
+	__u64 buf[2];
+	int r[2], t[2], p[2];
+	int i, j, ret;
+
+	for (i = 0; i < 2; i++); {
+		r[i] = buf[i] = 0;
+		p[i] = t[i] = JS_CR_MAX_STROBE;
+		p[i] += JS_CR_MAX_STROBE;
+	}
+	
+	__save_flags(flags);
+	__cli();
+
+	u = inb(io);
+
+	do {
+		t[0]--; t[1]--;
+		v = inb(io);
+		for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2)
+			if (w & 0x30) {
+				if ((w & 0x30) < 0x30 && r[i] < JS_CR_LENGTH && t[i] > 0) {
+					buf[i] |= (__u64)((w >> 5) & 1) << r[i]++;
+					p[i] = t[i] = (p[i] - t[i]) << 1;
+					u = v;
+				} else t[i] = 0;
+			}
+	} while (t[0] > 0 || t[1] > 0);
+
+	__restore_flags(flags);
+
+
+	ret = 0;
+
+	for (i = 0; i < 2; i++) {
+
+		if (r[i] != JS_CR_LENGTH) continue;
+
+		for (j = 0; j < JS_CR_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++)
+			buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (JS_CR_LENGTH - 1));
+
+		if (j < JS_CR_LENGTH) ret |= (1 << i);
+
+		data[i] = ((buf[i] >>  7) & 0x000001f) | ((buf[i] >>  8) & 0x00003e0)
+			| ((buf[i] >>  9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000)
+			| ((buf[i] >> 11) & 0x1f00000);
+
+	}
+
+	return ret;
+}
+
+/*
+ * js_cr_read() reads and analyzes Blaster gamepad data.
+ */
+
+static int js_cr_read(void *xinfo, int **axes, int **buttons)
+{
+	struct js_cr_info *info = xinfo;
+	unsigned int data[2];
+	int i, r;
+
+	if (!(r = js_cr_read_packet(info->io, data)))
+		return -1;
+
+	for (i = 0; i < 2; i++)
+		if (r & (1 << i)) {
+			switch (info->mode[i]) {
+
+				case JS_CR_MODE_BGPC:
+
+					axes[i][0] = ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1);
+					axes[i][1] = ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1);
+
+					buttons[i][0] = ((data[i] >> 12) & 0x007) | ((data[i] >> 6) & 0x038)
+						      | ((data[i] >>  1) & 0x0c0) | ((data[i] >> 7) & 0x300)
+						      | ((data[i] <<  5) & 0xc00);
+
+					break;
+
+				default:
+					break;
+
+			}
+		}
+
+	return 0;
+}
+
+/*
+ * js_cr_open() is a callback from the file open routine.
+ */
+
+static int js_cr_open(struct js_dev *jd)
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * js_cr_close() is a callback from the file release routine.
+ */
+
+static int js_cr_close(struct js_dev *jd)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * js_cr_init_corr() initializes correction values of
+ * Blaster gamepads.
+ */
+
+static void __init js_cr_init_corr(int mode, struct js_corr *corr)
+{
+	int i;
+
+	switch (mode) {
+
+		case JS_CR_MODE_BGPC:
+
+			for (i = 0; i < 2; i++) {
+				corr[i].type = JS_CORR_BROKEN;
+				corr[i].prec = 0;
+				corr[i].coef[0] = 0;
+				corr[i].coef[1] = 0;
+				corr[i].coef[2] = (1 << 29);
+				corr[i].coef[3] = (1 << 29);
+			}
+
+			break;
+
+	}
+}
+
+/*
+ * js_cr_probe() probes for Blaster gamepads.
+ */
+
+static struct js_port __init *js_cr_probe(int io, struct js_port *port)
+{
+	struct js_cr_info info;
+	char *names[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Blaster GamePad Cobra" };
+	char axes[] = { 0, 0, 0, 0, 0, 0, 0, 0, 2 };
+	char buttons[] = { 0, 0, 0, 0, 0, 0, 0, 0, 12 };
+	unsigned int data[2];
+	int i, r;
+
+	if (check_region(io, 1)) return port;
+
+	info.mode[0] = info.mode[1] = 0;
+
+	if (!(r = js_cr_read_packet(io, data)))
+		return port;
+
+	for (i = 0; i < 2; i++) {
+		if (r & (1 << i)) {
+			if (~data[i] & 1) {
+				info.mode[i] = JS_CR_MODE_BGPC;
+			} else {
+				info.mode[i] = (data[i] >> 2) & 7;
+			}
+			if (!names[info.mode[i]]) {
+				printk(KERN_WARNING "joy-creative: Unknown Creative device %d at %#x\n",
+					info.mode[i], io);
+				info.mode[i] = 0;
+			}
+		}
+	}
+
+	if (!info.mode[0] && !info.mode[1]) return port;
+
+	info.io = io;
+
+	request_region(io, 1, "joystick (creative)");
+	port = js_register_port(port, &info, 2, sizeof(struct js_cr_info), js_cr_read);
+
+	for (i = 0; i < 2; i++)
+		if (info.mode[i]) {
+			printk(KERN_INFO "js%d: %s at %#x\n",
+				js_register_device(port, i, axes[info.mode[i]], buttons[info.mode[i]],
+					names[info.mode[i]], js_cr_open, js_cr_close),
+				names[info.mode[i]], io);
+			js_cr_init_corr(info.mode[i], port->corr[i]);
+		}
+
+	return port;
+}
+
+#ifdef MODULE
+int init_module(void)
+#else
+int __init js_cr_init(void)
+#endif
+{
+	int *p;
+
+	for (p = js_cr_port_list; *p; p++) js_cr_port = js_cr_probe(*p, js_cr_port);
+	if (js_cr_port) return 0;
+
+#ifdef MODULE
+	printk(KERN_WARNING "joy-creative: no joysticks found\n");
+#endif
+
+	return -ENODEV;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	int i;
+	struct js_cr_info *info;
+
+	while (js_cr_port) {
+		for (i = 0; i < js_cr_port->ndevs; i++)
+			if (js_cr_port->devs[i])
+				js_unregister_device(js_cr_port->devs[i]);
+		info = js_cr_port->info;
+		release_region(info->io, 1);
+		js_cr_port = js_unregister_port(js_cr_port);
+	}
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-db9.c linux.14p16/drivers/char/joystick/joy-db9.c
--- linux.vanilla/drivers/char/joystick/joy-db9.c	Wed Dec  2 03:05:05 1998
+++ linux.14p16/drivers/char/joystick/joy-db9.c	Tue Dec 21 00:31:12 1999
@@ -1,7 +1,10 @@
 /*
- * joy-db9.c  Version 0.5V
+ *  joy-db9.c  Version 0.6V
  *
- * Copyright (c) 1998 Andree Borrmann
+ *  Copyright (c) 1998 Andree Borrmann
+ *  Copyright (c) 1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
  */
 
 /*
@@ -24,6 +27,10 @@
  * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  */
 
 #include <asm/io.h>
@@ -35,8 +42,9 @@
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
-MODULE_AUTHOR("Andree Borrmann <A.Borrmann@tu-bs.de>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_PARM(js_db9, "2i");
 MODULE_PARM(js_db9_2, "2i");
 MODULE_PARM(js_db9_3, "2i");
@@ -48,7 +56,8 @@
 #define JS_GENESIS6_PAD	0x06
 #define JS_SATURN_PAD	0x07
 #define JS_MULTI_0802	0x08
-#define JS_MAX_PAD	0x09
+#define JS_MULTI_0802_2	0x09
+#define JS_MAX_PAD	0x0A
 
 #define JS_DB9_UP	0x01
 #define JS_DB9_DOWN	0x02
@@ -59,8 +68,8 @@
 #define JS_DB9_FIRE3	0x40
 #define JS_DB9_FIRE4	0x80
 
-#define JS_DB9_NORMAL	0x22
-#define JS_DB9_NOSELECT	0x20
+#define JS_DB9_NORMAL	0x2a
+#define JS_DB9_NOSELECT	0x28
 
 #define JS_DB9_SATURN0	0x20
 #define JS_DB9_SATURN1	0x22
@@ -76,11 +85,7 @@
 static int js_db9_3[] __initdata = { -1, 0 };
 
 struct js_db9_info {
-#ifdef USE_PARPORT
 	struct pardevice *port;	/* parport device */
-#else
-	int port;		/* hw port */
-#endif
 	int mode;		/* pad mode */
 };
 
@@ -95,6 +100,15 @@
 
 	switch(info->mode)
 	{
+	  case JS_MULTI_0802_2:
+
+		data = JS_PAR_DATA_IN(info->port) >> 3;
+
+		axes[1][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP  ?0:1);
+		axes[1][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
+
+		buttons[1][0] = (data&JS_DB9_FIRE1?0:1);
+
 	  case JS_MULTI_0802:
 
 		data = JS_PAR_STATUS(info->port) >> 3;
@@ -185,11 +199,12 @@
 		udelay(JS_GENESIS6_DELAY);
 		JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 3 */
 		udelay(JS_GENESIS6_DELAY);
-		JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
 		data=JS_PAR_DATA_IN(info->port);
 
-		buttons[0][0] |= (data&JS_DB9_LEFT?0:0x10) | (data&JS_DB9_DOWN?0:0x20) | (data&JS_DB9_UP?0:0x40);
+		buttons[0][0] |= (data&JS_DB9_LEFT?0:0x10) | (data&JS_DB9_DOWN ?0:0x20) |
+				 (data&JS_DB9_UP  ?0:0x40) | (data&JS_DB9_RIGHT?0:0x80);
 
+		JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
 		udelay(JS_GENESIS6_DELAY);
 		JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 4 */
 		udelay(JS_GENESIS6_DELAY);
@@ -236,11 +251,11 @@
 	struct js_db9_info *info = dev->port->info;
 
 	if (!MOD_IN_USE) {
-#ifdef USE_PARPORT
 		if (parport_claim(info->port)) return -EBUSY;
-#endif
 
-		JS_PAR_ECTRL_OUT(0x35,info->port);		/* enable PS/2 mode: */
+		JS_PAR_DATA_OUT(0xff, info->port);
+		if (info->mode != JS_MULTI_0802)
+			JS_PAR_ECTRL_OUT(0x35,info->port);	/* enable PS/2 mode: */
 		JS_PAR_CTRL_OUT(JS_DB9_NORMAL,info->port);	/* reverse direction, enable Select signal */
 	}
 		
@@ -260,12 +275,11 @@
 
 	if (!MOD_IN_USE) {
 
-		JS_PAR_CTRL_OUT(0x00,info->port);	/* normal direction */
-		JS_PAR_ECTRL_OUT(0x15,info->port);	/* enable normal mode */
+		JS_PAR_CTRL_OUT(0x00,info->port);		/* normal direction */
+		if (info->mode != JS_MULTI_0802)
+			JS_PAR_ECTRL_OUT(0x15,info->port);	/* enable normal mode */
 
-#ifdef USE_PARPORT
 		parport_release(info->port);
-#endif
 	}
 	return 0;
 }
@@ -274,16 +288,15 @@
 void cleanup_module(void)
 {
 	struct js_db9_info *info;
+	int i;
 
-	while (js_db9_port != NULL) {
-		js_unregister_device(js_db9_port->devs[0]);
+	while (js_db9_port) {
 		info = js_db9_port->info;
-#ifdef USE_PARPORT
+
+		for (i = 0; i < js_db9_port->ndevs; i++)
+			if (js_db9_port->devs[i])
+				js_unregister_device(js_db9_port->devs[i]);
 		parport_unregister_device(info->port);
-#else
-		release_region(info->port, 3);
-		release_region(info->port+0x402, 1);
-#endif
 		js_db9_port = js_unregister_port(js_db9_port);
 	}
 
@@ -295,17 +308,17 @@
  * db9 gamepads.
  */
 
-static void __init js_db9_init_corr(struct js_corr **corr)
+static void __init js_db9_init_corr(struct js_corr *corr)
 {
 	int i;
 
 	for (i = 0; i < 2; i++) {
-		corr[0][i].type = JS_CORR_BROKEN;
-		corr[0][i].prec = 0;
-		corr[0][i].coef[0] = 0;
-		corr[0][i].coef[1] = 0;
-		corr[0][i].coef[2] = (1 << 29);
-		corr[0][i].coef[3] = (1 << 29);
+		corr[i].type = JS_CORR_BROKEN;
+		corr[i].prec = 0;
+		corr[i].coef[0] = 0;
+		corr[i].coef[1] = 0;
+		corr[i].coef[2] = (1 << 29);
+		corr[i].coef[3] = (1 << 29);
 	}
 }
 
@@ -316,75 +329,76 @@
 static struct js_port __init *js_db9_probe(int *config, struct js_port *port)
 {
 	struct js_db9_info info;
-	char buttons[JS_MAX_PAD] = {0,1,2,4,0,6,7,8,1};
+	struct parport *pp;
+	int i;
+	char buttons[JS_MAX_PAD] = {0,1,2,4,0,6,8,8,1,1};
 	char *name[JS_MAX_PAD] = {NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad",
-					NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick"};
+					NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick",
+					"Multisystem (0.8.0.2-dual) joystick"};
 
 	if (config[0] < 0) return port;
 	if (config[1] < 0 || config[1] >= JS_MAX_PAD || !name[config[1]]) return port;
 
-#ifdef USE_PARPORT
-	{
-		struct parport *pp;
+	info.mode = config[1];
 
-		if (config[0] > 0x10)
-			for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next);
-		else
-			for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) config[0]--;
-
-		if (pp == NULL) {
-			printk(KERN_ERR "joy-db9: no such parport\n");
-			return port;
-		}
-
-		if (!(pp->modes & (PARPORT_MODE_PCPS2 | PARPORT_MODE_PCECPPS2))) {
-			printk(KERN_ERR "js-db9: specified parport is not bidirectional\n");
-			return port;
-		}
-
-		info.port = parport_register_device(pp, "joystick (db9)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
-		if (!info.port)
-			return port;
+	if (config[0] > 0x10)
+		for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next);
+	else
+		for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--;
+
+	if (!pp) {
+		printk(KERN_ERR "joy-db9: no such parport\n");
+		return port;
 	}
-#else
-	info.port = config[0];
-	if (check_region(info.port, 3) || check_region(info.port+0x402,1)) return port;
-	request_region(info.port, 3, "joystick (db9)");
-	request_region(info.port+0x402, 1, "joystick (db9)");
-#endif
 
-	info.mode = config[1];
+	if (!(pp->modes & (PARPORT_MODE_PCPS2 | PARPORT_MODE_PCECPPS2)) && info.mode != JS_MULTI_0802) {
+		printk(KERN_ERR "js-db9: specified parport is not bidirectional\n");
+		return port;
+	}
 
-	port = js_register_port(port, &info, 1, sizeof(struct js_db9_info), js_db9_read);
+	info.port = parport_register_device(pp, "joystick (db9)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+	if (!info.port)
+		return port;
+
+	port = js_register_port(port, &info, 1 + (info.mode == JS_MULTI_0802_2), sizeof(struct js_db9_info), js_db9_read);
+
+	for (i = 0; i < 1 + (info.mode == JS_MULTI_0802_2); i++) {
+		printk(KERN_INFO "js%d: %s on %s\n",
+			js_register_device(port, i, 2, buttons[info.mode], name[info.mode], js_db9_open, js_db9_close),
+			name[info.mode], info.port->port->name);
 
-#ifdef USE_PARPORT
-	printk(KERN_INFO "js%d: %s on %s\n",
-		js_register_device(port, 0, 2, buttons[info.mode], name[info.mode], js_db9_open, js_db9_close),
-		name[info.mode], info.port->port->name);
-#else
-	printk(KERN_INFO "js%d: %s at %#x\n",
-		js_register_device(port, 0, 2, buttons[info.mode], name[info.mode], js_db9_open, js_db9_close),
-		name[info.mode], info.port);
-#endif
+		js_db9_init_corr(port->corr[i]);
+	}
 
-	js_db9_init_corr(port->corr);
 
 	return port;
 }
 
 #ifndef MODULE
-void __init js_db9_setup(char *str, int *ints)
+int __init js_db9_setup(SETUP_PARAM)
 {
 	int i;
-
-	if (!strcmp(str,"js_db9"))
-		for (i = 0; i <= ints[0] && i < 2; i++) js_db9[i] = ints[i+1];
-	if (!strcmp(str,"js_db9_2"))
-		for (i = 0; i <= ints[0] && i < 2; i++) js_db9_2[i] = ints[i+1];
-	if (!strcmp(str,"js_db9_3"))
-		for (i = 0; i <= ints[0] && i < 2; i++) js_db9_3[i] = ints[i+1];
-
+	SETUP_PARSE(2);
+	for (i = 0; i <= ints[0] && i < 2; i++) js_db9[i] = ints[i+1];
+	return 1;
+}
+int __init js_db9_setup_2(SETUP_PARAM)
+{
+	int i;
+	SETUP_PARSE(2);
+	for (i = 0; i <= ints[0] && i < 2; i++) js_db9_2[i] = ints[i+1];
+	return 1;
+}
+int __init js_db9_setup_3(SETUP_PARAM)
+{
+	int i;
+	SETUP_PARSE(2);
+	for (i = 0; i <= ints[0] && i < 2; i++) js_db9_3[i] = ints[i+1];
+	return 1;
 }
+__setup("js_db9=", js_db9_setup);
+__setup("js_db9_2=", js_db9_setup_2);
+__setup("js_db9_3=", js_db9_setup_3);
 #endif
 
 #ifdef MODULE
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-gravis.c linux.14p16/drivers/char/joystick/joy-gravis.c
--- linux.vanilla/drivers/char/joystick/joy-gravis.c	Wed Dec  2 03:05:05 1998
+++ linux.14p16/drivers/char/joystick/joy-gravis.c	Tue Dec 21 00:31:12 1999
@@ -1,7 +1,9 @@
 /*
  *  joy-gravis.c  Version 1.2
  *
- *  Copyright (c) 1998 Vojtech Pavlik
+ *  Copyright (c) 1998-1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
  */
 
 /*
@@ -25,7 +27,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  */
 
@@ -37,15 +39,16 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/init.h>
 
 #define JS_GR_MODE_GPP		1
 #define JS_GR_LENGTH_GPP	24
-#define JS_GR_STROBE_GPP	75
+#define JS_GR_STROBE_GPP	400
 
 #define JS_GR_MODE_XT		2
 #define JS_GR_MODE_BD		3
 #define JS_GR_LENGTH_XT		4
-#define JS_GR_STROBE_XT		30
+#define JS_GR_STROBE_XT		200
 #define JS_GR_MAX_CHUNKS_XT	10	
 #define JS_GR_MAX_BITS_XT	30	
 
@@ -63,37 +66,36 @@
 
 static int js_gr_gpp_read_packet(int io, int shift, unsigned int *data)
 {
-	unsigned int t, t1;
+	unsigned long flags;
 	unsigned char u, v;
+	unsigned int t, p;
 	int i;
-	unsigned long flags;
-
-	int strobe = (js_time_speed * JS_GR_STROBE_GPP) >> 10;
 
 	i = 0;
 	data[0] = 0;
+	p = t = JS_GR_STROBE_GPP;
+	p += JS_GR_STROBE_GPP;
 
 	__save_flags(flags);
 	__cli();
-	u = inb(io) >> shift;
-	t = js_get_time();
+
+	v = inb(io) >> shift;
 
 	do {
-		v = (inb(io) >> shift) & 3;
-		t1 = js_get_time();
-		if ((u ^ v) & u & 1) {
+		t--;
+		u = v; v = (inb(io) >> shift) & 3;
+		if (~v & u & 1) {
 			data[0] |= (v >> 1) << i++;
-			t = t1;
+			p = t = (p - t) << 1;
 		}
-		u = v;
-	} while (i < JS_GR_LENGTH_GPP && js_delta(t1,t) < strobe);
+	} while (i < JS_GR_LENGTH_GPP && t > 0);
 
 	__restore_flags(flags);
 
 	if (i < JS_GR_LENGTH_GPP) return -1;
 
 	for (i = 0; i < JS_GR_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++)
-		data[0] = data[0] >> 1 | (data[0] & 1) << 23;
+		data[0] = data[0] >> 1 | (data[0] & 1) << (JS_GR_LENGTH_GPP - 1);
 
 	return -(i == JS_GR_LENGTH_GPP);
 }
@@ -104,35 +106,36 @@
 
 static int js_gr_xt_read_packet(int io, int shift, unsigned int *data)
 {
-	unsigned int t, t1;
-	unsigned char u, v, w;
 	unsigned int i, j, buf, crc;
+	unsigned char u, v, w;
 	unsigned long flags;
+	unsigned int t, p;
 	char status;
 
-	int strobe = (js_time_speed * JS_GR_STROBE_XT) >> 10;
-
 	data[0] = data[1] = data[2] = data[3] = 0;
 	status = buf = i = j = 0;
+	p = t = JS_GR_STROBE_XT;
+	p += JS_GR_STROBE_XT;
 
 	__save_flags(flags);
 	__cli();
 
 	v = w = (inb(io) >> shift) & 3;
-	t = js_get_time();
 
 	do {
+		t--;
 		u = (inb(io) >> shift) & 3;
-		t1 = js_get_time();
 
 		if (u ^ v) {
 
 			if ((u ^ v) & 1) {
+				p = t = (p - t) << 2;
 				buf = (buf << 1) | (u >> 1);
 				i++;
 			} else 
 
 			if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) {
+				p = t = (p - t) << 2;
 				if (i == 20) {
 					crc = buf ^ (buf >> 7) ^ (buf >> 14);
 					if (!((crc ^ (0x25cb9e70 >> ((crc >> 2) & 0x1c))) & 0xf)) {
@@ -145,12 +148,11 @@
 				i = 0;
 			}
 
-			t = t1;
 			w = v;
 			v = u;
 		}
 
-	} while (status != 0xf && i < JS_GR_MAX_BITS_XT && j < JS_GR_MAX_CHUNKS_XT && js_delta(t1,t) < strobe);
+	} while (status != 0xf && i < JS_GR_MAX_BITS_XT && j < JS_GR_MAX_CHUNKS_XT && t > 0);
 
 	__restore_flags(flags);
 
@@ -320,7 +322,7 @@
 }
 
 /*
- * js_gr_probe() probes fro GrIP joysticks.
+ * js_gr_probe() probes for GrIP joysticks.
  */
 
 static struct js_port __init *js_gr_probe(int io, struct js_port *port)
@@ -389,9 +391,9 @@
 	int i;
 	struct js_gr_info *info;
 
-	while (js_gr_port != NULL) {
+	while (js_gr_port) {
 		for (i = 0; i < js_gr_port->ndevs; i++)
-			if (js_gr_port->devs[i] != NULL)
+			if (js_gr_port->devs[i])
 				js_unregister_device(js_gr_port->devs[i]);
 		info = js_gr_port->info;
 		release_region(info->io, 1);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-lightning.c linux.14p16/drivers/char/joystick/joy-lightning.c
--- linux.vanilla/drivers/char/joystick/joy-lightning.c	Wed Dec  2 03:05:05 1998
+++ linux.14p16/drivers/char/joystick/joy-lightning.c	Tue Dec 21 00:31:12 1999
@@ -1,7 +1,9 @@
 /*
  *  joy-lightning.c  Version 1.2
  *
- *  Copyright (c) 1998 Vojtech Pavlik
+ *  Copyright (c) 1998-1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
  */
 
 /*
@@ -26,7 +28,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  */
 
@@ -38,6 +40,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/init.h>
 
 #define JS_L4_PORT		0x201
 #define JS_L4_SELECT_ANALOG	0xa4
@@ -52,10 +55,10 @@
 
 static struct js_port* __initdata js_l4_port = NULL;
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_PARM(js_l4, "2-24i");
 
-static int js_l4[]={-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0};
+static int __initdata js_l4[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 };
 
 #include "joy-analog.h"
 
@@ -70,11 +73,10 @@
 
 static int js_l4_wait_ready(void)
 {
-	unsigned int t, t1, timeout;
-	timeout = (JS_L4_TIMEOUT * js_time_speed) >> 10;
-	t = t1 = js_get_time();
-	while ((inb(JS_L4_PORT) & JS_L4_BUSY) && (js_delta(t1 = js_get_time(), t) < timeout));
-	return -(js_delta(t1, t) >= timeout);
+	unsigned int t;
+	t = JS_L4_TIMEOUT;
+	while ((inb(JS_L4_PORT) & JS_L4_BUSY) && t > 0) t--;
+	return -(t<=0);
 }
 
 /*
@@ -255,14 +257,14 @@
 
 	port = js_register_port(port, info, numdev, sizeof(struct js_l4_info), js_l4_read);
 
+	info = port->info;
+
 	for (i = 0; i < numdev; i++)
 		printk(KERN_INFO "js%d: %s on L4 port %d\n",
 			js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an),
 				js_an_name(i, &info->an), js_l4_open, js_l4_close),
 			js_an_name(i, &info->an), info->port);
 
-	info = port->info;
-
 	js_l4_calibrate(info);
 	js_l4_read(info, port->axes, port->buttons);
 	js_an_init_corr(&info->an, port->axes, port->corr, 0);
@@ -300,18 +302,21 @@
 
 		cards[i] = rev; 
 
-		printk(KERN_INFO "js: PDPI Lightning 4 %s card (ports %d-%d) firmware v%d.%d found at %#x\n",
+		printk(KERN_INFO "js: PDPI Lightning 4 %s card (ports %d-%d) firmware v%d.%d at %#x\n",
 			i ? "secondary" : "primary", (i << 2), (i << 2) + 3, rev >> 4, rev & 0xf, JS_L4_PORT);
 	}
 
 }
 
 #ifndef MODULE
-void __init js_l4_setup(char *str, int *ints)
+int __init js_l4_setup(SETUP_PARAM)
 {
 	int i;
+	SETUP_PARSE(24);
 	for (i = 0; i <= ints[0] && i < 24; i++) js_l4[i] = ints[i+1];
+	return 1;
 }
+__setup("js_l4=", js_l4_setup);
 #endif
 
 #ifdef MODULE
@@ -333,7 +338,7 @@
 			js_l4_port = js_l4_probe(cards, i, 0, 0, js_l4_port);
 	}
 
-	if (js_l4_port == NULL) {
+	if (!js_l4_port) {
 #ifdef MODULE
 		printk(KERN_WARNING "joy-lightning: no joysticks found\n");
 #endif
@@ -352,9 +357,9 @@
 	int cal[4] = {59, 59, 59, 59};
 	struct js_l4_info *info;
 
-	while (js_l4_port != NULL) {
+	while (js_l4_port) {
 		for (i = 0; i < js_l4_port->ndevs; i++)
-			if (js_l4_port->devs[i] != NULL)
+			if (js_l4_port->devs[i])
 				js_unregister_device(js_l4_port->devs[i]);
 		info = js_l4_port->info;
 		js_l4_setcal(info->port, cal);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-logitech.c linux.14p16/drivers/char/joystick/joy-logitech.c
--- linux.vanilla/drivers/char/joystick/joy-logitech.c	Wed Dec  2 03:05:05 1998
+++ linux.14p16/drivers/char/joystick/joy-logitech.c	Tue Dec 21 00:31:12 1999
@@ -1,12 +1,14 @@
 /*
  *  joy-logitech.c  Version 1.2
  *
- *  Copyright (c) 1998 Vojtech Pavlik
+ *  Copyright (c) 1998-1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
  */
 
 /*
  * This is a module for the Linux joystick driver, supporting
- * Logitech Digital joystick family.
+ * Logitech ADI joystick family.
  */
 
 /*
@@ -25,7 +27,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  */
 
@@ -38,113 +40,175 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
 
-#define JS_LT_MAX_START		250
-#define JS_LT_MAX_STROBE	25
-#define JS_LT_MAX_LENGTH	72
+/*
+ * Times array sizes, flags, ids.
+ */
+
+#undef JS_LT_DEBUG
+
+#define JS_LT_MAX_START		400	/* Trigger to packet timeout [400us] */
 
-#define JS_LT_MAX_DELAY		12000
+#define JS_LT_MAX_LENGTH	256
+#define JS_LT_MIN_LENGTH	8
+#define JS_LT_MIN_LEN_LENGTH	10
+#define JS_LT_MIN_ID_LENGTH	66
+#define JS_LT_MAX_NAME_LENGTH	16
 
-#define JS_LT_MODE_WMED		1
-#define JS_LT_MODE_CM2		2
-#define JS_LT_MODE_TPD		3
+#define JS_LT_INIT_DELAY	10	/* Delay after init packet [10ms] */
+#define JS_LT_DATA_DELAY	4	/* Delay after data packet [4ms] */
 
-static int js_lt_seq_init[] __initdata = { 6000, 11000, 7000, 9000, 6000, 11000, 7000, 9000, 0 };
-static int js_lt_seq_reset[] __initdata = { 2000, 3000, 2000, 3000, 0 };
+#define JS_LT_FLAG_HAT		0x04
+#define JS_LT_FLAG_10BIT	0x08
 
-static int js_lt_port_list[] __initdata = {0x201, 0};
+#define JS_LT_ID_WMED		0x00
+#define JS_LT_ID_TPD		0x01
+#define JS_LT_ID_WMI		0x04
+#define JS_LT_ID_WGP		0x06
+#define JS_LT_ID_WM3D		0x07
+#define JS_LT_ID_WGPE		0x08
+
+#define JS_LT_BUG_BUTTONS	0x01
+#define JS_LT_BUG_LONGID	0x02
+#define JS_LT_BUG_LONGDATA	0x04
+#define JS_LT_BUG_IGNTRIG	0x08
+
+/*
+ * Port probing variables.
+ */
+
+static int js_lt_port_list[] __initdata = { 0x201, 0 };
 static struct js_port* js_lt_port __initdata = NULL;
 
+/*
+ * Device names.
+ */
+
+#define JS_LT_MAX_ID		10
+
+static char *js_lt_names[] = {	"WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2",
+				"WingMan Interceptor", "WingMan Formula", "WingMan GamePad", 
+				"WingMan Extreme Digital 3D", "WingMan GamePad Extreme", 
+				"WingMan GamePad USB", "Unknown Device %#x"};
+
+/*
+ * Hat to axis conversion arrays.
+ */
+
 static struct {
 	int x;
 	int y;
 } js_lt_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
 
+/*
+ * Per-port information.
+ */
+
 struct js_lt_info {
-	int io;
-	unsigned char mode;
+	int  io;
+	int  length[2];
+	int  ret[2];
+	int  idx[2];
+	unsigned char id[2];
+	char buttons[2];
+	char axes10[2];
+	char axes8[2];
+	char pad[2];
+	char hats[2];
+	char name[2][JS_LT_MAX_NAME_LENGTH];
+	unsigned char data[2][JS_LT_MAX_LENGTH];
+	char bugs[2];
 };
 
 /*
- * js_lt_read_packet() reads a Logitech packet.
+ * js_lt_read_packet() reads a Logitech ADI packet.
  */
 
-static int js_lt_read_packet(int io, __u64 *data)
+static void js_lt_read_packet(struct js_lt_info *info)
 {
-
-	static unsigned char buf[JS_LT_MAX_LENGTH];
-	unsigned char u, v, w, mask = 0;
-	int i;
+	unsigned char u, v, w, x, z;
+	int t[2], s[2], p[2], i;
 	unsigned long flags;
-	unsigned int t, t1;
-
-	int start = (js_time_speed * JS_LT_MAX_START) >> 10;
-	int strobe = (js_time_speed * JS_LT_MAX_STROBE) >> 10;
 
-	u = inb(io) >> 4;
-
-	if (u == 0xc) mask = 0x10;
-	if (u == 0x0) mask = 0x50;
-	if (!mask) return 0;
-
-	i = 0;
+	for (i = 0; i < 2; i++) {
+		info->ret[i] = -1;
+		p[i] = t[i] = JS_LT_MAX_START;
+		s[i] = 0;
+	}
 
 	__save_flags(flags);
 	__cli();
 
-	outb(0xff,io);
+	outb(0xff, info->io);
+	v = z = inb(info->io);
 
-	u = inb(io);
-	t = js_get_time();
+	do {
+		u = v;
+		w = u ^ (v = x = inb(info->io));
+		for (i = 0; i < 2; i++, w >>= 2, x >>= 2) {
+			t[i]--;
+			if ((w & 0x30) && s[i]) {
+				if ((w & 0x30) < 0x30 && info->ret[i] < JS_LT_MAX_LENGTH && t[i] > 0) {
+					info->data[i][++info->ret[i]] = w;
+					p[i] = t[i] = (p[i] - t[i]) << 1;
+				} else t[i] = 0;
+			} else if (!(x & 0x30)) s[i] = 1;
+		}
+	} while (t[0] > 0 || t[1] > 0);
 
-	if ((u & 0xc) != 0xc) mask = 0x10;
+	__restore_flags(flags);
 
-	do {
-		u = inb(io);
-		t1 = js_get_time();
-	} while ((((u >> 1) ^ u) & mask) != mask && js_delta(t1,t) < start);
+	for (i = 0; i < 2; i++, z >>= 2)
+		if ((z & 0x30) && info->ret[i] > 0)
+			info->bugs[i] |= JS_LT_BUG_BUTTONS;
+
+#ifdef JS_LT_DEBUG
+	printk(KERN_DEBUG "joy-logitech: read %d %d bits\n", info->ret[0], info->ret[1]);
+	printk(KERN_DEBUG "joy-logitech: stream0:");
+	for (i = 0; i <= info->ret[0]; i++) printk("%d", (info->data[0][i] >> 5) & 1);
+	printk("\n");
+	printk(KERN_DEBUG "joy-logitech: stream1:");
+	for (i = 0; i <= info->ret[1]; i++) printk("%d", (info->data[1][i] >> 5) & 1);
+	printk("\n");
+#endif
 
-	t = t1;
+	return;
+}
 
-	do {
-		v = inb(io);
-		t1 = js_get_time();
-		w = u ^ v;
-		if ((((w >> 1) ^ w) & mask) == mask) {
-			buf[i++] = w;
-			t = t1;
-			u = v;
-		}
-	} while (i < JS_LT_MAX_LENGTH && js_delta(t1,t) < strobe);
+/*
+ * js_lt_move_bits() detects a possible 2-stream mode, and moves
+ * the bits accordingly. 
+ */
 
-	__restore_flags(flags);
+static void js_lt_move_bits(struct js_lt_info *info, int length)
+{
+	int i;
 
-	t = i;
-	*data = 0;
+ 	info->idx[0] = info->idx[1] = 0;
 
-	if (mask == 0x10) {
-		for (i = 0; i < t; i++)
-			*data = ((buf[i] >> 5) & 1) | (*data << 1);
-		return t;
-	}
-	if (mask == 0x50) {
-		for (i = 0; i < t; i++)
-			*data = ((__u64)(buf[i] & 0x20) << (t - 5)) | (buf[i] >> 7) | (*data << 1);
-		return t << 1;
-	}
-	return 0;
+	if (info->ret[0] <= 0 || info->ret[1] <= 0) return;
+	if (info->data[0][0] & 0x20 || ~info->data[1][0] & 0x20) return;
+
+	for (i = 1; i <= info->ret[1]; i++)
+		info->data[0][((length - 1) >> 1) + i + 1] = info->data[1][i];
+
+	info->ret[0] += info->ret[1];
+	info->ret[1] = -1;
 }
 
 /*
- * js_lt_reverse() reverses the order of bits in a byte.
+ * js_lt_get_bits() gathers bits from the data packet.
  */
 
-static unsigned char js_lt_reverse(unsigned char u)
+static inline int js_lt_get_bits(struct js_lt_info *info, int device, int count)
 {
-	u = ((u & 0x0f) << 4) | ((u >> 4) & 0x0f);
-	u = ((u & 0x33) << 2) | ((u >> 2) & 0x33);
-	u = ((u & 0x55) << 1) | ((u >> 1) & 0x55);
-	return u;
+	int bits = 0;
+	int i;
+	if ((info->idx[device] += count) > info->ret[device]) return 0;
+	for (i = 0; i < count; i++) bits |= ((info->data[device][info->idx[device] - i] >> 5) & 1) << i; 
+	return bits;
 }
 
 /*
@@ -154,54 +218,61 @@
 static int js_lt_read(void *xinfo, int **axes, int **buttons)
 {
 	struct js_lt_info *info = xinfo;
-	__u64 data;
-	int hat;
-
-	switch (info->mode) {
-
-		case JS_LT_MODE_TPD:
-
-			if (js_lt_read_packet(info->io, &data) != 20) return -1;
-
-			axes[0][0] = ((data >> 6) & 1) - ((data >> 4) & 1);
-			axes[0][1] = ((data >> 5) & 1) - ((data >> 7) & 1);
-
-			buttons[0][0] = js_lt_reverse((data & 0x0f) | ((data >> 4) & 0xf0));
-
-			return 0;
+	int i, j, k, l, t;
+	int ret = 0;
 
-		case JS_LT_MODE_WMED:
+	js_lt_read_packet(info);
+	js_lt_move_bits(info, info->length[0]);
 
-			if (js_lt_read_packet(info->io, &data) != 42) return -1;
-			if ((hat = data & 0xf) > 8) return -1;
+	for (i = 0; i < 2; i++) {
 
-			axes[0][0] = (data >> 26) & 0xff;
-			axes[0][1] = (data >> 18) & 0xff;
-			axes[0][2] = (data >> 10) & 0xff;
-			axes[0][3] = js_lt_hat_to_axis[hat].x;
-			axes[0][4] = js_lt_hat_to_axis[hat].y;
-
-			buttons[0][0] = js_lt_reverse((data >> 2) & 0xfc);
-
-			return 0;
-
-		case JS_LT_MODE_CM2:
-
-			if (js_lt_read_packet(info->io, &data) != 64) return -1;
+		if (!info->length[i]) continue;
+		
+		if (info->length[i] > info->ret[i] ||
+		    info->id[i] != (js_lt_get_bits(info, i, 4) | (js_lt_get_bits(info, i, 4) << 4))) {
+			ret = -1;
+			continue;
+		}
 
-			axes[0][0] = (data >> 48) & 0xff;
-			axes[0][1] = (data >> 40) & 0xff;
-			axes[0][2] = (data >> 32) & 0xff;
-			axes[0][3] = (data >> 24) & 0xff;
-			axes[0][4] = (data >> 16) & 0xff;
-			axes[0][5] = (data >>  8) & 0xff;
+		if (info->length[i] < info->ret[i])
+			info->bugs[i] |= JS_LT_BUG_LONGDATA;
+			
+		k = l = 0;
+
+		for (j = 0; j < info->axes10[i]; j++) 
+			axes[i][k++] = js_lt_get_bits(info, i, 10);
+
+		for (j = 0; j < info->axes8[i]; j++) 
+			axes[i][k++] = js_lt_get_bits(info, i, 8);
+
+		for (j = 0; j <= (info->buttons[i] - 1) >> 5; j++) buttons[i][j] = 0;
+
+		for (j = 0; j < info->buttons[i] && j < 63; j++) {
+			if (j == info->pad[i]) {
+				t = js_lt_get_bits(info, i, 4);
+				axes[i][k++] = ((t >> 2) & 1) - ( t       & 1);
+				axes[i][k++] = ((t >> 1) & 1) - ((t >> 3) & 1);
+			}
+			buttons[i][l >> 5] |= js_lt_get_bits(info, i, 1) << (l & 0x1f);
+			l++;
+		}
 
-			buttons[0][0] = js_lt_reverse(data & 0xff);
+		for (j = 0; j < info->hats[i]; j++) {
+			if((t = js_lt_get_bits(info, i, 4)) > 8) {
+				if (t != 15) ret = -1; /* Hat press */
+				t = 0;
+			}
+			axes[i][k++] = js_lt_hat_to_axis[t].x;
+			axes[i][k++] = js_lt_hat_to_axis[t].y;
+		}
 
-			return 0;
+		for (j = 63; j < info->buttons[i]; j++) {
+			buttons[i][l >> 5] |= js_lt_get_bits(info, i, 1) << (l & 0x1f);
+			l++;
+		}
 	}
 
-	return -1;
+	return ret;
 }
 
 /*
@@ -225,15 +296,18 @@
 }
 
 /*
- * js_lt_trigger_sequence() sends a trigger & delay sequence
- * to reset/initialize a Logitech joystick.
+ * js_lt_init_digital() sends a trigger & delay sequence
+ * to reset and initialize a Logitech joystick into digital mode.
  */
 
-static void __init js_lt_trigger_sequence(int io, int *seq)
+static void __init js_lt_init_digital(int io)
 {
-	while (*seq) {
+	int seq[] = { 3, 2, 3, 10, 6, 11, 7, 9, 11, 0 };
+	int i;
+
+	for (i = 0; seq[i]; i++) {
 		outb(0xff,io);
-		udelay(*seq++);
+		mdelay(seq[i]);
 	}
 }
 
@@ -242,35 +316,45 @@
  * Logitech joysticks.
  */
 
-static void __init js_lt_init_corr(int num_axes, int mode, int **axes, struct js_corr **corr)
+static void __init js_lt_init_corr(int id, int naxes10, int naxes8, int naxes1, int *axes, struct js_corr *corr)
 {
 	int j;
-
-	for (j = 0; j < num_axes; j++) {
-		corr[0][j].type = JS_CORR_BROKEN;
-		corr[0][j].prec = 2;
-		corr[0][j].coef[0] = axes[0][j] - 8;
-		corr[0][j].coef[1] = axes[0][j] + 8;
-		corr[0][j].coef[2] = (1 << 29) / (127 - 32);
-		corr[0][j].coef[3] = (1 << 29) / (127 - 32);
+	
+	if (id == JS_LT_ID_WMED) axes[2] = 128;	/* Throttle fixup */
+	if (id == JS_LT_ID_WMI)  axes[2] = 512;
+	if (id == JS_LT_ID_WM3D) axes[3] = 128;	
+
+	if (id == JS_LT_ID_WGPE) {		/* Tilt fixup */
+		axes[0] = 512;
+		axes[1] = 512;
 	}
 
-	switch (mode) {
-		case JS_LT_MODE_TPD:  j = 0; break;
-		case JS_LT_MODE_WMED: j = 3; break;
-		case JS_LT_MODE_CM2:  j = 6; break;
-		default:	      j = 0; break;
+	for (j = 0; j < naxes10; j++) {
+		corr[j].type = JS_CORR_BROKEN;
+		corr[j].prec = 2;
+		corr[j].coef[0] = axes[j] - 16;
+		corr[j].coef[1] = axes[j] + 16;
+		corr[j].coef[2] = (1 << 29) / (256 - 32);
+		corr[j].coef[3] = (1 << 29) / (256 - 32);
 	}
 
-	for (; j < num_axes; j++) {
-		corr[0][j].type = JS_CORR_BROKEN;
-		corr[0][j].prec = 0;
-		corr[0][j].coef[0] = 0;
-		corr[0][j].coef[1] = 0;
-		corr[0][j].coef[2] = (1 << 29);
-		corr[0][j].coef[3] = (1 << 29);
+	for (; j < naxes8 + naxes10; j++) {
+		corr[j].type = JS_CORR_BROKEN;
+		corr[j].prec = 1;
+		corr[j].coef[0] = axes[j] - 2;
+		corr[j].coef[1] = axes[j] + 2;
+		corr[j].coef[2] = (1 << 29) / (64 - 16);
+		corr[j].coef[3] = (1 << 29) / (64 - 16);
 	}
 
+	for (; j < naxes1 + naxes8 + naxes10; j++) {
+		corr[j].type = JS_CORR_BROKEN;
+		corr[j].prec = 0;
+		corr[j].coef[0] = 0;
+		corr[j].coef[1] = 0;
+		corr[j].coef[2] = (1 << 29);
+		corr[j].coef[3] = (1 << 29);
+	}
 }
 
 /*
@@ -279,61 +363,157 @@
 
 static struct js_port __init *js_lt_probe(int io, struct js_port *port)
 {
-	struct js_lt_info info;
-	char *name;
-	int axes, buttons, i;
-	__u64 data;
-	unsigned char u;
+	struct js_lt_info iniinfo;
+	struct js_lt_info *info = &iniinfo;
+	char name[32];
+	int i, j, t;
 
 	if (check_region(io, 1)) return port;
 
-	if (((u = inb(io)) & 3) == 3) return port;
-	outb(0xff,io);
-	if (!((inb(io) ^ u) & ~u & 0xf)) return port;
-
-	if (!(i = js_lt_read_packet(io, &data))) {
-		udelay(JS_LT_MAX_DELAY);
-		js_lt_trigger_sequence(io, js_lt_seq_reset);
-		js_lt_trigger_sequence(io, js_lt_seq_init);
-		i = js_lt_read_packet(io, &data);
-	}
+	js_lt_init_digital(io);
+
+	memset(info, 0, sizeof(struct js_lt_info));
+
+	info->length[0] = info->length[1] = JS_LT_MAX_LENGTH;
+
+	info->io = io;
+	js_lt_read_packet(info);
+	
+	if (info->ret[0] >= JS_LT_MIN_LEN_LENGTH)
+		js_lt_move_bits(info, js_lt_get_bits(info, 0, 10));
+
+	info->length[0] = info->length[1] = 0;
+
+	for (i = 0; i < 2; i++) {
+
+		if (info->ret[i] < JS_LT_MIN_ID_LENGTH) continue; /* Minimum ID packet length */
+
+		if (info->ret[i] < (t = js_lt_get_bits(info, i, 10))) {
+			printk(KERN_WARNING "joy-logitech: Short ID packet: reported: %d != read: %d\n",
+				t, info->ret[i]); 
+			continue;
+		}
+
+		if (info->ret[i] > t)
+			info->bugs[i] |= JS_LT_BUG_LONGID;
+
+#ifdef JS_LT_DEBUG
+		printk(KERN_DEBUG "joy-logitech: id %d length %d", i, t);
+#endif
+
+		info->id[i] = js_lt_get_bits(info, i, 4) | (js_lt_get_bits(info, i, 4) << 4);
+
+		if ((t = js_lt_get_bits(info, i, 4)) & JS_LT_FLAG_HAT) info->hats[i]++;
+
+#ifdef JS_LT_DEBUG
+		printk(KERN_DEBUG "joy-logitech: id %d flags %d", i, t);
+#endif
+
+		if ((info->length[i] = js_lt_get_bits(info, i, 10)) >= JS_LT_MAX_LENGTH) {
+			printk(KERN_WARNING "joy-logitech: Expected packet length too long (%d).\n",
+				info->length[i]);
+			continue;
+		}
+
+		if (info->length[i] < JS_LT_MIN_LENGTH) {
+			printk(KERN_WARNING "joy-logitech: Expected packet length too short (%d).\n",
+				info->length[i]);
+			continue;
+		}
+
+		info->axes8[i] = js_lt_get_bits(info, i, 4);
+		info->buttons[i] = js_lt_get_bits(info, i, 6);
+
+		if (js_lt_get_bits(info, i, 6) != 8 && info->hats[i]) {
+			printk(KERN_WARNING "joy-logitech: Other than 8-dir POVs not supported yet.\n");
+			continue;
+		}
+
+		info->buttons[i] += js_lt_get_bits(info, i, 6);
+		info->hats[i] += js_lt_get_bits(info, i, 4);
+
+		j = js_lt_get_bits(info, i, 4);
+
+		if (t & JS_LT_FLAG_10BIT) {
+			info->axes10[i] = info->axes8[i] - j;
+			info->axes8[i] = j;
+		}
+
+		t = js_lt_get_bits(info, i, 4);
+
+		for (j = 0; j < t; j++)
+			info->name[i][j] = js_lt_get_bits(info, i, 8);
+		info->name[i][j] = 0;
+
+		switch (info->id[i]) {
+			case JS_LT_ID_TPD:
+				info->pad[i] = 4;
+				info->buttons[i] -= 4;
+				break;
+			case JS_LT_ID_WGP:
+				info->pad[i] = 0;
+				info->buttons[i] -= 4;
+				break;
+			default:
+				info->pad[i] = -1;
+				break;
+		}
+
+		if (info->length[i] != 
+			(t = 8 + info->buttons[i] + info->axes10[i] * 10 + info->axes8[i] * 8 +
+			info->hats[i] * 4 + (info->pad[i] != -1) * 4)) {
+			printk(KERN_WARNING "js%d: Expected lenght %d != data length %d\n", i, t, info->length[i]);
+		}
 
-	switch (i) {
-		case 0:
-			return port;
-		case 20:
-			info.mode = JS_LT_MODE_TPD;
-			axes = 2; buttons = 8; name = "Logitech ThunderPad Digital";
-			break;
-		case 42:
-			info.mode = JS_LT_MODE_WMED;
-			axes = 5; buttons = 6; name = "Logitech WingMan Extreme Digital";
-			break;
-		case 64:
-			info.mode = JS_LT_MODE_CM2;
-			axes = 6; buttons = 8; name = "Logitech CyberMan 2";
-			break;
-		case 72:
-		case 144:
-			return port;
-		default:
-			printk(KERN_WARNING "joy-logitech: unknown joystick device detected "
-				"(io=%#x, count=%d, data=0x%08x%08x), contact <vojtech@ucw.cz>\n",
-				io, i, (int)(data >> 32), (int)(data & 0xffffffff));
-			return port;
 	}
 
-	info.io = io;
+	if (!info->length[0] && !info->length[1])
+		return port;
 
 	request_region(io, 1, "joystick (logitech)");
-	port = js_register_port(port, &info, 1, sizeof(struct js_lt_info), js_lt_read);
-	printk(KERN_INFO "js%d: %s at %#x\n",
-		js_register_device(port, 0, axes, buttons, name, js_lt_open, js_lt_close), name, io);
 
-	udelay(JS_LT_MAX_DELAY);
+	port = js_register_port(port, info, 2, sizeof(struct js_lt_info), js_lt_read);
+	info = port->info;
+
+	for (i = 0; i < 2; i++)
+		if (info->length[i] > 0) {
+			sprintf(name, info->id[i] < JS_LT_MAX_ID ?
+				js_lt_names[info->id[i]] : js_lt_names[JS_LT_MAX_ID], info->id[i]); 
+			printk(KERN_INFO "js%d: %s [%s] at %#x\n",
+				js_register_device(port, i,
+					info->axes10[i] + info->axes8[i] + ((info->hats[i] + (info->pad[i] >= 0)) << 1),
+					info->buttons[i], name, js_lt_open, js_lt_close), name, info->name[i], io);
+		}
+
+	mdelay(JS_LT_INIT_DELAY);
+	if (js_lt_read(info, port->axes, port->buttons)) {
+		if (info->ret[0] < 1) info->bugs[0] |= JS_LT_BUG_IGNTRIG;
+		if (info->ret[1] < 1) info->bugs[1] |= JS_LT_BUG_IGNTRIG;
+		mdelay(JS_LT_DATA_DELAY);
+		js_lt_read(info, port->axes, port->buttons);
+	}
 
-	js_lt_read(port->info, port->axes, port->buttons);
-	js_lt_init_corr(axes, info.mode, port->axes, port->corr);
+	for (i = 0; i < 2; i++)
+		if (info->length[i] > 0) {
+#ifdef JS_LT_DEBUG
+				printk(KERN_DEBUG "js%d: length %d ret %d id %d buttons %d axes10 %d axes8 %d "
+						  "pad %d hats %d name %s explen %d\n",
+					i, info->length[i], info->ret[i], info->id[i],
+					info->buttons[i], info->axes10[i], info->axes8[i],
+					info->pad[i], info->hats[i], info->name[i],
+					8 + info->buttons[i] + info->axes10[i] * 10 + info->axes8[i] * 8 +
+					info->hats[i] * 4 + (info->pad[i] != -1) * 4);
+#endif
+				if (info->bugs[i]) {
+					printk(KERN_WARNING "js%d: Firmware bugs detected:%s%s%s%s\n", i,
+						info->bugs[i] & JS_LT_BUG_BUTTONS ? " init_buttons" : "",
+						info->bugs[i] & JS_LT_BUG_LONGID ? " long_id" : "",
+						info->bugs[i] & JS_LT_BUG_LONGDATA ? " long_data" : "",
+						info->bugs[i] & JS_LT_BUG_IGNTRIG ? " ignore_trigger" : "");
+				}
+				js_lt_init_corr(info->id[i], info->axes10[i], info->axes8[i],
+					((info->pad[i] >= 0) + info->hats[i]) << 1, port->axes[i], port->corr[i]);
+	}
 
 	return port;
 }
@@ -359,10 +539,13 @@
 #ifdef MODULE
 void cleanup_module(void)
 {
+	int i;
 	struct js_lt_info *info;
 
-	while (js_lt_port != NULL) {
-		js_unregister_device(js_lt_port->devs[0]);
+	while (js_lt_port) {
+		for (i = 0; i < js_lt_port->ndevs; i++)
+			 if (js_lt_port->devs[i])
+				js_unregister_device(js_lt_port->devs[i]);
 		info = js_lt_port->info;
 		release_region(info->io, 1);
 		js_lt_port = js_unregister_port(js_lt_port);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-magellan.c linux.14p16/drivers/char/joystick/joy-magellan.c
--- linux.vanilla/drivers/char/joystick/joy-magellan.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/char/joystick/joy-magellan.c	Tue Dec 21 00:31:12 1999
@@ -0,0 +1,397 @@
+/*
+ *  joy-magellan.c  Version 0.1
+ *
+ *  Copyright (c) 1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This is a module for the Linux joystick driver, supporting
+ * the Magellan and Space Mouse 6dof controllers.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ *  Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/errno.h>
+#include <linux/joystick.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+
+/*
+ * Constants.
+ */
+
+#define	N_JOYSTICK_MAG		14
+#define JS_MAG_MAX_LENGTH	64
+
+/*
+ * List of Magellans.
+ */
+
+static struct js_port* js_mag_port = NULL;
+
+/*
+ * Per-Magellan data.
+ */
+
+struct js_mag_info {
+	struct tty_struct* tty;
+	struct js_port* port;
+	int idx;
+	unsigned char data[JS_MAG_MAX_LENGTH];
+	unsigned char name[JS_MAG_MAX_LENGTH];
+	char ack;
+	char used;
+};
+
+/*
+ * js_mag_crunch_nibbles() verifies that the bytes sent from the Magellan
+ * have correct upper nibbles for the lower ones, if not, the packet will
+ * be thrown away. It also strips these upper halves to simplify further
+ * processing.
+ */
+
+static int js_mag_crunch_nibbles(unsigned char *data, int count)
+{
+	static unsigned char nibbles[16] = "0AB3D56GH9:K<MN?";
+
+	do {
+		if (data[count] == nibbles[data[count] & 0xf])
+			data[count] = data[count] & 0xf;
+		else
+			return -1;
+	} while (--count);
+
+	return 0;
+}
+
+/*
+ * js_mag_process_packet() decodes packets the driver receives from the
+ * Magellan. It updates the data accordingly, and sets an ACK flag
+ * to the type of last packet received, if received OK.
+ */
+
+static void js_mag_process_packet(struct js_mag_info* info)
+{
+	int i;
+
+	if (!info->idx) return;
+
+	switch (info->data[0]) {
+
+		case 'd':				/* Axis data */
+			if (info->idx != 25) return;
+			if (js_mag_crunch_nibbles(info->data, 24)) return;
+			if (!info->port->devs[0]) return;
+			for (i = 0; i < 6; i++) {
+				info->port->axes[0][i] = 
+					( info->data[(i << 2) + 1] << 12 | info->data[(i << 2) + 2] << 8 |
+					  info->data[(i << 2) + 3] <<  4 | info->data[(i << 2) + 4] )
+					 - 32768;
+			}
+			break;
+
+		case 'e':				/* Error packet */
+			if (info->idx != 4) return;
+			if (js_mag_crunch_nibbles(info->data, 3)) return;
+			switch (info->data[1]) {
+				case 1:
+					printk(KERN_ERR "joy-magellan: Received command error packet. Failing command byte: %c\n",
+						info->data[2] | (info->data[3] << 4));
+					break;
+				case 2:
+					printk(KERN_ERR "joy-magellan: Received framing error packet.\n");
+					break;
+				default:
+					printk(KERN_ERR "joy-magellan: Received unknown error packet.\n");
+			}
+			break;
+
+		case 'k':				/* Button data */
+			if (info->idx != 4) return;
+			if (js_mag_crunch_nibbles(info->data, 3)) return;
+			if (!info->port->devs[0]) return;
+			info->port->buttons[0][0] = (info->data[1] << 1) | (info->data[2] << 5) | info->data[3];
+			break;
+
+		case 'm':				/* Mode */
+			if (info->idx != 2) return;
+			if (js_mag_crunch_nibbles(info->data, 1)) return; 
+			break;
+
+		case 'n':				/* Null radius */
+			if (info->idx != 2) return;
+			if (js_mag_crunch_nibbles(info->data, 1)) return; 
+			break;
+
+		case 'p':				/* Data rate */
+			if (info->idx != 3) return;
+			if (js_mag_crunch_nibbles(info->data, 2)) return;
+			break;
+
+		case 'q':				/* Sensitivity */
+			if (info->idx != 3) return;
+			if (js_mag_crunch_nibbles(info->data, 2)) return; 
+			break;
+
+		case 'v':				/* Version string */
+			info->data[info->idx] = 0;
+			for (i = 1; i < info->idx && info->data[i] == ' '; i++);
+			memcpy(info->name, info->data + i, info->idx - i);
+			break;
+
+		case 'z':				/* Zero position */
+			break;
+
+		default:
+			printk("joy-magellan: Unknown packet %d length %d:", info->data[0], info->idx);
+			for (i = 0; i < info->idx; i++) printk(" %02x", info->data[i]);
+			printk("\n");
+			return;
+	}
+
+	info->ack = info->data[0];
+}
+
+/*
+ * js_mag_command() sends a command to the Magellan, and waits for
+ * acknowledge.
+ */
+
+static int js_mag_command(struct js_mag_info *info, char *command, int timeout)
+{
+	info->ack = 0;
+	if (info->tty->driver.write(info->tty, 0, command, strlen(command)) != strlen(command)) return -1;
+	while (!info->ack && timeout--) mdelay(1);
+	return -(info->ack != command[0]);
+}
+
+/*
+ * js_mag_setup() initializes the Magellan to sane state. Also works as
+ * a probe for Magellan existence.
+ */
+
+static int js_mag_setup(struct js_mag_info *info)
+{
+
+	if (js_mag_command(info, "vQ\r", 800))	/* Read version */
+		return -1;
+	if (js_mag_command(info, "m3\r", 50))	/* Set full 3d mode */
+		return -1;
+	if (js_mag_command(info, "pBB\r", 50))	/* Set 16 reports/second (max) */
+		return -1;
+	if (js_mag_command(info, "z\r", 50))	/* Set zero position */
+		return -1;
+
+	return 0;
+}
+
+/*
+ * js_mag_read() updates the axis and button data upon startup.
+ */
+
+static int js_mag_read(struct js_mag_info *info)
+{
+	memset(info->port->axes[0],0, sizeof(int) * 6);		/* Axes are 0 after zero postition cmd */ 
+
+	if (js_mag_command(info, "kQ\r", 50))			/* Read buttons */
+		return -1;
+
+	return 0;
+}
+
+/*
+ * js_mag_open() is a callback from the joystick device open routine.
+ */
+
+static int js_mag_open(struct js_dev *jd)
+{
+	struct js_mag_info *info = jd->port->info;
+	info->used++;	
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * js_mag_close() is a callback from the joystick device release routine.
+ */
+
+static int js_mag_close(struct js_dev *jd)
+{
+	struct js_mag_info *info = jd->port->info;
+	if (!--info->used) {
+		js_unregister_device(jd->port->devs[0]);
+		js_mag_port = js_unregister_port(jd->port);
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * js_mag_init_corr() initializes the correction values for the Magellan.
+ * It asumes gain setting of 0, question is, what we should do for higher
+ * gain settings ...
+ */
+
+static void js_mag_init_corr(struct js_corr **corr)
+{
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		corr[0][i].type = JS_CORR_BROKEN;
+		corr[0][i].prec = 0;
+		corr[0][i].coef[0] = 0;
+		corr[0][i].coef[1] = 0;
+		corr[0][i].coef[2] = (1 << 29) / 256;
+		corr[0][i].coef[3] = (1 << 29) / 256;
+	}
+}
+
+/*
+ * js_mag_ldisc_open() is the routine that is called upon setting our line
+ * discipline on a tty. It looks for the Magellan, and if found, registers
+ * it as a joystick device.
+ */
+
+static int js_mag_ldisc_open(struct tty_struct *tty)
+{
+	struct js_mag_info iniinfo;
+	struct js_mag_info *info = &iniinfo;
+
+	info->tty = tty;
+	info->idx = 0;
+	info->used = 1;
+
+	js_mag_port = js_register_port(js_mag_port, info, 1, sizeof(struct js_mag_info), NULL);
+
+	info = js_mag_port->info;
+	info->port = js_mag_port;
+	tty->disc_data = info;
+
+	if (js_mag_setup(info)) {
+		js_mag_port = js_unregister_port(info->port);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "js%d: Magellan [%s] on %s%d\n",
+		js_register_device(js_mag_port, 0, 6, 9, "Magellan", js_mag_open, js_mag_close),
+		info->name, tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
+
+
+	js_mag_read(info);
+	js_mag_init_corr(js_mag_port->corr);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+/*
+ * js_mag_ldisc_close() is the opposite of js_mag_ldisc_open()
+ */
+
+static void js_mag_ldisc_close(struct tty_struct *tty)
+{
+	struct js_mag_info* info = (struct js_mag_info*) tty->disc_data;
+	if (!--info->used) {
+		js_unregister_device(info->port->devs[0]);
+		js_mag_port = js_unregister_port(info->port);
+	}
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * js_mag_ldisc_receive() is called by the low level driver when characters
+ * are ready for us. We then buffer them for further processing, or call the
+ * packet processing routine.
+ */
+
+static void js_mag_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+{
+	struct js_mag_info* info = (struct js_mag_info*) tty->disc_data;
+	int i;
+
+	for (i = 0; i < count; i++)
+		if (cp[i] == '\r') {
+			js_mag_process_packet(info);
+			info->idx = 0;
+		} else {
+			if (info->idx < JS_MAG_MAX_LENGTH)
+				info->data[info->idx++] = cp[i];
+		} 
+}
+
+/*
+ * js_mag_ldisc_room() reports how much room we do have for receiving data.
+ * Although we in fact have infinite room, we need to specify some value
+ * here, so why not the size of our packet buffer. It's big anyway.
+ */
+
+static int js_mag_ldisc_room(struct tty_struct *tty)
+{
+	return JS_MAG_MAX_LENGTH;
+}
+
+/*
+ * The line discipline structure.
+ */
+
+static struct tty_ldisc js_mag_ldisc = {
+        magic:          TTY_LDISC_MAGIC,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+        name:           "magellan",
+#endif
+	open:		js_mag_ldisc_open,
+	close:		js_mag_ldisc_close,
+	receive_buf:	js_mag_ldisc_receive,
+	receive_room:	js_mag_ldisc_room,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+#ifdef MODULE
+int init_module(void)
+#else
+int __init js_mag_init(void)
+#endif
+{
+        if (tty_register_ldisc(N_JOYSTICK_MAG, &js_mag_ldisc)) {
+                printk(KERN_ERR "joy-magellan: Error registering line discipline.\n");
+		return -ENODEV;
+	}
+
+	return  0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	tty_register_ldisc(N_JOYSTICK_MAG, NULL);
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-pci.c linux.14p16/drivers/char/joystick/joy-pci.c
--- linux.vanilla/drivers/char/joystick/joy-pci.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/char/joystick/joy-pci.c	Tue Dec 21 01:00:04 1999
@@ -0,0 +1,272 @@
+/*
+ *  joy-pci.c  Version 0.4.0
+ *
+ *  Copyright (c) 1999 Raymond Ingles
+ *  Copyright (c) 1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This is a module for the Linux joystick driver, supporting the
+ * gameports on Trident 4DWave and Aureal Vortex soundcards, and
+ * analog joysticks connected to them.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/joystick.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+MODULE_AUTHOR("Raymond Ingles <sorceror@tir.com>");
+MODULE_PARM(js_pci, "3-32i");
+
+#define NUM_CARDS              8
+static int js_pci[NUM_CARDS * 4] __initdata = { -1,0,0,0,-1,0,0,0,-1,0,0,0,-1,0,0,0,
+						-1,0,0,0,-1,0,0,0,-1,0,0,0,-1,0,0,0 };
+
+static struct js_port * js_pci_port __initdata = NULL;
+
+#include "joy-analog.h"
+
+struct js_pci_info;
+typedef void (*js_pci_func)(struct js_pci_info *);
+
+struct js_pci_data {
+	int vendor;	/* PCI Vendor ID */
+	int model;	/* PCI Model ID */
+	int size;	/* Memory / IO region size */
+	int lcr;	/* Aureal Legacy Control Register */
+	int gcr;	/* Gameport control register */
+	int buttons;	/* Buttons location */
+	int axes;	/* Axes start */
+	int axsize;	/* Axis field size */
+	int axmax;	/* Axis field max value */
+	js_pci_func init;	
+	js_pci_func cleanup;	
+	char *name;
+};
+
+struct js_pci_info {
+        unsigned char *base;
+	struct pci_dev *pci_p;
+	__u32 lcr;
+	struct js_pci_data *data;
+        struct js_an_info an;
+};
+
+/*
+ * js_pci_*_init() sets the info->base field, disables legacy gameports,
+ * and enables the enhanced ones.
+ */
+
+static void js_pci_4dwave_init(struct js_pci_info *info)
+{
+	info->base = ioremap(BASE_ADDRESS(info->pci_p, 1), info->data->size);
+	pci_read_config_word(info->pci_p, info->data->lcr, (unsigned short *)&info->lcr);
+	pci_write_config_word(info->pci_p, info->data->lcr, info->lcr & ~0x20);
+	writeb(0x80, info->base + info->data->gcr);
+}
+
+static void js_pci_vortex_init(struct js_pci_info *info)
+{
+	info->base = ioremap(BASE_ADDRESS(info->pci_p, 0), info->data->size);
+	info->lcr = readl(info->base + info->data->lcr);
+	writel(info->lcr & ~0x8, info->base + info->data->lcr);
+	writel(0x40, info->base + info->data->gcr);
+}
+
+/*
+ * js_pci_*_cleanup does the opposite of the above functions.
+ */
+
+static void js_pci_4dwave_cleanup(struct js_pci_info *info)
+{
+	pci_write_config_word(info->pci_p, info->data->lcr, info->lcr);
+	writeb(0x00, info->base + info->data->gcr);
+	iounmap(info->base);
+}
+
+static void js_pci_vortex_cleanup(struct js_pci_info *info)
+{
+	writel(info->lcr, info->base + info->data->lcr);
+	writel(0x00, info->base + info->data->gcr);
+	iounmap(info->base);
+}
+
+static struct js_pci_data js_pci_data[] =
+{{ PCI_VENDOR_ID_TRIDENT, 0x2000, 0x10000, 0x00044 ,0x00030, 0x00031, 0x00034, 2, 0xffff,
+	js_pci_4dwave_init, js_pci_4dwave_cleanup, "Trident 4DWave DX" },
+ { PCI_VENDOR_ID_TRIDENT, 0x2001, 0x10000, 0x00044, 0x00030, 0x00031, 0x00034, 2, 0xffff,
+	js_pci_4dwave_init, js_pci_4dwave_cleanup, "Trident 4DWave NX" },
+ { PCI_VENDOR_ID_AUREAL,  0x0001, 0x40000, 0x1280c, 0x1100c, 0x11008, 0x11010, 4, 0x1fff,
+	js_pci_vortex_init, js_pci_vortex_cleanup, "Aureal Vortex1" },
+ { PCI_VENDOR_ID_AUREAL,  0x0002, 0x40000, 0x2a00c, 0x2880c, 0x28808, 0x28810, 4, 0x1fff,
+	js_pci_vortex_init, js_pci_vortex_cleanup, "Aureal Vortex2" },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL }};
+
+/*
+ * js_pci_read() reads data from a PCI gameport.
+ */
+
+static int js_pci_read(void *xinfo, int **axes, int **buttons)
+{
+        struct js_pci_info *info = xinfo;
+	int i;
+
+	info->an.buttons = ~readb(info->base + info->data->buttons) >> 4;
+
+	for (i = 0; i < 4; i++)
+		info->an.axes[i] = readw(info->base + info->data->axes + i * info->data->axsize);
+
+        js_an_decode(&info->an, axes, buttons);
+        
+        return 0;
+}
+	
+/*
+ * js_pci_open() is a callback from the file open routine.
+ */
+
+static int js_pci_open(struct js_dev *jd)
+{
+        MOD_INC_USE_COUNT;
+        return 0;
+}
+
+/*
+ * js_pci_close() is a callback from the file release routine.
+ */
+
+static int js_pci_close(struct js_dev *jd)
+{
+        MOD_DEC_USE_COUNT;
+        return 0;
+}
+
+static struct js_port * __init js_pci_probe(struct js_port *port, int type, int number,
+					struct pci_dev *pci_p, struct js_pci_data *data)
+{
+	int i;
+	unsigned char u;
+	int mask0, mask1, numdev;
+        struct js_pci_info iniinfo;
+        struct js_pci_info *info = &iniinfo;
+
+	mask0 = mask1 = 0;
+	
+	for (i = 0; i < NUM_CARDS; i++)
+		if (js_pci[i * 4] == type && js_pci[i * 4 + 1] == number) {
+			mask0 = js_pci[i * 4 + 2];
+			mask1 = js_pci[i * 4 + 3];
+			if (!mask0 && !mask1) return port;
+			break;
+		}
+
+	memset(info, 0,  sizeof(struct js_pci_info));
+
+	info->data = data;
+	info->pci_p = pci_p;
+	data->init(info);
+
+	mdelay(10);
+	js_pci_read(info, NULL, NULL);
+
+	for (i = u = 0; i < 4; i++)
+		if (info->an.axes[i] < info->data->axmax) u |= 1 << i;
+
+	if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0)
+		return port;
+
+	port = js_register_port(port, info, numdev, sizeof(struct js_pci_info), js_pci_read);
+
+	info = port->info;
+
+	for (i = 0; i < numdev; i++)
+		printk(KERN_WARNING "js%d: %s on %s #%d\n",
+			js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an),
+			js_an_name(i, &info->an), js_pci_open, js_pci_close), js_an_name(i, &info->an), data->name, number);
+
+	js_pci_read(info, port->axes, port->buttons);
+	js_an_init_corr(&info->an, port->axes, port->corr, 32);
+
+	return port;
+}
+
+#ifndef MODULE
+int __init js_pci_setup(SETUP_PARAM)
+{
+        int i;
+	SETUP_PARSE(NUM_CARDS*4);
+        for (i = 0; i <= ints[0] && i < NUM_CARDS*4; i++)
+		js_pci[i] = ints[i+1];
+	return 1;
+}
+__setup("js_pci=", js_pci_setup);
+#endif
+
+#ifdef MODULE
+int init_module(void)
+#else
+int __init js_pci_init(void)
+#endif
+{
+        struct pci_dev *pci_p = NULL;
+        int i, j;
+
+	for (i = 0; js_pci_data[i].vendor; i++)
+		for (j = 0; (pci_p = pci_find_device(js_pci_data[i].vendor, js_pci_data[i].model, pci_p)); j++)
+			js_pci_port = js_pci_probe(js_pci_port, i, j, pci_p, js_pci_data + i);
+
+        if (!js_pci_port) {
+#ifdef MODULE
+                printk(KERN_WARNING "joy-pci: no joysticks found\n");
+#endif
+                return -ENODEV;
+        }
+
+        return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+        int i;
+        struct js_pci_info *info;
+
+        while (js_pci_port) {
+                for (i = 0; i < js_pci_port->ndevs; i++)
+                        if (js_pci_port->devs[i])
+                                js_unregister_device(js_pci_port->devs[i]);
+                info = js_pci_port->info;
+		info->data->cleanup(info);
+                js_pci_port = js_unregister_port(js_pci_port);
+        }
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-sidewinder.c linux.14p16/drivers/char/joystick/joy-sidewinder.c
--- linux.vanilla/drivers/char/joystick/joy-sidewinder.c	Wed Dec  2 03:05:05 1998
+++ linux.14p16/drivers/char/joystick/joy-sidewinder.c	Tue Dec 21 00:31:12 1999
@@ -1,7 +1,9 @@
 /*
  *  joy-sidewinder.c  Version 1.2
  *
- *  Copyright (c) 1998 Vojtech Pavlik
+ *  Copyright (c) 1998-1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
  */
 
 /*
@@ -25,7 +27,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  */
 
@@ -38,18 +40,36 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/init.h>
 
-#define JS_SW_MAX_START		250
-#define JS_SW_MIN_STROBE	25
-#define JS_SW_EXT_STROBE	45
-#define JS_SW_MIN_TIME		1500
-#define JS_SW_MAX_TIME		4000
-
-#define JS_SW_MAX_LENGTH	72
-
-#define JS_SW_MODE_3DP		1
-#define JS_SW_MODE_PP		2
-#define JS_SW_MODE_GP		3
+/*
+ * These are really magic values. Changing them can make a problem go away,
+ * as well as break everything.
+ */
+
+#undef JS_SW_DEBUG
+
+#define JS_SW_START		400	/* The time we wait for the first bit [400 us] */
+#define JS_SW_STROBE		45	/* Max time per bit [45 us] */
+#define JS_SW_TIMEOUT		4000	/* Wait for everything to settle [4 ms] */
+#define JS_SW_KICK		45	/* Wait after A0 fall till kick [45 us] */
+#define JS_SW_END		8	/* Number of bits before end of packet to kick */
+#define JS_SW_FAIL		16	/* Number of packet read errors to fail and reinitialize */
+#define JS_SW_BAD		2	/* Number of packet read errors to switch off 3d Pro optimization */
+#define JS_SW_OK		64	/* Number of packet read successes to switch optimization back on */
+#define JS_SW_LENGTH		512	/* Max number of bits in a packet */
+
+/*
+ * SideWinder joystick types ...
+ */
+
+#define JS_SW_TYPE_3DP		1
+#define JS_SW_TYPE_F23		2
+#define JS_SW_TYPE_GP		3
+#define JS_SW_TYPE_PP		4
+#define JS_SW_TYPE_FFP		5
+#define JS_SW_TYPE_FSP		6
+#define JS_SW_TYPE_FFW		7
 
 static int js_sw_port_list[] __initdata = {0x201, 0};
 static struct js_port* js_sw_port __initdata = NULL;
@@ -61,208 +81,398 @@
 
 struct js_sw_info {
 	int io;
-	unsigned char mode;
+	int length;
+	int speed;
+	unsigned char type;
+	unsigned char bits;
 	unsigned char number;
-	unsigned char optimize;
+	unsigned char fail;
+	unsigned char ok;
 };
 
 /*
- * js_sw_init_digital() switches a SideWinder into digital mode.
+ * Gameport speed.
+ */
+
+unsigned int js_sw_io_speed = 0;
+
+/*
+ * js_sw_measure_speed() measures the gameport i/o speed.
  */
 
-static void __init js_sw_init_digital(int io)
+static int __init js_sw_measure_speed(int io)
 {
-	unsigned int t;
-	unsigned int timeout = (js_time_speed * JS_SW_MAX_TIME) >> 10;
-        int delays[] = {140, 140+726, 140+300, 0};
-	int i = 0;
+#ifdef __i386__
+
+#define GET_TIME(x)     do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
+#define DELTA(x,y)      ((y)-(x)+((y)<(x)?1193180L/HZ:0))
+
+	unsigned int i, t, t1, t2, t3, tx;
 	unsigned long flags;
 
-	__save_flags(flags);
-	__cli();
-	do {
-		outb(0xff,io);
-		t = js_get_time();
-		while ((inb(io) & 1) && (js_delta(js_get_time(),t) < timeout));
-		udelay(delays[i]);
-	} while (delays[i++]);
-	__restore_flags(flags);
+	tx = 1 << 30;
 
-	for (i = 0; i < 4; i++) {
-		udelay(300);
-		outb(0xff, io);
+	for(i = 0; i < 50; i++) {
+		save_flags(flags);	/* Yes, all CPUs */
+		cli();
+		GET_TIME(t1);
+		for(t = 0; t < 50; t++) inb(io);
+		GET_TIME(t2);
+		GET_TIME(t3);
+		restore_flags(flags);
+		udelay(i * 10);
+		if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
 	}
 
-	return;
+	return 59659 / t;
+
+#else
+
+	unsigned int j, t = 0;
+
+	j = jiffies; while (j == jiffies);
+	j = jiffies; while (j == jiffies) { t++; inb(0x201); }
+
+	return t * HZ / 1000;
+
+#endif
 }
 
 /*
- * js_sw_read_packet() reads a SideWinder packet.
+ * js_sw_read_packet() is a function which reads either a data packet, or an
+ * identification packet from a SideWinder joystick. Better don't try to
+ * understand this, since all the ugliness of the Microsoft Digital
+ * Overdrive protocol is concentrated in this function. If you really want
+ * to know how this works, first go watch a couple horror movies, so that
+ * you are well prepared, read US patent #5628686 and then e-mail me,
+ * and I'll send you an explanation.
+ *					Vojtech <vojtech@suse.cz>
  */
 
-static int js_sw_read_packet(int io, int l1, int l2, int strobe, __u64 *data)
+static int js_sw_read_packet(int io, int speed, unsigned char *buf, int length, int id)
 {
-	static unsigned char buf[JS_SW_MAX_LENGTH];
-	unsigned char u, v;
-	int i;
 	unsigned long flags;
-	unsigned int t, t1;
-
-	int length = l1 < l2 ? l2 : l1;
-	int start = (js_time_speed * JS_SW_MAX_START) >> 10;
-	strobe = (js_time_speed * strobe) >> 10;
+	int timeout, bitout, sched, i, kick, start, strobe;
+	unsigned char pending, u, v;
 
-	i = 0;
+	i = -id;						/* Don't care about data, only want ID */
+	timeout = id ? (JS_SW_TIMEOUT * speed) >> 10 : 0;	/* Set up global timeout for ID packet */
+	kick = id ? (JS_SW_KICK * speed) >> 10 : 0;		/* Set up kick timeout for ID packet */
+	start = (JS_SW_START * speed) >> 10;
+	strobe = (JS_SW_STROBE * speed) >> 10;
+	bitout = start;
+	pending = 0;
+	sched = 0;
 
-	__save_flags(flags);
-	__cli();
-	outb(0xff,io);
+        __save_flags(flags);					/* Quiet, please */
+        __cli();
 
+	outb(0xff, io);						/* Trigger */
 	v = inb(io);
-	t = js_get_time();
 
 	do {
+		bitout--;
 		u = v;
 		v = inb(io);
-		t1 = js_get_time();
-	} while (!((u ^ v) & u & 0x10) && js_delta(t1, t) < start);
+	} while (!(~v & u & 0x10) && (bitout > 0));		/* Wait for first falling edge on clock */
 
-	t = t1;
+	if (bitout > 0) bitout = strobe;			/* Extend time if not timed out */
+
+	while ((timeout > 0 || bitout > 0) && (i < length)) {
+
+		timeout--;
+		bitout--;					/* Decrement timers */
+		sched--;
 
-	do {
-		v = inb(io);
-		t1 = js_get_time();
-		if ((u ^ v) & v & 0x10) {
-			buf[i++] = v >> 5;
-			t = t1;
-		}
 		u = v;
-	} while (i < length && js_delta(t1,t) < strobe);
+		v = inb(io);
 
-	__restore_flags(flags);
+		if ((~u & v & 0x10) && (bitout > 0)) {		/* Rising edge on clock - data bit */
+			if (i >= 0)				/* Want this data */
+				buf[i] = v >> 5;		/* Store it */
+			i++;					/* Advance index */
+			bitout = strobe;			/* Extend timeout for next bit */
+		} 
+
+		if (kick && (~v & u & 0x01)) {			/* Falling edge on axis 0 */
+			sched = kick;				/* Schedule second trigger */
+			kick = 0;				/* Don't schedule next time on falling edge */
+			pending = 1;				/* Mark schedule */
+		} 
+
+		if (pending && sched < 0 && (i > -JS_SW_END)) {	/* Second trigger time */
+			outb(0xff, io);				/* Trigger */
+			bitout = start;				/* Long bit timeout */
+			pending = 0;				/* Unmark schedule */
+			timeout = 0;				/* Switch from global to bit timeouts */ 
+		}
+	}
 
-	*data = 0;
+	__restore_flags(flags);					/* Done - relax */
 
-	if (i == l1) {
-		t = i > 64 ? 64 : i;
-		for (i = 0; i < t; i++)
-			*data |= (__u64) (buf[i] & 1) << i;
-		return t;
-	}
-	if (i == l2) {
-		t = i > 22 ? 22 : i;
-		for (i = 0; i < t; i++)
-			*data |= (__u64) buf[i] << (3 * i);
-		return t * 3;
+#ifdef JS_SW_DEBUG
+	{
+		int j;
+		printk(KERN_DEBUG "joy-sidewinder: Read %d triplets. [", i);
+		for (j = 0; j < i; j++) printk("%d", buf[j]);
+		printk("]\n");
 	}
+#endif
 
 	return i;
 }
 
 /*
- * js_sw_parity computes parity of __u64
+ * js_sw_get_bits() and GB() compose bits from the triplet buffer into a __u64.
+ * Parameter 'pos' is bit number inside packet where to start at, 'num' is number
+ * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits
+ * is number of bits per triplet.
+ */
+
+#define GB(pos,num,shift) js_sw_get_bits(buf, pos, num, shift, info->bits)
+
+static __u64 js_sw_get_bits(unsigned char *buf, int pos, int num, char shift, char bits)
+{
+	__u64 data = 0;
+	int tri = pos % bits;						/* Start position */
+	int i   = pos / bits;
+	int bit = shift;
+
+	while (num--) {
+		data |= (__u64)((buf[i] >> tri++) & 1) << bit++;	/* Transfer bit */
+		if (tri == bits) {
+			i++;						/* Next triplet */
+			tri = 0;
+		}
+	}
+
+	return data;
+}
+
+/*
+ * js_sw_init_digital() initializes a SideWinder 3D Pro joystick
+ * into digital mode.
+ */
+
+static void js_sw_init_digital(int io, int speed)
+{
+	int seq[] = { 140, 140+725, 140+300, 0 };
+	unsigned long flags;
+	int i, t;
+
+        __save_flags(flags);
+        __cli();
+
+	i = 0;
+        do {
+                outb(0xff, io);					/* Trigger */
+		t = (JS_SW_TIMEOUT * speed) >> 10;
+		while ((inb(io) & 1) && t) t--;			/* Wait for axis to fall back to 0 */
+                udelay(seq[i]);					/* Delay magic time */
+        } while (seq[++i]);
+
+	outb(0xff, io);						/* Last trigger */
+
+	__restore_flags(flags);
+}
+
+/*
+ * js_sw_parity() computes parity of __u64
  */
 
 static int js_sw_parity(__u64 t)
 {
-	t ^= t >> 32;
-	t ^= t >> 16;
-	t ^= t >> 8;
-	t ^= t >> 4;
-	t ^= t >> 2;
-	t ^= t >> 1;
-	return t & 1;
+	int x = t ^ (t >> 32);
+	x ^= x >> 16;
+	x ^= x >> 8;
+	x ^= x >> 4;
+	x ^= x >> 2;
+	x ^= x >> 1;
+	return x & 1;
 }
 
 /*
- * js_sw_csum() computes checksum of nibbles in __u64
+ * js_sw_ccheck() checks synchronization bits and computes checksum of nibbles.
  */
 
-static int js_sw_csum(__u64 t)
+static int js_sw_check(__u64 t)
 {
 	char sum = 0;
-	while (t) {
+
+	if ((t & 0x8080808080808080ULL) ^ 0x80)			/* Sync */
+		return -1;
+
+	while (t) {						/* Sum */
 		sum += t & 0xf;
 		t >>= 4;
 	}
+
 	return sum & 0xf;
 }
 
 /*
- * js_sw_read() reads and analyzes SideWinder joystick data.
+ * js_sw_parse() analyzes SideWinder joystick data, and writes the results into
+ * the axes and buttons arrays.
  */
 
-static int js_sw_read(void *xinfo, int **axes, int **buttons)
+static int js_sw_parse(unsigned char *buf, struct js_sw_info *info, int **axes, int **buttons)
 {
-	struct js_sw_info *info = xinfo;
-	__u64 data;
 	int hat, i;
 
-	switch (info->mode) {
-
-		case JS_SW_MODE_3DP:
+	switch (info->type) {
 
-			if (info->optimize) {
-				i = js_sw_read_packet(info->io, -1, 22, JS_SW_EXT_STROBE, &data);
-			} else {
-				i = js_sw_read_packet(info->io, 64, 66, JS_SW_EXT_STROBE, &data);
-				if (i == 198) info->optimize = 1;
-			}
+		case JS_SW_TYPE_3DP:
+		case JS_SW_TYPE_F23:
 
-			if (i < 60) {
-				js_sw_init_digital(info->io);
-				info->optimize = 0;
-				return -1;
-			}
+			if (js_sw_check(GB(0,64,0)) || (hat = GB(6,1,3) | GB(60,3,0))  > 8) return -1;
 
-			if (((data & 0x8080808080808080ULL) ^ 0x80) || js_sw_csum(data) ||
-				(hat = ((data >> 3) & 0x08) | ((data >> 60) & 0x07)) > 8) {
-				info->optimize = 0;
-				return -1;
-			}
-			axes[0][0] = ((data <<  4) & 0x380) | ((data >> 16) & 0x07f);
-			axes[0][1] = ((data <<  7) & 0x380) | ((data >> 24) & 0x07f);
-			axes[0][2] = ((data >> 28) & 0x180) | ((data >> 40) & 0x07f);
-			axes[0][3] = ((data >> 25) & 0x380) | ((data >> 48) & 0x07f);
+			axes[0][0] = GB( 3,3,7) | GB(16,7,0);
+			axes[0][1] = GB( 0,3,7) | GB(24,7,0);
+			axes[0][2] = GB(35,2,7) | GB(40,7,0);
+			axes[0][3] = GB(32,3,7) | GB(48,7,0);
 			axes[0][4] = js_sw_hat_to_axis[hat].x;
 			axes[0][5] = js_sw_hat_to_axis[hat].y;
-			buttons[0][0] = ((~data >> 31) & 0x80) | ((~data >> 8) & 0x7f);
+			buttons[0][0] = ~(GB(37,1,8) | GB(38,1,7) | GB(8,7,0));
+
+			return 0;
+
+		case JS_SW_TYPE_GP:
+
+			for (i = 0; i < info->number * 15; i += 15) {
+
+				if (js_sw_parity(GB(i,15,0))) return -1;
+
+				axes[i][0] = GB(i+3,1,0) - GB(i+2,1,0);
+				axes[i][1] = GB(i+0,1,0) - GB(i+1,1,0);
+				buttons[i][0] = ~GB(i+4,10,0);
+
+			}
 
 			return 0;
 
-		case JS_SW_MODE_PP:
+		case JS_SW_TYPE_PP:
+		case JS_SW_TYPE_FFP:
 
-			if (js_sw_read_packet(info->io, 48, 16, JS_SW_EXT_STROBE, &data) != 48) return -1;
-			if (!js_sw_parity(data) || (hat = (data >> 42) & 0xf) > 8) return -1;
+			if (!js_sw_parity(GB(0,48,0)) || (hat = GB(42,4,0)) > 8) return -1;
 
-			axes[0][0] = (data >>  9) & 0x3ff;
-			axes[0][1] = (data >> 19) & 0x3ff;
-			axes[0][2] = (data >> 29) & 0x07f;
-			axes[0][3] = (data >> 36) & 0x03f;
+			axes[0][0] = GB( 9,10,0);
+			axes[0][1] = GB(19,10,0);
+			axes[0][2] = GB(36, 6,0);
+			axes[0][3] = GB(29, 7,0);
 			axes[0][4] = js_sw_hat_to_axis[hat].x;
 			axes[0][5] = js_sw_hat_to_axis[hat].y;
-			buttons[0][0] = ~data & 0x1ff;
+			buttons[0][0] = ~GB(0,9,0);
 
 			return 0;
 
-		case JS_SW_MODE_GP:
+		case JS_SW_TYPE_FSP:
 
-			if (js_sw_read_packet(info->io, 15 * info->number, 5 * info->number,
-				JS_SW_EXT_STROBE, &data) != 15 * info->number) return -1;
-			if (js_sw_parity(data)) return -1;
-
-			for (i = 0; i < info->number; i++) {
-				axes[i][0] = ((data >> 3) & 1) - ((data >> 2) & 1);
-				axes[i][1] = ( data       & 1) - ((data >> 1) & 1);
-				buttons[i][0] = (~data >> 4) & 0x3ff;
-				data >>= 15;
-			}
+			if (!js_sw_parity(GB(0,43,0)) || (hat = GB(28,4,0)) > 8) return -1;
+
+			axes[0][0] = GB( 0,10,0);
+			axes[0][1] = GB(16,10,0);
+			axes[0][2] = GB(32, 6,0);
+			axes[0][3] = js_sw_hat_to_axis[hat].x;
+			axes[0][4] = js_sw_hat_to_axis[hat].y;
+			buttons[0][0] = ~(GB(10,6,0) | GB(26,2,6) | GB(38,2,8));
+
+			return 0;
+
+		case JS_SW_TYPE_FFW:
+
+			if (!js_sw_parity(GB(0,33,0))) return -1;
+
+			axes[0][0] = GB( 0,10,0);
+			axes[0][1] = GB(10, 6,0);
+			axes[0][2] = GB(16, 6,0);
+			buttons[0][0] = ~GB(22,8,0);
 
 			return 0;
+	}
+
+	return -1;
+}
+
+/*
+ * js_sw_read() reads SideWinder joystick data, and reinitializes
+ * the joystick in case of persistent problems. This is the function that is
+ * called from the generic code to poll the joystick.
+ */
+
+static int js_sw_read(void *xinfo, int **axes, int **buttons)
+{
+	struct js_sw_info *info = xinfo;
+	unsigned char buf[JS_SW_LENGTH];
+	int i;
+
+	i = js_sw_read_packet(info->io, info->speed, buf, info->length, 0);
+
+	if (info->type <= JS_SW_TYPE_F23 && info->length == 66 && i != 66) {	/* Broken packet, try to fix */
 
-		default:
-			return -1;
+		if (i == 64 && !js_sw_check(js_sw_get_bits(buf,0,64,0,1))) {	/* Last init failed, 1 bit mode */
+			printk(KERN_WARNING "joy-sidewinder: Joystick in wrong mode on %#x"
+				" - going to reinitialize.\n", info->io);
+			info->fail = JS_SW_FAIL;				/* Reinitialize */
+			i = 128;						/* Bogus value */
+		}
+
+		if (i < 66 && GB(0,64,0) == GB(i*3-66,64,0))			/* 1 == 3 */
+			i = 66;							/* Everything is fine */
+
+		if (i < 66 && GB(0,64,0) == GB(66,64,0))			/* 1 == 2 */
+			i = 66;							/* Everything is fine */
+
+		if (i < 66 && GB(i*3-132,64,0) == GB(i*3-66,64,0)) {		/* 2 == 3 */
+			memmove(buf, buf + i - 22, 22);				/* Move data */
+			i = 66;							/* Carry on */
+		}
+	}
+
+	if (i == info->length && !js_sw_parse(buf, info, axes, buttons)) {	/* Parse data */
+
+		info->fail = 0;
+		info->ok++;
+
+		if (info->type <= JS_SW_TYPE_F23 && info->length == 66		/* Many packets OK */
+			&& info->ok > JS_SW_OK) {
+
+			printk(KERN_INFO "joy-sidewinder: No more trouble on %#x"
+				" - enabling optimization again.\n", info->io);
+			info->length = 22;
+		}
+
+		return 0;
 	}
+
+	info->ok = 0;
+	info->fail++;
+
+	if (info->type <= JS_SW_TYPE_F23 && info->length == 22			/* Consecutive bad packets */
+			&& info->fail > JS_SW_BAD) {
+
+		printk(KERN_INFO "joy-sidewinder: Many bit errors on %#x"
+			" - disabling optimization.\n", info->io);
+		info->length = 66;
+	}
+
+	if (info->fail < JS_SW_FAIL) return -1;					/* Not enough, don't reinitialize yet */
+
+	printk(KERN_WARNING "joy-sidewinder: Too many bit errors on %#x"
+		" - reinitializing joystick.\n", info->io);
+
+	if (!i && info->type <= JS_SW_TYPE_F23) {				/* 3D Pro can be in analog mode */
+		udelay(3 * JS_SW_TIMEOUT);
+		js_sw_init_digital(info->io, info->speed);
+	}
+
+	udelay(JS_SW_TIMEOUT);
+	i = js_sw_read_packet(info->io, info->speed, buf, JS_SW_LENGTH, 0);	/* Read normal data packet */
+	udelay(JS_SW_TIMEOUT);
+	js_sw_read_packet(info->io, info->speed, buf, JS_SW_LENGTH, i);		/* Read ID packet, this initializes the stick */
+
+	info->fail = JS_SW_FAIL;
+	
+	return -1;
 }
 
 /*
@@ -290,7 +500,7 @@
  * SideWinders.
  */
 
-static void __init js_sw_init_corr(int num_axes, int mode, int number, struct js_corr **corr)
+static void __init js_sw_init_corr(int num_axes, int type, int number, struct js_corr **corr)
 {
 	int i, j;
 
@@ -305,9 +515,10 @@
 			corr[i][j].coef[3] = (1 << 29) / (511 - 32);
 		}
 
-		switch (mode) {
+		switch (type) {
 
-			case JS_SW_MODE_3DP:
+			case JS_SW_TYPE_3DP:
+			case JS_SW_TYPE_F23:
 
 				corr[i][2].type = JS_CORR_BROKEN;
 				corr[i][2].prec = 4;
@@ -320,33 +531,73 @@
 
 			break;
 
-			case JS_SW_MODE_PP:
+			case JS_SW_TYPE_PP:
+			case JS_SW_TYPE_FFP:
 
 				corr[i][2].type = JS_CORR_BROKEN;
-				corr[i][2].prec = 1;
-				corr[i][2].coef[0] = 63 - 4;
-				corr[i][2].coef[1] = 64 + 4;
-				corr[i][2].coef[2] = (1 << 29) / (63 - 4);
-				corr[i][2].coef[3] = (1 << 29) / (63 - 4);
+				corr[i][2].prec = 0;
+				corr[i][2].coef[0] = 31 - 2;
+				corr[i][2].coef[1] = 32 + 2;
+				corr[i][2].coef[2] = (1 << 29) / (31 - 2);
+				corr[i][2].coef[3] = (1 << 29) / (31 - 2);
 
 				corr[i][3].type = JS_CORR_BROKEN;
-				corr[i][3].prec = 0;
-				corr[i][3].coef[0] = 31 - 2;
-				corr[i][3].coef[1] = 32 + 2;
-				corr[i][3].coef[2] = (1 << 29) / (31 - 2);
-				corr[i][3].coef[3] = (1 << 29) / (31 - 2);
+				corr[i][3].prec = 1;
+				corr[i][3].coef[0] = 63 - 4;
+				corr[i][3].coef[1] = 64 + 4;
+				corr[i][3].coef[2] = (1 << 29) / (63 - 4);
+				corr[i][3].coef[3] = (1 << 29) / (63 - 4);
 
 				j = 4;
 
 			break;
 
+			case JS_SW_TYPE_FFW:
+
+				corr[i][0].type = JS_CORR_BROKEN;
+				corr[i][0].prec = 2;
+				corr[i][0].coef[0] = 511 - 8;
+				corr[i][0].coef[1] = 512 + 8;
+				corr[i][0].coef[2] = (1 << 29) / (511 - 8);
+				corr[i][0].coef[3] = (1 << 29) / (511 - 8);
+
+				corr[i][1].type = JS_CORR_BROKEN;
+				corr[i][1].prec = 1;
+				corr[i][1].coef[0] = 63;
+				corr[i][1].coef[1] = 63;
+				corr[i][1].coef[2] = (1 << 29) / -63;
+				corr[i][1].coef[3] = (1 << 29) / -63;
+
+				corr[i][2].type = JS_CORR_BROKEN;
+				corr[i][2].prec = 1;
+				corr[i][2].coef[0] = 63;
+				corr[i][2].coef[1] = 63;
+				corr[i][2].coef[2] = (1 << 29) / -63;
+				corr[i][2].coef[3] = (1 << 29) / -63;
+
+				j = 3;
+
+			break;
+
+			case JS_SW_TYPE_FSP:
+				
+				corr[i][2].type = JS_CORR_BROKEN;
+				corr[i][2].prec = 0;
+				corr[i][2].coef[0] = 31 - 2;
+				corr[i][2].coef[1] = 32 + 2;
+				corr[i][2].coef[2] = (1 << 29) / (31 - 2);
+				corr[i][2].coef[3] = (1 << 29) / (31 - 2);
+
+				j = 3;
+
+			break;
+
 			default:
 
 				j = 0;
-
 		}
 
-		for (; j < num_axes; j++) {
+		for (; j < num_axes; j++) {				/* Hats & other binary axes */
 			corr[i][j].type = JS_CORR_BROKEN;
 			corr[i][j].prec = 0;
 			corr[i][j].coef[0] = 0;
@@ -358,83 +609,211 @@
 }
 
 /*
+ * js_sw_print_packet() prints the contents of a SideWinder packet.
+ */
+
+static void js_sw_print_packet(char *name, int length, unsigned char *buf, char bits)
+{
+	int i;
+
+	printk("joy-sidewinder: %s packet, %d bits. [", name, length);
+	for (i = (((length + 3) >> 2) - 1); i >= 0; i--)
+		printk("%x", (int)js_sw_get_bits(buf, i << 2, 4, 0, bits));
+	printk("]\n");
+}
+
+/*
+ * js_sw_3dp_id() translates the 3DP id into a human legible string.
+ * Unfortunately I don't know how to do this for the other SW types.
+ */
+
+static void js_sw_3dp_id(unsigned char *buf, char *comment)
+{
+	int i;
+	char pnp[8], rev[9];
+
+	for (i = 0; i < 7; i++)						/* ASCII PnP ID */
+		pnp[i] = js_sw_get_bits(buf, 24+8*i, 8, 0, 1);
+
+	for (i = 0; i < 8; i++)						/* ASCII firmware revision */
+		rev[i] = js_sw_get_bits(buf, 88+8*i, 8, 0, 1);
+
+	pnp[7] = rev[8] = 0;
+
+	sprintf(comment, " [PnP %d.%02d id %s rev %s]",
+		(int) (js_sw_get_bits(buf, 8, 6, 6, 1) |		/* Two 6-bit values */
+			js_sw_get_bits(buf, 16, 6, 0, 1)) / 100,
+		(int) (js_sw_get_bits(buf, 8, 6, 6, 1) |
+			js_sw_get_bits(buf, 16, 6, 0, 1)) % 100,
+		 pnp, rev);
+}
+
+/*
+ * js_sw_guess_mode() checks the upper two button bits for toggling -
+ * indication of that the joystick is in 3-bit mode. This is documented
+ * behavior for 3DP ID packet, and for example the FSP does this in
+ * normal packets instead. Fun ...
+ */
+
+static int js_sw_guess_mode(unsigned char *buf, int len)
+{
+	int i;
+	unsigned char xor = 0;
+	for (i = 1; i < len; i++) xor |= (buf[i - 1] ^ buf[i]) & 6;
+	return !!xor * 2 + 1;
+}
+
+/*
  * js_sw_probe() probes for SideWinder type joysticks.
  */
 
 static struct js_port __init *js_sw_probe(int io, struct js_port *port)
 {
 	struct js_sw_info info;
-	char *name;
-	int i, j, axes, buttons;
-	__u64 data;
-	unsigned char u;
+	char *names[] = {NULL, "SideWinder 3D Pro", "Flight2000 F-23", "SideWinder GamePad", "SideWinder Precision Pro",
+			"SideWinder Force Feedback Pro", "SideWinder FreeStyle Pro", "SideWinder Force Feedback Wheel" };
+	char axes[] = { 0, 6, 6, 2, 6, 6, 5, 3 };
+	char buttons[] = { 0, 9, 9, 10, 9, 9, 10, 8 };
+	int i, j, k, l, speed;
+	unsigned char buf[JS_SW_LENGTH];
+	unsigned char idbuf[JS_SW_LENGTH];
+	unsigned char m = 1;
+	char comment[40];
 
+	comment[0] = 0;
 
 	if (check_region(io, 1)) return port;
-	if (((u = inb(io)) & 3) == 3) return port;
-	outb(0xff,io);
-	if (!((inb(io) ^ u) & ~u & 0xf)) return port;
-
-	i = js_sw_read_packet(io, JS_SW_MAX_LENGTH, -1, JS_SW_EXT_STROBE, &data);
-
-	if (!i) {
-		udelay(JS_SW_MIN_TIME);
-		js_sw_init_digital(io);
-		udelay(JS_SW_MAX_TIME);
-		i = js_sw_read_packet(io, JS_SW_MAX_LENGTH, -1, JS_SW_EXT_STROBE, &data);
-	}
-
-	switch (i) {
-		case 0:
-			return port;
-		case 5:
-		case 10:
-		case 15:
-		case 20:
-		case 30:
-		case 45:
-		case 60:
-			info.mode = JS_SW_MODE_GP;
-			outb(0xff,io);							/* Kick into 3-bit mode */
-			udelay(JS_SW_MAX_TIME);
-			i = js_sw_read_packet(io, 60, -1, JS_SW_EXT_STROBE, &data);	/* Get total length */
-			udelay(JS_SW_MIN_TIME);
-			j = js_sw_read_packet(io, 15, -1, JS_SW_MIN_STROBE, &data);	/* Get subpacket length */
-			if (!i || !j) {
-				printk(KERN_WARNING "joy-sidewinder: SideWinder GamePad detected (%d,%d),"
-							" but not idenfitied.\n", i, j);
-				return port;
+
+	speed = js_sw_measure_speed(io);
+
+	i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0);		/* Read normal packet */
+	m |= js_sw_guess_mode(buf, i);					/* Data packet (1-bit) can carry mode info [FSP] */
+	udelay(JS_SW_TIMEOUT);
+
+#ifdef JS_SW_DEBUG
+	printk(KERN_DEBUG "joy-sidewinder: Init 1: Mode %d. Length %d.\n", m , i);
+#endif
+
+	if (!i) {							/* No data. 3d Pro analog mode? */
+		js_sw_init_digital(io, speed);				/* Switch to digital */
+		udelay(JS_SW_TIMEOUT);
+		i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0);	/* Retry reading packet */
+		udelay(JS_SW_TIMEOUT);
+#ifdef JS_SW_DEBUG
+	printk(KERN_DEBUG "joy-sidewinder: Init 1b: Length %d.\n", i);
+#endif
+		if (!i) return port;					/* No data -> FAIL */
+	}
+
+	j = js_sw_read_packet(io, speed, idbuf, JS_SW_LENGTH, i);	/* Read ID. This initializes the stick */
+	m |= js_sw_guess_mode(idbuf, j);				/* ID packet should carry mode info [3DP] */
+
+#ifdef JS_SW_DEBUG
+	printk(KERN_DEBUG "joy-sidewinder: Init 2: Mode %d. ID Length %d.\n", m , j);
+#endif
+
+	if (!j) {							/* Read ID failed. Happens in 1-bit mode on PP */
+		udelay(JS_SW_TIMEOUT);
+		i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0);	/* Retry reading packet */
+#ifdef JS_SW_DEBUG
+	printk(KERN_DEBUG "joy-sidewinder: Init 2b: Mode %d. Length %d.\n", m , i);
+#endif
+		if (!i) return port;
+		udelay(JS_SW_TIMEOUT);
+		j = js_sw_read_packet(io, speed, idbuf, JS_SW_LENGTH, i);/* Retry reading ID */
+#ifdef JS_SW_DEBUG
+	printk(KERN_DEBUG "joy-sidewinder: Init 2c: ID Length %d.\n", j);
+#endif
+
+	}
+
+	k = JS_SW_FAIL;							/* Try JS_SW_FAIL times */
+	l = 0;
+
+	do {
+		k--;
+		udelay(JS_SW_TIMEOUT);
+		i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0);	/* Read data packet */
+#ifdef JS_SW_DEBUG
+		printk(KERN_DEBUG "joy-sidewinder: Init 3: Length %d.\n", i);
+#endif
+
+		if (i > l) {						/* Longer? As we can only lose bits, it makes */
+									/* no sense to try detection for a packet shorter */
+			l = i;						/* than the previous one */
+
+			info.number = 1;
+			info.io = io;
+			info.speed = speed;
+			info.length = i;
+			info.bits = m;
+			info.fail = 0;
+			info.ok = 0;
+			info.type = 0;
+
+			switch (i * m) {
+				case 60:
+					info.number++;
+				case 45:				/* Ambiguous packet length */
+					if (j <= 40) {			/* ID length less or eq 40 -> FSP */	
+				case 43:
+						info.type = JS_SW_TYPE_FSP;
+						break;
+					}
+					info.number++;
+				case 30:
+					info.number++;
+				case 15:
+					info.type = JS_SW_TYPE_GP;
+					break;
+				case 33:
+				case 31:
+					info.type = JS_SW_TYPE_FFW;
+					break;
+				case 48:				/* Ambiguous */
+					if (j == 14) {			/* ID lenght 14*3 -> FFP */
+						info.type = JS_SW_TYPE_FFP;
+						sprintf(comment, " [AC %s]", js_sw_get_bits(idbuf,38,1,0,3) ? "off" : "on");
+					} else
+					info.type = JS_SW_TYPE_PP;
+					break;
+				case 198:
+					info.length = 22;
+				case 64:
+					info.type = JS_SW_TYPE_3DP;
+					if (j == 160) js_sw_3dp_id(idbuf, comment);
+					break;
 			}
-			info.number = i / j;
-			axes = 2; buttons = 10; name = "SideWinder GamePad";
-			break;
-		case 16:
-		case 48:
-			info.mode = JS_SW_MODE_PP; info.number = 1;
-			axes = 6; buttons = 9; name = "SideWinder Precision Pro";
-			break;
-		case 64:
-		case 66:
-			info.mode = JS_SW_MODE_3DP; info.number = 1; info.optimize = 0;
-			axes = 6; buttons = 8; name = "SideWinder 3D Pro";
-			break;
-		case 72:
-			return port;
-		default:
-			printk(KERN_WARNING "joy-sidewinder: unknown joystick device detected "
-				"(io=%#x, count=%d, data=0x%08x%08x), contact <vojtech@ucw.cz>\n",
-				io, i, (int)(data >> 32), (int)(data & 0xffffffff));
-			return port;
+		}
+
+	} while (k && !info.type);
+
+	if (!info.type) {
+		printk(KERN_WARNING "joy-sidewinder: unknown joystick device detected "
+			"(io=%#x), contact <vojtech@suse.cz>\n", io);
+		js_sw_print_packet("ID", j * 3, idbuf, 3);
+		js_sw_print_packet("Data", i * m, buf, m);
+		return port;
 	}
 
-	info.io = io;
+#ifdef JS_SW_DEBUG
+	js_sw_print_packet("ID", j * 3, idbuf, 3);
+	js_sw_print_packet("Data", i * m, buf, m);
+#endif
+
+	k = i;
 
 	request_region(io, 1, "joystick (sidewinder)");
+
 	port = js_register_port(port, &info, info.number, sizeof(struct js_sw_info), js_sw_read);
+
 	for (i = 0; i < info.number; i++)
-		printk(KERN_INFO "js%d: %s at %#x\n",
-			js_register_device(port, i, axes, buttons, name, js_sw_open, js_sw_close), name, io);
-	js_sw_init_corr(axes, info.mode, info.number, port->corr);
+		printk(KERN_INFO "js%d: %s%s at %#x [%d ns res %d-bit id %d data %d]\n",
+			js_register_device(port, i, axes[info.type], buttons[info.type],
+				names[info.type], js_sw_open, js_sw_close), names[info.type], comment, io,
+				1000000 / speed, m, j, k);
+
+	js_sw_init_corr(axes[info.type], info.type, info.number, port->corr);
 
 	return port;
 }
@@ -463,9 +842,9 @@
 	int i;
 	struct js_sw_info *info;
 
-	while (js_sw_port != NULL) {
+	while (js_sw_port) {
 		for (i = 0; i < js_sw_port->ndevs; i++)
-			if (js_sw_port->devs[i] != NULL)
+			if (js_sw_port->devs[i])
 				js_unregister_device(js_sw_port->devs[i]);
 		info = js_sw_port->info;
 		release_region(info->io, 1);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-spaceball.c linux.14p16/drivers/char/joystick/joy-spaceball.c
--- linux.vanilla/drivers/char/joystick/joy-spaceball.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/char/joystick/joy-spaceball.c	Tue Dec 21 00:31:12 1999
@@ -0,0 +1,347 @@
+/*
+ *  joy-spaceball.c  Version 0.1
+ *
+ *  Copyright (c) 1998 David Thompson
+ *  Copyright (c) 1999 Vojtech Pavlik
+ *  Copyright (c) 1999 Joseph Krahn
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This is a module for the Linux joystick driver, supporting
+ * the SpaceTec SpaceBall 4000 FLX.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ *  Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/errno.h>
+#include <linux/joystick.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+
+/*
+ * Constants.
+ */
+
+#define	N_JOYSTICK_SBALL	12
+#define JS_SBALL_MAX_LENGTH	128
+
+/*
+ * List of SpaceBalls.
+ */
+
+static struct js_port* js_sball_port = NULL;
+
+/*
+ * Per-Ball data.
+ */
+
+struct js_sball_info {
+	struct tty_struct* tty;
+	struct js_port* port;
+	int idx;
+	unsigned char data[JS_SBALL_MAX_LENGTH];
+	int js;
+	char used;
+};
+
+/*
+ * js_sball_process_packet() decodes packets the driver receives from the
+ * SpaceBall.
+ */
+
+static void js_sball_process_packet(struct js_sball_info* info)
+{
+	int i,b;
+	int **axes = info->port->axes;
+	int **buttons = info->port->buttons;
+	unsigned char *data = info->data;
+
+	if (info->idx < 2) return;
+
+	switch (info->data[0]) {
+
+		case '@':					/* Reset packet */
+			info->data[info->idx - 1] = 0;
+			for (i = 1; i < info->idx && info->data[i] == ' '; i++);
+
+			printk(KERN_INFO "js%d: SpaceBall 4000FLX [%s] on %s%d\n",
+				info->js, info->data + i, info->tty->driver.name,
+				MINOR(info->tty->device) - info->tty->driver.minor_start);
+
+			memset(axes[0], 0, sizeof(int) * 6);	/* All axes, buttons should be zero */
+			buttons[0][0] = 0;
+			break;
+
+		case 'D':					/* Ball data */
+			if (info->idx != 16) return;
+			if (!info->port->devs[0]) return;
+			axes[0][0] = ((data[3] << 8) | data[4] );
+			axes[0][1] = ((data[5] << 8) | data[6] );
+			axes[0][2] = ((data[7] << 8) | data[8] );
+			axes[0][3] = ((data[9] << 8) | data[10]);
+			axes[0][4] = ((data[11]<< 8) | data[12]);
+			axes[0][5] = ((data[13]<< 8) | data[14]);
+			for(i = 0; i < 6; i ++) if (axes[0][i] & 0x8000) axes[0][i] -= 0x10000;
+			break;
+
+		case 'K':				/* Button data, part1 */
+			/* We can ignore this packet for the SB 4000FLX. */
+			break;
+
+		case '.':				/* Button data, part2 */
+			if (info->idx != 4) return;
+			if (!info->port->devs[0]) return;
+			b = (data[1] & 0xbf) << 8 | (data[2] & 0xbf);
+			buttons[0][0] = ((b & 0x1f80) >> 1 | (b & 0x3f));
+			break;
+
+		case '?':				/* Error packet */
+			info->data[info->idx - 1] = 0;
+			printk(KERN_ERR "joy-spaceball: Device error. [%s]\n",info->data+1);
+			break;
+
+		case 'A':				/* reply to A command (ID# report) */
+		case 'B':				/* reply to B command (beep) */
+		case 'H':				/* reply to H command (firmware report) */
+		case 'S':				/* reply to S command (single beep) */
+		case 'Y':				/* reply to Y command (scale flag) */
+		case '"':				/* reply to "n command (report info, part n) */
+			break;
+
+		case 'P':				/* Pulse (update) speed */
+			if (info->idx != 3) return;     /* data[2],data[3] = hex digits for speed 00-FF */
+			break;
+
+		default:
+			printk("joy-spaceball: Unknown packet %d length %d:", data[0], info->idx);
+			for (i = 0; i < info->idx; i++) printk(" %02x", data[i]);
+			printk("\n");
+			return;
+	}
+}
+
+/*
+ * js_sball_open() is a callback from the joystick device open routine.
+ */
+
+static int js_sball_open(struct js_dev *jd)
+{
+	struct js_sball_info *info = jd->port->info;
+	info->used++;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * js_sball_close() is a callback from the joystick device release routine.
+ */
+
+static int js_sball_close(struct js_dev *jd)
+{
+	struct js_sball_info *info = jd->port->info;
+	if (!--info->used) {
+		js_unregister_device(jd->port->devs[0]);
+		js_sball_port = js_unregister_port(jd->port);
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * js_sball_init_corr() initializes the correction values for the SpaceBall.
+ */
+
+static void __init js_sball_init_corr(struct js_corr **corr)
+{
+	int j;
+
+	for (j = 0; j < 3; j++) {
+		corr[0][j].type = JS_CORR_BROKEN;
+		corr[0][j].prec = 0;
+		corr[0][j].coef[0] = 0;
+		corr[0][j].coef[1] = 0;
+		corr[0][j].coef[2] = 50000;
+		corr[0][j].coef[3] = 50000;
+	}
+	for (j = 3; j < 6; j++) {
+		corr[0][j].type = JS_CORR_BROKEN;
+		corr[0][j].prec = 0;
+		corr[0][j].coef[0] = 0;
+		corr[0][j].coef[1] = 0;
+		corr[0][j].coef[2] = 300000;
+		corr[0][j].coef[3] = 300000;
+	}
+}
+
+/*
+ * js_sball_ldisc_open() is the routine that is called upon setting our line
+ * discipline on a tty.
+ */
+
+static int js_sball_ldisc_open(struct tty_struct *tty)
+{
+	struct js_sball_info iniinfo;
+	struct js_sball_info *info = &iniinfo;
+
+	info->tty = tty;
+	info->idx = 0;
+	info->used = 1;
+
+	js_sball_port = js_register_port(js_sball_port, info, 1, sizeof(struct js_sball_info), NULL);
+	
+	info = js_sball_port->info;
+	info->port = js_sball_port;
+	tty->disc_data = info;
+
+	info->js = js_register_device(js_sball_port, 0, 6, 12, "SpaceBall 4000 FLX", js_sball_open, js_sball_close);
+
+	js_sball_init_corr(js_sball_port->corr);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+/*
+ * js_sball_ldisc_close() is the opposite of js_sball_ldisc_open()
+ */
+
+static void js_sball_ldisc_close(struct tty_struct *tty)
+{
+	struct js_sball_info* info = (struct js_sball_info*) tty->disc_data;
+	if (!--info->used) {
+		js_unregister_device(info->port->devs[0]);
+		js_sball_port = js_unregister_port(info->port);
+	}
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * js_sball_ldisc_receive() is called by the low level driver when characters
+ * are ready for us. We then buffer them for further processing, or call the
+ * packet processing routine.
+ */
+
+static void js_sball_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+{
+	struct js_sball_info* info = (struct js_sball_info*) tty->disc_data;
+	int i;
+	int esc_flag = 0;
+
+/*
+ * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor,
+ * and end in 0x0d.  It uses '^' as an escape for 0x0d characters which can
+ * occur in the axis values.  ^M, ^Q and ^S all mean 0x0d, depending (I think)
+ * on whether the axis value is increasing, decreasing, or same as before.
+ * (I don't see why this is useful).
+ *
+ * There may be a nicer whay to handle the escapes, but I wanted to be sure to
+ * allow for an escape at the end of the buffer.
+ */
+	for (i = 0; i < count; i++) {
+		if (esc_flag) {	 /* If the last char was an escape, overwrite it with the escaped value */
+
+			switch (cp[i]){
+				case 'M':
+                        	case 'Q':
+                        	case 'S':
+                                	info->data[info->idx]=0x0d;
+                                	break;
+                        	case '^': /* escaped escape; leave as is */
+                                	break;
+                        	default:
+					printk("joy-spaceball: Unknown escape character: %02x\n", cp[i]);
+			}
+
+			esc_flag = 0;
+
+		} else {
+
+			if (info->idx < JS_SBALL_MAX_LENGTH)
+				info->data[info->idx++] = cp[i];
+
+			if (cp[i] == 0x0D) {
+				if (info->idx)
+					js_sball_process_packet(info);
+				info->idx = 0;
+			} else
+				if (cp[i] == '^') esc_flag = 1;
+
+		}
+	}
+}
+
+/*
+ * js_sball_ldisc_room() reports how much room we do have for receiving data.
+ * Although we in fact have infinite room, we need to specify some value
+ * here, so why not the size of our packet buffer. It's big anyway.
+ */
+
+static int js_sball_ldisc_room(struct tty_struct *tty)
+{
+	return JS_SBALL_MAX_LENGTH;
+}
+
+/*
+ * The line discipline structure.
+ */
+
+static struct tty_ldisc js_sball_ldisc = {
+	magic:		TTY_LDISC_MAGIC,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+	name:		"spaceball",
+#endif
+	open:		js_sball_ldisc_open,
+	close:		js_sball_ldisc_close,
+	receive_buf:	js_sball_ldisc_receive,
+	receive_room:	js_sball_ldisc_room,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+#ifdef MODULE
+int init_module(void)
+#else
+int __init js_sball_init(void)
+#endif
+{
+        if (tty_register_ldisc(N_JOYSTICK_SBALL, &js_sball_ldisc)) {
+                printk(KERN_ERR "joy-spaceball: Error registering line discipline.\n");
+		return -ENODEV;
+	}
+
+	return  0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	tty_register_ldisc(N_JOYSTICK_SBALL, NULL);
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-spaceorb.c linux.14p16/drivers/char/joystick/joy-spaceorb.c
--- linux.vanilla/drivers/char/joystick/joy-spaceorb.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/char/joystick/joy-spaceorb.c	Tue Dec 21 00:31:12 1999
@@ -0,0 +1,305 @@
+/*
+ *  joy-spaceorb.c  Version 0.1
+ *
+ *  Copyright (c) 1998 David Thompson
+ *  Copyright (c) 1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This is a module for the Linux joystick driver, supporting
+ * the SpaceTec SpaceOrb 360 and SpaceBall Avenger 6dof controllers.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ *  Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/errno.h>
+#include <linux/joystick.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+
+/*
+ * Constants.
+ */
+
+#define	N_JOYSTICK_ORB		15
+#define JS_ORB_MAX_LENGTH	64
+
+/*
+ * List of SpaceOrbs.
+ */
+
+static struct js_port* js_orb_port = NULL;
+
+/*
+ * Per-Orb data.
+ */
+
+struct js_orb_info {
+	struct tty_struct* tty;
+	struct js_port* port;
+	int idx;
+	unsigned char data[JS_ORB_MAX_LENGTH];
+	int js;
+	char used;
+};
+
+static unsigned char js_orb_xor[] = "SpaceWare";
+
+static unsigned char *js_orb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout",
+		"Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" }; 
+
+/*
+ * js_orb_process_packet() decodes packets the driver receives from the
+ * SpaceOrb.
+ */
+
+static void js_orb_process_packet(struct js_orb_info* info)
+{
+	int i;
+	int **axes = info->port->axes;
+	int **buttons = info->port->buttons;
+	unsigned char *data = info->data;
+	unsigned char c = 0;
+
+	if (info->idx < 2) return;
+	for (i = 0; i < info->idx; i++) c ^= data[i];
+	if (c) return;
+
+	switch (info->data[0]) {
+
+		case 'R':				/* Reset packet */
+			info->data[info->idx - 1] = 0;
+			for (i = 1; i < info->idx && info->data[i] == ' '; i++);
+			printk(KERN_INFO "js%d: SpaceOrb 360 [%s] on %s%d\n",
+				info->js, info->data + i, info->tty->driver.name,
+				MINOR(info->tty->device) - info->tty->driver.minor_start);
+			break;
+
+		case 'D':				/* Ball + button data */
+			if (info->idx != 12) return;
+			if (!info->port->devs[0]) return;
+			for (i = 0; i < 9; i++) info->data[i+2] ^= js_orb_xor[i]; 
+			axes[0][0] = ( data[2]         << 3) | (data[ 3] >> 4);
+			axes[0][1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1);
+			axes[0][2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5);
+			axes[0][3] = ((data[6] & 0x1f) << 5) | (data[ 7] >> 2);
+			axes[0][4] = ((data[7] & 0x03) << 8) | (data[ 8] << 1) | (data[7] >> 6);
+			axes[0][5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3);
+			for(i = 0; i < 6; i ++) if (axes[0][i] & 0x200) axes[0][i] -= 1024;
+			buttons[0][0] = data[1];
+			break;
+
+		case 'K':				/* Button data */
+			if (info->idx != 5) return;
+			if (!info->port->devs[0]) return;
+			buttons[0][0] = data[2];
+			break;
+
+		case 'E':				/* Error packet */
+			if (info->idx != 4) return;
+			printk(KERN_ERR "joy-spaceorb: Device error. [ ");
+			for (i = 0; i < 7; i++)
+				if (data[1] & (1 << i))
+					printk("%s ", js_orb_errors[i]);
+			printk("]\n");
+			break;
+
+		case 'N':				/* Null region */
+			if (info->idx != 3) return;
+			break;
+
+		case 'P':				/* Pulse (update) speed */
+			if (info->idx != 4) return;
+			break;
+
+		default:
+			printk("joy-spaceorb: Unknown packet %d length %d:", data[0], info->idx);
+			for (i = 0; i < info->idx; i++) printk(" %02x", data[i]);
+			printk("\n");
+			return;
+	}
+}
+
+/*
+ * js_orb_open() is a callback from the joystick device open routine.
+ */
+
+static int js_orb_open(struct js_dev *jd)
+{
+	struct js_orb_info *info = jd->port->info;
+	info->used++;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * js_orb_close() is a callback from the joystick device release routine.
+ */
+
+static int js_orb_close(struct js_dev *jd)
+{
+	struct js_orb_info *info = jd->port->info;
+	if (!--info->used) {
+		js_unregister_device(jd->port->devs[0]);
+		js_orb_port = js_unregister_port(jd->port);
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * js_orb_init_corr() initializes the correction values for the SpaceOrb.
+ */
+
+static void __init js_orb_init_corr(struct js_corr **corr)
+{
+	int j;
+
+	for (j = 0; j < 6; j++) {
+		corr[0][j].type = JS_CORR_BROKEN;
+		corr[0][j].prec = 0;
+		corr[0][j].coef[0] = 0 ;
+		corr[0][j].coef[1] = 0 ;
+		corr[0][j].coef[2] = (1 << 29) / 511;
+		corr[0][j].coef[3] = (1 << 29) / 511;
+	}
+}
+
+/*
+ * js_orb_ldisc_open() is the routine that is called upon setting our line
+ * discipline on a tty.
+ */
+
+static int js_orb_ldisc_open(struct tty_struct *tty)
+{
+	struct js_orb_info iniinfo;
+	struct js_orb_info *info = &iniinfo;
+
+	info->tty = tty;
+	info->idx = 0;
+	info->used = 1;
+
+	js_orb_port = js_register_port(js_orb_port, info, 1, sizeof(struct js_orb_info), NULL);
+	
+	info = js_orb_port->info;
+	info->port = js_orb_port;
+	tty->disc_data = info;
+
+	info->js = js_register_device(js_orb_port, 0, 6, 7, "SpaceOrb 360", js_orb_open, js_orb_close);
+
+	js_orb_init_corr(js_orb_port->corr);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+/*
+ * js_orb_ldisc_close() is the opposite of js_orb_ldisc_open()
+ */
+
+static void js_orb_ldisc_close(struct tty_struct *tty)
+{
+	struct js_orb_info* info = (struct js_orb_info*) tty->disc_data;
+	if (!--info->used) {
+		js_unregister_device(info->port->devs[0]);
+		js_orb_port = js_unregister_port(info->port);
+	}
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * js_orb_ldisc_receive() is called by the low level driver when characters
+ * are ready for us. We then buffer them for further processing, or call the
+ * packet processing routine.
+ */
+
+static void js_orb_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+{
+	struct js_orb_info* info = (struct js_orb_info*) tty->disc_data;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		if (~cp[i] & 0x80) {
+			if (info->idx) js_orb_process_packet(info);
+			info->idx = 0;
+		}
+		if (info->idx < JS_ORB_MAX_LENGTH)
+			info->data[info->idx++] = cp[i] & 0x7f;
+	}
+}
+
+/*
+ * js_orb_ldisc_room() reports how much room we do have for receiving data.
+ * Although we in fact have infinite room, we need to specify some value
+ * here, so why not the size of our packet buffer. It's big anyway.
+ */
+
+static int js_orb_ldisc_room(struct tty_struct *tty)
+{
+	return JS_ORB_MAX_LENGTH;
+}
+
+/*
+ * The line discipline structure.
+ */
+
+static struct tty_ldisc js_orb_ldisc = {
+	magic:		TTY_LDISC_MAGIC,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+	name:		"spaceorb",
+#endif
+	open:		js_orb_ldisc_open,
+	close:		js_orb_ldisc_close,
+	receive_buf:	js_orb_ldisc_receive,
+	receive_room:	js_orb_ldisc_room,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+#ifdef MODULE
+int init_module(void)
+#else
+int __init js_orb_init(void)
+#endif
+{
+        if (tty_register_ldisc(N_JOYSTICK_ORB, &js_orb_ldisc)) {
+                printk(KERN_ERR "joy-spaceorb: Error registering line discipline.\n");
+		return -ENODEV;
+	}
+
+	return  0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	tty_register_ldisc(N_JOYSTICK_ORB, NULL);
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-thrustmaster.c linux.14p16/drivers/char/joystick/joy-thrustmaster.c
--- linux.vanilla/drivers/char/joystick/joy-thrustmaster.c	Wed Dec  2 03:05:05 1998
+++ linux.14p16/drivers/char/joystick/joy-thrustmaster.c	Tue Dec 21 00:31:12 1999
@@ -1,7 +1,9 @@
 /*
  *  joy-thrustmaster.c  Version 1.2
  *
- *  Copyright (c) 1998 Vojtech Pavlik
+ *  Copyright (c) 1998-1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
  */
 
 /*
@@ -25,7 +27,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  */
 
@@ -38,28 +40,15 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/init.h>
 
 #define JS_TM_MAX_START		400
-#define JS_TM_MAX_STROBE	25
+#define JS_TM_MAX_STROBE	45
 #define JS_TM_MAX_LENGTH	13
 
 #define JS_TM_MODE_M3DI		1
 #define JS_TM_MODE_3DRP		3
-#define JS_TM_MODE_WCS3		4
-
-#define JS_TM_MODE_MAX		5	/* Last mode + 1 */
-
-#define JS_TM_BYTE_A0		0
-#define JS_TM_BYTE_A1		1
-#define JS_TM_BYTE_A2		3
-#define JS_TM_BYTE_A3		4
-#define JS_TM_BYTE_A4		6
-#define JS_TM_BYTE_A5		7
-
-#define JS_TM_BYTE_D0		2
-#define JS_TM_BYTE_D1		5
-#define JS_TM_BYTE_D2		8
-#define JS_TM_BYTE_D3		9
+#define JS_TM_MODE_FGP		163
 
 #define JS_TM_BYTE_ID		10
 #define JS_TM_BYTE_REV		11
@@ -68,48 +57,39 @@
 static int js_tm_port_list[] __initdata = {0x201, 0};
 static struct js_port* js_tm_port __initdata = NULL;
 
+static unsigned char js_tm_byte_a[16] = { 0, 1, 3, 4, 6, 7 };
+static unsigned char js_tm_byte_d[16] = { 2, 5, 8, 9 };
+
 struct js_tm_info {
 	int io;
 	unsigned char mode;
 };
 
-static int js_tm_id_to_def[JS_TM_MODE_MAX] = {0x00, 0x42, 0x00, 0x22, 0x00};
-
 /*
  * js_tm_read_packet() reads a ThrustMaster packet.
  */
 
 static int js_tm_read_packet(int io, unsigned char *data)
 {
-	unsigned int t, t1;
+	unsigned int t, p;
 	unsigned char u, v, error;
 	int i, j;
 	unsigned long flags;
 
-	int start = (js_time_speed * JS_TM_MAX_START) >> 10;
-	int strobe = (js_time_speed * JS_TM_MAX_STROBE) >> 10;
-
 	error = 0;
 	i = j = 0;
+	p = t = JS_TM_MAX_START;
 
 	__save_flags(flags);
 	__cli();
 	outb(0xff,io);
-
-	t = js_get_time();
+	
+	v = inb(io) >> 4;
 
 	do {
-		u = inb(io);
-		t1 = js_get_time();
-	} while ((u & 1) && js_delta(t1, t) < start);
-
-	t = t1;
-	u >>= 4;
-
-	do {
-		v = inb(io) >> 4;
-		t1 = js_get_time();
-		if ((u ^ v) & u & 2) {
+		t--;
+		u = v; v = inb(io) >> 4;
+		if (~v & u & 2) {
 			if (j) {
 				if (j < 9) {				/* Data bit */
 					data[i] |= (~v & 1) << (j - 1);
@@ -124,10 +104,9 @@
 				error |= ~v & 1;
 				j++;
 			}
-			t = t1;
+			p = t = (p - t) << 1;
 		}
-		u = v;
-	} while (!error && i < JS_TM_MAX_LENGTH && js_delta(t1,t) < strobe);
+	} while (!error && i < JS_TM_MAX_LENGTH && t > 0);
 
 	__restore_flags(flags);
 
@@ -142,46 +121,39 @@
 {
 	struct js_tm_info *info = xinfo;
 	unsigned char data[JS_TM_MAX_LENGTH];
+	int i;
 
-	if (js_tm_read_packet(info->io, data)) {
-		printk(KERN_WARNING "joy-thrustmaster: failed to read data packet\n");
-		return -1;
-	}
-	if (data[JS_TM_BYTE_ID] != info->mode) {
-		printk(KERN_WARNING "joy-thrustmaster: ID (%d) != mode (%d)\n",
-			data[JS_TM_BYTE_ID], info->mode);
-		return -1;
-	}
-	if (data[JS_TM_BYTE_DEF] != js_tm_id_to_def[info->mode]) {
-		printk(KERN_WARNING "joy-thrustmaster: DEF (%d) != def(mode) (%d)\n",
-			data[JS_TM_BYTE_DEF], js_tm_id_to_def[info->mode]);
-		return -1;
-	}
+	if (js_tm_read_packet(info->io, data)) return -1;
+	if (data[JS_TM_BYTE_ID] != info->mode) return -1;
+
+	for (i = 0; i < data[JS_TM_BYTE_DEF] >> 4; i++) axes[0][i] = data[js_tm_byte_a[i]];
 
 	switch (info->mode) {
 
 		case JS_TM_MODE_M3DI:
 
-			axes[0][0] = data[JS_TM_BYTE_A0];
-			axes[0][1] = data[JS_TM_BYTE_A1];
-			axes[0][2] = data[JS_TM_BYTE_A2];
-			axes[0][3] = data[JS_TM_BYTE_A3];
-
-			axes[0][4] = ((data[JS_TM_BYTE_D0] >> 3) & 1) - ((data[JS_TM_BYTE_D0] >> 1) & 1);
-			axes[0][5] = ((data[JS_TM_BYTE_D0] >> 2) & 1) - ( data[JS_TM_BYTE_D0]       & 1);
+			axes[0][4] = ((data[js_tm_byte_d[0]] >> 3) & 1) - ((data[js_tm_byte_d[0]] >> 1) & 1);
+			axes[0][5] = ((data[js_tm_byte_d[0]] >> 2) & 1) - ( data[js_tm_byte_d[0]]       & 1);
 
-			buttons[0][0] = ((data[JS_TM_BYTE_D0] >> 6) & 0x01) | ((data[JS_TM_BYTE_D0] >> 3) & 0x06)
-				      | ((data[JS_TM_BYTE_D0] >> 4) & 0x08) | ((data[JS_TM_BYTE_D1] >> 2) & 0x30);
+			buttons[0][0] = ((data[js_tm_byte_d[0]] >> 6) & 0x01) | ((data[js_tm_byte_d[0]] >> 3) & 0x06)
+				      | ((data[js_tm_byte_d[0]] >> 4) & 0x08) | ((data[js_tm_byte_d[1]] >> 2) & 0x30);
 
 			return 0;
 
 		case JS_TM_MODE_3DRP:
+		case JS_TM_MODE_FGP:
+
+			buttons[0][0] = (data[js_tm_byte_d[0]] & 0x3f) | ((data[js_tm_byte_d[1]] << 6) & 0xc0)
+				      | (( ((int) data[js_tm_byte_d[0]]) << 2) & 0x300);
+
+			return 0;
+
+		default:
 
-			axes[0][0] = data[JS_TM_BYTE_A0];
-			axes[0][1] = data[JS_TM_BYTE_A1];
+			buttons[0][0] = 0;
 
-			buttons[0][0] = ( data[JS_TM_BYTE_D0]       & 0x3f) | ((data[JS_TM_BYTE_D1] << 6) & 0xc0)
-				      | (( ((int) data[JS_TM_BYTE_D0]) << 2) & 0x300);
+			for (i = 0; i < (data[JS_TM_BYTE_DEF] & 0xf); i++)
+				buttons[0][0] |= ((int) data[js_tm_byte_d[i]]) << (i << 3);
 
 			return 0;
 
@@ -217,9 +189,9 @@
 
 static void __init js_tm_init_corr(int num_axes, int mode, int **axes, struct js_corr **corr)
 {
-	int j;
+	int j = 0;
 
-	for (j = 0; j < num_axes; j++) {
+	for (; j < num_axes; j++) {
 		corr[0][j].type = JS_CORR_BROKEN;
 		corr[0][j].prec = 0;
 		corr[0][j].coef[0] = 127 - 2;
@@ -230,8 +202,7 @@
 
 	switch (mode) {
 		case JS_TM_MODE_M3DI: j = 4; break;
-		case JS_TM_MODE_3DRP: j = 2; break;
-		default:	      j = 0; break;
+		default: break;
 	}
 
 	for (; j < num_axes; j++) {
@@ -252,48 +223,46 @@
 static struct js_port __init *js_tm_probe(int io, struct js_port *port)
 {
 	struct js_tm_info info;
-	char *names[JS_TM_MODE_MAX] = { NULL, "ThrustMaster Millenium 3D Inceptor", NULL,
-						"ThrustMaster Rage 3D Gamepad", "ThrustMaster WCS III" };
-	char axes[JS_TM_MODE_MAX] = { 0, 6, 0, 2, 0 };
-	char buttons[JS_TM_MODE_MAX] = { 0, 5, 0, 10, 0 };
-
+	struct js_rm_models {
+		unsigned char id;
+		char *name;
+		char axes;
+		char buttons;
+	} models[] = {	{   1, "ThrustMaster Millenium 3D Inceptor", 6, 6 },
+			{   3, "ThrustMaster Rage 3D Gamepad", 2, 10 },
+			{ 163, "Thrustmaster Fusion GamePad", 2, 10 },
+			{   0, NULL, 0, 0 }};
+	char name[64];
 	unsigned char data[JS_TM_MAX_LENGTH];
-	unsigned char u;
+	unsigned char a, b;
+	int i;
 
 	if (check_region(io, 1)) return port;
 
-	if (((u = inb(io)) & 3) == 3) return port;
-	outb(0xff,io);
-	if (!((inb(io) ^ u) & ~u & 0xf)) return port;
-
-	if(js_tm_read_packet(io, data)) {
-		printk(KERN_WARNING "joy-thrustmaster: probe - can't read packet\n");
-		return port;
-	}
+	if (js_tm_read_packet(io, data)) return port;
 
 	info.io = io;
 	info.mode = data[JS_TM_BYTE_ID];
 
 	if (!info.mode) return port;
 
-	if (info.mode >= JS_TM_MODE_MAX || !names[info.mode]) {
-		printk(KERN_WARNING "joy-thrustmaster: unknown device detected "
-				    "(io=%#x, id=%d), contact <vojtech@ucw.cz>\n",
-					io, info.mode);
-		return port;
-	}
+	for (i = 0; models[i].id && models[i].id != info.mode; i++);
 
-	if (data[JS_TM_BYTE_DEF] != js_tm_id_to_def[info.mode]) {
-		printk(KERN_WARNING "joy-thrustmaster: wrong DEF (%d) for ID %d - should be %d\n",
-				data[JS_TM_BYTE_DEF], info.mode, js_tm_id_to_def[info.mode]);
+	if (models[i].id != info.mode) {
+		a = data[JS_TM_BYTE_DEF] >> 4;
+		b = (data[JS_TM_BYTE_DEF] & 0xf) << 3;
+		sprintf(name, "Unknown %d-axis, %d-button TM device %d", a, b, info.mode);
+	} else {
+		sprintf(name, models[i].name);
+		a = models[i].axes;
+		b = models[i].buttons;
 	}
 
 	request_region(io, 1, "joystick (thrustmaster)");
 	port = js_register_port(port, &info, 1, sizeof(struct js_tm_info), js_tm_read);
 	printk(KERN_INFO "js%d: %s revision %d at %#x\n",
-		js_register_device(port, 0, axes[info.mode], buttons[info.mode],
-				names[info.mode], js_tm_open, js_tm_close), names[info.mode], data[JS_TM_BYTE_REV], io);
-	js_tm_init_corr(axes[info.mode], info.mode, port->axes, port->corr);
+		js_register_device(port, 0, a, b, name, js_tm_open, js_tm_close), name, data[JS_TM_BYTE_REV], io);
+	js_tm_init_corr(a, info.mode, port->axes, port->corr);
 
 	return port;
 }
@@ -321,7 +290,7 @@
 {
 	struct js_tm_info *info;
 
-	while (js_tm_port != NULL) {
+	while (js_tm_port) {
 		js_unregister_device(js_tm_port->devs[0]);
 		info = js_tm_port->info;
 		release_region(info->io, 1);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-turbografx.c linux.14p16/drivers/char/joystick/joy-turbografx.c
--- linux.vanilla/drivers/char/joystick/joy-turbografx.c	Wed Dec  2 03:05:05 1998
+++ linux.14p16/drivers/char/joystick/joy-turbografx.c	Tue Dec 21 00:31:12 1999
@@ -1,7 +1,9 @@
 /*
  *  joy-turbografx.c  Version 1.2
  *
- *  Copyright (c) 1998 Vojtech Pavlik
+ *  Copyright (c) 1998-1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
  */
 
 /*
@@ -26,7 +28,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  */
 
@@ -39,9 +41,10 @@
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_PARM(js_tg, "2-8i");
 MODULE_PARM(js_tg_2, "2-8i");
 MODULE_PARM(js_tg_3, "2-8i");
@@ -57,18 +60,14 @@
 #define JS_TG_BUTTON4	0x01
 #define JS_TG_BUTTON5	0x08
 
-static struct js_port* js_tg_port = NULL;
+static struct js_port* js_tg_port __initdata = NULL;
 
 static int js_tg[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
 static int js_tg_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
 static int js_tg_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
 
 struct js_tg_info {
-#ifdef USE_PARPORT
 	struct pardevice *port;	/* parport device */
-#else
-	int port;		/* hw port */
-#endif
 	int sticks;		/* joysticks connected */
 };
 
@@ -109,9 +108,7 @@
 	struct js_tg_info *info = dev->port->info;
 
 	if (!MOD_IN_USE) {
-#ifdef USE_PARPORT
 		if (parport_claim(info->port)) return -EBUSY; 
-#endif
 		JS_PAR_CTRL_OUT(0x04, info->port);
 	}
 	MOD_INC_USE_COUNT;
@@ -129,9 +126,7 @@
         MOD_DEC_USE_COUNT;
 	if (!MOD_IN_USE) {
 		JS_PAR_CTRL_OUT(0x00, info->port);
-#ifdef USE_PARPORT
         	parport_release(info->port);
-#endif
 	}
         return 0;
 }
@@ -142,16 +137,12 @@
 	struct js_tg_info *info;
 	int i;
 
-	while (js_tg_port != NULL) {
+	while (js_tg_port) {
 		for (i = 0; i < js_tg_port->ndevs; i++)
-			if (js_tg_port->devs[i] != NULL)
+			if (js_tg_port->devs[i])
 				js_unregister_device(js_tg_port->devs[i]);
 		info = js_tg_port->info;
-#ifdef USE_PARPORT
 		parport_unregister_device(info->port);
-#else
-		release_region(info->port, 3);
-#endif
 		js_tg_port = js_unregister_port(js_tg_port);
 	}
 }
@@ -186,33 +177,25 @@
 {
 	struct js_tg_info iniinfo;
 	struct js_tg_info *info = &iniinfo;
+	struct parport *pp;
 	int i;
 
 	if (config[0] < 0) return port;
 
-#ifdef USE_PARPORT
-	{
-		struct parport *pp;
-
-		if (config[0] > 0x10)
-			for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next);
-		else
-			for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) config[0]--;
-
-		if (pp == NULL) {
-			printk(KERN_ERR "joy-tg: no such parport\n");
-			return port;
-		}
 
-		info->port = parport_register_device(pp, "joystick (turbografx)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
-		if (!info->port)
-			return port;
+	if (config[0] > 0x10)
+		for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next);
+	else
+		for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--;
+
+	if (!pp) {
+		printk(KERN_ERR "joy-tg: no such parport\n");
+		return port;
 	}
-#else
-	info->port = config[0];
-	if (check_region(info->port, 3)) return port;
-	request_region(info->port, 3, "joystick (turbografx)");
-#endif
+
+	info->port = parport_register_device(pp, "joystick (turbografx)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+	if (!info->port)
+		return port;
 
 	port = js_register_port(port, info, 7, sizeof(struct js_tg_info), js_tg_read);
 	info = port->info;
@@ -221,24 +204,14 @@
 
 	for (i = 0; i < 7; i++)
 		if (config[i+1] > 0 && config[i+1] < 6) {
-#ifdef USE_PARPORT
 			printk(KERN_INFO "js%d: Multisystem joystick on %s\n",
 				js_register_device(port, i, 2, config[i+1], "Multisystem joystick", js_tg_open, js_tg_close),
 				info->port->port->name);
-#else
-			printk(KERN_INFO "js%d: Multisystem joystick at %#x\n",
-				js_register_device(port, i, 2, config[i+1], "Multisystem joystick", js_tg_open, js_tg_close),
-				info->port);
-#endif
 			info->sticks |= (1 << i);
 		}
 
         if (!info->sticks) {
-#ifdef USE_PARPORT
 		parport_unregister_device(info->port);
-#else
-		release_region(info->port, 3);
-#endif
 		return port;
         }
 		
@@ -248,18 +221,30 @@
 }
 
 #ifndef MODULE
-void __init js_tg_setup(char *str, int *ints)
+int __init js_tg_setup(SETUP_PARAM)
 {
 	int i;
-
-	if (!strcmp(str,"js_tg"))
-		for (i = 0; i <= ints[0] && i < 2; i++) js_tg[i] = ints[i+1];
-	if (!strcmp(str,"js_tg_2"))
-		for (i = 0; i <= ints[0] && i < 2; i++) js_tg_2[i] = ints[i+1];
-	if (!strcmp(str,"js_tg_3"))
-		for (i = 0; i <= ints[0] && i < 2; i++) js_tg_3[i] = ints[i+1];
-
+	SETUP_PARSE(2);
+	for (i = 0; i <= ints[0] && i < 2; i++) js_tg[i] = ints[i+1];
+	return 1;
 }
+int __init js_tg_setup_2(SETUP_PARAM)
+{
+	int i;
+	SETUP_PARSE(2);
+	for (i = 0; i <= ints[0] && i < 2; i++) js_tg_2[i] = ints[i+1];
+	return 1;
+}
+int __init js_tg_setup_3(SETUP_PARAM)
+{
+	int i;
+	SETUP_PARSE(2);
+	for (i = 0; i <= ints[0] && i < 2; i++) js_tg_3[i] = ints[i+1];
+	return 1;
+}
+__setup("js_tg=", js_tg_setup);
+__setup("js_tg_2=", js_tg_setup_2);
+__setup("js_tg_3=", js_tg_setup_3);
 #endif
 
 #ifdef MODULE
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joy-warrior.c linux.14p16/drivers/char/joystick/joy-warrior.c
--- linux.vanilla/drivers/char/joystick/joy-warrior.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/char/joystick/joy-warrior.c	Tue Dec 21 00:31:12 1999
@@ -0,0 +1,318 @@
+/*
+ *  joy-warrior.c  Version 0.1
+ *
+ *  Copyright (c) 1998 David Thompson
+ *  Copyright (c) 1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This is a module for the Linux joystick driver, supporting
+ * the Logitech WingMan Warrior joystick.
+ */
+
+/*
+ * This program is free warftware; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ *  Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/errno.h>
+#include <linux/joystick.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+
+/*
+ * Constants.
+ */
+
+#define	N_JOYSTICK_WAR		13
+#define JS_WAR_MAX_LENGTH	16
+
+/*
+ * List of Warriors.
+ */
+
+static struct js_port* js_war_port = NULL;
+
+static char js_war_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 }; 
+
+/*
+ * Per-Warrior data.
+ */
+
+struct js_war_info {
+	struct tty_struct* tty;
+	struct js_port* port;
+	int idx;
+	int len;
+	unsigned char data[JS_WAR_MAX_LENGTH];
+	char used;
+};
+
+/*
+ * js_war_process_packet() decodes packets the driver receives from the
+ * Warrior. It updates the data accordingly.
+ */
+
+static void js_war_process_packet(struct js_war_info* info)
+{
+	int **axes = info->port->axes;
+	int **buttons = info->port->buttons;
+	unsigned char *data = info->data;
+	int i;
+
+	if (!info->idx) return;
+
+	switch ((data[0] >> 4) & 7) {
+
+		case 1:					/* Button data */
+			if (!info->port->devs[0]) return;
+			buttons[0][0] = ((data[3] & 0xa) >> 1) | ((data[3] & 0x5) << 1);
+			return;
+		case 2:					/* Static status (Send !S to get one) */
+#if 0
+			printk("joy-warrior: Static status:");
+			for (i = 0; i < 12; i++)
+				printk(" %02x", info->data[i]);
+			printk("\n");
+#endif
+			return;
+		case 3:					/* XY-axis info->data */
+			if (!info->port->devs[0]) return;
+			axes[0][0] = ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5));
+			axes[0][1] = (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7);
+			return;
+			break;
+		case 4:					/* Dynamic status */
+#if 0
+			printk("joy-warrior: Dynamic status:");
+			for (i = 0; i < 4; i++)
+				printk(" %02x", info->data[i]);
+			printk("\n");
+#endif
+			return;
+		case 5:					/* Throttle, spinner, hat info->data */
+			if (!info->port->devs[0]) return;
+			axes[0][2] = (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7);
+			axes[0][3] = (data[3] & 2 ? 1 : 0) - (info->data[3] & 1 ? 1 : 0);
+			axes[0][4] = (data[3] & 8 ? 1 : 0) - (info->data[3] & 4 ? 1 : 0);
+			axes[0][5] = (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5);
+			return;
+		default:
+			printk("joy-warrior: Unknown packet %d length %d:", (data[0] >> 4) & 7, info->idx);
+			for (i = 0; i < info->idx; i++)
+				printk(" %02x", data[i]);
+			printk("\n");
+			return;
+	}
+}
+
+/*
+ * js_war_open() is a callback from the joystick device open routine.
+ */
+
+static int js_war_open(struct js_dev *jd)
+{
+	struct js_war_info *info = jd->port->info;
+	info->used++;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * js_war_close() is a callback from the joystick device release routine.
+ */
+
+static int js_war_close(struct js_dev *jd)
+{
+	struct js_war_info *info = jd->port->info;
+	if (!--info->used) {
+		js_unregister_device(jd->port->devs[0]);
+		js_war_port = js_unregister_port(jd->port);
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * js_war_init_corr() initializes the correction values for the Warrior.
+ */
+
+static void __init js_war_init_corr(struct js_corr **corr)
+{
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		corr[0][i].type = JS_CORR_BROKEN;
+		corr[0][i].prec = 0;
+		corr[0][i].coef[0] = -8;
+		corr[0][i].coef[1] = 8;
+		corr[0][i].coef[2] = (1 << 29) / (128 - 64);
+		corr[0][i].coef[3] = (1 << 29) / (128 - 64);
+	}
+
+	corr[0][2].coef[2] = (1 << 29) / (128 - 16);
+	corr[0][2].coef[3] = (1 << 29) / (128 - 16);
+
+	for (i = 3; i < 5; i++) {
+		corr[0][i].coef[0] = 0;
+		corr[0][i].coef[1] = 0;
+		corr[0][i].coef[2] = (1 << 29);
+		corr[0][i].coef[3] = (1 << 29);
+	}
+
+	corr[0][5].prec = -1;
+	corr[0][5].coef[0] = 0;
+	corr[0][5].coef[1] = 0;
+	corr[0][5].coef[2] = (1 << 29) / 128;
+	corr[0][5].coef[3] = (1 << 29) / 128;
+}
+
+/*
+ * js_war_ldisc_open() is the routine that is called upon setting our line
+ * discipline on a tty.
+ */
+
+static int js_war_ldisc_open(struct tty_struct *tty)
+{
+	struct js_war_info iniinfo;
+	struct js_war_info *info = &iniinfo;
+
+	info->tty = tty;
+	info->idx = 0;
+	info->len = 0;
+	info->used = 1;
+
+	js_war_port = js_register_port(js_war_port, info, 1, sizeof(struct js_war_info), NULL);
+
+	info = js_war_port->info;
+	info->port = js_war_port;
+	tty->disc_data = info;
+
+	printk(KERN_INFO "js%d: WingMan Warrior on %s%d\n",
+		js_register_device(js_war_port, 0, 6, 4, "WingMan Warrior", js_war_open, js_war_close),
+		tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
+
+	js_war_init_corr(js_war_port->corr);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+/*
+ * js_war_ldisc_close() is the opposite of js_war_ldisc_open()
+ */
+
+static void js_war_ldisc_close(struct tty_struct *tty)
+{
+	struct js_war_info* info = (struct js_war_info*) tty->disc_data;
+	if (!--info->used) {
+		js_unregister_device(info->port->devs[0]);
+		js_war_port = js_unregister_port(info->port);
+	}
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * js_war_ldisc_receive() is called by the low level driver when characters
+ * are ready for us. We then buffer them for further processing, or call the
+ * packet processing routine.
+ */
+
+static void js_war_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+{
+	struct js_war_info* info = (struct js_war_info*) tty->disc_data;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		if (cp[i] & 0x80) {
+			if (info->idx)
+				js_war_process_packet(info);
+			info->idx = 0;
+			info->len = js_war_lengths[(cp[i] >> 4) & 7];
+		}
+
+		if (info->idx < JS_WAR_MAX_LENGTH)
+			info->data[info->idx++] = cp[i];
+
+		if (info->idx == info->len) {
+			if (info->idx)
+				js_war_process_packet(info);	
+			info->idx = 0;
+			info->len = 0;
+		}
+	}
+}
+
+/*
+ * js_war_ldisc_room() reports how much room we do have for receiving data.
+ * Although we in fact have infinite room, we need to specify some value
+ * here, so why not the size of our packet buffer. It's big anyway.
+ */
+
+static int js_war_ldisc_room(struct tty_struct *tty)
+{
+	return JS_WAR_MAX_LENGTH;
+}
+
+/*
+ * The line discipline structure.
+ */
+
+static struct tty_ldisc js_war_ldisc = {
+        magic:          TTY_LDISC_MAGIC,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+        name:           "warrior",
+#endif
+	open:		js_war_ldisc_open,
+	close:		js_war_ldisc_close,
+	receive_buf:	js_war_ldisc_receive,
+	receive_room:	js_war_ldisc_room,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+#ifdef MODULE
+int init_module(void)
+#else
+int __init js_war_init(void)
+#endif
+{
+        if (tty_register_ldisc(N_JOYSTICK_WAR, &js_war_ldisc)) {
+                printk(KERN_ERR "joy-warrior: Error registering line discipline.\n");
+		return -ENODEV;
+	}
+
+	return  0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	tty_register_ldisc(N_JOYSTICK_WAR, NULL);
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/joystick/joystick.c linux.14p16/drivers/char/joystick/joystick.c
--- linux.vanilla/drivers/char/joystick/joystick.c	Wed Dec  2 03:05:05 1998
+++ linux.14p16/drivers/char/joystick/joystick.c	Tue Dec 21 00:31:12 1999
@@ -1,7 +1,9 @@
 /*
- * joystick.c  Version 1.2
+ *  joystick.c  Version 1.2
  *
- * Copyright (c) 1996-1998 Vojtech Pavlik
+ *  Copyright (c) 1996-1999 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
  */
 
 /*
@@ -26,14 +28,13 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  */
 
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/segment.h>
-#include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/joystick.h>
@@ -42,10 +43,9 @@
 #include <linux/malloc.h>
 #include <linux/mm.h>
 #include <linux/module.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-#include <asm/spinlock.h>
 #include <linux/poll.h>
-#endif
+#include <linux/config.h>
+#include <linux/init.h>
 
 /*
  * Configurable parameters.
@@ -54,6 +54,15 @@
 #define JS_REFRESH_TIME		HZ/50	/* Time between two reads of joysticks (20ms) */
 
 /*
+ * Exported symbols.
+ */
+
+EXPORT_SYMBOL(js_register_port);
+EXPORT_SYMBOL(js_unregister_port);
+EXPORT_SYMBOL(js_register_device);
+EXPORT_SYMBOL(js_unregister_device);
+
+/*
  * Buffer macros.
  */
 
@@ -74,263 +83,13 @@
 static int js_use_count = 0;
 
 /*
- * Exported variables.
- */
-
-unsigned int js_time_speed = 0;
-js_time_func js_get_time;
-js_delta_func js_delta;
-
-unsigned int js_time_speed_a = 0;
-js_time_func js_get_time_a;
-js_delta_func js_delta_a;
-
-/*
  * Module info.
  */
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_SUPPORTED_DEVICE("js");
 
 /*
- * js_get_time_*() are different functions to get current time.
- * js_delta_*() are functions to compute time difference.
- */
-
-#ifdef __i386__
-
-static unsigned int js_get_time_rdtsc(void)
-{
-	unsigned int x;
-	__asm__ __volatile__ ( "rdtsc" : "=A" (x) );
-	return x;
-}
-
-static unsigned int js_get_time_pit(void)
-{
-	unsigned long flags;
-	unsigned int x;
-
-	__save_flags(flags);
-	__cli();
-	outb(0, 0x43);
-	x = inb(0x40);
-	x |= inb(0x40) << 8;
-	__restore_flags(flags);
-
-	return x;
-}
-
-static int js_delta_pit(unsigned int x, unsigned int y)
-{
-	return y - x + ( y < x ? 1193180L / HZ : 0 );
-}
-
-static unsigned int js_get_time_counter(void)
-{
-	static int time_counter = 0;
-	return time_counter++;
-}
-
-#else
-#ifdef __alpha__
-
-static unsigned int js_get_time_rpcc(void)
-{
-	unsigned int x;
-	__asm__ __volatile__ ( "rpcc %0" : "=r" (x) );
-	return x;
-}
-
-#else
-
-#ifndef MODULE
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-static unsigned int js_get_time_system(void)
-{
-	static struct timeval js_tv;
-	get_fast_time(&js_tv);
-	return js_tv.tv_sec * 1000000L + js_tv.tv_usec;
-}
-#endif
-#endif
-
-#endif
-#endif
-
-static int js_delta_normal(unsigned int x, unsigned int y)
-{
-	return x - y;
-}
-
-/*
- * js_calibrate_time() calibrates a given timer.
- */
-
-static int __init js_calibrate_time(js_time_func get_time, js_delta_func delta)
-{
-	unsigned int t1, t2, t3;
-	unsigned long flags;
-
-	__save_flags(flags);
-	__cli();
-	t1 = get_time();
-	udelay(1000);
-	t2 = get_time();
-	t3 = get_time();
-	__restore_flags(flags);
-
-	return delta(t2, t1) - delta(t3, t2);
-}
-
-/*
- * js_calibrate_time_counter() calibrates the counter timer, which can't
- * be calibrated using the above function.
- */
-
-#ifdef __i386__
-
-static int __init js_calibrate_time_counter(void)
-{
-	unsigned int i, j, t1, t2, t3;
-
-	j = jiffies; do { inb(0x201); t1 = js_get_time_counter(); } while (j == jiffies);
-	j = jiffies; do { inb(0x201); t2 = js_get_time_counter(); } while (j == jiffies);
-
-	j = (t2 - t1) * HZ / 1000;
-
-	t1 = js_get_time_pit();
-	for (i = 0; i < 1000; i++) {
-		inb(0x201);
-		js_get_time_counter();
-	}
-	t2 = js_get_time_pit();
-	t3 = js_get_time_pit();
-
-	i = 1193180L / (js_delta_pit(t2, t1) - js_delta_pit(t3, t2));
-
-	if (DIFF(i,j) > 5)
-		printk(KERN_WARNING "js: Counter timer calibration unsure,"
-			" pass1 (0.%d MHz) and pass2 (0.%d MHz) differ.\n", j, i);
-
-	return (i + j) >> 1;
-}
-
-#endif
-
-/*
- * js_setup_time chooses the best available timers
- * on the system and calibrates them.
- */
-
-static int __init js_setup_time(void)
-{
-	int t;
-	char *name, *name_a;
-
-	name = "";
-	name_a = "";
-	js_time_speed = 0;
-	js_time_speed_a = 0;
-
-#ifdef __i386__
-
-	t = js_calibrate_time(js_get_time_pit, js_delta_pit);
-
-	if (DIFF(t, 1193) > 5)
-		printk(KERN_WARNING "js: Measured PIT speed is %d.%03d MHz, but should be 1.193 MHz.\n"
-		       KERN_WARNING "js: This is probably caused by wrong BogoMIPS value. It is: %ld, should be: %ld.\n",
-			t / 1000, t % 1000, loops_per_sec / 500000, loops_per_sec / (t * 500000 / 1193));
-
-	if (JS_HAS_RDTSC && (t = js_calibrate_time(js_get_time_rdtsc, js_delta_normal)) > 0) {
-
-		js_time_speed_a = t;
-		js_get_time_a = js_get_time_rdtsc;
-		js_delta_a = js_delta_normal;
-		js_time_speed = t;
-		js_get_time = js_get_time_rdtsc;
-		js_delta = js_delta_normal;
-		name = "RDTSC";
-
-	} else {
-
-		js_time_speed_a = t;
-		js_get_time_a = js_get_time_pit;
-		js_delta_a = js_delta_pit;
-		name_a = "PIT";
-
-		t = js_calibrate_time_counter();
-
-		js_time_speed = t;
-		js_get_time = js_get_time_counter;
-		js_delta = js_delta_normal;
-		name = "counter";
-
-	}
-
-#else
-#ifdef __alpha__
-
-	t = js_calibrate_time(js_get_time_rpcc, js_delta_normal);
-
-	js_time_speed_a = t;
-	js_get_time_a = js_get_time_rpcc;
-	js_delta_a = js_delta_normal;
-	js_time_speed = t;
-	js_get_time = js_get_time_rpcc;
-	js_delta = js_delta_normal;
-	name = "RPCC";
-
-#else
-
-#ifndef MODULE
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-	t = js_calibrate_time(js_get_time_system, js_delta_normal);
-
-	js_time_speed_a = t;
-	js_get_time_a = js_get_time_system;
-	js_delta_a = js_delta_normal;
-	js_time_speed = t;
-	js_get_time = js_get_time_system;
-	js_delta = js_delta_normal;
-	name = "system";
-#endif
-#endif
-
-#endif
-#endif
-
-	printk(KERN_INFO "js: Version %d.%d.%d ",
-		JS_VERSION >> 16 & 0xff, JS_VERSION >> 8 & 0xff, JS_VERSION & 0xff);
-
-	if (js_time_speed_a <= 0 || js_time_speed <= 0) {
-		printk("\n");
-		return -1;
-	}
-
-	printk("using ");
-
-	if (js_time_speed > 10000) {
-		t = js_time_speed / 1000 + (js_time_speed % 1000 >= 500);
-		printk("%d MHz ", t);
-	} else {
-		t = js_time_speed / 10 + (js_time_speed % 10 >= 5);
-		printk("%d.%02d MHz ", t / 100, t % 100);
-	}
-
-	if (js_get_time_a != js_get_time) {
-		t = js_time_speed_a / 10 + (js_time_speed_a % 10 >= 5);
-		printk("%s timer and %d.%02d MHz %s timer.\n",
-			name, t / 100, t % 100, name_a);
-	} else {
-		printk("%s timer.\n", name);
-	}
-
-	return 0;
-}
-
-
-/*
  * js_correct() performs correction of raw joystick data.
  */
 
@@ -364,7 +123,6 @@
 	return (buttons[i >> 5] >> (i & 0x1f)) & 1;
 }
 
-
 /*
  * js_add_event() adds an event to the buffer. This requires additional
  * queue post-processing done by js_sync_buff.
@@ -457,14 +215,17 @@
 	struct js_dev *curd = js_dev;
 	unsigned long flags;
 
-	while (curp != NULL) {
-		curp->read(curp->info, curp->axes, curp->buttons);
+	while (curp) {
+		if (curp->read) 
+			if (curp->read(curp->info, curp->axes, curp->buttons))
+				curp->fail++;
+		curp->total++;
 		curp = curp->next;
 	}
 
 	spin_lock_irqsave(&js_lock, flags);
 
-	while (curd != NULL) {
+	while (curd) {
 		if (data) {
 			js_process_data(curd);
 			js_sync_buff(curd);
@@ -485,13 +246,9 @@
  * space.
  */
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
 static ssize_t js_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-#else
-static int js_read(struct inode *inode, struct file *file, char *buf, int count)
-#endif
 {
-	struct wait_queue wait = { current, NULL };
+	DECLARE_WAITQUEUE(wait, current);
 	struct js_event *buff = (void *) buf;
 	struct js_list *curl;
 	struct js_dev *jd;
@@ -525,8 +282,8 @@
 
 		if (GOF(curl->tail) == jd->bhead && curl->startup == jd->num_axes + jd->num_buttons) {
 
+			__set_current_state(TASK_INTERRUPTIBLE);
 			add_wait_queue(&jd->wait, &wait);
-			current->state = TASK_INTERRUPTIBLE;
 
 			while (GOF(curl->tail) == jd->bhead) {
 
@@ -575,13 +332,8 @@
 
 			tmpevent.time = jiffies * (1000/HZ);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
 			if (copy_to_user(&buff[written], &tmpevent, sizeof(struct js_event)))
 				retval = -EFAULT;
-#else
-			if (!(retval = verify_area(VERIFY_WRITE, &buff[written], sizeof(struct js_event))))
-				memcpy_tofs(&buff[written], &tmpevent, sizeof(struct js_event));
-#endif
 
 			curl->startup++;
 			written++;
@@ -593,17 +345,11 @@
 
 		while ((jd->bhead != (new_tail = GOF(curl->tail))) && (written < blocks) && !retval) {
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
 			if (copy_to_user(&buff[written], &jd->buff[new_tail], sizeof(struct js_event)))
 				retval = -EFAULT;
 			if (put_user((__u32)(jd->buff[new_tail].time * (1000/HZ)), &buff[written].time))
 				retval = -EFAULT;
-#else
-			if (!(retval = verify_area(VERIFY_WRITE, &buff[written], sizeof(struct js_event)))) {
-				memcpy_tofs(&buff[written], &jd->buff[new_tail], sizeof(struct js_event));
-				put_user((__u32)(jd->buff[new_tail].time * (1000/HZ)), &buff[written].time);
-			}
-#endif
+
 			curl->tail = new_tail;
 			written++;
 		}
@@ -624,15 +370,9 @@
 		data.y = jd->num_axes < 2 ? 0 :
 			((js_correct(jd->new.axes[1], &jd->corr[1]) / 256) + 128) >> js_comp_glue.JS_CORR.y;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
 		retval = copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
-#else
-		if (!(retval = verify_area(VERIFY_WRITE, buf, sizeof(struct JS_DATA_TYPE)))) {
-			memcpy_tofs(buf, &data, sizeof(struct JS_DATA_TYPE));
-		}
-#endif
 
-		curl->startup = 0;
+		curl->startup = jd->num_axes + jd->num_buttons;
 		curl->tail = GOB(jd->bhead);
 		if (!retval) retval = sizeof(struct JS_DATA_TYPE);
 	}
@@ -644,12 +384,12 @@
 	if (orig_tail == jd->tail) {
 		new_tail = curl->tail;
 		curl = jd->list;
-		while (curl != NULL && curl->tail != jd->tail) {
+		while (curl && curl->tail != jd->tail) {
 			if (ROT(jd->bhead, new_tail, curl->tail) ||
 				(jd->bhead == curl->tail)) new_tail = curl->tail;
 			curl = curl->next;
 		}
-		if (curl == NULL) jd->tail = new_tail;
+		if (!curl) jd->tail = new_tail;
 	}
 
 	spin_unlock_irqrestore(&js_lock, flags);
@@ -661,8 +401,6 @@
  * js_poll() does select() support.
  */
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-
 static unsigned int js_poll(struct file *file, poll_table *wait)
 {
 	struct js_list *curl = file->private_data;
@@ -676,20 +414,6 @@
 	return retval;
 }
 
-#else
-
-static int js_select(struct inode *inode, struct file *file, int sel_type, select_table *wait)
-{
-	struct js_list *curl = file->private_data;
-	if (sel_type == SEL_IN) {
-		if (GOF(curl->tail) != curl->dev->bhead) return 1;
-		select_wait(&curl->dev->wait, wait);
-	}
-	return 0;
-}
-
-#endif
-
 /*
  * js_ioctl handles misc ioctl calls.
  */
@@ -703,8 +427,6 @@
 	curl = file->private_data;
 	jd = curl->dev;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-
 	switch (cmd) {
 
 /*
@@ -757,95 +479,6 @@
 			}
 	}
 
-#else
-
-	switch (cmd) {
-
-/*
- * 0.x compatibility
- */
-
-		case JS_SET_CAL:
-			if (verify_area(VERIFY_READ, (struct JS_DATA_TYPE *) arg,
-				sizeof(struct JS_DATA_TYPE))) return -EFAULT;
-			memcpy_fromfs(&js_comp_glue.JS_CORR, (struct JS_DATA_SAVE_TYPE *) arg,
-				sizeof(struct JS_DATA_TYPE));
-			return 0;
-		case JS_GET_CAL:
-			if (verify_area(VERIFY_WRITE, (struct JS_DATA_TYPE *) arg,
-				sizeof(struct JS_DATA_TYPE))) return -EFAULT;
-			memcpy_tofs((struct JS_DATA_SAVE_TYPE *) arg, &js_comp_glue.JS_CORR,
-				sizeof(struct JS_DATA_TYPE));
-			return 0;
-		case JS_SET_TIMEOUT:
-			if (verify_area(VERIFY_READ, (int *) arg, sizeof(int))) return -EFAULT;
-			js_comp_glue.JS_TIMEOUT = get_user((int *) arg);
-			return 0;
-		case JS_GET_TIMEOUT:
-			if (verify_area(VERIFY_WRITE, (int *) arg, sizeof(int))) return -EFAULT;
-			put_user(js_comp_glue.JS_TIMEOUT, (int *) arg);
-			return 0;
-		case JS_SET_TIMELIMIT:
-			if (verify_area(VERIFY_READ, (long *) arg, sizeof(long))) return -EFAULT;
-			js_comp_glue.JS_TIMELIMIT = get_user((long *) arg);
-			return 0;
-		case JS_GET_TIMELIMIT:
-			if (verify_area(VERIFY_WRITE, (long *) arg, sizeof(long))) return -EFAULT;
-			put_user(js_comp_glue.JS_TIMELIMIT, (long *) arg);
-			return 0;
-		case JS_SET_ALL:
-			if (verify_area(VERIFY_READ, (struct JS_DATA_SAVE_TYPE *) arg,
-				sizeof(struct JS_DATA_SAVE_TYPE))) return -EFAULT;
-			memcpy_fromfs(&js_comp_glue, (struct JS_DATA_SAVE_TYPE *) arg,
-				sizeof(struct JS_DATA_SAVE_TYPE));
-			return 0;
-		case JS_GET_ALL:
-			if (verify_area(VERIFY_WRITE, (struct JS_DATA_SAVE_TYPE *) arg,
-				sizeof(struct JS_DATA_SAVE_TYPE))) return -EFAULT;
-			memcpy_tofs((struct JS_DATA_SAVE_TYPE *) arg, &js_comp_glue,
-				sizeof(struct JS_DATA_SAVE_TYPE));
-			return 0;
-
-/*
- * 1.x ioctl calls
- */
-
-		case JSIOCGVERSION:
-			if (verify_area(VERIFY_WRITE, (__u32 *) arg, sizeof(__u32))) return -EFAULT;
-			put_user(JS_VERSION, (__u32 *) arg);
-			return 0;
-		case JSIOCGAXES:
-			if (verify_area(VERIFY_WRITE, (__u8 *) arg, sizeof(__u8))) return -EFAULT;
-			put_user(jd->num_axes, (__u8 *) arg);
-			return 0;
-		case JSIOCGBUTTONS:
-			if (verify_area(VERIFY_WRITE, (__u8 *) arg, sizeof(__u8))) return -EFAULT;
-			put_user(jd->num_buttons, (__u8 *) arg);
-			return 0;
-		case JSIOCSCORR:
-			if (verify_area(VERIFY_READ, (struct js_corr *) arg,
-				sizeof(struct js_corr) * jd->num_axes)) return -EFAULT;
-			memcpy_fromfs(jd->corr, (struct js_corr *) arg,
-				sizeof(struct js_corr) * jd->num_axes);
-			return 0;
-		case JSIOCGCORR:
-			if (verify_area(VERIFY_WRITE, (struct js_corr *) arg,
-				sizeof(struct js_corr) * jd->num_axes)) return -EFAULT;
-			memcpy_tofs((struct js_corr *) arg,
-				jd->corr, sizeof(struct js_corr) * jd->num_axes);
-			return 0;
-		default:
-			if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
-				len = strlen(jd->name) + 1;
-				if (verify_area(VERIFY_WRITE, (char *) arg, len)) return -EFAULT;
-				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-				memcpy_tofs((char *) arg, jd->name, len);
-				return len;
-			}
-	}
-
-#endif
-
 	return -EINVAL;
 }
 
@@ -867,21 +500,20 @@
 
 	spin_lock_irqsave(&js_lock, flags);
 
-	while (i > 0 && jd != NULL) {
+	while (i > 0 && jd) {
 		jd = jd->next;
 		i--;
 	}
 
 	spin_unlock_irqrestore(&js_lock, flags);
 
-	if (jd == NULL) return -ENODEV;
+	if (!jd) return -ENODEV;
 
 	if ((result = jd->open(jd))) return result;
 
-	MOD_INC_USE_COUNT;
-	if (!js_use_count++) js_do_timer(0);
+	if ((new = kmalloc(sizeof(struct js_list), GFP_KERNEL))) {
 
-	if ((new = kmalloc(sizeof(struct js_list), GFP_KERNEL)) != NULL) {
+		MOD_INC_USE_COUNT;
 
 		spin_lock_irqsave(&js_lock, flags);
 
@@ -896,6 +528,8 @@
 
 		spin_unlock_irqrestore(&js_lock, flags);
 
+		if (!js_use_count++) js_do_timer(0);
+
 	} else {
 		result = -ENOMEM;
 	}
@@ -908,11 +542,7 @@
  * used by it.
  */
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
 static int js_release(struct inode *inode, struct file *file)
-#else
-static void js_release(struct inode *inode, struct file *file)
-#endif
 {
 	struct js_list *curl = file->private_data;
 	struct js_dev *jd = curl->dev;
@@ -925,11 +555,11 @@
 	while (*curp && (*curp != curl)) curp = &((*curp)->next);
 	*curp = (*curp)->next;
 
-	if (jd->list != NULL)
+	if (jd->list)
 	if (curl->tail == jd->tail) {
 		curl = jd->list;
 		new_tail = curl->tail;
-		while (curl != NULL && curl->tail != jd->tail) {
+		while (curl && curl->tail != jd->tail) {
 			if (ROT(jd->bhead, new_tail, curl->tail) ||
 			       (jd->bhead == curl->tail)) new_tail = curl->tail;
 			curl = curl->next;
@@ -946,9 +576,7 @@
 
 	jd->close(jd);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
 	return 0;
-#endif
 }
 
 /*
@@ -967,7 +595,7 @@
 	printk(",--- Dumping Devices:\n");
 	printk("| js_dev = %x\n", (int) js_dev);
 
-	while (curd != NULL) {
+	while (curd) {
 		printk("|  %s-device %x, next %x axes %d, buttons %d, port %x - %#x\n",
 			curd->next ? "|":"`",
 			(int) curd, (int) curd->next, curd->num_axes, curd->num_buttons, (int) curd->port, curd->port->io);
@@ -977,7 +605,7 @@
 	printk(">--- Dumping ports:\n");
 	printk("| js_port = %x\n", (int) js_port);
 
-	while (curp != NULL) {
+	while (curp) {
 		printk("|  %s-port %x, next %x, io %#x, devices %d\n",
 			curp->next ? "|":"`",
 			(int) curp, (int) curp->next, curp->io, curp->ndevs);
@@ -1009,7 +637,7 @@
 	int i;
 	unsigned long flags;
 
-	if ((all = kmalloc(sizeof(struct js_port) + 4 * devs * sizeof(void*) + infos, GFP_KERNEL)) == NULL)
+	if (!(all = kmalloc(sizeof(struct js_port) + 4 * devs * sizeof(void*) + infos, GFP_KERNEL)))
 		return NULL;
 
 	curp = all;
@@ -1018,6 +646,8 @@
 	curp->prev = port;
 	curp->read = read;
 	curp->ndevs = devs;
+	curp->fail = 0;
+	curp->total = 0;
 
 	curp->devs = all += sizeof(struct js_port);
 	for (i = 0; i < devs; i++) curp->devs[i] = NULL;
@@ -1035,7 +665,7 @@
 
 	spin_lock_irqsave(&js_lock, flags);
 
-	while (*ptrp != NULL) ptrp=&((*ptrp)->next);
+	while (*ptrp) ptrp=&((*ptrp)->next);
 	*ptrp = curp;
 
 	spin_unlock_irqrestore(&js_lock, flags);
@@ -1051,7 +681,9 @@
 
 	spin_lock_irqsave(&js_lock, flags);
 
-	while (*curp != NULL && (*curp != port)) curp = &((*curp)->next);
+	printk("js: There were %d failures out of %d read attempts.\n", port->fail, port->total);
+
+	while (*curp && (*curp != port)) curp = &((*curp)->next);
 	*curp = (*curp)->next;
 
 	spin_unlock_irqrestore(&js_lock, flags);
@@ -1071,9 +703,9 @@
 	int i = 0;
 	unsigned long flags;
 
-	if ((all = kmalloc(sizeof(struct js_dev) + 2 * axes * sizeof(int) +
+	if (!(all = kmalloc(sizeof(struct js_dev) + 2 * axes * sizeof(int) +
 			2 * (((buttons - 1) >> 5) + 1) * sizeof(int) +
-			axes * sizeof(struct js_corr) + strlen(name) + 1, GFP_KERNEL)) == NULL)
+			axes * sizeof(struct js_corr) + strlen(name) + 1, GFP_KERNEL)))
 		return -1;
 
 	curd = all;
@@ -1081,10 +713,11 @@
 	curd->next = NULL;
 	curd->list = NULL;
 	curd->port = port;
-	curd->wait = NULL;
 	curd->open = open;
 	curd->close = close;
 
+	init_waitqueue_head(&curd->wait);
+
 	curd->ahead = 0;
 	curd->bhead = 0;
 	curd->tail = JS_BUFF_SIZE - 1;
@@ -1107,7 +740,7 @@
 
 	spin_lock_irqsave(&js_lock, flags);
 
-	while (*ptrd != NULL) { ptrd=&(*ptrd)->next; i++; }
+	while (*ptrd) { ptrd=&(*ptrd)->next; i++; }
 	*ptrd = curd;
 
 	spin_unlock_irqrestore(&js_lock, flags);	
@@ -1122,7 +755,7 @@
 
 	spin_lock_irqsave(&js_lock, flags);
 
-	while (*curd != NULL && (*curd != dev)) curd = &((*curd)->next);
+	while (*curd && (*curd != dev)) curd = &((*curd)->next);
 	*curd = (*curd)->next;
 
 	spin_unlock_irqrestore(&js_lock, flags);	
@@ -1137,11 +770,7 @@
 static struct file_operations js_fops =
 {
 	read:		js_read,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
 	poll:		js_poll,
-#else
-	select:		js_select,
-#endif
 	ioctl:		js_ioctl,
 	open:		js_open,
 	release:	js_release,
@@ -1158,15 +787,15 @@
 int __init js_init(void)
 #endif
 {
-	int result;
-
-	js_setup_time();
 
 	if (register_chrdev(JOYSTICK_MAJOR, "js", &js_fops)) {
 		printk(KERN_ERR "js: unable to get major %d for joystick\n", JOYSTICK_MAJOR);
 		return -EBUSY;
 	}
 
+	printk(KERN_INFO "js: Joystick driver v%d.%d.%d (c) 1999 Vojtech Pavlik <vojtech@suse.cz>\n",
+		JS_VERSION >> 16 & 0xff, JS_VERSION >> 8 & 0xff, JS_VERSION & 0xff);
+
 	spin_lock_init(&js_lock);
 
 	init_timer(&js_timer);
@@ -1177,44 +806,61 @@
 	js_comp_glue.JS_TIMEOUT = JS_DEF_TIMEOUT;
 	js_comp_glue.JS_TIMELIMIT = JS_DEF_TIMELIMIT;
 
-#ifdef MODULE
-	result = 0;
-#else
-	result = -ENODEV;
+#ifndef MODULE
+#ifdef CONFIG_JOY_PCI
+	js_pci_init();
+#endif
 #ifdef CONFIG_JOY_LIGHTNING
-	if (!js_l4_init()) result = 0;
+	js_l4_init();
 #endif
 #ifdef CONFIG_JOY_SIDEWINDER
-	if (!js_sw_init()) result = 0;
+	js_sw_init();
 #endif
-#ifdef CONFIG_JOY_ASSASIN
-	if (!js_as_init()) result = 0;
+#ifdef CONFIG_JOY_ASSASSIN
+	js_as_init();
 #endif
 #ifdef CONFIG_JOY_LOGITECH
-	if (!js_lt_init()) result = 0;
+	js_lt_init();
 #endif
 #ifdef CONFIG_JOY_THRUSTMASTER
-	if (!js_tm_init()) result = 0;
+	js_tm_init();
 #endif
 #ifdef CONFIG_JOY_GRAVIS
-	if (!js_gr_init()) result = 0;
+	js_gr_init();
+#endif
+#ifdef CONFIG_JOY_CREATIVE
+	js_cr_init();
 #endif
 #ifdef CONFIG_JOY_ANALOG
-	if (!js_an_init()) result = 0;
+	js_an_init();
 #endif
 #ifdef CONFIG_JOY_CONSOLE
-	if (!js_console_init()) result = 0;
+	js_console_init();
 #endif
 #ifdef CONFIG_JOY_DB9
-	if (!js_db9_init()) result = 0;
+	js_db9_init();
+#endif
+#ifdef CONFIG_JOY_TURBOGRAFX
+	js_tg_init();
 #endif
 #ifdef CONFIG_JOY_AMIGA
-	if (!js_am_init()) result = 0;
+	js_am_init();
+#endif
+#ifdef CONFIG_JOY_MAGELLAN
+	js_mag_init();
+#endif
+#ifdef CONFIG_JOY_WARRIOR
+	js_war_init();
+#endif
+#ifdef CONFIG_JOY_SPACEORB
+	js_orb_init();
+#endif
+#ifdef CONFIG_JOY_SPACEBALL
+	js_sball_init();
 #endif
-	if (result) printk(KERN_ERR "js: no joysticks found\n");
 #endif
 
-	return result;
+	return 0;
 }
 
 /*
@@ -1229,3 +875,4 @@
 		printk(KERN_ERR "js: can't unregister device\n");
 }
 #endif
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/lp.c linux.14p16/drivers/char/lp.c
--- linux.vanilla/drivers/char/lp.c	Wed Oct 20 01:12:35 1999
+++ linux.14p16/drivers/char/lp.c	Thu Dec  9 15:33:42 1999
@@ -424,7 +424,7 @@
 {
 	unsigned int last = lp_table[minor].last_error;
 	unsigned char status = r_str(minor);
-	if (status & LP_PERRORP)
+	if ((status & LP_PERRORP) && !(LP_F(minor) & LP_CAREFUL))
 		/* No error. */
 		last = 0;
 	else if ((status & LP_POUTPA)) {
@@ -437,11 +437,14 @@
 			last = LP_PSELECD;
 			printk(KERN_INFO "lp%d off-line\n", minor);
 		}
-	} else {
+	} else if (!(status & LP_PERRORP)) {
 		if (last != LP_PERRORP) {
 			last = LP_PERRORP;
 			printk(KERN_INFO "lp%d on fire\n", minor);
 		}
+	} else {
+		last = 0; /* Come here if LP_CAREFUL is set and no
+                             errors are reported. */
 	}
 
 	lp_table[minor].last_error = last;
@@ -787,14 +790,12 @@
 			else
 				LP_F(minor) &= ~LP_ABORTOPEN;
 			break;
-#ifdef OBSOLETED
 		case LPCAREFUL:
 			if (arg)
 				LP_F(minor) |= LP_CAREFUL;
 			else
 				LP_F(minor) &= ~LP_CAREFUL;
 			break;
-#endif
 		case LPTRUSTIRQ:
 			if (arg)
 				LP_F(minor) |= LP_TRUST_IRQ;
@@ -971,7 +972,8 @@
 			return -EIO;
 		}
 	} else {
-		printk(KERN_INFO "lp: driver loaded but no devices found\n");
+		printk(KERN_INFO "lp: no devices found\n");
+		return -ENODEV;
 	}
 
 	return 0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/mem.c linux.14p16/drivers/char/mem.c
--- linux.vanilla/drivers/char/mem.c	Sat Aug 14 02:27:17 1999
+++ linux.14p16/drivers/char/mem.c	Fri Dec 17 19:05:44 1999
@@ -37,6 +37,9 @@
 #ifdef CONFIG_ISDN
 int isdn_init(void);
 #endif
+#ifdef CONFIG_PHONE
+extern int telephony_init(void);
+#endif
 #ifdef CONFIG_VIDEO_DEV
 extern int videodev_init(void);
 #endif
@@ -681,6 +684,9 @@
 #endif
 #ifdef CONFIG_VIDEO_DEV
 	videodev_init();
+#endif
+#ifdef CONFIG_PHONE
+	telephony_init();
 #endif
 	return 0;
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/mixcomwd.c linux.14p16/drivers/char/mixcomwd.c
--- linux.vanilla/drivers/char/mixcomwd.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/char/mixcomwd.c	Thu Dec  9 15:33:49 1999
@@ -0,0 +1,250 @@
+/*
+ * MixCom Watchdog: A Simple Hardware Watchdog Device
+ * Based on Softdog driver by Alan Cox and PC Watchdog driver by Ken Hollis
+ *
+ * Author: Gergely Madarasz <gorgo@itc.hu>
+ *
+ * Copyright (c) 1999 ITConsult-Pro Co. <info@itc.hu>
+ *
+ * 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.
+ *
+ * Version 0.1 (99/04/15):
+ *		- first version
+ *
+ * Version 0.2 (99/06/16):
+ *		- added kernel timer watchdog ping after close
+ *		  since the hardware does not support watchdog shutdown
+ *
+ * Version 0.3 (99/06/21):
+ *		- added WDIOC_GETSTATUS and WDIOC_GETSUPPORT ioctl calls
+ *
+ * Version 0.3.1 (99/06/22):
+ *		- allow module removal while internal timer is active,
+ *		  print warning about probable reset
+ *	
+ */
+
+#define VERSION "0.3.1" 
+  
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/ioport.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+static int mixcomwd_ioports[] = { 0x180, 0x280, 0x380, 0x000 };
+
+#define MIXCOM_WATCHDOG_OFFSET 0xc10
+#define MIXCOM_ID1 0x11
+#define MIXCOM_ID2 0x13
+
+static int mixcomwd_opened;
+static int mixcomwd_port;
+
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+static int mixcomwd_timer_alive;
+static struct timer_list mixcomwd_timer;
+#endif
+
+static void mixcomwd_ping(void)
+{
+	outb_p(55,mixcomwd_port+MIXCOM_WATCHDOG_OFFSET);
+	return;
+}
+
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+static void mixcomwd_timerfun(unsigned long d)
+{
+	mixcomwd_ping();
+	
+	mod_timer(&mixcomwd_timer,jiffies+ 5*HZ);
+}
+#endif
+
+/*
+ *	Allow only one person to hold it open
+ */
+ 
+static int mixcomwd_open(struct inode *inode, struct file *file)
+{
+	if(test_and_set_bit(0,&mixcomwd_opened)) {
+		return -EBUSY;
+	}
+	mixcomwd_ping();
+	
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+	if(mixcomwd_timer_alive) {
+		del_timer(&mixcomwd_timer);
+		mixcomwd_timer_alive=0;
+	} 
+#endif
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static int mixcomwd_release(struct inode *inode, struct file *file)
+{
+
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+	if(mixcomwd_timer_alive) {
+		printk(KERN_ERR "mixcomwd: release called while internal timer alive");
+		return -EBUSY;
+	}
+	init_timer(&mixcomwd_timer);
+	mixcomwd_timer.expires=jiffies + 5 * HZ;
+	mixcomwd_timer.function=mixcomwd_timerfun;
+	mixcomwd_timer.data=0;
+	mixcomwd_timer_alive=1;
+	add_timer(&mixcomwd_timer);
+#endif
+	MOD_DEC_USE_COUNT;
+
+	clear_bit(0,&mixcomwd_opened);
+	return 0;
+}
+
+
+static ssize_t mixcomwd_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+	if (ppos != &file->f_pos) {
+		return -ESPIPE;
+	}
+
+	if(len)
+	{
+		mixcomwd_ping();
+		return 1;
+	}
+	return 0;
+}
+
+static int mixcomwd_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	int status;
+        static struct watchdog_info ident = {
+		WDIOF_KEEPALIVEPING, 1, "MixCOM watchdog"
+	};
+                                        
+	switch(cmd)
+	{
+		case WDIOC_GETSTATUS:
+			status=mixcomwd_opened;
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+			status|=mixcomwd_timer_alive;
+#endif
+			if (copy_to_user((int *)arg, &status, sizeof(int))) {
+				return -EFAULT;
+			}
+			break;
+		case WDIOC_GETSUPPORT:
+			if (copy_to_user((struct watchdog_info *)arg, &ident, 
+			    sizeof(ident))) {
+				return -EFAULT;
+			}
+			break;
+		case WDIOC_KEEPALIVE:
+			mixcomwd_ping();
+			break;
+		default:
+			return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static struct file_operations mixcomwd_fops=
+{
+	NULL,		/* Seek */
+	NULL,		/* Read */
+	mixcomwd_write,	/* Write */
+	NULL,		/* Readdir */
+	NULL,		/* Select */
+	mixcomwd_ioctl,	/* Ioctl */
+	NULL,		/* MMap */
+	mixcomwd_open,
+	NULL,		/* flush */
+	mixcomwd_release,
+	NULL,		
+	NULL		/* Fasync */
+};
+
+static struct miscdevice mixcomwd_miscdev=
+{
+	WATCHDOG_MINOR,
+	"watchdog",
+	&mixcomwd_fops
+};
+
+__initfunc(static int mixcomwd_checkcard(int port))
+{
+	int id;
+
+	if(check_region(port,1)) {
+		return 0;
+	}
+	
+	id=inb_p(port + MIXCOM_WATCHDOG_OFFSET) & 0x3f;
+	if(id!=MIXCOM_ID1 && id!=MIXCOM_ID2) {
+		return 0;
+	}
+	return 1;
+}
+
+
+__initfunc(void mixcomwd_init(void))
+{
+	int i;
+	int found=0;
+
+	for (i = 0; mixcomwd_ioports[i] != 0; i++) {
+		if (mixcomwd_checkcard(mixcomwd_ioports[i])) {
+			found = 1;
+			mixcomwd_port = mixcomwd_ioports[i];
+			break;
+		}
+	}
+
+	if (!found) {
+		printk("mixcomwd: No card detected, or port not available.\n");
+		return;
+	}
+
+	request_region(mixcomwd_port+MIXCOM_WATCHDOG_OFFSET,1,"MixCOM watchdog");
+	
+	misc_register(&mixcomwd_miscdev);
+	printk("MixCOM watchdog driver v%s, MixCOM card at 0x%3x\n",VERSION,mixcomwd_port);
+}	
+
+#ifdef MODULE
+int init_module(void)
+{
+	mixcomwd_init();
+	return 0;
+}
+
+void cleanup_module(void)
+{
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+	if(mixcomwd_timer_alive) {
+		printk(KERN_WARNING "mixcomwd: I quit now, hardware will"
+			" probably reboot!\n");
+		del_timer(&mixcomwd_timer);
+		mixcomwd_timer_alive=0;
+	}
+#endif
+	release_region(mixcomwd_port+MIXCOM_WATCHDOG_OFFSET,1);
+	misc_deregister(&mixcomwd_miscdev);
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/msbusmouse.c linux.14p16/drivers/char/msbusmouse.c
--- linux.vanilla/drivers/char/msbusmouse.c	Wed Dec 16 21:39:11 1998
+++ linux.14p16/drivers/char/msbusmouse.c	Thu Dec  9 15:33:43 1999
@@ -157,7 +157,8 @@
 		put_user(0x00, buffer + i);
 	mouse.dx -= dx;
 	mouse.dy += dy;
-	mouse.ready = 0;
+	if(mouse.dx == 0 && mouse.dy == 0)
+		mouse.ready = 0;
 	return i;	
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/radio-aimslab.c linux.14p16/drivers/char/radio-aimslab.c
--- linux.vanilla/drivers/char/radio-aimslab.c	Sat Aug 14 02:25:39 1999
+++ linux.14p16/drivers/char/radio-aimslab.c	Thu Dec  9 15:33:47 1999
@@ -195,7 +195,7 @@
 	return 0;
 }
 
-int rt_getsigstr(struct rt_device *dev)
+static int rt_getsigstr(struct rt_device *dev)
 {
 	if (inb(io) & 2)	/* bit set = no signal present	*/
 		return 0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/radio-cadet.c linux.14p16/drivers/char/radio-cadet.c
--- linux.vanilla/drivers/char/radio-cadet.c	Sat Aug 14 02:27:17 1999
+++ linux.14p16/drivers/char/radio-cadet.c	Thu Dec  9 15:33:48 1999
@@ -39,6 +39,7 @@
 static __u8 rdsin=0,rdsout=0,rdsstat=0;
 static unsigned char rdsbuf[RDS_BUFFER];
 static int cadet_lock=0;
+static int cadet_probe(void);
 
 /*
  * Signal Strength Threshold Values
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/radio-rtrack2.c linux.14p16/drivers/char/radio-rtrack2.c
--- linux.vanilla/drivers/char/radio-rtrack2.c	Sat Aug 14 02:25:40 1999
+++ linux.14p16/drivers/char/radio-rtrack2.c	Thu Dec  9 15:33:47 1999
@@ -89,7 +89,7 @@
 	return 0;
 }
 
-int rt_getsigstr(struct rt_device *dev)
+static int rt_getsigstr(struct rt_device *dev)
 {
 	if (inb(io) & 2)	/* bit set = no signal present	*/
 		return 0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/serial.c linux.14p16/drivers/char/serial.c
--- linux.vanilla/drivers/char/serial.c	Wed Oct 20 01:12:35 1999
+++ linux.14p16/drivers/char/serial.c	Thu Dec  9 15:33:43 1999
@@ -61,6 +61,7 @@
  * 		Check the magic number for the async_structure where
  * 		ever possible.
  */
+#include <linux/config.h>
 
 #undef SERIAL_PARANOIA_CHECK
 #define CONFIG_SERIAL_NOPAUSE_IO
@@ -119,7 +120,6 @@
  * End of serial driver configuration section.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/synclink.c linux.14p16/drivers/char/synclink.c
--- linux.vanilla/drivers/char/synclink.c	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/char/synclink.c	Thu Dec  9 15:33:48 1999
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/synclink.c
  *
- * ==FILEDATE 19990901==
+ * ==FILEDATE 19991207==
  *
  * Device driver for Microgate SyncLink ISA and PCI
  * high speed multiprotocol serial adapters.
@@ -925,7 +925,7 @@
 #endif
 
 static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "1.14";
+static char *driver_version = "1.15";
 
 static struct tty_driver serial_driver, callout_driver;
 static int serial_refcount;
@@ -6981,7 +6981,6 @@
 
 	spin_lock_irqsave(&info->irq_spinlock,flags);
 	usc_reset(info);
-	spin_unlock_irqrestore(&info->irq_spinlock,flags);
 
 	/* Verify the reset state of some registers. */
 
@@ -7015,7 +7014,6 @@
 		}
 	}
 
-	spin_lock_irqsave(&info->irq_spinlock,flags);
 	usc_reset(info);
 	spin_unlock_irqrestore(&info->irq_spinlock,flags);
 
@@ -7035,7 +7033,6 @@
 
 	spin_lock_irqsave(&info->irq_spinlock,flags);
 	usc_reset(info);
-	spin_unlock_irqrestore(&info->irq_spinlock,flags);
 
 	/*
 	 * Setup 16C32 to interrupt on TxC pin (14MHz clock) transition. 
@@ -7057,6 +7054,8 @@
 	usc_UnlatchIostatusBits(info, MISCSTATUS_TXC_LATCHED);
 	usc_EnableStatusIrqs(info, SICR_TXC_ACTIVE + SICR_TXC_INACTIVE);
 
+	spin_unlock_irqrestore(&info->irq_spinlock,flags);
+
 	EndTime=100;
 	while( EndTime-- && !info->irq_occurred ) {
 		set_current_state(TASK_INTERRUPTIBLE);
@@ -7359,7 +7358,9 @@
 		}
 	}
 
+	spin_lock_irqsave(&info->irq_spinlock,flags);
 	usc_reset( info );
+	spin_unlock_irqrestore(&info->irq_spinlock,flags);
 
 	/* restore current port options */
 	memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS));
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/tty_io.c linux.14p16/drivers/char/tty_io.c
--- linux.vanilla/drivers/char/tty_io.c	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/char/tty_io.c	Wed Dec 15 22:16:58 1999
@@ -129,6 +129,9 @@
 extern long console_8xx_init(long, long);
 extern int rs_8xx_init(void);
 #endif /* CONFIG_8xx */
+#ifdef CONFIG_3215
+extern long con3215_init(long, long);
+#endif /* CONFIG_3215 */
 
 #ifndef MIN
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
@@ -2070,12 +2073,18 @@
 #ifdef CONFIG_VT
 	kmem_start = con_init(kmem_start);
 #endif
+#ifdef CONFIG_HWC
+        kmem_start = hwc_console_init(kmem_start);
+#endif
 #ifdef CONFIG_SERIAL_CONSOLE
 #ifdef CONFIG_8xx
 	kmem_start = console_8xx_init(kmem_start, kmem_end);
 #else 	
 	kmem_start = serial_console_init(kmem_start, kmem_end);
 #endif /* CONFIG_8xx */
+#endif
+#ifdef CONFIG_3215
+       kmem_start = con3215_init(kmem_start, kmem_end);
 #endif
 	return kmem_start;
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/fc4/Makefile linux.14p16/drivers/fc4/Makefile
--- linux.vanilla/drivers/fc4/Makefile	Tue Mar 16 00:11:29 1999
+++ linux.14p16/drivers/fc4/Makefile	Thu Dec  9 15:34:16 1999
@@ -7,8 +7,6 @@
 M_OBJS   :=
 MOD_LIST_NAME := FC4_MODULES
 
-include ../../.config
-
 ifeq ($(CONFIG_FC4),y)
   FC4 = fc.o
   ifeq ($(CONFIG_MODULES),y)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/Config.in linux.14p16/drivers/isdn/Config.in
--- linux.vanilla/drivers/isdn/Config.in	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/Config.in	Thu Dec  9 15:34:06 1999
@@ -2,77 +2,78 @@
 # ISDN device configuration
 #
 if [ "$CONFIG_INET" != "n" ]; then
-  bool 'Support synchronous PPP' CONFIG_ISDN_PPP
-  if [ "$CONFIG_ISDN_PPP" != "n" ]; then
-    bool 'Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
-    bool 'Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
-  fi
+   bool '  Support synchronous PPP' CONFIG_ISDN_PPP
+   if [ "$CONFIG_ISDN_PPP" != "n" ]; then
+      bool '    Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
+      bool '    Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
+   fi
 fi
-bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO
+bool '  Support audio via ISDN' CONFIG_ISDN_AUDIO
 if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then
-  bool 'Support AT-Fax Class 2 commands' CONFIG_ISDN_TTY_FAX
+   bool '    Support AT-Fax Class 2 commands' CONFIG_ISDN_TTY_FAX
 fi
-bool 'Support isdn diversion services' CONFIG_ISDN_DIVERSION
+bool '  Support isdn diversion services' CONFIG_ISDN_DIVERSION
 if [ "$CONFIG_X25" != "n" ]; then
-  bool 'X.25 PLP on top of ISDN (EXPERIMENTAL)' CONFIG_ISDN_X25
+   bool '  X.25 PLP on top of ISDN' CONFIG_ISDN_X25
 fi
-dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
-dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
-dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
-dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
+dep_tristate '  ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
+dep_tristate '  isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
+dep_tristate '  PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
+dep_tristate '  HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
 if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
-    bool 'HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
-    if [ "$CONFIG_HISAX_EURO" != "n" ]; then
-	    bool 'Support for german chargeinfo' CONFIG_DE_AOC
-	    bool 'Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE
-	    bool 'Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC
-    fi
-    bool 'HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
-    bool 'HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0
-    bool 'HiSax Support for Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
-    bool 'HiSax Support for Teles PCI' CONFIG_HISAX_TELESPCI 
-    bool 'HiSax Support for Teles S0Box' CONFIG_HISAX_S0BOX 
-    bool 'HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
-    bool 'HiSax Support for AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
-    bool 'HiSax Support for AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
-    bool 'HiSax Support for Elsa cards' CONFIG_HISAX_ELSA
-    bool 'HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
-    bool 'HiSax Support for Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
-    bool 'HiSax Support for ASUSCOM cards' CONFIG_HISAX_ASUSCOM
-    bool 'HiSax Support for TELEINT cards' CONFIG_HISAX_TELEINT
-    bool 'HiSax Support for HFC-S based cards' CONFIG_HISAX_HFCS
-    bool 'HiSax Support for Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
-    bool 'HiSax Support for USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
-    bool 'HiSax Support for MIC card' CONFIG_HISAX_MIC
-    bool 'HiSax Support for NETjet card' CONFIG_HISAX_NETJET
-    bool 'HiSax Support for Niccy PnP/PCI card' CONFIG_HISAX_NICCY
-    bool 'HiSax Support for Siemens I-Surf card' CONFIG_HISAX_ISURF
-    bool 'HiSax Support for HST Saphir card' CONFIG_HISAX_HSTSAPHIR
-    bool 'HiSax Support for Telekom A4T card' CONFIG_HISAX_BKM_A4T
-    bool 'HiSax Support for Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
-    bool 'HiSax Support for Gazel cards' CONFIG_HISAX_GAZEL
-    bool 'HiSax Support for HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI
-    if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
-        bool 'HiSax Support for Winbond W6692 based cards (EXPERIMENTAL)' CONFIG_HISAX_W6692
-#	bool 'HiSax Support for TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
-	if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
-		bool 'HiSax Support for Am7930' CONFIG_HISAX_AMD7930
-	fi
-    fi
+   bool '    HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
+   if [ "$CONFIG_HISAX_EURO" != "n" ]; then
+      bool '      Support for german chargeinfo' CONFIG_DE_AOC
+      bool '      Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE
+      bool '      Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC
+   fi
+   bool '    HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
+   bool '    HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0
+   bool '    HiSax Support for Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
+   bool '    HiSax Support for Teles PCI' CONFIG_HISAX_TELESPCI 
+   bool '    HiSax Support for Teles S0Box' CONFIG_HISAX_S0BOX 
+   bool '    HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
+   bool '    HiSax Support for AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
+   bool '    HiSax Support for AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
+   bool '    HiSax Support for Elsa cards' CONFIG_HISAX_ELSA
+   bool '    HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
+   bool '    HiSax Support for Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
+   bool '    HiSax Support for ASUSCOM cards' CONFIG_HISAX_ASUSCOM
+   bool '    HiSax Support for TELEINT cards' CONFIG_HISAX_TELEINT
+   bool '    HiSax Support for HFC-S based cards' CONFIG_HISAX_HFCS
+   bool '    HiSax Support for Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
+   bool '    HiSax Support for USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
+   bool '    HiSax Support for MIC card' CONFIG_HISAX_MIC
+   bool '    HiSax Support for NETjet card' CONFIG_HISAX_NETJET
+   bool '    HiSax Support for Niccy PnP/PCI card' CONFIG_HISAX_NICCY
+   bool '    HiSax Support for Siemens I-Surf card' CONFIG_HISAX_ISURF
+   bool '    HiSax Support for HST Saphir card' CONFIG_HISAX_HSTSAPHIR
+   bool '    HiSax Support for Telekom A4T card' CONFIG_HISAX_BKM_A4T
+   bool '    HiSax Support for Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
+   bool '    HiSax Support for Gazel cards' CONFIG_HISAX_GAZEL
+   bool '    HiSax Support for HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI
+   bool '    HiSax Support for Winbond W6692 based cards' CONFIG_HISAX_W6692
+   if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+#      bool '    HiSax Support for TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
+      if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+	 bool '    HiSax Support for Am7930' CONFIG_HISAX_AMD7930
+      fi
+   fi
 fi
 if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
-	dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
-	dep_tristate 'IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
+   dep_tristate '  Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
+   dep_tristate '  IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
 fi
-dep_tristate 'Eicon.Diehl active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
+dep_tristate '  Eicon.Diehl active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
 if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
-    bool 'Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
+   bool '    Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
 fi
-dep_tristate 'AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
+dep_tristate '  AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
 if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then
-    bool 'AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
-    bool 'AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI
-    bool 'AVM T1/T1B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA
-    bool 'AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
-    bool 'Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+   bool '    AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
+   bool '    AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI
+   bool '    AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA
+   bool '    AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
+   bool '    AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI
+   bool '    Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
 fi
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/act2000/act2000_isa.c linux.14p16/drivers/isdn/act2000/act2000_isa.c
--- linux.vanilla/drivers/isdn/act2000/act2000_isa.c	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/act2000/act2000_isa.c	Thu Dec  9 15:34:09 1999
@@ -1,4 +1,4 @@
-/* $Id: act2000_isa.c,v 1.9 1999/09/04 06:20:04 keil Exp $
+/* $Id: act2000_isa.c,v 1.10 1999/10/24 18:46:05 fritz Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
  *
@@ -20,6 +20,10 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: act2000_isa.c,v $
+ * Revision 1.10  1999/10/24 18:46:05  fritz
+ * Changed isa_ prefix to act2000_isa_ to prevent name-clash in latest
+ * kernels.
+ *
  * Revision 1.9  1999/09/04 06:20:04  keil
  * Changes from kernel set_current_state()
  *
@@ -64,14 +68,14 @@
 	0, 0, 0, 0, 0, 0, 0, 0,	0, 0, 0, 0, 0, 0, 0, 0
 };
 
-static int isa_irqs[] =
+static int act2000_isa_irqs[] =
 {
         3, 5, 7, 10, 11, 12, 15
 };
-#define ISA_NRIRQS (sizeof(isa_irqs)/sizeof(int))
+#define ISA_NRIRQS (sizeof(act2000_isa_irqs)/sizeof(int))
 
 static void
-isa_delay(long t)
+act2000_isa_delay(long t)
 {
         sti();
         current->state = TASK_INTERRUPTIBLE;
@@ -86,7 +90,7 @@
  *   0 = Signature not found.
  */
 static int
-isa_reset(unsigned short portbase)
+act2000_isa_reset(unsigned short portbase)
 {
         unsigned char reg;
         int i;
@@ -112,7 +116,7 @@
 }
 
 int
-isa_detect(unsigned short portbase)
+act2000_isa_detect(unsigned short portbase)
 {
         int ret = 0;
         unsigned long flags;
@@ -120,13 +124,13 @@
         save_flags(flags);
         cli();
         if (!check_region(portbase, ISA_REGION))
-                ret = isa_reset(portbase);
+                ret = act2000_isa_reset(portbase);
         restore_flags(flags);
         return ret;
 }
 
 static void
-isa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+act2000_isa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
         act2000_card *card = irq2card_map[irq];
         u_char istatus;
@@ -141,7 +145,7 @@
                 /* RX fifo has data */
 		istatus &= ISA_ISR_OUT_MASK;
 		outb(0, ISA_PORT_SIS);
-		isa_receive(card);
+		act2000_isa_receive(card);
 		outb(ISA_SIS_INT, ISA_PORT_SIS);
         }
         if (istatus & ISA_ISR_ERR) {
@@ -154,7 +158,7 @@
 }
 
 static void
-isa_select_irq(act2000_card * card)
+act2000_isa_select_irq(act2000_card * card)
 {
 	unsigned char reg;
 
@@ -186,9 +190,9 @@
 }
 
 static void
-isa_enable_irq(act2000_card * card)
+act2000_isa_enable_irq(act2000_card * card)
 {
-	isa_select_irq(card);
+	act2000_isa_select_irq(card);
 	/* Enable READ irq */
 	outb(ISA_SIS_INT, ISA_PORT_SIS);
 }
@@ -198,7 +202,7 @@
  * If irq is -1, choose next free irq, else irq is given explicitely.
  */
 int
-isa_config_irq(act2000_card * card, short irq)
+act2000_isa_config_irq(act2000_card * card, short irq)
 {
         int i;
         unsigned long flags;
@@ -216,8 +220,8 @@
         if (irq == -1) {
                 /* Auto select */
                 for (i = 0; i < ISA_NRIRQS; i++) {
-                        if (!request_irq(isa_irqs[i], &isa_interrupt, 0, card->regname, NULL)) {
-                                card->irq = isa_irqs[i];
+                        if (!request_irq(act2000_isa_irqs[i], &act2000_isa_interrupt, 0, card->regname, NULL)) {
+                                card->irq = act2000_isa_irqs[i];
                                 irq2card_map[card->irq] = card;
                                 card->flags |= ACT2000_FLAGS_IVALID;
                                 break;
@@ -225,7 +229,7 @@
                 }
         } else {
                 /* Fixed irq */
-                if (!request_irq(irq, &isa_interrupt, 0, card->regname, NULL)) {
+                if (!request_irq(irq, &act2000_isa_interrupt, 0, card->regname, NULL)) {
                         card->irq = irq;
                         irq2card_map[card->irq] = card;
 			card->flags |= ACT2000_FLAGS_IVALID;
@@ -237,7 +241,7 @@
                        "act2000: Could not request irq\n");
                 return -EBUSY;
         } else {
-		isa_select_irq(card);
+		act2000_isa_select_irq(card);
                 /* Disable READ and WRITE irq */
                 outb(0, ISA_PORT_SIS);
                 outb(0, ISA_PORT_SOS);
@@ -246,7 +250,7 @@
 }
 
 int
-isa_config_port(act2000_card * card, unsigned short portbase)
+act2000_isa_config_port(act2000_card * card, unsigned short portbase)
 {
         if (card->flags & ACT2000_FLAGS_PVALID) {
                 release_region(card->port, ISA_REGION);
@@ -265,7 +269,7 @@
  * Release ressources, used by an adaptor.
  */
 void
-isa_release(act2000_card * card)
+act2000_isa_release(act2000_card * card)
 {
         unsigned long flags;
 
@@ -283,7 +287,7 @@
 }
 
 static int
-isa_writeb(act2000_card * card, u_char data)
+act2000_isa_writeb(act2000_card * card, u_char data)
 {
         u_char timeout = 40;
 
@@ -300,7 +304,7 @@
 }
 
 static int
-isa_readb(act2000_card * card, u_char * data)
+act2000_isa_readb(act2000_card * card, u_char * data)
 {
         u_char timeout = 40;
 
@@ -317,13 +321,13 @@
 }
 
 void
-isa_receive(act2000_card *card)
+act2000_isa_receive(act2000_card *card)
 {
 	u_char c;
 
         if (test_and_set_bit(ACT2000_LOCK_RX, (void *) &card->ilock) != 0)
 		return;
-	while (!isa_readb(card, &c)) {
+	while (!act2000_isa_readb(card, &c)) {
 		if (card->idat.isa.rcvidx < 8) {
                         card->idat.isa.rcvhdr[card->idat.isa.rcvidx++] = c;
 			if (card->idat.isa.rcvidx == 8) {
@@ -335,7 +339,7 @@
 					if (card->idat.isa.rcvskb == NULL) {
 						card->idat.isa.rcvignore = 1;
 						printk(KERN_WARNING
-						       "isa_receive: no memory\n");
+						       "act2000_isa_receive: no memory\n");
 						test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
 						return;
 					}
@@ -344,12 +348,12 @@
 				} else {
 					card->idat.isa.rcvidx = 0;
 					printk(KERN_WARNING
-					       "isa_receive: Invalid CAPI msg\n");
+					       "act2000_isa_receive: Invalid CAPI msg\n");
 					{
 						int i; __u8 *p; __u8 *c; __u8 tmp[30];
 						for (i = 0, p = (__u8 *)&card->idat.isa.rcvhdr, c = tmp; i < 8; i++)
 							c += sprintf(c, "%02x ", *(p++));
-						printk(KERN_WARNING "isa_receive: %s\n", tmp);
+						printk(KERN_WARNING "act2000_isa_receive: %s\n", tmp);
 					}
 				}
 			}
@@ -380,7 +384,7 @@
 }
 
 void
-isa_send(act2000_card * card)
+act2000_isa_send(act2000_card * card)
 {
 	unsigned long flags;
 	struct sk_buff *skb;
@@ -413,7 +417,7 @@
 		skb = card->sbuf;
 		l = 0;
 		while (skb->len) {
-			if (isa_writeb(card, *(skb->data))) {
+			if (act2000_isa_writeb(card, *(skb->data))) {
 				/* Fifo is full, but more data to send */
 				test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
 				/* Schedule myself */
@@ -444,7 +448,7 @@
  * Get firmware ID, check for 'ISDN' signature.
  */
 static int
-isa_getid(act2000_card * card)
+act2000_isa_getid(act2000_card * card)
 {
 
         act2000_fwid fid;
@@ -454,7 +458,7 @@
         while (1) {
                 if (count > 510)
                         return -EPROTO;
-                if (isa_readb(card, p++))
+                if (act2000_isa_readb(card, p++))
                         break;
                 count++;
         }
@@ -473,7 +477,7 @@
         printk(KERN_INFO "act2000: Firmware-ID: %s\n", fid.revision);
 	if (card->flags & ACT2000_FLAGS_IVALID) {
 		printk(KERN_DEBUG "Enabling Interrupts ...\n");
-		isa_enable_irq(card);
+		act2000_isa_enable_irq(card);
 	}
         return 0;
 }
@@ -482,7 +486,7 @@
  * Download microcode into card, check Firmware signature.
  */
 int
-isa_download(act2000_card * card, act2000_ddef * cb)
+act2000_isa_download(act2000_card * card, act2000_ddef * cb)
 {
         int length;
         int ret;
@@ -494,9 +498,9 @@
         u_char *buf;
         act2000_ddef cblock;
 
-        if (!isa_reset(card->port))
+        if (!act2000_isa_reset(card->port))
                 return -ENXIO;
-        isa_delay(HZ / 2);
+        act2000_isa_delay(HZ / 2);
         if ((ret = verify_area(VERIFY_READ, (void *) cb, sizeof(cblock))))
                 return ret;
         copy_from_user(&cblock, (char *) cb, sizeof(cblock));
@@ -514,7 +518,7 @@
                 b = buf;
                 copy_from_user(buf, p, l);
                 while (c < l) {
-                        if (isa_writeb(card, *b++)) {
+                        if (act2000_isa_writeb(card, *b++)) {
                                 printk(KERN_WARNING
                                        "act2000: loader timed out"
                                        " len=%d c=%d\n", length, c);
@@ -527,6 +531,6 @@
                 p += l;
         }
         kfree(buf);
-        isa_delay(HZ / 2);
-        return (isa_getid(card));
+        act2000_isa_delay(HZ / 2);
+        return (act2000_isa_getid(card));
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/act2000/act2000_isa.h linux.14p16/drivers/isdn/act2000/act2000_isa.h
--- linux.vanilla/drivers/isdn/act2000/act2000_isa.h	Sat Aug 14 02:27:18 1999
+++ linux.14p16/drivers/isdn/act2000/act2000_isa.h	Thu Dec  9 15:34:09 1999
@@ -1,4 +1,4 @@
-/* $Id: act2000_isa.h,v 1.2 1998/11/05 22:12:43 fritz Exp $
+/* $Id: act2000_isa.h,v 1.3 1999/10/24 18:46:05 fritz Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
  *
@@ -20,6 +20,10 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: act2000_isa.h,v $
+ * Revision 1.3  1999/10/24 18:46:05  fritz
+ * Changed isa_ prefix to act2000_isa_ to prevent name-clash in latest
+ * kernels.
+ *
  * Revision 1.2  1998/11/05 22:12:43  fritz
  * Changed mail-address.
  *
@@ -141,12 +145,12 @@
 
 /* Prototypes */
 
-extern int isa_detect(unsigned short portbase);
-extern int isa_config_irq(act2000_card * card, short irq);
-extern int isa_config_port(act2000_card * card, unsigned short portbase);
-extern int isa_download(act2000_card * card, act2000_ddef * cb);
-extern void isa_release(act2000_card * card);
-extern void isa_receive(act2000_card *card);
-extern void isa_send(act2000_card *card);
+extern int act2000_isa_detect(unsigned short portbase);
+extern int act2000_isa_config_irq(act2000_card * card, short irq);
+extern int act2000_isa_config_port(act2000_card * card, unsigned short portbase);
+extern int act2000_isa_download(act2000_card * card, act2000_ddef * cb);
+extern void act2000_isa_release(act2000_card * card);
+extern void act2000_isa_receive(act2000_card *card);
+extern void act2000_isa_send(act2000_card *card);
 
 #endif                          /* act2000_isa_h */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/act2000/module.c linux.14p16/drivers/isdn/act2000/module.c
--- linux.vanilla/drivers/isdn/act2000/module.c	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/act2000/module.c	Thu Dec  9 15:34:09 1999
@@ -1,4 +1,4 @@
-/* $Id: module.c,v 1.9 1999/04/12 13:13:56 fritz Exp $
+/* $Id: module.c,v 1.11 1999/10/30 09:48:04 keil Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *
@@ -20,6 +20,13 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: module.c,v $
+ * Revision 1.11  1999/10/30 09:48:04  keil
+ * miss one prefix act2000
+ *
+ * Revision 1.10  1999/10/24 18:46:05  fritz
+ * Changed isa_ prefix to act2000_isa_ to prevent name-clash in latest
+ * kernels.
+ *
  * Revision 1.9  1999/04/12 13:13:56  fritz
  * Made cards pointer static to avoid name-clash.
  *
@@ -56,12 +63,12 @@
 #include "act2000_isa.h"
 #include "capi.h"
 
-static unsigned short isa_ports[] =
+static unsigned short act2000_isa_ports[] =
 {
         0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380,
         0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60,
 };
-#define ISA_NRPORTS (sizeof(isa_ports)/sizeof(unsigned short))
+#define ISA_NRPORTS (sizeof(act2000_isa_ports)/sizeof(unsigned short))
 
 static act2000_card *cards = (act2000_card *) NULL;
 
@@ -238,7 +245,7 @@
 {
 	switch (card->bus) {
 		case ACT2000_BUS_ISA:
-			isa_send(card);
+			act2000_isa_send(card);
 			break;
 		case ACT2000_BUS_PCMCIA:
 		case ACT2000_BUS_MCA:
@@ -253,7 +260,7 @@
 {
 	switch (card->bus) {
 		case ACT2000_BUS_ISA:
-			isa_receive(card);
+			act2000_isa_receive(card);
 			break;
 		case ACT2000_BUS_PCMCIA:
 		case ACT2000_BUS_MCA:
@@ -296,7 +303,7 @@
 				case ACT2000_IOCTL_LOADBOOT:
 					switch (card->bus) {
 						case ACT2000_BUS_ISA:
-							ret = isa_download(card,
+							ret = act2000_isa_download(card,
 									   (act2000_ddef *)a);
 							if (!ret) {
 								card->flags |= ACT2000_FLAGS_LOADED;
@@ -758,7 +765,7 @@
         card->interface.statcallb(&cmd);
         switch (card->bus) {
 		case ACT2000_BUS_ISA:
-			isa_release(card);
+			act2000_isa_release(card);
 			break;
 		case ACT2000_BUS_MCA:
 		case ACT2000_BUS_PCMCIA:
@@ -792,11 +799,11 @@
 		switch (bus) {
 			case ACT2000_BUS_ISA:
 				for (i = 0; i < ISA_NRPORTS; i++)
-					if (isa_detect(isa_ports[i])) {
+					if (act2000_isa_detect(act2000_isa_ports[i])) {
 						printk(KERN_INFO
 						       "act2000: Detected ISA card at port 0x%x\n",
-						       isa_ports[i]);
-						act2000_alloccard(bus, isa_ports[i], irq, id);
+						       act2000_isa_ports[i]);
+						act2000_alloccard(bus, act2000_isa_ports[i], irq, id);
 					}
 				break;
 			case ACT2000_BUS_MCA:
@@ -819,10 +826,10 @@
 			added++;
 			switch (p->bus) {
 				case ACT2000_BUS_ISA:
-					if (isa_detect(p->port)) {
+					if (act2000_isa_detect(p->port)) {
 						if (act2000_registercard(p))
 							break;
-						if (isa_config_port(p, p->port)) {
+						if (act2000_isa_config_port(p, p->port)) {
 							printk(KERN_WARNING
 							       "act2000: Could not request port 0x%04x\n",
 							       p->port);
@@ -830,7 +837,7 @@
 							p->interface.statcallb = NULL;
 							break;
 						}
-						if (isa_config_irq(p, p->irq)) {
+						if (act2000_isa_config_irq(p, p->irq)) {
 							printk(KERN_INFO
 							       "act2000: No IRQ available, fallback to polling\n");
 							/* Fall back to polled operation */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/avmcard.h linux.14p16/drivers/isdn/avmb1/avmcard.h
--- linux.vanilla/drivers/isdn/avmb1/avmcard.h	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/avmb1/avmcard.h	Thu Dec  9 15:34:07 1999
@@ -1,9 +1,16 @@
 /*
- * $Id: avmcard.h,v 1.5 1999/09/07 09:02:53 calle Exp $
+ * $Id: avmcard.h,v 1.6 1999/11/05 16:38:01 calle Exp $
  *
  * Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: avmcard.h,v $
+ * Revision 1.6  1999/11/05 16:38:01  calle
+ * Cleanups before kernel 2.4:
+ * - Changed all messages to use card->name or driver->name instead of
+ *   constant string.
+ * - Moved some data from struct avmcard into new struct avmctrl_info.
+ *   Changed all lowlevel capi driver to match the new structur.
+ *
  * Revision 1.5  1999/09/07 09:02:53  calle
  * SETDATA removed. Now inside the kernel the datapart of DATA_B3_REQ and
  * DATA_B3_IND is always directly after the CAPI message. The "Data" member
@@ -78,6 +85,7 @@
 	__u8  sendbuf[128+2048];
 } avmcard_dmainfo;
 
+
 typedef struct avmcard {
 	char name[32];
 	unsigned int port;
@@ -86,13 +94,6 @@
 	enum avmcardtype cardtype;
 	int cardnr; /* for t1isa */
 
-	int versionlen;
-	char versionbuf[1024];
-	char *version[AVM_MAXVERSION];
-
-	char cardname[32];
-
-	char infobuf[128];	/* for function procinfo */
 	char msgbuf[128];	/* capimsg msg part */
 	char databuf[2048];	/* capimsg data part */
 
@@ -102,9 +103,25 @@
 	volatile __u32 csr;
 	avmcard_dmainfo *dma;
 
-	struct capi_ctr *ctrl;
+	struct avmctrl_info {
+		char cardname[32];
+
+		int versionlen;
+		char versionbuf[1024];
+		char *version[AVM_MAXVERSION];
+
+		char infobuf[128];	/* for function procinfo */
+
+		struct avmcard  *card;
+		struct capi_ctr *capi_ctrl;
+
+	} *ctrlinfo;
+
+	int nlogcontr;
 } avmcard;
 
+typedef struct avmctrl_info avmctrl_info;
+
 extern int b1_irq_table[16];
 
 /*
@@ -545,16 +562,16 @@
 }
 
 int b1_detect(unsigned int base, enum avmcardtype cardtype);
-int b1_load_t4file(unsigned int base, capiloaddatapart * t4file);
-int b1_load_config(unsigned int base, capiloaddatapart * config);
-int b1_loaded(unsigned int base);
+int b1_load_t4file(avmcard *card, capiloaddatapart * t4file);
+int b1_load_config(avmcard *card, capiloaddatapart * config);
+int b1_loaded(avmcard *card);
 int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
 void b1_reset_ctr(struct capi_ctr *ctrl);
 void b1_register_appl(struct capi_ctr *ctrl, __u16 appl,
 				capi_register_params *rp);
 void b1_release_appl(struct capi_ctr *ctrl, __u16 appl);
 void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
-void b1_parse_version(avmcard *card);
+void b1_parse_version(avmctrl_info *card);
 void b1_handle_interrupt(avmcard * card);
 
 int b1ctl_read_proc(char *page, char **start, off_t off,
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/b1.c linux.14p16/drivers/isdn/avmb1/b1.c
--- linux.vanilla/drivers/isdn/avmb1/b1.c	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/avmb1/b1.c	Thu Dec  9 15:34:07 1999
@@ -1,11 +1,21 @@
 /*
- * $Id: b1.c,v 1.10 1999/09/15 08:16:03 calle Exp $
+ * $Id: b1.c,v 1.12 1999/11/05 16:38:01 calle Exp $
  * 
  * Common module for AVM B1 cards.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1.c,v $
+ * Revision 1.12  1999/11/05 16:38:01  calle
+ * Cleanups before kernel 2.4:
+ * - Changed all messages to use card->name or driver->name instead of
+ *   constant string.
+ * - Moved some data from struct avmcard into new struct avmctrl_info.
+ *   Changed all lowlevel capi driver to match the new structur.
+ *
+ * Revision 1.11  1999/10/11 22:04:12  keil
+ * COMPAT_NEED_UACCESS (no include in isdn_compat.h)
+ *
  * Revision 1.10  1999/09/15 08:16:03  calle
  * Implementation of 64Bit extention complete.
  *
@@ -76,7 +86,7 @@
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.10 $";
+static char *revision = "$Revision: 1.12 $";
 
 /* ------------------------------------------------------------- */
 
@@ -148,11 +158,12 @@
 	return 0;
 }
 
-int b1_load_t4file(unsigned int base, capiloaddatapart * t4file)
+int b1_load_t4file(avmcard *card, capiloaddatapart * t4file)
 {
 	unsigned char buf[256];
 	unsigned char *dp;
 	int i, left, retval;
+	unsigned int base = card->port;
 
 	dp = t4file->data;
 	left = t4file->len;
@@ -166,7 +177,8 @@
 		}
 		for (i = 0; i < sizeof(buf); i++)
 			if (b1_save_put_byte(base, buf[i]) < 0) {
-				printk(KERN_ERR "b1_load_t4file: corrupted t4 file ?\n");
+				printk(KERN_ERR "%s: corrupted firmware file ?\n",
+						card->name);
 				return -EIO;
 			}
 		left -= sizeof(buf);
@@ -182,17 +194,19 @@
 		}
 		for (i = 0; i < left; i++)
 			if (b1_save_put_byte(base, buf[i]) < 0) {
-				printk(KERN_ERR "b1_load_t4file: corrupted t4 file ?\n");
+				printk(KERN_ERR "%s: corrupted firmware file ?\n",
+						card->name);
 				return -EIO;
 			}
 	}
 	return 0;
 }
 
-int b1_load_config(unsigned int base, capiloaddatapart * config)
+int b1_load_config(avmcard *card, capiloaddatapart * config)
 {
 	unsigned char buf[256];
 	unsigned char *dp;
+	unsigned int base = card->port;
 	int i, j, left, retval;
 
 	dp = config->data;
@@ -241,8 +255,9 @@
 	return 0;
 }
 
-int b1_loaded(unsigned int base)
+int b1_loaded(avmcard *card)
 {
+	unsigned int base = card->port;
 	unsigned long stop;
 	unsigned char ans;
 	unsigned long tout = 2;
@@ -252,7 +267,8 @@
 			break;
 	}
 	if (!b1_tx_empty(base)) {
-		printk(KERN_ERR "b1_loaded: tx err, corrupted t4 file ?\n");
+		printk(KERN_ERR "%s: b1_loaded: tx err, corrupted t4 file ?\n",
+				card->name);
 		return 0;
 	}
 	b1_put_byte(base, SEND_POLL);
@@ -261,11 +277,12 @@
 			if ((ans = b1_get_byte(base)) == RECEIVE_POLL) {
 				return 1;
 			}
-			printk(KERN_ERR "b1_loaded: got 0x%x, firmware not running\n", ans);
+			printk(KERN_ERR "%s: b1_loaded: got 0x%x, firmware not running\n",
+					card->name, ans);
 			return 0;
 		}
 	}
-	printk(KERN_ERR "b1_loaded: firmware not running\n");
+	printk(KERN_ERR "%s: b1_loaded: firmware not running\n", card->name);
 	return 0;
 }
 
@@ -273,14 +290,15 @@
 
 int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
 	unsigned int port = card->port;
 	unsigned long flags;
 	int retval;
 
 	b1_reset(port);
 
-	if ((retval = b1_load_t4file(port, &data->firmware))) {
+	if ((retval = b1_load_t4file(card, &data->firmware))) {
 		b1_reset(port);
 		printk(KERN_ERR "%s: failed to load t4file!!\n",
 					card->name);
@@ -290,7 +308,7 @@
 	b1_disable_irq(port);
 
 	if (data->configuration.len > 0 && data->configuration.data) {
-		if ((retval = b1_load_config(port, &data->configuration))) {
+		if ((retval = b1_load_config(card, &data->configuration))) {
 			b1_reset(port);
 			printk(KERN_ERR "%s: failed to load config!!\n",
 					card->name);
@@ -298,7 +316,7 @@
 		}
 	}
 
-	if (!b1_loaded(port)) {
+	if (!b1_loaded(card)) {
 		printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
 		return -EIO;
 	}
@@ -317,13 +335,14 @@
 
 void b1_reset_ctr(struct capi_ctr *ctrl)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
 	unsigned int port = card->port;
 
 	b1_reset(port);
 	b1_reset(port);
 
-	memset(card->version, 0, sizeof(card->version));
+	memset(cinfo->version, 0, sizeof(cinfo->version));
 	ctrl->reseted(ctrl);
 }
 
@@ -331,7 +350,8 @@
 				__u16 appl,
 				capi_register_params *rp)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
 	unsigned int port = card->port;
 	unsigned long flags;
 	int nconn, want = rp->level3cnt;
@@ -355,7 +375,8 @@
 
 void b1_release_appl(struct capi_ctr *ctrl, __u16 appl)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
 	unsigned int port = card->port;
 	unsigned long flags;
 
@@ -368,7 +389,8 @@
 
 void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
 	unsigned int port = card->port;
 	unsigned long flags;
 	__u16 len = CAPIMSG_LEN(skb->data);
@@ -392,25 +414,26 @@
 
 /* ------------------------------------------------------------- */
 
-void b1_parse_version(avmcard *card)
+void b1_parse_version(avmctrl_info *cinfo)
 {
-	struct capi_ctr *ctrl = card->ctrl;
+	struct capi_ctr *ctrl = cinfo->capi_ctrl;
+	avmcard *card = cinfo->card;
 	capi_profile *profp;
 	__u8 *dversion;
 	__u8 flag;
 	int i, j;
 
 	for (j = 0; j < AVM_MAXVERSION; j++)
-		card->version[j] = "\0\0" + 1;
+		cinfo->version[j] = "\0\0" + 1;
 	for (i = 0, j = 0;
-	     j < AVM_MAXVERSION && i < card->versionlen;
-	     j++, i += card->versionbuf[i] + 1)
-		card->version[j] = &card->versionbuf[i + 1];
+	     j < AVM_MAXVERSION && i < cinfo->versionlen;
+	     j++, i += cinfo->versionbuf[i] + 1)
+		cinfo->version[j] = &cinfo->versionbuf[i + 1];
 
-	strncpy(ctrl->serial, card->version[VER_SERIAL], CAPI_SERIAL_LEN);
-	memcpy(&ctrl->profile, card->version[VER_PROFILE],sizeof(capi_profile));
+	strncpy(ctrl->serial, cinfo->version[VER_SERIAL], CAPI_SERIAL_LEN);
+	memcpy(&ctrl->profile, cinfo->version[VER_PROFILE],sizeof(capi_profile));
 	strncpy(ctrl->manu, "AVM GmbH", CAPI_MANUFACTURER_LEN);
-	dversion = card->version[VER_DRIVER];
+	dversion = cinfo->version[VER_DRIVER];
 	ctrl->version.majorversion = 2;
 	ctrl->version.minorversion = 0;
 	ctrl->version.majormanuversion = (((dversion[0] - '0') & 0xf) << 4);
@@ -423,23 +446,24 @@
 
 	flag = ((__u8 *)(profp->manu))[1];
 	switch (flag) {
-	case 0: if (card->version[VER_CARDTYPE])
-	           strcpy(card->cardname, card->version[VER_CARDTYPE]);
-	        else strcpy(card->cardname, "B1");
+	case 0: if (cinfo->version[VER_CARDTYPE])
+	           strcpy(cinfo->cardname, cinfo->version[VER_CARDTYPE]);
+	        else strcpy(cinfo->cardname, "B1");
 		break;
-	case 3: strcpy(card->cardname,"PCMCIA B"); break;
-	case 4: strcpy(card->cardname,"PCMCIA M1"); break;
-	case 5: strcpy(card->cardname,"PCMCIA M2"); break;
-	case 6: strcpy(card->cardname,"B1 V3.0"); break;
-	case 7: strcpy(card->cardname,"B1 PCI"); break;
-	default: sprintf(card->cardname, "AVM?%u", (unsigned int)flag); break;
+	case 3: strcpy(cinfo->cardname,"PCMCIA B"); break;
+	case 4: strcpy(cinfo->cardname,"PCMCIA M1"); break;
+	case 5: strcpy(cinfo->cardname,"PCMCIA M2"); break;
+	case 6: strcpy(cinfo->cardname,"B1 V3.0"); break;
+	case 7: strcpy(cinfo->cardname,"B1 PCI"); break;
+	default: sprintf(cinfo->cardname, "AVM?%u", (unsigned int)flag); break;
         }
         printk(KERN_NOTICE "%s: card %d \"%s\" ready.\n",
-				card->name, ctrl->cnr, card->cardname);
+				card->name, ctrl->cnr, cinfo->cardname);
 
         flag = ((__u8 *)(profp->manu))[3];
         if (flag)
-		printk(KERN_NOTICE "b1capi: card %d Protocol:%s%s%s%s%s%s%s\n",
+		printk(KERN_NOTICE "%s: card %d Protocol:%s%s%s%s%s%s%s\n",
+			card->name,
 			ctrl->cnr,
 			(flag & 0x01) ? " DSS1" : "",
 			(flag & 0x02) ? " CT1" : "",
@@ -466,7 +490,8 @@
 
 void b1_handle_interrupt(avmcard * card)
 {
-	struct capi_ctr *ctrl = card->ctrl;
+	avmctrl_info *cinfo = &card->ctrlinfo[0];
+	struct capi_ctr *ctrl = cinfo->capi_ctrl;
 	unsigned char b1cmd;
 	struct sk_buff *skb;
 
@@ -548,12 +573,12 @@
 
 	case RECEIVE_INIT:
 
-		card->versionlen = b1_get_slice(card->port, card->versionbuf);
-		b1_parse_version(card);
+		cinfo->versionlen = b1_get_slice(card->port, cinfo->versionbuf);
+		b1_parse_version(cinfo);
 		printk(KERN_INFO "%s: %s-card (%s) now active\n",
 		       card->name,
-		       card->version[VER_CARDTYPE],
-		       card->version[VER_DRIVER]);
+		       cinfo->version[VER_CARDTYPE],
+		       cinfo->version[VER_DRIVER]);
 		ctrl->ready(ctrl);
 		break;
 
@@ -593,7 +618,8 @@
 int b1ctl_read_proc(char *page, char **start, off_t off,
         		int count, int *eof, struct capi_ctr *ctrl)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
 	__u8 flag;
 	int len = 0;
 	char *s;
@@ -615,11 +641,11 @@
 	len += sprintf(page+len, "%-16s %s\n", "type", s);
 	if (card->cardtype == avm_t1isa)
 	   len += sprintf(page+len, "%-16s %d\n", "cardnr", card->cardnr);
-	if ((s = card->version[VER_DRIVER]) != 0)
+	if ((s = cinfo->version[VER_DRIVER]) != 0)
 	   len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
-	if ((s = card->version[VER_CARDTYPE]) != 0)
+	if ((s = cinfo->version[VER_CARDTYPE]) != 0)
 	   len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
-	if ((s = card->version[VER_SERIAL]) != 0)
+	if ((s = cinfo->version[VER_SERIAL]) != 0)
 	   len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
 
 	if (card->cardtype != avm_m1) {
@@ -647,7 +673,7 @@
 			(flag & 0x04) ? " leased line with D-channel" : ""
 			);
 	}
-	len += sprintf(page+len, "%-16s %s\n", "cardname", card->cardname);
+	len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
 
 	if (off+count >= len)
 	   *eof = 1;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/b1isa.c linux.14p16/drivers/isdn/avmb1/b1isa.c
--- linux.vanilla/drivers/isdn/avmb1/b1isa.c	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/avmb1/b1isa.c	Thu Dec  9 15:34:07 1999
@@ -1,11 +1,18 @@
 /*
- * $Id: b1isa.c,v 1.4 1999/08/22 20:26:24 calle Exp $
+ * $Id: b1isa.c,v 1.5 1999/11/05 16:38:01 calle Exp $
  * 
  * Module for AVM B1 ISA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1isa.c,v $
+ * Revision 1.5  1999/11/05 16:38:01  calle
+ * Cleanups before kernel 2.4:
+ * - Changed all messages to use card->name or driver->name instead of
+ *   constant string.
+ * - Moved some data from struct avmcard into new struct avmctrl_info.
+ *   Changed all lowlevel capi driver to match the new structur.
+ *
  * Revision 1.4  1999/08/22 20:26:24  calle
  * backported changes from kernel 2.3.14:
  * - several #include "config.h" gone, others come.
@@ -54,7 +61,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.4 $";
+static char *revision = "$Revision: 1.5 $";
 
 /* ------------------------------------------------------------- */
 
@@ -91,7 +98,8 @@
 
 static void b1isa_remove_ctr(struct capi_ctr *ctrl)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
 	unsigned int port = card->port;
 
 	b1_reset(port);
@@ -100,6 +108,7 @@
 	di->detach_ctr(ctrl);
 	free_irq(card->irq, card);
 	release_region(card->port, AVMB1_PORTLEN);
+	kfree(card->ctrlinfo);
 	kfree(card);
 
 	MOD_DEC_USE_COUNT;
@@ -109,6 +118,7 @@
 
 static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
 {
+	avmctrl_info *cinfo;
 	avmcard *card;
 	int retval;
 
@@ -119,6 +129,15 @@
 		return -ENOMEM;
 	}
 	memset(card, 0, sizeof(avmcard));
+        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+	if (!cinfo) {
+		printk(KERN_WARNING "b1isa: no memory.\n");
+		kfree(card);
+		return -ENOMEM;
+	}
+	memset(cinfo, 0, sizeof(avmctrl_info));
+	card->ctrlinfo = cinfo;
+	cinfo->card = card;
 	sprintf(card->name, "b1isa-%x", p->port);
 	card->port = p->port;
 	card->irq = p->irq;
@@ -128,17 +147,20 @@
 		printk(KERN_WARNING
 		       "b1isa: ports 0x%03x-0x%03x in use.\n",
 		       card->port, card->port + AVMB1_PORTLEN);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EBUSY;
 	}
 	if (b1_irq_table[card->irq & 0xf] == 0) {
 		printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EINVAL;
 	}
 	if (   card->port != 0x150 && card->port != 0x250
 	    && card->port != 0x300 && card->port != 0x340) {
 		printk(KERN_WARNING "b1isa: illegal port 0x%x.\n", card->port);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EINVAL;
 	}
@@ -146,6 +168,7 @@
 	if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
 		printk(KERN_NOTICE "b1isa: NO card at 0x%x (%d)\n",
 					card->port, retval);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EIO;
 	}
@@ -157,15 +180,17 @@
 	if (retval) {
 		printk(KERN_ERR "b1isa: unable to get IRQ %d.\n", card->irq);
 		release_region(card->port, AVMB1_PORTLEN);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EBUSY;
 	}
 
-	card->ctrl = di->attach_ctr(driver, card->name, card);
-	if (!card->ctrl) {
+	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "b1isa: attach controller failed.\n");
 		free_irq(card->irq, card);
 		release_region(card->port, AVMB1_PORTLEN);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EBUSY;
 	}
@@ -176,15 +201,17 @@
 
 static char *b1isa_procinfo(struct capi_ctr *ctrl)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
-	if (!card)
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+	if (!cinfo)
 		return "";
-	sprintf(card->infobuf, "%s %s 0x%x %d",
-		card->cardname[0] ? card->cardname : "-",
-		card->version[VER_DRIVER] ? card->version[VER_DRIVER] : "-",
-		card->port, card->irq
+	sprintf(cinfo->infobuf, "%s %s 0x%x %d",
+		cinfo->cardname[0] ? cinfo->cardname : "-",
+		cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+		cinfo->card ? cinfo->card->port : 0x0,
+		cinfo->card ? cinfo->card->irq : 0
 		);
-	return card->infobuf;
+	return cinfo->infobuf;
 }
 
 /* ------------------------------------------------------------- */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/b1pci.c linux.14p16/drivers/isdn/avmb1/b1pci.c
--- linux.vanilla/drivers/isdn/avmb1/b1pci.c	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/avmb1/b1pci.c	Thu Dec  9 15:34:07 1999
@@ -1,11 +1,21 @@
 /*
- * $Id: b1pci.c,v 1.16 1999/08/11 21:01:07 keil Exp $
+ * $Id: b1pci.c,v 1.18 1999/11/05 16:38:01 calle Exp $
  * 
  * Module for AVM B1 PCI-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1pci.c,v $
+ * Revision 1.18  1999/11/05 16:38:01  calle
+ * Cleanups before kernel 2.4:
+ * - Changed all messages to use card->name or driver->name instead of
+ *   constant string.
+ * - Moved some data from struct avmcard into new struct avmctrl_info.
+ *   Changed all lowlevel capi driver to match the new structur.
+ *
+ * Revision 1.17  1999/10/05 06:50:07  calle
+ * Forgot SA_SHIRQ as argument to request_irq.
+ *
  * Revision 1.16  1999/08/11 21:01:07  keil
  * new PCI codefix
  *
@@ -56,7 +66,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.16 $";
+static char *revision = "$Revision: 1.18 $";
 
 /* ------------------------------------------------------------- */
 
@@ -85,11 +95,11 @@
 	card = (avmcard *) devptr;
 
 	if (!card) {
-		printk(KERN_WARNING "b1_interrupt: wrong device\n");
+		printk(KERN_WARNING "b1pci: interrupt: wrong device\n");
 		return;
 	}
 	if (card->interrupt) {
-		printk(KERN_ERR "b1_interrupt: reentering interrupt hander (%s)\n", card->name);
+		printk(KERN_ERR "%s: reentering interrupt hander.\n", card->name);
 		return;
 	}
 
@@ -103,7 +113,8 @@
 
 static void b1pci_remove_ctr(struct capi_ctr *ctrl)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
 	unsigned int port = card->port;
 
 	b1_reset(port);
@@ -113,6 +124,7 @@
 	free_irq(card->irq, card);
 	release_region(card->port, AVMB1_PORTLEN);
 	ctrl->driverdata = 0;
+	kfree(card->ctrlinfo);
 	kfree(card);
 
 	MOD_DEC_USE_COUNT;
@@ -122,15 +134,17 @@
 
 static char *b1pci_procinfo(struct capi_ctr *ctrl)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
-	if (!card)
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+	if (!cinfo)
 		return "";
-	sprintf(card->infobuf, "%s %s 0x%x %d",
-		card->cardname[0] ? card->cardname : "-",
-		card->version[VER_DRIVER] ? card->version[VER_DRIVER] : "-",
-		card->port, card->irq
+	sprintf(cinfo->infobuf, "%s %s 0x%x %d",
+		cinfo->cardname[0] ? cinfo->cardname : "-",
+		cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+		cinfo->card ? cinfo->card->port : 0x0,
+		cinfo->card ? cinfo->card->irq : 0
 		);
-	return card->infobuf;
+	return cinfo->infobuf;
 }
 
 /* ------------------------------------------------------------- */
@@ -138,15 +152,25 @@
 static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
 {
 	avmcard *card;
+	avmctrl_info *cinfo;
 	int retval;
 
 	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
 
 	if (!card) {
-		printk(KERN_WARNING "b1pci: no memory.\n");
+		printk(KERN_WARNING "%s: no memory.\n", driver->name);
 		return -ENOMEM;
 	}
 	memset(card, 0, sizeof(avmcard));
+        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+	if (!cinfo) {
+		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		kfree(card);
+		return -ENOMEM;
+	}
+	memset(cinfo, 0, sizeof(avmctrl_info));
+	card->ctrlinfo = cinfo;
+	cinfo->card = card;
 	sprintf(card->name, "b1pci-%x", p->port);
 	card->port = p->port;
 	card->irq = p->irq;
@@ -154,15 +178,17 @@
 
 	if (check_region(card->port, AVMB1_PORTLEN)) {
 		printk(KERN_WARNING
-		       "b1pci: ports 0x%03x-0x%03x in use.\n",
-		       card->port, card->port + AVMB1_PORTLEN);
+		       "%s: ports 0x%03x-0x%03x in use.\n",
+		       driver->name, card->port, card->port + AVMB1_PORTLEN);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EBUSY;
 	}
 	b1_reset(card->port);
 	if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
-		printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n",
-					card->port, retval);
+		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+					driver->name, card->port, retval);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EIO;
 	}
@@ -170,19 +196,23 @@
 
 	request_region(p->port, AVMB1_PORTLEN, card->name);
 
-	retval = request_irq(card->irq, b1pci_interrupt, 0, card->name, card);
+	retval = request_irq(card->irq, b1pci_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
-		printk(KERN_ERR "b1pci: unable to get IRQ %d.\n", card->irq);
+		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+				driver->name, card->irq);
 		release_region(card->port, AVMB1_PORTLEN);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EBUSY;
 	}
 
-	card->ctrl = di->attach_ctr(driver, card->name, card);
-	if (!card->ctrl) {
-		printk(KERN_ERR "b1pci: attach controller failed.\n");
+	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+	if (!cinfo->capi_ctrl) {
+		printk(KERN_ERR "%s: attach controller failed.\n",
+				driver->name);
 		free_irq(card->irq, card);
 		release_region(card->port, AVMB1_PORTLEN);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EBUSY;
 	}
@@ -276,7 +306,7 @@
 	printk(KERN_ERR "%s: NO B1-PCI card detected\n", driver->name);
 	return -ESRCH;
 #else
-	printk(KERN_ERR "b1pci: kernel not compiled with PCI.\n");
+	printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name);
 	return -EIO;
 #endif
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/b1pcmcia.c linux.14p16/drivers/isdn/avmb1/b1pcmcia.c
--- linux.vanilla/drivers/isdn/avmb1/b1pcmcia.c	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/avmb1/b1pcmcia.c	Thu Dec  9 15:34:07 1999
@@ -1,11 +1,18 @@
 /*
- * $Id: b1pcmcia.c,v 1.4 1999/08/22 20:26:26 calle Exp $
+ * $Id: b1pcmcia.c,v 1.5 1999/11/05 16:38:01 calle Exp $
  * 
  * Module for AVM B1/M1/M2 PCMCIA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1pcmcia.c,v $
+ * Revision 1.5  1999/11/05 16:38:01  calle
+ * Cleanups before kernel 2.4:
+ * - Changed all messages to use card->name or driver->name instead of
+ *   constant string.
+ * - Moved some data from struct avmcard into new struct avmctrl_info.
+ *   Changed all lowlevel capi driver to match the new structur.
+ *
  * Revision 1.4  1999/08/22 20:26:26  calle
  * backported changes from kernel 2.3.14:
  * - several #include "config.h" gone, others come.
@@ -55,7 +62,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.4 $";
+static char *revision = "$Revision: 1.5 $";
 
 /* ------------------------------------------------------------- */
 
@@ -74,11 +81,12 @@
 	card = (avmcard *) devptr;
 
 	if (!card) {
-		printk(KERN_WARNING "b1_interrupt: wrong device\n");
+		printk(KERN_WARNING "b1pcmcia: interrupt: wrong device\n");
 		return;
 	}
 	if (card->interrupt) {
-		printk(KERN_ERR "b1_interrupt: reentering interrupt hander (%s)\n", card->name);
+		printk(KERN_ERR "%s: reentering interrupt hander.\n",
+			card->name);
 		return;
 	}
 
@@ -92,7 +100,8 @@
 
 static void b1pcmcia_remove_ctr(struct capi_ctr *ctrl)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
 	unsigned int port = card->port;
 
 	b1_reset(port);
@@ -115,16 +124,26 @@
 				unsigned irq,
 				enum avmcardtype cardtype)
 {
+	avmctrl_info *cinfo;
 	avmcard *card;
 	int retval;
 
 	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
 
 	if (!card) {
-		printk(KERN_WARNING "b1pcmcia: no memory.\n");
+		printk(KERN_WARNING "%s: no memory.\n", driver->name);
 		return -ENOMEM;
 	}
 	memset(card, 0, sizeof(avmcard));
+        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+	if (!cinfo) {
+		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		kfree(card);
+		return -ENOMEM;
+	}
+	memset(cinfo, 0, sizeof(avmctrl_info));
+	card->ctrlinfo = cinfo;
+	cinfo->card = card;
 	switch (cardtype) {
 		case avm_m1: sprintf(card->name, "m1-%x", port); break;
 		case avm_m2: sprintf(card->name, "m2-%x", port); break;
@@ -136,8 +155,9 @@
 
 	b1_reset(card->port);
 	if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
-		printk(KERN_NOTICE "b1pcmcia: NO card at 0x%x (%d)\n",
-					card->port, retval);
+		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+					driver->name, card->port, retval);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EIO;
 	}
@@ -145,36 +165,42 @@
 
 	retval = request_irq(card->irq, b1pcmcia_interrupt, 0, card->name, card);
 	if (retval) {
-		printk(KERN_ERR "b1pcmcia: unable to get IRQ %d.\n", card->irq);
+		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+				driver->name, card->irq);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EBUSY;
 	}
 
-	card->ctrl = di->attach_ctr(driver, card->name, card);
-	if (!card->ctrl) {
-		printk(KERN_ERR "b1pcmcia: attach controller failed.\n");
+	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+	if (!cinfo->capi_ctrl) {
+		printk(KERN_ERR "%s: attach controller failed.\n",
+				driver->name);
 		free_irq(card->irq, card);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EBUSY;
 	}
 
 	MOD_INC_USE_COUNT;
-	return card->ctrl->cnr;
+	return cinfo->capi_ctrl->cnr;
 }
 
 /* ------------------------------------------------------------- */
 
 static char *b1pcmcia_procinfo(struct capi_ctr *ctrl)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
-	if (!card)
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+	if (!cinfo)
 		return "";
-	sprintf(card->infobuf, "%s %s 0x%x %d",
-		card->cardname[0] ? card->cardname : "-",
-		card->version[VER_DRIVER] ? card->version[VER_DRIVER] : "-",
-		card->port, card->irq
+	sprintf(cinfo->infobuf, "%s %s 0x%x %d",
+		cinfo->cardname[0] ? cinfo->cardname : "-",
+		cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+		cinfo->card ? cinfo->card->port : 0x0,
+		cinfo->card ? cinfo->card->irq : 0
 		);
-	return card->infobuf;
+	return cinfo->infobuf;
 }
 
 /* ------------------------------------------------------------- */
@@ -219,7 +245,7 @@
 	avmcard *card;
 
 	for (ctrl = b1pcmcia_driver.controller; ctrl; ctrl = ctrl->next) {
-		card = (avmcard *)(ctrl->driverdata);
+		card = ((avmctrl_info *)(ctrl->driverdata))->card;
 		if (card->port == port && card->irq == irq) {
 			b1pcmcia_remove_ctr(ctrl);
 			return 0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/capi.c linux.14p16/drivers/isdn/avmb1/capi.c
--- linux.vanilla/drivers/isdn/avmb1/capi.c	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/avmb1/capi.c	Thu Dec  9 15:34:07 1999
@@ -1,11 +1,14 @@
 /*
- * $Id: capi.c,v 1.21 1999/09/10 17:24:18 calle Exp $
+ * $Id: capi.c,v 1.22 1999/11/13 21:27:16 keil Exp $
  *
  * CAPI 2.0 Interface for Linux
  *
  * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capi.c,v $
+ * Revision 1.22  1999/11/13 21:27:16  keil
+ * remove KERNELVERSION
+ *
  * Revision 1.21  1999/09/10 17:24:18  calle
  * Changes for proposed standard for CAPI2.0:
  * - AK148 "Linux Exention"
@@ -282,20 +285,13 @@
 capi_poll(struct file *file, poll_table * wait)
 {
 	unsigned int mask = 0;
-#if (LINUX_VERSION_CODE >= 0x02012d)
 	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
-#else
-	unsigned int minor = MINOR(file->f_inode->i_rdev);
-#endif
 	struct capidev *cdev;
 
 	if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
 		return POLLERR;
 
 	cdev = &capidevs[minor];
-#if (LINUX_VERSION_CODE < 0x020159) /* 2.1.89 */
-#define poll_wait(f,wq,w) poll_wait((wq),(w))
-#endif
 	poll_wait(file, &(cdev->recv_wait), wait);
 	mask = POLLOUT | POLLWRNORM;
 	if (!skb_queue_empty(&cdev->recv_queue))
@@ -523,9 +519,7 @@
 	capi_ioctl,
 	NULL,			/* capi_mmap */
 	capi_open,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,118)
         NULL,                   /* capi_flush */
-#endif
 	capi_release,
 	NULL,			/* capi_fsync */
 	NULL,			/* capi_fasync */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/capidrv.c linux.14p16/drivers/isdn/avmb1/capidrv.c
--- linux.vanilla/drivers/isdn/avmb1/capidrv.c	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/avmb1/capidrv.c	Thu Dec  9 15:34:07 1999
@@ -1,11 +1,14 @@
 /*
- * $Id: capidrv.c,v 1.27 1999/09/16 15:13:04 calle Exp $
+ * $Id: capidrv.c,v 1.28 1999/11/05 16:22:37 calle Exp $
  *
  * ISDN4Linux Driver, using capi20 interface (kernelcapi)
  *
  * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capidrv.c,v $
+ * Revision 1.28  1999/11/05 16:22:37  calle
+ * Bugfix: Missing break in switch on ISDN_CMD_HANGUP.
+ *
  * Revision 1.27  1999/09/16 15:13:04  calle
  * forgot to change paramter type of contr for lower_callback ...
  *
@@ -165,7 +168,7 @@
 #include "capicmd.h"
 #include "capidrv.h"
 
-static char *revision = "$Revision: 1.27 $";
+static char *revision = "$Revision: 1.28 $";
 int debugmode = 0;
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
@@ -716,8 +719,6 @@
   /* P-0.1 */
   {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0},
   {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, 0},
-  {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
-  {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
   /* P-1 */
   {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0},
   {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
@@ -1857,14 +1858,19 @@
 			);
 			ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ);
 			send_message(card, &cmdcmsg);
+			return 0;
 		} else if (bchan->plcip) {
-			bchan->disconnecting = 1;
 			if (bchan->plcip->state == ST_PLCI_INCOMING) {
-				/* just ignore, we a called from isdn_status_callback(),
-				 * which will return 0 or 2, this is handled by the
-				 * CONNECT_IND handler
+				/*
+				 * just ignore, we a called from
+				 * isdn_status_callback(),
+				 * which will return 0 or 2, this is handled
+				 * by the CONNECT_IND handler
 				 */
-			} else {
+				bchan->disconnecting = 1;
+				return 0;
+			} else if (bchan->plcip->plci) {
+				bchan->disconnecting = 1;
 				capi_fill_DISCONNECT_REQ(&cmdcmsg,
 							 global.appid,
 							 card->msgid++,
@@ -1876,8 +1882,18 @@
 				);
 				plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ);
 				send_message(card, &cmdcmsg);
+				return 0;
+			} else {
+				printk(KERN_ERR "capidrv-%d: chan %ld disconnect request while waiting for CONNECT_CONF\n",
+				       card->contrnr,
+				       c->arg);
+				return -EINVAL;
 			}
 		}
+		printk(KERN_ERR "capidrv-%d: chan %ld disconnect request on free channel\n",
+				       card->contrnr,
+				       c->arg);
+		return -EINVAL;
 /* ready */
 
 	case ISDN_CMD_SETL2:
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/kcapi.c linux.14p16/drivers/isdn/avmb1/kcapi.c
--- linux.vanilla/drivers/isdn/avmb1/kcapi.c	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/avmb1/kcapi.c	Thu Dec  9 15:34:07 1999
@@ -1,11 +1,18 @@
 /*
- * $Id: kcapi.c,v 1.8 1999/09/10 17:24:18 calle Exp $
+ * $Id: kcapi.c,v 1.10 1999/10/26 15:30:32 calle Exp $
  * 
  * Kernel CAPI 2.0 Module
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: kcapi.c,v $
+ * Revision 1.10  1999/10/26 15:30:32  calle
+ * Generate error message if user want to add card, but driver module is
+ * not loaded.
+ *
+ * Revision 1.9  1999/10/11 22:04:12  keil
+ * COMPAT_NEED_UACCESS (no include in isdn_compat.h)
+ *
  * Revision 1.8  1999/09/10 17:24:18  calle
  * Changes for proposed standard for CAPI2.0:
  * - AK148 "Linux Exention"
@@ -72,7 +79,7 @@
 #include <linux/b1lli.h>
 #endif
 
-static char *revision = "$Revision: 1.8 $";
+static char *revision = "$Revision: 1.10 $";
 
 /* ------------------------------------------------------------- */
 
@@ -1226,7 +1233,12 @@
 			case AVM_CARDTYPE_T1: driver = t1isa_driver; break;
 			default: driver = 0;
 		}
-		if (!driver || !driver->add_card) {
+		if (!driver) {
+			printk(KERN_ERR "kcapi: driver not loaded.\n");
+			return -EIO;
+		}
+		if (!driver->add_card) {
+			printk(KERN_ERR "kcapi: driver has no add card function.\n");
 			return -EIO;
 		}
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/t1isa.c linux.14p16/drivers/isdn/avmb1/t1isa.c
--- linux.vanilla/drivers/isdn/avmb1/t1isa.c	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/avmb1/t1isa.c	Thu Dec  9 15:34:07 1999
@@ -1,11 +1,18 @@
 /*
- * $Id: t1isa.c,v 1.7 1999/09/15 08:16:03 calle Exp $
+ * $Id: t1isa.c,v 1.8 1999/11/05 16:38:01 calle Exp $
  * 
  * Module for AVM T1 HEMA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: t1isa.c,v $
+ * Revision 1.8  1999/11/05 16:38:01  calle
+ * Cleanups before kernel 2.4:
+ * - Changed all messages to use card->name or driver->name instead of
+ *   constant string.
+ * - Moved some data from struct avmcard into new struct avmctrl_info.
+ *   Changed all lowlevel capi driver to match the new structur.
+ *
  * Revision 1.7  1999/09/15 08:16:03  calle
  * Implementation of 64Bit extention complete.
  *
@@ -66,7 +73,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.7 $";
+static char *revision = "$Revision: 1.8 $";
 
 /* ------------------------------------------------------------- */
 
@@ -169,7 +176,8 @@
 
 static void t1_handle_interrupt(avmcard * card)
 {
-	struct capi_ctr *ctrl = card->ctrl;
+	avmctrl_info *cinfo = &card->ctrlinfo[0];
+	struct capi_ctr *ctrl = cinfo->capi_ctrl;
 	unsigned char b1cmd;
 	struct sk_buff *skb;
 
@@ -197,7 +205,8 @@
 				CAPIMSG_SETLEN(card->msgbuf, 30);
 			}
 			if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {
-				printk(KERN_ERR "t1isa: incoming packet dropped\n");
+				printk(KERN_ERR "%s: incoming packet dropped\n",
+					card->name);
 			} else {
 				memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
 				memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
@@ -210,7 +219,8 @@
 			ApplId = (unsigned) b1_get_word(card->port);
 			MsgLen = t1_get_slice(card->port, card->msgbuf);
 			if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
-				printk(KERN_ERR "t1isa: incoming packet dropped\n");
+				printk(KERN_ERR "%s: incoming packet dropped\n",
+						card->name);
 			} else {
 				memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
 				ctrl->handle_capimsg(ctrl, ApplId, skb);
@@ -248,12 +258,12 @@
 
 		case RECEIVE_INIT:
 
-			card->versionlen = t1_get_slice(card->port, card->versionbuf);
-			b1_parse_version(card);
+			cinfo->versionlen = t1_get_slice(card->port, cinfo->versionbuf);
+			b1_parse_version(cinfo);
 			printk(KERN_INFO "%s: %s-card (%s) now active\n",
 			       card->name,
-			       card->version[VER_CARDTYPE],
-			       card->version[VER_DRIVER]);
+			       cinfo->version[VER_CARDTYPE],
+			       cinfo->version[VER_DRIVER]);
 			ctrl->ready(ctrl);
 			break;
 
@@ -299,11 +309,12 @@
 	card = (avmcard *) devptr;
 
 	if (!card) {
-		printk(KERN_WARNING "t1_interrupt: wrong device\n");
+		printk(KERN_WARNING "t1isa: interrupt: wrong device\n");
 		return;
 	}
 	if (card->interrupt) {
-		printk(KERN_ERR "t1_interrupt: reentering interrupt hander (%s)\n", card->name);
+		printk(KERN_ERR "%s: reentering interrupt hander.\n",
+				 card->name);
 		return;
 	}
 
@@ -317,7 +328,8 @@
 
 static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
 	unsigned int port = card->port;
 	unsigned long flags;
 	int retval;
@@ -325,7 +337,7 @@
 	t1_disable_irq(port);
 	b1_reset(port);
 
-	if ((retval = b1_load_t4file(port, &data->firmware))) {
+	if ((retval = b1_load_t4file(card, &data->firmware))) {
 		b1_reset(port);
 		printk(KERN_ERR "%s: failed to load t4file!!\n",
 					card->name);
@@ -333,7 +345,7 @@
 	}
 
 	if (data->configuration.len > 0 && data->configuration.data) {
-		if ((retval = b1_load_config(port, &data->configuration))) {
+		if ((retval = b1_load_config(card, &data->configuration))) {
 			b1_reset(port);
 			printk(KERN_ERR "%s: failed to load config!!\n",
 					card->name);
@@ -341,7 +353,7 @@
 		}
 	}
 
-	if (!b1_loaded(port)) {
+	if (!b1_loaded(card)) {
 		printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
 		return -EIO;
 	}
@@ -360,20 +372,22 @@
 
 void t1isa_reset_ctr(struct capi_ctr *ctrl)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
 	unsigned int port = card->port;
 
 	t1_disable_irq(port);
 	b1_reset(port);
 	b1_reset(port);
 
-	memset(card->version, 0, sizeof(card->version));
+	memset(cinfo->version, 0, sizeof(cinfo->version));
 	ctrl->reseted(ctrl);
 }
 
 static void t1isa_remove_ctr(struct capi_ctr *ctrl)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
 	unsigned int port = card->port;
 
 	t1_disable_irq(port);
@@ -384,6 +398,7 @@
 	di->detach_ctr(ctrl);
 	free_irq(card->irq, card);
 	release_region(card->port, AVMB1_PORTLEN);
+	kfree(card->ctrlinfo);
 	kfree(card);
 
 	MOD_DEC_USE_COUNT;
@@ -394,16 +409,26 @@
 static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
 {
 	struct capi_ctr *ctrl;
+	avmctrl_info *cinfo;
 	avmcard *card;
 	int retval;
 
 	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
 
 	if (!card) {
-		printk(KERN_WARNING "t1isa: no memory.\n");
+		printk(KERN_WARNING "%s: no memory.\n", driver->name);
 		return -ENOMEM;
 	}
 	memset(card, 0, sizeof(avmcard));
+        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+	if (!cinfo) {
+		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		kfree(card);
+		return -ENOMEM;
+	}
+	memset(cinfo, 0, sizeof(avmctrl_info));
+	card->ctrlinfo = cinfo;
+	cinfo->card = card;
 	sprintf(card->name, "t1isa-%x", p->port);
 	card->port = p->port;
 	card->irq = p->irq;
@@ -411,33 +436,42 @@
 	card->cardnr = p->cardnr;
 
 	if (!(((card->port & 0x7) == 0) && ((card->port & 0x30) != 0x30))) {
-		printk(KERN_WARNING "t1isa: illegal port 0x%x.\n", card->port);
+		printk(KERN_WARNING "%s: illegal port 0x%x.\n",
+				driver->name, card->port);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EINVAL;
         }
 
 	if (check_region(card->port, AVMB1_PORTLEN)) {
 		printk(KERN_WARNING
-		       "t1isa: ports 0x%03x-0x%03x in use.\n",
-		       card->port, card->port + AVMB1_PORTLEN);
+		       "%s: ports 0x%03x-0x%03x in use.\n",
+		       driver->name, card->port, card->port + AVMB1_PORTLEN);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EBUSY;
 	}
 	if (hema_irq_table[card->irq & 0xf] == 0) {
-		printk(KERN_WARNING "t1isa: irq %d not valid.\n", card->irq);
+		printk(KERN_WARNING "%s: irq %d not valid.\n",
+				driver->name, card->irq);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EINVAL;
 	}
 	for (ctrl = driver->controller; ctrl; ctrl = ctrl->next) {
-		if (((avmcard *)(ctrl->driverdata))->cardnr == card->cardnr) {
-			printk(KERN_WARNING "t1isa: card with number %d already installed.\n", card->cardnr);
+	        avmcard *cardp = ((avmctrl_info *)(ctrl->driverdata))->card;
+		if (cardp->cardnr == card->cardnr) {
+			printk(KERN_WARNING "%s: card with number %d already installed at 0x%x.\n",
+					driver->name, card->cardnr, cardp->port);
+	                kfree(card->ctrlinfo);
 			kfree(card);
 			return -EBUSY;
 		}
 	}
         if ((retval = t1_detectandinit(card->port, card->irq, card->cardnr)) != 0) {
-		printk(KERN_NOTICE "t1isa: NO card at 0x%x (%d)\n",
-					card->port, retval);
+		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+					driver->name, card->port, retval);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EIO;
 	}
@@ -448,17 +482,21 @@
 
 	retval = request_irq(card->irq, t1isa_interrupt, 0, card->name, card);
 	if (retval) {
-		printk(KERN_ERR "t1isa: unable to get IRQ %d.\n", card->irq);
+		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+				driver->name, card->irq);
 		release_region(card->port, AVMB1_PORTLEN);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EBUSY;
 	}
 
-	card->ctrl = di->attach_ctr(driver, card->name, card);
-	if (!card->ctrl) {
-		printk(KERN_ERR "t1isa: attach controller failed.\n");
+	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+	if (!cinfo->capi_ctrl) {
+		printk(KERN_ERR "%s: attach controller failed.\n",
+				driver->name);
 		free_irq(card->irq, card);
 		release_region(card->port, AVMB1_PORTLEN);
+	        kfree(card->ctrlinfo);
 		kfree(card);
 		return -EBUSY;
 	}
@@ -469,7 +507,8 @@
 
 static void t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
 	unsigned int port = card->port;
 	unsigned long flags;
 	__u16 len = CAPIMSG_LEN(skb->data);
@@ -494,15 +533,18 @@
 
 static char *t1isa_procinfo(struct capi_ctr *ctrl)
 {
-	avmcard *card = (avmcard *)(ctrl->driverdata);
-	if (!card)
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+	if (!cinfo)
 		return "";
-	sprintf(card->infobuf, "%s %s 0x%x %d %d",
-		card->cardname[0] ? card->cardname : "-",
-		card->version[VER_DRIVER] ? card->version[VER_DRIVER] : "-",
-		card->port, card->irq, card->cardnr
+	sprintf(cinfo->infobuf, "%s %s 0x%x %d %d",
+		cinfo->cardname[0] ? cinfo->cardname : "-",
+		cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+		cinfo->card ? cinfo->card->port : 0x0,
+		cinfo->card ? cinfo->card->irq : 0,
+		cinfo->card ? cinfo->card->cardnr : 0
 		);
-	return card->infobuf;
+	return cinfo->infobuf;
 }
 
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/t1pci.c linux.14p16/drivers/isdn/avmb1/t1pci.c
--- linux.vanilla/drivers/isdn/avmb1/t1pci.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/isdn/avmb1/t1pci.c	Thu Dec  9 15:34:07 1999
@@ -0,0 +1,1166 @@
+/*
+ * $Id: t1pci.c,v 1.3 1999/11/13 21:27:16 keil Exp $
+ * 
+ * Module for AVM T1 PCI-card.
+ * 
+ * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
+ * 
+ * $Log: t1pci.c,v $
+ * Revision 1.3  1999/11/13 21:27:16  keil
+ * remove KERNELVERSION
+ *
+ * Revision 1.2  1999/11/05 16:38:02  calle
+ * Cleanups before kernel 2.4:
+ * - Changed all messages to use card->name or driver->name instead of
+ *   constant string.
+ * - Moved some data from struct avmcard into new struct avmctrl_info.
+ *   Changed all lowlevel capi driver to match the new structur.
+ *
+ * Revision 1.1  1999/10/26 15:31:42  calle
+ * Added driver for T1-PCI card.
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/capi.h>
+#include <asm/io.h>
+#include "capicmd.h"
+#include "capiutil.h"
+#include "capilli.h"
+#include "avmcard.h"
+
+static char *revision = "$Revision: 1.3 $";
+
+#undef CONFIG_T1PCI_DEBUG
+#undef CONFIG_T1PCI_POLLDEBUG
+
+/* ------------------------------------------------------------- */
+
+#ifndef PCI_VENDOR_ID_AVM
+#define PCI_VENDOR_ID_AVM	0x1244
+#endif
+
+#ifndef PCI_DEVICE_ID_AVM_T1
+#define PCI_DEVICE_ID_AVM_T1	0x1200
+#endif
+
+/* ------------------------------------------------------------- */
+
+int suppress_pollack = 0;
+
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+
+MODULE_PARM(suppress_pollack, "0-1i");
+
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver_interface *di;
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_dispatch_tx(avmcard *card);
+
+/* ------------------------------------------------------------- */
+
+/* S5933 */
+
+#define	AMCC_RXPTR	0x24
+#define	AMCC_RXLEN	0x28
+#define	AMCC_TXPTR	0x2c
+#define	AMCC_TXLEN	0x30
+
+#define	AMCC_INTCSR	0x38
+#	define EN_READ_TC_INT		0x00008000L
+#	define EN_WRITE_TC_INT		0x00004000L
+#	define EN_TX_TC_INT		EN_READ_TC_INT
+#	define EN_RX_TC_INT		EN_WRITE_TC_INT
+#	define AVM_FLAG			0x30000000L
+
+#	define ANY_S5933_INT		0x00800000L
+#	define	READ_TC_INT		0x00080000L
+#	define WRITE_TC_INT		0x00040000L
+#	define	TX_TC_INT		READ_TC_INT
+#	define	RX_TC_INT		WRITE_TC_INT
+#	define MASTER_ABORT_INT		0x00100000L
+#	define TARGET_ABORT_INT		0x00200000L
+#	define BUS_MASTER_INT		0x00200000L
+#	define ALL_INT			0x000C0000L
+
+#define	AMCC_MCSR	0x3c
+#	define A2P_HI_PRIORITY		0x00000100L
+#	define EN_A2P_TRANSFERS		0x00000400L
+#	define P2A_HI_PRIORITY		0x00001000L
+#	define EN_P2A_TRANSFERS		0x00004000L
+#	define RESET_A2P_FLAGS		0x04000000L
+#	define RESET_P2A_FLAGS		0x02000000L
+
+/* ------------------------------------------------------------- */
+
+#define t1outmeml(addr, value)	writel(value, addr)
+#define t1inmeml(addr)	readl(addr)
+#define t1outmemw(addr, value)	writew(value, addr)
+#define t1inmemw(addr)	readw(addr)
+#define t1outmemb(addr, value)	writeb(value, addr)
+#define t1inmemb(addr)	readb(addr)
+
+/* ------------------------------------------------------------- */
+
+static inline int t1pci_tx_empty(unsigned int port)
+{
+	return inb(port + 0x03) & 0x1;
+}
+
+static inline int t1pci_rx_full(unsigned int port)
+{
+	return inb(port + 0x02) & 0x1;
+}
+
+static int t1pci_tolink(avmcard *card, void *buf, unsigned int len)
+{
+	unsigned long stop = jiffies + 1 * HZ;	/* maximum wait time 1 sec */
+	unsigned char *s = (unsigned char *)buf;
+	while (len--) {
+		while (   !t1pci_tx_empty(card->port)
+		       && time_before(jiffies, stop));
+		if (!t1pci_tx_empty(card->port)) 
+			return -1;
+	        t1outp(card->port, 0x01, *s++);
+	}
+	return 0;
+}
+
+static int t1pci_fromlink(avmcard *card, void *buf, unsigned int len)
+{
+	unsigned long stop = jiffies + 1 * HZ;	/* maximum wait time 1 sec */
+	unsigned char *s = (unsigned char *)buf;
+	while (len--) {
+		while (   !t1pci_rx_full(card->port)
+		       && time_before(jiffies, stop));
+		if (!t1pci_rx_full(card->port)) 
+			return -1;
+	        *s++ = t1inp(card->port, 0x00);
+	}
+	return 0;
+}
+
+static int WriteReg(avmcard *card, __u32 reg, __u8 val)
+{
+	__u8 cmd = 0x00;
+	if (   t1pci_tolink(card, &cmd, 1) == 0
+	    && t1pci_tolink(card, &reg, 4) == 0) {
+		__u32 tmp = val;
+		return t1pci_tolink(card, &tmp, 4);
+	}
+	return -1;
+}
+
+static __u8 ReadReg(avmcard *card, __u32 reg)
+{
+	__u8 cmd = 0x01;
+	if (   t1pci_tolink(card, &cmd, 1) == 0
+	    && t1pci_tolink(card, &reg, 4) == 0) {
+		__u32 tmp;
+		if (t1pci_fromlink(card, &tmp, 4) == 0)
+			return (__u8)tmp;
+	}
+	return 0xff;
+}
+
+/* ------------------------------------------------------------- */
+
+static inline void _put_byte(void **pp, __u8 val)
+{
+	__u8 *s = *pp;
+	*s++ = val;
+	*pp = s;
+}
+
+static inline void _put_word(void **pp, __u32 val)
+{
+	__u8 *s = *pp;
+	*s++ = val & 0xff;
+	*s++ = (val >> 8) & 0xff;
+	*s++ = (val >> 16) & 0xff;
+	*s++ = (val >> 24) & 0xff;
+	*pp = s;
+}
+
+static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len)
+{
+	unsigned i = len;
+	_put_word(pp, i);
+	while (i-- > 0)
+		_put_byte(pp, *dp++);
+}
+
+static inline __u8 _get_byte(void **pp)
+{
+	__u8 *s = *pp;
+	__u8 val;
+	val = *s++;
+	*pp = s;
+	return val;
+}
+
+static inline __u32 _get_word(void **pp)
+{
+	__u8 *s = *pp;
+	__u32 val;
+	val = *s++;
+	val |= (*s++ << 8);
+	val |= (*s++ << 16);
+	val |= (*s++ << 24);
+	*pp = s;
+	return val;
+}
+
+static inline __u32 _get_slice(void **pp, unsigned char *dp)
+{
+	unsigned int len, i;
+
+	len = i = _get_word(pp);
+	while (i-- > 0) *dp++ = _get_byte(pp);
+	return len;
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_reset(avmcard *card)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	card->csr = 0x0;
+	t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
+	t1outmeml(card->mbase+AMCC_MCSR, 0);
+	t1outmeml(card->mbase+AMCC_RXLEN, 0);
+	t1outmeml(card->mbase+AMCC_TXLEN, 0);
+
+	t1outp(card->port, T1_RESETLINK, 0x00);
+	t1outp(card->port, 0x07, 0x00);
+
+	restore_flags(flags);
+
+	t1outmeml(card->mbase+AMCC_MCSR, 0);
+	udelay(10 * 1000);
+	t1outmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
+	udelay(10 * 1000);
+	t1outmeml(card->mbase+AMCC_MCSR, 0);
+	udelay(42 * 1000);
+
+}
+
+/* ------------------------------------------------------------- */
+
+static int t1pci_detect(avmcard *card)
+{
+	t1outmeml(card->mbase+AMCC_MCSR, 0);
+	udelay(10 * 1000);
+	t1outmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
+	udelay(10 * 1000);
+	t1outmeml(card->mbase+AMCC_MCSR, 0);
+	udelay(42 * 1000);
+
+	t1outmeml(card->mbase+AMCC_RXLEN, 0);
+	t1outmeml(card->mbase+AMCC_TXLEN, 0);
+	card->csr = 0x0;
+	t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
+
+	if (t1inmeml(card->mbase+AMCC_MCSR) != 0x000000E6)
+		return 1;
+
+	t1outmeml(card->mbase+AMCC_RXPTR, 0xffffffff);
+	t1outmeml(card->mbase+AMCC_TXPTR, 0xffffffff);
+	if (   t1inmeml(card->mbase+AMCC_RXPTR) != 0xfffffffc
+	    || t1inmeml(card->mbase+AMCC_TXPTR) != 0xfffffffc)
+		return 2;
+
+	t1outmeml(card->mbase+AMCC_RXPTR, 0x0);
+	t1outmeml(card->mbase+AMCC_TXPTR, 0x0);
+	if (   t1inmeml(card->mbase+AMCC_RXPTR) != 0x0
+	    || t1inmeml(card->mbase+AMCC_TXPTR) != 0x0)
+		return 3;
+
+	t1outp(card->port, T1_RESETLINK, 0x00);
+	t1outp(card->port, 0x07, 0x00);
+	
+	t1outp(card->port, 0x02, 0x02);
+	t1outp(card->port, 0x03, 0x02);
+
+	if (   (t1inp(card->port, 0x02) & 0xFE) != 0x02
+	    || t1inp(card->port, 0x3) != 0x03)
+		return 4;
+
+	t1outp(card->port, 0x02, 0x00);
+	t1outp(card->port, 0x03, 0x00);
+
+	if (   (t1inp(card->port, 0x02) & 0xFE) != 0x00
+	    || t1inp(card->port, 0x3) != 0x01)
+		return 5;
+
+	/* Transputer test */
+	
+	if (   WriteReg(card, 0x80001000, 0x11) != 0
+	    || WriteReg(card, 0x80101000, 0x22) != 0
+	    || WriteReg(card, 0x80201000, 0x33) != 0
+	    || WriteReg(card, 0x80301000, 0x44) != 0)
+		return 6;
+
+	if (   ReadReg(card, 0x80001000) != 0x11
+	    || ReadReg(card, 0x80101000) != 0x22
+	    || ReadReg(card, 0x80201000) != 0x33
+	    || ReadReg(card, 0x80301000) != 0x44)
+		return 7;
+
+	if (   WriteReg(card, 0x80001000, 0x55) != 0
+	    || WriteReg(card, 0x80101000, 0x66) != 0
+	    || WriteReg(card, 0x80201000, 0x77) != 0
+	    || WriteReg(card, 0x80301000, 0x88) != 0)
+		return 8;
+
+	if (   ReadReg(card, 0x80001000) != 0x55
+	    || ReadReg(card, 0x80101000) != 0x66
+	    || ReadReg(card, 0x80201000) != 0x77
+	    || ReadReg(card, 0x80301000) != 0x88)
+		return 9;
+
+	return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_dispatch_tx(avmcard *card)
+{
+	avmcard_dmainfo *dma = card->dma;
+	unsigned long flags;
+	struct sk_buff *skb;
+	__u8 cmd, subcmd;
+	__u16 len;
+	__u32 txlen;
+	int inint;
+	void *p;
+	
+	save_flags(flags);
+	cli();
+
+	inint = card->interrupt;
+
+	if (card->csr & EN_TX_TC_INT) { /* tx busy */
+	        restore_flags(flags);
+		return;
+	}
+
+	skb = skb_dequeue(&dma->send_queue);
+	if (!skb) {
+#ifdef CONFIG_T1PCI_DEBUG
+		printk(KERN_DEBUG "tx(%d): underrun\n", inint);
+#endif
+	        restore_flags(flags);
+		return;
+	}
+
+	len = CAPIMSG_LEN(skb->data);
+
+	if (len) {
+		cmd = CAPIMSG_COMMAND(skb->data);
+		subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+
+		p = dma->sendbuf;
+
+		if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
+			__u16 dlen = CAPIMSG_DATALEN(skb->data);
+			_put_byte(&p, SEND_DATA_B3_REQ);
+			_put_slice(&p, skb->data, len);
+			_put_slice(&p, skb->data + len, dlen);
+		} else {
+			_put_byte(&p, SEND_MESSAGE);
+			_put_slice(&p, skb->data, len);
+		}
+		txlen = (__u8 *)p - (__u8 *)dma->sendbuf;
+#ifdef CONFIG_T1PCI_DEBUG
+		printk(KERN_DEBUG "tx(%d): put msg len=%d\n",
+				inint, txlen);
+#endif
+	} else {
+		txlen = skb->len-2;
+#ifdef CONFIG_T1PCI_POLLDEBUG
+		if (skb->data[2] == SEND_POLLACK)
+			printk(KERN_INFO "%s: ack to t1\n", card->name);
+#endif
+#ifdef CONFIG_T1PCI_DEBUG
+		printk(KERN_DEBUG "tx(%d): put 0x%x len=%d\n",
+				inint, skb->data[2], txlen);
+#endif
+		memcpy(dma->sendbuf, skb->data+2, skb->len-2);
+	}
+	txlen = (txlen + 3) & ~3;
+
+	t1outmeml(card->mbase+AMCC_TXPTR, virt_to_phys(dma->sendbuf));
+	t1outmeml(card->mbase+AMCC_TXLEN, txlen);
+
+	card->csr |= EN_TX_TC_INT;
+
+	if (!inint)
+		t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
+
+	restore_flags(flags);
+	dev_kfree_skb(skb);
+}
+
+/* ------------------------------------------------------------- */
+
+static void queue_pollack(avmcard *card)
+{
+	struct sk_buff *skb;
+	void *p;
+
+	skb = alloc_skb(3, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_CRIT "%s: no memory, lost poll ack\n",
+					card->name);
+		return;
+	}
+	p = skb->data;
+	_put_byte(&p, 0);
+	_put_byte(&p, 0);
+	_put_byte(&p, SEND_POLLACK);
+	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+	skb_queue_tail(&card->dma->send_queue, skb);
+	t1pci_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_handle_rx(avmcard *card)
+{
+	avmctrl_info *cinfo = &card->ctrlinfo[0];
+	avmcard_dmainfo *dma = card->dma;
+	struct capi_ctr *ctrl = cinfo->capi_ctrl;
+	struct sk_buff *skb;
+	void *p = dma->recvbuf+4;
+	__u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
+	__u8 b1cmd =  _get_byte(&p);
+
+#ifdef CONFIG_T1PCI_DEBUG
+	printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen);
+#endif
+	
+	switch (b1cmd) {
+	case RECEIVE_DATA_B3_IND:
+
+		ApplId = (unsigned) _get_word(&p);
+		MsgLen = _get_slice(&p, card->msgbuf);
+		DataB3Len = _get_slice(&p, card->databuf);
+
+		if (MsgLen < 30) { /* not CAPI 64Bit */
+			memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
+			MsgLen = 30;
+			CAPIMSG_SETLEN(card->msgbuf, 30);
+		}
+		if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {
+			printk(KERN_ERR "%s: incoming packet dropped\n",
+					card->name);
+		} else {
+			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+			memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
+			ctrl->handle_capimsg(ctrl, ApplId, skb);
+		}
+		break;
+
+	case RECEIVE_MESSAGE:
+
+		ApplId = (unsigned) _get_word(&p);
+		MsgLen = _get_slice(&p, card->msgbuf);
+		if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
+			printk(KERN_ERR "%s: incoming packet dropped\n",
+					card->name);
+		} else {
+			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+			ctrl->handle_capimsg(ctrl, ApplId, skb);
+		}
+		break;
+
+	case RECEIVE_NEW_NCCI:
+
+		ApplId = _get_word(&p);
+		NCCI = _get_word(&p);
+		WindowSize = _get_word(&p);
+
+		ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
+
+		break;
+
+	case RECEIVE_FREE_NCCI:
+
+		ApplId = _get_word(&p);
+		NCCI = _get_word(&p);
+
+		if (NCCI != 0xffffffff)
+			ctrl->free_ncci(ctrl, ApplId, NCCI);
+		else ctrl->appl_released(ctrl, ApplId);
+		break;
+
+	case RECEIVE_START:
+#ifdef CONFIG_T1PCI_POLLDEBUG
+		printk(KERN_INFO "%s: poll from t1\n", card->name);
+#endif
+		if (!suppress_pollack)
+			queue_pollack(card);
+		ctrl->resume_output(ctrl);
+		break;
+
+	case RECEIVE_STOP:
+		ctrl->suspend_output(ctrl);
+		break;
+
+	case RECEIVE_INIT:
+
+		cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
+		b1_parse_version(cinfo);
+		printk(KERN_INFO "%s: %s-card (%s) now active\n",
+		       card->name,
+		       cinfo->version[VER_CARDTYPE],
+		       cinfo->version[VER_DRIVER]);
+		ctrl->ready(ctrl);
+		break;
+
+	case RECEIVE_TASK_READY:
+		ApplId = (unsigned) _get_word(&p);
+		MsgLen = _get_slice(&p, card->msgbuf);
+		card->msgbuf[MsgLen--] = 0;
+		while (    MsgLen >= 0
+		       && (   card->msgbuf[MsgLen] == '\n'
+			   || card->msgbuf[MsgLen] == '\r'))
+			card->msgbuf[MsgLen--] = 0;
+		printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
+				card->name, ApplId, card->msgbuf);
+		break;
+
+	case RECEIVE_DEBUGMSG:
+		MsgLen = _get_slice(&p, card->msgbuf);
+		card->msgbuf[MsgLen--] = 0;
+		while (    MsgLen >= 0
+		       && (   card->msgbuf[MsgLen] == '\n'
+			   || card->msgbuf[MsgLen] == '\r'))
+			card->msgbuf[MsgLen--] = 0;
+		printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
+		break;
+
+	default:
+		printk(KERN_ERR "%s: t1pci_interrupt: 0x%x ???\n",
+				card->name, b1cmd);
+		return;
+	}
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_handle_interrupt(avmcard *card)
+{
+	__u32 status = t1inmeml(card->mbase+AMCC_INTCSR);
+	__u32 newcsr;
+
+	if ((status & ANY_S5933_INT) == 0) 
+		return;
+
+        newcsr = card->csr | (status & ALL_INT);
+	if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
+	if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
+	t1outmeml(card->mbase+AMCC_INTCSR, newcsr);
+
+	if ((status & RX_TC_INT) != 0) {
+		__u8 *recvbuf = card->dma->recvbuf;
+		__u32 rxlen;
+	   	if (card->dma->recvlen == 0) {
+			card->dma->recvlen = *((__u32 *)recvbuf);
+			rxlen = (card->dma->recvlen + 3) & ~3;
+			t1outmeml(card->mbase+AMCC_RXPTR,
+					virt_to_phys(recvbuf+4));
+			t1outmeml(card->mbase+AMCC_RXLEN, rxlen);
+		} else {
+			t1pci_handle_rx(card);
+	   		card->dma->recvlen = 0;
+			t1outmeml(card->mbase+AMCC_RXPTR, virt_to_phys(recvbuf));
+			t1outmeml(card->mbase+AMCC_RXLEN, 4);
+		}
+	}
+
+	if ((status & TX_TC_INT) != 0) {
+		card->csr &= ~EN_TX_TC_INT;
+	        t1pci_dispatch_tx(card);
+	} else if (card->csr & EN_TX_TC_INT) {
+		if (t1inmeml(card->mbase+AMCC_TXLEN) == 0) {
+			card->csr &= ~EN_TX_TC_INT;
+			t1pci_dispatch_tx(card);
+		}
+	}
+	t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
+}
+
+static void t1pci_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+{
+	avmcard *card;
+
+	card = (avmcard *) devptr;
+
+	if (!card) {
+		printk(KERN_WARNING "t1pci: interrupt: wrong device\n");
+		return;
+	}
+	if (card->interrupt) {
+		printk(KERN_ERR "%s: reentering interrupt hander\n", card->name);
+		return;
+	}
+
+	card->interrupt = 1;
+
+	t1pci_handle_interrupt(card);
+
+	card->interrupt = 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static int t1pci_loaded(avmcard *card)
+{
+	unsigned long stop;
+	unsigned char ans;
+	unsigned long tout = 2;
+	unsigned int base = card->port;
+
+	for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
+		if (b1_tx_empty(base))
+			break;
+	}
+	if (!b1_tx_empty(base)) {
+		printk(KERN_ERR "%s: t1pci_loaded: tx err, corrupted t4 file ?\n",
+				card->name);
+		return 0;
+	}
+	b1_put_byte(base, SEND_POLLACK);
+	for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
+		if (b1_rx_full(base)) {
+			if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) {
+				return 1;
+			}
+			printk(KERN_ERR "%s: t1pci_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans);
+			return 0;
+		}
+	}
+	printk(KERN_ERR "%s: t1pci_loaded: firmware not running\n", card->name);
+	return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_send_init(avmcard *card)
+{
+	struct sk_buff *skb;
+	void *p;
+
+	skb = alloc_skb(15, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_CRIT "%s: no memory, lost register appl.\n",
+					card->name);
+		return;
+	}
+	p = skb->data;
+	_put_byte(&p, 0);
+	_put_byte(&p, 0);
+	_put_byte(&p, SEND_INIT);
+	_put_word(&p, AVM_NAPPS);
+	_put_word(&p, AVM_NCCI_PER_CHANNEL*30);
+	_put_word(&p, card->cardnr - 1);
+	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+	skb_queue_tail(&card->dma->send_queue, skb);
+	t1pci_dispatch_tx(card);
+}
+
+static int t1pci_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	unsigned long flags;
+	int retval;
+
+	t1pci_reset(card);
+
+	if ((retval = b1_load_t4file(card, &data->firmware))) {
+		t1pci_reset(card);
+		printk(KERN_ERR "%s: failed to load t4file!!\n",
+					card->name);
+		return retval;
+	}
+
+	if (data->configuration.len > 0 && data->configuration.data) {
+		if ((retval = b1_load_config(card, &data->configuration))) {
+			t1pci_reset(card);
+			printk(KERN_ERR "%s: failed to load config!!\n",
+					card->name);
+			return retval;
+		}
+	}
+
+	if (!t1pci_loaded(card)) {
+		t1pci_reset(card);
+		printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
+		return -EIO;
+	}
+
+	save_flags(flags);
+	cli();
+
+	card->csr = AVM_FLAG;
+	t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
+	t1outmeml(card->mbase+AMCC_MCSR,
+		EN_A2P_TRANSFERS|EN_P2A_TRANSFERS
+		|A2P_HI_PRIORITY|P2A_HI_PRIORITY
+		|RESET_A2P_FLAGS|RESET_P2A_FLAGS);
+	t1outp(card->port, 0x07, 0x30);
+	t1outp(card->port, 0x10, 0xF0);
+
+	card->dma->recvlen = 0;
+	t1outmeml(card->mbase+AMCC_RXPTR, virt_to_phys(card->dma->recvbuf));
+	t1outmeml(card->mbase+AMCC_RXLEN, 4);
+	card->csr |= EN_RX_TC_INT;
+	t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
+	restore_flags(flags);
+
+        t1pci_send_init(card);
+
+	return 0;
+}
+
+void t1pci_reset_ctr(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+
+ 	t1pci_reset(card);
+
+	memset(cinfo->version, 0, sizeof(cinfo->version));
+	ctrl->reseted(ctrl);
+}
+
+static void t1pci_remove_ctr(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+
+ 	t1pci_reset(card);
+
+	di->detach_ctr(ctrl);
+	free_irq(card->irq, card);
+	iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+	release_region(card->port, AVMB1_PORTLEN);
+	ctrl->driverdata = 0;
+	kfree(card->ctrlinfo);
+	kfree(card->dma);
+	kfree(card);
+
+	MOD_DEC_USE_COUNT;
+}
+
+/* ------------------------------------------------------------- */
+
+
+void t1pci_register_appl(struct capi_ctr *ctrl,
+				__u16 appl,
+				capi_register_params *rp)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	struct sk_buff *skb;
+	int want = rp->level3cnt;
+	int nconn;
+	void *p;
+
+	if (want > 0) nconn = want;
+	else nconn = ctrl->profile.nbchannel * -want;
+	if (nconn == 0) nconn = ctrl->profile.nbchannel;
+
+	skb = alloc_skb(23, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_CRIT "%s: no memory, lost register appl.\n",
+					card->name);
+		return;
+	}
+	p = skb->data;
+	_put_byte(&p, 0);
+	_put_byte(&p, 0);
+	_put_byte(&p, SEND_REGISTER);
+	_put_word(&p, appl);
+	_put_word(&p, 1024 * (nconn+1));
+	_put_word(&p, nconn);
+	_put_word(&p, rp->datablkcnt);
+	_put_word(&p, rp->datablklen);
+	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+	skb_queue_tail(&card->dma->send_queue, skb);
+	t1pci_dispatch_tx(card);
+
+	ctrl->appl_registered(ctrl, appl);
+}
+
+/* ------------------------------------------------------------- */
+
+void t1pci_release_appl(struct capi_ctr *ctrl, __u16 appl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	struct sk_buff *skb;
+	void *p;
+
+	skb = alloc_skb(7, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_CRIT "%s: no memory, lost release appl.\n",
+					card->name);
+		return;
+	}
+	p = skb->data;
+	_put_byte(&p, 0);
+	_put_byte(&p, 0);
+	_put_byte(&p, SEND_RELEASE);
+	_put_word(&p, appl);
+
+	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+	skb_queue_tail(&card->dma->send_queue, skb);
+	t1pci_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+
+static void t1pci_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	skb_queue_tail(&card->dma->send_queue, skb);
+	t1pci_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+static char *t1pci_procinfo(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+	if (!cinfo)
+		return "";
+	sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx",
+		cinfo->cardname[0] ? cinfo->cardname : "-",
+		cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+		cinfo->card ? cinfo->card->port : 0x0,
+		cinfo->card ? cinfo->card->irq : 0,
+		cinfo->card ? cinfo->card->membase : 0
+		);
+	return cinfo->infobuf;
+}
+
+static int t1pci_read_proc(char *page, char **start, off_t off,
+        		int count, int *eof, struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	unsigned long flags;
+	__u8 flag;
+	int len = 0;
+	char *s;
+	__u32 txaddr, txlen, rxaddr, rxlen, csr;
+
+	len += sprintf(page+len, "%-16s %s\n", "name", card->name);
+	len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
+	len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
+	len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
+	switch (card->cardtype) {
+	case avm_b1isa: s = "B1 ISA"; break;
+	case avm_b1pci: s = "B1 PCI"; break;
+	case avm_b1pcmcia: s = "B1 PCMCIA"; break;
+	case avm_m1: s = "M1"; break;
+	case avm_m2: s = "M2"; break;
+	case avm_t1isa: s = "T1 ISA (HEMA)"; break;
+	case avm_t1pci: s = "T1 PCI"; break;
+	case avm_c4: s = "C4"; break;
+	default: s = "???"; break;
+	}
+	len += sprintf(page+len, "%-16s %s\n", "type", s);
+	if ((s = cinfo->version[VER_DRIVER]) != 0)
+	   len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+	if ((s = cinfo->version[VER_CARDTYPE]) != 0)
+	   len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+	if ((s = cinfo->version[VER_SERIAL]) != 0)
+	   len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+
+	if (card->cardtype != avm_m1) {
+        	flag = ((__u8 *)(ctrl->profile.manu))[3];
+        	if (flag)
+			len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
+			"protocol",
+			(flag & 0x01) ? " DSS1" : "",
+			(flag & 0x02) ? " CT1" : "",
+			(flag & 0x04) ? " VN3" : "",
+			(flag & 0x08) ? " NI1" : "",
+			(flag & 0x10) ? " AUSTEL" : "",
+			(flag & 0x20) ? " ESS" : "",
+			(flag & 0x40) ? " 1TR6" : ""
+			);
+	}
+	if (card->cardtype != avm_m1) {
+        	flag = ((__u8 *)(ctrl->profile.manu))[5];
+		if (flag)
+			len += sprintf(page+len, "%-16s%s%s%s%s\n",
+			"linetype",
+			(flag & 0x01) ? " point to point" : "",
+			(flag & 0x02) ? " point to multipoint" : "",
+			(flag & 0x08) ? " leased line without D-channel" : "",
+			(flag & 0x04) ? " leased line with D-channel" : ""
+			);
+	}
+	len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
+
+	save_flags(flags);
+	cli();
+
+	txaddr = (__u32)phys_to_virt(t1inmeml(card->mbase+0x2c));
+	txaddr -= (__u32)card->dma->sendbuf;
+	txlen  = t1inmeml(card->mbase+0x30);
+
+	rxaddr = (__u32)phys_to_virt(t1inmeml(card->mbase+0x24));
+	rxaddr -= (__u32)card->dma->recvbuf;
+	rxlen  = t1inmeml(card->mbase+0x28);
+
+	csr  = t1inmeml(card->mbase+AMCC_INTCSR);
+
+	restore_flags(flags);
+
+        len += sprintf(page+len, "%-16s 0x%lx\n",
+				"csr (cached)", (unsigned long)card->csr);
+        len += sprintf(page+len, "%-16s 0x%lx\n",
+				"csr", (unsigned long)csr);
+        len += sprintf(page+len, "%-16s %lu\n",
+				"txoff", (unsigned long)txaddr);
+        len += sprintf(page+len, "%-16s %lu\n",
+				"txlen", (unsigned long)txlen);
+        len += sprintf(page+len, "%-16s %lu\n",
+				"rxoff", (unsigned long)rxaddr);
+        len += sprintf(page+len, "%-16s %lu\n",
+				"rxlen", (unsigned long)rxlen);
+
+	if (off+count >= len)
+	   *eof = 1;
+	if (len < off)
+           return 0;
+	*start = page + off;
+	return ((count < len-off) ? count : len-off);
+}
+
+/* ------------------------------------------------------------- */
+
+static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
+{
+	unsigned long page_offset, base;
+	avmcard *card;
+	avmctrl_info *cinfo;
+	int retval;
+
+	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
+
+	if (!card) {
+		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		return -ENOMEM;
+	}
+	memset(card, 0, sizeof(avmcard));
+	card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC);
+	if (!card->dma) {
+		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		kfree(card);
+		return -ENOMEM;
+	}
+	memset(card->dma, 0, sizeof(avmcard_dmainfo));
+        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+	if (!cinfo) {
+		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		kfree(card->dma);
+		kfree(card);
+		return -ENOMEM;
+	}
+	memset(cinfo, 0, sizeof(avmctrl_info));
+	card->ctrlinfo = cinfo;
+	cinfo->card = card;
+	sprintf(card->name, "t1pci-%x", p->port);
+	card->port = p->port;
+	card->irq = p->irq;
+	card->membase = p->membase;
+	card->cardtype = avm_t1pci;
+
+	if (check_region(card->port, AVMB1_PORTLEN)) {
+		printk(KERN_WARNING
+		       "%s: ports 0x%03x-0x%03x in use.\n",
+		       driver->name, card->port, card->port + AVMB1_PORTLEN);
+	        kfree(card->ctrlinfo);
+		kfree(card->dma);
+		kfree(card);
+		return -EBUSY;
+	}
+
+        base = card->membase & PAGE_MASK;
+	page_offset = card->membase - base;
+	card->mbase = ioremap_nocache(base, page_offset + 64);
+
+	t1pci_reset(card);
+
+	if ((retval = t1pci_detect(card)) != 0) {
+		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+					driver->name, card->port, retval);
+                iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+	        kfree(card->ctrlinfo);
+		kfree(card->dma);
+		kfree(card);
+		return -EIO;
+	}
+	t1pci_reset(card);
+
+	request_region(p->port, AVMB1_PORTLEN, card->name);
+
+	retval = request_irq(card->irq, t1pci_interrupt, SA_SHIRQ, card->name, card);
+	if (retval) {
+		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+				driver->name, card->irq);
+                iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+		release_region(card->port, AVMB1_PORTLEN);
+	        kfree(card->ctrlinfo);
+		kfree(card->dma);
+		kfree(card);
+		return -EBUSY;
+	}
+
+	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+	if (!cinfo->capi_ctrl) {
+		printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
+                iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+		free_irq(card->irq, card);
+		release_region(card->port, AVMB1_PORTLEN);
+	        kfree(card->ctrlinfo);
+		kfree(card->dma);
+		kfree(card);
+		return -EBUSY;
+	}
+	card->cardnr = cinfo->capi_ctrl->cnr;
+
+	skb_queue_head_init(&card->dma->send_queue);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver t1pci_driver = {
+    "t1pci",
+    "0.0",
+    t1pci_load_firmware,
+    t1pci_reset_ctr,
+    t1pci_remove_ctr,
+    t1pci_register_appl,
+    t1pci_release_appl,
+    t1pci_send_message,
+
+    t1pci_procinfo,
+    t1pci_read_proc,
+    0,	/* use standard driver_read_proc */
+
+    0, /* no add_card function */
+};
+
+#ifdef MODULE
+#define t1pci_init init_module
+void cleanup_module(void);
+#endif
+
+static int ncards = 0;
+
+int t1pci_init(void)
+{
+	struct capi_driver *driver = &t1pci_driver;
+	struct pci_dev *dev = NULL;
+	char *p;
+	int retval;
+
+	if ((p = strchr(revision, ':'))) {
+		strncpy(driver->revision, p + 1, sizeof(driver->revision));
+		p = strchr(driver->revision, '$');
+		*p = 0;
+	}
+
+	printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
+
+        di = attach_capi_driver(driver);
+
+	if (!di) {
+		printk(KERN_ERR "%s: failed to attach capi_driver\n",
+				driver->name);
+		return -EIO;
+	}
+
+#ifdef CONFIG_PCI
+	if (!pci_present()) {
+		printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
+    		detach_capi_driver(driver);
+		return -EIO;
+	}
+
+	while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, dev))) {
+		struct capicardparams param;
+
+		param.port = dev->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK;
+		param.irq = dev->irq;
+		param.membase = dev->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK;
+
+		printk(KERN_INFO
+			"%s: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n",
+			driver->name, param.port, param.irq, param.membase);
+		retval = t1pci_add_card(driver, &param);
+		if (retval != 0) {
+		        printk(KERN_ERR
+			"%s: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n",
+			driver->name, param.port, param.irq, param.membase);
+#ifdef MODULE
+			cleanup_module();
+#endif
+			return retval;
+		}
+		ncards++;
+	}
+	if (ncards) {
+		printk(KERN_INFO "%s: %d T1-PCI card(s) detected\n",
+				driver->name, ncards);
+		return 0;
+	}
+	printk(KERN_ERR "%s: NO T1-PCI card detected\n", driver->name);
+	return -ESRCH;
+#else
+	printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name);
+	return -EIO;
+#endif
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+    detach_capi_driver(&t1pci_driver);
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/eicon/eicon.h linux.14p16/drivers/isdn/eicon/eicon.h
--- linux.vanilla/drivers/isdn/eicon/eicon.h	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/eicon/eicon.h	Wed Dec 15 23:34:37 1999
@@ -1,4 +1,4 @@
-/* $Id: eicon.h,v 1.14 1999/09/08 20:17:31 armin Exp $
+/* $Id: eicon.h,v 1.17 1999/10/26 21:15:33 armin Exp $
  *
  * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
  *
@@ -21,6 +21,17 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: eicon.h,v $
+ * Revision 1.17  1999/10/26 21:15:33  armin
+ * using define for checking phone number len to avoid buffer overflow.
+ *
+ * Revision 1.16  1999/10/08 22:09:33  armin
+ * Some fixes of cards interface handling.
+ * Bugfix of NULL pointer occurence.
+ * Changed a few log outputs.
+ *
+ * Revision 1.15  1999/09/26 14:17:53  armin
+ * Improved debug and log via readstat()
+ *
  * Revision 1.14  1999/09/08 20:17:31  armin
  * Added microchannel patch from Erik Weber.
  *
@@ -126,6 +137,7 @@
 
 #define MAX_HEADER_LEN 10
 
+#define MAX_STATUS_BUFFER	150
 
 /* Struct for adding new cards */
 typedef struct eicon_cdef {
@@ -233,6 +245,7 @@
 #include <linux/delay.h>
 #include <linux/ctype.h>
 
+#include <linux/isdn.h>
 #include <linux/isdnif.h>
 
 
@@ -480,7 +493,6 @@
 
 typedef struct {
 	int	       No;		 /* Channel Number	        */
-	unsigned short callref;          /* Call Reference              */
 	unsigned short fsm_state;        /* Current D-Channel state     */
 	unsigned short eazmask;          /* EAZ-Mask for this Channel   */
 	int		queued;          /* User-Data Bytes in TX queue */
@@ -497,9 +509,13 @@
 	entity		e;		 /* Entity  			*/
 	char		cpn[32];	 /* remember cpn		*/
 	char		oad[32];	 /* remember oad		*/
+	char		dsa[32];	 /* remember dsa		*/
+	char		osa[32];	 /* remember osa		*/
 	unsigned char   cause[2];	 /* Last Cause			*/
 	unsigned char	si1;
 	unsigned char	si2;
+	unsigned char	plan;
+	unsigned char	screen;
 } eicon_chan;
 
 typedef struct {
@@ -535,7 +551,7 @@
 #define EICON_STATE_LISTEN  15
 #define EICON_STATE_WMCONN  16
 
-#define EICON_MAX_QUEUED  8000 /* 2 * maxbuff */
+#define EICON_MAX_QUEUE  2138
 
 #define EICON_LOCK_TX 0
 #define EICON_LOCK_RX 1
@@ -589,6 +605,8 @@
 	struct sk_buff_head sndq;        /* Send-Message queue               */
 	struct sk_buff_head rackq;       /* Req-Ack-Message queue            */
 	struct sk_buff_head sackq;       /* Data-Ack-Message queue           */
+	struct sk_buff_head statq;       /* Status-Message queue             */
+	int statq_entries;
 	u_char *ack_msg;                 /* Ptr to User Data in User skb     */
 	__u16 need_b3ack;                /* Flag: Need ACK for current skb   */
 	struct sk_buff *sbuf;            /* skb which is currently sent      */
@@ -677,6 +695,7 @@
 #endif /* CONFIG_MCA */
 
 extern ulong DebugVar;
+extern void eicon_log(eicon_card * card, int level, const char *fmt, ...);
 
 #endif  /* __KERNEL__ */
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/eicon/eicon_idi.c linux.14p16/drivers/isdn/eicon/eicon_idi.c
--- linux.vanilla/drivers/isdn/eicon/eicon_idi.c	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/eicon/eicon_idi.c	Thu Dec  9 15:34:10 1999
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.c,v 1.18 1999/09/07 12:48:05 armin Exp $
+/* $Id: eicon_idi.c,v 1.24 1999/10/26 21:15:33 armin Exp $
  *
  * ISDN lowlevel-module for Eicon.Diehl active cards.
  *        IDI interface 
@@ -6,6 +6,11 @@
  * Copyright 1998,99 by Armin Schindler (mac@melware.de)
  * Copyright 1999    Cytronics & Melware (info@melware.de)
  *
+ * Thanks to	Deutsche Mailbox Saar-Lor-Lux GmbH
+ *		for sponsoring and testing fax
+ *		capabilities with Diva Server cards.
+ *		(dor@deutschemailbox.de)
+ *
  * 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)
@@ -21,6 +26,26 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: eicon_idi.c,v $
+ * Revision 1.24  1999/10/26 21:15:33  armin
+ * using define for checking phone number len to avoid buffer overflow.
+ *
+ * Revision 1.23  1999/10/11 18:13:25  armin
+ * Added fax capabilities for Eicon Diva Server cards.
+ *
+ * Revision 1.22  1999/10/08 22:09:33  armin
+ * Some fixes of cards interface handling.
+ * Bugfix of NULL pointer occurence.
+ * Changed a few log outputs.
+ *
+ * Revision 1.21  1999/09/26 14:17:53  armin
+ * Improved debug and log via readstat()
+ *
+ * Revision 1.20  1999/09/21 20:35:43  armin
+ * added more error checking.
+ *
+ * Revision 1.19  1999/09/21 20:06:40  armin
+ * Added pointer checks.
+ *
  * Revision 1.18  1999/09/07 12:48:05  armin
  * Prepared for sub-address usage.
  *
@@ -105,7 +130,7 @@
 
 #undef EICON_FULL_SERVICE_OKTETT
 
-char *eicon_idi_revision = "$Revision: 1.18 $";
+char *eicon_idi_revision = "$Revision: 1.24 $";
 
 eicon_manifbuf *manbuf;
 
@@ -289,8 +314,7 @@
 	reqbuf->XBuffer.P[8] = 0;
 	reqbuf->XBuffer.length = l;
 	reqbuf->Reference = 0; /* Sig Entity */
-	if (DebugVar & 8)
-		printk(KERN_DEBUG"idi_req: Ch%d: Call_Res\n", chan->No);
+	eicon_log(NULL, 8, "idi_req: Ch%d: Call_Res\n", chan->No);
    return(0);
 }
 
@@ -306,8 +330,7 @@
         skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
 
         if ((!skb) || (!skb2)) {
-		if (DebugVar & 1)
-                	printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in do_req()\n", chan->No);
+               	eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in do_req()\n", chan->No);
 		if (skb) 
 			dev_kfree_skb(skb);
 		if (skb2) 
@@ -319,8 +342,7 @@
 	chan2->ptr = chan;
 
 	reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
-	if (DebugVar & 8)
-		printk(KERN_DEBUG "idi_req: Ch%d: req %x (%s)\n", chan->No, cmd, (layer)?"Net":"Sig");
+	eicon_log(card, 8, "idi_req: Ch%d: req %x (%s)\n", chan->No, cmd, (layer)?"Net":"Sig");
 	if (layer) cmd |= 0x700;
 	switch(cmd) {
 		case ASSIGN:
@@ -359,8 +381,7 @@
 			idi_put_req(reqbuf, IDI_N_DISC_ACK, 1);
 			break;
 		default:
-			if (DebugVar & 1)
-				printk(KERN_ERR "idi_req: Ch%d: Unknown request\n", chan->No);
+			eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No);
 			dev_kfree_skb(skb);
 			dev_kfree_skb(skb2);
 			return(-1);
@@ -375,8 +396,10 @@
 int
 eicon_idi_listen_req(eicon_card *card, eicon_chan *chan)
 {
-	if (DebugVar & 16)
-		printk(KERN_DEBUG"idi_req: Ch%d: Listen_Req eazmask=0x%x\n",chan->No, chan->eazmask);
+	if ((!card) || (!chan))
+		return 1;
+
+	eicon_log(card, 16, "idi_req: Ch%d: Listen_Req eazmask=0x%x\n",chan->No, chan->eazmask);
 	if (!chan->e.D3Id) {
 		idi_do_req(card, chan, ASSIGN, 0); 
 	}
@@ -430,15 +453,19 @@
 int
 idi_hangup(eicon_card *card, eicon_chan *chan)
 {
+	if ((!card) || (!chan))
+		return 1;
+
 	if ((chan->fsm_state == EICON_STATE_ACTIVE) ||
 	    (chan->fsm_state == EICON_STATE_WMCONN)) {
   		if (chan->e.B2Id) idi_do_req(card, chan, IDI_N_DISC, 1);
 	}
 	if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1);
-	idi_do_req(card, chan, HANGUP, 0);
-	chan->fsm_state = EICON_STATE_NULL;
-	if (DebugVar & 8)
-		printk(KERN_DEBUG"idi_req: Ch%d: Hangup\n", chan->No);
+	if (chan->fsm_state != EICON_STATE_NULL) {
+		idi_do_req(card, chan, HANGUP, 0);
+		chan->fsm_state = EICON_STATE_NULL;
+	}
+	eicon_log(card, 8, "idi_req: Ch%d: Hangup\n", chan->No);
 #ifdef CONFIG_ISDN_TTY_FAX
 	chan->fax = 0;
 #endif
@@ -448,14 +475,16 @@
 int
 idi_connect_res(eicon_card *card, eicon_chan *chan)
 {
+	if ((!card) || (!chan))
+		return 1;
+
 	chan->fsm_state = EICON_STATE_IWAIT;
 	idi_do_req(card, chan, CALL_RES, 0);
 	
 	/* check if old NetID has been removed */
 	if (chan->e.B2Id) {
-		if (DebugVar & 1)
-			printk(KERN_WARNING "idi_err: Ch%d: Old NetID %x was not removed.\n",
-				chan->No, chan->e.B2Id);
+		eicon_log(card, 1, "eicon: Ch%d: old net_id %x still exist, removing.\n",
+			chan->No, chan->e.B2Id);
 		idi_do_req(card, chan, REMOVE, 1);
 	}
 
@@ -478,12 +507,14 @@
 	eicon_REQ *reqbuf;
 	eicon_chan_ptr *chan2;
 
+	if ((!card) || (!chan))
+		return 1;
+
         skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC);
         skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
 
         if ((!skb) || (!skb2)) {
-		if (DebugVar & 1)
-                	printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in connect_req()\n", chan->No);
+               	eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in connect_req()\n", chan->No);
 		if (skb) 
 			dev_kfree_skb(skb);
 		if (skb2) 
@@ -629,8 +660,7 @@
 	skb_queue_tail(&card->sndq, skb2); 
 	eicon_schedule_tx(card);
 
-	if (DebugVar & 8)
-  		printk(KERN_DEBUG"idi_req: Ch%d: Conn_Req %s -> %s\n",chan->No, eazmsn, phone);
+	eicon_log(card, 8, "idi_req: Ch%d: Conn_Req %s -> %s\n",chan->No, eazmsn, phone);
    return(0);
 }
 
@@ -647,9 +677,10 @@
 	__u16 code;
 	isdn_ctrl cmd;
 
-  memset(message, 0, sizeof(idi_ind_message));
+	memset(message, 0, sizeof(idi_ind_message));
+
+	if ((!len) || (!buffer[pos])) return;
 
-  if ((!len) || (!buffer[pos])) return;
   while(pos <= len) {
 	w = buffer[pos++];
 	if (!w) return;
@@ -679,8 +710,18 @@
 		else code = w;
 		code |= (codeset<<8);
 
+		if (pos + wlen > len) {
+			eicon_log(ccard, 1, "idi_err: Ch%d: IElen %d of %x exceeds Ind_Length (+%d)\n", chan->No, 
+					wlen, code, (pos + wlen) - len);
+			return;
+		}
+
 		switch(code) {
 			case OAD:
+				if (wlen > sizeof(message->oad)) {
+					pos += wlen;
+					break;
+				}
 				j = 1;
 				if (wlen) {
 					message->plan = buffer[pos++];
@@ -693,11 +734,14 @@
 				}
 				for(i=0; i < wlen-j; i++) 
 					message->oad[i] = buffer[pos++];
-				if (DebugVar & 2)
-					printk(KERN_DEBUG"idi_inf: Ch%d: OAD=(0x%02x,0x%02x) %s\n", chan->No, 
-						message->plan, message->screen, message->oad);
+				eicon_log(ccard, 2, "idi_inf: Ch%d: OAD=(0x%02x,0x%02x) %s\n", chan->No, 
+					message->plan, message->screen, message->oad);
 				break;
 			case RDN:
+				if (wlen > sizeof(message->rdn)) {
+					pos += wlen;
+					break;
+				}
 				j = 1;
 				if (wlen) {
 					if (!(buffer[pos++] & 0x80)) {
@@ -707,92 +751,116 @@
 				}
 				for(i=0; i < wlen-j; i++) 
 					message->rdn[i] = buffer[pos++];
-				if (DebugVar & 2)
-					printk(KERN_DEBUG"idi_inf: Ch%d: RDN= %s\n", chan->No, 
+				eicon_log(ccard, 2, "idi_inf: Ch%d: RDN= %s\n", chan->No, 
 						message->rdn);
 				break;
 			case CPN:
+				if (wlen > sizeof(message->cpn)) {
+					pos += wlen;
+					break;
+				}
 				for(i=0; i < wlen; i++) 
 					message->cpn[i] = buffer[pos++];
-				if (DebugVar & 2)
-					printk(KERN_DEBUG"idi_inf: Ch%d: CPN=(0x%02x) %s\n", chan->No,
-						(__u8)message->cpn[0], message->cpn + 1);
+				eicon_log(ccard, 2, "idi_inf: Ch%d: CPN=(0x%02x) %s\n", chan->No,
+					(__u8)message->cpn[0], message->cpn + 1);
 				break;
 			case DSA:
+				if (wlen > sizeof(message->dsa)) {
+					pos += wlen;
+					break;
+				}
 				pos += 2;
 				for(i=0; i < wlen-2; i++) 
 					message->dsa[i] = buffer[pos++];
-				if (DebugVar & 2)
-					printk(KERN_DEBUG"idi_inf: Ch%d: DSA=%s\n", chan->No, message->dsa);
+				eicon_log(ccard, 2, "idi_inf: Ch%d: DSA=%s\n", chan->No, message->dsa);
 				break;
 			case OSA:
+				if (wlen > sizeof(message->osa)) {
+					pos += wlen;
+					break;
+				}
 				pos += 2;
 				for(i=0; i < wlen-2; i++) 
 					message->osa[i] = buffer[pos++];
-				if (DebugVar & 2)
-					printk(KERN_DEBUG"idi_inf: Ch%d: OSA=%s\n", chan->No, message->osa);
+				eicon_log(ccard, 2, "idi_inf: Ch%d: OSA=%s\n", chan->No, message->osa);
 				break;
 			case BC:
+				if (wlen > sizeof(message->bc)) {
+					pos += wlen;
+					break;
+				}
 				for(i=0; i < wlen; i++) 
 					message->bc[i] = buffer[pos++];
-				if (DebugVar & 4)
-					printk(KERN_DEBUG"idi_inf: Ch%d: BC = 0x%02x 0x%02x 0x%02x\n", chan->No,
-						message->bc[0],message->bc[1],message->bc[2]);
+				eicon_log(ccard, 4, "idi_inf: Ch%d: BC = 0x%02x 0x%02x 0x%02x\n", chan->No,
+					message->bc[0],message->bc[1],message->bc[2]);
 				break;
 			case 0x800|BC:
+				if (wlen > sizeof(message->e_bc)) {
+					pos += wlen;
+					break;
+				}
 				for(i=0; i < wlen; i++) 
 					message->e_bc[i] = buffer[pos++];
-				if (DebugVar & 4)
-					printk(KERN_DEBUG"idi_inf: Ch%d: ESC/BC=%d\n", chan->No, message->bc[0]);
+				eicon_log(ccard, 4, "idi_inf: Ch%d: ESC/BC=%d\n", chan->No, message->bc[0]);
 				break;
 			case LLC:
+				if (wlen > sizeof(message->llc)) {
+					pos += wlen;
+					break;
+				}
 				for(i=0; i < wlen; i++) 
 					message->llc[i] = buffer[pos++];
-				if (DebugVar & 4)
-					printk(KERN_DEBUG"idi_inf: Ch%d: LLC=%d %d %d %d\n", chan->No, message->llc[0],
-						message->llc[1],message->llc[2],message->llc[3]);
+				eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d\n", chan->No, message->llc[0],
+					message->llc[1],message->llc[2],message->llc[3]);
 				break;
 			case HLC:
+				if (wlen > sizeof(message->hlc)) {
+					pos += wlen;
+					break;
+				}
 				for(i=0; i < wlen; i++) 
 					message->hlc[i] = buffer[pos++];
-				if (DebugVar & 4)
-					printk(KERN_DEBUG"idi_inf: Ch%d: HLC=%x %x %x %x %x\n", chan->No,
-						message->hlc[0], message->hlc[1],
-						message->hlc[2], message->hlc[3], message->hlc[4]);
+				eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x\n", chan->No,
+					message->hlc[0], message->hlc[1],
+					message->hlc[2], message->hlc[3], message->hlc[4]);
 				break;
 			case DSP:
 			case 0x600|DSP:
+				if (wlen > sizeof(message->display)) {
+					pos += wlen;
+					break;
+				}
 				for(i=0; i < wlen; i++) 
 					message->display[i] = buffer[pos++];
-				if (DebugVar & 4)
-					printk(KERN_DEBUG"idi_inf: Ch%d: Display: %s\n", chan->No,
-						message->display);
+				eicon_log(ccard, 4, "idi_inf: Ch%d: Display: %s\n", chan->No,
+					message->display);
 				break;
 			case 0x600|KEY:
+				if (wlen > sizeof(message->keypad)) {
+					pos += wlen;
+					break;
+				}
 				for(i=0; i < wlen; i++) 
 					message->keypad[i] = buffer[pos++];
-				if (DebugVar & 4)
-					printk(KERN_DEBUG"idi_inf: Ch%d: Keypad: %s\n", chan->No,
-						message->keypad);
+				eicon_log(ccard, 4, "idi_inf: Ch%d: Keypad: %s\n", chan->No,
+					message->keypad);
 				break;
 			case NI:
 			case 0x600|NI:
 				if (wlen) {
-					if (DebugVar & 4) {
-						switch(buffer[pos] & 127) {
-							case 0:
-								printk(KERN_DEBUG"idi_inf: Ch%d: User suspended.\n", chan->No);
-								break;
-							case 1:
-								printk(KERN_DEBUG"idi_inf: Ch%d: User resumed.\n", chan->No);
-								break;
-							case 2:
-								printk(KERN_DEBUG"idi_inf: Ch%d: Bearer service change.\n", chan->No);
-								break;
-							default:
-								printk(KERN_DEBUG"idi_inf: Ch%d: Unknown Notification %x.\n", 
-										chan->No, buffer[pos] & 127);
-						}
+					switch(buffer[pos] & 127) {
+						case 0:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: User suspended.\n", chan->No);
+							break;
+						case 1:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: User resumed.\n", chan->No);
+							break;
+						case 2:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: Bearer service change.\n", chan->No);
+							break;
+						default:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: Unknown Notification %x.\n", 
+									chan->No, buffer[pos] & 127);
 					}
 					pos += wlen;
 				}
@@ -800,80 +868,91 @@
 			case PI:
 			case 0x600|PI:
 				if (wlen > 1) {
-					if (DebugVar & 4) {
-						switch(buffer[pos+1] & 127) {
-							case 1:
-								printk(KERN_DEBUG"idi_inf: Ch%d: Call is not end-to-end ISDN.\n", chan->No);
-								break;
-							case 2:
-								printk(KERN_DEBUG"idi_inf: Ch%d: Destination address is non ISDN.\n", chan->No);
-								break;
-							case 3:
-								printk(KERN_DEBUG"idi_inf: Ch%d: Origination address is non ISDN.\n", chan->No);
-								break;
-							case 4:
-								printk(KERN_DEBUG"idi_inf: Ch%d: Call has returned to the ISDN.\n", chan->No);
-								break;
-							case 5:
-								printk(KERN_DEBUG"idi_inf: Ch%d: Interworking has occurred.\n", chan->No);
-								break;
-							case 8:
-								printk(KERN_DEBUG"idi_inf: Ch%d: In-band information available.\n", chan->No);
-								break;
-							default:
-								printk(KERN_DEBUG"idi_inf: Ch%d: Unknown Progress %x.\n", 
-										chan->No, buffer[pos+1] & 127);
-						}
+					switch(buffer[pos+1] & 127) {
+						case 1:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: Call is not end-to-end ISDN.\n", chan->No);
+							break;
+						case 2:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: Destination address is non ISDN.\n", chan->No);
+							break;
+						case 3:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: Origination address is non ISDN.\n", chan->No);
+							break;
+						case 4:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: Call has returned to the ISDN.\n", chan->No);
+							break;
+						case 5:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: Interworking has occurred.\n", chan->No);
+							break;
+						case 8:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: In-band information available.\n", chan->No);
+							break;
+						default:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: Unknown Progress %x.\n", 
+									chan->No, buffer[pos+1] & 127);
 					}
 				}
 				pos += wlen;
 				break;
 			case CAU:
+				if (wlen > sizeof(message->cau)) {
+					pos += wlen;
+					break;
+				}
 				for(i=0; i < wlen; i++) 
 					message->cau[i] = buffer[pos++];
 				memcpy(&chan->cause, &message->cau, 2);
-				if (DebugVar & 4)
-					printk(KERN_DEBUG"idi_inf: Ch%d: CAU=%d %d\n", chan->No,
-						message->cau[0],message->cau[1]);
+				eicon_log(ccard, 4, "idi_inf: Ch%d: CAU=%d %d\n", chan->No,
+					message->cau[0],message->cau[1]);
 				break;
 			case 0x800|CAU:
+				if (wlen > sizeof(message->e_cau)) {
+					pos += wlen;
+					break;
+				}
 				for(i=0; i < wlen; i++) 
 					message->e_cau[i] = buffer[pos++];
-				if (DebugVar & 4)
-					printk(KERN_DEBUG"idi_inf: Ch%d: ECAU=%d %d\n", chan->No,
-						message->e_cau[0],message->e_cau[1]);
+				eicon_log(ccard, 4, "idi_inf: Ch%d: ECAU=%d %d\n", chan->No,
+					message->e_cau[0],message->e_cau[1]);
 				break;
 			case 0x800|CHI:
+				if (wlen > sizeof(message->e_chi)) {
+					pos += wlen;
+					break;
+				}
 				for(i=0; i < wlen; i++) 
 					message->e_chi[i] = buffer[pos++];
-				if (DebugVar & 4)
-					printk(KERN_DEBUG"idi_inf: Ch%d: ESC/CHI=%d\n", chan->No,
-						message->e_cau[0]);
+				eicon_log(ccard, 4, "idi_inf: Ch%d: ESC/CHI=%d\n", chan->No,
+					message->e_cau[0]);
 				break;
 			case 0x800|0x7a:
 				pos ++;
 				message->e_mt=buffer[pos++];
-				if (DebugVar & 2)
-					printk(KERN_DEBUG"idi_inf: Ch%d: EMT=0x%x\n", chan->No, message->e_mt);
+				eicon_log(ccard, 4, "idi_inf: Ch%d: EMT=0x%x\n", chan->No, message->e_mt);
 				break;
 			case DT:
+				if (wlen > sizeof(message->dt)) {
+					pos += wlen;
+					break;
+				}
 				for(i=0; i < wlen; i++) 
 					message->dt[i] = buffer[pos++];
-				if (DebugVar & 4)
-					printk(KERN_DEBUG"idi_inf: Ch%d: DT: %02d.%02d.%02d %02d:%02d:%02d\n", chan->No,
-						message->dt[2], message->dt[1], message->dt[0],
-						message->dt[3], message->dt[4], message->dt[5]);
+				eicon_log(ccard, 4, "idi_inf: Ch%d: DT: %02d.%02d.%02d %02d:%02d:%02d\n", chan->No,
+					message->dt[2], message->dt[1], message->dt[0],
+					message->dt[3], message->dt[4], message->dt[5]);
 				break;
 			case 0x600|SIN:
+				if (wlen > sizeof(message->sin)) {
+					pos += wlen;
+					break;
+				}
 				for(i=0; i < wlen; i++) 
 					message->sin[i] = buffer[pos++];
-				if (DebugVar & 2)
-					printk(KERN_DEBUG"idi_inf: Ch%d: SIN=%d %d\n", chan->No,
-						message->sin[0],message->sin[1]);
+				eicon_log(ccard, 2, "idi_inf: Ch%d: SIN=%d %d\n", chan->No,
+					message->sin[0],message->sin[1]);
 				break;
 			case 0x600|CPS:
-				if (DebugVar & 2)
-					printk(KERN_DEBUG"idi_inf: Ch%d: Called Party Status in ind\n", chan->No);
+				eicon_log(ccard, 2, "idi_inf: Ch%d: Called Party Status in ind\n", chan->No);
 				pos += wlen;
 				break;
 			case 0x600|CIF:
@@ -881,8 +960,7 @@
 					if (buffer[pos + i] != '0') break;
 				memcpy(&cmd.parm.num, &buffer[pos + i], wlen - i);
 				cmd.parm.num[wlen - i] = 0;
-				if (DebugVar & 2)
-					printk(KERN_DEBUG"idi_inf: Ch%d: CIF=%s\n", chan->No, cmd.parm.num);
+				eicon_log(ccard, 2, "idi_inf: Ch%d: CIF=%s\n", chan->No, cmd.parm.num);
 				pos += wlen;
 				cmd.driver = ccard->myid;
 				cmd.command = ISDN_STAT_CINF;
@@ -890,8 +968,11 @@
 				ccard->interface.statcallb(&cmd);
 				break;
 			case 0x600|DATE:
-				if (DebugVar & 2)
-					printk(KERN_DEBUG"idi_inf: Ch%d: Date in ind\n", chan->No);
+				eicon_log(ccard, 2, "idi_inf: Ch%d: Date in ind\n", chan->No);
+				pos += wlen;
+				break;
+			case 0xa1: 
+				eicon_log(ccard, 2, "idi_inf: Ch%d: Sending Complete in ind.\n", chan->No);
 				pos += wlen;
 				break;
 			case 0xe08: 
@@ -911,8 +992,7 @@
 			case 0x880:
 				/* Managment Information Element */
 				if (!manbuf) {
-					if (DebugVar & 1)
-						printk(KERN_WARNING"idi_err: manbuf not allocated\n");
+					eicon_log(ccard, 1, "idi_err: manbuf not allocated\n");
 				}
 				else {
 					memcpy(&manbuf->data[manbuf->pos], &buffer[pos], wlen);
@@ -924,9 +1004,8 @@
 				break;
 			default:
 				pos += wlen;
-				if (DebugVar & 6)
-					printk(KERN_WARNING"idi_inf: Ch%d: unknown information element 0x%x in ind, len:%x\n", 
-						chan->No, code, wlen);
+				eicon_log(ccard, 6, "idi_inf: Ch%d: unknown information element 0x%x in ind, len:%x\n", 
+					chan->No, code, wlen);
 		}
 	}
   }
@@ -967,110 +1046,1095 @@
 int
 idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer)
 {
+	eicon_t30_s	*t30 = (eicon_t30_s *) buffer;
 
-	/* TODO , code follows */
+	if (!chan->fax) {
+		eicon_log(NULL, 1,"idi_T30: fill_in with NULL fax struct, ERROR\n");
+		return 0;
+	}
+	memset(t30, 0, sizeof(eicon_t30_s));
+	t30->station_id_len = EICON_FAXID_LEN;
+	memcpy(&t30->station_id[0], &chan->fax->id[0], EICON_FAXID_LEN);
+	t30->resolution = chan->fax->resolution;
+	t30->rate = chan->fax->rate + 1;	/* eicon rate starts with 1 */
+	t30->format = T30_FORMAT_SFF;
+	t30->pages_low = 0;
+	t30->pages_high = 0;
+	t30->atf = 1;				/* optimised for AT+F command set */
+	t30->code = 0;
+	t30->feature_bits_low = 0;
+	t30->feature_bits_high = 0;
+	t30->control_bits_low = 0;
+	t30->control_bits_high = 0;
+
+	if (chan->fax->nbc) {
+		/* set compression by DCC value */
+  	  switch(chan->fax->compression) {
+		case (0):	/* 1-D modified */
+			break;
+		case (1):	/* 2-D modified Read */
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
+			t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
+			break;
+		case (2):	/* 2-D uncompressed */
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR;
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
+			t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED;
+			t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
+			break;
+		case (3):	/* 2-D modified Read */
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_T6_CODING;
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR;
+			t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED;
+			t30->feature_bits_low |= T30_FEATURE_BIT_T6_CODING;
+			t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
+			t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
+			break;
+	  }
+	} else {
+		/* set compression to best */
+		t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_T6_CODING;
+		t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
+		t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR;
+		t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED;
+		t30->feature_bits_low |= T30_FEATURE_BIT_T6_CODING;
+		t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
+		t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
+		t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
+	}
+	switch(chan->fax->ecm) {
+		case (0):	/* disable ECM */
+			break;
+		case (1):
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
+			t30->control_bits_low |= T30_CONTROL_BIT_ECM_64_BYTES;
+			t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
+			t30->feature_bits_low |= T30_FEATURE_BIT_ECM_64_BYTES;
+			break;
+		case (2):
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
+			t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
+			break;
+	}
 
-	return(0);
+	if (DebugVar & 128) {
+		char st[40];
+		eicon_log(NULL, 128, "sT30:code = %x\n", t30->code);
+		eicon_log(NULL, 128, "sT30:rate = %x\n", t30->rate);
+		eicon_log(NULL, 128, "sT30:res  = %x\n", t30->resolution);
+		eicon_log(NULL, 128, "sT30:format = %x\n", t30->format);
+		eicon_log(NULL, 128, "sT30:pages_low = %x\n", t30->pages_low);
+		eicon_log(NULL, 128, "sT30:pages_high = %x\n", t30->pages_high);
+		eicon_log(NULL, 128, "sT30:atf  = %x\n", t30->atf);
+		eicon_log(NULL, 128, "sT30:control_bits_low = %x\n", t30->control_bits_low);
+		eicon_log(NULL, 128, "sT30:control_bits_high = %x\n", t30->control_bits_high);
+		eicon_log(NULL, 128, "sT30:feature_bits_low = %x\n", t30->feature_bits_low);
+		eicon_log(NULL, 128, "sT30:feature_bits_high = %x\n", t30->feature_bits_high);
+		//eicon_log(NULL, 128, "sT30:universal_5 = %x\n", t30->universal_5);
+		//eicon_log(NULL, 128, "sT30:universal_6 = %x\n", t30->universal_6);
+		//eicon_log(NULL, 128, "sT30:universal_7 = %x\n", t30->universal_7);
+		eicon_log(NULL, 128, "sT30:station_id_len = %x\n", t30->station_id_len);
+		eicon_log(NULL, 128, "sT30:head_line_len = %x\n", t30->head_line_len);
+		strncpy(st, t30->station_id, t30->station_id_len);
+		st[t30->station_id_len] = 0;
+		eicon_log(NULL, 128, "sT30:station_id = <%s>\n", st);
+	}
+	return(sizeof(eicon_t30_s));
 }
 
 /* send fax struct */
 int
 idi_send_edata(eicon_card *card, eicon_chan *chan)
 {
+	struct sk_buff *skb;
+	struct sk_buff *skb2;
+	eicon_REQ *reqbuf;
+	eicon_chan_ptr *chan2;
 
-	/* TODO , code follows */
+	if ((chan->fsm_state == EICON_STATE_NULL) || (chan->fsm_state == EICON_STATE_LISTEN)) {
+		eicon_log(card, 1, "idi_snd: Ch%d: send edata on state %d !\n", chan->No, chan->fsm_state);
+		return -ENODEV;
+	}
+	eicon_log(card, 128, "idi_snd: Ch%d: edata (fax)\n", chan->No);
+
+	skb = alloc_skb(sizeof(eicon_REQ) + sizeof(eicon_t30_s), GFP_ATOMIC);
+	skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+	if ((!skb) || (!skb2)) {
+		eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_edata()\n", chan->No);
+		if (skb) 
+			dev_kfree_skb(skb);
+		if (skb2) 
+			dev_kfree_skb(skb2);
+		return -ENOMEM;
+	}
 
+	chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+	chan2->ptr = chan;
+
+	reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ));
+
+	reqbuf->Req = IDI_N_EDATA;
+	reqbuf->ReqCh = 0;
+	reqbuf->ReqId = 1;
+
+	reqbuf->XBuffer.length = idi_fill_in_T30(chan, reqbuf->XBuffer.P);
+	reqbuf->Reference = 1; /* Net Entity */
+
+	skb_queue_tail(&chan->e.X, skb);
+	skb_queue_tail(&card->sndq, skb2);
+	eicon_schedule_tx(card);
 	return (0);
 }
 
 void
 idi_parse_edata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int len)
 {
+	eicon_t30_s *p = (eicon_t30_s *)buffer;
+	int i;
 
-	/* TODO , code follows */
+	if (DebugVar & 128) {
+		char st[40];
+		eicon_log(ccard, 128, "rT30:len %d , size %d\n", len, sizeof(eicon_t30_s));
+		eicon_log(ccard, 128, "rT30:code = %x\n", p->code);
+		eicon_log(ccard, 128, "rT30:rate = %x\n", p->rate);
+		eicon_log(ccard, 128, "rT30:res  = %x\n", p->resolution);
+		eicon_log(ccard, 128, "rT30:format = %x\n", p->format);
+		eicon_log(ccard, 128, "rT30:pages_low = %x\n", p->pages_low);
+		eicon_log(ccard, 128, "rT30:pages_high = %x\n", p->pages_high);
+		eicon_log(ccard, 128, "rT30:atf  = %x\n", p->atf);
+		eicon_log(ccard, 128, "rT30:control_bits_low = %x\n", p->control_bits_low);
+		eicon_log(ccard, 128, "rT30:control_bits_high = %x\n", p->control_bits_high);
+		eicon_log(ccard, 128, "rT30:feature_bits_low = %x\n", p->feature_bits_low);
+		eicon_log(ccard, 128, "rT30:feature_bits_high = %x\n", p->feature_bits_high);
+		//eicon_log(ccard, 128, "rT30:universal_5 = %x\n", p->universal_5);
+		//eicon_log(ccard, 128, "rT30:universal_6 = %x\n", p->universal_6);
+		//eicon_log(ccard, 128, "rT30:universal_7 = %x\n", p->universal_7);
+		eicon_log(ccard, 128, "rT30:station_id_len = %x\n", p->station_id_len);
+		eicon_log(ccard, 128, "rT30:head_line_len = %x\n", p->head_line_len);
+		strncpy(st, p->station_id, p->station_id_len);
+		st[p->station_id_len] = 0;
+		eicon_log(ccard, 128, "rT30:station_id = <%s>\n", st);
+	}
+	if (!chan->fax) {
+		eicon_log(ccard, 1, "idi_edata: parse to NULL fax struct, ERROR\n");
+		return;
+	}
+	chan->fax->code = p->code;
+	i = (p->station_id_len < FAXIDLEN) ? p->station_id_len : (FAXIDLEN - 1);
+	memcpy(chan->fax->r_id, p->station_id, i);
+	chan->fax->r_id[i] = 0;
+	chan->fax->r_resolution = p->resolution;
+	chan->fax->r_rate = p->rate - 1;
+	chan->fax->r_binary = 0; /* no binary support */
+	chan->fax->r_width = 0;
+	chan->fax->r_length = 2;
+	chan->fax->r_scantime = 0;
+	chan->fax->r_compression = 0;
+	chan->fax->r_ecm = 0;
+	if (p->feature_bits_low & T30_FEATURE_BIT_2D_CODING) {
+		chan->fax->r_compression = 1;
+		if (p->feature_bits_low & T30_FEATURE_BIT_UNCOMPR_ENABLED) {
+			chan->fax->r_compression = 2;
+		}
+	}
+	if (p->feature_bits_low & T30_FEATURE_BIT_T6_CODING) {
+		chan->fax->r_compression = 3;
+	}
 
+	if (p->feature_bits_low & T30_FEATURE_BIT_ECM) {
+		chan->fax->r_ecm = 2;
+		if (p->feature_bits_low & T30_FEATURE_BIT_ECM_64_BYTES)
+			chan->fax->r_ecm = 1;
+	}
 }
 
 void
 idi_fax_send_header(eicon_card *card, eicon_chan *chan, int header)
 {
+	static __u16 wd2sff[] = {
+		1728, 2048, 2432, 1216, 864
+	};
+	static __u16 ln2sff[2][3] = {
+		{ 1143, 1401, 0 } , { 2287, 2802, 0 }
+	};
+	struct sk_buff *skb;
+	eicon_sff_dochead *doc;
+	eicon_sff_pagehead *page;
+	u_char *docp;
+
+	if (!chan->fax) {
+		eicon_log(card, 1, "idi_fax: send head with NULL fax struct, ERROR\n");
+		return;
+	}
+	if (header == 2) { /* DocHeader + PageHeader */
+		skb = alloc_skb(sizeof(eicon_sff_dochead) + sizeof(eicon_sff_pagehead), GFP_ATOMIC);
+	} else {
+		skb = alloc_skb(sizeof(eicon_sff_pagehead), GFP_ATOMIC);
+	}
+	if (!skb) {
+		eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in fax_send_header()\n", chan->No);
+		return;
+	}
 
-	/* TODO , code follows */
+	if (header == 2) { /* DocHeader + PageHeader */
+		docp = skb_put(skb, sizeof(eicon_sff_dochead) + sizeof(eicon_sff_pagehead));
+		doc = (eicon_sff_dochead *) docp;
+		page = (eicon_sff_pagehead *) (docp + sizeof(eicon_sff_dochead));
+		memset(docp, 0,sizeof(eicon_sff_dochead)  + sizeof(eicon_sff_pagehead));
+		doc->id = 0x66666653;
+		doc->version = 0x01;
+		doc->off1pagehead = sizeof(eicon_sff_dochead);
+	} else {
+		page = (eicon_sff_pagehead *)skb_put(skb, sizeof(eicon_sff_pagehead));
+		memset(page, 0, sizeof(eicon_sff_pagehead));
+	}
 
+	switch(header) {
+		case 1:	/* PageHeaderEnd */
+			page->pageheadid = 254;
+			page->pageheadlen = 0; 
+			break;
+		case 0: /* PageHeader */
+		case 2: /* DocHeader + PageHeader */
+			page->pageheadid = 254;
+			page->pageheadlen = sizeof(eicon_sff_pagehead) - 2;
+			page->resvert = chan->fax->resolution;
+			page->reshoriz = 0; /* always 203 dpi */
+			page->coding = 0; /* always 1D */
+			page->linelength = wd2sff[chan->fax->width];
+			page->pagelength = ln2sff[chan->fax->resolution][chan->fax->length]; 
+			eicon_log(card, 128, "sSFF-Head: linelength = %d\n", page->linelength);
+			eicon_log(card, 128, "sSFF-Head: pagelength = %d\n", page->pagelength);
+			break;
+	}
+	idi_send_data(card, chan, 0, skb, 0);
 }
 
 void
 idi_fax_cmd(eicon_card *card, eicon_chan *chan) 
 {
+	isdn_ctrl cmd;
+
+	if ((!card) || (!chan))
+		return;
+
+	if (!chan->fax) {
+		eicon_log(card, 1, "idi_fax: cmd with NULL fax struct, ERROR\n");
+		return;
+	}
+	switch (chan->fax->code) {
+		case ISDN_TTY_FAX_DT:
+			if (chan->fax->phase == ISDN_FAX_PHASE_B) {
+				idi_send_edata(card, chan);
+				break;
+			}
+			if (chan->fax->phase == ISDN_FAX_PHASE_D) {
+				idi_send_edata(card, chan);
+				break;
+			}
+			break;
+
+		case ISDN_TTY_FAX_DR:
+			if (chan->fax->phase == ISDN_FAX_PHASE_B) {
+				idi_send_edata(card, chan);
+
+				cmd.driver = card->myid;
+				cmd.command = ISDN_STAT_FAXIND;
+				cmd.arg = chan->No;
+				chan->fax->r_code = ISDN_TTY_FAX_CFR;
+				card->interface.statcallb(&cmd);
+
+				cmd.driver = card->myid;
+				cmd.command = ISDN_STAT_FAXIND;
+				cmd.arg = chan->No;
+				chan->fax->r_code = ISDN_TTY_FAX_RID;
+				card->interface.statcallb(&cmd);
+
+				/* telling 1-D compression */
+				chan->fax->r_compression = 0;
+				cmd.driver = card->myid;
+				cmd.command = ISDN_STAT_FAXIND;
+				cmd.arg = chan->No;
+				chan->fax->r_code = ISDN_TTY_FAX_DCS;
+				card->interface.statcallb(&cmd);
 
-	/* TODO , code follows */
+				chan->fax2.NextObject = FAX_OBJECT_DOCU;
+				chan->fax2.PrevObject = FAX_OBJECT_DOCU;
 
+				break;
+			}
+			if (chan->fax->phase == ISDN_FAX_PHASE_D) {
+				idi_send_edata(card, chan);
+				break;
+			}
+			break;
+
+		case ISDN_TTY_FAX_ET:
+				switch(chan->fax->fet) {
+					case 0:
+					case 1:
+						idi_fax_send_header(card, chan, 0);
+						break;
+					case 2:
+						idi_fax_send_header(card, chan, 1);
+						break;
+				}
+			break;
+	}
 }
 
 void
 idi_edata_rcveop(eicon_card *card, eicon_chan *chan)
 {
+	isdn_ctrl cmd;
 
-	/* TODO , code follows */
-
+	if (!chan->fax) {
+		eicon_log(card, 1, "idi_edata: rcveop with NULL fax struct, ERROR\n");
+		return;
+	}
+	cmd.driver = card->myid;
+	cmd.command = ISDN_STAT_FAXIND;
+	cmd.arg = chan->No;
+	chan->fax->r_code = ISDN_TTY_FAX_ET;
+	card->interface.statcallb(&cmd);
 }
 
 void
 idi_reset_fax_stat(eicon_chan *chan)
 {
-
-	/* TODO , code follows */
-
+	chan->fax2.LineLen = 0;
+	chan->fax2.LineData = 0;
+	chan->fax2.LineDataLen = 0;
+	chan->fax2.NullByteExist = 0;
+	chan->fax2.Dle = 0;
+	chan->fax2.PageCount = 0;
+	chan->fax2.Eop = 0;
 }
 
 void
 idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len)
 {
+	isdn_ctrl cmd;
+
+	if (!chan->fax) {
+		eicon_log(ccard, 1, "idi_edata: action with NULL fax struct, ERROR\n");
+		return;
+	}
+	if (chan->fax->direction == ISDN_TTY_FAX_CONN_OUT) {
+		idi_parse_edata(ccard, chan, buffer, len);
+
+		if (chan->fax->phase == ISDN_FAX_PHASE_A) {
+			idi_reset_fax_stat(chan);
+
+			chan->fsm_state = EICON_STATE_ACTIVE;
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_BCONN;
+			cmd.arg = chan->No;
+			ccard->interface.statcallb(&cmd);
+
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_FAXIND;
+			cmd.arg = chan->No;
+			chan->fax->r_code = ISDN_TTY_FAX_FCON;
+			ccard->interface.statcallb(&cmd);
+
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_FAXIND;
+			cmd.arg = chan->No;
+			chan->fax->r_code = ISDN_TTY_FAX_RID;
+			ccard->interface.statcallb(&cmd);
+
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_FAXIND;
+			cmd.arg = chan->No;
+			chan->fax->r_code = ISDN_TTY_FAX_DIS;
+			ccard->interface.statcallb(&cmd);
+
+			if (chan->fax->r_compression != 0) {
+			/* telling fake compression in second DIS message */
+				chan->fax->r_compression = 0;
+				cmd.driver = ccard->myid;
+				cmd.command = ISDN_STAT_FAXIND;
+				cmd.arg = chan->No;
+				chan->fax->r_code = ISDN_TTY_FAX_DIS;
+				ccard->interface.statcallb(&cmd);
+			}
+
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_FAXIND;
+			cmd.arg = chan->No;
+			chan->fax->r_code = ISDN_TTY_FAX_SENT; /* OK message */
+			ccard->interface.statcallb(&cmd);
+		} else
+		if (chan->fax->phase == ISDN_FAX_PHASE_D) {
 
-	/* TODO , code follows */
+			if ((chan->fax->code == EDATA_T30_MCF) &&
+			    (chan->fax->fet != 2)) {
+				cmd.driver = ccard->myid;
+				cmd.command = ISDN_STAT_FAXIND;
+				cmd.arg = chan->No;
+				chan->fax->r_code = ISDN_TTY_FAX_PTS;
+				ccard->interface.statcallb(&cmd);
+			}
 
+			switch(chan->fax->fet) {
+				case 0:	/* new page */
+					/* stay in phase D , wait on cmd +FDT */
+					break;
+				case 1:	/* new document */
+					/* link-level switch to phase B */
+					break;
+				case 2:	/* session end */
+				default:
+					/* idi_send_edata(ccard, chan); */
+					break;
+			}
+		}
+	}
+
+	if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) {
+		idi_parse_edata(ccard, chan, buffer, len);
+
+		if ((chan->fax->code == EDATA_T30_DCS) &&
+		    (chan->fax->phase == ISDN_FAX_PHASE_A)) {
+			idi_reset_fax_stat(chan);
+
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_BCONN;
+			cmd.arg = chan->No;
+			ccard->interface.statcallb(&cmd);
+
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_FAXIND;
+			cmd.arg = chan->No;
+			chan->fax->r_code = ISDN_TTY_FAX_FCON_I;
+			ccard->interface.statcallb(&cmd);
+		} else
+		if ((chan->fax->code == EDATA_T30_TRAIN_OK) &&
+		    (chan->fax->phase == ISDN_FAX_PHASE_A)) {
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_FAXIND;
+			cmd.arg = chan->No;
+			chan->fax->r_code = ISDN_TTY_FAX_RID;
+			ccard->interface.statcallb(&cmd);
+
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_FAXIND;
+			cmd.arg = chan->No;
+			chan->fax->r_code = ISDN_TTY_FAX_TRAIN_OK;
+			ccard->interface.statcallb(&cmd);
+		} else
+		if ((chan->fax->code == EDATA_T30_TRAIN_OK) &&
+		    (chan->fax->phase == ISDN_FAX_PHASE_B)) {
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_FAXIND;
+			cmd.arg = chan->No;
+			chan->fax->r_code = ISDN_TTY_FAX_TRAIN_OK;
+			ccard->interface.statcallb(&cmd);
+		} else
+		if (chan->fax->phase == ISDN_FAX_PHASE_C) {
+			switch(chan->fax->code) {
+				case EDATA_T30_TRAIN_OK:
+					idi_send_edata(ccard, chan);
+					break;
+				case EDATA_T30_MPS:
+					chan->fax->fet = 0;
+					idi_edata_rcveop(ccard, chan);
+					break;
+				case EDATA_T30_EOM:
+					chan->fax->fet = 1;
+					idi_edata_rcveop(ccard, chan);
+					break;
+				case EDATA_T30_EOP:
+					chan->fax->fet = 2;
+					idi_edata_rcveop(ccard, chan);
+					break;
+			}
+		}
+	}
 }
 
 void
 fax_put_rcv(eicon_card *ccard, eicon_chan *chan, u_char *Data, int len)
 {
-
-	/* TODO , code follows */
-
+	struct sk_buff *skb;
+	
+        skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC);
+	if (!skb) {
+		eicon_log(ccard, 1, "idi_err: Ch%d: alloc_skb failed in fax_put_rcv()\n", chan->No);
+		return;
+	}
+	skb_reserve(skb, MAX_HEADER_LEN);
+	memcpy(skb_put(skb, len), Data, len);
+	ccard->interface.rcvcallb_skb(ccard->myid, chan->No, skb);
 }
 
 void
 idi_faxdata_rcv(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb)
 {
+	eicon_OBJBUFFER InBuf;
+	eicon_OBJBUFFER LineBuf;
+	unsigned int Length = 0;
+	unsigned int aLength = 0;
+	unsigned int ObjectSize = 0;
+	unsigned int ObjHeadLen = 0;
+	unsigned int ObjDataLen = 0;
+	__u8 Recordtype;
+	__u8 PageHeaderLen;	
+	__u8 Event;
+	eicon_sff_pagehead *ob_page;
+
+	__u16 Cl2Eol = 0x8000;
+
+#	define EVENT_NONE	0
+#	define EVENT_NEEDDATA	1
+
+	if (!chan->fax) {
+		eicon_log(ccard, 1, "idi_fax: rcvdata with NULL fax struct, ERROR\n");
+		return;
+	}
+
+
+	
+	if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) {
+		InBuf.Data = skb->data;
+		InBuf.Size = skb->len;
+		InBuf.Len  = 0;
+		InBuf.Next = InBuf.Data;
+		LineBuf.Data = chan->fax2.abLine;
+		LineBuf.Size = sizeof(chan->fax2.abLine);
+		LineBuf.Len  = chan->fax2.LineLen;
+		LineBuf.Next = LineBuf.Data + LineBuf.Len;
+
+		Event = EVENT_NONE;
+		while (Event == EVENT_NONE) {
+			switch(chan->fax2.NextObject) {
+				case FAX_OBJECT_DOCU:
+						Length = LineBuf.Len + (InBuf.Size - InBuf.Len);
+						if (Length < sizeof(eicon_sff_dochead)) {
+							Event = EVENT_NEEDDATA;
+							break;
+						}
+						ObjectSize = sizeof(eicon_sff_dochead);
+						Length = ObjectSize;
+						if (LineBuf.Len < Length) {
+							Length -= LineBuf.Len;
+							LineBuf.Len = 0;
+							LineBuf.Next = LineBuf.Data;
+							InBuf.Len += Length;
+							InBuf.Next += Length;
+						} else {
+							LineBuf.Len -= Length;
+							LineBuf.Next = LineBuf.Data + LineBuf.Len;
+							memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len);
+						}
+						chan->fax2.PrevObject = FAX_OBJECT_DOCU;
+						chan->fax2.NextObject = FAX_OBJECT_PAGE;
+					break;
+
+				case FAX_OBJECT_PAGE:
+						Length = LineBuf.Len + (InBuf.Size - InBuf.Len);
+						if (Length < 2) {
+							Event = EVENT_NEEDDATA;
+							break;
+						}
+						if (LineBuf.Len == 0) {
+							*LineBuf.Next++ = *InBuf.Next++;
+							LineBuf.Len++;
+							InBuf.Len++;
+						}
+						if (LineBuf.Len == 1) {
+							*LineBuf.Next++ = *InBuf.Next++;
+							LineBuf.Len++;
+							InBuf.Len++;
+						}
+						PageHeaderLen = *(LineBuf.Data + 1);
+						ObjectSize = (PageHeaderLen == 0) ? 2 : sizeof(eicon_sff_pagehead);
+						if (Length < ObjectSize) {
+							Event = EVENT_NEEDDATA;
+							break;
+						}
+						Length = ObjectSize;
+						/* extract page dimensions */
+						if (LineBuf.Len < Length) {
+							aLength = Length - LineBuf.Len;
+							memcpy(LineBuf.Next, InBuf.Next, aLength);
+							LineBuf.Next += aLength;
+							InBuf.Next += aLength;
+							LineBuf.Len += aLength;
+							InBuf.Len += aLength;
+						}
+						if (Length > 2) {
+							ob_page = (eicon_sff_pagehead *)LineBuf.Data;
+							switch(ob_page->linelength) {
+								case 2048:
+									chan->fax->r_width = 1;
+									break;
+								case 2432:
+									chan->fax->r_width = 2;
+									break;
+								case 1216:
+									chan->fax->r_width = 3;
+									break;
+								case 864:
+									chan->fax->r_width = 4;
+									break;
+								case 1728:
+								default:
+									chan->fax->r_width = 0;
+							}
+							switch(ob_page->pagelength) {
+								case 1143:
+								case 2287:
+									chan->fax->r_length = 0;
+									break;
+								case 1401:
+								case 2802:
+									chan->fax->r_length = 1;
+									break;
+								default:
+									chan->fax->r_length = 2;
+							}
+							eicon_log(ccard, 128, "rSFF-Head: linelength = %d\n", ob_page->linelength);
+							eicon_log(ccard, 128, "rSFF-Head: pagelength = %d\n", ob_page->pagelength);
+						}
+						LineBuf.Len -= Length;
+						LineBuf.Next = LineBuf.Data + LineBuf.Len;
+						memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len);
+
+						chan->fax2.PrevObject = FAX_OBJECT_PAGE;
+						chan->fax2.NextObject = FAX_OBJECT_LINE;
+					break;
 
-	/* TODO , code follows */
+				case FAX_OBJECT_LINE:
+						Length = LineBuf.Len + (InBuf.Size - InBuf.Len);
+						if (Length < 1) {
+							Event = EVENT_NEEDDATA;
+							break;
+						}
+						if (LineBuf.Len == 0) {
+							*LineBuf.Next++ = *InBuf.Next++;
+							LineBuf.Len++;
+							InBuf.Len++;
+						}
+						Recordtype = *LineBuf.Data;
+						if (Recordtype == 0) {
+							/* recordtype pixel row (2 byte length) */
+							ObjHeadLen = 3;
+							if (Length < ObjHeadLen) {
+								Event = EVENT_NEEDDATA;
+								break;
+							}
+							while (LineBuf.Len < ObjHeadLen) {
+								*LineBuf.Next++ = *InBuf.Next++;
+								LineBuf.Len++;
+								InBuf.Len++;
+							}
+							ObjDataLen = *((__u16*) (LineBuf.Data + 1));
+							ObjectSize = ObjHeadLen + ObjDataLen;
+							if (Length < ObjectSize) {
+								Event = EVENT_NEEDDATA;
+								break;
+							}
+						} else
+						if ((Recordtype >= 1) && (Recordtype <= 216)) {
+							/* recordtype pixel row (1 byte length) */
+							ObjHeadLen = 1;
+							ObjDataLen = Recordtype;
+							ObjectSize = ObjHeadLen + ObjDataLen;
+							if (Length < ObjectSize) {
+								Event = EVENT_NEEDDATA;
+								break;
+							}
+						} else
+						if ((Recordtype >= 217) && (Recordtype <= 253)) {
+							/* recordtype empty lines */
+							ObjHeadLen = 1;
+							ObjDataLen = 0;
+							ObjectSize = ObjHeadLen + ObjDataLen;
+							LineBuf.Len--;
+							LineBuf.Next = LineBuf.Data + LineBuf.Len;
+							memmove(LineBuf.Data, LineBuf.Data + 1, LineBuf.Len);
+							break;
+						} else
+						if (Recordtype == 254) {
+							/* recordtype page header */
+							chan->fax2.PrevObject = FAX_OBJECT_LINE;
+							chan->fax2.NextObject = FAX_OBJECT_PAGE;
+							break;
+						} else {
+							/* recordtype user information */
+							ObjHeadLen = 2;
+							if (Length < ObjHeadLen) {
+								Event = EVENT_NEEDDATA;
+								break;
+							}
+							while (LineBuf.Len < ObjHeadLen) {
+								*LineBuf.Next++ = *InBuf.Next++;
+								LineBuf.Len++;
+								InBuf.Len++;
+							}
+							ObjDataLen = *(LineBuf.Data + 1);
+							ObjectSize = ObjHeadLen + ObjDataLen;
+							if (ObjDataLen == 0) {
+								/* illegal line coding */
+								LineBuf.Len -= ObjHeadLen;
+								LineBuf.Next = LineBuf.Data + LineBuf.Len;
+								memmove(LineBuf.Data, LineBuf.Data + ObjHeadLen, LineBuf.Len);
+								break;
+							} else {
+								/* user information */
+								if (Length < ObjectSize) {
+									Event = EVENT_NEEDDATA;
+									break;
+								}
+								Length = ObjectSize;
+								if (LineBuf.Len < Length) {
+									Length -= LineBuf.Len;
+									LineBuf.Len = 0;
+									LineBuf.Next = LineBuf.Data;
+									InBuf.Len += Length;
+									InBuf.Next += Length;
+								} else {
+									LineBuf.Len -= Length;
+									LineBuf.Next = LineBuf.Data + LineBuf.Len;
+									memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len);
+								}
+							}
+							break;	
+						}
+						Length = ObjectSize;
+						if (LineBuf.Len > ObjHeadLen) {
+							fax_put_rcv(ccard, chan, LineBuf.Data + ObjHeadLen,
+									(LineBuf.Len - ObjHeadLen));
+						}
+						Length -= LineBuf.Len;
+						LineBuf.Len = 0;
+						LineBuf.Next = LineBuf.Data;
+						if (Length > 0) {
+							fax_put_rcv(ccard, chan, InBuf.Next, Length);
+							InBuf.Len += Length;
+							InBuf.Next += Length;
+						}
+						fax_put_rcv(ccard, chan, (__u8 *)&Cl2Eol, sizeof(Cl2Eol));
+					break;
+			} /* end of switch (chan->fax2.NextObject) */
+		} /* end of while (Event==EVENT_NONE) */
+		if (InBuf.Len < InBuf.Size) {
+			Length = InBuf.Size - InBuf.Len;
+			if ((LineBuf.Len + Length) > LineBuf.Size) {
+				eicon_log(ccard, 1, "idi_fax: Ch%d: %d bytes dropping, small buffer\n", chan->No,
+					Length);
+				} else {
+					memcpy(LineBuf.Next, InBuf.Next, Length);
+					LineBuf.Len += Length;
+				}
+		}
+		chan->fax2.LineLen = LineBuf.Len;
+	} else { /* CONN_OUT */
+		/* On CONN_OUT we do not need incoming data, drop it */
+		/* maybe later for polling */
+	}
 
+#	undef EVENT_NONE
+#	undef EVENT_NEEDDATA
+
+	return;
 }
 
 int
 idi_fax_send_outbuf(eicon_card *ccard, eicon_chan *chan, eicon_OBJBUFFER *OutBuf)
 {
+	struct sk_buff *skb;
 
-	/* TODO , code follows */
+	skb = alloc_skb(OutBuf->Len, GFP_ATOMIC);
+	if (!skb) {
+		eicon_log(ccard, 1, "idi_err: Ch%d: alloc_skb failed in fax_send_outbuf()\n", chan->No);
+		return(-1);
+	}
+	memcpy(skb_put(skb, OutBuf->Len), OutBuf->Data, OutBuf->Len);
 
-	return(0);
+	OutBuf->Len = 0;
+	OutBuf->Next = OutBuf->Data;
+
+	return(idi_send_data(ccard, chan, 0, skb, 1));
 }
 
 int
 idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb)
 {
+	isdn_ctrl cmd;
+	eicon_OBJBUFFER InBuf;
+	__u8 InData;
+	__u8 InMask;
+	eicon_OBJBUFFER OutBuf;
+	eicon_OBJBUFFER LineBuf;
+	__u32 LineData;
+	unsigned int LineDataLen;
+	__u8 Byte;
+	__u8 Event;
+	int ret = 1;
+
+#	define EVENT_NONE	0
+#	define EVENT_EOD	1
+#	define EVENT_EOL 	2
+#	define EVENT_EOP 	3
 
-	/* TODO , code follows */
+	if ((!ccard) || (!chan))
+		return -1;
 
-	return(0);
+	if (!chan->fax) {
+		eicon_log(ccard, 1, "idi_fax: senddata with NULL fax struct, ERROR\n");
+		return -1;
+	}
+
+	if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) {
+		/* Simply ignore any data written in data mode when receiving a fax.    */
+		/* This is not completely correct because only XON's should come here.  */
+        	dev_kfree_skb(skb);
+		return 1;
+	}
+
+	if (chan->fax->phase != ISDN_FAX_PHASE_C) {
+        	dev_kfree_skb(skb);
+		return 1;
+	}
+
+        if (chan->queued + skb->len > 1200)
+                return 0;
+
+	InBuf.Data = skb->data;
+	InBuf.Size = skb->len;
+	InBuf.Len  = 0;
+	InBuf.Next = InBuf.Data;
+	InData = 0;
+	InMask = 0;
+
+	LineBuf.Data = chan->fax2.abLine;
+	LineBuf.Size = sizeof(chan->fax2.abLine);
+	LineBuf.Len  = chan->fax2.LineLen;
+	LineBuf.Next = LineBuf.Data + LineBuf.Len;
+	LineData = chan->fax2.LineData;
+	LineDataLen = chan->fax2.LineDataLen;
+
+	OutBuf.Data = chan->fax2.abFrame;
+	OutBuf.Size = sizeof(chan->fax2.abFrame);
+	OutBuf.Len = 0;
+	OutBuf.Next = OutBuf.Data;
+
+	Event = EVENT_NONE;
+
+	chan->fax2.Eop = 0;
+
+	for (;;) {
+	  for (;;) {
+		if (InMask == 0) {
+			if (InBuf.Len >= InBuf.Size) {
+				Event = EVENT_EOD;
+				break;
+			}
+			if ((chan->fax2.Dle != _DLE_) && *InBuf.Next == _DLE_) {
+				chan->fax2.Dle = _DLE_;
+				InBuf.Next++;
+				InBuf.Len++;
+				if (InBuf.Len >= InBuf.Size) {
+					Event = EVENT_EOD;
+					break;
+				}
+			}
+			if (chan->fax2.Dle == _DLE_) {
+				chan->fax2.Dle = 0;
+				if (*InBuf.Next == _ETX_) {
+					Event = EVENT_EOP;
+					break;
+				} else
+				if (*InBuf.Next == _DLE_) {
+					/* do nothing */
+				} else {
+					eicon_log(ccard, 1,
+						"idi_err: Ch%d: unknown DLE escape %02x found\n",
+							chan->No, *InBuf.Next);
+					InBuf.Next++;
+					InBuf.Len++;
+					if (InBuf.Len >= InBuf.Size) {
+						Event = EVENT_EOD;
+						break;
+					}
+				}
+			}
+			InBuf.Len++;
+			InData = *InBuf.Next++;
+			InMask = (chan->fax->bor) ? 0x80 : 0x01;
+		}
+		while (InMask) {
+			LineData >>= 1;
+			LineDataLen++;
+			if (InData & InMask)
+				LineData |= 0x80000000;
+			if (chan->fax->bor)
+				InMask >>= 1;
+			else
+				InMask <<= 1;
+
+			if ((LineDataLen >= T4_EOL_BITSIZE) &&
+			   ((LineData & T4_EOL_MASK_DWORD) == T4_EOL_DWORD)) {
+				Event = EVENT_EOL;
+				if (LineDataLen > T4_EOL_BITSIZE) {
+					Byte = (__u8)
+						((LineData & ~T4_EOL_MASK_DWORD) >>
+						(32 - LineDataLen));
+					if (Byte == 0) {
+						if (! chan->fax2.NullByteExist) {
+							chan->fax2.NullBytesPos = LineBuf.Len;
+							chan->fax2.NullByteExist = 1;
+						}
+					} else {
+						chan->fax2.NullByteExist = 0;
+					}
+					if (LineBuf.Len < LineBuf.Size) {
+						*LineBuf.Next++  = Byte;
+						LineBuf.Len++;
+					}
+				}
+				LineDataLen = 0;
+				break;
+			}
+			if (LineDataLen >= T4_EOL_BITSIZE + 8) {
+				Byte = (__u8)
+					((LineData & ~T4_EOL_MASK_DWORD) >>
+					(32 - T4_EOL_BITSIZE - 8));
+				LineData &= T4_EOL_MASK_DWORD;
+				LineDataLen = T4_EOL_BITSIZE;
+				if (Byte == 0) {
+					if (! chan->fax2.NullByteExist) {
+						chan->fax2.NullBytesPos = LineBuf.Len;
+						chan->fax2.NullByteExist = 1;
+					}
+				} else {
+					chan->fax2.NullByteExist = 0;
+				}
+				if (LineBuf.Len < LineBuf.Size) {
+					*LineBuf.Next++  = Byte; 
+					LineBuf.Len++;
+				}
+			}
+		}
+		if (Event != EVENT_NONE)
+			break;
+	  }
+
+		if ((Event != EVENT_EOL) && (Event != EVENT_EOP))
+			break;
+
+		if ((Event == EVENT_EOP) && (LineDataLen > 0)) {
+			LineData >>= 32 - LineDataLen;
+			LineDataLen = 0;
+			while (LineData != 0) {
+				Byte = (__u8) LineData;
+				LineData >>= 8;
+				if (Byte == 0) {
+					if (! chan->fax2.NullByteExist) {
+						chan->fax2.NullBytesPos = LineBuf.Len;
+						chan->fax2.NullByteExist = 1;
+					}
+				} else {
+					chan->fax2.NullByteExist = 0;
+				}
+				if (LineBuf.Len < LineBuf.Size) {
+					*LineBuf.Next++  = Byte;
+					LineBuf.Len++;
+				}
+				
+			}
+		}
+		if (chan->fax2.NullByteExist) {
+			if (chan->fax2.NullBytesPos == 0) {
+				LineBuf.Len = 0;
+			} else {
+				LineBuf.Len = chan->fax2.NullBytesPos + 1;
+			}
+		}
+		if (LineBuf.Len > 0) {
+			if (OutBuf.Len + LineBuf.Len + SFF_LEN_FLD_SIZE > OutBuf.Size) {
+				ret = idi_fax_send_outbuf(ccard, chan, &OutBuf);
+			}
+			if (LineBuf.Len <= 216) {
+				*OutBuf.Next++ = (__u8) LineBuf.Len;
+				OutBuf.Len++;
+			} else {
+				*OutBuf.Next++ = 0;
+				*((__u16 *) OutBuf.Next)++ = (__u16) LineBuf.Len;
+				OutBuf.Len += 3;
+			}
+			memcpy(OutBuf.Next, LineBuf.Data, LineBuf.Len);
+			OutBuf.Next += LineBuf.Len;
+			OutBuf.Len  += LineBuf.Len;
+		}
+		LineBuf.Len = 0;
+		LineBuf.Next = LineBuf.Data;
+		chan->fax2.NullByteExist = 0;
+		if (Event == EVENT_EOP)
+			break;
+
+		Event = EVENT_NONE;
+	}
+
+	if (Event == EVENT_EOP) {
+		chan->fax2.Eop = 1;
+		chan->fax2.PageCount++;
+		cmd.driver = ccard->myid;
+		cmd.command = ISDN_STAT_FAXIND;
+		cmd.arg = chan->No;
+		chan->fax->r_code = ISDN_TTY_FAX_EOP;
+		ccard->interface.statcallb(&cmd);
+	}
+	if (OutBuf.Len > 0) {
+		ret = idi_fax_send_outbuf(ccard, chan, &OutBuf);
+	}
+
+	chan->fax2.LineLen = LineBuf.Len;
+	chan->fax2.LineData = LineData;
+	chan->fax2.LineDataLen = LineDataLen;
+
+#	undef EVENT_NONE
+#	undef EVENT_EOD
+#	undef EVENT_EOL
+#	undef EVENT_EOP
+
+	if (ret >= 0)
+	        dev_kfree_skb(skb);
+	if (ret == 0)
+		ret = 1;
+	return(ret);
 }
 
 void
 idi_fax_hangup(eicon_card *ccard, eicon_chan *chan)
 {
+	isdn_ctrl cmd;
 
-	/* TODO , code follows */
-
+	if (!chan->fax) {
+		eicon_log(ccard, 1, "idi_fax: hangup with NULL fax struct, ERROR\n");
+		return;
+	}
+	if ((chan->fax->direction == ISDN_TTY_FAX_CONN_OUT) &&
+	    (chan->fax->code == 0)) {
+		cmd.driver = ccard->myid;
+		cmd.command = ISDN_STAT_FAXIND;
+		cmd.arg = chan->No;
+		chan->fax->r_code = ISDN_TTY_FAX_PTS;
+		ccard->interface.statcallb(&cmd);
+	}
+	if ((chan->fax->code > 1) && (chan->fax->code < 120))
+		chan->fax->code += 120;
+	chan->fax->r_code = ISDN_TTY_FAX_HNG;
+	cmd.driver = ccard->myid;
+	cmd.command = ISDN_STAT_FAXIND;
+	cmd.arg = chan->No;
+	ccard->interface.statcallb(&cmd);
 }
 
 #endif	/******** FAX ********/
@@ -1084,20 +2148,17 @@
 	eicon_chan_ptr *chan2;
 
 	if ((chan->fsm_state == EICON_STATE_NULL) || (chan->fsm_state == EICON_STATE_LISTEN)) {
-		if (DebugVar & 1)
-			printk(KERN_DEBUG"idi_snd: Ch%d: send udata on state %d !\n", chan->No, chan->fsm_state);
+		eicon_log(card, 1, "idi_snd: Ch%d: send udata on state %d !\n", chan->No, chan->fsm_state);
 		return -ENODEV;
 	}
-	if (DebugVar & 8)
-		printk(KERN_DEBUG"idi_snd: Ch%d: udata 0x%x: %d %d %d %d\n", chan->No,
-				UReq, buffer[0], buffer[1], buffer[2], buffer[3]);
+	eicon_log(card, 8, "idi_snd: Ch%d: udata 0x%x: %d %d %d %d\n", chan->No,
+			UReq, buffer[0], buffer[1], buffer[2], buffer[3]);
 
 	skb = alloc_skb(sizeof(eicon_REQ) + len + 1, GFP_ATOMIC);
 	skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
 
 	if ((!skb) || (!skb2)) {
-		if (DebugVar & 1)
-			printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in send_udata()\n", chan->No);
+		eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_udata()\n", chan->No);
 		if (skb) 
 			dev_kfree_skb(skb);
 		if (skb2) 
@@ -1131,6 +2192,9 @@
 	u_char buf[6];
 	struct enable_dtmf_s *dtmf_buf = (struct enable_dtmf_s *)buf;
 
+	if ((!ccard) || (!chan))
+		return;
+
 	memset(buf, 0, 6);
 	switch(cmd) {
 		case ISDN_AUDIO_SETDD:
@@ -1162,14 +2226,15 @@
 	'1','4','7','*','2','5','8','0','3','6','9','#','A','B','C','D'
 	};
 
+	if ((!ccard) || (!chan))
+		return;
+
 	switch (buffer[0]) {
 		case DSP_UDATA_INDICATION_SYNC:
-			if (DebugVar & 16)
-  				printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_SYNC time %d\n", chan->No, p->time);
+			eicon_log(ccard, 16, "idi_ind: Ch%d: UDATA_SYNC time %d\n", chan->No, p->time);
 			break;
 		case DSP_UDATA_INDICATION_DCD_OFF:
-			if (DebugVar & 8)
-  				printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DCD_OFF time %d\n", chan->No, p->time);
+			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DCD_OFF time %d\n", chan->No, p->time);
 			break;
 		case DSP_UDATA_INDICATION_DCD_ON:
 			if ((chan->l2prot == ISDN_PROTO_L2_MODEM) &&
@@ -1181,31 +2246,24 @@
 				sprintf(cmd.parm.num, "%d/%s", p->speed, connmsg[p->norm]);
 				ccard->interface.statcallb(&cmd);
 			}
-			if (DebugVar & 8) {
-  				printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DCD_ON time %d\n", chan->No, p->time);
-				printk(KERN_DEBUG"idi_ind: Ch%d: %d %d %d %d\n", chan->No,
-					    p->norm, p->options, p->speed, p->delay); 
-			    }
+			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DCD_ON time %d\n", chan->No, p->time);
+			eicon_log(ccard, 8, "idi_ind: Ch%d: %d %d %d %d\n", chan->No,
+				p->norm, p->options, p->speed, p->delay); 
 			break;
 		case DSP_UDATA_INDICATION_CTS_OFF:
-			if (DebugVar & 8)
-  				printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_CTS_OFF time %d\n", chan->No, p->time);
+			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_CTS_OFF time %d\n", chan->No, p->time);
 			break;
 		case DSP_UDATA_INDICATION_CTS_ON:
-			if (DebugVar & 8) {
-  				printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_CTS_ON time %d\n", chan->No, p->time);
-				printk(KERN_DEBUG"idi_ind: Ch%d: %d %d %d %d\n", chan->No,
-					    p->norm, p->options, p->speed, p->delay); 
-			}
+			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_CTS_ON time %d\n", chan->No, p->time);
+			eicon_log(ccard, 8, "idi_ind: Ch%d: %d %d %d %d\n", chan->No,
+				p->norm, p->options, p->speed, p->delay); 
 			break;
 		case DSP_UDATA_INDICATION_DISCONNECT:
-			if (DebugVar & 8)
-  				printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DISCONNECT cause %d\n", chan->No, buffer[1]);
+			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DISCONNECT cause %d\n", chan->No, buffer[1]);
 			break;
 		case DSP_UDATA_INDICATION_DTMF_DIGITS_RECEIVED:
-			if (DebugVar & 8)
-  				printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DTMF_REC '%c'\n", chan->No,
-					dtmf_code[buffer[1]]);
+			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DTMF_REC '%c'\n", chan->No,
+				dtmf_code[buffer[1]]);
 			cmd.driver = ccard->myid;
 			cmd.command = ISDN_STAT_AUDIO;
 			cmd.parm.num[0] = ISDN_AUDIO_DTMF;
@@ -1214,8 +2272,7 @@
 			ccard->interface.statcallb(&cmd);
 			break;
 		default:
-			if (DebugVar & 8)
-				printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED UDATA Indication 0x%02x\n", chan->No, buffer[0]);
+			eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED UDATA Indication 0x%02x\n", chan->No, buffer[0]);
 	}
 }
 
@@ -1223,23 +2280,35 @@
 idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
 {
 	int tmp;
+	char tnum[64];
+	int dlev;
 	int free_buff;
+	ulong flags;
 	struct sk_buff *skb2;
         eicon_IND *ind = (eicon_IND *)skb->data;
 	eicon_chan *chan;
 	idi_ind_message message;
 	isdn_ctrl cmd;
 
+	if (!ccard) {
+		eicon_log(ccard, 1, "idi_err: Ch??: null card in handle_ind\n");
+  		dev_kfree_skb(skb);
+		return;
+	}
+
 	if ((chan = ccard->IdTable[ind->IndId]) == NULL) {
+		eicon_log(ccard, 1, "idi_err: Ch??: null chan in handle_ind\n");
   		dev_kfree_skb(skb);
 		return;
 	}
 	
-	if ((DebugVar & 128) || 
-	   ((DebugVar & 16) && (ind->Ind != 8))) {
-        	printk(KERN_DEBUG "idi_hdl: Ch%d: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", chan->No,
-		        ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
-	}
+	if (ind->Ind != 8)
+		dlev = 144;
+	else
+		dlev = 128;
+
+       	eicon_log(ccard, dlev, "idi_hdl: Ch%d: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", chan->No,
+	        ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
 
 	free_buff = 1;
 	/* Signal Layer */
@@ -1247,15 +2316,16 @@
 		idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length);
 		switch(ind->Ind) {
 			case HANGUP:
-				if (DebugVar & 8)
-  					printk(KERN_DEBUG"idi_ind: Ch%d: Hangup\n", chan->No);
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Hangup\n", chan->No);
 		                while((skb2 = skb_dequeue(&chan->e.X))) {
 					dev_kfree_skb(skb2);
 				}
-				chan->e.busy = 0;
+				save_flags(flags);
+				cli();
 				chan->queued = 0;
 				chan->waitq = 0;
 				chan->waitpq = 0;
+				restore_flags(flags);
 				if (message.e_cau[0] & 0x7f) {
 					cmd.driver = ccard->myid;
 					cmd.arg = chan->No;
@@ -1269,8 +2339,10 @@
 				if (!chan->e.B2Id)
 					chan->fax = 0;
 #endif
-				if ((chan->fsm_state == EICON_STATE_ACTIVE) ||
-				    (chan->fsm_state == EICON_STATE_WMCONN)) {
+				if (((chan->fsm_state == EICON_STATE_ACTIVE) ||
+				    (chan->fsm_state == EICON_STATE_WMCONN)) ||
+				    ((chan->l2prot == ISDN_PROTO_L2_FAX) &&
+				    (chan->fsm_state == EICON_STATE_OBWAIT))) {
 					chan->fsm_state = EICON_STATE_NULL;
 				} else {
 					if (chan->e.B2Id)
@@ -1284,51 +2356,62 @@
 				}
 				break;
 			case INDICATE_IND:
-				if (DebugVar & 8)
-  					printk(KERN_DEBUG"idi_ind: Ch%d: Indicate_Ind\n", chan->No);
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Indicate_Ind\n", chan->No);
+				if (chan->fsm_state != EICON_STATE_LISTEN) {
+					eicon_log(ccard, 1, "idi_err: Ch%d: Incoming call on wrong state (%d).\n",
+						chan->No, chan->fsm_state);
+					idi_do_req(ccard, chan, HANGUP, 0);
+					break;
+				}
 				chan->fsm_state = EICON_STATE_ICALL;
 				idi_bc2si(message.bc, message.hlc, &chan->si1, &chan->si2);
 				strcpy(chan->cpn, message.cpn + 1);
-				if (strlen(message.dsa)) {
-					strcat(chan->cpn, ".");
-					strcat(chan->cpn, message.dsa);
-				}
 				strcpy(chan->oad, message.oad);
-				if (strlen(message.osa)) {
-					strcat(chan->oad, ".");
-					strcat(chan->oad, message.osa);
-				}
+				strcpy(chan->dsa, message.dsa);
+				strcpy(chan->osa, message.osa);
+				chan->plan = message.plan;
+				chan->screen = message.screen;
 				try_stat_icall_again: 
 				cmd.driver = ccard->myid;
 				cmd.command = ISDN_STAT_ICALL;
 				cmd.arg = chan->No;
 				cmd.parm.setup.si1 = chan->si1;
 				cmd.parm.setup.si2 = chan->si2;
-				strcpy(cmd.parm.setup.eazmsn, chan->cpn);
-				strcpy(cmd.parm.setup.phone, chan->oad);
-				cmd.parm.setup.plan = message.plan;
-				cmd.parm.setup.screen = message.screen;
+				strcpy(tnum, chan->cpn);
+				if (strlen(chan->dsa)) {
+					strcat(tnum, ".");
+					strcat(tnum, chan->dsa);
+				}
+				tnum[ISDN_MSNLEN - 1] = 0;
+				strcpy(cmd.parm.setup.eazmsn, tnum);
+				strcpy(tnum, chan->oad);
+				if (strlen(chan->osa)) {
+					strcat(tnum, ".");
+					strcat(tnum, chan->osa);
+				}
+				tnum[ISDN_MSNLEN - 1] = 0;
+				strcpy(cmd.parm.setup.phone, tnum);
+				cmd.parm.setup.plan = chan->plan;
+				cmd.parm.setup.screen = chan->screen;
 				tmp = ccard->interface.statcallb(&cmd);
 				switch(tmp) {
 					case 0: /* no user responding */
 						idi_do_req(ccard, chan, HANGUP, 0);
+						chan->fsm_state = EICON_STATE_NULL;
 						break;
 					case 1: /* alert */
-						if (DebugVar & 8)
-  							printk(KERN_DEBUG"idi_req: Ch%d: Call Alert\n", chan->No);
+						eicon_log(ccard, 8, "idi_req: Ch%d: Call Alert\n", chan->No);
 						if ((chan->fsm_state == EICON_STATE_ICALL) || (chan->fsm_state == EICON_STATE_ICALLW)) {
 							chan->fsm_state = EICON_STATE_ICALL;
 							idi_do_req(ccard, chan, CALL_ALERT, 0);
 						}
 						break;
 					case 2: /* reject */
-						if (DebugVar & 8)
-  							printk(KERN_DEBUG"idi_req: Ch%d: Call Reject\n", chan->No);
+						eicon_log(ccard, 8, "idi_req: Ch%d: Call Reject\n", chan->No);
 						idi_do_req(ccard, chan, REJECT, 0);
 						break;
 					case 3: /* incomplete number */
-						if (DebugVar & 8)
-  							printk(KERN_DEBUG"idi_req: Ch%d: Incomplete Number\n", chan->No);
+						eicon_log(ccard, 8, "idi_req: Ch%d: Incomplete Number\n", chan->No);
 					        switch(ccard->type) {
 					                case EICON_CTYPE_MAESTRAP:
 					                case EICON_CTYPE_S2M:
@@ -1342,8 +2425,7 @@
 				}
 				break;
 			case INFO_IND:
-				if (DebugVar & 8)
-  					printk(KERN_DEBUG"idi_ind: Ch%d: Info_Ind\n", chan->No);
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Info_Ind\n", chan->No);
 				if ((chan->fsm_state == EICON_STATE_ICALLW) &&
 				    (message.cpn[0])) {
 					strcat(chan->cpn, message.cpn + 1);
@@ -1351,8 +2433,7 @@
 				}
 				break;
 			case CALL_IND:
-				if (DebugVar & 8)
-  					printk(KERN_DEBUG"idi_ind: Ch%d: Call_Ind\n", chan->No);
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Ind\n", chan->No);
 				if ((chan->fsm_state == EICON_STATE_ICALL) || (chan->fsm_state == EICON_STATE_IWAIT)) {
 					chan->fsm_state = EICON_STATE_IBWAIT;
 					cmd.driver = ccard->myid;
@@ -1376,8 +2457,7 @@
 					idi_hangup(ccard, chan);
 				break;
 			case CALL_CON:
-				if (DebugVar & 8)
-  					printk(KERN_DEBUG"idi_ind: Ch%d: Call_Con\n", chan->No);
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No);
 				if (chan->fsm_state == EICON_STATE_OCALL) {
 					chan->fsm_state = EICON_STATE_OBWAIT;
 					cmd.driver = ccard->myid;
@@ -1387,9 +2467,8 @@
 
 					/* check if old NetID has been removed */
 					if (chan->e.B2Id) {
-						if (DebugVar & 1)
-							printk(KERN_WARNING "idi_err: Ch%d: Old NetID %x was not removed.\n",
-								chan->No, chan->e.B2Id);
+						eicon_log(ccard, 1, "eicon: Ch%d: old net_id %x still exist, removing.\n",
+							chan->No, chan->e.B2Id);
 						idi_do_req(ccard, chan, REMOVE, 1);
 					}
 
@@ -1405,12 +2484,10 @@
 				idi_hangup(ccard, chan);
 				break;
 			case AOC_IND:
-				if (DebugVar & 8)
-  					printk(KERN_DEBUG"idi_ind: Ch%d: Advice of Charge\n", chan->No);
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Advice of Charge\n", chan->No);
 				break;
 			default:
-				if (DebugVar & 8)
-					printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind);
+				eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind);
 		}
 	}
 	/* Network Layer */
@@ -1424,8 +2501,7 @@
 		else
 		switch(ind->Ind) {
 			case IDI_N_CONNECT_ACK:
-				if (DebugVar & 16)
-  					printk(KERN_DEBUG"idi_ind: Ch%d: N_Connect_Ack\n", chan->No);
+				eicon_log(ccard, 16, "idi_ind: Ch%d: N_Connect_Ack\n", chan->No);
 				if (chan->l2prot == ISDN_PROTO_L2_MODEM) {
 					chan->fsm_state = EICON_STATE_WMCONN;
 					break;
@@ -1445,8 +2521,7 @@
 						}
 					}
 					else {
-						if (DebugVar & 1)
-							printk(KERN_DEBUG "idi_ind: N_CONNECT_ACK with NULL fax struct, ERROR\n");
+						eicon_log(ccard, 1, "idi_ind: N_CONNECT_ACK with NULL fax struct, ERROR\n");
 					}
 #endif
 					break;
@@ -1458,8 +2533,7 @@
 				ccard->interface.statcallb(&cmd);
 				break; 
 			case IDI_N_CONNECT:
-				if (DebugVar & 16)
-  					printk(KERN_DEBUG"idi_ind: Ch%d: N_Connect\n", chan->No);
+				eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No);
 				if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1);
 				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
 					break;
@@ -1475,9 +2549,11 @@
 				ccard->interface.statcallb(&cmd);
 				break; 
 			case IDI_N_DISC:
-				if (DebugVar & 16)
-  					printk(KERN_DEBUG"idi_ind: Ch%d: N_DISC\n", chan->No);
+				eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC\n", chan->No);
 				if (chan->e.B2Id) {
+		                	while((skb2 = skb_dequeue(&chan->e.X))) {
+						dev_kfree_skb(skb2);
+					}
 					idi_do_req(ccard, chan, IDI_N_DISC_ACK, 1);
 					idi_do_req(ccard, chan, REMOVE, 1);
 				}
@@ -1487,9 +2563,12 @@
 					idi_fax_hangup(ccard, chan);
 				}
 #endif
+				save_flags(flags);
+				cli();
 				chan->queued = 0;
 				chan->waitq = 0;
 				chan->waitpq = 0;
+				restore_flags(flags);
 				idi_do_req(ccard, chan, HANGUP, 0);
 				if (chan->fsm_state == EICON_STATE_ACTIVE) {
 					cmd.driver = ccard->myid;
@@ -1503,8 +2582,7 @@
 #endif
 				break; 
 			case IDI_N_DISC_ACK:
-				if (DebugVar & 16)
-  					printk(KERN_DEBUG"idi_ind: Ch%d: N_DISC_ACK\n", chan->No);
+				eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC_ACK\n", chan->No);
 #ifdef CONFIG_ISDN_TTY_FAX
 				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
 					idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
@@ -1513,13 +2591,11 @@
 #endif
 				break; 
 			case IDI_N_DATA_ACK:
-				if (DebugVar & 16)
-  					printk(KERN_DEBUG"idi_ind: Ch%d: N_DATA_ACK\n", chan->No);
+				eicon_log(ccard, 16, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No);
 				break;
 			case IDI_N_DATA:
 				skb_pull(skb, sizeof(eicon_IND) - 1);
-				if (DebugVar & 128)
-					printk(KERN_DEBUG"idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len);
+				eicon_log(ccard, 128, "idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len);
 				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
 #ifdef CONFIG_ISDN_TTY_FAX
 					idi_faxdata_rcv(ccard, chan, skb);
@@ -1538,27 +2614,26 @@
 				break; 
 #endif
 			default:
-				if (DebugVar & 8)
-					printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED NetIndication 0x%02x\n", chan->No, ind->Ind);
+				eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED NetIndication 0x%02x\n", chan->No, ind->Ind);
 		}
 	}
 	else {
-		if (DebugVar & 1)
-			printk(KERN_ERR "idi_ind: Ch%d: Ind is neither SIG nor NET !\n", chan->No);
+		eicon_log(ccard, 1, "idi_ind: Ch%d: Ind is neither SIG nor NET !\n", chan->No);
 	}
-   if (free_buff) dev_kfree_skb(skb);
+   if (free_buff)
+	dev_kfree_skb(skb);
 }
 
 int
 idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
 {
+	ulong flags;
 	isdn_ctrl cmd;
 
 	if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) {
 		/* I dont know why this happens, just ignoring this RC */
-		if (DebugVar & 16)
-			printk(KERN_DEBUG "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No, 
-				ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id);
+		eicon_log(ccard, 16, "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No, 
+			ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id);
 		return 1;
 	}
 
@@ -1572,27 +2647,27 @@
 	/* Remove an Id */
 	if (chan->e.Req == REMOVE) {
 		if (ack->Reference != chan->e.ref) {
-			if (DebugVar & 16)
-				printk(KERN_DEBUG "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
-					ack->Reference, chan->e.ref);
+			eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
+				ack->Reference, chan->e.ref);
 			return 0;
 		}
+		save_flags(flags);
+		cli();
 		ccard->IdTable[ack->RcId] = NULL;
-		if (DebugVar & 16)
-			printk(KERN_DEBUG "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No,
-				ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
+		eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No,
+			ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
 		if (!chan->e.ReqCh) 
 			chan->e.D3Id = 0;
 		else
 			chan->e.B2Id = 0;
+		restore_flags(flags);
 		return 1;
 	}
 
 	/* Signal layer */
 	if (!chan->e.ReqCh) {
-		if (DebugVar & 16)
-			printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
-				ack->RcId, ack->RcCh, ack->Reference);
+		eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
+			ack->RcId, ack->RcCh, ack->Reference);
 	} else {
 	/* Network layer */
 		switch(chan->e.Req & 0x0f) {
@@ -1606,7 +2681,10 @@
 						cmd.parm.length = chan->waitpq;
 						ccard->interface.statcallb(&cmd);
 					}
+					save_flags(flags);
+					cli();
 					chan->waitpq = 0;
+					restore_flags(flags);
 #ifdef CONFIG_ISDN_TTY_FAX
 					if (chan->l2prot == ISDN_PROTO_L2_FAX) {
 						if (((chan->queued - chan->waitq) < 1) &&
@@ -1620,20 +2698,21 @@
 								ccard->interface.statcallb(&cmd);
 							}
 							else {
-								if (DebugVar & 1)
-									printk(KERN_DEBUG "idi_ack: Sent with NULL fax struct, ERROR\n");
+								eicon_log(ccard, 1, "idi_ack: Sent with NULL fax struct, ERROR\n");
 							}
 						}
 					}
 #endif
 				}
+				save_flags(flags);
+				cli();
 				chan->queued -= chan->waitq;
 				if (chan->queued < 0) chan->queued = 0;
+				restore_flags(flags);
 				break;
 			default:
-				if (DebugVar & 16)
-					printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
-						ack->RcId, ack->RcCh, ack->Reference);
+				eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
+					ack->RcId, ack->RcCh, ack->Reference);
 		}
 	}
 	return 1;
@@ -1643,22 +2722,30 @@
 idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
 {
 	int j;
+	ulong flags;
         eicon_RC *ack = (eicon_RC *)skb->data;
 	eicon_chan *chan;
 	isdn_ctrl cmd;
 	int dCh = -1;
 
+	if (!ccard) {
+		eicon_log(ccard, 1, "idi_err: Ch??: null card in handle_ack\n");
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	save_flags(flags);
+	cli();
 	if ((chan = ccard->IdTable[ack->RcId]) != NULL)
 		dCh = chan->No;
-	
+	restore_flags(flags);
 
 	switch (ack->Rc) {
 		case OK_FC:
 		case N_FLOW_CONTROL:
 		case ASSIGN_RC:
-			if (DebugVar & 1)
-				printk(KERN_ERR "idi_ack: Ch%d: unhandled RC 0x%x\n",
-					dCh, ack->Rc);
+			eicon_log(ccard, 1, "idi_ack: Ch%d: unhandled RC 0x%x\n",
+				dCh, ack->Rc);
 			break;
 		case READY_INT:
 		case TIMER_INT:
@@ -1667,8 +2754,7 @@
 
 		case OK:
 			if (!chan) {
-				if (DebugVar & 1)
-					printk(KERN_ERR "idi_ack: Ch%d: OK on chan without Id\n", dCh);
+				eicon_log(ccard, 1, "idi_ack: Ch%d: OK on chan without Id\n", dCh);
 				break;
 			}
 			if (!idi_handle_ack_ok(ccard, chan, ack))
@@ -1677,29 +2763,29 @@
 
 		case ASSIGN_OK:
 			if (chan) {
-				if (DebugVar & 1)
-					printk(KERN_ERR "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n",
-						chan->No, chan->e.D3Id, chan->e.B2Id);
+				eicon_log(ccard, 1, "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n",
+					chan->No, chan->e.D3Id, chan->e.B2Id);
 			}
+			save_flags(flags);
+			cli();
 			for(j = 0; j < ccard->nchannels + 1; j++) {
-				if (ccard->bch[j].e.ref == ack->Reference) {
+				if ((ccard->bch[j].e.ref == ack->Reference) &&
+					(ccard->bch[j].e.Req == ASSIGN)) {
 					if (!ccard->bch[j].e.ReqCh) 
 						ccard->bch[j].e.D3Id  = ack->RcId;
 					else
 						ccard->bch[j].e.B2Id  = ack->RcId;
 					ccard->IdTable[ack->RcId] = &ccard->bch[j];
-					ccard->bch[j].e.busy = 0;
-					ccard->bch[j].e.ref = 0;
-					if (DebugVar & 16)
-						printk(KERN_DEBUG"idi_ack: Ch%d: Id %x assigned (%s)\n", j, 
-							ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
+					chan = &ccard->bch[j];
+					eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, 
+						ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
 					break;
 				}
 			}		
+			restore_flags(flags);
 			if (j > ccard->nchannels) {
-				if (DebugVar & 24)
-					printk(KERN_DEBUG"idi_ack: Ch??: ref %d not found for Id %d\n", 
-						ack->Reference, ack->RcId);
+				eicon_log(ccard, 24, "idi_ack: Ch??: ref %d not found for Id %d\n", 
+					ack->Reference, ack->RcId);
 			}
 			break;
 
@@ -1711,9 +2797,19 @@
 		case UNKNOWN_IE:
 		case WRONG_IE:
 		default:
-			if (DebugVar & 1)
-				printk(KERN_ERR "eicon_ack: Ch%d: Not OK !!: Rc=%d Id=%x Ch=%d\n", dCh, 
-					ack->Rc, ack->RcId, ack->RcCh);
+			if (!chan) {
+				eicon_log(ccard, 1, "idi_ack: Ch%d: Not OK !! on chan without Id\n", dCh);
+				break;
+			} else
+			switch (chan->e.Req) {
+				case 12:	/* Alert */
+					eicon_log(ccard, 2, "eicon_err: Ch%d: Alert Not OK : Rc=%d Id=%x Ch=%d\n",
+						dCh, ack->Rc, ack->RcId, ack->RcCh);
+					break;
+				default:
+					eicon_log(ccard, 1, "eicon_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n",
+						dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req);
+			}
 			if (dCh == ccard->nchannels) { /* Management */
 				chan->fsm_state = 2;
 			} else if (dCh >= 0) {
@@ -1726,8 +2822,13 @@
 				ccard->interface.statcallb(&cmd);
 			}
 	}
-	if (chan)
+	save_flags(flags);
+	cli();
+	if (chan) {
+		chan->e.ref = 0;
 		chan->e.busy = 0;
+	}
+	restore_flags(flags);
 	dev_kfree_skb(skb);
 	eicon_schedule_tx(ccard);
 }
@@ -1742,21 +2843,25 @@
         int len, plen = 0, offset = 0;
 	unsigned long flags;
 
+	if ((!card) || (!chan)) {
+		eicon_log(card, 1, "idi_err: Ch??: null card/chan in send_data\n");
+		return -1;
+	}
+
         if (chan->fsm_state != EICON_STATE_ACTIVE) {
-		if (DebugVar & 1)
-			printk(KERN_DEBUG"idi_snd: Ch%d: send bytes on state %d !\n", chan->No, chan->fsm_state);
+		eicon_log(card, 1, "idi_snd: Ch%d: send bytes on state %d !\n", chan->No, chan->fsm_state);
                 return -ENODEV;
 	}
 
         len = skb->len;
-	if (len > 2138)	/* too much for the shared memory */
+	if (len > EICON_MAX_QUEUE)	/* too much for the shared memory */
 		return -1;
         if (!len)
                 return 0;
-	if (chan->queued + len > ((chan->l2prot == ISDN_PROTO_L2_TRANS) ? 4000 : EICON_MAX_QUEUED))
+	if (chan->queued + len > EICON_MAX_QUEUE)
 		return 0;
-	if (DebugVar & 128)
-		printk(KERN_DEBUG"idi_snd: Ch%d: %d bytes\n", chan->No, len);
+
+	eicon_log(card, 128, "idi_snd: Ch%d: %d bytes\n", chan->No, len);
 
 	save_flags(flags);
 	cli();
@@ -1769,8 +2874,7 @@
 
 	        if ((!xmit_skb) || (!skb2)) {
 			restore_flags(flags);
-			if (DebugVar & 1)
-	        	        printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No);
+        	        eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No);
 			if (xmit_skb) 
 				dev_kfree_skb(skb);
 			if (skb2) 
@@ -1824,8 +2928,7 @@
         skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
 
         if ((!skb) || (!skb2)) {
-		if (DebugVar & 1)
-			printk(KERN_WARNING "idi_err: alloc_skb failed in manage_assign()\n");
+		eicon_log(card, 1, "idi_err: alloc_skb failed in manage_assign()\n");
 		if (skb) 
 			dev_kfree_skb(skb);
 		if (skb2) 
@@ -1867,8 +2970,7 @@
         skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
 
         if ((!skb) || (!skb2)) {
-		if (DebugVar & 1)
-                	printk(KERN_WARNING "idi_err: alloc_skb failed in manage_remove()\n");
+               	eicon_log(card, 1, "idi_err: alloc_skb failed in manage_remove()\n");
 		if (skb) 
 			dev_kfree_skb(skb);
 		if (skb2) 
@@ -1934,8 +3036,7 @@
 	chan->fsm_state = 0;
 
 	if (!(manbuf = kmalloc(sizeof(eicon_manifbuf), GFP_KERNEL))) {
-		if (DebugVar & 1)
-                	printk(KERN_WARNING "idi_err: alloc_manifbuf failed\n");
+               	eicon_log(card, 1, "idi_err: alloc_manifbuf failed\n");
 		chan->e.D3Id = 0;
 		return -ENOMEM;
 	}
@@ -1949,8 +3050,7 @@
         skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
 
         if ((!skb) || (!skb2)) {
-		if (DebugVar & 1)
-                	printk(KERN_WARNING "idi_err_manif: alloc_skb failed in manage()\n");
+               	eicon_log(card, 1, "idi_err_manif: alloc_skb failed in manage()\n");
 		if (skb) 
 			dev_kfree_skb(skb);
 		if (skb2) 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/eicon/eicon_io.c linux.14p16/drivers/isdn/eicon/eicon_io.c
--- linux.vanilla/drivers/isdn/eicon/eicon_io.c	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/eicon/eicon_io.c	Thu Dec  9 15:34:10 1999
@@ -1,4 +1,4 @@
-/* $Id: eicon_io.c,v 1.5 1999/08/31 11:20:11 paul Exp $
+/* $Id: eicon_io.c,v 1.8 1999/10/08 22:09:34 armin Exp $
  *
  * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
  * Code for communicating with hardware.
@@ -24,6 +24,17 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: eicon_io.c,v $
+ * Revision 1.8  1999/10/08 22:09:34  armin
+ * Some fixes of cards interface handling.
+ * Bugfix of NULL pointer occurence.
+ * Changed a few log outputs.
+ *
+ * Revision 1.7  1999/09/26 14:17:53  armin
+ * Improved debug and log via readstat()
+ *
+ * Revision 1.6  1999/09/21 20:35:43  armin
+ * added more error checking.
+ *
  * Revision 1.5  1999/08/31 11:20:11  paul
  * various spelling corrections (new checksums may be needed, Karsten!)
  *
@@ -54,19 +65,21 @@
 
 void
 eicon_io_rcv_dispatch(eicon_card *ccard) {
+	ulong flags;
         struct sk_buff *skb, *skb2, *skb_new;
         eicon_IND *ind, *ind2, *ind_new;
         eicon_chan *chan;
 
         if (!ccard) {
-		if (DebugVar & 1)
-	                printk(KERN_WARNING "eicon_io_rcv_dispatch: NULL card!\n");
+	        eicon_log(ccard, 1, "eicon_err: NULL card in rcv_dispatch !\n");
                 return;
         }
 
 	while((skb = skb_dequeue(&ccard->rcvq))) {
         	ind = (eicon_IND *)skb->data;
 
+		save_flags(flags);
+		cli();
         	if ((chan = ccard->IdTable[ind->IndId]) == NULL) {
 			if (DebugVar & 1) {
 				switch(ind->Ind) {
@@ -74,14 +87,16 @@
 						/* doesn't matter if this happens */ 
 						break;
 					default: 
-						printk(KERN_ERR "idi: Indication for unknown channel Ind=%d Id=%x\n", ind->Ind, ind->IndId);
-						printk(KERN_DEBUG "idi_hdl: Ch??: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
+						eicon_log(ccard, 1, "idi: Indication for unknown channel Ind=%d Id=%x\n", ind->Ind, ind->IndId);
+						eicon_log(ccard, 1, "idi_hdl: Ch??: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
 							ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
 				}
 			}
+			restore_flags(flags);
 	                dev_kfree_skb(skb);
 	                continue;
 	        }
+		restore_flags(flags);
 
 		if (chan->e.complete) { /* check for rec-buffer chaining */
 			if (ind->MLength == ind->RBuffer.length) {
@@ -97,10 +112,12 @@
 			}
 		}
 		else {
+			save_flags(flags);
+			cli();
 			if (!(skb2 = skb_dequeue(&chan->e.R))) {
 				chan->e.complete = 1;
-				if (DebugVar & 1)
-	                		printk(KERN_ERR "eicon: buffer incomplete, but 0 in queue\n");
+                		eicon_log(ccard, 1, "eicon: buffer incomplete, but 0 in queue\n");
+				restore_flags(flags);
 	                	dev_kfree_skb(skb);
 				continue;	
 			}
@@ -108,8 +125,8 @@
 			skb_new = alloc_skb(((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length),
 					GFP_ATOMIC);
 			if (!skb_new) {
-				if (DebugVar & 1)
-	                		printk(KERN_ERR "eicon_io: skb_alloc failed in rcv_dispatch()\n");
+                		eicon_log(ccard, 1, "eicon_io: skb_alloc failed in rcv_dispatch()\n");
+				restore_flags(flags);
 	                	dev_kfree_skb(skb);
 	                	dev_kfree_skb(skb2);
 				continue;	
@@ -128,12 +145,14 @@
                 	dev_kfree_skb(skb2);
 			if (ind->MLength == ind->RBuffer.length) {
 				chan->e.complete = 2;
+				restore_flags(flags);
 				idi_handle_ind(ccard, skb_new);
 				continue;
 			}
 			else {
 				chan->e.complete = 0;
 				skb_queue_tail(&chan->e.R, skb_new);
+				restore_flags(flags);
 				continue;
 			}
 		}
@@ -145,8 +164,7 @@
         struct sk_buff *skb;
 
         if (!ccard) {
-		if (DebugVar & 1)
-			printk(KERN_WARNING "eicon_io_ack_dispatch: NULL card!\n");
+		eicon_log(ccard, 1, "eicon_err: NULL card in ack_dispatch!\n");
                 return;
         }
 	while((skb = skb_dequeue(&ccard->rackq))) {
@@ -402,13 +420,13 @@
 	int scom = 0;
 	int tmp = 0;
 	int quloop = 1;
+	int dlev = 0;
 
 	pci_card = &ccard->hwif.pci;
 	isa_card = &ccard->hwif.isa;
 
         if (!ccard) {
-		if (DebugVar & 1)
-                	printk(KERN_WARNING "eicon_transmit: NULL card!\n");
+               	eicon_log(ccard, 1, "eicon_transmit: NULL card!\n");
                 return;
         }
 
@@ -441,7 +459,7 @@
 			prram = 0;
 			break;
 		default:
-                	printk(KERN_WARNING "eicon_transmit: unsupported card-type!\n");
+                	eicon_log(ccard, 1, "eicon_transmit: unsupported card-type!\n");
 			return;
 	}
 
@@ -460,16 +478,14 @@
 				}
         	                restore_flags(flags);
                 	        skb_queue_head(&ccard->sndq, skb2);
-				if (DebugVar & 32)
-        	                	printk(KERN_INFO "eicon: transmit: Card not ready\n");
+       	                	eicon_log(ccard, 32, "eicon: transmit: Card not ready\n");
 	                        return;
 			}
 		} else {
 	                if (!(ram_inb(ccard, &prram->ReqOutput) - ram_inb(ccard, &prram->ReqInput))) {
         	                restore_flags(flags);
                 	        skb_queue_head(&ccard->sndq, skb2);
-				if (DebugVar & 32)
-        	                	printk(KERN_INFO "eicon: transmit: Card not ready\n");
+       	                	eicon_log(ccard, 32, "eicon: transmit: Card not ready\n");
 	                        return;
         	        }
 		}
@@ -482,8 +498,7 @@
 		  cli();
 		  reqbuf = (eicon_REQ *)skb->data;
 		  if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) {
-			if (DebugVar & 16)
-				printk(KERN_WARNING "eicon: transmit: error Id=0 on %d (Net)\n", chan->No); 
+			eicon_log(ccard, 16, "eicon: transmit: error Id=0 on %d (Net)\n", chan->No); 
 		  } else {
 			if (scom) {
 				ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length);
@@ -498,7 +513,7 @@
 				ram_outb(ccard, &ReqOut->ReqCh, reqbuf->ReqCh);
 				ram_outb(ccard, &ReqOut->Req, reqbuf->Req); 
 			}
-
+			dlev = 160;
 			if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */
 
 				if (!reqbuf->Reference) { /* Signal Layer */
@@ -520,6 +535,7 @@
 					   ((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */
 						chan->waitq = reqbuf->XBuffer.length;
 						chan->waitpq += reqbuf->XBuffer.length;
+						dlev = 128;
 					}
 				}
 
@@ -547,13 +563,12 @@
 			else
 				ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next)); 
 
-			chan->e.busy = 1; 
-			if (DebugVar & 32)
-	                	printk(KERN_DEBUG "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n", 
-							reqbuf->Req, 
-							ram_inb(ccard, &ReqOut->ReqId),
-							reqbuf->ReqCh, reqbuf->XBuffer.length,
-							chan->e.ref); 
+			chan->e.busy = 1;
+	               	eicon_log(ccard, dlev, "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n", 
+					reqbuf->Req, 
+					ram_inb(ccard, &ReqOut->ReqId),
+					reqbuf->ReqCh, reqbuf->XBuffer.length,
+					chan->e.ref); 
 		  }
 		  restore_flags(flags);
 		  dev_kfree_skb(skb);
@@ -562,8 +577,7 @@
 		} 
 		else {
 		skb_queue_tail(&ccard->sackq, skb2);
-		if (DebugVar & 32)
-                	printk(KERN_INFO "eicon: transmit: busy chan %d\n", chan->No); 
+               	eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No); 
 		}
 
 		if (scom)
@@ -604,10 +618,11 @@
 	unsigned char *irqprobe = 0;
 	int scom = 0;
 	int tmp = 0;
+	int dlev = 0;
 
 
         if (!ccard) {
-                printk(KERN_WARNING "eicon_irq: spurious interrupt %d\n", irq);
+                eicon_log(ccard, 1, "eicon_irq: spurious interrupt %d\n", irq);
                 return;
         }
 
@@ -659,7 +674,7 @@
 			prram = 0;
 			break;
 		default:
-                	printk(KERN_WARNING "eicon_irq: unsupported card-type!\n");
+                	eicon_log(ccard, 1, "eicon_irq: unsupported card-type!\n");
 			return;
 	}
 
@@ -709,24 +724,21 @@
 		case EICON_CTYPE_QUADRO:
 		case EICON_CTYPE_S2M:
 			if (!(readb(isa_card->intack))) { /* card did not interrupt */
-				if (DebugVar & 1)
-					printk(KERN_DEBUG "eicon: IRQ: card reports no interrupt!\n");
+				eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n");
 				return;
 			} 
 			break;
 #endif
 		case EICON_CTYPE_MAESTRAP:
 			if (!(readb(&ram[0x3fe]))) { /* card did not interrupt */
-				if (DebugVar & 1)
-					printk(KERN_DEBUG "eicon: IRQ: card reports no interrupt!\n");
+				eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n");
 				return;
 			} 
 			break;
 		case EICON_CTYPE_MAESTRA:
 			outw(0x3fe, pci_card->PCIreg + M_ADDR);
 			if (!(inb(pci_card->PCIreg + M_DATA))) { /* card did not interrupt */
-				if (DebugVar & 1)
-					printk(KERN_DEBUG "eicon: IRQ: card reports no interrupt!\n");
+				eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n");
 				return;
 			} 
 			break;
@@ -738,8 +750,7 @@
 	if ((tmp = ram_inb(ccard, &com->Rc))) {
 		eicon_RC *ack;
 		if (tmp == READY_INT) {
-			if (DebugVar & 64)
-                        	printk(KERN_INFO "eicon: IRQ Rc=READY_INT\n");
+                       	eicon_log(ccard, 64, "eicon: IRQ Rc=READY_INT\n");
 			if (ccard->ReadyInt) {
 				ccard->ReadyInt--;
 				ram_outb(ccard, &com->Rc, 0);
@@ -747,17 +758,15 @@
 		} else {
 			skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
 			if (!skb) {
-				if (DebugVar & 1)
-	                		printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n");
+                		eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _irq()\n");
 			} else {
 				ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
 				ack->Rc = tmp;
 				ack->RcId = ram_inb(ccard, &com->RcId);
 				ack->RcCh = ram_inb(ccard, &com->RcCh);
 				ack->Reference = ccard->ref_in++;
-				if (DebugVar & 64)
-                	        	printk(KERN_INFO "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n",
-						tmp,ack->RcId,ack->RcCh,ack->Reference);
+               	        	eicon_log(ccard, 128, "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n",
+					tmp,ack->RcId,ack->RcCh,ack->Reference);
 				skb_queue_tail(&ccard->rackq, skb);
 				eicon_schedule_ack(ccard);
 			}
@@ -773,8 +782,7 @@
 			int len = ram_inw(ccard, &com->RBuffer.length);
 			skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
 			if (!skb) {
-				if (DebugVar & 1)
-	                		printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n");
+                		eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _irq()\n");
 			} else {
 				ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
 				ind->Ind = tmp;
@@ -782,9 +790,12 @@
 				ind->IndCh = ram_inb(ccard, &com->IndCh);
 				ind->MInd  = ram_inb(ccard, &com->MInd);
 				ind->MLength = ram_inw(ccard, &com->MLength);
-				ind->RBuffer.length = len; 
-				if (DebugVar & 64)
-                        		printk(KERN_INFO "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
+				ind->RBuffer.length = len;
+				if ((tmp == 1) || (tmp == 8))
+					dlev = 128;
+				else
+					dlev = 192;
+                       		eicon_log(ccard, dlev, "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
 					tmp,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len);
 				ram_copyfromcard(ccard, &ind->RBuffer.P, &com->RBuffer.P, len);
 				skb_queue_tail(&ccard->rcvq, skb);
@@ -807,17 +818,15 @@
                         if((Rc=ram_inb(ccard, &RcIn->Rc))) {
 				skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
 				if (!skb) {
-					if (DebugVar & 1)
-	                			printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n");
+                			eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _irq()\n");
 				} else {
 					ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
 					ack->Rc = Rc;
 					ack->RcId = ram_inb(ccard, &RcIn->RcId);
 					ack->RcCh = ram_inb(ccard, &RcIn->RcCh);
 					ack->Reference = ram_inw(ccard, &RcIn->Reference);
-					if (DebugVar & 64)
-	        	                	printk(KERN_INFO "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n",
-							Rc,ack->RcId,ack->RcCh,ack->Reference);
+        	                	eicon_log(ccard, 128, "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n",
+						Rc,ack->RcId,ack->RcCh,ack->Reference);
 					skb_queue_tail(&ccard->rackq, skb);
 					eicon_schedule_ack(ccard);
 				}
@@ -842,8 +851,7 @@
 				int len = ram_inw(ccard, &IndIn->RBuffer.length);
 				skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
 				if (!skb) {
-					if (DebugVar & 1)
-	                			printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n");
+                			eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _irq()\n");
 				} else {
 					ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
 					ind->Ind = Ind;
@@ -852,8 +860,11 @@
 					ind->MInd  = ram_inb(ccard, &IndIn->MInd);
 					ind->MLength = ram_inw(ccard, &IndIn->MLength);
 					ind->RBuffer.length = len;
-					if (DebugVar & 64)
-	                	        	printk(KERN_INFO "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
+					if ((Ind == 1) || (Ind == 8))
+						dlev = 128;
+					else
+						dlev = 192;
+                	        	eicon_log(ccard, dlev, "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
 						Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len);
 	                                ram_copyfromcard(ccard, &ind->RBuffer.P, &IndIn->RBuffer.P, len);
 					skb_queue_tail(&ccard->rcvq, skb);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/eicon/eicon_isa.h linux.14p16/drivers/isdn/eicon/eicon_isa.h
--- linux.vanilla/drivers/isdn/eicon/eicon_isa.h	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/eicon/eicon_isa.h	Thu Dec  9 15:34:10 1999
@@ -1,4 +1,4 @@
-/* $Id: eicon_isa.h,v 1.5 1999/09/08 20:17:31 armin Exp $
+/* $Id: eicon_isa.h,v 1.6 1999/11/15 19:37:04 keil Exp $
  *
  * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
  *
@@ -21,6 +21,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: eicon_isa.h,v $
+ * Revision 1.6  1999/11/15 19:37:04  keil
+ * need config.h
+ *
  * Revision 1.5  1999/09/08 20:17:31  armin
  * Added microchannel patch from Erik Weber.
  *
@@ -48,6 +51,7 @@
 #define eicon_isa_h
 
 #ifdef __KERNEL__
+#include <linux/config.h>
 
 /* Factory defaults for ISA-Cards */
 #define EICON_ISA_MEMBASE 0xd0000
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/eicon/eicon_mod.c linux.14p16/drivers/isdn/eicon/eicon_mod.c
--- linux.vanilla/drivers/isdn/eicon/eicon_mod.c	Wed Oct 20 01:12:36 1999
+++ linux.14p16/drivers/isdn/eicon/eicon_mod.c	Thu Dec  9 15:34:10 1999
@@ -1,4 +1,4 @@
-/* $Id: eicon_mod.c,v 1.15 1999/09/08 20:17:31 armin Exp $
+/* $Id: eicon_mod.c,v 1.19 1999/11/12 13:21:44 armin Exp $
  *
  * ISDN lowlevel-module for Eicon.Diehl active cards.
  * 
@@ -11,6 +11,11 @@
  *
  *              Deutsche Telekom AG for S2M support.
  *
+ *		Deutsche Mailbox Saar-Lor-Lux GmbH
+ *		for sponsoring and testing fax
+ *		capabilities with Diva Server cards.
+ *		(dor@deutschemailbox.de)
+ *
  * 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)
@@ -26,6 +31,20 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: eicon_mod.c,v $
+ * Revision 1.19  1999/11/12 13:21:44  armin
+ * Bugfix of undefined reference with CONFIG_MCA
+ *
+ * Revision 1.18  1999/10/11 18:13:25  armin
+ * Added fax capabilities for Eicon Diva Server cards.
+ *
+ * Revision 1.17  1999/10/08 22:09:34  armin
+ * Some fixes of cards interface handling.
+ * Bugfix of NULL pointer occurence.
+ * Changed a few log outputs.
+ *
+ * Revision 1.16  1999/09/26 14:17:53  armin
+ * Improved debug and log via readstat()
+ *
  * Revision 1.15  1999/09/08 20:17:31  armin
  * Added microchannel patch from Erik Weber.
  *
@@ -104,7 +123,7 @@
 static eicon_card *cards = (eicon_card *) NULL;   /* glob. var , contains
                                                      start of card-list   */
 
-static char *eicon_revision = "$Revision: 1.15 $";
+static char *eicon_revision = "$Revision: 1.19 $";
 
 extern char *eicon_pci_revision;
 extern char *eicon_isa_revision;
@@ -185,8 +204,7 @@
 {
 	if ((channel >= 0) && (channel < card->nchannels))
         	return &(card->bch[channel]);
-	if (DebugVar & 1)
-		printk(KERN_WARNING "eicon: Invalid channel %d\n", channel);
+	eicon_log(card, 1, "eicon: Invalid channel %d\n", channel);
 	return NULL;
 }
 
@@ -263,9 +281,8 @@
 			eicon_io_rcv_dispatch(card);
 			break;
 		default:
-			if (DebugVar & 1)
-				printk(KERN_WARNING
-				       "eicon_ack_dispatch: Illegal bustype %d\n", card->bus);
+			eicon_log(card, 1,
+			       "eicon_ack_dispatch: Illegal bustype %d\n", card->bus);
 	}
 }
 
@@ -279,9 +296,8 @@
 			eicon_io_ack_dispatch(card);
 			break;
 		default:
-			if (DebugVar & 1)
-				printk(KERN_WARNING
-			       		"eicon_ack_dispatch: Illegal bustype %d\n", card->bus);
+			eicon_log(card, 1,
+		       		"eicon_ack_dispatch: Illegal bustype %d\n", card->bus);
 	}
 }
 
@@ -295,9 +311,8 @@
 			eicon_io_transmit(card);
 			break;
 		default:
-			if (DebugVar & 1)
-				printk(KERN_WARNING
-				       "eicon_transmit: Illegal bustype %d\n", card->bus);
+			eicon_log(card, 1,
+			       "eicon_transmit: Illegal bustype %d\n", card->bus);
 	}
 }
 
@@ -307,8 +322,7 @@
 	int ret_val;
 
 	if (!(xlr = kmalloc(sizeof(xlogreq_t), GFP_KERNEL))) {
-		if (DebugVar & 1)
-			printk(KERN_WARNING "idi_err: alloc_xlogreq_t failed\n");
+		eicon_log(card, 1, "idi_err: alloc_xlogreq_t failed\n");
 		return -ENOMEM;
 	}
 	if (copy_from_user(xlr, xlogreq, sizeof(xlogreq_t))) {
@@ -338,9 +352,8 @@
 	int ret = 0;
 	unsigned long flags;
  
-	if (DebugVar & 16)
-		printk(KERN_WARNING "eicon_cmd 0x%x with arg 0x%lx (0x%lx)\n",
-			c->command, c->arg, (ulong) *c->parm.num);
+	eicon_log(card, 16, "eicon_cmd 0x%x with arg 0x%lx (0x%lx)\n",
+		c->command, c->arg, (ulong) *c->parm.num);
 
         switch (c->command) {
 		case ISDN_CMD_IOCTL:
@@ -360,9 +373,8 @@
 							return card->hwif.pci.PCIram;
 #endif
 						default:
-							if (DebugVar & 1)
-								printk(KERN_WARNING
-								       "eicon: Illegal BUS type %d\n",
+							eicon_log(card, 1,
+							       "eicon: Illegal BUS type %d\n",
 							       card->bus);
 							ret = -ENODEV;
 					}
@@ -389,9 +401,8 @@
 							return 0;
 #endif /* CONFIG_MCA */
 						default:
-							if (DebugVar & 1)
-								printk(KERN_WARNING
-							      		"eicon: Illegal BUS type %d\n",
+							eicon_log(card, 1,
+						      		"eicon: Illegal BUS type %d\n",
 							       card->bus);
 							ret = -ENODEV;
 					}					
@@ -406,9 +417,8 @@
 							return card->hwif.pci.irq;
 #endif
 						default:
-							if (DebugVar & 1)
-								printk(KERN_WARNING
-								       "eicon: Illegal BUS type %d\n",
+							eicon_log(card, 1,
+							       "eicon: Illegal BUS type %d\n",
 							       card->bus);
 							ret = -ENODEV;
 					}
@@ -423,9 +433,8 @@
 							card->hwif.isa.irq = a;
 							return 0;
 						default:
-							if (DebugVar & 1)
-								printk(KERN_WARNING
-							      		"eicon: Illegal BUS type %d\n",
+							eicon_log(card, 1,
+						      		"eicon: Illegal BUS type %d\n",
 							       card->bus);
 							ret = -ENODEV;
 					}					
@@ -441,9 +450,8 @@
 								&(((eicon_codebuf *)a)->isa));
 							break;
 						default:
-							if (DebugVar & 1)
-								printk(KERN_WARNING
-								       "eicon: Illegal BUS type %d\n",
+							eicon_log(card, 1,
+							       "eicon: Illegal BUS type %d\n",
 							       card->bus);
 							ret = -ENODEV;
 					}
@@ -475,9 +483,8 @@
 							}
 							break;
 						default:
-							if (DebugVar & 1)
-								printk(KERN_WARNING
-								       "eicon: Illegal BUS type %d\n",
+							eicon_log(card, 1,
+							       "eicon: Illegal BUS type %d\n",
 							       card->bus);
 							ret = -ENODEV;
 					}
@@ -541,7 +548,7 @@
 					return 0;
 				case EICON_IOCTL_DEBUGVAR:
 					DebugVar = a;
-					printk(KERN_DEBUG"Eicon: Debug Value set to %ld\n", DebugVar);
+					eicon_log(card, 1, "Eicon: Debug Value set to %ld\n", DebugVar);
 					return 0;
 #ifdef MODULE
 				case EICON_IOCTL_FREEIT:
@@ -562,8 +569,7 @@
 			cli();
 			if ((chan->fsm_state != EICON_STATE_NULL) && (chan->fsm_state != EICON_STATE_LISTEN)) {
 				restore_flags(flags);
-				if (DebugVar & 1)
-					printk(KERN_WARNING "Dial on channel %d with state %d\n",
+				eicon_log(card, 1, "Dial on channel %d with state %d\n",
 					chan->No, chan->fsm_state);
 				return -EBUSY;
 			}
@@ -572,7 +578,6 @@
 			else
 				tmp[0] = c->parm.setup.eazmsn[0];
 			chan->fsm_state = EICON_STATE_OCALL;
-			chan->callref = 0xffff;
 			restore_flags(flags);
 			
 			ret = idi_connect_req(card, chan, c->parm.setup.phone,
@@ -667,20 +672,17 @@
 		case ISDN_CMD_GETEAZ:
 			if (!card->flags & EICON_FLAGS_RUNNING)
 				return -ENODEV;
-			if (DebugVar & 1)
-				printk(KERN_DEBUG "eicon CMD_GETEAZ not implemented\n");
+			eicon_log(card, 1, "eicon CMD_GETEAZ not implemented\n");
 			return 0;
 		case ISDN_CMD_SETSIL:
 			if (!card->flags & EICON_FLAGS_RUNNING)
 				return -ENODEV;
-			if (DebugVar & 1)
-				printk(KERN_DEBUG "eicon CMD_SETSIL not implemented\n");
+			eicon_log(card, 1, "eicon CMD_SETSIL not implemented\n");
 			return 0;
 		case ISDN_CMD_GETSIL:
 			if (!card->flags & EICON_FLAGS_RUNNING)
 				return -ENODEV;
-			if (DebugVar & 1)
-				printk(KERN_DEBUG "eicon CMD_GETSIL not implemented\n");
+			eicon_log(card, 1, "eicon CMD_GETSIL not implemented\n");
 			return 0;
 		case ISDN_CMD_LOCK:
 			MOD_INC_USE_COUNT;
@@ -752,6 +754,52 @@
 static int
 if_readstatus(u_char * buf, int len, int user, int id, int channel)
 {
+	int count = 0;
+	int cnt = 0;
+	ulong flags = 0;
+	u_char *p = buf;
+	struct sk_buff *skb;
+
+        eicon_card *card = eicon_findcard(id);
+	
+        if (card) {
+                if (!card->flags & EICON_FLAGS_RUNNING)
+                        return -ENODEV;
+	
+		save_flags(flags);
+		cli();
+		while((skb = skb_dequeue(&card->statq))) {
+
+			if ((skb->len + count) > len)
+				cnt = len - count;
+			else
+				cnt = skb->len;
+
+			if (user)
+				copy_to_user(p, skb->data, cnt);
+			else
+				memcpy(p, skb->data, cnt);
+
+			count += cnt;
+			p += cnt;
+
+			if (cnt == skb->len) {
+				dev_kfree_skb(skb);
+				if (card->statq_entries > 0)
+					card->statq_entries--;
+			} else {
+				skb_pull(skb, cnt);
+				skb_queue_head(&card->statq, skb);
+				restore_flags(flags);
+				return count;
+			}
+		}
+		card->statq_entries = 0;
+		restore_flags(flags);
+		return count;
+        }
+        printk(KERN_ERR
+               "eicon: if_readstatus called with invalid driverId!\n");
         return 0;
 }
 
@@ -766,14 +814,11 @@
 	len = skb->len;
 	
         if (card) {
-                if (!card->flags & EICON_FLAGS_RUNNING) {
-			dev_kfree_skb(skb);
+                if (!card->flags & EICON_FLAGS_RUNNING)
                         return -ENODEV;
-		}
-        	if (!(chan = find_channel(card, channel))) {
-			dev_kfree_skb(skb);
+        	if (!(chan = find_channel(card, channel)))
 			return -ENODEV;
-		}
+
 		if (chan->fsm_state == EICON_STATE_ACTIVE) {
 #ifdef CONFIG_ISDN_TTY_FAX
 			if (chan->l2prot == ISDN_PROTO_L2_FAX) {
@@ -785,16 +830,116 @@
 				ret = idi_send_data(card, chan, ack, skb, 1);
 			return (ret);
 		} else {
-			dev_kfree_skb(skb);
 			return -ENODEV;
 		}
         }
         printk(KERN_ERR
                "eicon: if_sendbuf called with invalid driverId!\n");
-	dev_kfree_skb(skb);
         return -ENODEV;
 }
 
+/* jiftime() copied from HiSax */
+/* Copying functions without making them static causes nameclashed --ADVE */
+static inline int
+jiftime(char *s, long mark)
+{
+        s += 8;
+
+        *s-- = '\0';
+        *s-- = mark % 10 + '0';
+        mark /= 10;
+        *s-- = mark % 10 + '0';
+        mark /= 10;
+        *s-- = '.';
+        *s-- = mark % 10 + '0';
+        mark /= 10;
+        *s-- = mark % 6 + '0';
+        mark /= 6;
+        *s-- = ':';
+        *s-- = mark % 10 + '0';
+        mark /= 10;
+        *s-- = mark % 10 + '0';
+        return(8);
+}
+
+void
+eicon_putstatus(eicon_card * card, char * buf)
+{
+	ulong flags;
+	int count;
+	isdn_ctrl cmd;
+	u_char *p;
+	struct sk_buff *skb;
+
+	if (!card)
+		return;
+
+	save_flags(flags);
+	cli();
+	count = strlen(buf);
+	skb = alloc_skb(count, GFP_ATOMIC);
+	if (!skb) {
+		restore_flags(flags);
+		printk(KERN_ERR "eicon: could not alloc skb in putstatus\n");
+		return;
+	}
+	p = skb_put(skb, count);
+	memcpy(p, buf, count);
+
+	skb_queue_tail(&card->statq, skb);
+
+	if (card->statq_entries >= MAX_STATUS_BUFFER) {
+		if ((skb = skb_dequeue(&card->statq))) {
+			count -= skb->len;
+			dev_kfree_skb(skb);
+		} else
+			count = 0;
+	} else
+		card->statq_entries++;
+
+	restore_flags(flags);
+        if (count) {
+                cmd.command = ISDN_STAT_STAVAIL;
+                cmd.driver = card->myid;
+                cmd.arg = count;
+		card->interface.statcallb(&cmd);
+        }
+}
+
+/*
+ * Debug and Log 
+ */
+void
+eicon_log(eicon_card * card, int level, const char *fmt, ...)
+{
+	va_list args;
+	char Line[160];
+	u_char *p;
+
+
+	if ((DebugVar & level) || (DebugVar & 256)) {
+		va_start(args, fmt);
+
+		if (DebugVar & level) {
+			if (DebugVar & 256) {
+				/* log-buffer */
+				p = Line;
+				p += jiftime(p, jiffies);
+				*p++ = 32;
+				p += vsprintf(p, fmt, args);
+				*p = 0;	
+				eicon_putstatus(card, Line);
+			} else {
+				/* printk, syslogd */
+				vsprintf(Line, fmt, args);
+				printk(KERN_DEBUG "%s", Line);
+			}
+		}
+
+		va_end(args);
+	}
+}
+
 
 /*
  * Allocate a new card-struct, initialize it
@@ -817,7 +962,7 @@
 	qloop = (Type == EICON_CTYPE_QUADRO)?2:0;
 	for (i = 0; i <= qloop; i++) {
 		if (!(card = (eicon_card *) kmalloc(sizeof(eicon_card), GFP_KERNEL))) {
-			printk(KERN_WARNING
+			eicon_log(card, 1,
 			       "eicon: (%s) Could not allocate card-struct.\n", id);
 			return;
 		}
@@ -826,6 +971,8 @@
 		skb_queue_head_init(&card->rcvq);
 		skb_queue_head_init(&card->rackq);
 		skb_queue_head_init(&card->sackq);
+		skb_queue_head_init(&card->statq);
+		card->statq_entries = 0;
 		card->snd_tq.routine = (void *) (void *) eicon_transmit;
 		card->snd_tq.data = card;
 		card->rcv_tq.routine = (void *) (void *) eicon_rcv_dispatch;
@@ -897,7 +1044,7 @@
 						p = p->next;
 					}
 					if (!p) {
-						printk(KERN_WARNING "eicon_alloccard: Quadro Master not found.\n");
+						eicon_log(card, 1, "eicon_alloccard: Quadro Master not found.\n");
 						kfree(card);
 						return;
 					}
@@ -919,7 +1066,7 @@
 					ISDN_FEATURE_L2_V11019 |
 					ISDN_FEATURE_L2_V11038 |
 					ISDN_FEATURE_L2_MODEM |
-					/* ISDN_FEATURE_L2_FAX | */ 
+					ISDN_FEATURE_L2_FAX | 
 					ISDN_FEATURE_L3_TRANSDSP |
 					ISDN_FEATURE_L3_FAX;
                                 card->hwif.pci.card = (void *)card;
@@ -943,7 +1090,7 @@
 					ISDN_FEATURE_L2_V11019 |
 					ISDN_FEATURE_L2_V11038 |
 					ISDN_FEATURE_L2_MODEM |
-					/* ISDN_FEATURE_L2_FAX | */
+					ISDN_FEATURE_L2_FAX |
 					ISDN_FEATURE_L3_TRANSDSP |
 					ISDN_FEATURE_L3_FAX;
                                 card->hwif.pci.card = (void *)card;
@@ -992,13 +1139,13 @@
 				break;
 #endif
 			default:
-				printk(KERN_WARNING "eicon_alloccard: Invalid type %d\n", Type);
+				eicon_log(card, 1, "eicon_alloccard: Invalid type %d\n", Type);
 				kfree(card);
 				return;
 		}
 		if (!(card->bch = (eicon_chan *) kmalloc(sizeof(eicon_chan) * (card->nchannels + 1)
 							 , GFP_KERNEL))) {
-			printk(KERN_WARNING
+			eicon_log(card, 1,
 			       "eicon: (%s) Could not allocate bch-struct.\n", id);
 			kfree(card);
 			return;
@@ -1044,9 +1191,8 @@
 			break;
 #endif
 		default:
-			if (DebugVar & 1)
-				printk(KERN_WARNING
-				       "eicon_registercard: Illegal BUS type %d\n",
+			eicon_log(card, 1,
+			       "eicon_registercard: Illegal BUS type %d\n",
 			       card->bus);
 			return -1;
         }
@@ -1085,9 +1231,8 @@
 			break;
 #endif
 		default:
-			if (DebugVar & 1)
-				printk(KERN_WARNING
-				       "eicon: Invalid BUS type %d\n",
+			eicon_log(card, 1,
+			       "eicon: Invalid BUS type %d\n",
 			       card->bus);
 			break;
         }
@@ -1096,6 +1241,26 @@
 
 static void
 eicon_freecard(eicon_card *card) {
+	int i;
+	struct sk_buff *skb;
+
+	for(i = 0; i < (card->nchannels + 1); i++) {
+		while((skb = skb_dequeue(&card->bch[i].e.X)))
+			dev_kfree_skb(skb);
+		while((skb = skb_dequeue(&card->bch[i].e.R)))
+			dev_kfree_skb(skb);
+	}
+	while((skb = skb_dequeue(&card->sndq)))
+		dev_kfree_skb(skb);
+	while((skb = skb_dequeue(&card->rcvq)))
+		dev_kfree_skb(skb);
+	while((skb = skb_dequeue(&card->rackq)))
+		dev_kfree_skb(skb);
+	while((skb = skb_dequeue(&card->sackq)))
+		dev_kfree_skb(skb);
+	while((skb = skb_dequeue(&card->statq)))
+		dev_kfree_skb(skb);
+
 	eicon_clear_msn(card);
 	kfree(card->bch);
 	kfree(card);
@@ -1141,9 +1306,8 @@
 					break;
 #endif
 				default:
-					if (DebugVar & 1)
-						printk(KERN_WARNING
-						       "eicon: addcard: Invalid BUS type %d\n",
+					printk(KERN_ERR
+					       "eicon: addcard: Invalid BUS type %d\n",
 					       p->bus);
 			}
 		} else
@@ -1155,7 +1319,7 @@
                         p = p->next;
                 } else {
                         /* registering failed, remove card from list, free memory */
-                        printk(KERN_WARNING
+                        printk(KERN_ERR
                                "eicon: Initialization of %s failed\n",
                                p->interface.id);
                         if (q) {
@@ -1222,10 +1386,9 @@
                 printk(KERN_INFO
                         "eicon: No MCA bus, ISDN-interfaces  not probed.\n");
         } else {
-		if (DebugVar & 8)
-               		printk(KERN_DEBUG
-			       "eicon_mca_find_card, irq=%d.\n", 
-                                irq);
+		eicon_log(NULL, 8,
+			"eicon_mca_find_card, irq=%d.\n", 
+				irq);
                	if (!eicon_mca_find_card(0, membase, irq, id))
                        card_count++;
         };
@@ -1346,10 +1509,9 @@
 {
 	int j, curr_slot = 0;
 
-	if (DebugVar & 8)
-        	printk(KERN_DEBUG
-                       "eicon_mca_find_card type: %d, membase: %#x, irq %d \n",
-                       type, membase, irq);
+       	eicon_log(NULL, 8,
+		"eicon_mca_find_card type: %d, membase: %#x, irq %d \n",
+		type, membase, irq);
 	/* find a no-driver-assigned eicon card                               */
 	for (j=0; eicon_mca_adapters[j].adf_id != 0; j++) 
 		{
@@ -1414,11 +1576,10 @@
 	int irq_array1[]={3,4,0,0,2,10,11,12};
 
         adf_pos0 = mca_read_stored_pos(slot,2);
-	if (DebugVar & 8)
-		printk(KERN_DEBUG
-                       "eicon_mca_probe irq=%d, membase=%d\n", 
-                        irq,
-                        membase);
+	eicon_log(NULL, 8,
+		"eicon_mca_probe irq=%d, membase=%d\n", 
+		irq,
+		membase);
 	switch (a_idx) {
 		case 0:                /* P/2-Adapter (== PRI/S2M ? )         */
 			cards_membase= 0xC0000+((adf_pos0>>4)*0x4000);
@@ -1473,7 +1634,7 @@
 		default:
 			return  ENODEV;
 	};
-	/* Uebereinstimmung vorgegebener membase & irq */
+	/* matching membase & irq */
 	if ( 1 == eicon_addcard(type, membase, irq, id)) { 
 		mca_set_adapter_name(slot, eicon_mca_adapters[a_idx].name);
   		mca_set_adapter_procfn(slot, (MCA_ProcFn) eicon_info, cards);
@@ -1486,10 +1647,9 @@
 		/* reset card */
 		outb_p(0,cards_io+1);
 
-		if (DebugVar & 8)
-			printk(KERN_INFO "eicon_addcard: successful for slot # %d.\n", 
+		eicon_log(NULL, 8, "eicon_addcard: successful for slot # %d.\n", 
 			cards->mca_slot+1);
-		return  0 ; /* eicon_addcard hat eine Karte zugefuegt */
+		return  0 ; /* eicon_addcard added a card */
 	} else {
 		return ENODEV;
 	};
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/avm_pci.c linux.14p16/drivers/isdn/hisax/avm_pci.c
--- linux.vanilla/drivers/isdn/hisax/avm_pci.c	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/avm_pci.c	Tue Dec 21 00:27:14 1999
@@ -269,18 +269,26 @@
 	int hdlc = bcs->channel;
 
 	if (cs->debug & L1_DEB_HSCX)
-		debugl1(cs, "hdlc %c mode %d ichan %d",
-			'A' + hdlc, mode, bc);
-	bcs->mode = mode;
-	bcs->channel = bc;
+		debugl1(cs, "hdlc %c mode %d --> %d ichan %d --> %d",
+			'A' + hdlc, bcs->mode, mode, hdlc, bc);
 	bcs->hw.hdlc.ctrl.ctrl = 0;
 	switch (mode) {
+		case (-1): /* used for init */
+			bcs->mode = 1;
+			bcs->channel = bc;
+			bc = 0;
 		case (L1_MODE_NULL):
+			if (bcs->mode == L1_MODE_NULL)
+				return;
 			bcs->hw.hdlc.ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS;
 			bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
 			write_ctrl(bcs, 5);
+			bcs->mode = L1_MODE_NULL;
+			bcs->channel = bc;
 			break;
 		case (L1_MODE_TRANS):
+			bcs->mode = mode;
+			bcs->channel = bc;
 			bcs->hw.hdlc.ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS;
 			bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
 			write_ctrl(bcs, 5);
@@ -290,6 +298,8 @@
 			hdlc_sched_event(bcs, B_XMTBUFREADY);
 			break;
 		case (L1_MODE_HDLC):
+			bcs->mode = mode;
+			bcs->channel = bc;
 			bcs->hw.hdlc.ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS;
 			bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_ITF_FLG;
 			write_ctrl(bcs, 5);
@@ -695,8 +705,8 @@
 	cs->bcs[1].BC_SetStack = setstack_hdlc;
 	cs->bcs[0].BC_Close = close_hdlcstate;
 	cs->bcs[1].BC_Close = close_hdlcstate;
-	modehdlc(cs->bcs, 0, 0);
-	modehdlc(cs->bcs + 1, 0, 0);
+	modehdlc(cs->bcs, -1, 0);
+	modehdlc(cs->bcs + 1, -1, 1);
 }
 
 static void
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/callc.c linux.14p16/drivers/isdn/hisax/callc.c
--- linux.vanilla/drivers/isdn/hisax/callc.c	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/callc.c	Thu Dec  9 15:34:07 1999
@@ -1,4 +1,4 @@
-/* $Id: callc.c,v 2.37 1999/09/20 19:49:47 keil Exp $
+/* $Id: callc.c,v 2.39 1999/10/14 20:25:28 keil Exp $
 
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
@@ -11,6 +11,12 @@
  *              Fritz Elfert
  *
  * $Log: callc.c,v $
+ * Revision 2.39  1999/10/14 20:25:28  keil
+ * add a statistic for error monitoring
+ *
+ * Revision 2.38  1999/10/11 22:16:27  keil
+ * Suspend/Resume is possible without explicit ID too
+ *
  * Revision 2.37  1999/09/20 19:49:47  keil
  * Fix wrong init of PStack
  *
@@ -157,7 +163,7 @@
 #define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module))
 #endif	/* MODULE */
 
-const char *lli_revision = "$Revision: 2.37 $";
+const char *lli_revision = "$Revision: 2.39 $";
 
 extern struct IsdnCard cards[];
 extern int nrcards;
@@ -1478,11 +1484,6 @@
 }
 
 static void
-channel_report(struct Channel *chanp)
-{
-}
-
-static void
 distr_debug(struct IsdnCardState *csta, int debugflags)
 {
 	int i;
@@ -1515,7 +1516,6 @@
 {
 	char *t = tmpbuf;
 
-	t += sprintf(tmpbuf, "%d CAPIMSG", chanp->chan);
 	t += QuickHex(t, (u_char *)cm, (cm->Length>50)? 50: cm->Length);
 	t--;
 	*t= 0;
@@ -1532,20 +1532,16 @@
 		return;
 	switch(cm->para[3]) {
 		case 4: /* Suspend */
-			if (cm->para[5]) {
-				strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1);
-				FsmEvent(&chanp->fi, EV_SUSPEND, cm);
-			}
+			strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1);
+			FsmEvent(&chanp->fi, EV_SUSPEND, cm);
 			break;
 		case 5: /* Resume */
-			if (cm->para[5]) {
-				strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1);
-				if (chanp->fi.state == ST_NULL) {
-					FsmEvent(&chanp->fi, EV_RESUME, cm);
-				} else {
-					FsmDelTimer(&chanp->dial_timer, 72);
-					FsmAddTimer(&chanp->dial_timer, 80, EV_RESUME, cm, 73);
-				}
+			strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1);
+			if (chanp->fi.state == ST_NULL) {
+				FsmEvent(&chanp->fi, EV_RESUME, cm);
+			} else {
+				FsmDelTimer(&chanp->dial_timer, 72);
+				FsmAddTimer(&chanp->dial_timer, 80, EV_RESUME, cm, 73);
 			}
 			break;
 	}
@@ -1697,9 +1693,8 @@
 		case (ISDN_CMD_IOCTL):
 			switch (ic->arg) {
 				case (0):
-					HiSax_reportcard(csta->cardnr);
-					for (i = 0; i < 2; i++)
-						channel_report(&csta->channel[i]);
+					num = *(unsigned int *) ic->parm.num;
+					HiSax_reportcard(csta->cardnr, num);
 					break;
 				case (1):
 					num = *(unsigned int *) ic->parm.num;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/config.c linux.14p16/drivers/isdn/hisax/config.c
--- linux.vanilla/drivers/isdn/hisax/config.c	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/config.c	Thu Dec  9 15:34:07 1999
@@ -1,10 +1,19 @@
-/* $Id: config.c,v 2.37 1999/09/20 12:11:08 keil Exp $
+/* $Id: config.c,v 2.40 1999/10/30 13:09:45 keil Exp $
 
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
  *
  * $Log: config.c,v $
+ * Revision 2.40  1999/10/30 13:09:45  keil
+ * Version 3.3c
+ *
+ * Revision 2.39  1999/10/16 14:44:45  keil
+ * Fix module parm if only NICCY was selected
+ *
+ * Revision 2.38  1999/10/14 20:25:28  keil
+ * add a statistic for error monitoring
+ *
  * Revision 2.37  1999/09/20 12:11:08  keil
  * Fix hang if no protocol was selected
  *
@@ -483,10 +492,10 @@
 MODULE_PARM(irq, "1-8i");
 MODULE_PARM(mem, "1-8i");
 MODULE_PARM(id, "s");
-#ifdef CONFIG_HISAX_16_3	/* For Creatix/Teles PnP */
+#ifdef IO0_IO1
 MODULE_PARM(io0, "1-8i");
 MODULE_PARM(io1, "1-8i");
-#endif /* CONFIG_HISAX_16_3 */
+#endif /* IO0_IO1 */
 #endif /* MODULE */
 
 int nrcards;
@@ -519,9 +528,9 @@
 
 	printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n");
 #ifdef MODULE
-	printk(KERN_INFO "HiSax: Version 3.3a (module)\n");
+	printk(KERN_INFO "HiSax: Version 3.3c (module)\n");
 #else
-	printk(KERN_INFO "HiSax: Version 3.3a (kernel)\n");
+	printk(KERN_INFO "HiSax: Version 3.3c (kernel)\n");
 #endif
 	strcpy(tmp, l1_revision);
 	printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp));
@@ -1369,12 +1378,9 @@
 }
 
 void
-HiSax_reportcard(int cardnr)
+HiSax_reportcard(int cardnr, int sel)
 {
 	struct IsdnCardState *cs = cards[cardnr].cs;
-	struct PStack *stptr;
-	struct l3_process *pc;
-	int j, i = 1;
 
 	printk(KERN_DEBUG "HiSax: reportcard No %d\n", cardnr + 1);
 	printk(KERN_DEBUG "HiSax: Type %s\n", CardType[cs->typ]);
@@ -1382,45 +1388,33 @@
 	printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n",
 		(ulong) & HiSax_reportcard);
 	printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs);
-	printk(KERN_DEBUG "HiSax: HW_Flags %x bc0 flg %x bc0 flg %x\n",
+	printk(KERN_DEBUG "HiSax: HW_Flags %x bc0 flg %x bc1 flg %x\n",
 		cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag);
 	printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n",
 		cs->bcs[0].mode, cs->bcs[0].channel);
 	printk(KERN_DEBUG "HiSax: bcs 1 mode %d ch%d\n",
 		cs->bcs[1].mode, cs->bcs[1].channel);
-	printk(KERN_DEBUG "HiSax: cs setstack_d 0x%lX\n", (ulong) cs->setstack_d);
-	printk(KERN_DEBUG "HiSax: cs stl 0x%lX\n", (ulong) & (cs->stlist));
-	stptr = cs->stlist;
-	while (stptr != NULL) {
-		printk(KERN_DEBUG "HiSax: dst%d 0x%lX\n", i, (ulong) stptr);
-		printk(KERN_DEBUG "HiSax: dst%d stp 0x%lX\n", i, (ulong) stptr->l1.stlistp);
-		printk(KERN_DEBUG "HiSax: dst%d l1.l1hw 0x%lX\n", i, (ulong) stptr->l1.l1hw);
-		printk(KERN_DEBUG "HiSax:   tei %d sapi %d\n",
-		       stptr->l2.tei, stptr->l2.sap);
-		printk(KERN_DEBUG "HiSax:      man 0x%lX\n", (ulong) stptr->ma.layer);
-		pc = stptr->l3.proc;
-		while (pc) {
-			printk(KERN_DEBUG "HiSax: l3proc %x 0x%lX\n", pc->callref,
-			       (ulong) pc);
-			printk(KERN_DEBUG "HiSax:    state %d  st 0x%lX chan 0x%lX\n",
-			    pc->state, (ulong) pc->st, (ulong) pc->chan);
-			pc = pc->next;
-		}
-		stptr = stptr->next;
-		i++;
-	}
-	for (j = 0; j < 2; j++) {
-		printk(KERN_DEBUG "HiSax: ch%d 0x%lX\n", j,
-		       (ulong) & cs->channel[j]);
-		stptr = cs->channel[j].b_st;
-		i = 1;
-		while (stptr != NULL) {
-			printk(KERN_DEBUG "HiSax:  b_st%d 0x%lX\n", i, (ulong) stptr);
-			printk(KERN_DEBUG "HiSax:    man 0x%lX\n", (ulong) stptr->ma.layer);
-			stptr = stptr->next;
-			i++;
-		}
+#ifdef ERROR_STATISTIC
+	printk(KERN_DEBUG "HiSax: dc errors(rx,crc,tx) %d,%d,%d\n",
+		cs->err_rx, cs->err_crc, cs->err_tx);
+	printk(KERN_DEBUG "HiSax: bc0 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
+		cs->bcs[0].err_inv, cs->bcs[0].err_rdo, cs->bcs[0].err_crc, cs->bcs[0].err_tx);
+	printk(KERN_DEBUG "HiSax: bc1 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
+		cs->bcs[1].err_inv, cs->bcs[1].err_rdo, cs->bcs[1].err_crc, cs->bcs[1].err_tx);
+	if (sel == 99) {
+		cs->err_rx  = 0;
+		cs->err_crc = 0;
+		cs->err_tx  = 0;
+		cs->bcs[0].err_inv = 0;
+		cs->bcs[0].err_rdo = 0;
+		cs->bcs[0].err_crc = 0;
+		cs->bcs[0].err_tx  = 0;
+		cs->bcs[1].err_inv = 0;
+		cs->bcs[1].err_rdo = 0;
+		cs->bcs[1].err_crc = 0;
+		cs->bcs[1].err_tx  = 0;
 	}
+#endif
 }
 
 
@@ -1599,9 +1593,7 @@
 
 	nrcards = 0;
 	HiSaxVersion();
-	if (id)			/* If id= string used */
-		HiSax_id = id;
-	/* Initialize all 8 structs, even though we only accept
+	/* Initialize all structs, even though we only accept
 	   two pcmcia cards
 	   */
 	for (i = 0; i < HISAX_MAX_CARDS; i++) {
@@ -1650,9 +1642,7 @@
 
 	nrcards = 0;
 	HiSaxVersion();
-	if (id)			/* If id= string used */
-		HiSax_id = id;
-	/* Initialize all 8 structs, even though we only accept
+	/* Initialize all structs, even though we only accept
 	   two pcmcia cards
 	   */
 	for (i = 0; i < HISAX_MAX_CARDS; i++) {
@@ -1701,12 +1691,10 @@
 
 	nrcards = 0;
 	HiSaxVersion();
-	if (id)			/* If id= string used */
-		HiSax_id = id;
-	/* Initialize all 16 structs, even though we only accept
+	/* Initialize all structs, even though we only accept
 	   two pcmcia cards
 	   */
-	for (i = 0; i < 16; i++) {
+	for (i = 0; i < HISAX_MAX_CARDS; i++) {
 		cards[i].para[0] = irq[i];
 		cards[i].para[1] = io[i];
 		cards[i].typ = type[i];
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/hfc_2bds0.c linux.14p16/drivers/isdn/hisax/hfc_2bds0.c
--- linux.vanilla/drivers/isdn/hisax/hfc_2bds0.c	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/hfc_2bds0.c	Thu Dec  9 15:34:07 1999
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bds0.c,v 1.9 1999/07/01 08:11:35 keil Exp $
+/* $Id: hfc_2bds0.c,v 1.10 1999/10/14 20:25:28 keil Exp $
  *
  *  specific routines for CCD's HFC 2BDS0
  *
@@ -6,6 +6,9 @@
  *
  *
  * $Log: hfc_2bds0.c,v $
+ * Revision 1.10  1999/10/14 20:25:28  keil
+ * add a statistic for error monitoring
+ *
  * Revision 1.9  1999/07/01 08:11:35  keil
  * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
  *
@@ -260,6 +263,9 @@
 		if (cs->debug & L1_DEB_WARN)
 			debugl1(cs, "hfc_empty_fifo: incoming packet too small");
 		cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);
+#ifdef ERROR_STATISTIC
+		bcs->err_inv++;
+#endif
 		cli();
 		while ((idx++ < count) && WaitNoBusy(cs))
 			ReadReg(cs, HFCD_DATA_NODEB, cip);
@@ -302,6 +308,9 @@
 				debugl1(cs, "FIFO CRC error");
 				dev_kfree_skb(skb);
 				skb = NULL;
+#ifdef ERROR_STATISTIC
+				bcs->err_crc++;
+#endif
 			}
 		}
 	}
@@ -741,6 +750,9 @@
 				printk(KERN_WARNING "HFC DFIFO channel BUSY Error\n");
 				dev_kfree_skb(skb);
 				skb = NULL;
+#ifdef ERROR_STATISTIC
+				cs->err_rx++;
+#endif
 			} else {
 				cli();
 				WaitNoBusy(cs);
@@ -757,6 +769,9 @@
 					debugl1(cs, "FIFO CRC error");
 					dev_kfree_skb(skb);
 					skb = NULL;
+#ifdef ERROR_STATISTIC
+					cs->err_crc++;
+#endif
 				} else {
 					skb_queue_tail(&cs->rq, skb);
 					sched_event_D(cs, D_RCVBUFREADY);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/hfc_2bs0.c linux.14p16/drivers/isdn/hisax/hfc_2bs0.c
--- linux.vanilla/drivers/isdn/hisax/hfc_2bs0.c	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/hfc_2bs0.c	Thu Dec  9 15:34:07 1999
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bs0.c,v 1.9 1999/07/01 08:11:36 keil Exp $
+/* $Id: hfc_2bs0.c,v 1.10 1999/10/14 20:25:28 keil Exp $
 
  *  specific routines for CCD's HFC 2BS0
  *
@@ -6,6 +6,9 @@
  *
  *
  * $Log: hfc_2bs0.c,v $
+ * Revision 1.10  1999/10/14 20:25:28  keil
+ * add a statistic for error monitoring
+ *
  * Revision 1.9  1999/07/01 08:11:36  keil
  * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
  *
@@ -217,6 +220,9 @@
 		stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
 				       HFC_CHANNEL(bcs->channel));
 		WaitForBusy(cs);
+#ifdef ERROR_STATISTIC
+		bcs->err_inv++;
+#endif
 		return (NULL);
 	}
 	if (!(skb = dev_alloc_skb(count - 3)))
@@ -252,6 +258,9 @@
 			debugl1(cs, "FIFO CRC error");
 			dev_kfree_skb(skb);
 			skb = NULL;
+#ifdef ERROR_STATISTIC
+			bcs->err_crc++;
+#endif
 		}
 		WaitNoBusy(cs);
 		stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/hfc_pci.c linux.14p16/drivers/isdn/hisax/hfc_pci.c
--- linux.vanilla/drivers/isdn/hisax/hfc_pci.c	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/hfc_pci.c	Thu Dec  9 15:34:08 1999
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.c,v 1.20 1999/09/07 06:18:55 werner Exp $
+/* $Id: hfc_pci.c,v 1.23 1999/11/07 17:01:55 keil Exp $
 
  * hfc_pci.c     low level driver for CCD´s hfc-pci based cards
  *
@@ -23,6 +23,17 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: hfc_pci.c,v $
+ * Revision 1.23  1999/11/07 17:01:55  keil
+ * fix for 2.3 pci structs
+ *
+ * Revision 1.22  1999/10/10 20:14:27  werner
+ *
+ * Correct B2-chan usage in conjuntion with echo mode. First implementation of NT-leased line mode.
+ *
+ * Revision 1.21  1999/10/02 17:47:49  werner
+ *
+ * Changed init order, added correction for page alignment with shared mem
+ *
  * Revision 1.20  1999/09/07 06:18:55  werner
  *
  * Added io parameter for HFC-PCI based cards. Needed only with multiple cards
@@ -103,33 +114,36 @@
 
 extern const char *CardType[];
 
-static const char *hfcpci_revision = "$Revision: 1.20 $";
+static const char *hfcpci_revision = "$Revision: 1.23 $";
 
 /* table entry in the PCI devices list */
 typedef struct {
-  int vendor_id; 
-  int device_id;
-  char *vendor_name;
-  char *card_name;
-  } PCI_ENTRY;
-
-static const PCI_ENTRY id_list[] = {
-  {0x1397,0x2BD0,"CCD/Billion/Asuscom","2BD0"},
-  {0x1397,0xB000,"Billion","B000"},
-  {0x1397,0xB006,"Billion","B006"},
-  {0x1397,0xB007,"Billion","B007"},
-  {0x1397,0xB008,"Billion","B008"},
-  {0x1397,0xB009,"Billion","B009"},
-  {0x1397,0xB00A,"Billion","B00A"},
-  {0x1397,0xB00B,"Billion","B00B"},
-  {0x1397,0xB00C,"Billion","B00C"},
-  {0x1043,0x0675,"Asuscom/Askey","675"},
-  {0x0871,0xFFA2,"German telekom","T-Concept"},
-  {0x0871,0xFFA1,"German telekom","A1T"},
-  {0x1051,0x0100,"Motorola MC145575","MC145575"},
-  {0x1397,0xB100,"Seyeon","B100"},
-  {0x15B0,0x2BD0,"Zoltrix","2BD0"},
-  {0,0,NULL,NULL},      
+	int vendor_id;
+	int device_id;
+	char *vendor_name;
+	char *card_name;
+} PCI_ENTRY;
+
+#define NT_T1_COUNT 20		/* number of 3.125ms interrupts for G2 timeout */
+
+static const PCI_ENTRY id_list[] =
+{
+	{0x1397, 0x2BD0, "CCD/Billion/Asuscom", "2BD0"},
+	{0x1397, 0xB000, "Billion", "B000"},
+	{0x1397, 0xB006, "Billion", "B006"},
+	{0x1397, 0xB007, "Billion", "B007"},
+	{0x1397, 0xB008, "Billion", "B008"},
+	{0x1397, 0xB009, "Billion", "B009"},
+	{0x1397, 0xB00A, "Billion", "B00A"},
+	{0x1397, 0xB00B, "Billion", "B00B"},
+	{0x1397, 0xB00C, "Billion", "B00C"},
+	{0x1043, 0x0675, "Asuscom/Askey", "675"},
+	{0x0871, 0xFFA2, "German telekom", "T-Concept"},
+	{0x0871, 0xFFA1, "German telekom", "A1T"},
+	{0x1051, 0x0100, "Motorola MC145575", "MC145575"},
+	{0x1397, 0xB100, "Seyeon", "B100"},
+	{0x15B0, 0x2BD0, "Zoltrix", "2BD0"},
+	{0, 0, NULL, NULL},
 };
 
 
@@ -156,9 +170,21 @@
 void
 release_io_hfcpci(struct IsdnCardState *cs)
 {
+	int flags;
+
+	save_flags(flags);
+	cli();
+	cs->hw.hfcpci.int_m2 = 0;	/* interrupt output off ! */
+	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
+	restore_flags(flags);
+	Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET);	/* Reset On */
+	sti();
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
+	Write_hfc(cs, HFCPCI_CIRM, 0);	/* Reset Off */
 #if CONFIG_PCI
-	pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0);	/* disabe memory mapped ports + busmaster */
-#endif	/* CONFIG_PCI */
+	pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0);	/* disable memory mapped ports + busmaster */
+#endif				/* CONFIG_PCI */
 	releasehfcpci(cs);
 	del_timer(&cs->hw.hfcpci.timer);
 	kfree(cs->hw.hfcpci.share_start);
@@ -175,11 +201,15 @@
 {
 	long flags;
 
+	save_flags(flags);
+	cli();
 	pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO);	/* enable memory mapped ports, disable busmaster */
+	cs->hw.hfcpci.int_m2 = 0;	/* interrupt output off ! */
+	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
+
 	printk(KERN_INFO "HFC_PCI: resetting card\n");
 	pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER);	/* enable memory ports + busmaster */
 	Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET);	/* Reset On */
-	save_flags(flags);
 	sti();
 	current->state = TASK_INTERRUPTIBLE;
 	schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
@@ -192,25 +222,23 @@
 	cs->hw.hfcpci.fifo_en = 0x30;	/* only D fifos enabled */
 	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
 
-	cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */
+	cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK;	/* no echo connect , threshold */
 	Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
 
 	Write_hfc(cs, HFCPCI_CLKDEL, 0x0e);	/* ST-Bit delay for TE-Mode */
 	cs->hw.hfcpci.sctrl_e = HFCPCI_AUTO_AWAKE;
 	Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e);	/* S/T Auto awake */
-	cs->hw.hfcpci.bswapped = 0; /* no exchange */
+	cs->hw.hfcpci.bswapped = 0;	/* no exchange */
+	cs->hw.hfcpci.nt_mode = 0;	/* we are in TE mode */
 	cs->hw.hfcpci.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER;
 	Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
 
-	cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE;
-	cs->hw.hfcpci.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC | 
-	                       HFCPCI_INTS_L1STATE | HFCPCI_CLTIMER;
+	cs->hw.hfcpci.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC |
+	    HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER;
 	Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
-	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
 
 	/* Clear already pending ints */
 	if (Read_hfc(cs, HFCPCI_INT_S1));
-	if (Read_hfc(cs, HFCPCI_INT_S2));
 
 	Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 2);	/* HFC ST 2 */
 	udelay(10);
@@ -218,24 +246,29 @@
 	cs->hw.hfcpci.mst_m = HFCPCI_MASTER;	/* HFC Master Mode */
 
 	Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
-	cs->hw.hfcpci.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */
+	cs->hw.hfcpci.sctrl = 0x40;	/* set tx_lo mode, error in datasheet ! */
 	Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
 	cs->hw.hfcpci.sctrl_r = 0;
 	Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
 
-        /* Init GCI/IOM2 in master mode */
+	/* Init GCI/IOM2 in master mode */
 	/* Slots 0 and 1 are set for B-chan 1 and 2 */
 	/* D- and monitor/CI channel are not enabled */
 	/* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */
-	/* STIO2 is used as data input, B1+B2 from IOM->ST */ 
+	/* STIO2 is used as data input, B1+B2 from IOM->ST */
 	/* ST B-channel send disabled -> continous 1s */
 	/* The IOM slots are always enabled */
-	cs->hw.hfcpci.conn = 0x36; /* set data flow directions */
+	cs->hw.hfcpci.conn = 0x36;	/* set data flow directions */
 	Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
-	Write_hfc(cs, HFCPCI_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */
-	Write_hfc(cs, HFCPCI_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */
-	Write_hfc(cs, HFCPCI_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */
-	Write_hfc(cs, HFCPCI_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */
+	Write_hfc(cs, HFCPCI_B1_SSL, 0x80);	/* B1-Slot 0 STIO1 out enabled */
+	Write_hfc(cs, HFCPCI_B2_SSL, 0x81);	/* B2-Slot 1 STIO1 out enabled */
+	Write_hfc(cs, HFCPCI_B1_RSL, 0x80);	/* B1-Slot 0 STIO2 in enabled */
+	Write_hfc(cs, HFCPCI_B2_RSL, 0x81);	/* B2-Slot 1 STIO2 in enabled */
+
+	/* Finally enable IRQ output */
+	cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE;
+	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
+	if (Read_hfc(cs, HFCPCI_INT_S2));
 	restore_flags(flags);
 }
 
@@ -326,7 +359,7 @@
 		count -= 3;
 		ptr = skb_put(skb, count);
 
- 		if (zp->z2 + count <= B_FIFO_SIZE + B_SUB_VAL)
+		if (zp->z2 + count <= B_FIFO_SIZE + B_SUB_VAL)
 			maxlen = count;		/* complete transfer */
 		else
 			maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2;	/* maximum */
@@ -418,54 +451,56 @@
 /*******************************************************************************/
 /* check for transparent receive data and read max one threshold size if avail */
 /*******************************************************************************/
-int hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type *bz, u_char *bdata)
-{ unsigned short *z1r, *z2r;
-  int new_z2, fcnt, maxlen;
-  struct sk_buff *skb;
-  u_char *ptr, *ptr1;
-
-  z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */
-  z2r = z1r + 1; 
-
-  if (!(fcnt = *z1r - *z2r)) 
-    return(0); /* no data avail */
-
-  if (fcnt <= 0) 
-    fcnt += B_FIFO_SIZE; /* bytes actually buffered */  
-  if (fcnt > HFCPCI_BTRANS_THRESHOLD)
-    fcnt = HFCPCI_BTRANS_THRESHOLD; /* limit size */
-
-  new_z2 = *z2r + fcnt;	/* new position in fifo */
-  if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
-    new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
+int
+hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type * bz, u_char * bdata)
+{
+	unsigned short *z1r, *z2r;
+	int new_z2, fcnt, maxlen;
+	struct sk_buff *skb;
+	u_char *ptr, *ptr1;
+
+	z1r = &bz->za[MAX_B_FRAMES].z1;		/* pointer to z reg */
+	z2r = z1r + 1;
+
+	if (!(fcnt = *z1r - *z2r))
+		return (0);	/* no data avail */
+
+	if (fcnt <= 0)
+		fcnt += B_FIFO_SIZE;	/* bytes actually buffered */
+	if (fcnt > HFCPCI_BTRANS_THRESHOLD)
+		fcnt = HFCPCI_BTRANS_THRESHOLD;		/* limit size */
+
+	new_z2 = *z2r + fcnt;	/* new position in fifo */
+	if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
+		new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
 
-  if (!(skb = dev_alloc_skb(fcnt)))
+	if (!(skb = dev_alloc_skb(fcnt)))
 		printk(KERN_WARNING "HFCPCI: receive out of memory\n");
-  else {
-    ptr = skb_put(skb, fcnt);
-    if (*z2r + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
-      maxlen = fcnt; /* complete transfer */
-    else
-      maxlen = B_FIFO_SIZE + B_SUB_VAL - *z2r;	/* maximum */
-
-    ptr1 = bdata + (*z2r - B_SUB_VAL);	/* start of data */
-    memcpy(ptr, ptr1, maxlen);	/* copy data */
-    fcnt -= maxlen;
-
-    if (fcnt) {	/* rest remaining */
-      ptr += maxlen;
-      ptr1 = bdata;	/* start of buffer */
-      memcpy(ptr, ptr1, fcnt);	/* rest */
-    }
-    cli();
-    skb_queue_tail(&bcs->rqueue, skb);
-    sti();
-    hfcpci_sched_event(bcs, B_RCVBUFREADY); 
-  }
-  
-  *z2r = new_z2; /* new position */
-  return(1);
-} /* hfcpci_empty_fifo_trans */ 
+	else {
+		ptr = skb_put(skb, fcnt);
+		if (*z2r + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
+			maxlen = fcnt;	/* complete transfer */
+		else
+			maxlen = B_FIFO_SIZE + B_SUB_VAL - *z2r;	/* maximum */
+
+		ptr1 = bdata + (*z2r - B_SUB_VAL);	/* start of data */
+		memcpy(ptr, ptr1, maxlen);	/* copy data */
+		fcnt -= maxlen;
+
+		if (fcnt) {	/* rest remaining */
+			ptr += maxlen;
+			ptr1 = bdata;	/* start of buffer */
+			memcpy(ptr, ptr1, fcnt);	/* rest */
+		}
+		cli();
+		skb_queue_tail(&bcs->rqueue, skb);
+		sti();
+		hfcpci_sched_event(bcs, B_RCVBUFREADY);
+	}
+
+	*z2r = new_z2;		/* new position */
+	return (1);
+}				/* hfcpci_empty_fifo_trans */
 
 /**********************************/
 /* B-channel main receive routine */
@@ -526,11 +561,10 @@
 			receive = 1;
 		else
 			receive = 0;
-	} else 
-	  if (bcs->mode == L1_MODE_TRANS)
-	    receive = hfcpci_empty_fifo_trans(bcs, bz, bdata);
-	  else
-	    receive = 0;
+	} else if (bcs->mode == L1_MODE_TRANS)
+		receive = hfcpci_empty_fifo_trans(bcs, bz, bdata);
+	else
+		receive = 0;
 	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
 	if (count && receive)
 		goto Begin;
@@ -622,7 +656,7 @@
 	bzfifo_type *bz;
 	u_char *bdata;
 	u_char new_f1, *src, *dst;
-        unsigned short *z1t, *z2t;
+	unsigned short *z1t, *z2t;
 
 	if (!bcs->tx_skb)
 		return;
@@ -641,57 +675,53 @@
 	}
 
 	if (bcs->mode == L1_MODE_TRANS) {
-	  z1t = &bz->za[MAX_B_FRAMES].z1;
-	  z2t = z1t + 1;
-	  if (cs->debug & L1_DEB_HSCX)
-	          debugl1(cs, "hfcpci_fill_fifo_trans %d z1(%x) z2(%x)",
-		  bcs->channel, *z1t, *z2t);
-	  fcnt = *z2t - *z1t;
-	  if (fcnt <= 0)
-	          fcnt += B_FIFO_SIZE;	/* fcnt contains available bytes in fifo */
-	  fcnt = B_FIFO_SIZE - fcnt; /* remaining bytes to send */
-
-	  while ((fcnt < 2 * HFCPCI_BTRANS_THRESHOLD) && (bcs->tx_skb)) {
-	    if (bcs->tx_skb->len < B_FIFO_SIZE - fcnt) { 
-	      /* data is suitable for fifo */
-	      count = bcs->tx_skb->len;
-
-	      new_z1 = *z1t + count;	/* new buffer Position */
-	      if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
-		new_z1 -= B_FIFO_SIZE;	/* buffer wrap */
-	      src = bcs->tx_skb->data;	/* source pointer */
-	      dst = bdata + (*z1t - B_SUB_VAL);
-	      maxlen = (B_FIFO_SIZE + B_SUB_VAL) - *z1t; /* end of fifo */
-	      if (maxlen > count)
-		maxlen = count;	/* limit size */
-	      memcpy(dst, src, maxlen);	/* first copy */
+		z1t = &bz->za[MAX_B_FRAMES].z1;
+		z2t = z1t + 1;
+		if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "hfcpci_fill_fifo_trans %d z1(%x) z2(%x)",
+				bcs->channel, *z1t, *z2t);
+		fcnt = *z2t - *z1t;
+		if (fcnt <= 0)
+			fcnt += B_FIFO_SIZE;	/* fcnt contains available bytes in fifo */
+		fcnt = B_FIFO_SIZE - fcnt;	/* remaining bytes to send */
+
+		while ((fcnt < 2 * HFCPCI_BTRANS_THRESHOLD) && (bcs->tx_skb)) {
+			if (bcs->tx_skb->len < B_FIFO_SIZE - fcnt) {
+				/* data is suitable for fifo */
+				count = bcs->tx_skb->len;
+
+				new_z1 = *z1t + count;	/* new buffer Position */
+				if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
+					new_z1 -= B_FIFO_SIZE;	/* buffer wrap */
+				src = bcs->tx_skb->data;	/* source pointer */
+				dst = bdata + (*z1t - B_SUB_VAL);
+				maxlen = (B_FIFO_SIZE + B_SUB_VAL) - *z1t;	/* end of fifo */
+				if (maxlen > count)
+					maxlen = count;		/* limit size */
+				memcpy(dst, src, maxlen);	/* first copy */
+
+				count -= maxlen;	/* remaining bytes */
+				if (count) {
+					dst = bdata;	/* start of buffer */
+					src += maxlen;	/* new position */
+					memcpy(dst, src, count);
+				}
+				bcs->tx_cnt -= bcs->tx_skb->len;
+				fcnt += bcs->tx_skb->len;
+				*z1t = new_z1;	/* now send data */
+			} else if (cs->debug & L1_DEB_HSCX)
+				debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded",
+					bcs->channel, bcs->tx_skb->len);
 
-	      count -= maxlen;	/* remaining bytes */
-	      if (count) {
-		dst = bdata;	/* start of buffer */
-		src += maxlen;	/* new position */
-		memcpy(dst, src, count);
-	      }
-	      bcs->tx_cnt -= bcs->tx_skb->len;
-	      fcnt += bcs->tx_skb->len;
-	      *z1t = new_z1; /* now send data */
-	    }
-            else 
-	      if (cs->debug & L1_DEB_HSCX)
-		debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded",
-			bcs->channel, bcs->tx_skb->len);
-
-	    dev_kfree_skb(bcs->tx_skb);
-            cli();
-            bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */
-            sti();
-	  }  
-	  test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
-	  restore_flags(flags);
-	  return;
+			dev_kfree_skb(bcs->tx_skb);
+			cli();
+			bcs->tx_skb = skb_dequeue(&bcs->squeue);	/* fetch next data */
+			sti();
+		}
+		test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+		restore_flags(flags);
+		return;
 	}
-
-
 	if (cs->debug & L1_DEB_HSCX)
 		debugl1(cs, "hfcpci_fill_fifo_hdlc %d f1(%d) f2(%d) z1(f1)(%x)",
 			bcs->channel, bz->f1, bz->f2,
@@ -757,51 +787,107 @@
 	return;
 }
 
+/**********************************************/
+/* D-channel l1 state call for leased NT-mode */
+/**********************************************/
+static void
+dch_nt_l2l1(struct PStack *st, int pr, void *arg)
+{
+	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+
+	switch (pr) {
+		case (PH_DATA | REQUEST):
+		case (PH_PULL | REQUEST):
+		case (PH_PULL | INDICATION):
+			st->l1.l1hw(st, pr, arg);
+			break;
+		case (PH_ACTIVATE | REQUEST):
+			st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+			break;
+		case (PH_TESTLOOP | REQUEST):
+			if (1 & (long) arg)
+				debugl1(cs, "PH_TEST_LOOP B1");
+			if (2 & (long) arg)
+				debugl1(cs, "PH_TEST_LOOP B2");
+			if (!(3 & (long) arg))
+				debugl1(cs, "PH_TEST_LOOP DISABLED");
+			st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg);
+			break;
+		default:
+			if (cs->debug)
+				debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr);
+			break;
+	}
+}
+
+
+
 /***********************/
 /* set/reset echo mode */
-/***********************/ 
+/***********************/
 static int
-hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic)
+hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic)
 {
-  int flags;
-  int i = *(unsigned int *) ic->parm.num;
-  
-  if (cs->chanlimit > 1)
-    return(-EINVAL);
-
-  save_flags(flags);
-  cli();
-  if (i) {
-    cs->logecho = 1;
-    cs->hw.hfcpci.trm |= 0x20; /* enable echo chan */
-    cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_B2REC;
-    cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2RX;
-  }
-  else {
-    cs->logecho = 0;
-    cs->hw.hfcpci.trm &= ~0x20; /* enable echo chan */
-    cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_B2REC;
-    cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2RX;
-  }
-    cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA;
-    cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA;
-    cs->hw.hfcpci.conn |= 0x10; /* B2-IOM -> B2-ST */ 
-    cs->hw.hfcpci.ctmt &= ~2;
-  Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
-  Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
-  Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
-  Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
-  Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
-  Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
-  Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
-  restore_flags(flags);
-  return(0);
-} /* hfcpci_auxcmd */ 
+	int flags;
+	int i = *(unsigned int *) ic->parm.num;
+
+	if ((ic->arg == 98) &&
+	    (!(cs->hw.hfcpci.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) {
+		save_flags(flags);
+		cli();
+		Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0);	/* HFC ST G0 */
+		udelay(10);
+		cs->hw.hfcpci.sctrl |= SCTRL_MODE_NT;
+		Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);	/* set NT-mode */
+		udelay(10);
+		Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 1);	/* HFC ST G1 */
+		udelay(10);
+		Write_hfc(cs, HFCPCI_STATES, 1 | HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
+		cs->dc.hfcpci.ph_state = 1;
+		cs->hw.hfcpci.nt_mode = 1;
+		cs->hw.hfcpci.nt_timer = 0;
+		cs->stlist->l2.l2l1 = dch_nt_l2l1;
+		restore_flags(flags);
+		debugl1(cs, "NT mode activated");
+		return (0);
+	}
+	if ((cs->chanlimit > 1) || (cs->hw.hfcpci.bswapped) ||
+	    (cs->hw.hfcpci.nt_mode) || (ic->arg != 12))
+		return (-EINVAL);
+
+	save_flags(flags);
+	cli();
+	if (i) {
+		cs->logecho = 1;
+		cs->hw.hfcpci.trm |= 0x20;	/* enable echo chan */
+		cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_B2REC;
+		cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2RX;
+	} else {
+		cs->logecho = 0;
+		cs->hw.hfcpci.trm &= ~0x20;	/* disable echo chan */
+		cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_B2REC;
+		cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2RX;
+	}
+	cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA;
+	cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA;
+	cs->hw.hfcpci.conn |= 0x10;	/* B2-IOM -> B2-ST */
+	cs->hw.hfcpci.ctmt &= ~2;
+	Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
+	Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
+	Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
+	Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
+	Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
+	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
+	Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+	restore_flags(flags);
+	return (0);
+}				/* hfcpci_auxcmd */
 
 /*****************************/
 /* E-channel receive routine */
 /*****************************/
-static void receive_emsg(struct IsdnCardState *cs)
+static void
+receive_emsg(struct IsdnCardState *cs)
 {
 	long flags;
 	int rcnt;
@@ -838,55 +924,54 @@
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "hfcpci e_rec z1(%x) z2(%x) cnt(%d)",
 				zp->z1, zp->z2, rcnt);
-                new_z2 = zp->z2 + rcnt; /* new position in fifo */
+		new_z2 = zp->z2 + rcnt;		/* new position in fifo */
 		if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
-		  new_z2 -= B_FIFO_SIZE; /* buffer wrap */
+			new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
 		new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
-	        if ((rcnt > 256 + 3) || (count < 4) ||
+		if ((rcnt > 256 + 3) || (count < 4) ||
 		    (*(bdata + (zp->z1 - B_SUB_VAL)))) {
-		  if (cs->debug & L1_DEB_WARN)
-			debugl1(cs, "hfcpci_empty_echan: incoming packet invalid length %d or crc", rcnt);
-		  bz->za[new_f2].z2 = new_z2;
-		  bz->f2 = new_f2;	/* next buffer */
+			if (cs->debug & L1_DEB_WARN)
+				debugl1(cs, "hfcpci_empty_echan: incoming packet invalid length %d or crc", rcnt);
+			bz->za[new_f2].z2 = new_z2;
+			bz->f2 = new_f2;	/* next buffer */
 		} else {
-		    total = rcnt;
-		    rcnt -= 3;
-		    ptr = e_buffer;
-
-		    if (zp->z2 <= B_FIFO_SIZE + B_SUB_VAL)
-			maxlen = rcnt;		/* complete transfer */
-		    else
-			maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2;	/* maximum */
+			total = rcnt;
+			rcnt -= 3;
+			ptr = e_buffer;
 
-		    ptr1 = bdata + (zp->z2 - B_SUB_VAL);	/* start of data */
-		    memcpy(ptr, ptr1, maxlen);	/* copy data */
-		    rcnt -= maxlen;
+			if (zp->z2 <= B_FIFO_SIZE + B_SUB_VAL)
+				maxlen = rcnt;	/* complete transfer */
+			else
+				maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2;	/* maximum */
 
-		    if (rcnt) {	/* rest remaining */
-			ptr += maxlen;
-			ptr1 = bdata;	/* start of buffer */
-			memcpy(ptr, ptr1, rcnt);	/* rest */
-		    }
-		    bz->za[new_f2].z2 = new_z2;
-		    bz->f2 = new_f2;	/* next buffer */
-		    if (cs->debug & DEB_DLOG_HEX) {
-		      	ptr = cs->dlog;
-			if ((total - 3) < MAX_DLOG_SPACE / 3 - 10) {
-			  *ptr++ = 'E';
-			  *ptr++ = 'C';
-			  *ptr++ = 'H';
-			  *ptr++ = 'O';
-			  *ptr++ = ':';
-			  ptr += QuickHex(ptr, e_buffer, total - 3);
-			  ptr--;
-			  *ptr++ = '\n';
-			  *ptr = 0;
-			  HiSax_putstatus(cs, NULL, cs->dlog);
-			} else
-			  HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3);
-		    }
+			ptr1 = bdata + (zp->z2 - B_SUB_VAL);	/* start of data */
+			memcpy(ptr, ptr1, maxlen);	/* copy data */
+			rcnt -= maxlen;
 
-	}
+			if (rcnt) {	/* rest remaining */
+				ptr += maxlen;
+				ptr1 = bdata;	/* start of buffer */
+				memcpy(ptr, ptr1, rcnt);	/* rest */
+			}
+			bz->za[new_f2].z2 = new_z2;
+			bz->f2 = new_f2;	/* next buffer */
+			if (cs->debug & DEB_DLOG_HEX) {
+				ptr = cs->dlog;
+				if ((total - 3) < MAX_DLOG_SPACE / 3 - 10) {
+					*ptr++ = 'E';
+					*ptr++ = 'C';
+					*ptr++ = 'H';
+					*ptr++ = 'O';
+					*ptr++ = ':';
+					ptr += QuickHex(ptr, e_buffer, total - 3);
+					ptr--;
+					*ptr++ = '\n';
+					*ptr = 0;
+					HiSax_putstatus(cs, NULL, cs->dlog);
+				} else
+					HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3);
+			}
+		}
 
 		rcnt = bz->f1 - bz->f2;
 		if (rcnt < 0)
@@ -902,7 +987,7 @@
 		goto Begin;
 	restore_flags(flags);
 	return;
-} /* receive_emsg */
+}				/* receive_emsg */
 
 /*********************/
 /* Interrupt handler */
@@ -921,6 +1006,9 @@
 		printk(KERN_WARNING "HFC-PCI: Spurious interrupt!\n");
 		return;
 	}
+	if (!(cs->hw.hfcpci.int_m2 & 0x08))
+		return;		/* not initialised */
+
 	if (HFCPCI_ANYINT & (stat = Read_hfc(cs, HFCPCI_STATUS))) {
 		val = Read_hfc(cs, HFCPCI_INT_S1);
 		if (cs->debug & L1_DEB_ISAC)
@@ -933,7 +1021,7 @@
 			test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
 			"locked" : "unlocked");
 	val &= cs->hw.hfcpci.int_m1;
-	if (val & 0x40) {	/* TE state machine irq */
+	if (val & 0x40) {	/* state machine irq */
 		exval = Read_hfc(cs, HFCPCI_STATES) & 0xf;
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcpci.ph_state,
@@ -942,6 +1030,14 @@
 		sched_event_D_pci(cs, D_L1STATECHANGE);
 		val &= ~0x40;
 	}
+	if (val & 0x80) {	/* timer irq */
+		if (cs->hw.hfcpci.nt_mode) {
+			if ((--cs->hw.hfcpci.nt_timer) < 0)
+				sched_event_D_pci(cs, D_L1STATECHANGE);
+		}
+		val &= ~0x80;
+		Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER);
+	}
 	while (val) {
 		save_flags(flags);
 		cli();
@@ -956,24 +1052,23 @@
 			cs->hw.hfcpci.int_s1 = exval;
 		}
 		if (val & 0x08) {
-			if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1:0))) {
+			if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1 : 0))) {
 				if (cs->debug)
 					debugl1(cs, "hfcpci spurious 0x08 IRQ");
 			} else
 				main_rec_hfcpci(bcs);
 		}
-		if (val & 0x10) { 
-		        if (cs->logecho)
-			  receive_emsg(cs);
-			else    
-			if (!(bcs = Sel_BCS(cs, 1))) {
+		if (val & 0x10) {
+			if (cs->logecho)
+				receive_emsg(cs);
+			else if (!(bcs = Sel_BCS(cs, 1))) {
 				if (cs->debug)
 					debugl1(cs, "hfcpci spurious 0x10 IRQ");
 			} else
 				main_rec_hfcpci(bcs);
 		}
 		if (val & 0x01) {
-			if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1:0))) {
+			if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1 : 0))) {
 				if (cs->debug)
 					debugl1(cs, "hfcpci spurious 0x01 IRQ");
 			} else {
@@ -1082,6 +1177,7 @@
 {
 	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
 	struct sk_buff *skb = arg;
+	int flags;
 
 	switch (pr) {
 		case (PH_DATA | REQUEST):
@@ -1157,13 +1253,46 @@
 			Write_hfc(cs, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
 			break;
 		case (HW_DEACTIVATE | REQUEST):
-      			cs->hw.hfcpci.mst_m &= ~HFCPCI_MASTER;
+			cs->hw.hfcpci.mst_m &= ~HFCPCI_MASTER;
 			Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
 			break;
 		case (HW_INFO3 | REQUEST):
 			cs->hw.hfcpci.mst_m |= HFCPCI_MASTER;
 			Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
 			break;
+		case (HW_TESTLOOP | REQUEST):
+			switch ((int) arg) {
+				case (1):
+					Write_hfc(cs, HFCPCI_B1_SSL, 0x80);	/* tx slot */
+					Write_hfc(cs, HFCPCI_B1_RSL, 0x80);	/* rx slot */
+					save_flags(flags);
+					cli();
+					cs->hw.hfcpci.conn = (cs->hw.hfcpci.conn & ~7) | 1;
+					Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
+					restore_flags(flags);
+					break;
+
+				case (2):
+					Write_hfc(cs, HFCPCI_B2_SSL, 0x81);	/* tx slot */
+					Write_hfc(cs, HFCPCI_B2_RSL, 0x81);	/* rx slot */
+					save_flags(flags);
+					cli();
+					cs->hw.hfcpci.conn = (cs->hw.hfcpci.conn & ~0x38) | 0x08;
+					Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
+					restore_flags(flags);
+					break;
+
+				default:
+					if (cs->debug & L1_DEB_WARN)
+						debugl1(cs, "hfcpci_l1hw loop invalid %4x", (int) arg);
+					return;
+			}
+			save_flags(flags);
+			cli();
+			cs->hw.hfcpci.trm |= 0x80;	/* enable IOM-loop */
+			Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
+			restore_flags(flags);
+			break;
 		default:
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "hfcpci_l1hw unknown pr %4x", pr);
@@ -1203,113 +1332,127 @@
 {
 	struct IsdnCardState *cs = bcs->cs;
 	bzfifo_type *bzr, *bzt;
-	int flags;
+	int flags, fifo2;
 
 	if (cs->debug & L1_DEB_HSCX)
 		debugl1(cs, "HFCPCI bchannel mode %d bchan %d/%d",
 			mode, bc, bcs->channel);
 	bcs->mode = mode;
 	bcs->channel = bc;
-	if (cs->chanlimit > 1) { 
-	  cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */
-	  cs->hw.hfcpci.sctrl_e &= ~0x80; 
-	}
-	else {
-	  if (bc) {
-	    cs->hw.hfcpci.bswapped = 1; /* B1 and B2 exchanged */
-	    cs->hw.hfcpci.sctrl_e |= 0x80;
-	    bc = 0; /* B1 controller used */
-	  }
-	  else {
-	    cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */
-	    cs->hw.hfcpci.sctrl_e &= ~0x80; 
-	  }  
-	}  
+	fifo2 = bc;
 	save_flags(flags);
 	cli();
+	if (cs->chanlimit > 1) {
+		cs->hw.hfcpci.bswapped = 0;	/* B1 and B2 normal mode */
+		cs->hw.hfcpci.sctrl_e &= ~0x80;
+	} else {
+		if (bc) {
+			if (mode != L1_MODE_NULL) {
+				cs->hw.hfcpci.bswapped = 1;	/* B1 and B2 exchanged */
+				cs->hw.hfcpci.sctrl_e |= 0x80;
+			} else {
+				cs->hw.hfcpci.bswapped = 0;	/* B1 and B2 normal mode */
+				cs->hw.hfcpci.sctrl_e &= ~0x80;
+			}
+			fifo2 = 0;
+		} else {
+			cs->hw.hfcpci.bswapped = 0;	/* B1 and B2 normal mode */
+			cs->hw.hfcpci.sctrl_e &= ~0x80;
+		}
+	}
 	switch (mode) {
 		case (L1_MODE_NULL):
 			if (bc) {
 				cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA;
 				cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA;
-				cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2;
-				cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC);
 			} else {
 				cs->hw.hfcpci.sctrl &= ~SCTRL_B1_ENA;
 				cs->hw.hfcpci.sctrl_r &= ~SCTRL_B1_ENA;
+			}
+			if (fifo2) {
+				cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2;
+				cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
+			} else {
 				cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1;
-				cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC);
+				cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
 			}
 			break;
 		case (L1_MODE_TRANS):
 			if (bc) {
-				cs->hw.hfcpci.ctmt |= 2;
-				cs->hw.hfcpci.conn &= ~0x18;
 				cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
 				cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
-				cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
-				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC);
-		                bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
-		                bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2;
 			} else {
-				cs->hw.hfcpci.ctmt |= 1;
-				cs->hw.hfcpci.conn &= ~0x03;
 				cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
 				cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
+			}
+			if (fifo2) {
+				cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
+				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
+				cs->hw.hfcpci.ctmt |= 2;
+				cs->hw.hfcpci.conn &= ~0x18;
+				bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
+				bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2;
+			} else {
 				cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1;
-				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC);
-		                bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1;
-		                bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1;
+				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
+				cs->hw.hfcpci.ctmt |= 1;
+				cs->hw.hfcpci.conn &= ~0x03;
+				bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1;
+				bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1;
 			}
 			bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
-                        bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1; 
+			bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1;
 			bzr->f1 = MAX_B_FRAMES;
-			bzr->f2 = bzr->f1; /* init F pointers to remain constant */
+			bzr->f2 = bzr->f1;	/* init F pointers to remain constant */
 			bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
-                        bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1; 
+			bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1;
 			bzt->f1 = MAX_B_FRAMES;
-			bzt->f2 = bzt->f1; /* init F pointers to remain constant */
+			bzt->f2 = bzt->f1;	/* init F pointers to remain constant */
 			break;
 		case (L1_MODE_HDLC):
 			if (bc) {
-				cs->hw.hfcpci.ctmt &= ~2;
-				cs->hw.hfcpci.conn &= ~0x18;
 				cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
 				cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
-				cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
-				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC);
 			} else {
-				cs->hw.hfcpci.ctmt &= ~1;
-				cs->hw.hfcpci.conn &= ~0x3;
 				cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
 				cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
+			}
+			if (fifo2) {
+				cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
+				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
+				cs->hw.hfcpci.ctmt &= ~2;
+				cs->hw.hfcpci.conn &= ~0x18;
+			} else {
 				cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1;
-				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC);
+				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
+				cs->hw.hfcpci.ctmt &= ~1;
+				cs->hw.hfcpci.conn &= ~0x03;
 			}
 			break;
 		case (L1_MODE_EXTRN):
 			if (bc) {
-			        cs->hw.hfcpci.conn |= 0x10;
+				cs->hw.hfcpci.conn |= 0x10;
 				cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
 				cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
 				cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2;
-				cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC);
+				cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
 			} else {
-			        cs->hw.hfcpci.conn |= 0x02;
+				cs->hw.hfcpci.conn |= 0x02;
 				cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
 				cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
 				cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1;
-				cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC);
+				cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
 			}
 			break;
 	}
+	Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e);
 	Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
-	restore_flags(flags);
 	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
 	Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
 	Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
 	Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
 	Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
+	restore_flags(flags);
 }
 
 /******************************/
@@ -1429,29 +1572,72 @@
 static void
 hfcpci_bh(struct IsdnCardState *cs)
 {
+	int flags;
 /*      struct PStack *stptr;
  */
 	if (!cs)
 		return;
 	if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
-		switch (cs->dc.hfcpci.ph_state) {
-			case (0):
-				l1_msg(cs, HW_RESET | INDICATION, NULL);
-				break;
-			case (3):
-				l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
-				break;
-			case (8):
-				l1_msg(cs, HW_RSYNC | INDICATION, NULL);
-				break;
-			case (6):
-				l1_msg(cs, HW_INFO2 | INDICATION, NULL);
-				break;
-			case (7):
-				l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
-				break;
-			default:
-				break;
+		if (!cs->hw.hfcpci.nt_mode)
+			switch (cs->dc.hfcpci.ph_state) {
+				case (0):
+					l1_msg(cs, HW_RESET | INDICATION, NULL);
+					break;
+				case (3):
+					l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
+					break;
+				case (8):
+					l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+					break;
+				case (6):
+					l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+					break;
+				case (7):
+					l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+					break;
+				default:
+					break;
+		} else {
+			switch (cs->dc.hfcpci.ph_state) {
+				case (2):
+					save_flags(flags);
+					cli();
+					if (cs->hw.hfcpci.nt_timer < 0) {
+						cs->hw.hfcpci.nt_timer = 0;
+						cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
+						Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+						/* Clear already pending ints */
+						if (Read_hfc(cs, HFCPCI_INT_S1));
+
+						Write_hfc(cs, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE);
+						udelay(10);
+						Write_hfc(cs, HFCPCI_STATES, 4);
+						cs->dc.hfcpci.ph_state = 4;
+					} else {
+						cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_TIMER;
+						Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+						cs->hw.hfcpci.ctmt &= ~HFCPCI_AUTO_TIMER;
+						cs->hw.hfcpci.ctmt |= HFCPCI_TIM3_125;
+						Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER);
+						Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER);
+						cs->hw.hfcpci.nt_timer = NT_T1_COUNT;
+						Write_hfc(cs, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3);	/* allow G2 -> G3 transition */
+					}
+					restore_flags(flags);
+					break;
+				case (1):
+				case (3):
+				case (4):
+					save_flags(flags);
+					cli();
+					cs->hw.hfcpci.nt_timer = 0;
+					cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
+					Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+					restore_flags(flags);
+					break;
+				default:
+					break;
+			}
 		}
 	}
 	if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
@@ -1551,9 +1737,10 @@
 	   setup_hfcpci(struct IsdnCard *card))
 {
 	struct IsdnCardState *cs = card->cs;
+	unsigned short cmd;
 	char tmp[64];
 	int i;
-        struct pci_dev *tmp_hfcpci = NULL;
+	struct pci_dev *tmp_hfcpci = NULL;
 
 	strcpy(tmp, hfcpci_revision);
 	printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
@@ -1569,22 +1756,22 @@
 			return (0);
 		}
 		i = 0;
-                while (id_list[i].vendor_id) {
-		  tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
-					       id_list[i].device_id,
-					       dev_hfcpci);
-		  i++;
-		  if (tmp_hfcpci) {
-		    if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->base_address[0] & PCI_BASE_ADDRESS_IO_MASK)))
-		      continue;
-		    else
-		      break;
-		  }  
-		}  
-					      
+		while (id_list[i].vendor_id) {
+			tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
+						     id_list[i].device_id,
+						     dev_hfcpci);
+			i++;
+			if (tmp_hfcpci) {
+				if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->base_address[ 0] & PCI_BASE_ADDRESS_IO_MASK)))
+					continue;
+				else
+					break;
+			}
+		}
+
 		if (tmp_hfcpci) {
-		        i--;
-		        dev_hfcpci = tmp_hfcpci; /* old device */
+			i--;
+			dev_hfcpci = tmp_hfcpci;	/* old device */
 			cs->hw.hfcpci.pci_bus = dev_hfcpci->bus->number;
 			cs->hw.hfcpci.pci_device_fn = dev_hfcpci->devfn;
 			cs->irq = dev_hfcpci->irq;
@@ -1593,11 +1780,44 @@
 				return (0);
 			}
 			cs->hw.hfcpci.pci_io = (char *) dev_hfcpci->base_address[ 1];
-			printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n",id_list[i].vendor_name,id_list[i].card_name);
+			printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
 		} else {
 			printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
 			return (0);
 		}
+		if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) {
+			printk(KERN_WARNING "HFC-PCI shared mem address will be corrected\n");
+			pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
+					     cs->hw.hfcpci.pci_device_fn,
+						  PCI_COMMAND,
+						  0x0103);	/* set SERR */
+			pcibios_read_config_word(cs->hw.hfcpci.pci_bus,
+					     cs->hw.hfcpci.pci_device_fn,
+						 PCI_COMMAND,
+						 &cmd);
+			pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
+					     cs->hw.hfcpci.pci_device_fn,
+						  PCI_COMMAND,
+						  cmd & ~2);
+			(int) cs->hw.hfcpci.pci_io &= ~(PAGE_SIZE - 1);
+			pcibios_write_config_dword(cs->hw.hfcpci.pci_bus,
+					     cs->hw.hfcpci.pci_device_fn,
+						   PCI_BASE_ADDRESS_1,
+					     (int) cs->hw.hfcpci.pci_io);
+			pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
+					     cs->hw.hfcpci.pci_device_fn,
+						  PCI_COMMAND,
+						  cmd);
+			pcibios_read_config_dword(cs->hw.hfcpci.pci_bus,
+					     cs->hw.hfcpci.pci_device_fn,
+						  PCI_BASE_ADDRESS_1,
+					 (void *) &cs->hw.hfcpci.pci_io);
+			if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) {
+				printk(KERN_WARNING "HFC-PCI unable to align address %x\n", (unsigned) cs->hw.hfcpci.pci_io);
+				return (0);
+			}
+			dev_hfcpci->base_address[1] = (int) cs->hw.hfcpci.pci_io;
+		}
 		if (!cs->hw.hfcpci.pci_io) {
 			printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
 			return (0);
@@ -1613,16 +1833,16 @@
 		    (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000;
 		pcibios_write_config_dword(cs->hw.hfcpci.pci_bus,
 				       cs->hw.hfcpci.pci_device_fn, 0x80,
-					   (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
+			       (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
 		cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
 		printk(KERN_INFO
-		 "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n",
+		       "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n",
 		       (u_int) cs->hw.hfcpci.pci_io,
 		       (u_int) cs->hw.hfcpci.fifos,
 		       (u_int) virt_to_bus(cs->hw.hfcpci.fifos),
 		       cs->irq, HZ);
 		pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO);	/* enable memory mapped ports, disable busmaster */
-		cs->hw.hfcpci.int_m2 = 0; /* disable alle interrupts */
+		cs->hw.hfcpci.int_m2 = 0;	/* disable alle interrupts */
 		cs->hw.hfcpci.int_m1 = 0;
 		Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
 		Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
@@ -1647,7 +1867,7 @@
 
 	reset_hfcpci(cs);
 	cs->cardmsg = &hfcpci_card_msg;
-	cs->auxcmd  = &hfcpci_auxcmd;
+	cs->auxcmd = &hfcpci_auxcmd;
 	return (1);
 #else
 	printk(KERN_WARNING "HFC-PCI: NO_PCI_BIOS\n");
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/hfc_pci.h linux.14p16/drivers/isdn/hisax/hfc_pci.h
--- linux.vanilla/drivers/isdn/hisax/hfc_pci.h	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/hfc_pci.h	Thu Dec  9 15:34:08 1999
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.h,v 1.6 1999/08/28 21:04:29 werner Exp $
+/* $Id: hfc_pci.h,v 1.7 1999/10/10 20:13:06 werner Exp $
 
  *  specific defines for CCD's HFC 2BDS0 PCI chips
  *
@@ -21,6 +21,10 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: hfc_pci.h,v $
+ * Revision 1.7  1999/10/10 20:13:06  werner
+ *
+ * Corrected timer constant
+ *
  * Revision 1.6  1999/08/28 21:04:29  werner
  * Implemented full audio support (transparent mode)
  *
@@ -129,7 +133,7 @@
 
 /* bits in CTMT (Write) */
 #define HFCPCI_CLTIMER    0x80
-#define HFCPCI_TIM3_125   0x00
+#define HFCPCI_TIM3_125   0x04
 #define HFCPCI_TIM25      0x10
 #define HFCPCI_TIM50      0x14
 #define HFCPCI_TIM400     0x18
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/hisax.h linux.14p16/drivers/isdn/hisax/hisax.h
--- linux.vanilla/drivers/isdn/hisax/hisax.h	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/hisax.h	Tue Dec 21 01:10:18 1999
@@ -1,8 +1,18 @@
-/* $Id: hisax.h,v 2.35 1999/09/04 06:35:09 keil Exp $
+/* $Id: hisax.h,v 2.38 1999/11/14 23:37:03 keil Exp $
 
  *   Basic declarations, defines and prototypes
  *
  * $Log: hisax.h,v $
+ * Revision 2.38  1999/11/14 23:37:03  keil
+ * new ISA memory mapped IO
+ *
+ * Revision 2.37  1999/10/14 20:25:28  keil
+ * add a statistic for error monitoring
+ *
+ * Revision 2.36  1999/10/10 20:16:15  werner
+ *
+ * Added variable to hfcpci union.
+ *
  * Revision 2.35  1999/09/04 06:35:09  keil
  * Winbond W6692 support
  *
@@ -140,6 +150,8 @@
 #include <linux/tty.h>
 #include <linux/serial_reg.h>
 
+#undef ERROR_STATISTIC
+
 #define REQUEST		0
 #define CONFIRM		1
 #define INDICATION	2
@@ -581,6 +593,12 @@
 	int event;
 	int  (*BC_SetStack) (struct PStack *, struct BCState *);
 	void (*BC_Close) (struct BCState *);
+#ifdef ERROR_STATISTIC
+	int err_crc;
+	int err_tx;
+	int err_rdo;
+	int err_inv;
+#endif
 	union {
 		struct hscx_hw hscx;
 		struct hdlc_hw hdlc;
@@ -648,7 +666,8 @@
 
 struct teles0_hw {
 	unsigned int cfg_reg;
-	unsigned int membase;
+	unsigned long membase;
+	unsigned long phymem;
 };
 
 struct avm_hw {
@@ -755,7 +774,8 @@
 	unsigned char fifo;
         unsigned char fifo_en;
         unsigned char bswapped;
-  /*	unsigned int *send; */
+        unsigned char nt_mode;
+        int nt_timer;
 	unsigned char pci_bus;
         unsigned char pci_device_fn;
         unsigned char *pci_io; /* start of PCI IO memory */
@@ -787,8 +807,9 @@
 
 struct isurf_hw {
 	unsigned int reset;
-	unsigned int isac;
-	unsigned int isar;
+	unsigned long phymem;
+	unsigned long isac;
+	unsigned long isar;
 	struct isar_reg isar_r;
 };
 
@@ -961,6 +982,11 @@
 	int event;
 	struct tq_struct tqueue;
 	struct timer_list dbusytimer;
+#ifdef ERROR_STATISTIC
+	int err_crc;
+	int err_tx;
+	int err_rx;
+#endif
 };
 
 #define  MON0_RX	1
@@ -1355,7 +1381,7 @@
 int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb);
 void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...);
 void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args);
-void HiSax_reportcard(int cardnr);
+void HiSax_reportcard(int cardnr, int sel);
 int QuickHex(char *txt, u_char * p, int cnt);
 void LogFrame(struct IsdnCardState *cs, u_char * p, int size);
 void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/hscx_irq.c linux.14p16/drivers/isdn/hisax/hscx_irq.c
--- linux.vanilla/drivers/isdn/hisax/hscx_irq.c	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/hscx_irq.c	Thu Dec  9 15:34:08 1999
@@ -1,4 +1,4 @@
-/* $Id: hscx_irq.c,v 1.12 1999/07/01 08:11:42 keil Exp $
+/* $Id: hscx_irq.c,v 1.13 1999/10/14 20:25:28 keil Exp $
 
  * hscx_irq.c     low level b-channel stuff for Siemens HSCX
  *
@@ -7,6 +7,9 @@
  * This is an include file for fast inline IRQ stuff
  *
  * $Log: hscx_irq.c,v $
+ * Revision 1.13  1999/10/14 20:25:28  keil
+ * add a statistic for error monitoring
+ *
  * Revision 1.12  1999/07/01 08:11:42  keil
  * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
  *
@@ -181,16 +184,28 @@
 	if (val & 0x80) {	/* RME */
 		r = READHSCX(cs, hscx, HSCX_RSTA);
 		if ((r & 0xf0) != 0xa0) {
-			if (!(r & 0x80))
+			if (!(r & 0x80)) {
 				if (cs->debug & L1_DEB_WARN)
 					debugl1(cs, "HSCX invalid frame");
-			if ((r & 0x40) && bcs->mode)
+#ifdef ERROR_STATISTIC
+				bcs->err_inv++;
+#endif
+			}
+			if ((r & 0x40) && bcs->mode) {
 				if (cs->debug & L1_DEB_WARN)
 					debugl1(cs, "HSCX RDO mode=%d",
 						bcs->mode);
-			if (!(r & 0x20))
+#ifdef ERROR_STATISTIC
+				bcs->err_rdo++;
+#endif
+			}
+			if (!(r & 0x20)) {
 				if (cs->debug & L1_DEB_WARN)
 					debugl1(cs, "HSCX CRC error");
+#ifdef ERROR_STATISTIC
+				bcs->err_crc++;
+#endif
+			}
 			WriteHSCXCMDR(cs, hscx, 0x80);
 		} else {
 			count = READHSCX(cs, hscx, HSCX_RBCL) & (
@@ -265,6 +280,9 @@
 			if (bcs->mode == 1)
 				hscx_fill_fifo(bcs);
 			else {
+#ifdef ERROR_STATISTIC
+				bcs->err_tx++;
+#endif
 				/* Here we lost an TX interrupt, so
 				   * restart transmitting the whole frame.
 				 */
@@ -295,6 +313,9 @@
 				/* Here we lost an TX interrupt, so
 				   * restart transmitting the whole frame.
 				 */
+#ifdef ERROR_STATISTIC
+				bcs->err_tx++;
+#endif
 				if (bcs->tx_skb) {
 					skb_push(bcs->tx_skb, bcs->hw.hscx.count);
 					bcs->tx_cnt += bcs->hw.hscx.count;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/isac.c linux.14p16/drivers/isdn/hisax/isac.c
--- linux.vanilla/drivers/isdn/hisax/isac.c	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/isac.c	Thu Dec  9 15:34:08 1999
@@ -1,4 +1,4 @@
-/* $Id: isac.c,v 1.23 1999/08/25 16:50:52 keil Exp $
+/* $Id: isac.c,v 1.24 1999/10/14 20:25:28 keil Exp $
 
  * isac.c   ISAC specific routines
  *
@@ -9,6 +9,9 @@
  *		../../../Documentation/isdn/HiSax.cert
  *
  * $Log: isac.c,v $
+ * Revision 1.24  1999/10/14 20:25:28  keil
+ * add a statistic for error monitoring
+ *
  * Revision 1.23  1999/08/25 16:50:52  keil
  * Fix bugs which cause 2.3.14 hangs (waitqueue init)
  *
@@ -281,12 +284,20 @@
 	if (val & 0x80) {	/* RME */
 		exval = cs->readisac(cs, ISAC_RSTA);
 		if ((exval & 0x70) != 0x20) {
-			if (exval & 0x40)
+			if (exval & 0x40) {
 				if (cs->debug & L1_DEB_WARN)
 					debugl1(cs, "ISAC RDO");
-			if (!(exval & 0x20))
+#ifdef ERROR_STATISTIC
+				cs->err_rx++;
+#endif
+			}
+			if (!(exval & 0x20)) {
 				if (cs->debug & L1_DEB_WARN)
 					debugl1(cs, "ISAC CRC error");
+#ifdef ERROR_STATISTIC
+				cs->err_crc++;
+#endif
+			}
 			cs->writeisac(cs, ISAC_CMDR, 0x80);
 		} else {
 			count = cs->readisac(cs, ISAC_RBCL) & 0x1f;
@@ -371,6 +382,9 @@
 		if (exval & 0x40) {  /* XDU */
 			debugl1(cs, "ISAC XDU");
 			printk(KERN_WARNING "HiSax: ISAC XDU\n");
+#ifdef ERROR_STATISTIC
+			cs->err_tx++;
+#endif
 			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 				del_timer(&cs->dbusytimer);
 			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/isar.c linux.14p16/drivers/isdn/hisax/isar.c
--- linux.vanilla/drivers/isdn/hisax/isar.c	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/isar.c	Thu Dec  9 15:34:08 1999
@@ -1,4 +1,4 @@
-/* $Id: isar.c,v 1.6 1999/08/31 11:20:20 paul Exp $
+/* $Id: isar.c,v 1.7 1999/10/14 20:25:29 keil Exp $
 
  * isar.c   ISAR (Siemens PSB 7110) specific routines
  *
@@ -6,6 +6,9 @@
  *
  *
  * $Log: isar.c,v $
+ * Revision 1.7  1999/10/14 20:25:29  keil
+ * add a statistic for error monitoring
+ *
  * Revision 1.6  1999/08/31 11:20:20  paul
  * various spelling corrections (new checksums may be needed, Karsten!)
  *
@@ -480,6 +483,12 @@
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "isar frame error %x len %d",
 					ireg->cmsb, ireg->clsb);
+#ifdef ERROR_STATISTIC
+			if (ireg->cmsb & HDLC_ERR_RER)
+				bcs->err_inv++;
+			if (ireg->cmsb & HDLC_ERR_CER)
+				bcs->err_crc++;
+#endif
 			bcs->hw.isar.rcvidx = 0;
 			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 		} else {
@@ -790,10 +799,19 @@
 			check_send(cs, ireg->cmsb);
 			break;
 		case ISAR_IIS_BSTEV:
-			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+#ifdef ERROR_STATISTIC
+			if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
+				if (ireg->cmsb == BSTEV_TBO)
+					bcs->err_tx++;
+				if (ireg->cmsb == BSTEV_RBO)
+					bcs->err_rdo++;
+			}
+#endif
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "Buffer STEV dpath%d msb(%x)",
 					ireg->iis>>6, ireg->cmsb);
+			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+			break;
 		case ISAR_IIS_PSTEV:
 			if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
 				rcv_mbox(cs, ireg, (u_char *)ireg->par);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/isar.h linux.14p16/drivers/isdn/hisax/isar.h
--- linux.vanilla/drivers/isdn/hisax/isar.h	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/isar.h	Thu Dec  9 15:34:08 1999
@@ -1,10 +1,13 @@
-/* $Id: isar.h,v 1.5 1999/08/25 16:59:59 keil Exp $
+/* $Id: isar.h,v 1.6 1999/10/14 20:25:29 keil Exp $
  * isar.h   ISAR (Siemens PSB 7110) specific defines
  *
  * Author Karsten Keil (keil@isdn4linux.de)
  *
  *
  * $Log: isar.h,v $
+ * Revision 1.6  1999/10/14 20:25:29  keil
+ * add a statistic for error monitoring
+ *
  * Revision 1.5  1999/08/25 16:59:59  keil
  * Make ISAR V32bis modem running
  * Make LL->HL interface open for additional commands
@@ -178,12 +181,17 @@
 #define HDLC_FSD	0x20
 #define HDLC_FST	0x20
 #define HDLC_ERROR	0x1c
+#define HDLC_ERR_FAD	0x10
+#define HDLC_ERR_RER	0x08
+#define HDLC_ERR_CER	0x01
 #define SART_NMD	0x01
 
 #define BSTAT_RDM0	0x1
 #define BSTAT_RDM1	0x2
 #define BSTAT_RDM2	0x4
 #define BSTAT_RDM3	0x8
+#define BSTEV_TBO	0x1f
+#define BSTEV_RBO	0x2f
 
 extern int ISARVersion(struct IsdnCardState *cs, char *s);
 extern void isar_int_main(struct IsdnCardState *cs);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/isurf.c linux.14p16/drivers/isdn/hisax/isurf.c
--- linux.vanilla/drivers/isdn/hisax/isurf.c	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/isurf.c	Thu Dec  9 15:34:08 1999
@@ -1,10 +1,13 @@
-/* $Id: isurf.c,v 1.6 1999/09/04 06:20:06 keil Exp $
+/* $Id: isurf.c,v 1.7 1999/11/14 23:37:03 keil Exp $
 
  * isurf.c  low level stuff for Siemens I-Surf/I-Talk cards
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
  * $Log: isurf.c,v $
+ * Revision 1.7  1999/11/14 23:37:03  keil
+ * new ISA memory mapped IO
+ *
  * Revision 1.6  1999/09/04 06:20:06  keil
  * Changes from kernel set_current_state()
  *
@@ -37,7 +40,7 @@
 
 extern const char *CardType[];
 
-static const char *ISurf_revision = "$Revision: 1.6 $";
+static const char *ISurf_revision = "$Revision: 1.7 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -50,7 +53,7 @@
 
 #define ISURF_ISAR_OFFSET	0
 #define ISURF_ISAC_OFFSET	0x100
-
+#define ISURF_IOMEM_SIZE	0x400
 /* Interface functions */
 
 static u_char
@@ -223,8 +226,7 @@
  		return(0);
 	if (card->para[1] && card->para[2]) {
 		cs->hw.isurf.reset = card->para[1];
-		cs->hw.isurf.isar = card->para[2] + ISURF_ISAR_OFFSET;
-		cs->hw.isurf.isac = card->para[2] + ISURF_ISAC_OFFSET;
+		cs->hw.isurf.phymem = card->para[2];
 		cs->irq = card->para[0];
 	} else {
 		printk(KERN_WARNING "HiSax: %s port/mem not set\n",
@@ -240,11 +242,12 @@
 	} else {
 		request_region(cs->hw.isurf.reset, 1, "isurf isdn");
 	}
-
+	cs->hw.isurf.isar = cs->hw.isurf.phymem + ISURF_ISAR_OFFSET;
+	cs->hw.isurf.isac = cs->hw.isurf.phymem + ISURF_ISAC_OFFSET;
 	printk(KERN_INFO
-	       "ISurf: defined at 0x%x 0x%x IRQ %d\n",
+	       "ISurf: defined at 0x%x 0x%lx IRQ %d\n",
 	       cs->hw.isurf.reset,
-	       cs->hw.isurf.isar,
+	       cs->hw.isurf.phymem,
 	       cs->irq);
 
 	cs->cardmsg = &ISurf_card_msg;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/l3dss1.c linux.14p16/drivers/isdn/hisax/l3dss1.c
--- linux.vanilla/drivers/isdn/hisax/l3dss1.c	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/l3dss1.c	Thu Dec  9 15:34:07 1999
@@ -1,4 +1,4 @@
-/* $Id: l3dss1.c,v 2.19 1999/08/25 16:55:23 keil Exp $
+/* $Id: l3dss1.c,v 2.20 1999/10/11 22:16:27 keil Exp $
 
  * EURO/DSS1 D-channel protocol
  *
@@ -13,6 +13,9 @@
  *              Fritz Elfert
  *
  * $Log: l3dss1.c,v $
+ * Revision 2.20  1999/10/11 22:16:27  keil
+ * Suspend/Resume is possible without explicit ID too
+ *
  * Revision 2.19  1999/08/25 16:55:23  keil
  * Fix for test case TC10011
  *
@@ -90,7 +93,7 @@
 #include <linux/ctype.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 2.19 $";
+const char *dss1_revision = "$Revision: 2.20 $";
 
 #define EXT_BEARER_CAPS 1
 
@@ -2520,14 +2523,13 @@
 	u_char *msg = pc->chan->setup.phone;
 
 	MsgHead(p, pc->callref, MT_SUSPEND);
-
-	*p++ = IE_CALL_ID;
 	l = *msg++;
 	if (l && (l <= 10)) {	/* Max length 10 octets */
+		*p++ = IE_CALL_ID;
 		*p++ = l;
 		for (i = 0; i < l; i++)
 			*p++ = *msg++;
-	} else {
+	} else if (l) {
 		l3_debug(pc->st, "SUS wrong CALL_ID len %d", l);
 		return;
 	}
@@ -2596,13 +2598,13 @@
 
 	MsgHead(p, pc->callref, MT_RESUME);
 
-	*p++ = IE_CALL_ID;
 	l = *msg++;
 	if (l && (l <= 10)) {	/* Max length 10 octets */
+		*p++ = IE_CALL_ID;
 		*p++ = l;
 		for (i = 0; i < l; i++)
 			*p++ = *msg++;
-	} else {
+	} else if (l) {
 		l3_debug(pc->st, "RES wrong CALL_ID len %d", l);
 		return;
 	}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/md5sums.asc linux.14p16/drivers/isdn/hisax/md5sums.asc
--- linux.vanilla/drivers/isdn/hisax/md5sums.asc	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/md5sums.asc	Thu Dec  9 15:34:08 1999
@@ -6,14 +6,14 @@
 # Eicon Technology Diva 2.01 PCI cards in the moment.
 # Read ../../../Documentation/isdn/HiSax.cert for more informations.
 # 
-2760872030085b2d36aa203b44e9570e  isac.c
+3c2b1c96274cba97a8261d1cecc662b8  isac.c
 a9a15d069dbacb383cc24c238cb5ebbe  isdnl1.c
 bb51bd223040b511c18f091da5ab6456  isdnl2.c
 b7aa7f97b2374967a4aca7c52991142c  isdnl3.c
 a23fbf8879c1432b04640b8b04bdf419  tei.c
-c07fd0729b93ebffc3dbfc88cc334be1  callc.c
+d7072dbbeeb7c4c45f3810ed13cf5545  callc.c
 bf9605b36429898f7be6630034e83230  cert.c
-3fe91ac7175e1c15ad5f15b6d71b2756  l3dss1.c
+0e500813968adacaea2ef22c9cdd89eb  l3dss1.c
 2d748ced0eea375b21fe7ea91ca7917c  l3_1tr6.c
 72ee065c70473949a676f06f8ce83ebf  elsa.c
 1b26dd9b0f132744a7be2ce2ab1eda83  diva.c
@@ -23,9 +23,9 @@
 Version: 2.6.3i
 Charset: noconv
 
-iQCVAwUBN+/NfDpxHvX/mS9tAQEC4gQAlAfRvVnILSrDUtH83RzPd6nCLONiHpKn
-nmyE3BkGk2DO1D8azCjx3X/9x7ozEm8pL5UN2kZuu5p9EO0ISzM5ZmcCi0jxAOq5
-c493UJmnWWOw02G0pNw+EsmRH9mUh1t7IyUEL+UpUMNyAEQRqq66k764YyUkKF88
-fup3c64mSKw=
-=bmv8
+iQCVAwUBOCwLCTpxHvX/mS9tAQEZ5wP7B6kHy8fHHHANxqU1XAiJR5DvttJtJGi1
+0MDX2lNAPbfZQolTkkmmWgYBSnLTLVpM2jxj5pdnKWMoEp0embrb0fw1Nx+DkcJ1
+OfogKy0HvBPfZdwyKV+CZymXZystw/n47hekOTSNLkAOMA6BXcWrS6SLpfv6fEri
+Cdp0XgIaIWQ=
+=Cmob
 -----END PGP SIGNATURE-----
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/netjet.c linux.14p16/drivers/isdn/hisax/netjet.c
--- linux.vanilla/drivers/isdn/hisax/netjet.c	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/netjet.c	Thu Dec  9 15:34:08 1999
@@ -1,4 +1,4 @@
-/* $Id: netjet.c,v 1.15 1999/09/04 06:20:06 keil Exp $
+/* $Id: netjet.c,v 1.16 1999/10/14 20:25:29 keil Exp $
 
  * netjet.c     low level stuff for Traverse Technologie NETJet ISDN cards
  *
@@ -7,6 +7,9 @@
  * Thanks to Traverse Technologie Australia for documents and informations
  *
  * $Log: netjet.c,v $
+ * Revision 1.16  1999/10/14 20:25:29  keil
+ * add a statistic for error monitoring
+ *
  * Revision 1.15  1999/09/04 06:20:06  keil
  * Changes from kernel set_current_state()
  *
@@ -78,7 +81,7 @@
 
 extern const char *CardType[];
 
-const char *NETjet_revision = "$Revision: 1.15 $";
+const char *NETjet_revision = "$Revision: 1.16 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -528,19 +531,26 @@
 							debugl1(bcs->cs, "tiger: frame not byte aligned");
 							state=HDLC_FLAG_SEARCH;
 							bcs->hw.tiger.r_err++;
+#ifdef ERROR_STATISTIC
+							bcs->err_inv++;
+#endif
 						} else {
 							if (bcs->cs->debug & L1_DEB_HSCX)
 								debugl1(bcs->cs,"tiger frame end(%d,%d): fcs(%x) i %x",
 									i,j,bcs->hw.tiger.r_fcs, bcs->cs->hw.njet.irqstat0);
 							if (bcs->hw.tiger.r_fcs == PPP_GOODFCS) {
 								got_frame(bcs, (bitcnt>>3)-3);
-							} else
+							} else {
 								if (bcs->cs->debug) {
 									debugl1(bcs->cs, "tiger FCS error");
 									printframe(bcs->cs, bcs->hw.tiger.rcvbuf,
 										(bitcnt>>3)-1, "rec");
 									bcs->hw.tiger.r_err++;
 								}
+#ifdef ERROR_STATISTIC
+							bcs->err_crc++;
+#endif
+							}
 							state=HDLC_FLAG_FOUND;
 						}
 						bitcnt=0;
@@ -562,6 +572,9 @@
 						r_val=0; 
 						state=HDLC_FLAG_SEARCH;
 						bcs->hw.tiger.r_err++;
+#ifdef ERROR_STATISTIC
+						bcs->err_inv++;
+#endif
 					} else {
 						bcs->hw.tiger.rcvbuf[(bitcnt>>3)-1] = r_val;
 						bcs->hw.tiger.r_fcs = 
@@ -586,6 +599,12 @@
 	if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_READ) {
 		debugl1(cs,"tiger warn read double dma %x/%x",
 			cs->hw.njet.irqstat0, cs->hw.njet.last_is0);
+#ifdef ERROR_STATISTIC
+		if (cs->bcs[0].mode)
+			cs->bcs[0].err_rdo++;
+		if (cs->bcs[1].mode)
+			cs->bcs[1].err_rdo++;
+#endif
 		return;
 	} else {
 		cs->hw.njet.last_is0 &= ~NETJET_IRQM0_READ;
@@ -757,6 +776,12 @@
 	if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) {
 		debugl1(cs,"tiger warn write double dma %x/%x",
 			cs->hw.njet.irqstat0, cs->hw.njet.last_is0);
+#ifdef ERROR_STATISTIC
+		if (cs->bcs[0].mode)
+			cs->bcs[0].err_tx++;
+		if (cs->bcs[1].mode)
+			cs->bcs[1].err_tx++;
+#endif
 		return;
 	} else {
 		cs->hw.njet.last_is0 &= ~NETJET_IRQM0_WRITE;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/sedlbauer.c linux.14p16/drivers/isdn/hisax/sedlbauer.c
--- linux.vanilla/drivers/isdn/hisax/sedlbauer.c	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/sedlbauer.c	Thu Dec  9 15:34:08 1999
@@ -1,4 +1,4 @@
-/* $Id: sedlbauer.c,v 1.17 1999/09/04 06:20:06 keil Exp $
+/* $Id: sedlbauer.c,v 1.18 1999/11/13 21:25:03 keil Exp $
 
  * sedlbauer.c  low level stuff for Sedlbauer cards
  *              includes support for the Sedlbauer speed star (speed star II),
@@ -17,6 +17,9 @@
  *            Edgar Toernig
  *
  * $Log: sedlbauer.c,v $
+ * Revision 1.18  1999/11/13 21:25:03  keil
+ * Support for Speedfax+ PCI
+ *
  * Revision 1.17  1999/09/04 06:20:06  keil
  * Changes from kernel set_current_state()
  *
@@ -79,12 +82,13 @@
  * ---------------------------------------------------------------------
  * Speed Card	ISAC_HSCX	DIP-SWITCH
  * Speed Win	ISAC_HSCX	ISAPNP
- * Speed Fax+	ISAC_ISAR	ISAPNP		#HDLC works#
+ * Speed Fax+	ISAC_ISAR	ISAPNP		Full analog support
  * Speed Star	ISAC_HSCX	CARDMGR
  * Speed Win2	IPAC		ISAPNP
  * ISDN PC/104	IPAC		DIP-SWITCH
  * Speed Star2	IPAC		CARDMGR
- * Speed PCI	IPAC		PNP		
+ * Speed PCI	IPAC		PCI PNP		
+ * Speed Fax+ 	ISAC_ISAR	PCI PNP		Full analog support
  *
  * Important:
  * For the sedlbauer speed fax+ to work properly you have to download 
@@ -106,15 +110,18 @@
 
 extern const char *CardType[];
 
-const char *Sedlbauer_revision = "$Revision: 1.17 $";
+const char *Sedlbauer_revision = "$Revision: 1.18 $";
 
 const char *Sedlbauer_Types[] =
 	{"None", "speed card/win", "speed star", "speed fax+", 
-	"speed win II / ISDN PC/104", "speed star II", "speed pci"};
+	"speed win II / ISDN PC/104", "speed star II", "speed pci",
+	"speed fax+ pci"};
 
 #ifdef SEDLBAUER_PCI
 #define PCI_VENDOR_SEDLBAUER	0xe159
-#define PCI_SPEEDPCI_ID	0x02
+#define PCI_SPEEDPCI_ID		0x02
+#define PCI_SUBVENDOR_SEDLBAUER	0x51
+#define PCI_SUB_ID_SPEEDFAXP	0x01
 #endif
  
 #define SEDL_SPEED_CARD_WIN	1
@@ -123,6 +130,7 @@
 #define SEDL_SPEED_WIN2_PC104 	4
 #define SEDL_SPEED_STAR2 	5
 #define SEDL_SPEED_PCI   	6
+#define SEDL_SPEEDFAX_PCI	7
 
 #define SEDL_CHIP_TEST		0
 #define SEDL_CHIP_ISAC_HSCX	1
@@ -153,12 +161,19 @@
 #define SEDL_ISAR_ISA_ISAR_RESET_ON	10
 #define SEDL_ISAR_ISA_ISAR_RESET_OFF	12
 
-#define SEDL_IPAC_ANY_ADR 	0
-#define SEDL_IPAC_ANY_IPAC	2
+#define SEDL_IPAC_ANY_ADR		0
+#define SEDL_IPAC_ANY_IPAC		2
 
-#define SEDL_IPAC_PCI_BASE	0
-#define SEDL_IPAC_PCI_ADR	0xc0
-#define SEDL_IPAC_PCI_IPAC	0xc8
+#define SEDL_IPAC_PCI_BASE		0
+#define SEDL_IPAC_PCI_ADR		0xc0
+#define SEDL_IPAC_PCI_IPAC		0xc8
+#define SEDL_ISAR_PCI_ADR		0xc8
+#define SEDL_ISAR_PCI_ISAC		0xd0
+#define SEDL_ISAR_PCI_ISAR		0xe0
+#define SEDL_ISAR_PCI_ISAR_RESET_ON	0x01
+#define SEDL_ISAR_PCI_ISAR_RESET_OFF	0x18
+#define SEDL_ISAR_PCI_LED1		0x08
+#define SEDL_ISAR_PCI_LED2		0x10
 
 #define SEDL_RESET      0x3	/* same as DOS driver */
 
@@ -235,24 +250,25 @@
 static u_char
 ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
 {
-        return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80));}
+	return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80));
+}
 
 static void
 WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-        writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80, value);
+	writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80, value);
 }
 
 static void
 ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-        readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
+	readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
 }
 
 static void
 WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-        writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
+	writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
 }
 
 static u_char
@@ -485,6 +501,17 @@
 			writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xc0);
 			writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_PCFG, 0x12);
 			restore_flags(flags);
+		} else if ((cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) &&
+			(cs->hw.sedl.bus == SEDL_BUS_PCI)) {
+			byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
+			save_flags(flags);
+			sti();
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout((20*HZ)/1000);
+			byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout((20*HZ)/1000);
+			restore_flags(flags);
 		} else {		
 			byteout(cs->hw.sedl.reset_on, SEDL_RESET);	/* Reset On */
 			save_flags(flags);
@@ -537,6 +564,24 @@
 			return(0);
 		case CARD_TEST:
 			return(0);
+		case MDL_INFO_CONN:
+			if (cs->subtyp != SEDL_SPEEDFAX_PCI)
+				return(0);
+			if ((long) arg)
+				cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2;
+			else
+				cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED1;
+			byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+			break;
+		case MDL_INFO_REL:
+			if (cs->subtyp != SEDL_SPEEDFAX_PCI)
+				return(0);
+			if ((long) arg)
+				cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2;
+			else
+				cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED1;
+			byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+			break;
 	}
 	return(0);
 }
@@ -551,6 +596,8 @@
 	int bytecnt, ver, val;
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
+	u16 sub_vendor_id, sub_id;
+	long flags;
 
 	strcpy(tmp, Sedlbauer_revision);
 	printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp));
@@ -598,15 +645,40 @@
 			printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
 			return(0);
 		}
-		 cs->irq_flags |= SA_SHIRQ;
+		cs->irq_flags |= SA_SHIRQ;
 		cs->hw.sedl.bus = SEDL_BUS_PCI;
-		cs->hw.sedl.chip = SEDL_CHIP_IPAC;
-		cs->subtyp = SEDL_SPEED_PCI;
+		pci_read_config_word(dev_sedl, PCI_SUBSYSTEM_VENDOR_ID,
+			&sub_vendor_id);
+		pci_read_config_word(dev_sedl, PCI_SUBSYSTEM_ID,
+			&sub_id);
+		printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
+			sub_vendor_id, sub_id);
+		printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
+			cs->hw.sedl.cfg_reg);
+		if ((sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER) &&
+			(sub_id == PCI_SUB_ID_SPEEDFAXP)) {
+			cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+			cs->subtyp = SEDL_SPEEDFAX_PCI;
+			cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg +
+						SEDL_ISAR_PCI_ISAR_RESET_ON;
+			cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg +
+						SEDL_ISAR_PCI_ISAR_RESET_OFF;
+		} else {
+			cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+			cs->subtyp = SEDL_SPEED_PCI;
+		}
 		bytecnt = 256;
 		byteout(cs->hw.sedl.cfg_reg, 0xff);
 		byteout(cs->hw.sedl.cfg_reg, 0x00);
 		byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
 		byteout(cs->hw.sedl.cfg_reg+ 5, 0x02);
+		byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
+		save_flags(flags);
+		sti();
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout((10*HZ)/1000);
+		byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+		restore_flags(flags);
 #else
 		printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n");
 		return (0);
@@ -688,7 +760,7 @@
                 cs->writeisacfifo = &WriteISACfifo_IPAC;
                 cs->irq_func = &sedlbauer_interrupt_ipac;
 
-		val = readreg(cs->hw.sedl.adr,cs->hw.sedl.isac, IPAC_ID);
+		val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ID);
                 printk(KERN_INFO "Sedlbauer: IPAC version %x\n", val);
 		reset_sedlbauer(cs);
 	} else {
@@ -698,18 +770,31 @@
 		cs->readisacfifo = &ReadISACfifo;
 		cs->writeisacfifo = &WriteISACfifo;
 		if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
-			cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ADR;
-			cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAC;
-			cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR;
-			cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR_RESET_ON;
-			cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR_RESET_OFF;
+			if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
+				cs->hw.sedl.adr = cs->hw.sedl.cfg_reg +
+							SEDL_ISAR_PCI_ADR;
+				cs->hw.sedl.isac = cs->hw.sedl.cfg_reg +
+							SEDL_ISAR_PCI_ISAC;
+				cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg +
+							SEDL_ISAR_PCI_ISAR;
+			} else {
+				cs->hw.sedl.adr = cs->hw.sedl.cfg_reg +
+							SEDL_ISAR_ISA_ADR;
+				cs->hw.sedl.isac = cs->hw.sedl.cfg_reg +
+							SEDL_ISAR_ISA_ISAC;
+				cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg +
+							SEDL_ISAR_ISA_ISAR;
+				cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg +
+							SEDL_ISAR_ISA_ISAR_RESET_ON;
+				cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg +
+							SEDL_ISAR_ISA_ISAR_RESET_OFF;
+			}
 			cs->bcs[0].hw.isar.reg = &cs->hw.sedl.isar;
 			cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar;
 			test_and_set_bit(HW_ISAR, &cs->HW_Flags);
 			cs->irq_func = &sedlbauer_interrupt_isar;
 			cs->auxcmd = &isar_auxcmd;
 			ISACVersion(cs, "Sedlbauer:");
-		
 			cs->BC_Read_Reg = &ReadISAR;
 			cs->BC_Write_Reg = &WriteISAR;
 			cs->BC_Send_Data = &isar_fill_fifo;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/teles0.c linux.14p16/drivers/isdn/hisax/teles0.c
--- linux.vanilla/drivers/isdn/hisax/teles0.c	Sat Aug 14 02:27:26 1999
+++ linux.14p16/drivers/isdn/hisax/teles0.c	Thu Dec  9 15:34:07 1999
@@ -1,4 +1,4 @@
-/* $Id: teles0.c,v 2.9 1999/07/12 21:05:31 keil Exp $
+/* $Id: teles0.c,v 2.10 1999/11/14 23:37:03 keil Exp $
 
  * teles0.c     low level stuff for Teles Memory IO isdn cards
  *              based on the teles driver from Jan den Ouden
@@ -10,6 +10,9 @@
  *              Beat Doebeli
  *
  * $Log: teles0.c,v $
+ * Revision 2.10  1999/11/14 23:37:03  keil
+ * new ISA memory mapped IO
+ *
  * Revision 2.9  1999/07/12 21:05:31  keil
  * fix race in IRQ handling
  * added watchdog for lost IRQs
@@ -58,71 +61,72 @@
 
 extern const char *CardType[];
 
-const char *teles0_revision = "$Revision: 2.9 $";
+const char *teles0_revision = "$Revision: 2.10 $";
 
+#define TELES_IOMEM_SIZE	0x400
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
 
 static inline u_char
-readisac(unsigned int adr, u_char off)
+readisac(unsigned long adr, u_char off)
 {
 	return readb(adr + ((off & 1) ? 0x2ff : 0x100) + off);
 }
 
 static inline void
-writeisac(unsigned int adr, u_char off, u_char data)
+writeisac(unsigned long adr, u_char off, u_char data)
 {
 	writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb();
 }
 
 
 static inline u_char
-readhscx(unsigned int adr, int hscx, u_char off)
+readhscx(unsigned long adr, int hscx, u_char off)
 {
 	return readb(adr + (hscx ? 0x1c0 : 0x180) +
 		     ((off & 1) ? 0x1ff : 0) + off);
 }
 
 static inline void
-writehscx(unsigned int adr, int hscx, u_char off, u_char data)
+writehscx(unsigned long adr, int hscx, u_char off, u_char data)
 {
 	writeb(data, adr + (hscx ? 0x1c0 : 0x180) +
 	       ((off & 1) ? 0x1ff : 0) + off); mb();
 }
 
 static inline void
-read_fifo_isac(unsigned int adr, u_char * data, int size)
+read_fifo_isac(unsigned long adr, u_char * data, int size)
 {
 	register int i;
-	register u_char *ad = (u_char *) ((long)adr + 0x100);
+	register u_char *ad = (u_char *)adr + 0x100;
 	for (i = 0; i < size; i++)
 		data[i] = readb(ad);
 }
 
 static inline void
-write_fifo_isac(unsigned int adr, u_char * data, int size)
+write_fifo_isac(unsigned long adr, u_char * data, int size)
 {
 	register int i;
-	register u_char *ad = (u_char *) ((long)adr + 0x100);
+	register u_char *ad = (u_char *)adr + 0x100;
 	for (i = 0; i < size; i++) {
 		writeb(data[i], ad); mb();
 	}
 }
 
 static inline void
-read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+read_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
 {
 	register int i;
-	register u_char *ad = (u_char *) ((long)adr + (hscx ? 0x1c0 : 0x180));
+	register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180));
 	for (i = 0; i < size; i++)
 		data[i] = readb(ad);
 }
 
 static inline void
-write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+write_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
 {
 	int i;
-	register u_char *ad = (u_char *) ((long)adr + (hscx ? 0x1c0 : 0x180));
+	register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180));
 	for (i = 0; i < size; i++) {
 		writeb(data[i], ad); mb();
 	}
@@ -262,7 +266,7 @@
 			default:
 				return(1);
 		}
-		cfval |= ((cs->hw.teles0.membase >> 9) & 0xF0);
+		cfval |= ((cs->hw.teles0.phymem >> 9) & 0xF0);
 		byteout(cs->hw.teles0.cfg_reg + 4, cfval);
 		HZDELAY(HZ / 10 + 1);
 		byteout(cs->hw.teles0.cfg_reg + 4, cfval | 1);
@@ -318,10 +322,9 @@
 		   "Teles0: membase configured DOSish, assuming 0x%lx\n",
 		       (unsigned long) card->para[1]);
 	}
-	cs->hw.teles0.membase = card->para[1];
 	cs->irq = card->para[0];
 	if (cs->hw.teles0.cfg_reg) {
-		if (check_region((cs->hw.teles0.cfg_reg), 8)) {
+		if (check_region(cs->hw.teles0.cfg_reg, 8)) {
 			printk(KERN_WARNING
 			  "HiSax: %s config port %x-%x already in use\n",
 			       CardType[card->typ],
@@ -358,8 +361,10 @@
 	}
 	/* 16.0 and 8.0 designed for IOM1 */
 	test_and_set_bit(HW_IOM1, &cs->HW_Flags);
+	cs->hw.teles0.phymem = card->para[1];
+	cs->hw.teles0.membase = cs->hw.teles0.phymem;
 	printk(KERN_INFO
-	       "HiSax: %s config irq:%d mem:0x%X cfg:0x%X\n",
+	       "HiSax: %s config irq:%d mem:0x%lX cfg:0x%X\n",
 	       CardType[cs->typ], cs->irq,
 	       cs->hw.teles0.membase, cs->hw.teles0.cfg_reg);
 	if (reset_teles0(cs)) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/telespci.c linux.14p16/drivers/isdn/hisax/telespci.c
--- linux.vanilla/drivers/isdn/hisax/telespci.c	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/hisax/telespci.c	Thu Dec  9 15:34:08 1999
@@ -1,4 +1,4 @@
-/* $Id: telespci.c,v 2.9 1999/08/11 21:01:34 keil Exp $
+/* $Id: telespci.c,v 2.10 1999/11/15 14:20:05 keil Exp $
 
  * telespci.c     low level stuff for Teles PCI isdn cards
  *
@@ -7,6 +7,9 @@
  *
  *
  * $Log: telespci.c,v $
+ * Revision 2.10  1999/11/15 14:20:05  keil
+ * 64Bit compatibility
+ *
  * Revision 2.9  1999/08/11 21:01:34  keil
  * new PCI codefix
  *
@@ -44,7 +47,7 @@
 #include <linux/pci.h>
 
 extern const char *CardType[];
-const char *telespci_revision = "$Revision: 2.9 $";
+const char *telespci_revision = "$Revision: 2.10 $";
 
 #define ZORAN_PO_RQ_PEN	0x02000000
 #define ZORAN_PO_WR	0x00800000
@@ -66,7 +69,7 @@
 				} while (portdata & ZORAN_PO_RQ_PEN)
 
 static inline u_char
-readisac(unsigned int adr, u_char off)
+readisac(unsigned long adr, u_char off)
 {
 	register unsigned int portdata;
 
@@ -83,7 +86,7 @@
 }
 
 static inline void
-writeisac(unsigned int adr, u_char off, u_char data)
+writeisac(unsigned long adr, u_char off, u_char data)
 {
 	register unsigned int portdata;
 
@@ -99,7 +102,7 @@
 }
 
 static inline u_char
-readhscx(unsigned int adr, int hscx, u_char off)
+readhscx(unsigned long adr, int hscx, u_char off)
 {
 	register unsigned int portdata;
 
@@ -115,7 +118,7 @@
 }
 
 static inline void
-writehscx(unsigned int adr, int hscx, u_char off, u_char data)
+writehscx(unsigned long adr, int hscx, u_char off, u_char data)
 {
 	register unsigned int portdata;
 
@@ -130,7 +133,7 @@
 }
 
 static inline void
-read_fifo_isac(unsigned int adr, u_char * data, int size)
+read_fifo_isac(unsigned long adr, u_char * data, int size)
 {
 	register unsigned int portdata;
 	register int i;
@@ -148,7 +151,7 @@
 }
 
 static void
-write_fifo_isac(unsigned int adr, u_char * data, int size)
+write_fifo_isac(unsigned long adr, u_char * data, int size)
 {
 	register unsigned int portdata;
 	register int i;
@@ -165,7 +168,7 @@
 }
 
 static inline void
-read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+read_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
 {
 	register unsigned int portdata;
 	register int i;
@@ -183,7 +186,7 @@
 }
 
 static inline void
-write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+write_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
 {
 	unsigned int portdata;
 	register int i;
@@ -324,7 +327,7 @@
 			printk(KERN_WARNING "Teles: No IRQ for PCI card found\n");
 			return(0);
 		}
-		cs->hw.teles0.membase = (u_int) ioremap(dev_tel->base_address[ 0],
+		cs->hw.teles0.membase = (u_long) ioremap(dev_tel->base_address[ 0],
 			PAGE_SIZE);
 		printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n",
 			dev_tel->base_address[ 0], dev_tel->irq);
@@ -348,7 +351,7 @@
 	/* writel(0x00800000, cs->hw.teles0.membase + 0x200); */
 
 	printk(KERN_INFO
-	       "HiSax: %s config irq:%d mem:%x\n",
+	       "HiSax: %s config irq:%d mem:%lx\n",
 	       CardType[cs->typ], cs->irq,
 	       cs->hw.teles0.membase);
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_common.c linux.14p16/drivers/isdn/isdn_common.c
--- linux.vanilla/drivers/isdn/isdn_common.c	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/isdn_common.c	Thu Dec  9 15:34:07 1999
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.87 1999/09/12 16:19:39 detabc Exp $
+/* $Id: isdn_common.c,v 1.93 1999/11/04 13:11:36 keil Exp $
 
  * Linux ISDN subsystem, common used functions (linklevel).
  *
@@ -21,6 +21,31 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_common.c,v $
+ * Revision 1.93  1999/11/04 13:11:36  keil
+ * Reinit of v110 structs
+ *
+ * Revision 1.92  1999/10/31 15:59:50  he
+ * more skb headroom checks
+ *
+ * Revision 1.91  1999/10/28 22:48:45  armin
+ * Bugfix: isdn_free_channel() now frees the channel,
+ * even when the usage of the ttyI has changed.
+ *
+ * Revision 1.90  1999/10/27 21:21:17  detabc
+ * Added support for building logically-bind-group's per interface.
+ * usefull for outgoing call's with more then one isdn-card.
+ *
+ * Switchable support to dont reset the hangup-timeout for
+ * receive frames. Most part's of the timru-rules for receiving frames
+ * are now obsolete. If the input- or forwarding-firewall deny
+ * the frame, the line will be not hold open.
+ *
+ * Revision 1.89  1999/10/16 14:46:47  keil
+ * replace kmalloc with vmalloc for the big dev struct
+ *
+ * Revision 1.88  1999/10/02 00:39:26  he
+ * Fixed a 2.3.x wait queue initialization (was causing panics)
+ *
  * Revision 1.87  1999/09/12 16:19:39  detabc
  * added abc features
  * low cost routing for net-interfaces (only the HL side).
@@ -371,6 +396,7 @@
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/poll.h>
+#include <linux/vmalloc.h>
 #include <linux/isdn.h>
 #include "isdn_common.h"
 #include "isdn_tty.h"
@@ -390,7 +416,7 @@
 
 isdn_dev *dev = (isdn_dev *) 0;
 
-static char *isdn_revision = "$Revision: 1.87 $";
+static char *isdn_revision = "$Revision: 1.93 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
@@ -2098,13 +2124,19 @@
 	save_flags(flags);
 	cli();
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
-		if (((dev->usage[i] & ISDN_USAGE_MASK) == usage) &&
+		if (((!usage) || ((dev->usage[i] & ISDN_USAGE_MASK) == usage)) &&
 		    (dev->drvmap[i] == di) &&
 		    (dev->chanmap[i] == ch)) {
 			dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE);
 			strcpy(dev->num[i], "???");
 			dev->ibytes[i] = 0;
 			dev->obytes[i] = 0;
+// 20.10.99 JIM, try to reinitialize v110 !
+			dev->v110emu[i] = 0;
+			atomic_set(&(dev->v110use[i]), 0);
+			isdn_v110_close(dev->v110[i]);
+			dev->v110[i] = NULL;
+// 20.10.99 JIM, try to reinitialize v110 !
 			isdn_info_update();
 			isdn_free_queue(&dev->drv[di]->rpqueue[ch]);
 		}
@@ -2186,8 +2218,33 @@
 		/* V.110 must always be acknowledged */
 		ack = 1;
 		ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, nskb);
-	} else
-		ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb);
+	} else {
+		int hl = dev->drv[drvidx]->interface->hl_hdrlen;
+
+		if( skb_headroom(skb) < hl ){
+			/* 
+			 * This should only occur when new HL driver with
+			 * increased hl_hdrlen was loaded after netdevice
+			 * was created and connected to the new driver.
+			 *
+			 * The V.110 branch (re-allocates on its own) does
+			 * not need this
+			 */
+			struct sk_buff * skb_tmp;
+
+			skb_tmp = skb_realloc_headroom(skb, hl);
+			printk(KERN_DEBUG "isdn_writebuf_skb_stub: reallocating headroom%s\n", skb_tmp ? "" : " failed");
+			if (!skb_tmp) return -ENOMEM; /* 0 better? */
+			ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb_tmp);
+			if( ret > 0 ){
+				dev_kfree_skb(skb);
+			} else {
+				dev_kfree_skb(skb_tmp);
+			}
+		} else {
+			ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb);
+		}
+	}
 	if (ret > 0) {
 		dev->obytes[idx] += ret;
 		if (dev->v110[idx]) {
@@ -2470,8 +2527,7 @@
 	int i;
 	char tmprev[50];
 
-	sti();
-	if (!(dev = (isdn_dev *) kmalloc(sizeof(isdn_dev), GFP_KERNEL))) {
+	if (!(dev = (isdn_dev *) vmalloc(sizeof(isdn_dev)))) {
 		printk(KERN_WARNING "isdn: Could not allocate device-struct.\n");
 		return -EIO;
 	}
@@ -2487,7 +2543,7 @@
 	}
 	if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
 		printk(KERN_WARNING "isdn: Could not register control devices\n");
-		kfree(dev);
+		vfree(dev);
 		return -EIO;
 	}
 	if ((i = isdn_tty_modem_init()) < 0) {
@@ -2496,7 +2552,7 @@
 			tty_unregister_driver(&dev->mdm.cua_modem);
 		if (i <= -2)
 			tty_unregister_driver(&dev->mdm.tty_modem);
-		kfree(dev);
+		vfree(dev);
 		unregister_chrdev(ISDN_MAJOR, "isdn");
 		return -EIO;
 	}
@@ -2508,7 +2564,7 @@
 		for (i = 0; i < ISDN_MAX_CHANNELS; i++)
 			kfree(dev->mdm.info[i].xmit_buf - 4);
 		unregister_chrdev(ISDN_MAJOR, "isdn");
-		kfree(dev);
+		vfree(dev);
 		return -EIO;
 	}
 #endif                          /* CONFIG_ISDN_PPP */
@@ -2577,7 +2633,7 @@
 		printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n");
 	} else {
 		del_timer(&dev->timer);
-		kfree(dev);
+		vfree(dev);
 		printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
 	}
 	restore_flags(flags);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_common.h linux.14p16/drivers/isdn/isdn_common.h
--- linux.vanilla/drivers/isdn/isdn_common.h	Wed Oct 20 01:12:37 1999
+++ linux.14p16/drivers/isdn/isdn_common.h	Thu Dec  9 15:34:07 1999
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.h,v 1.16 1999/07/01 08:29:54 keil Exp $
+/* $Id: isdn_common.h,v 1.17 1999/10/27 21:21:17 detabc Exp $
 
  * header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel).
  *
@@ -21,6 +21,15 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_common.h,v $
+ * Revision 1.17  1999/10/27 21:21:17  detabc
+ * Added support for building logically-bind-group's per interface.
+ * usefull for outgoing call's with more then one isdn-card.
+ *
+ * Switchable support to dont reset the hangup-timeout for
+ * receive frames. Most part's of the timru-rules for receiving frames
+ * are now obsolete. If the input- or forwarding-firewall deny
+ * the frame, the line will be not hold open.
+ *
  * Revision 1.16  1999/07/01 08:29:54  keil
  * compatibility to 2.3 kernel
  *
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_net.c linux.14p16/drivers/isdn/isdn_net.c
--- linux.vanilla/drivers/isdn/isdn_net.c	Wed Oct 20 01:12:38 1999
+++ linux.14p16/drivers/isdn/isdn_net.c	Thu Dec  9 15:34:07 1999
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.92 1999/09/13 23:25:17 he Exp $
+/* $Id: isdn_net.c,v 1.95 1999/10/27 21:21:17 detabc Exp $
 
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
@@ -21,6 +21,24 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_net.c,v $
+ * Revision 1.95  1999/10/27 21:21:17  detabc
+ * Added support for building logically-bind-group's per interface.
+ * usefull for outgoing call's with more then one isdn-card.
+ *
+ * Switchable support to dont reset the hangup-timeout for
+ * receive frames. Most part's of the timru-rules for receiving frames
+ * are now obsolete. If the input- or forwarding-firewall deny
+ * the frame, the line will be not hold open.
+ *
+ * Revision 1.94  1999/10/02 11:07:02  he
+ * Changed tbusy logic in indn_net.c
+ *
+ * Revision 1.93  1999/09/23 22:22:41  detabc
+ * added tcp-keepalive-detect with local response (ipv4 only)
+ * added host-only-interface support
+ * (source ipaddr == interface ipaddr) (ipv4 only)
+ * ok with kernel 2.3.18 and 2.2.12
+ *
  * Revision 1.92  1999/09/13 23:25:17  he
  * serialized xmitting frames from isdn_ppp and BSENT statcallb
  *
@@ -375,6 +393,49 @@
 #endif
 
 
+#ifndef ISDN_NEW_TBUSY
+#define ISDN_NEW_TBUSY
+#endif
+#ifdef ISDN_NEW_TBUSY
+/*
+ * Outline of new tbusy handling: 
+ *
+ * Old method, roughly spoken, consisted of setting tbusy when entering
+ * isdn_net_start_xmit() and at several other locations and clearing
+ * it from isdn_net_start_xmit() thread when sending was successful.
+ *
+ * With 2.3.x multithreaded network core, to prevent problems, tbusy should
+ * only be set by the isdn_net_start_xmit() thread and only when a tx-busy
+ * condition is detected. Other threads (in particular isdn_net_stat_callb())
+ * are only allowed to clear tbusy.
+ *
+ * -HE
+ */
+
+/*
+ * Tell upper layers that the network device is ready to xmit more frames.
+ */
+static void __inline__ isdn_net_dev_xon(struct device * dev)
+{
+	dev->tbusy = 0;
+	mark_bh(NET_BH);
+}
+
+static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
+{
+	lp->netdev->dev.tbusy = 0;
+	if(lp->master) lp->master->tbusy = 0;
+	mark_bh(NET_BH);
+}
+
+/*
+ * Ask upper layers to temporarily cease passing us more xmit frames.
+ */
+static void __inline__ isdn_net_dev_xoff(struct device * dev)
+{
+	dev->tbusy = 1;
+}
+#endif
 
 /* Prototypes */
 
@@ -382,7 +443,7 @@
 static int isdn_net_start_xmit(struct sk_buff *, struct device *);
 static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *);
 
-char *isdn_net_revision = "$Revision: 1.92 $";
+char *isdn_net_revision = "$Revision: 1.95 $";
 
  /*
   * Code for raw-networking over ISDN
@@ -424,7 +485,11 @@
 	save_flags(flags);
 	cli();                  /* Avoid glitch on writes to CMD regs */
 	dev->interrupt = 0;
+#ifdef ISDN_NEW_TBUSY
+	isdn_net_dev_xon(dev);
+#else
 	dev->tbusy = 0;
+#endif
 #ifdef CONFIG_ISDN_X25
 	if( cprot && cprot -> pops && dops )
 		cprot -> pops -> restart ( cprot, dev, dops );
@@ -638,13 +703,19 @@
 							mdev = &lp->netdev->dev;
 						if (!isdn_net_send_skb(mdev, lp, lp->sav_skb)) {
 							lp->sav_skb = NULL;
+#ifndef ISDN_NEW_TBUSY
 							mark_bh(NET_BH);
+#endif
 						} else {
 							return 1;
 						}
 					}
+#ifdef ISDN_NEW_TBUSY
+					isdn_net_lp_xon(lp);
+#else
 					if (test_and_clear_bit(0, (void *) &(p->dev.tbusy)))
 						mark_bh(NET_BH);
+#endif
 				}
 				return 1;
 			case ISDN_STAT_DCONN:
@@ -727,7 +798,6 @@
 						lp->dialstarted = 0;
 						lp->dialwait_timer = 0;
 
-						/* Immediately send first skb to speed up arp */
 #ifdef CONFIG_ISDN_PPP
 						if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
 							isdn_ppp_wakeup_daemon(lp);
@@ -738,11 +808,15 @@
 							if( pops->connect_ind)
 								pops->connect_ind(cprot);
 #endif /* CONFIG_ISDN_X25 */
+						/* Immediately send first skb to speed up arp */
 						if (lp->first_skb) {
 
 							if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb)))
 								lp->first_skb = NULL;
 						}
+#ifdef ISDN_NEW_TBUSY
+						if(! lp->first_skb) isdn_net_lp_xon(lp);
+#else
 						else {
 							/*
 							 * dev.tbusy is usually cleared implicitly by isdn_net_xmit(,,lp->first_skb).
@@ -751,6 +825,7 @@
 							lp->netdev->dev.tbusy = 0;
 							mark_bh(NET_BH);
 						}
+#endif /* ISDN_NEW_TBUSY */
 						return 1;
 				}
 				break;
@@ -1185,6 +1260,7 @@
 					break;
 			}
 			printk(KERN_INFO "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
+
 			       p[12], p[13], p[14], p[15],
 			       p[16], p[17], p[18], p[19],
 			       addinfo);
@@ -1203,8 +1279,12 @@
  * standard send-routine, else send directly.
  *
  * Return: 0 on success, !0 on failure.
+ */
+#ifndef ISDN_NEW_TBUSY
+/*
  * Side-effects: ndev->tbusy is cleared on success.
  */
+#endif
 int
 isdn_net_send_skb(struct device *ndev, isdn_net_local * lp,
 		  struct sk_buff *skb)
@@ -1215,13 +1295,17 @@
 	ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
 	if (ret == len) {
 		lp->transcount += len;
+#ifndef ISDN_NEW_TBUSY
 		clear_bit(0, (void *) &(ndev->tbusy));
+#endif
 		return 0;
 	}
 	if (ret < 0) {
 		dev_kfree_skb(skb);
 		lp->stats.tx_errors++;
+#ifndef ISDN_NEW_TBUSY
 		clear_bit(0, (void *) &(ndev->tbusy));
+#endif
 		return 0;
 	}
 	return 1;
@@ -1267,7 +1351,11 @@
 			if (lp->srobin == ndev)
 				ret = isdn_net_send_skb(ndev, lp, skb);
 			else
+#ifdef ISDN_NEW_TBUSY
+				ret = isdn_net_start_xmit(skb, lp->srobin);
+#else
 				ret = ndev->tbusy = isdn_net_start_xmit(skb, lp->srobin);
+#endif
 			lp->srobin = (slp->slave) ? slp->slave : ndev;
 			slp = (isdn_net_local *) (lp->srobin->priv);
 			if (!((slp->flags & ISDN_NET_CONNECTED) && (slp->dialstate == 0)))
@@ -1327,8 +1415,13 @@
 		if (!lp->dialstate)
 			lp->stats.tx_errors++;
 		ndev->trans_start = jiffies;
+#ifdef ISDN_NEW_TBUSY
+		isdn_net_dev_xon(ndev);
+#endif
 	}
+#ifndef ISDN_NEW_TBUSY
 	ndev->tbusy = 1; /* left instead of obsolete test_and_set_bit() */
+#endif
 #ifdef CONFIG_ISDN_X25
 /* At this point hard_start_xmit() passes control to the encapsulation
    protocol (if present).
@@ -1342,7 +1435,11 @@
    when a dl_establish request is received from the upper layer.
 */
 	if( cprot ) {
-		return  cprot -> pops -> encap_and_xmit ( cprot , skb);
+		int ret = cprot -> pops -> encap_and_xmit ( cprot , skb);
+#ifdef ISDN_NEW_TBUSY
+		if(ret) isdn_net_dev_xoff(ndev);
+#endif
+		return ret;
 	} else
 #endif
 	/* auto-dialing xmit function */
@@ -1361,7 +1458,9 @@
 			if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
 				isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'");
 				dev_kfree_skb(skb);
+#ifndef ISDN_NEW_TBUSY
 				ndev->tbusy = 0;
+#endif
 				return 0;
 			}
 			if (lp->phone[1]) {
@@ -1377,7 +1476,9 @@
 					if(jiffies < lp->dialwait_timer) {
 						isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
 						dev_kfree_skb(skb);
+#ifndef ISDN_NEW_TBUSY
 						ndev->tbusy = 0;
+#endif
 						restore_flags(flags);
 						return 0;
 					} else
@@ -1386,22 +1487,28 @@
 
 				/* Grab a free ISDN-Channel */
 				if (((chi =
-				     isdn_get_free_channel(ISDN_USAGE_NET,
-							   lp->l2_proto,
-							   lp->l3_proto,
-							   lp->pre_device,
-						 lp->pre_channel)) < 0) &&
+				     isdn_get_free_channel(
+					 		ISDN_USAGE_NET,
+							lp->l2_proto,
+							lp->l3_proto,
+							lp->pre_device,
+						 	lp->pre_channel)
+							) < 0) &&
 					((chi =
-				     isdn_get_free_channel(ISDN_USAGE_NET,
-							   lp->l2_proto,
-							   lp->l3_proto,
-							   lp->pre_device,
-						 lp->pre_channel^1)) < 0)) {
+				     isdn_get_free_channel(
+					 		ISDN_USAGE_NET,
+							lp->l2_proto,
+							lp->l3_proto,
+							lp->pre_device,
+						    lp->pre_channel^1)
+							) < 0)) {
 					restore_flags(flags);
 					isdn_net_unreachable(ndev, skb,
 							   "No channel");
 					dev_kfree_skb(skb);
+#ifndef ISDN_NEW_TBUSY
 					ndev->tbusy = 0;
+#endif
 					return 0;
 				}
 				/* Log packet, which triggered dialing */
@@ -1421,6 +1528,9 @@
 					}
 					restore_flags(flags);
 					isdn_net_dial();	/* Initiate dialing */
+#ifdef ISDN_NEW_TBUSY
+					isdn_net_dev_xoff(ndev);
+#endif
 					return 1;	/* let upper layer requeue skb packet */
 				}
 #endif
@@ -1434,7 +1544,9 @@
 				}
 				lp->first_skb = skb;
 				/* Initiate dialing */
+#ifndef ISDN_NEW_TBUSY
 				ndev->tbusy = 0;
+#endif
 				restore_flags(flags);
 				isdn_net_dial();
 				return 0;
@@ -1442,21 +1554,37 @@
 				isdn_net_unreachable(ndev, skb,
 						     "No phone number");
 				dev_kfree_skb(skb);
+#ifndef ISDN_NEW_TBUSY
 				ndev->tbusy = 0;
+#endif
 				return 0;
 			}
 		} else {
-			/* Connection is established, try sending */
+			/* Device is connected to an ISDN channel */ 
 			ndev->trans_start = jiffies;
 			if (!lp->dialstate) {
+				/* ISDN connection is established, try sending */
+				int ret;
 				if (lp->first_skb) {
-					if (isdn_net_xmit(ndev, lp, lp->first_skb))
+					if (isdn_net_xmit(ndev, lp, lp->first_skb)){
+#ifdef ISDN_NEW_TBUSY
+						isdn_net_dev_xoff(ndev);
+#endif
 						return 1;
+}
 					lp->first_skb = NULL;
 				}
-				return (isdn_net_xmit(ndev, lp, skb));
+				ret = (isdn_net_xmit(ndev, lp, skb));
+#ifdef ISDN_NEW_TBUSY
+				if(ret) isdn_net_dev_xoff(ndev);
+#endif
+				return ret;
 			} else
+#ifdef ISDN_NEW_TBUSY
+				isdn_net_dev_xoff(ndev);
+#else
 				ndev->tbusy = 1;
+#endif
 		}
 	}
 	return 1;
@@ -2068,7 +2196,6 @@
 	isdn_net_phone *n;
 	ulong flags;
 	char nr[32];
-
 	/* Search name in netdev-chain */
 	save_flags(flags);
 	cli();
@@ -2280,10 +2407,15 @@
 					       lp->name, nr, eaz);
 					if (lp->phone[1]) {
 						/* Grab a free ISDN-Channel */
-						if ((chi = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto,
+						if ((chi = 
+							isdn_get_free_channel(
+								ISDN_USAGE_NET,
+								lp->l2_proto,
 							    lp->l3_proto,
-							  lp->pre_device,
-						 lp->pre_channel)) < 0) {
+							  	lp->pre_device,
+						 		lp->pre_channel)
+								) < 0) {
+
 							printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name);
 							restore_flags(flags);
 							return 0;
@@ -2390,10 +2522,14 @@
 			cli();
 
 			/* Grab a free ISDN-Channel */
-			if ((chi = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto,
-							 lp->l3_proto,
-							 lp->pre_device,
-						 lp->pre_channel)) < 0) {
+			if ((chi = 
+						isdn_get_free_channel(
+							ISDN_USAGE_NET,
+							lp->l2_proto,
+							lp->l3_proto,
+							lp->pre_device,
+						 	lp->pre_channel)
+							) < 0) {
 				printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name);
 				restore_flags(flags);
 				return -EAGAIN;
@@ -3153,4 +3289,3 @@
 	restore_flags(flags);
 	return 0;
 }
-
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_ppp.c linux.14p16/drivers/isdn/isdn_ppp.c
--- linux.vanilla/drivers/isdn/isdn_ppp.c	Wed Oct 20 01:12:38 1999
+++ linux.14p16/drivers/isdn/isdn_ppp.c	Thu Dec  9 15:34:07 1999
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.54 1999/09/13 23:25:17 he Exp $
+/* $Id: isdn_ppp.c,v 1.60 1999/11/04 20:29:55 he Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
@@ -19,6 +19,28 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_ppp.c,v $
+ * Revision 1.60  1999/11/04 20:29:55  he
+ * applied Andre Beck's reset_free fix
+ *
+ * Revision 1.59  1999/10/31 15:59:50  he
+ * more skb headroom checks
+ *
+ * Revision 1.58  1999/10/30 13:13:01  keil
+ * Henners isdn_ppp_skb_push:under fix
+ *
+ * Revision 1.57  1999/10/05 22:47:17  he
+ * Removed dead ISDN_SYNCPPP_READDRESS code (obsoleted by sysctl_ip_dynaddr
+ * and network address translation)
+ *
+ * Revision 1.56  1999/09/29 16:01:06  he
+ * replaced dev_alloc_skb() for downstream skbs by equivalent alloc_skb()
+ *
+ * Revision 1.55  1999/09/23 22:07:51  detabc
+ *
+ * make ipc_head common usable (for use compressor with raw-ip)
+ * add function before netif_rx(). needed for ipv4-tcp-keepalive-detect.
+ * ~
+ *
  * Revision 1.54  1999/09/13 23:25:17  he
  * serialized xmitting frames from isdn_ppp and BSENT statcallb
  *
@@ -218,10 +240,6 @@
 
 /* TODO: right tbusy handling when using MP */
 
-/*
- * experimental for dynamic addressing: readdress IP frames
- */
-#undef ISDN_SYNCPPP_READDRESS
 #define CONFIG_ISDN_CCP 1
 
 #include <linux/config.h>
@@ -264,6 +282,7 @@
 				    unsigned char code, unsigned char id,
 				    unsigned char *data, int len);
 static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is);
+static void isdn_ppp_ccp_reset_free(struct ippp_struct *is);
 static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
 					  unsigned char id);
 static void isdn_ppp_ccp_timer_callback(unsigned long closure);
@@ -287,9 +306,10 @@
 static void isdn_ppp_free_mpqueue(isdn_net_dev *);
 #endif
 
-char *isdn_ppp_revision = "$Revision: 1.54 $";
+char *isdn_ppp_revision = "$Revision: 1.60 $";
 
 static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
+
 static struct isdn_ppp_compressor *ipc_head = NULL;
 
 /*
@@ -360,10 +380,6 @@
 		printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp);
 
 	is->lp = NULL;          /* link is down .. set lp to NULL */
-#ifdef ISDN_SYNCPPP_READDRESS
-	is->old_pa_addr = 0x0;
-	is->old_pa_dstaddr = 0x0;
-#endif
 	lp->ppp_slot = -1;      /* is this OK ?? */
 	restore_flags(flags);
 
@@ -608,9 +624,9 @@
 	is->comp_stat    = is->link_comp_stat    = NULL;
         is->decomp_stat  = is->link_decomp_stat  = NULL;
 
+	/* Clean up if necessary */
 	if(is->reset)
-		kfree(is->reset);
-	is->reset = NULL;
+		isdn_ppp_ccp_reset_free(is);
 
 	/* this slot is ready for new connections */
 	is->state = 0;
@@ -1462,12 +1478,6 @@
 	ipts = ippp_table[mlp->ppp_slot];
 
 	if (!(ipts->pppcfg & SC_ENABLE_IP)) {	/* PPP connected ? */
-#ifdef ISDN_SYNCPPP_READDRESS
-		if (!ipts->old_pa_addr)
-			ipts->old_pa_addr = mdev->pa_addr;
-		if (!ipts->old_pa_dstaddr)
-			ipts->old_pa_dstaddr = mdev->pa_dstaddr;
-#endif
 		if (ipts->debug & 0x1)
 			printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
 		return 1;
@@ -1476,21 +1486,6 @@
 	switch (ntohs(skb->protocol)) {
 		case ETH_P_IP:
 			proto = PPP_IP;
-#ifdef ISDN_SYNCPPP_READDRESS
-			if (ipts->old_pa_addr != mdev->pa_addr) {
-				struct iphdr *ipfr;
-				ipfr = (struct iphdr *) skb->data;
-				if(ipts->debug & 0x4)
-					printk(KERN_DEBUG "IF-address changed from %lx to %lx\n", ipts->old_pa_addr, mdev->pa_addr);
-				if (ipfr->version == 4) {
-					if (ipfr->saddr == ipts->old_pa_addr) {
-						printk(KERN_DEBUG "readdressing %lx to %lx\n", ipfr->saddr, mdev->pa_addr);
-						ipfr->saddr = mdev->pa_addr;
-					}
-				}
-			}
-			/* dstaddr change not so important */
-#endif
 			break;
 		case ETH_P_IPX:
 			proto = PPP_IPX;	/* untested */
@@ -1521,8 +1516,6 @@
 
 	/* Pull off the fake header we stuck on earlier to keep
      * the fragemntation code happy.
-     * this will break the ISDN_SYNCPPP_READDRESS hack a few lines
-     * above. So, enabling this is no longer allowed
      */
 	skb_pull(skb,IPPP_MAX_HEADER);
 
@@ -1540,7 +1533,13 @@
 		 * sk_buff. old call to dev_alloc_skb only reserved
 		 * 16 bytes, now we are looking what the driver want.
 		 */
-		hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
+		hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen + IPPP_MAX_HEADER;
+		/* 
+		 * Note: hl might still be insufficient because the method
+		 * above does not account for a possibible MPPP slave channel
+		 * which had larger HL header space requirements than the
+		 * master.
+		 */
 		new_skb = alloc_skb(hl+skb->len, GFP_ATOMIC);
 		if (new_skb) {
 			u_char *buf;
@@ -2227,18 +2226,20 @@
 {
 	struct sk_buff *skb;
 	unsigned char *p;
-	int count;
+	int count, hl;
 	unsigned long flags;
 	int cnt = 0;
 	isdn_net_local *lp = is->lp;
 
 	/* Alloc large enough skb */
-	skb = dev_alloc_skb(len + 16);
+	hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
+	skb = alloc_skb(len + hl + 16,GFP_ATOMIC);
 	if(!skb) {
 		printk(KERN_WARNING
 		       "ippp: CCP cannot send reset - out of memory\n");
 		return;
 	}
+	skb_reserve(skb, hl);
 
 	/* We may need to stuff an address and control field first */
 	if(!(is->pppcfg & SC_COMP_AC)) {
@@ -2293,15 +2294,34 @@
 static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is)
 {
 	struct ippp_ccp_reset *r;
-	printk(KERN_DEBUG "ippp_ccp: allocating reset data structure\n");
 	r = kmalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
-	if(!r)
+	if(!r) {
+		printk(KERN_ERR "ippp_ccp: failed to allocate reset data"
+		       " structure - no mem\n");
 		return NULL;
+	}
 	memset(r, 0, sizeof(struct ippp_ccp_reset));
+	printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r);
 	is->reset = r;
 	return r;
 }
 
+/* Destroy the reset state vector. Kill all pending timers first. */
+static void isdn_ppp_ccp_reset_free(struct ippp_struct *is)
+{
+	unsigned int id;
+
+	printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n",
+	       is->reset);
+	for(id = 0; id < 256; id++) {
+		if(is->reset->rs[id]) {
+			isdn_ppp_ccp_reset_free_state(is, (unsigned char)id);
+		}
+	}
+	kfree(is->reset);
+	is->reset = NULL;
+}
+
 /* Free a given state and clear everything up for later reallocation */
 static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
 					  unsigned char id)
@@ -2667,9 +2687,11 @@
 	}
 
 	/* Allow for at least 150 % expansion (for now) */
-	skb_out = dev_alloc_skb(skb_in->len + skb_in->len/2 + 32);
+	skb_out = alloc_skb(skb_in->len + skb_in->len/2 + 32 +
+		skb_headroom(skb_in), GFP_ATOMIC);
 	if(!skb_out)
 		return skb_in;
+	skb_reserve(skb_out, skb_headroom(skb_in));
 
 	ret = (compressor->compress)(stat,skb_in,skb_out,*proto);
 	if(!ret) {
@@ -2898,7 +2920,6 @@
 	}
 }
 
-
 int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
 {
 	ipc->next = ipc_head;
@@ -2932,6 +2953,16 @@
 	if(is->debug & 0x10)
 		printk(KERN_DEBUG "[%d] Set %s type %d\n",is->unit,
 			(data->flags&IPPP_COMP_FLAG_XMIT)?"compressor":"decompressor",num);
+
+	/* If is has no valid reset state vector, we cannot allocate a
+	   decompressor. The decompressor would cause reset transactions
+	   sooner or later, and they need that vector. */
+
+	if(!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) {
+		printk(KERN_ERR "ippp_ccp: no reset data structure - can't"
+		       " allow decompression.\n");
+		return -ENOMEM;
+	}
 
 	while(ipc) {
 		if(ipc->num == num) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_tty.c linux.14p16/drivers/isdn/isdn_tty.c
--- linux.vanilla/drivers/isdn/isdn_tty.c	Wed Oct 20 01:12:38 1999
+++ linux.14p16/drivers/isdn/isdn_tty.c	Thu Dec  9 15:34:07 1999
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.74 1999/09/04 06:20:04 keil Exp $
+/* $Id: isdn_tty.c,v 1.80 1999/11/07 13:34:30 armin Exp $
 
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
@@ -20,6 +20,27 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_tty.c,v $
+ * Revision 1.80  1999/11/07 13:34:30  armin
+ * Fixed AT command line editor
+ *
+ * Revision 1.79  1999/10/29 18:35:08  armin
+ * Check number len in isdn_get_msnstr() to avoid buffer overflow.
+ *
+ * Revision 1.78  1999/10/28 23:03:51  armin
+ * Bugfix: now freeing channel on modem_hup() even when
+ * usage on ttyI has changed and error-report for
+ * AT-commands on wrong channel-state.
+ *
+ * Revision 1.77  1999/10/26 21:13:14  armin
+ * using define for checking phone number len in isdn_tty_getdial()
+ *
+ * Revision 1.76  1999/10/11 22:16:26  keil
+ * Suspend/Resume is possible without explicit ID too
+ *
+ * Revision 1.75  1999/10/08 18:59:32  armin
+ * Bugfix of too small MSN buffer and checking phone number
+ * in isdn_tty_getdial()
+ *
  * Revision 1.74  1999/09/04 06:20:04  keil
  * Changes from kernel set_current_state()
  *
@@ -351,7 +372,7 @@
 static int si2bit[8] =
 {4, 1, 4, 4, 4, 4, 4, 4};
 
-char *isdn_tty_revision = "$Revision: 1.74 $";
+char *isdn_tty_revision = "$Revision: 1.80 $";
 
 
 /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
@@ -1017,7 +1038,6 @@
 isdn_tty_modem_hup(modem_info * info, int local)
 {
 	isdn_ctrl cmd;
-	int usage;
 
 	if (!info)
 		return;
@@ -1071,10 +1091,7 @@
 		}
 		isdn_all_eaz(info->isdn_driver, info->isdn_channel);
 		info->emu.mdmreg[REG_RINGCNT] = 0;
-		usage = isdn_calc_usage(info->emu.mdmreg[REG_SI1I],
-					info->emu.mdmreg[REG_L2PROT]);
-		isdn_free_channel(info->isdn_driver, info->isdn_channel,
-				  usage);
+		isdn_free_channel(info->isdn_driver, info->isdn_channel, 0);
 	}
 	info->isdn_driver = -1;
 	info->isdn_channel = -1;
@@ -1111,8 +1128,8 @@
 	printk(KERN_DEBUG "Msusp ttyI%d\n", info->line);
 #endif
 	l = strlen(id);
-	if ((info->isdn_driver >= 0) && l) {
-		cmd.parm.cmsg.Length = l+17;
+	if ((info->isdn_driver >= 0)) {
+		cmd.parm.cmsg.Length = l+18;
 		cmd.parm.cmsg.Command = CAPI_FACILITY;
 		cmd.parm.cmsg.Subcommand = CAPI_REQ;
 		cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
@@ -1150,10 +1167,6 @@
 	int l;
 
 	l = strlen(id);
-	if (!l) {
-		isdn_tty_modem_result(4, info);
-		return;
-	}
 	for (j = 7; j >= 0; j--)
 		if (m->mdmreg[REG_SI1] & (1 << j)) {
 			si = bit2si[j];
@@ -1207,7 +1220,7 @@
 		isdn_command(&cmd);
 		cmd.driver = info->isdn_driver;
 		cmd.arg = info->isdn_channel;
-		cmd.parm.cmsg.Length = l+17;
+		cmd.parm.cmsg.Length = l+18;
 		cmd.parm.cmsg.Command = CAPI_FACILITY;
 		cmd.parm.cmsg.Subcommand = CAPI_REQ;
 		cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
@@ -3091,9 +3104,12 @@
 static void
 isdn_tty_get_msnstr(char *n, char **p)
 {
-	while ((*p[0] >= '0' && *p[0] <= '9') ||
+	int limit = ISDN_MSNLEN - 1;
+
+	while (((*p[0] >= '0' && *p[0] <= '9') ||
 	       /* Why a comma ??? */
-	       (*p[0] == ','))
+	       (*p[0] == ',')) &&
+		(limit--))
 		*n++ = *p[0]++;
 	*n = '\0';
 }
@@ -3105,16 +3121,18 @@
 isdn_tty_getdial(char *p, char *q,int cnt)
 {
 	int first = 1;
-	int limit=39;	/* MUST match the size in isdn_tty_parse to avoid
-				buffer overflow */
+	int limit = ISDN_MSNLEN - 1;	/* MUST match the size of interface var to avoid
+					buffer overflow */
 
 	while (strchr(" 0123456789,#.*WPTS-", *p) && *p && --cnt>0) {
 		if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first) ||
-		    (*p == '*') || (*p == '#'))
+		    (*p == '*') || (*p == '#')) {
 			*q++ = *p;
-		p++;
-		if(!--limit)
+			limit--;
+		}
+		if(!limit)
 			break;
+		p++;
 		first = 0;
 	}
 	*q = 0;
@@ -3258,6 +3276,8 @@
 		case 'F':
 			/* &F -Set Factory-Defaults */
 			p[0]++;
+			if (info->msr & UART_MSR_DCD)
+				PARSE_ERROR1;
 			isdn_tty_reset_profile(m);
 			isdn_tty_modem_reset_regs(info, 1);
 			break;
@@ -3909,6 +3929,12 @@
 				break;
 			case 'D':
 				/* D - Dial */
+				if (info->msr & UART_MSR_DCD)
+					PARSE_ERROR;
+				if (info->msr & UART_MSR_RI) {
+					isdn_tty_modem_result(3, info);
+					return;
+				}
 				isdn_tty_getdial(++p, ds, sizeof ds);
 				p += strlen(p);
 				if (!strlen(m->msn))
@@ -4103,7 +4129,7 @@
 			c = *p;
 		total++;
 		if (c == m->mdmreg[REG_CR] || c == m->mdmreg[REG_LF]) {
-			/* Separator (CR oder LF) */
+			/* Separator (CR or LF) */
 			m->mdmcmd[m->mdmcmdl] = 0;
 			if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
 				eb[0] = c;
@@ -4116,7 +4142,7 @@
 			continue;
 		}
 		if (c == m->mdmreg[REG_BS] && m->mdmreg[REG_BS] < 128) {
-			/* Backspace-Funktion */
+			/* Backspace-Function */
 			if ((m->mdmcmdl > 2) || (!m->mdmcmdl)) {
 				if (m->mdmcmdl)
 					m->mdmcmdl--;
@@ -4134,18 +4160,24 @@
 			if (m->mdmcmdl < 255) {
 				c = my_toupper(c);
 				switch (m->mdmcmdl) {
-					case 0:
-						if (c == 'A')
-							m->mdmcmd[m->mdmcmdl] = c;
-						break;
 					case 1:
-						if (c == 'T')
+						if (c == 'T') {
+							m->mdmcmd[m->mdmcmdl] = c;
+							m->mdmcmd[++m->mdmcmdl] = 0;
+							break;
+						} else
+							m->mdmcmdl = 0;
+						/* Fall through, check for 'A' */
+					case 0:
+						if (c == 'A') {
 							m->mdmcmd[m->mdmcmdl] = c;
+							m->mdmcmd[++m->mdmcmdl] = 0;
+						}
 						break;
 					default:
 						m->mdmcmd[m->mdmcmdl] = c;
+						m->mdmcmd[++m->mdmcmdl] = 0;
 				}
-				m->mdmcmd[++m->mdmcmdl] = 0;
 			}
 		}
 	}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_v110.c linux.14p16/drivers/isdn/isdn_v110.c
--- linux.vanilla/drivers/isdn/isdn_v110.c	Wed Oct 20 01:12:38 1999
+++ linux.14p16/drivers/isdn/isdn_v110.c	Thu Dec  9 15:34:09 1999
@@ -1,4 +1,4 @@
-/* $Id: isdn_v110.c,v 1.2 1998/02/22 19:44:25 fritz Exp $
+/* $Id: isdn_v110.c,v 1.3 1999/10/30 09:49:28 keil Exp $
 
  * Linux ISDN subsystem, V.110 related functions (linklevel).
  *
@@ -19,6 +19,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_v110.c,v $
+ * Revision 1.3  1999/10/30 09:49:28  keil
+ * Reinit of v110 structs
+ *
  * Revision 1.2  1998/02/22 19:44:25  fritz
  * Bugfixes and improvements regarding V.110, V.110 now running.
  *
@@ -36,7 +39,7 @@
 
 #undef ISDN_V110_DEBUG
 
-char *isdn_v110_revision = "$Revision: 1.2 $";
+char *isdn_v110_revision = "$Revision: 1.3 $";
 
 #define V110_38400 255
 #define V110_19200  15
@@ -148,7 +151,7 @@
 }
 
 /* isdn_v110_close frees private V.110 data structures */
-static void
+void
 isdn_v110_close(isdn_v110_stream * v)
 {
 	if (v == NULL)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_v110.h linux.14p16/drivers/isdn/isdn_v110.h
--- linux.vanilla/drivers/isdn/isdn_v110.h	Thu Apr  2 01:21:03 1998
+++ linux.14p16/drivers/isdn/isdn_v110.h	Thu Dec  9 15:34:09 1999
@@ -1,4 +1,4 @@
-/* $Id: isdn_v110.h,v 1.1 1998/02/20 17:32:11 fritz Exp $
+/* $Id: isdn_v110.h,v 1.2 1999/10/30 09:49:28 keil Exp $
 
  * Linux ISDN subsystem, V.110 related functions (linklevel).
  *
@@ -19,6 +19,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_v110.h,v $
+ * Revision 1.2  1999/10/30 09:49:28  keil
+ * Reinit of v110 structs
+ *
  * Revision 1.1  1998/02/20 17:32:11  fritz
  * First checkin (not yet completely functionable).
  *
@@ -41,5 +44,6 @@
 extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *);
 
 extern int isdn_v110_stat_callback(int, isdn_ctrl *);
+extern void isdn_v110_close(isdn_v110_stream * v);
 
 #endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/pcbit/drv.c linux.14p16/drivers/isdn/pcbit/drv.c
--- linux.vanilla/drivers/isdn/pcbit/drv.c	Wed Oct 20 01:12:38 1999
+++ linux.14p16/drivers/isdn/pcbit/drv.c	Thu Dec  9 15:34:07 1999
@@ -87,9 +87,11 @@
 	dev_pcbit[board] = dev;
 	memset(dev, 0, sizeof(struct pcbit_dev));
 
-	if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF )
+	if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF ) {
+		dev->ph_mem = mem_base;
 		dev->sh_mem = (unsigned char*) mem_base;
-	else
+	}
+	else 
 	{
 		printk("memory address invalid");
 		kfree(dev);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/pcbit/pcbit.h linux.14p16/drivers/isdn/pcbit/pcbit.h
--- linux.vanilla/drivers/isdn/pcbit/pcbit.h	Wed Oct 20 01:12:38 1999
+++ linux.14p16/drivers/isdn/pcbit/pcbit.h	Thu Dec  9 15:34:07 1999
@@ -46,6 +46,7 @@
 	/* board */
 
 	volatile unsigned char* sh_mem;		/* RDP address	*/
+	unsigned long ph_mem;
 	unsigned int irq;
 	unsigned int id;
 	unsigned int interrupt;			/* set during interrupt 
@@ -166,10 +167,3 @@
 #define L2_ERROR    6
 
 #endif
-
-
-
-
-
-
-
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/macintosh/macserial.c linux.14p16/drivers/macintosh/macserial.c
--- linux.vanilla/drivers/macintosh/macserial.c	Wed Oct 20 01:12:38 1999
+++ linux.14p16/drivers/macintosh/macserial.c	Thu Dec  9 15:34:15 1999
@@ -6,7 +6,9 @@
  * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  *
- * $Id: macserial.c,v 1.24.2.3 1999/09/10 02:05:58 paulus Exp $
+ * Receive DMA code by Takashi Oe <toe@unlserve.unl.edu>.
+ *
+ * $Id: macserial.c,v 1.24.2.4 1999/10/19 04:36:42 paulus Exp $
  */
 
 #include <linux/config.h>
@@ -28,6 +30,7 @@
 #ifdef CONFIG_SERIAL_CONSOLE
 #include <linux/console.h>
 #endif
+#include <linux/slab.h>
 
 #include <asm/io.h>
 #include <asm/pgtable.h>
@@ -42,6 +45,7 @@
 #ifdef CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
+#include <asm/dbdma.h>
 
 #include "macserial.h"
 
@@ -53,6 +57,8 @@
 };
 #endif
 
+#define SUPPORT_SERIAL_DMA
+
 /*
  * It would be nice to dynamically allocate everything that
  * depends on NUM_SERIAL, so we could support any number of
@@ -128,6 +134,13 @@
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
 static int set_scc_power(struct mac_serial * info, int state);
 static int setup_scc(struct mac_serial * info);
+static void dbdma_reset(volatile struct dbdma_regs *dma);
+static void dbdma_flush(volatile struct dbdma_regs *dma);
+static void rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs);
+static void rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs);
+static void dma_init(struct mac_serial * info);
+static void rxdma_start(struct mac_serial * info, int current);
+static void rxdma_to_tty(struct mac_serial * info);
 
 static struct tty_struct *serial_table[NUM_CHANNELS];
 static struct termios *serial_termios[NUM_CHANNELS];
@@ -153,7 +166,7 @@
 __openfirmware
 #endif /* MODULE */
 static inline int serial_paranoia_check(struct mac_serial *info,
-					dev_t device, const char *routine)
+                                       dev_t device, const char *routine)
 {
 #ifdef SERIAL_PARANOIA_CHECK
 	static const char *badmagic =
@@ -177,7 +190,7 @@
  * Reading and writing Z8530 registers.
  */
 static inline unsigned char read_zsreg(struct mac_zschannel *channel,
-				       unsigned char reg)
+                                      unsigned char reg)
 {
 	unsigned char retval;
 	unsigned long flags;
@@ -197,7 +210,7 @@
 }
 
 static inline void write_zsreg(struct mac_zschannel *channel,
-			       unsigned char reg, unsigned char value)
+                              unsigned char reg, unsigned char value)
 {
 	unsigned long flags;
 
@@ -290,6 +303,39 @@
 }
 
 /*
+ * Reset a Descriptor-Based DMA channel.
+ */
+static void dbdma_reset(volatile struct dbdma_regs *dma)
+{
+	int i;
+
+	out_le32(&dma->control, (WAKE|FLUSH|PAUSE|RUN) << 16);
+
+	/*
+	 * Yes this looks peculiar, but apparently it needs to be this
+	 * way on some machines.  (We need to make sure the DBDMA
+	 * engine has actually got the write above and responded
+	 * to it. - paulus)
+	 */
+	for (i = 200; i > 0; --i)
+		if (ld_le32(&dma->control) & RUN)
+			udelay(1);
+}
+
+/*
+ * Tells a DBDMA channel to stop and write any buffered data
+ * it might have to memory.
+ */
+static _INLINE_ void dbdma_flush(volatile struct dbdma_regs *dma)
+{
+	int i = 0;
+
+	out_le32(&dma->control, (FLUSH << 16) | FLUSH);
+	while (((in_le32(&dma->status) & FLUSH) != 0) && (i++ < 100))
+		udelay(1);
+}
+
+/*
  * ----------------------------------------------------------------------
  *
  * Here starts the interrupt handling routines.  All of the following
@@ -312,6 +358,22 @@
 	mark_bh(MACSERIAL_BH);
 }
 
+/* Work out the flag value for a z8530 status value. */
+static _INLINE_ int stat_to_flag(int stat)
+{
+	int flag;
+
+	if (stat & Rx_OVR) {
+		flag = TTY_OVERRUN;
+	} else if (stat & FRM_ERR) {
+		flag = TTY_FRAME;
+	} else if (stat & PAR_ERR) {
+		flag = TTY_PARITY;
+	} else
+		flag = 0;
+	return flag;
+}
+
 static _INLINE_ void receive_chars(struct mac_serial *info,
 				   struct pt_regs *regs)
 {
@@ -349,14 +411,7 @@
 			if (flip_max_cnt < tty->flip.count)
 				flip_max_cnt = tty->flip.count;
 		}
-		if (stat & Rx_OVR) {
-			flag = TTY_OVERRUN;
-		} else if (stat & FRM_ERR) {
-			flag = TTY_FRAME;
-		} else if (stat & PAR_ERR) {
-			flag = TTY_PARITY;
-		} else
-			flag = 0;
+		flag = stat_to_flag(stat);
 		if (flag)
 			/* reset the error indication */
 			write_zsreg(info->zs_channel, 0, ERR_RES);
@@ -452,6 +507,32 @@
 	info->read_reg_zero = status;
 }
 
+static _INLINE_ void receive_special_dma(struct mac_serial *info)
+{
+	unsigned char stat, flag;
+	volatile struct dbdma_regs *rd = &info->rx->dma;
+	int where = RX_BUF_SIZE;
+
+	spin_lock(&info->rx_dma_lock);
+	if ((ld_le32(&rd->status) & ACTIVE) != 0)
+		dbdma_flush(rd);
+	if (in_le32(&rd->cmdptr)
+	    == virt_to_bus(info->rx_cmds[info->rx_cbuf] + 1))
+		where -= in_le16(&info->rx->res_count);
+	where--;
+	
+	stat = read_zsreg(info->zs_channel, R1);
+
+	flag = stat_to_flag(stat);
+	if (flag) {
+		info->rx_flag_buf[info->rx_cbuf][where] = flag;
+		/* reset the error indication */
+		write_zsreg(info->zs_channel, 0, ERR_RES);
+	}
+
+	spin_unlock(&info->rx_dma_lock);
+}
+
 /*
  * This is the serial driver's generic interrupt routine
  */
@@ -461,6 +542,12 @@
 	unsigned char zs_intreg;
 	int shift;
 
+	if (!(info->flags & ZILOG_INITIALIZED)) {
+		printk("rs_interrupt: irq %d, port not initialized\n", irq);
+		disable_irq(irq);
+		return;
+	}
+
 	/* NOTE: The read register 3, which holds the irq status,
 	 *       does so for both channels on each chip.  Although
 	 *       the status value itself must be read from the A
@@ -477,19 +564,21 @@
 	for (;;) {
 		zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift;
 #ifdef SERIAL_DEBUG_INTR
-		printk("rs_interrupt: irq %d, zs_intreg 0x%x\n", irq, (int)zs_intreg);
+		printk("rs_interrupt: irq %d, zs_intreg 0x%x\n",
+		       irq, (int)zs_intreg);
 #endif	
 
 		if ((zs_intreg & CHAN_IRQMASK) == 0)
 			break;
 
-		if (!(info->flags & ZILOG_INITIALIZED)) {
-			printk("rs_interrupt: irq %d, port not initialized\n", irq);
-			break;
+		if (zs_intreg & CHBRxIP) {
+			/* If we are doing DMA, we only ask for interrupts
+			   on characters with errors or special conditions. */
+			if (info->dma_initted)
+				receive_special_dma(info);
+			else
+				receive_chars(info, regs);
 		}
-
-		if (zs_intreg & CHBRxIP)
-			receive_chars(info, regs);
 		if (zs_intreg & CHBTxIP)
 			transmit_chars(info);
 		if (zs_intreg & CHBEXT)
@@ -497,6 +586,39 @@
 	}
 }
 
+/* Transmit DMA interrupt - not used at present */
+static void rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+/*
+ * Receive DMA interrupt.
+ */
+static void rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct mac_serial *info = (struct mac_serial *) dev_id;
+	volatile struct dbdma_cmd *cd;
+
+	if (!info->dma_initted)
+		return;
+	spin_lock(&info->rx_dma_lock);
+	/* First, confirm that this interrupt is, indeed, coming */
+	/* from Rx DMA */
+	cd = info->rx_cmds[info->rx_cbuf] + 2;
+	if ((in_le16(&cd->xfer_status) & (RUN | ACTIVE)) != (RUN | ACTIVE)) {
+		spin_unlock(&info->rx_dma_lock);
+		return;
+	}
+	if (info->rx_fbuf != RX_NO_FBUF) {
+		info->rx_cbuf = info->rx_fbuf;
+		if (++info->rx_fbuf == info->rx_nbuf)
+			info->rx_fbuf = 0;
+		if (info->rx_fbuf == info->rx_ubuf)
+			info->rx_fbuf = RX_NO_FBUF;
+	}
+	spin_unlock(&info->rx_dma_lock);
+}
+
 /*
  * -------------------------------------------------------------------
  * Here ends the serial interrupt routines.
@@ -592,10 +714,6 @@
 	}
 }
 
-static void rs_timer(void)
-{
-}
-
 static int startup(struct mac_serial * info, int can_sleep)
 {
 	int delay;
@@ -631,6 +749,10 @@
 
 	info->flags |= ZILOG_INITIALIZED;
 	enable_irq(info->irq);
+	if (info->dma_initted) {
+//		enable_irq(info->tx_dma_irq);
+		enable_irq(info->rx_dma_irq);
+	}
 
 	if (delay) {
 		if (can_sleep) {
@@ -644,6 +766,187 @@
 	return 0;
 }
 
+static _INLINE_ void rxdma_start(struct mac_serial * info, int current)
+{
+	volatile struct dbdma_regs *rd = &info->rx->dma;
+	volatile struct dbdma_cmd *cd = info->rx_cmds[current];
+
+//printk(KERN_DEBUG "SCC: rxdma_start\n");
+
+	st_le32(&rd->cmdptr, virt_to_bus(cd));
+	out_le32(&rd->control, (RUN << 16) | RUN);
+}
+
+static void rxdma_to_tty(struct mac_serial *info)
+{
+	struct tty_struct	*tty = info->tty;
+	volatile struct dbdma_regs *rd = &info->rx->dma;
+	unsigned long flags;
+	int residue, available, space, do_queue;
+
+	if (!tty)
+		return;
+
+	do_queue = 0;
+	spin_lock_irqsave(&info->rx_dma_lock, flags);
+more:
+	space = TTY_FLIPBUF_SIZE - tty->flip.count;
+	if (!space) {
+		do_queue++;
+		goto out;
+	}
+	residue = 0;
+	if (info->rx_ubuf == info->rx_cbuf) {
+		if ((ld_le32(&rd->status) & ACTIVE) != 0) {
+			dbdma_flush(rd);
+			if (in_le32(&rd->cmdptr)
+			    == virt_to_bus(info->rx_cmds[info->rx_cbuf]+1))
+				residue = in_le16(&info->rx->res_count);
+		}
+	}
+	available = RX_BUF_SIZE - residue - info->rx_done_bytes;
+	if (available > space)
+		available = space;
+	if (available) {
+		memcpy(tty->flip.char_buf_ptr,
+		       info->rx_char_buf[info->rx_ubuf] + info->rx_done_bytes,
+		       available);
+		memcpy(tty->flip.flag_buf_ptr,
+		       info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes,
+		       available);
+		tty->flip.char_buf_ptr += available;
+		tty->flip.count += available;
+		tty->flip.flag_buf_ptr += available;
+		memset(info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes,
+		       0, available);
+		info->rx_done_bytes += available;
+		do_queue++;
+	}
+	if (info->rx_done_bytes == RX_BUF_SIZE) {
+		volatile struct dbdma_cmd *cd = info->rx_cmds[info->rx_ubuf];
+
+		if (info->rx_ubuf == info->rx_cbuf)
+			goto out;
+		/* mark rx_char_buf[rx_ubuf] free */
+		st_le16(&cd->command, DBDMA_NOP);
+		cd++;
+		st_le32(&cd->cmd_dep, 0);
+		st_le32((unsigned int *)&cd->res_count, 0);
+		cd++;
+		st_le16(&cd->xfer_status, 0);
+
+		if (info->rx_fbuf == RX_NO_FBUF) {
+			info->rx_fbuf = info->rx_ubuf;
+			if (!(ld_le32(&rd->status) & ACTIVE)) {
+				dbdma_reset(&info->rx->dma);
+				rxdma_start(info, info->rx_ubuf);
+				info->rx_cbuf = info->rx_ubuf;
+			}
+		}
+		info->rx_done_bytes = 0;
+		if (++info->rx_ubuf == info->rx_nbuf)
+			info->rx_ubuf = 0;
+		if (info->rx_fbuf == info->rx_ubuf)
+			info->rx_fbuf = RX_NO_FBUF;
+		goto more;
+	}
+out:
+	spin_unlock_irqrestore(&info->rx_dma_lock, flags);
+	if (do_queue)
+		queue_task(&tty->flip.tqueue, &tq_timer);
+}
+
+static void poll_rxdma(void *private_)
+{
+	struct mac_serial	*info = (struct mac_serial *) private_;
+	unsigned long flags;
+
+	rxdma_to_tty(info);
+	spin_lock_irqsave(&info->rx_dma_lock, flags);
+	mod_timer(&info->poll_dma_timer, RX_DMA_TIMER);
+	spin_unlock_irqrestore(&info->rx_dma_lock, flags);
+}
+
+static void dma_init(struct mac_serial * info)
+{
+	int i, size;
+	volatile struct dbdma_cmd *cd;
+	unsigned char *p;
+
+//printk(KERN_DEBUG "SCC: dma_init\n");
+
+	info->rx_nbuf = 8;
+
+	/* various mem set up */
+	size = sizeof(struct dbdma_cmd) * (3 * info->rx_nbuf + 2)
+		+ (RX_BUF_SIZE * 2 + sizeof(*info->rx_cmds)
+		   + sizeof(*info->rx_char_buf) + sizeof(*info->rx_flag_buf))
+		* info->rx_nbuf;
+	info->dma_priv = kmalloc(size, GFP_KERNEL | GFP_DMA);
+	if (info->dma_priv == NULL)
+		return;
+	memset(info->dma_priv, 0, size);
+
+	info->rx_cmds = (volatile struct dbdma_cmd **)info->dma_priv;
+	info->rx_char_buf = (unsigned char **) (info->rx_cmds + info->rx_nbuf);
+	info->rx_flag_buf = info->rx_char_buf + info->rx_nbuf;
+	p = (unsigned char *) (info->rx_flag_buf + info->rx_nbuf);
+	for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE)
+		info->rx_char_buf[i] = p;
+	for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE)
+		info->rx_flag_buf[i] = p;
+
+	/* a bit of DMA programming */
+	cd = info->rx_cmds[0] = (volatile struct dbdma_cmd *) DBDMA_ALIGN(p);
+	st_le16(&cd->command, DBDMA_NOP);
+	cd++;
+	st_le16(&cd->req_count, RX_BUF_SIZE);
+	st_le16(&cd->command, INPUT_MORE);
+	st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[0]));
+	cd++;
+	st_le16(&cd->req_count, 4);
+	st_le16(&cd->command, STORE_WORD | INTR_ALWAYS);
+	st_le32(&cd->phy_addr, virt_to_bus(cd-2));
+	st_le32(&cd->cmd_dep, DBDMA_STOP);
+	for (i = 1; i < info->rx_nbuf; i++) {
+		info->rx_cmds[i] = ++cd;
+		st_le16(&cd->command, DBDMA_NOP);
+		cd++;
+		st_le16(&cd->req_count, RX_BUF_SIZE);
+		st_le16(&cd->command, INPUT_MORE);
+		st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[i]));
+		cd++;
+		st_le16(&cd->req_count, 4);
+		st_le16(&cd->command, STORE_WORD | INTR_ALWAYS);
+		st_le32(&cd->phy_addr, virt_to_bus(cd-2));
+		st_le32(&cd->cmd_dep, DBDMA_STOP);
+	}
+	cd++;
+	st_le16(&cd->command, DBDMA_NOP | BR_ALWAYS);
+	st_le32(&cd->cmd_dep, virt_to_bus(info->rx_cmds[0]));
+
+	/* setup DMA to our liking */
+	dbdma_reset(&info->rx->dma);
+	st_le32(&info->rx->dma.intr_sel, 0x10001);
+	st_le32(&info->rx->dma.br_sel, 0x10001);
+	out_le32(&info->rx->dma.wait_sel, 0x10001);
+
+	/* set various flags */
+	info->rx_ubuf = 0;
+	info->rx_cbuf = 0;
+	info->rx_fbuf = info->rx_ubuf + 1;
+	if (info->rx_fbuf == info->rx_nbuf)
+		info->rx_fbuf = RX_NO_FBUF;
+	info->rx_done_bytes = 0;
+
+	/* setup polling */
+	init_timer(&info->poll_dma_timer);
+	info->poll_dma_timer.function = (void *)&poll_rxdma;
+	info->poll_dma_timer.data = (unsigned long)info;
+
+	info->dma_initted = 1;
+}
+
 static int setup_scc(struct mac_serial * info)
 {
 	unsigned long flags;
@@ -669,6 +972,12 @@
 	info->xmit_fifo_size = 1;
 
 	/*
+	 * Reset DMAs
+	 */
+	if (info->has_dma)
+		dma_init(info);
+
+	/*
 	 * Clear the interrupt registers.
 	 */
 	write_zsreg(info->zs_channel, 0, ERR_RES);
@@ -682,7 +991,23 @@
 	/*
 	 * Finally, enable sequencing and interrupts
 	 */
-	info->curregs[1] = (info->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+	if (!info->dma_initted) {
+		/* interrupt on ext/status changes, all received chars,
+		   transmit ready */
+		info->curregs[1] = (info->curregs[1] & ~0x18)
+				| (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+	} else {
+		/* interrupt on ext/status changes, W/Req pin is
+		   receive DMA request */
+		info->curregs[1] = (info->curregs[1] & ~(0x18 | TxINT_ENAB))
+				| (EXT_INT_ENAB | WT_RDY_RT | WT_FN_RDYFN);
+		write_zsreg(info->zs_channel, 1, info->curregs[1]);
+		/* enable W/Req pin */
+		info->curregs[1] |= WT_RDY_ENAB;
+		write_zsreg(info->zs_channel, 1, info->curregs[1]);
+		/* enable interrupts on transmit ready and receive errors */
+		info->curregs[1] |= INT_ERR_Rx | TxINT_ENAB;
+	}
 	info->pendregs[1] = info->curregs[1];
 	info->curregs[3] |= (RxENABLE | Rx8);
 	info->pendregs[3] = info->curregs[3];
@@ -708,6 +1033,14 @@
 
 	restore_flags(flags);
 
+	if (info->dma_initted) {
+		spin_lock_irqsave(&info->rx_dma_lock, flags);
+		rxdma_start(info, 0);
+		info->poll_dma_timer.expires = RX_DMA_TIMER;
+		add_timer(&info->poll_dma_timer);
+		spin_unlock_irqrestore(&info->rx_dma_lock, flags);
+	}
+
 	return 0;
 }
 
@@ -729,7 +1062,14 @@
 	
 		return;
 	}
-	
+
+	if (info->has_dma) {
+		del_timer(&info->poll_dma_timer);
+		dbdma_reset(info->tx_dma);
+		dbdma_reset(&info->rx->dma);
+		disable_irq(info->tx_dma_irq);
+		disable_irq(info->rx_dma_irq);
+	}
 	disable_irq(info->irq);
 
 	info->pendregs[1] = info->curregs[1] = 0;
@@ -755,6 +1095,12 @@
 		info->xmit_buf = 0;
 	}
 
+	if (info->has_dma && info->dma_priv) {
+		kfree(info->dma_priv);
+		info->dma_priv = NULL;
+		info->dma_initted = 0;
+	}
+
 	memset(info->curregs, 0, sizeof(info->curregs));
 	memset(info->curregs, 0, sizeof(info->pendregs));
 
@@ -1052,7 +1398,6 @@
 	if (!tty || !info->xmit_buf || !tmp_buf)
 		return 0;
 
-	save_flags(flags);
 	if (from_user) {
 		down(&tmp_buf_sem);
 		while (1) {
@@ -1068,6 +1413,7 @@
 					ret = -EFAULT;
 				break;
 			}
+			save_flags(flags);
 			cli();
 			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
 				       SERIAL_XMIT_SIZE - info->xmit_head));
@@ -1083,6 +1429,7 @@
 		up(&tmp_buf_sem);
 	} else {
 		while (1) {
+			save_flags(flags);
 			cli();		
 			c = MIN(count,
 				MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
@@ -1104,7 +1451,6 @@
 	if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
 	    && !info->tx_active)
 		transmit_chars(info);
-	restore_flags(flags);
 	return ret;
 }
 
@@ -1133,12 +1479,13 @@
 static void rs_flush_buffer(struct tty_struct *tty)
 {
 	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+	unsigned long flags;
 				
 	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
 		return;
-	cli();
+	save_flags(flags); cli();
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-	sti();
+	restore_flags(flags);
 	wake_up_interruptible(&tty->write_wait);
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 	    tty->ldisc.write_wakeup)
@@ -1158,7 +1505,6 @@
 	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
 	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
-	char	buf[64];
 	
 	printk("throttle %ld....\n",tty->ldisc.chars_in_buffer(tty));
 #endif
@@ -1195,7 +1541,6 @@
 	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
 	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
-	char	buf[64];
 	
 	printk("unthrottle %s: %d....\n",tty->ldisc.chars_in_buffer(tty));
 #endif
@@ -1473,6 +1818,7 @@
 	save_flags(flags); cli();
 	
 	if (tty_hung_up_p(filp)) {
+		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 		return;
 	}
@@ -1498,6 +1844,7 @@
 		info->count = 0;
 	}
 	if (info->count) {
+		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 		return;
 	}
@@ -1518,8 +1865,12 @@
 	printk("waiting end of Tx... (timeout:%d)\n", info->closing_wait);
 #endif
 	tty->closing = 1;
-	if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
+	if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) {
+		restore_flags(flags);
 		tty_wait_until_sent(tty, info->closing_wait);
+		save_flags(flags); cli();
+	}
+
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receiver and receive interrupts.
@@ -1539,7 +1890,9 @@
 #ifdef SERIAL_DEBUG_OPEN
 		printk("waiting end of Rx...\n");
 #endif
+		restore_flags(flags);
 		rs_wait_until_sent(tty, info->timeout);
+		save_flags(flags); cli();
 	}
 
 	shutdown(info);
@@ -1565,6 +1918,7 @@
 	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
 			 ZILOG_CLOSING);
 	wake_up_interruptible(&info->close_wait);
+	MOD_DEC_USE_COUNT;
 }
 
 /*
@@ -1603,7 +1957,6 @@
 		char_time = MIN(char_time, timeout);
 	while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
 		current->state = TASK_INTERRUPTIBLE;
-		current->counter = 0;	/* make us low-priority */
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
@@ -1775,14 +2128,19 @@
 	int 			retval, line;
 	unsigned long		page;
 
+	MOD_INC_USE_COUNT;
 	line = MINOR(tty->device) - tty->driver.minor_start;
-	if ((line < 0) || (line >= zs_channels_found))
+	if ((line < 0) || (line >= zs_channels_found)) {
+		MOD_DEC_USE_COUNT;
 		return -ENODEV;
+	}
 	info = zs_soft + line;
 
 #ifdef CONFIG_KGDB
-	if (info->kgdb_channel)
+	if (info->kgdb_channel) {
+		MOD_DEC_USE_COUNT;
 		return -ENODEV;
+	}
 #endif
 	if (serial_paranoia_check(info, tty->device, "rs_open"))
 		return -ENODEV;
@@ -1865,7 +2223,58 @@
 
 static void show_serial_version(void)
 {
-	printk("PowerMac Z8530 serial driver version 1.01\n");
+	printk("PowerMac Z8530 serial driver version 2.0\n");
+}
+
+/*
+ * Initialize one channel, both the mac_serial and mac_zschannel
+ * structs.  We use the dev_node field of the mac_serial struct.
+ */
+static void
+chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan,
+	  struct mac_zschannel *zs_chan_a)
+{
+	struct device_node *ch = zss->dev_node;
+	char *conn;
+	int len;
+
+	zss->irq = ch->intrs[0].line;
+	zss->has_dma = 0;
+#if !defined(CONFIG_KGDB) && defined(SUPPORT_SERIAL_DMA)
+	if (ch->n_addrs == 3 && ch->n_intrs == 3)
+		zss->has_dma = 1;
+#endif
+	zss->dma_initted = 0;
+
+	zs_chan->control = (volatile unsigned char *)
+		ioremap(ch->addrs[0].address, 0x1000);
+	zs_chan->data = zs_chan->control + 0x10;
+	spin_lock_init(&zs_chan->lock);
+	zs_chan->parent = zss;
+	zss->zs_channel = zs_chan;
+	zss->zs_chan_a = zs_chan_a;
+
+	/* setup misc varariables */
+	zss->kgdb_channel = 0;
+	zss->is_cobalt_modem = device_is_compatible(ch, "cobalt");
+
+	/* XXX tested only with wallstreet PowerBook,
+	   should do no harm anyway */
+	conn = get_property(ch, "AAPL,connector", &len);
+	zss->is_pwbk_ir = conn && (strcmp(conn, "infrared") == 0);
+
+	if (zss->has_dma) {
+		zss->dma_priv = NULL;
+		/* it seems that the last two addresses are the
+		   DMA controllers */
+		zss->tx_dma = (volatile struct dbdma_regs *)
+			ioremap(ch->addrs[ch->n_addrs - 2].address, 0x100);
+		zss->rx = (volatile struct mac_dma *)
+			ioremap(ch->addrs[ch->n_addrs - 1].address, 0x100);
+		zss->tx_dma_irq = ch->intrs[1].line;
+		zss->rx_dma_irq = ch->intrs[2].line;
+		spin_lock_init(&zss->rx_dma_lock);
+	}
 }
 
 /* Ask the PROM how many Z8530s we have and initialize their zs_channels */
@@ -1874,51 +2283,63 @@
 {
 	struct device_node *dev, *ch;
 	struct mac_serial **pp;
-	int n, lenp;
-	char *conn;
+	int n, chip, nchan;
+	struct mac_zschannel *zs_chan;
+	int chan_a_index;
 
 	n = 0;
 	pp = &zs_chain;
+	zs_chan = zs_channels;
 	for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
+		nchan = 0;
+		chip = n;
 		if (n >= NUM_CHANNELS) {
 			printk("Sorry, can't use %s: no more channels\n",
 			       dev->full_name);
 			continue;
 		}
+		chan_a_index = 0;
 		for (ch = dev->child; ch != 0; ch = ch->sibling) {
+			if (nchan >= 2) {
+				printk(KERN_WARNING "SCC: Only 2 channels per "
+					"chip are supported\n");
+				break;
+			}
 			if (ch->n_addrs < 1 || (ch ->n_intrs < 1)) {
 				printk("Can't use %s: %d addrs %d intrs\n",
 				      ch->full_name, ch->n_addrs, ch->n_intrs);
 				continue;
 			}
-			zs_channels[n].control = (volatile unsigned char *)
-				ioremap(ch->addrs[0].address, 0x1000);
-			zs_channels[n].data = zs_channels[n].control + 0x10;
-			spin_lock_init(&zs_channels[n].lock);
-			zs_soft[n].zs_channel = &zs_channels[n];
-			zs_soft[n].dev_node = ch;
-			zs_soft[n].irq = ch->intrs[0].line;
-			zs_soft[n].zs_channel->parent = &zs_soft[n];
-			zs_soft[n].is_cobalt_modem = device_is_compatible(ch, "cobalt");
-
-			/* XXX tested only with wallstreet PowerBook,
-			   should do no harm anyway */
-			conn = get_property(ch, "AAPL,connector", &lenp);
-			zs_soft[n].is_pwbk_ir =
-				conn && (strcmp(conn, "infrared") == 0);
-
-			/* XXX this assumes the prom puts chan A before B */
-			if (n & 1)
-				zs_soft[n].zs_chan_a = &zs_channels[n-1];
-			else
-				zs_soft[n].zs_chan_a = &zs_channels[n];
 
+			/* The channel with the higher address
+			   will be the A side. */
+			if (nchan > 0 &&
+			    ch->addrs[0].address
+			    > zs_soft[n-1].dev_node->addrs[0].address)
+				chan_a_index = 1;
+
+			/* minimal initialization for now */
+			zs_soft[n].dev_node = ch;
 			*pp = &zs_soft[n];
 			pp = &zs_soft[n].zs_next;
+			++nchan;
 			++n;
 		}
+		if (nchan == 0)
+			continue;
+
+		/* set up A side */
+		chan_init(&zs_soft[chip + chan_a_index], zs_chan, zs_chan);
+		++zs_chan;
+
+		/* set up B side, if it exists */
+		if (nchan > 1)
+			chan_init(&zs_soft[chip + 1 - chan_a_index],
+				  zs_chan, zs_chan - 1);
+		++zs_chan;
 	}
 	*pp = 0;
+
 	zs_channels_found = n;
 #ifdef CONFIG_PMAC_PBOOK
 	if (n)
@@ -1935,8 +2356,6 @@
 
 	/* Setup base handler, and timer table. */
 	init_bh(MACSERIAL_BH, do_serial_bh);
-	timer_table[RS_TIMER].fn = rs_timer;
-	timer_table[RS_TIMER].expires = 0;
 
 	/* Find out how many Z8530 SCCs we have */
 	if (zs_chain == 0)
@@ -1948,6 +2367,18 @@
 	/* Register the interrupt handler for each one */
 	save_flags(flags); cli();
 	for (i = 0; i < zs_channels_found; ++i) {
+		if (zs_soft[i].has_dma) {
+			if (request_irq(zs_soft[i].tx_dma_irq, rs_txdma_irq, 0,
+					"SCC-txdma", &zs_soft[i]))
+				printk(KERN_ERR "macserial: can't get irq %d\n",
+				       zs_soft[i].tx_dma_irq);
+			disable_irq(zs_soft[i].tx_dma_irq);
+			if (request_irq(zs_soft[i].rx_dma_irq, rs_rxdma_irq, 0,
+					"SCC-rxdma", &zs_soft[i]))
+				printk(KERN_ERR "macserial: can't get irq %d\n",
+				       zs_soft[i].rx_dma_irq);
+			disable_irq(zs_soft[i].rx_dma_irq);
+		}
 		if (request_irq(zs_soft[i].irq, rs_interrupt, 0,
 				"SCC", &zs_soft[i]))
 			printk(KERN_ERR "macserial: can't get irq %d\n",
@@ -2107,8 +2538,13 @@
 	for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
 		set_scc_power(info, 0);
 	save_flags(flags); cli();
-	for (i = 0; i < zs_channels_found; ++i)
+	for (i = 0; i < zs_channels_found; ++i) {
 		free_irq(zs_soft[i].irq, &zs_soft[i]);
+		if (zs_soft[i].has_dma) {
+			free_irq(zs_soft[i].tx_dma_irq, &zs_soft[i]);
+			free_irq(zs_soft[i].rx_dma_irq, &zs_soft[i]);
+		}
+	}
 	restore_flags(flags);
 	tty_unregister_driver(&callout_driver);
 	tty_unregister_driver(&serial_driver);
@@ -2238,6 +2674,8 @@
 	if (zs_chain == 0)
 		return -1;
 
+	set_scc_power(info, 1);
+
 	/* Reset the channel */
 	write_zsreg(info->zs_channel, R9, CHRA);
 
@@ -2481,14 +2919,13 @@
 	if (zs_chain == 0)
 		probe_sccs();
 
-	set_scc_power(&zs_soft[n], 1);
+	set_scc_power(&zs_soft[tty_num], 1);
 	
 	zs_kgdbchan = zs_soft[tty_num].zs_channel;
 	zs_soft[tty_num].change_needed = 0;
 	zs_soft[tty_num].clk_divisor = 16;
 	zs_soft[tty_num].zs_baud = 38400;
 	zs_soft[tty_num].kgdb_channel = 1;     /* This runs kgdb */
-	zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
 
 	/* Turn on transmitter/receiver at 8-bits/char */
         kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/macintosh/macserial.h linux.14p16/drivers/macintosh/macserial.h
--- linux.vanilla/drivers/macintosh/macserial.h	Wed Oct 20 01:12:38 1999
+++ linux.14p16/drivers/macintosh/macserial.h	Thu Dec  9 15:34:15 1999
@@ -92,6 +92,13 @@
 	struct mac_serial*	parent;
 };
 
+struct mac_dma {
+	volatile struct dbdma_regs	dma;
+	volatile unsigned short		res_count;
+	volatile unsigned short		command;
+	volatile unsigned int		buf_addr;
+};
+
 struct mac_serial {
 	struct mac_serial *zs_next;	/* For IRQ servicing chain */
 	struct mac_zschannel *zs_channel; /* Channel registers */
@@ -156,6 +163,28 @@
 	struct termios		callout_termios;
 	struct wait_queue	*open_wait;
 	struct wait_queue	*close_wait;
+
+	volatile struct dbdma_regs *tx_dma;
+	int			tx_dma_irq;
+	volatile struct dbdma_cmd *tx_cmds;
+	volatile struct mac_dma *rx;
+	int 			rx_dma_irq;
+	volatile struct dbdma_cmd **rx_cmds;
+	unsigned char		**rx_char_buf;
+	unsigned char		**rx_flag_buf;
+#define	RX_BUF_SIZE	256
+	int			rx_nbuf;
+	int			rx_done_bytes;
+	int			rx_ubuf;
+	int			rx_fbuf;
+#define	RX_NO_FBUF	(-1)
+	int			rx_cbuf;
+	spinlock_t		rx_dma_lock;
+	int			has_dma;
+	int			dma_initted;
+	void			*dma_priv;
+	struct timer_list	poll_dma_timer;
+#define RX_DMA_TIMER	(jiffies + 10*HZ/1000)
 };
 
 
@@ -226,9 +255,9 @@
 #define	INT_ALL_Rx	0x10	/* Int on all Rx Characters or error */
 #define	INT_ERR_Rx	0x18	/* Int on error only */
 
-#define	WT_RDY_RT	0x20	/* Wait/Ready on R/T */
-#define	WT_FN_RDYFN	0x40	/* Wait/FN/Ready FN */
-#define	WT_RDY_ENAB	0x80	/* Wait/Ready Enable */
+#define	WT_RDY_RT	0x20	/* W/Req reflects recv if 1, xmit if 0 */
+#define	WT_FN_RDYFN	0x40	/* W/Req pin is DMA request if 1, wait if 0 */
+#define	WT_RDY_ENAB	0x80	/* Enable W/Req pin */
 
 /* Write Register #2 (Interrupt Vector) */
 
@@ -286,6 +315,9 @@
 
 /* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
 
+/* Write Register 7' (Some enhanced feature control) */
+#define	ENEXREAD	0x40	/* Enable read of some write registers */
+
 /* Write Register 8 (transmit buffer) */
 
 /* Write Register 9 (Master interrupt control) */
@@ -346,7 +378,9 @@
 #define	SNRZI	0xe0	/* Set NRZI mode */
 
 /* Write Register 15 (external/status interrupt control) */
+#define	EN85C30	1	/* Enable some 85c30-enhanced registers */
 #define	ZCIE	2	/* Zero count IE */
+#define	ENSTFIFO 4	/* Enable status FIFO (SDLC) */
 #define	DCDIE	8	/* DCD IE */
 #define	SYNCIE	0x10	/* Sync/hunt IE */
 #define	CTSIE	0x20	/* CTS IE */
@@ -382,6 +416,15 @@
 #define	END_FR		0x80	/* End of Frame (SDLC) */
 
 /* Read Register 2 (channel b only) - Interrupt vector */
+#define	CHB_Tx_EMPTY	0x00
+#define	CHB_EXT_STAT	0x02
+#define	CHB_Rx_AVAIL	0x04
+#define	CHB_SPECIAL	0x06
+#define	CHA_Tx_EMPTY	0x08
+#define	CHA_EXT_STAT	0x0a
+#define	CHA_Rx_AVAIL	0x0c
+#define	CHA_SPECIAL	0x0e
+#define	STATUS_MASK	0x06
 
 /* Read Register 3 (interrupt pending register) ch a only */
 #define	CHBEXT	0x1		/* Channel B Ext/Stat IP */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/macintosh/mediabay.c linux.14p16/drivers/macintosh/mediabay.c
--- linux.vanilla/drivers/macintosh/mediabay.c	Wed Oct 20 01:12:38 1999
+++ linux.14p16/drivers/macintosh/mediabay.c	Thu Dec  9 15:34:15 1999
@@ -94,6 +94,12 @@
  */
 #define MB_IDE_WAIT	1500
 
+/*
+ * Wait at least this many ticks after resetting an IDE device before
+ * believing its ready bit.
+ */
+#define MB_IDE_MINWAIT	250
+
 static void poll_media_bay(int which);
 static void set_media_bay(int which, int id);
 static int media_bay_task(void *);
@@ -285,7 +291,10 @@
 #endif
 			}
 #ifdef CONFIG_BLK_DEV_IDE
-		} else if (bay->cd_timer && (--bay->cd_timer == 0 || MB_IDE_READY(i))
+		} else if (bay->cd_timer
+			   && (--bay->cd_timer == 0
+			       || (bay->cd_timer < MB_IDE_WAIT - MB_IDE_MINWAIT
+				   && MB_IDE_READY(i)))
 			   && bay->cd_index < 0) {
 			bay->cd_timer = 0;
 			printk(KERN_DEBUG "Registering IDE, base:0x%08lx, irq:%d\n", bay->cd_base, bay->cd_irq);
@@ -299,11 +308,13 @@
 		}
 
 		bay->previous_id = bay->content_id;
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(1);
-		if (signal_pending(current))
-			return 0;
-		i = (i+1)%media_bay_count;
+		if (++i >= media_bay_count) {
+			i = 0;
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(1);
+			if (signal_pending(current))
+				return 0;
+		}
 	}
 }
 
@@ -405,31 +416,30 @@
 			feature_set(bay->dev_node, FEATURE_Mediabay_enable);
 			/* I suppose this is enough delay to stabilize MB_CONTENT ... */
 			mdelay(10);
-			/* We re-enable the bay using it's previous content only if
-			   it did not change */
-			if (MB_CONTENTS(i) == bay->content_id) {
-				set_media_bay(i, bay->content_id);
-				if (bay->content_id != MB_NO) {
-					mdelay(400);
-					/* Clear the bay reset */
-					feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
-					/* This small delay makes sure the device has time
-					   to assert the BUSY bit (used by IDE sleep) */
-					udelay(100);
-					/* We reset the state machine timers in case we were in the
-					   middle of a wait loop */
-					if (bay->reset_timer)
-						bay->reset_timer = MB_RESET_COUNT;
-					if (bay->cd_timer)
-						bay->cd_timer = MB_IDE_WAIT;
-				}
-			}
+			/* We re-enable the bay using it's previous content
+			   only if it did not change */
+			if (MB_CONTENTS(i) != bay->content_id)
+				continue;
+			set_media_bay(i, bay->content_id);
+			if (bay->content_id == MB_NO)
+				continue;
+			mdelay(400);
+			/* Clear the bay reset */
+			feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
+			/* This small delay makes sure the device has time
+			   to assert the BUSY bit (used by IDE sleep) */
+			udelay(100);
+			/* We reset the state machine timers in case we were
+			   in the middle of a wait loop */
+			if (bay->reset_timer)
+				bay->reset_timer = MB_RESET_COUNT;
+#ifdef CONFIG_BLK_DEV_IDE
+			if (bay->cd_timer)
+				bay->cd_timer = MB_IDE_WAIT;
+#endif
 		}
 		break;
 	}
 	return PBOOK_SLEEP_OK;
 }
 #endif /* CONFIG_PMAC_PBOOK */
-
-
-
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/macintosh/via-pmu.c linux.14p16/drivers/macintosh/via-pmu.c
--- linux.vanilla/drivers/macintosh/via-pmu.c	Sat Aug 28 20:00:56 1999
+++ linux.14p16/drivers/macintosh/via-pmu.c	Thu Dec  9 15:34:15 1999
@@ -1126,11 +1126,6 @@
 		macio_base = (unsigned long)
 			ioremap(macio->addrs[0].address, 0x40);
 
-	/* Sync the disks. */
-	/* XXX It would be nice to have some way to ensure that
-	 * nobody is dirtying any new buffers while we wait. */
-	fsync_dev(0);
-
 	/* Notify device drivers */
 	ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, 1);
 	if (ret != PBOOK_SLEEP_OK) {
@@ -1138,6 +1133,15 @@
 		printk("pmu: sleep rejected\n");
 		return -EBUSY;
 	}
+
+	/* Sync the disks. */
+	/* XXX It would be nice to have some way to ensure that
+	 * nobody is dirtying any new buffers while we wait.
+	 * BenH: Moved to _after_ sleep request and changed video
+	 * drivers to vmalloc() during sleep request. This way, all
+	 * vmalloc's are done before actual sleep of block drivers */
+	fsync_dev(0);
+
 	broadcast_sleep(PBOOK_SLEEP_NOW, 0);
 
 	/* Give the disks a little time to actually finish writing */
@@ -1190,6 +1194,10 @@
 	pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); 
 	grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1);
 
+	/* Make sure the PMU is idle */
+	while (pmu_state != idle)
+		pmu_poll();
+
 	sti();
 #if 0
 	/* According to someone from Apple, this should not be needed,
@@ -1201,7 +1209,7 @@
 
 	/* Restore L2 cache */
 	if (save_l2cr)
-		_set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */
+ 		_set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */
 	
 	/* reenable interrupts */
 	sleep_restore_intrs();
@@ -1222,11 +1230,6 @@
 	unsigned long p, wait;
 	struct adb_request sleep_req;
 
-	/* Sync the disks. */
-	/* XXX It would be nice to have some way to ensure that
-	 * nobody is dirtying any new buffers while we wait. */
-	fsync_dev(0);
-
 	/* Notify device drivers */
 	ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, 1);
 	if (ret != PBOOK_SLEEP_OK) {
@@ -1234,6 +1237,15 @@
 		printk("pmu: sleep rejected\n");
 		return -EBUSY;
 	}
+
+	/* Sync the disks. */
+	/* XXX It would be nice to have some way to ensure that
+	 * nobody is dirtying any new buffers while we wait.
+	 * BenH: Moved to _after_ sleep request and changed video
+	 * drivers to vmalloc() during sleep request. This way, all
+	 * vmalloc's are done before actual sleep of block drivers */
+	fsync_dev(0);
+
 	broadcast_sleep(PBOOK_SLEEP_NOW, 0);
 
 	/* Give the disks a little time to actually finish writing */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/misc/parport_pc.c linux.14p16/drivers/misc/parport_pc.c
--- linux.vanilla/drivers/misc/parport_pc.c	Sat Aug 14 02:27:27 1999
+++ linux.14p16/drivers/misc/parport_pc.c	Thu Dec  9 15:34:15 1999
@@ -32,6 +32,9 @@
  * only in register addresses (eg because your registers are on 32-bit
  * word boundaries) then you can alter the constants in parport_pc.h to
  * accomodate this.
+ *
+ * Note that the ECP registers may not start at offset 0x400 for PCI cards,
+ * but rather will start at port->base_hi.
  */
 
 #include <linux/config.h>
@@ -43,6 +46,7 @@
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/malloc.h>
+#include <linux/pci.h>
 
 #include <asm/io.h>
 
@@ -62,27 +66,27 @@
 
 void parport_pc_write_epp(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+EPPDATA);
+	outb(d, EPPDATA(p));
 }
 
 unsigned char parport_pc_read_epp(struct parport *p)
 {
-	return inb(p->base+EPPDATA);
+	return inb(EPPDATA(p));
 }
 
 void parport_pc_write_epp_addr(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+EPPADDR);
+	outb(d, EPPADDR(p));
 }
 
 unsigned char parport_pc_read_epp_addr(struct parport *p)
 {
-	return inb(p->base+EPPADDR);
+	return inb(EPPADDR(p));
 }
 
 int parport_pc_check_epp_timeout(struct parport *p)
 {
-	if (!(inb(p->base+STATUS) & 1))
+	if (!(inb(STATUS(p)) & 1))
 		return 0;
 	parport_pc_epp_clear_timeout(p);
 	return 1;
@@ -90,24 +94,24 @@
 
 unsigned char parport_pc_read_configb(struct parport *p)
 {
-	return inb(p->base+CONFIGB);
+	return inb(CONFIGB(p));
 }
 
 void parport_pc_write_data(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+DATA);
+	outb(d, DATA(p));
 }
 
 unsigned char parport_pc_read_data(struct parport *p)
 {
-	return inb(p->base+DATA);
+	return inb(DATA(p));
 }
 
 void parport_pc_write_control(struct parport *p, unsigned char d)
 {
 	struct parport_pc_private *priv = p->private_data;
 	priv->ctr = d;/* update soft copy */
-	outb(d, p->base+CONTROL);
+	outb(d, CONTROL(p));
 }
 
 unsigned char parport_pc_read_control(struct parport *p)
@@ -121,34 +125,34 @@
 	struct parport_pc_private *priv = p->private_data;
 	unsigned char ctr = priv->ctr;
 	ctr = (ctr & ~mask) ^ val;
-	outb (ctr, p->base+CONTROL);
+	outb (ctr, CONTROL(p));
 	return priv->ctr = ctr; /* update soft copy */
 }
 
 void parport_pc_write_status(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+STATUS);
+	outb(d, STATUS(p));
 }
 
 unsigned char parport_pc_read_status(struct parport *p)
 {
-	return inb(p->base+STATUS);
+	return inb(STATUS(p));
 }
 
 void parport_pc_write_econtrol(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+ECONTROL);
+	outb(d, ECONTROL(p));
 }
 
 unsigned char parport_pc_read_econtrol(struct parport *p)
 {
-	return inb(p->base+ECONTROL);
+	return inb(ECONTROL(p));
 }
 
 unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask,  unsigned char val)
 {
-	unsigned char old = inb(p->base+ECONTROL);
-	outb(((old & ~mask) ^ val), p->base+ECONTROL);
+	unsigned char old = inb(ECONTROL(p));
+	outb(((old & ~mask) ^ val), ECONTROL(p));
 	return old;
 }
 
@@ -159,12 +163,12 @@
 
 void parport_pc_write_fifo(struct parport *p, unsigned char v)
 {
-	outb (v, p->base+CONFIGA);
+	outb (v, CONFIGA(p));
 }
 
 unsigned char parport_pc_read_fifo(struct parport *p)
 {
-	return inb (p->base+CONFIGA);
+	return inb (CONFIGA(p));
 }
 
 void parport_pc_disable_irq(struct parport *p)
@@ -183,7 +187,7 @@
 		free_irq(p->irq, p);
 	release_region(p->base, p->size);
 	if (p->modes & PARPORT_MODE_PCECR)
-		release_region(p->base+0x400, 3);
+		release_region(p->base_hi, 3);
 }
 
 int parport_pc_claim_resources(struct parport *p)
@@ -195,7 +199,7 @@
 			return err;
 	request_region(p->base, p->size, p->name);
 	if (p->modes & PARPORT_MODE_PCECR)
-		request_region(p->base+0x400, 3, p->name);
+		request_region(p->base_hi, 3, p->name);
 	return 0;
 }
 
@@ -223,8 +227,8 @@
 {
 	size_t got = 0;
 	for (; got < length; got++) {
-		*((char*)buf)++ = inb (p->base+EPPDATA);
-		if (inb (p->base+STATUS) & 0x01)
+		*((char*)buf)++ = inb (EPPDATA(p));
+		if (inb (STATUS(p)) & 0x01)
 			break;
 	}
 	return got;
@@ -234,8 +238,8 @@
 {
 	size_t written = 0;
 	for (; written < length; written++) {
-		outb (*((char*)buf)++, p->base+EPPDATA);
-		if (inb (p->base+STATUS) & 0x01)
+		outb (*((char*)buf)++, EPPDATA(p));
+		if (inb (STATUS(p)) & 0x01)
 			break;
 	}
 	return written;
@@ -370,11 +374,11 @@
 	 * allow reads, so read_control just returns a software
 	 * copy. Some ports _do_ allow reads, so bypass the software
 	 * copy here.  In addition, some bits aren't writable. */
-	r = inb (pb->base+CONTROL);
+	r = inb (CONTROL(pb));
 	if ((r & 0xf) == w) {
 		w = 0xe;
 		parport_pc_write_control (pb, w);
-		r = inb (pb->base+CONTROL);
+		r = inb (CONTROL(pb));
 		parport_pc_write_control (pb, 0xc);
 		if ((r & 0xf) == w)
 			return PARPORT_MODE_PCSPP;
@@ -754,13 +758,16 @@
 
 /* --- Initialisation code -------------------------------- */
 
-static int probe_one_port(unsigned long int base, int irq, int dma)
+static int probe_one_port(unsigned long int base,
+			  unsigned long int base_hi,
+			  int irq, int dma)
 {
 	struct parport *p;
 	int probedirq = PARPORT_IRQ_NONE;
 	if (check_region(base, 3)) return 0;
 	if (!(p = parport_register_port(base, irq, dma, &parport_pc_ops)))
 		return 0;
+	p->base_hi = base_hi;
 	p->private_data = kmalloc (sizeof (struct parport_pc_private),
 				   GFP_KERNEL);
 	if (!p->private_data) {
@@ -770,16 +777,14 @@
 		return 0;
 	}
 	((struct parport_pc_private *) (p->private_data))->ctr = 0xc;
-	if (p->base != 0x3bc) {
-		if (!check_region(base+0x400,3)) {
-			p->modes |= parport_ECR_present(p);	
-			p->modes |= parport_ECP_supported(p);
-			p->modes |= parport_ECPPS2_supported(p);
-		}
-		if (!check_region(base+0x3, 5)) {
-			p->modes |= parport_EPP_supported(p);
-			p->modes |= parport_ECPEPP_supported(p);
-		}
+	if (base_hi && !check_region(base_hi,3)) {
+		p->modes |= parport_ECR_present(p);
+		p->modes |= parport_ECP_supported(p);
+		p->modes |= parport_ECPPS2_supported(p);
+	}
+	if (p->base != 0x3bc && !check_region(base+0x3, 5)) {
+		p->modes |= parport_EPP_supported(p);
+		p->modes |= parport_ECPEPP_supported(p);
 	}
 	if (!parport_SPP_supported(p)) {
 		/* No port. */
@@ -791,6 +796,8 @@
 	p->size = (p->modes & (PARPORT_MODE_PCEPP 
 			       | PARPORT_MODE_PCECPEPP))?8:3;
 	printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
+	if (p->base_hi && (p->modes & PARPORT_MODE_PCECP))
+		printk(" (0x%lx)", p->base_hi);
 	if (p->irq == PARPORT_IRQ_AUTO) {
 		p->irq = PARPORT_IRQ_NONE;
 		parport_irq_probe(p);
@@ -844,6 +851,124 @@
 	return 1;
 }
 
+/* Look for PCI parallel port cards. */
+static int parport_pc_init_pci (int irq, int dma)
+{
+	struct {
+		unsigned int vendor;
+		unsigned int device;
+		unsigned int numports;
+		struct {
+			unsigned long lo;
+			unsigned long hi; /* -ve if not there */
+		} addr[4];
+	} cards[] = {
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, 1,
+		  { { 3, 4 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, 1,
+		  { { 3, 4 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, 1,
+		  { { 3, 4 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_10x, 1,
+		  { { 2, 3 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_10x, 2,
+		  { { 2, 3 }, { 4, 5 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, 1,
+		  { { 4, 5 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, 1,
+		  { { 4, 5 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, 1,
+		  { { 4, 5 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_20x, 1,
+		  { { 0, 1 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_20x, 2,
+		  { { 0, 1 }, { 2, 3 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, 2,
+		  { { 1, 2 }, { 3, 4 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, 2,
+		  { { 1, 2 }, { 3, 4 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, 2,
+		  { { 1, 2 }, { 3, 4 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, 1,
+		  { { 1, 2 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, 1,
+		  { { 1, 2 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, 1,
+		  { { 1, 2 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, 1,
+		  { { 2, 3 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, 1,
+		  { { 2, 3 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, 1,
+		  { { 2, 3 }, } },
+		{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PARALLEL, 1,
+		  { { 0, -1 }, } },
+		{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_A, 1,
+		  { { 0, -1 }, } },
+		{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B, 1,
+		  { { 0, -1 }, } },
+		{ 0, }
+	};
+
+	struct pci_dev *pcidev;
+	int count = 0;
+	int i;
+
+	if (!pci_present ())
+		return 0;
+
+	for (i = 0; cards[i].vendor; i++) {
+		pcidev = NULL;
+		while ((pcidev = pci_find_device (cards[i].vendor,
+						  cards[i].device,
+						  pcidev)) != NULL) {
+			int n;
+			for (n = 0; n < cards[i].numports; n++) {
+				unsigned long lo = cards[i].addr[n].lo;
+				unsigned long hi = cards[i].addr[n].hi;
+				unsigned long io_lo, io_hi;
+				io_lo = pcidev->base_address[lo];
+				io_hi = ((hi < 0) ? 0 :
+					 pcidev->base_address[hi]);
+				io_lo &= PCI_BASE_ADDRESS_IO_MASK;
+				io_hi &= PCI_BASE_ADDRESS_IO_MASK;
+				if (irq == PARPORT_IRQ_AUTO) {
+					if (probe_one_port (io_lo,
+							    io_hi,
+							    pcidev->irq,
+							    dma))
+						count++;
+				} else if (probe_one_port (io_lo, io_hi,
+							   irq, dma))
+					count++;
+			}
+		}
+	}
+
+	/* Look for parallel controllers that we don't know about. */
+	for (pcidev = pci_devices; pcidev; pcidev = pcidev->next) {
+		const int class_noprogif = pcidev->class & ~0xff;
+		if (class_noprogif != (PCI_CLASS_COMMUNICATION_PARALLEL << 8))
+			continue;
+
+		for (i = 0; cards[i].vendor; i++)
+			if ((cards[i].vendor == pcidev->vendor) &&
+			    (cards[i].device == pcidev->device))
+				break;
+		if (cards[i].vendor)
+			/* We know about this one. */
+			continue;
+
+		printk (KERN_INFO
+			"Unknown PCI parallel I/O card (%04x/%04x)\n"
+			"Please send 'lspci' output to "
+			"tim@cyberelk.demon.co.uk\n",
+			pcidev->vendor, pcidev->device);
+	}
+
+	return count;
+}
+
 int parport_pc_init(int *io, int *irq, int *dma)
 {
 	int count = 0, i = 0;
@@ -851,13 +976,16 @@
 		/* Only probe the ports we were given. */
 		user_specified = 1;
 		do {
-			count += probe_one_port(*(io++), *(irq++), *(dma++));
+			unsigned long int io_hi = 0x400 + *io;
+			count += probe_one_port(*(io++), io_hi,
+						*(irq++), *(dma++));
 		} while (*io && (++i < PARPORT_PC_MAX_PORTS));
 	} else {
 		/* Probe all the likely ports. */
-		count += probe_one_port(0x3bc, irq[0], dma[0]);
-		count += probe_one_port(0x378, irq[0], dma[0]);
-		count += probe_one_port(0x278, irq[0], dma[0]);
+		count += probe_one_port(0x3bc, 0x7bc, irq[0], dma[0]);
+		count += probe_one_port(0x378, 0x778, irq[0], dma[0]);
+		count += probe_one_port(0x278, 0x678, irq[0], dma[0]);
+		count += parport_pc_init_pci (irq[0], dma[0]);
 	}
 
 	return count;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/misc/parport_share.c linux.14p16/drivers/misc/parport_share.c
--- linux.vanilla/drivers/misc/parport_share.c	Sat Aug 14 02:26:48 1999
+++ linux.14p16/drivers/misc/parport_share.c	Thu Dec  9 15:34:15 1999
@@ -108,6 +108,7 @@
 	tmp->cad_lock = RW_LOCK_UNLOCKED;
 	spin_lock_init(&tmp->waitlist_lock);
 	spin_lock_init(&tmp->pardevice_lock);
+	tmp->base_hi = base + 0x400;
 
 	name = kmalloc(15, GFP_KERNEL);
 	if (!name) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Config.in linux.14p16/drivers/net/Config.in
--- linux.vanilla/drivers/net/Config.in	Wed Oct 20 01:12:38 1999
+++ linux.14p16/drivers/net/Config.in	Wed Dec 15 16:37:38 1999
@@ -46,6 +46,7 @@
   if [ "$CONFIG_PPC" = "y" ]; then
     tristate 'MACE (Power Mac ethernet) support' CONFIG_MACE
     tristate 'BMAC (G3 ethernet) support' CONFIG_BMAC
+    tristate 'Symbios 53c885 (Synergy ethernet) support' CONFIG_NCR885E
   fi
   if [ "$CONFIG_ZORRO" = "y" ]; then
     tristate 'Ariadne support' CONFIG_ARIADNE
@@ -93,8 +94,6 @@
   fi
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139
-      tristate 'SiS 900 PCI Fast Ethernet Adapter support' CONFIG_SIS900
-      tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN
   fi
   bool 'Other ISA cards' CONFIG_NET_ISA
   if [ "$CONFIG_NET_ISA" = "y" ]; then
@@ -125,15 +124,16 @@
   if [ "$CONFIG_NET_EISA" = "y" ]; then
     tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC
       tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
     fi
-
     tristate 'Apricot Xen-II on board Ethernet' CONFIG_APRICOT
     tristate 'CS89x0 support' CONFIG_CS89x0
     tristate 'DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102
     tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
     tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
+    if [ "$CONFIG_DEC_ELCP" != "y" ]; then
+      tristate 'Old DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP_OLD
+    fi
     tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
     tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
@@ -143,6 +143,7 @@
     tristate 'PCI NE2000 support' CONFIG_NE2K_PCI
     tristate 'TI ThunderLAN support' CONFIG_TLAN
     tristate 'VIA Rhine support' CONFIG_VIA_RHINE
+    tristate 'SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate 'Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210
       tristate 'SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100
@@ -159,13 +160,29 @@
 
 endmenu
 
+#
+#	Gigabit Ethernet
+#
+
+mainmenu_option next_comment
+comment 'Ethernet (1000 Mbit)'
+
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC
+      tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN
+    fi
+    tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN
+endmenu
+
 bool 'FDDI driver support' CONFIG_FDDI
 if [ "$CONFIG_FDDI" = "y" ]; then
   bool 'Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
+  if [ "$CONFIG_INET" = "y" ]; then
+    bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
+  fi
   if [ "$CONFIG_HIPPI" = "y" ]; then
     tristate 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER
     if [ "$CONFIG_ROADRUNNER" != "n" ]; then
@@ -234,7 +251,7 @@
 
 bool 'Fibre Channel driver support' CONFIG_NET_FC
 if [ "$CONFIG_NET_FC" = "y" ]; then
-  tristate 'Interphase 5526 Tachyon chipset based adaptor support' CONFIG_IPHASE5526
+  dep_tristate 'Interphase 5526 Tachyon chipset based adaptor support' CONFIG_IPHASE5526 $CONFIG_SCSI
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
@@ -262,6 +279,27 @@
 #
 dep_tristate 'Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m
 
+#
+# COMX drivers
+#
+
+tristate 'MultiGate (COMX) synchronous serial boards support' CONFIG_COMX
+   if [ "$CONFIG_COMX" != "n" ]; then
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      dep_tristate '  Support for COMX/CMX/HiCOMX boards' CONFIG_COMX_HW_COMX $CONFIG_COMX
+   fi
+   dep_tristate '  Support for LoCOMX board' CONFIG_COMX_HW_LOCOMX $CONFIG_COMX
+   dep_tristate '  Support for MixCOM board' CONFIG_COMX_HW_MIXCOM $CONFIG_COMX
+   dep_tristate '  Support for HDLC and syncPPP protocols on MultiGate boards' CONFIG_COMX_PROTO_PPP $CONFIG_COMX
+   if [ "$CONFIG_LAPB" = "y" ]; then
+      dep_tristate '  Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_COMX
+   fi
+   if [ "$CONFIG_LAPB" = "m" ]; then
+      dep_tristate '  Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_LAPB
+   fi
+   dep_tristate '  Support for Frame Relay on MultiGate boards' CONFIG_COMX_PROTO_FR $CONFIG_COMX
+fi
+
 tristate 'Frame relay DLCI support' CONFIG_DLCI
 if [ "$CONFIG_DLCI" != "n" ]; then
   int '  Max open DLCI' CONFIG_DLCI_COUNT 24
@@ -274,21 +312,20 @@
 #
 
 if [ "$CONFIG_WAN_ROUTER" != "n" ]; then
-  bool 'WAN drivers' CONFIG_WAN_DRIVERS
+  bool 'WAN drivers' CONFIG_WAN_DRIVERS 
   if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then
-    dep_tristate 'Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_DRIVERS
+    dep_tristate 'Sangoma WANPIPE(tm) multi-prot cards: (select M not Y !)' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_DRIVERS 
     if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then
       int  '  Maximum number of cards' CONFIG_WANPIPE_CARDS 1
-      bool '  WANPIPE X.25 support' CONFIG_WANPIPE_X25
+      #bool '  WANPIPE X.25 support' CONFIG_WANPIPE_X25
       bool '  WANPIPE Frame Relay support' CONFIG_WANPIPE_FR
       bool '  WANPIPE PPP support' CONFIG_WANPIPE_PPP
-  #    bool '  WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC
+      bool '  WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC
     fi
   fi
 fi
 
 endmenu
-
 
 #
 # X.25 network drivers
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Makefile linux.14p16/drivers/net/Makefile
--- linux.vanilla/drivers/net/Makefile	Wed Oct 20 01:12:38 1999
+++ linux.14p16/drivers/net/Makefile	Wed Dec 15 23:19:37 1999
@@ -5,10 +5,14 @@
 
 SUB_DIRS     := 
 MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS) hamradio irda fc
+ALL_SUB_DIRS := $(SUB_DIRS) hamradio irda fc sk98lin
 
 L_TARGET := net.a
-L_OBJS   := auto_irq.o
+L_OBJS   :=
+ifneq ($(ARCH),s390)  
+L_OBJS   += auto_irq.o
+endif
+
 M_OBJS   :=
 MOD_LIST_NAME := NET_MODULES
 
@@ -599,6 +603,16 @@
   endif
 endif
 
+ifeq ($(CONFIG_SK98LIN),y)
+  SUB_DIRS += sk98lin
+  MOD_IN_SUB_DIRS += sk98lin
+  L_OBJS += sk98lin/sk98lin.o
+else
+  ifeq ($(CONFIG_SK98LIN),m)
+    MOD_IN_SUB_DIRS += sk98lin
+  endif
+endif
+
 ifeq ($(CONFIG_WAVELAN),y)
 L_OBJS += wavelan.o
 else
@@ -737,6 +751,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_DEC_ELCP_OLD),y)
+L_OBJS += old_tulip.o
+else
+  ifeq ($(CONFIG_DEC_ELCP_OLD),m)
+  M_OBJS += old_tulip.o
+  endif
+endif
+
 ifeq ($(CONFIG_ARCNET),y)
 LX_OBJS += arcnet.o
 else
@@ -836,14 +858,66 @@
   endif
 endif
 
-# If anything built-in uses syncppp, then build it into the kernel also.
-# If not, but a module uses it, build as a module.
+#
+# COMX drivers
+#
+ifeq ($(CONFIG_COMX),y)
+LX_OBJS += comx.o
+else 
+  ifeq ($(CONFIG_COMX),m)
+  MX_OBJS += comx.o
+  endif
+endif
 
-ifdef CONFIG_SYNCPPP_BUILTIN
-LX_OBJS += syncppp.o
-else
-  ifdef CONFIG_SYNCPPP_MODULE
-  MX_OBJS += syncppp.o
+ifeq ($(CONFIG_COMX_HW_COMX),y)
+L_OBJS += comx-hw-comx.o
+else 
+  ifeq ($(CONFIG_COMX_HW_COMX),m)
+  M_OBJS += comx-hw-comx.o
+  endif
+endif
+
+ifeq ($(CONFIG_COMX_HW_LOCOMX),y)
+L_OBJS += comx-hw-locomx.o
+CONFIG_85230_BUILTIN=y
+else 
+  ifeq ($(CONFIG_COMX_HW_LOCOMX),m)
+  M_OBJS += comx-hw-locomx.o
+  CONFIG_85230_MODULE=y
+  endif
+endif
+
+ifeq ($(CONFIG_COMX_HW_MIXCOM),y)
+L_OBJS += comx-hw-mixcom.o
+else 
+  ifeq ($(CONFIG_COMX_HW_MIXCOM),m)
+  M_OBJS += comx-hw-mixcom.o
+  endif
+endif
+
+ifeq ($(CONFIG_COMX_PROTO_PPP),y)
+L_OBJS += comx-proto-ppp.o
+CONFIG_SYNCPPP_BUILTIN = y
+else 
+  ifeq ($(CONFIG_COMX_PROTO_PPP),m)
+  M_OBJS += comx-proto-ppp.o
+  CONFIG_SYNCPPP_MODULE = y
+  endif
+endif
+
+ifeq ($(CONFIG_COMX_PROTO_LAPB),y)
+L_OBJS += comx-proto-lapb.o
+else 
+  ifeq ($(CONFIG_COMX_PROTO_LAPB),m)
+  M_OBJS += comx-proto-lapb.o
+  endif
+endif
+
+ifeq ($(CONFIG_COMX_PROTO_FR),y)
+L_OBJS += comx-proto-fr.o
+else 
+  ifeq ($(CONFIG_COMX_PROTO_FR),m)
+  M_OBJS += comx-proto-fr.o
   endif
 endif
 
@@ -852,9 +926,22 @@
 
 ifdef CONFIG_85230_BUILTIN
 LX_OBJS += z85230.o
+CONFIG_SYNCPPP_BUILTIN=y
 else
   ifdef CONFIG_85230_MODULE
   MX_OBJS += z85230.o
+  CONFIG_SYNCPPP_MODULE=y
+  endif
+endif
+
+# If anything built-in uses syncppp, then build it into the kernel also.
+# If not, but a module uses it, build as a module.
+
+ifdef CONFIG_SYNCPPP_BUILTIN
+LX_OBJS += syncppp.o
+else
+  ifdef CONFIG_SYNCPPP_MODULE
+  MX_OBJS += syncppp.o
   endif
 endif
 
@@ -1089,11 +1176,20 @@
   endif
 endif
 
+ifeq ($(CONFIG_NCR885E),y)
+L_OBJS += ncr885e.o
+else
+  ifeq ($(CONFIG_NCR885E),m)
+  M_OBJS += ncr885e.o
+  endif
+endif
+
 ifeq ($(CONFIG_VENDOR_SANGOMA),y)
   LX_OBJS += sdladrv.o
   L_OBJS += sdlamain.o
   ifeq ($(CONFIG_WANPIPE_X25),y)
     L_OBJS += sdla_x25.o
+    L_OBJS += sdla_x25api.o
   endif
   ifeq ($(CONFIG_WANPIPE_FR),y)
     L_OBJS += sdla_fr.o
@@ -1101,6 +1197,9 @@
   ifeq ($(CONFIG_WANPIPE_PPP),y)
     L_OBJS += sdla_ppp.o
   endif
+  ifeq ($(CONFIG_WANPIPE_CHDLC),y)
+    L_OBJS += sdla_chdlc.o
+  endif    
 endif
 
 ifeq ($(CONFIG_VENDOR_SANGOMA),m)
@@ -1109,6 +1208,7 @@
   WANPIPE_OBJS = sdlamain.o
   ifeq ($(CONFIG_WANPIPE_X25),y)
     WANPIPE_OBJS += sdla_x25.o
+    WANPIPE_OBJS += sdla_x25api.o
   endif
   ifeq ($(CONFIG_WANPIPE_FR),y)
     WANPIPE_OBJS += sdla_fr.o
@@ -1116,6 +1216,9 @@
   ifeq ($(CONFIG_WANPIPE_PPP),y)
     WANPIPE_OBJS += sdla_ppp.o
   endif
+  ifeq ($(CONFIG_WANPIPE_CHDLC),y)
+    WANPIPE_OBJS += sdla_chdlc.o
+  endif    
 endif
 
 ifeq ($(CONFIG_X25_ASY),y)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Space.c linux.14p16/drivers/net/Space.c
--- linux.vanilla/drivers/net/Space.c	Wed Oct 20 01:12:38 1999
+++ linux.14p16/drivers/net/Space.c	Wed Dec 15 22:17:18 1999
@@ -103,6 +103,7 @@
 extern int tlan_probe(struct device *);
 extern int mace_probe(struct device *);
 extern int bmac_probe(struct device *);
+extern int ncr885e_probe(struct device *);
 extern int cs89x0_probe(struct device *dev);
 extern int ethertap_probe(struct device *dev);
 extern int ether1_probe (struct device *dev);
@@ -124,6 +125,8 @@
 /* Gigabit Ethernet adapters */
 extern int yellowfin_probe(struct device *dev);
 extern int acenic_probe(struct device *dev);
+extern int skge_probe(struct device *dev);
+
 
 /* Detachable devices ("pocket adaptors") */
 extern int atp_init(struct device *);
@@ -198,7 +201,7 @@
 #ifdef CONFIG_EEXPRESS_PRO100	/* Intel EtherExpress Pro/100 */
 	{eepro100_probe, 0},
 #endif
-#ifdef CONFIG_DEC_ELCP 
+#if defined(CONFIG_DEC_ELCP) || defined(CONFIG_DEC_ELCP_OLD)
 	{tulip_probe, 0},
 #endif
 #ifdef CONFIG_DE4X5             /* DEC DE425, DE434, DE435 adapters */
@@ -227,6 +230,9 @@
 #ifdef CONFIG_ACENIC
 	{acenic_probe, 0},
 #endif
+#ifdef CONFIG_SK98LIN
+	{skge_probe, 0},
+#endif
 #ifdef CONFIG_VIA_RHINE
 	{via_rhine_probe, 0},
 #endif
@@ -454,6 +460,9 @@
 #ifdef CONFIG_BMAC
 	{bmac_probe, 0},
 #endif
+#ifdef CONFIG_NCR885E
+	{ncr885e_probe, 0},
+#endif
 	{NULL, 0},
 };
 
@@ -898,6 +907,47 @@
 #   define      NEXT_DEV        (&sb1000_dev)
 #endif
 	
+/* S/390 channels */
+#ifdef CONFIG_CTC
+    extern int ctc_probe(struct device *dev);
+    static struct device ctc7_dev =
+       {"ctc7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV,  ctc_probe};
+    static struct device ctc6_dev =
+       {"ctc6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc7_dev, ctc_probe};
+    static struct device ctc5_dev =
+       {"ctc5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc6_dev, ctc_probe};
+    static struct device ctc4_dev =
+       {"ctc4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc5_dev, ctc_probe};
+    static struct device ctc3_dev =
+       {"ctc3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc4_dev, ctc_probe};
+    static struct device ctc2_dev =
+       {"ctc2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc3_dev, ctc_probe};
+    static struct device ctc1_dev =
+       {"ctc1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc2_dev, ctc_probe};
+    static struct device ctc0_dev =
+       {"ctc0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc1_dev, ctc_probe}; 
+
+    static struct device escon7_dev =
+       {"escon7", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc0_dev,   ctc_probe};
+    static struct device escon6_dev =
+       {"escon6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon7_dev, ctc_probe};
+    static struct device escon5_dev =
+       {"escon5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon6_dev, ctc_probe};
+    static struct device escon4_dev =
+       {"escon4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon5_dev, ctc_probe};
+    static struct device escon3_dev =
+       {"escon3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon4_dev, ctc_probe};
+    static struct device escon2_dev =
+       {"escon2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon3_dev, ctc_probe};
+    static struct device escon1_dev =
+       {"escon1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon2_dev, ctc_probe};
+    static struct device escon0_dev =
+       {"escon0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon1_dev, ctc_probe}; 
+
+#undef  NEXT_DEV
+#define NEXT_DEV        (&escon0_dev)                                  
+#endif  
+        
 extern int loopback_init(struct device *dev);
 struct device loopback_dev = {
 	"lo",			/* Software Loopback interface		*/
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/arcnet.c linux.14p16/drivers/net/arcnet.c
--- linux.vanilla/drivers/net/arcnet.c	Wed Oct 20 01:12:38 1999
+++ linux.14p16/drivers/net/arcnet.c	Thu Dec  9 15:33:26 1999
@@ -469,7 +469,7 @@
   register_netdevice(lp->edev);
 #endif
 
-#ifdef CONFIG_ARCNET_1051
+#if defined(CONFIG_ARCNET_1051) && defined(CONFIG_ARCNET_ETH)
   /* Initialize the RFC1051-encap protocol driver */
   lp->sdev=(struct device *)kmalloc(sizeof(struct device)+10,GFP_KERNEL);
   if(lp->sdev == NULL)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/arlan-proc.c linux.14p16/drivers/net/arlan-proc.c
--- linux.vanilla/drivers/net/arlan-proc.c	Sat Aug 14 02:27:28 1999
+++ linux.14p16/drivers/net/arlan-proc.c	Thu Dec  9 15:33:32 1999
@@ -1,11 +1,11 @@
 #include <linux/config.h>
 #include "arlan.h"
+#include <linux/sysctl.h>
+#include <linux/version.h>
 
 #ifdef CONFIG_PROC_FS
 
 
-#include <linux/sysctl.h>
-#include <linux/version.h>
 
 /* void enableReceive(struct device* dev);
 */
@@ -1001,6 +1001,11 @@
 	{0}
 };
 #endif
+#else
+static ctl_table arlan_table[MAX_ARLANS + 1] =
+{
+	{0}
+};
 #endif
 
 static int mmtu = 1234;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/arlan.c linux.14p16/drivers/net/arlan.c
--- linux.vanilla/drivers/net/arlan.c	Sat Aug 14 02:27:28 1999
+++ linux.14p16/drivers/net/arlan.c	Thu Dec  9 15:33:32 1999
@@ -101,7 +101,7 @@
 static  void 	arlan_tx_done_interrupt		(struct device * dev, int status);
 static  void	arlan_rx_interrupt		(struct device * dev, u_char rxStatus, u_short, u_short);
 static  void	arlan_process_interrupt		(struct device * dev);
-static  int	arlan_command(struct device * dev, int command);
+int	arlan_command(struct device * dev, int command);
 
 EXPORT_SYMBOL(arlan_command);
 
@@ -190,7 +190,7 @@
 };
 
 
-static int arlan_command(struct device *dev, int command_p)
+int arlan_command(struct device *dev, int command_p)
 {
 
 	volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/comx-hw-comx.c linux.14p16/drivers/net/comx-hw-comx.c
--- linux.vanilla/drivers/net/comx-hw-comx.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/comx-hw-comx.c	Thu Dec  9 15:33:37 1999
@@ -0,0 +1,1298 @@
+/*
+ * Hardware-level driver for the COMX and HICOMX cards
+ * for Linux kernel 2.2.X
+ *
+ * Original authors:  Arpad Bakay <bakay.arpad@synergon.hu>,
+ *                    Peter Bajan <bajan.peter@synergon.hu>,
+ * Rewritten by: Tivadar Szemethy <tiv@itc.hu>
+ * Currently maintained by: Gergely Madarasz <gorgo@itc.hu>
+ *
+ * Copyright (C) 1995-1999 ITConsult-Pro Co. <info@itc.hu>
+ *
+ * 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.
+ *
+ * Version 0.80 (99/06/11):
+ *		- port back to kernel, add support builtin driver 
+ *		- cleaned up the source code a bit
+ *
+ * Version 0.81 (99/06/22):
+ *		- cleaned up the board load functions, no more long reset
+ *		  timeouts
+ *		- lower modem lines on close
+ *		- some interrupt handling fixes
+ *
+ * Version 0.82 (99/08/24):
+ *		- fix multiple board support
+ * 
+ */
+
+#define VERSION "0.82"
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+
+#include "comx.h"
+#include "comxhw.h"
+
+MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>, Tivadar Szemethy <tiv@itc.hu>, Arpad Bakay");
+MODULE_DESCRIPTION("Hardware-level driver for the COMX and HICOMX adapters\n");
+
+#define	COMX_readw(dev, offset)	(readw(dev->mem_start + offset + \
+	(unsigned int)(((struct comx_privdata *)\
+	((struct comx_channel *)dev->priv)->HW_privdata)->channel) \
+	* COMX_CHANNEL_OFFSET))
+
+#define COMX_WRITE(dev, offset, value)	(writew(value, dev->mem_start + offset \
+	+ (unsigned int)(((struct comx_privdata *) \
+	((struct comx_channel *)dev->priv)->HW_privdata)->channel) \
+	* COMX_CHANNEL_OFFSET))
+
+#define COMX_CMD(dev, cmd)	(COMX_WRITE(dev, OFF_A_L2_CMD, cmd))
+
+struct comx_firmware {
+	int	len;
+	unsigned char *data;
+};
+
+struct comx_privdata {
+	struct comx_firmware *firmware;
+	u16	clock;
+	char	channel;		// channel no.
+	int	memory_size;
+	short	io_extent;
+	u_long	histogram[5];
+};
+
+struct device *memory_used[(COMX_MEM_MAX - COMX_MEM_MIN) / 0x10000];
+extern struct comx_hardware hicomx_hw;
+extern struct comx_hardware comx_hw;
+extern struct comx_hardware cmx_hw;
+
+static void COMX_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+static void COMX_board_on(struct device *dev)
+{
+	outb_p( (byte) (((dev->mem_start & 0xf0000) >> 16) | 
+	    COMX_ENABLE_BOARD_IT | COMX_ENABLE_BOARD_MEM), dev->base_addr);
+}
+
+static void COMX_board_off(struct device *dev)
+{
+	outb_p( (byte) (((dev->mem_start & 0xf0000) >> 16) | 
+	   COMX_ENABLE_BOARD_IT), dev->base_addr);
+}
+
+static void HICOMX_board_on(struct device *dev)
+{
+	outb_p( (byte) (((dev->mem_start & 0xf0000) >> 12) | 
+	   HICOMX_ENABLE_BOARD_MEM), dev->base_addr);
+}
+
+static void HICOMX_board_off(struct device *dev)
+{
+	outb_p( (byte) (((dev->mem_start & 0xf0000) >> 12) | 
+	   HICOMX_DISABLE_BOARD_MEM), dev->base_addr);
+}
+
+static void COMX_set_clock(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct comx_privdata *hw = ch->HW_privdata;
+
+	COMX_WRITE(dev, OFF_A_L1_CLKINI, hw->clock);
+}
+
+static struct device *COMX_access_board(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct device *ret;
+	int mempos = (dev->mem_start - COMX_MEM_MIN) >> 16;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	if (memory_used[mempos] == dev) {
+		restore_flags(flags);
+		return dev;
+	}
+
+	if (ch->twin && memory_used[mempos] == ch->twin) {
+		memory_used[mempos] = dev;
+		ret = ch->twin;
+	} else {	
+		ret = memory_used[mempos];
+		if (ret) ch->HW_board_off(ret);
+		memory_used[mempos] = dev;
+		ch->HW_board_on(dev);
+	}
+	restore_flags(flags);
+	return ret;
+}
+
+static void COMX_release_board(struct device *dev, struct device *savep)
+{
+	unsigned long flags;
+	int mempos = (dev->mem_start - COMX_MEM_MIN) >> 16;
+	struct comx_channel *ch = dev->priv;
+
+	save_flags(flags); cli();
+	if (memory_used[mempos] == savep) {
+		restore_flags(flags);
+		return;
+	}
+
+	memory_used[mempos] = savep;
+	if (!ch->twin || ch->twin != savep) {
+		ch->HW_board_off(dev);
+		if (savep) ch->HW_board_on(savep);
+	}
+	restore_flags(flags);
+}
+
+static int COMX_txe(struct device *dev) 
+{
+	struct device *savep;
+	struct comx_channel *ch = dev->priv;
+	int rc = 0;
+
+	savep = ch->HW_access_board(dev);
+	if (COMX_readw(dev,OFF_A_L2_LINKUP) == LINKUP_READY) {
+		rc = COMX_readw(dev,OFF_A_L2_TxEMPTY);
+	}
+	ch->HW_release_board(dev,savep);
+	return rc;
+}
+
+static int COMX_send_packet(struct device *dev, struct sk_buff *skb)
+{
+	struct device *savep;
+	struct comx_channel *ch = dev->priv;
+	struct comx_privdata *hw = ch->HW_privdata;
+	int ret = FRAME_DROPPED;
+
+	savep = ch->HW_access_board(dev);	
+
+	if (ch->debug_flags & DEBUG_HW_TX) {
+		comx_debug_bytes(dev, skb->data, skb->len,"COMX_send packet");
+	}
+
+	if (skb->len > COMX_MAX_TX_SIZE) {
+		dev_kfree_skb(skb);
+		return FRAME_DROPPED;
+	}
+
+	if ((ch->line_status & LINE_UP) && COMX_readw(dev, OFF_A_L2_TxEMPTY)) {
+		int lensave = skb->len;
+		int dest = COMX_readw(dev, OFF_A_L2_TxBUFP);
+		word *data = (word *)skb->data;
+
+		writew((unsigned short)skb->len, dev->mem_start + dest);
+		dest += 2;
+		while (skb->len > 1) {
+			writew(*data++, dev->mem_start + dest);
+			dest += 2; skb->len -= 2;
+		}
+		if (skb->len == 1) {
+			writew(*((byte *)data), dev->mem_start + dest);
+		}
+		writew(0, dev->mem_start + (int)hw->channel * 
+		   COMX_CHANNEL_OFFSET + OFF_A_L2_TxEMPTY);
+		ch->stats.tx_packets++;	
+		ch->stats.tx_bytes += lensave; 
+		ret = FRAME_ACCEPTED;
+	} else {
+		ch->stats.tx_dropped++;
+		printk(KERN_INFO "%s: frame dropped\n",dev->name);
+	}
+	
+	ch->HW_release_board(dev, savep);
+	dev_kfree_skb(skb);
+	return ret;
+}
+
+static inline int comx_read_buffer(struct device *dev) 
+{
+	struct comx_channel *ch = dev->priv;
+	word rbuf_offs;
+	struct sk_buff *skb;
+	word len;
+	int i=0;
+	word *writeptr;
+
+	i = 0;
+	rbuf_offs = COMX_readw(dev, OFF_A_L2_RxBUFP);
+	len = readw(dev->mem_start + rbuf_offs);
+	if ((skb = dev_alloc_skb(len + 16)) == NULL) {
+		ch->stats.rx_dropped++;
+		COMX_WRITE(dev, OFF_A_L2_DAV, 0);
+		return 0;
+	}
+	rbuf_offs += 2;
+	skb_reserve(skb, 16);
+	skb_put(skb, len);
+	skb->dev = dev;
+	writeptr = (word *)skb->data;
+	while (i < len) {
+		*writeptr++ = readw(dev->mem_start + rbuf_offs);
+		rbuf_offs += 2; 
+		i += 2;
+	}
+	COMX_WRITE(dev, OFF_A_L2_DAV, 0);
+	ch->stats.rx_packets++;
+	ch->stats.rx_bytes += len;
+	if (ch->debug_flags & DEBUG_HW_RX) {
+		comx_debug_skb(dev, skb, "COMX_interrupt receiving");
+	}
+	ch->LINE_rx(dev, skb);
+	return 1;
+}
+
+static inline char comx_line_change(struct device *dev, char linestat)
+{
+	struct comx_channel *ch=dev->priv;
+	char idle=1;
+	
+	
+	if (linestat & LINE_UP) { /* Vonal fol */
+		if (ch->lineup_delay) {
+			if (!test_and_set_bit(0, &ch->lineup_pending)) {
+				ch->lineup_timer.function = comx_lineup_func;
+				ch->lineup_timer.data = (unsigned long)dev;
+				ch->lineup_timer.expires = jiffies +
+					HZ*ch->lineup_delay;
+				add_timer(&ch->lineup_timer);
+				idle=0;
+			}
+		} else {
+			idle=0;
+			ch->LINE_status(dev, ch->line_status |= LINE_UP);
+		}
+	} else { /* Vonal le */
+		idle=0;
+		if (test_and_clear_bit(0, &ch->lineup_pending)) {
+			del_timer(&ch->lineup_timer);
+		} else {
+			ch->line_status &= ~LINE_UP;
+			if (ch->LINE_status) {
+				ch->LINE_status(dev, ch->line_status);
+			}
+		}
+	}
+	return idle;
+}
+
+
+
+static void COMX_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct device *dev = dev_id;
+	struct comx_channel *ch = dev->priv;
+	struct comx_privdata *hw = ch->HW_privdata;
+	struct device *interrupted;
+	unsigned long jiffs;
+	char idle = 0;
+	int count = 0;
+	word tmp;
+
+	if (dev == NULL) {
+		printk(KERN_ERR "COMX_interrupt: irq %d for unknown device\n", irq);
+		return;
+	}
+
+	if (dev->interrupt) {
+		printk(KERN_ERR "%s: re-entering interrupt handler!\n", dev->name);
+		return;
+	}
+
+	printk("%s: entering interrupt handler\n", dev->name);
+
+	jiffs = jiffies;
+
+	dev->interrupt = 1;
+	interrupted = ch->HW_access_board(dev);
+
+	while (!idle && count < 5000) {
+		char channel = 0;
+		idle = 1;
+
+		while (channel < 2) {
+			char linestat = 0;
+			char buffers_emptied = 0;
+
+			if (channel == 1) {
+				if (ch->twin) {
+					dev->interrupt = 0;
+					dev = ch->twin;
+					dev->interrupt = 1;
+					ch = dev->priv;
+					hw = ch->HW_privdata;
+				} else {
+					break;
+				}
+			} else {
+				COMX_WRITE(dev, OFF_A_L1_REPENA, 
+				    COMX_readw(dev, OFF_A_L1_REPENA) & 0xFF00);
+			}
+			channel++;
+
+			if ((ch->init_status & (HW_OPEN | LINE_OPEN)) != 
+			   (HW_OPEN | LINE_OPEN)) {
+				continue;
+			}
+	
+			/* Collect stats */
+			tmp = COMX_readw(dev, OFF_A_L1_ABOREC);
+			COMX_WRITE(dev, OFF_A_L1_ABOREC, 0);
+			ch->stats.rx_missed_errors += (tmp >> 8) & 0xff;
+			ch->stats.rx_over_errors += tmp & 0xff;
+			tmp = COMX_readw(dev, OFF_A_L1_CRCREC);
+			COMX_WRITE(dev, OFF_A_L1_CRCREC, 0);
+			ch->stats.rx_crc_errors += (tmp >> 8) & 0xff;
+			ch->stats.rx_missed_errors += tmp & 0xff;
+
+			if ((ch->line_status & LINE_UP) && ch->LINE_rx) {
+				while (COMX_readw(dev, OFF_A_L2_DAV)) {
+					idle=0;
+					buffers_emptied+=comx_read_buffer(dev);
+				}
+			}
+
+			if (COMX_readw(dev, OFF_A_L2_TxEMPTY) && ch->LINE_tx) {
+				ch->LINE_tx(dev);
+			}
+
+			if (COMX_readw(dev, OFF_A_L1_PBUFOVR) >> 8) {
+				linestat &= ~LINE_UP;
+			} else {
+				linestat |= LINE_UP;
+			}
+
+			if ((linestat & LINE_UP) != (ch->line_status & LINE_UP)) {
+				ch->stats.tx_carrier_errors++;
+				idle &= comx_line_change(dev,linestat);
+			}
+				
+			hw->histogram[(int)buffers_emptied]++;
+		}
+		count++;
+	}
+
+	if(count==5000) {
+		printk(KERN_WARNING "%s: interrupt stuck\n",dev->name);
+	}
+
+	ch->HW_release_board(dev, interrupted);
+	printk("%s: leaving interrupt handler\n", dev->name);
+	dev->interrupt = 0;
+}
+
+static int COMX_open(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct comx_privdata *hw = ch->HW_privdata;
+	struct proc_dir_entry *procfile = ch->procdir->subdir;
+	unsigned long jiffs;
+	struct device *savep;
+
+	if (!dev->base_addr || !dev->irq || !dev->mem_start) {
+		return -ENODEV;
+	}
+
+	if (!ch->twin || 
+	   (!(((struct comx_channel *)(ch->twin->priv))->init_status & HW_OPEN))) {
+		if (check_region(dev->base_addr, hw->io_extent)) {
+			return -EAGAIN;
+		}
+		if (request_irq(dev->irq, COMX_interrupt, SA_INTERRUPT, dev->name, 
+		   (void *)dev)) {
+			printk(KERN_ERR "comx-hw-comx: unable to obtain irq %d\n", dev->irq);
+			return -EAGAIN;
+		}
+		ch->init_status |= IRQ_ALLOCATED;
+		request_region(dev->base_addr, hw->io_extent, dev->name);
+		if (!ch->HW_load_board || ch->HW_load_board(dev)) {
+			release_region(dev->base_addr, hw->io_extent);
+			free_irq(dev->irq, (void *)dev);
+			ch->init_status &= ~IRQ_ALLOCATED;
+			return -ENODEV;
+		}
+	}
+
+	savep = ch->HW_access_board(dev);
+	COMX_WRITE(dev, OFF_A_L2_LINKUP, 0);
+
+	if (ch->HW_set_clock) {
+		ch->HW_set_clock(dev);
+	}
+
+	COMX_CMD(dev, COMX_CMD_INIT); 
+	jiffs = jiffies;
+	while (COMX_readw(dev, OFF_A_L2_LINKUP) != 1 && jiffies < jiffs + HZ) {
+		schedule_timeout(1);
+	}
+	
+	ch->HW_release_board(dev, savep);
+	if (jiffies > jiffs + HZ) {
+		printk(KERN_ERR "%s: board timeout on INIT command\n", dev->name);
+		release_region(dev->base_addr, hw->io_extent);
+		free_irq(dev->irq, (void *)dev);
+		return -EIO;
+	}
+
+	savep = ch->HW_access_board(dev);
+
+	/* Ide kellene irni, hogy DTE vagy DCE ? */
+	COMX_CMD(dev, COMX_CMD_OPEN);
+
+	ch->init_status |= HW_OPEN;
+	
+	/* Ez eleg ciki, de ilyen a rendszer */
+	if (COMX_readw(dev, OFF_A_L1_PBUFOVR) >> 8) {
+		ch->line_status &= ~LINE_UP;
+	} else {
+		ch->line_status |= LINE_UP;
+	}
+	
+	if (ch->LINE_status) {
+		ch->LINE_status(dev, ch->line_status);
+	}
+
+	ch->HW_release_board(dev, savep);
+
+	for ( ; procfile ; procfile = procfile->next) {
+		if (strcmp(procfile->name, FILENAME_IRQ) == 0 
+		    || strcmp(procfile->name, FILENAME_IO) == 0
+		    || strcmp(procfile->name, FILENAME_MEMADDR) == 0
+		    || strcmp(procfile->name, FILENAME_CHANNEL) == 0
+		    || strcmp(procfile->name, FILENAME_FIRMWARE) == 0
+		    || strcmp(procfile->name, FILENAME_CLOCK) == 0) {
+			procfile->mode = S_IFREG | 0444;
+		
+		}
+	}	
+	
+	return 0;	
+}
+
+static int COMX_close(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct proc_dir_entry *procfile = ch->procdir->subdir;
+	struct comx_privdata *hw = ch->HW_privdata;
+	struct comx_channel *twin_ch;
+	struct device *savep;
+
+	savep = ch->HW_access_board(dev);
+
+	COMX_CMD(dev, COMX_CMD_CLOSE);
+	udelay(1000);
+	COMX_CMD(dev, COMX_CMD_EXIT);
+
+	ch->HW_release_board(dev, savep);
+
+	if (ch->init_status & IRQ_ALLOCATED) {
+		free_irq(dev->irq, (void *)dev);
+		ch->init_status &= ~IRQ_ALLOCATED;
+	}
+	release_region(dev->base_addr, hw->io_extent);
+
+	if (ch->twin && (twin_ch = ch->twin->priv) && 
+	    (twin_ch->init_status & HW_OPEN)) {
+		/* Pass the irq to the twin */
+		if (request_irq(dev->irq, COMX_interrupt, 0, ch->twin->name, 
+		   (void *)ch->twin) == 0) {
+			twin_ch->init_status |= IRQ_ALLOCATED;
+		}
+	}
+
+	for ( ; procfile ; procfile = procfile->next) {
+		if (strcmp(procfile->name, FILENAME_IRQ) == 0 
+		    || strcmp(procfile->name, FILENAME_IO) == 0
+		    || strcmp(procfile->name, FILENAME_MEMADDR) == 0
+		    || strcmp(procfile->name, FILENAME_CHANNEL) == 0
+		    || strcmp(procfile->name, FILENAME_FIRMWARE) == 0
+		    || strcmp(procfile->name, FILENAME_CLOCK) == 0) {
+			procfile->mode = S_IFREG | 0644;
+		}
+	}
+	
+	ch->init_status &= ~HW_OPEN;
+	return 0;
+}
+
+static int COMX_statistics(struct device *dev, char *page)
+{
+	struct comx_channel *ch = dev->priv;
+	struct comx_privdata *hw = ch->HW_privdata;
+	struct device *savep;
+	int len = 0;
+
+	savep = ch->HW_access_board(dev);
+
+	len += sprintf(page + len, "Board data: %s %s %s %s\nPBUFOVR: %02x, "
+		"MODSTAT: %02x, LINKUP: %02x, DAV: %02x\nRxBUFP: %02x, "
+		"TxEMPTY: %02x, TxBUFP: %02x\n",
+		(ch->init_status & HW_OPEN) ? "HW_OPEN" : "",
+		(ch->init_status & LINE_OPEN) ? "LINE_OPEN" : "",
+		(ch->init_status & FW_LOADED) ? "FW_LOADED" : "",
+		(ch->init_status & IRQ_ALLOCATED) ? "IRQ_ALLOCATED" : "",
+		COMX_readw(dev, OFF_A_L1_PBUFOVR) & 0xff,
+		(COMX_readw(dev, OFF_A_L1_PBUFOVR) >> 8) & 0xff,
+		COMX_readw(dev, OFF_A_L2_LINKUP) & 0xff,
+		COMX_readw(dev, OFF_A_L2_DAV) & 0xff,
+		COMX_readw(dev, OFF_A_L2_RxBUFP) & 0xff,
+		COMX_readw(dev, OFF_A_L2_TxEMPTY) & 0xff,
+		COMX_readw(dev, OFF_A_L2_TxBUFP) & 0xff);
+
+	len += sprintf(page + len, "hist[0]: %8lu hist[1]: %8lu hist[2]: %8lu\n"
+		"hist[3]: %8lu hist[4]: %8lu\n",hw->histogram[0],hw->histogram[1],
+		hw->histogram[2],hw->histogram[3],hw->histogram[4]);
+
+	ch->HW_release_board(dev, savep);
+
+	return len;
+}
+
+static int COMX_load_board(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct comx_privdata *hw = ch->HW_privdata;
+	struct comx_firmware *fw = hw->firmware;
+	word board_segment = dev->mem_start >> 16;
+	unsigned long jiff;
+	unsigned char id1, id2;
+	int len;
+	byte *COMX_address;
+
+	if (!fw || !fw->len) {
+		struct comx_channel *twin_ch = ch->twin ? ch->twin->priv : NULL;
+		struct comx_privdata *twin_hw;
+
+		if (!twin_ch || !(twin_hw = twin_ch->HW_privdata)) {
+			return -EAGAIN;
+		}
+
+		if (!(fw = twin_hw->firmware) || !fw->len) {
+			return -EAGAIN;
+		}
+	}
+
+	id1 = fw->data[OFF_FW_L1_ID]; 
+	id2 = fw->data[OFF_FW_L1_ID + 1];
+
+	if (id1 != FW_L1_ID_1 || id2 != FW_L1_ID_2_COMX) {
+		printk(KERN_ERR "%s: incorrect firmware, load aborted\n", 
+			dev->name);
+		return -EAGAIN;
+	}
+
+	printk(KERN_INFO "%s: Loading COMX Layer 1 firmware %s\n", dev->name, 
+		(char *)(fw->data + OFF_FW_L1_ID + 2));
+
+	id1 = fw->data[OFF_FW_L2_ID]; 
+	id2 = fw->data[OFF_FW_L2_ID + 1];
+	if (id1 == FW_L2_ID_1 && (id2 == 0xc0 || id2 == 0xc1 || id2 == 0xc2)) {
+		printk(KERN_INFO "with Layer 2 code %s\n", 
+			(char *)(fw->data + OFF_FW_L2_ID + 2));
+	}
+
+	outb_p(board_segment | COMX_BOARD_RESET, dev->base_addr);
+	/* 10 usec should be enough here */
+	udelay(100);
+	outb_p(board_segment | COMX_ENABLE_BOARD_MEM, dev->base_addr);
+
+	writeb(0, dev->mem_start + COMX_JAIL_OFFSET);	
+	jiff=jiffies;
+	while(jiffies < jiff + HZ && readb(dev->mem_start + COMX_JAIL_OFFSET) 
+	    != COMX_JAIL_VALUE) {
+		schedule_timeout(1);
+	}	
+	
+	if (readb(dev->mem_start + COMX_JAIL_OFFSET) != COMX_JAIL_VALUE) {
+		printk(KERN_ERR "%s: Can't reset board, JAIL value is %02x\n",
+			dev->name, readb(dev->mem_start + COMX_JAIL_OFFSET));
+		outb_p(board_segment | COMX_DISABLE_ALL, dev->base_addr);
+		return -ENODEV;
+	}
+
+	writeb(0x55, dev->mem_start + 0x18ff);
+	jiff=jiffies;
+	while(jiffies < jiff + 3*HZ && readb(dev->mem_start + 0x18ff) != 0) {
+		schedule_timeout(1);
+	}
+
+	if(readb(dev->mem_start + 0x18ff) != 0) {
+		printk(KERN_ERR "%s: Can't reset board, reset timeout\n",
+			dev->name);
+		outb_p(board_segment | COMX_DISABLE_ALL, dev->base_addr);
+		return -ENODEV;
+	}		
+
+	len = 0;
+	COMX_address = (byte *)dev->mem_start;
+	while (fw->len > len) {
+		writeb(fw->data[len++], COMX_address++);
+	}
+
+	len = 0;
+	COMX_address = (byte *)dev->mem_start;
+	while (len != fw->len && readb(COMX_address++) == fw->data[len]) {
+		len++;
+	}
+
+	if (len != fw->len) {
+		printk(KERN_ERR "%s: error loading firmware: [%d] is 0x%02x "
+			"instead of 0x%02x\n", dev->name, len, 
+			readb(COMX_address - 1), fw->data[len]);
+		outb_p(board_segment | COMX_DISABLE_ALL, dev->base_addr);
+		return -EAGAIN;
+	}
+
+	writeb(0, dev->mem_start + COMX_JAIL_OFFSET);
+
+	jiff = jiffies;
+	while ( COMX_readw(dev, OFF_A_L2_LINKUP) != 1 && jiffies < jiff + 3*HZ ) {
+		schedule_timeout(1);
+	}
+
+	if (jiffies > jiff + 3*HZ) {
+		printk(KERN_ERR "%s: error starting firmware, linkup word is %04x\n",
+			dev->name, COMX_readw(dev, OFF_A_L2_LINKUP));
+		outb_p(board_segment | COMX_DISABLE_ALL, dev->base_addr);
+		return -EAGAIN;
+	}
+
+	outb_p(board_segment | COMX_DISABLE_BOARD_MEM, dev->base_addr);
+	ch->init_status |= FW_LOADED;
+	return 0;
+}
+
+static int CMX_load_board(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct comx_privdata *hw = ch->HW_privdata;
+	struct comx_firmware *fw = hw->firmware;
+	word board_segment = dev->mem_start >> 16;
+	unsigned long jiff;
+	#if 0
+	unsigned char id1, id2;
+	#endif
+	int len;
+	byte *COMX_address;
+
+	if (!fw || !fw->len) {
+		struct comx_channel *twin_ch = ch->twin ? ch->twin->priv : NULL;
+		struct comx_privdata *twin_hw;
+
+		if (!twin_ch || !(twin_hw = twin_ch->HW_privdata)) {
+			return -EAGAIN;
+		}
+
+		if (!(fw = twin_hw->firmware) || !fw->len) {
+			return -EAGAIN;
+		}
+	}
+
+	/* Ide kell olyat tenni, hogy ellenorizze az ID-t */
+
+	if (inb_p(dev->base_addr) != CMX_ID_BYTE) {
+		printk(KERN_ERR "%s: CMX id byte is invalid(%02x)\n", dev->name,
+			inb_p(dev->base_addr));
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "%s: Loading CMX Layer 1 firmware %s\n", dev->name, 
+		(char *)(fw->data + OFF_FW_L1_ID + 2));
+
+	outb_p(board_segment | COMX_ENABLE_BOARD_MEM | COMX_BOARD_RESET, 
+		dev->base_addr);
+
+	len = 0;
+	COMX_address = (byte *)dev->mem_start;
+	while (fw->len > len) {
+		writeb(fw->data[len++], COMX_address++);
+	}
+
+	len = 0;
+	COMX_address = (byte *)dev->mem_start;
+	while (len != fw->len && readb(COMX_address++) == fw->data[len]) {
+		len++;
+	}
+
+	outb_p(board_segment | COMX_ENABLE_BOARD_MEM, dev->base_addr);
+
+	if (len != fw->len) {
+		printk(KERN_ERR "%s: error loading firmware: [%d] is 0x%02x "
+			"instead of 0x%02x\n", dev->name, len, 
+			readb(COMX_address - 1), fw->data[len]);
+		outb_p(board_segment | COMX_DISABLE_ALL, dev->base_addr);
+		return -EAGAIN;
+	}
+
+	jiff = jiffies;
+	while ( COMX_readw(dev, OFF_A_L2_LINKUP) != 1 && jiffies < jiff + 3*HZ ) {
+		schedule_timeout(1);
+	}
+
+	if (jiffies > jiff + 3*HZ) {
+		printk(KERN_ERR "%s: error starting firmware, linkup word is %04x\n",
+			dev->name, COMX_readw(dev, OFF_A_L2_LINKUP));
+		outb_p(board_segment | COMX_DISABLE_ALL, dev->base_addr);
+		return -EAGAIN;
+	}
+
+	outb_p(board_segment | COMX_DISABLE_BOARD_MEM, dev->base_addr);
+	ch->init_status |= FW_LOADED;
+	return 0;
+}
+
+static int HICOMX_load_board(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct comx_privdata *hw = ch->HW_privdata;
+	struct comx_firmware *fw = hw->firmware;
+	word board_segment = dev->mem_start >> 12;
+	unsigned long jiff;
+	unsigned char id1, id2;
+	int len;
+	word *HICOMX_address;
+	char id = 1;
+
+	if (!fw || !fw->len) {
+		struct comx_channel *twin_ch = ch->twin ? ch->twin->priv : NULL;
+		struct comx_privdata *twin_hw;
+
+		if (!twin_ch || !(twin_hw = twin_ch->HW_privdata)) {
+			return -EAGAIN;
+		}
+
+		if (!(fw = twin_hw->firmware) || !fw->len) {
+			return -EAGAIN;
+		}
+	}
+
+	while (id != 4) {
+		if (inb_p(dev->base_addr + id++) != HICOMX_ID_BYTE) {
+			break;
+		}
+	}
+
+	if (id != 4) {
+		printk(KERN_ERR "%s: can't find HICOMX at 0x%04x, id[%d] = %02x\n",
+			dev->name, (unsigned int)dev->base_addr, id - 1,
+			inb_p(dev->base_addr + id - 1));
+		return -1;	
+	}
+
+	id1 = fw->data[OFF_FW_L1_ID]; 
+	id2 = fw->data[OFF_FW_L1_ID + 1];
+	if (id1 != FW_L1_ID_1 || id2 != FW_L1_ID_2_HICOMX) {
+		printk(KERN_ERR "%s: incorrect firmware, load aborted\n", dev->name);
+		return -EAGAIN;
+	}
+
+	printk(KERN_INFO "%s: Loading HICOMX Layer 1 firmware %s\n", dev->name, 
+		(char *)(fw->data + OFF_FW_L1_ID + 2));
+
+	id1 = fw->data[OFF_FW_L2_ID]; 
+	id2 = fw->data[OFF_FW_L2_ID + 1];
+	if (id1 == FW_L2_ID_1 && (id2 == 0xc0 || id2 == 0xc1 || id2 == 0xc2)) {
+		printk(KERN_INFO "with Layer 2 code %s\n", 
+			(char *)(fw->data + OFF_FW_L2_ID + 2));
+	}
+
+	outb_p(board_segment | HICOMX_BOARD_RESET, dev->base_addr);
+	udelay(10);	
+	outb_p(board_segment | HICOMX_ENABLE_BOARD_MEM, dev->base_addr);
+	outb_p(HICOMX_PRG_MEM, dev->base_addr + 1);
+
+	len = 0;
+	HICOMX_address = (word *)dev->mem_start;
+	while (fw->len > len) {
+		writeb(fw->data[len++], HICOMX_address++);
+	}
+
+	len = 0;
+	HICOMX_address = (word *)dev->mem_start;
+	while (len != fw->len && (readw(HICOMX_address++) & 0xff) == fw->data[len]) {
+		len++;
+	}
+
+	if (len != fw->len) {
+		printk(KERN_ERR "%s: error loading firmware: [%d] is 0x%02x "
+			"instead of 0x%02x\n", dev->name, len, 
+			readw(HICOMX_address - 1) & 0xff, fw->data[len]);
+		outb_p(board_segment | HICOMX_DISABLE_ALL, dev->base_addr);
+		outb_p(HICOMX_DATA_MEM, dev->base_addr + 1);
+		return -EAGAIN;
+	}
+
+	outb_p(board_segment | HICOMX_BOARD_RESET, dev->base_addr);
+	outb_p(HICOMX_DATA_MEM, dev->base_addr + 1);
+	outb_p(board_segment | HICOMX_ENABLE_BOARD_MEM, dev->base_addr);
+
+	jiff = jiffies;
+	while ( COMX_readw(dev, OFF_A_L2_LINKUP) != 1 && jiffies < jiff + 3*HZ ) {
+		schedule_timeout(1);
+	}
+
+	if ( COMX_readw(dev, OFF_A_L2_LINKUP) != 1 ) {
+		printk(KERN_ERR "%s: error starting firmware, linkup word is %04x\n",
+			dev->name, COMX_readw(dev, OFF_A_L2_LINKUP));
+		outb_p(board_segment | HICOMX_DISABLE_ALL, dev->base_addr);
+		return -EAGAIN;
+	}
+
+	outb_p(board_segment | HICOMX_DISABLE_ALL, dev->base_addr);
+	ch->init_status |= FW_LOADED;
+	return 0;
+}
+
+static struct device *comx_twin_check(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct proc_dir_entry *procfile = ch->procdir->parent->subdir;
+	struct comx_privdata *hw = ch->HW_privdata;
+
+	struct device *twin;
+	struct comx_channel *ch_twin;
+	struct comx_privdata *hw_twin;
+
+
+	for ( ; procfile ; procfile = procfile->next) {
+	
+		if(!S_ISDIR(procfile->mode)) {
+			continue;
+		}
+	
+		twin=procfile->data;
+		ch_twin=twin->priv;
+		hw_twin=ch_twin->HW_privdata;
+
+
+		if (twin != dev && dev->irq && dev->base_addr && dev->mem_start &&
+		   dev->irq == twin->irq && dev->base_addr == twin->base_addr &&
+	  	   dev->mem_start == twin->mem_start &&
+		   hw->channel == (1 - hw_twin->channel) &&
+		   ch->hardware == ch_twin->hardware) {
+		   	return twin;
+		}
+	}
+	return NULL;
+}
+
+static int comxhw_write_proc(struct file *file, const char *buffer, 
+	u_long count, void *data)
+{
+	struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
+	struct device *dev = entry->parent->data;
+	struct comx_channel *ch = dev->priv;
+	struct comx_privdata *hw = ch->HW_privdata;
+	char *page;
+
+
+	if (file->f_dentry->d_inode->i_ino != entry->low_ino) {
+		printk(KERN_ERR "comx_write_proc: file <-> data internal error\n");
+		return -EIO;
+	}
+
+	if(ch->init_status & HW_OPEN) {
+		return -EAGAIN;	
+	}
+	
+	if (strcmp(FILENAME_FIRMWARE, entry->name) != 0) {
+		if (!(page = (char *)__get_free_page(GFP_KERNEL))) {
+			return -ENOMEM;
+		}
+		copy_from_user(page, buffer, count = (min(count, PAGE_SIZE)));
+		if (*(page + count - 1) == '\n') {
+			*(page + count - 1) = 0;
+		}
+	} else {
+		byte *tmp;
+
+		if (!hw->firmware) {
+			if ((hw->firmware = kmalloc(sizeof(struct comx_firmware), 
+			    GFP_KERNEL)) == NULL) {
+			    	return -ENOMEM;
+			}
+			hw->firmware->len = 0;
+			hw->firmware->data = NULL;
+		}
+		
+		if ((tmp = kmalloc(count + file->f_pos, GFP_KERNEL)) == NULL) {
+			return -ENOMEM;
+		}
+		
+		/* Ha nem 0 a fpos, akkor meglevo file-t irunk. Gyenge trukk. */
+		if (hw->firmware && hw->firmware->len && file->f_pos 
+		    && hw->firmware->len < count + file->f_pos) {
+			memcpy(tmp, hw->firmware->data, hw->firmware->len);
+		}
+		if (hw->firmware->data) {
+			kfree(hw->firmware->data);
+		}
+		copy_from_user(tmp + file->f_pos, buffer, count);
+		hw->firmware->len = entry->size = file->f_pos + count;
+		hw->firmware->data = tmp;
+		file->f_pos += count;
+		return count;
+	}
+
+	if (strcmp(entry->name, FILENAME_CHANNEL) == 0) {
+		hw->channel = simple_strtoul(page, NULL, 0);
+		if (hw->channel >= MAX_CHANNELNO) {
+			printk(KERN_ERR "Invalid channel number\n");
+			hw->channel = 0;
+		}
+		if ((ch->twin = comx_twin_check(dev)) != NULL) {
+			struct comx_channel *twin_ch = ch->twin->priv;
+			twin_ch->twin = dev;
+		}
+	} else if (strcmp(entry->name, FILENAME_IRQ) == 0) {
+		dev->irq = simple_strtoul(page, NULL, 0);
+		if (dev->irq == 2) {
+			dev->irq = 9;
+		}
+		if (dev->irq < 3 || dev->irq > 15) {
+			printk(KERN_ERR "comxhw: Invalid irq number\n");
+			dev->irq = 0;
+		}
+		if ((ch->twin = comx_twin_check(dev)) != NULL) {
+			struct comx_channel *twin_ch = ch->twin->priv;
+			twin_ch->twin = dev;
+		}
+	} else if (strcmp(entry->name, FILENAME_IO) == 0) {
+		dev->base_addr = simple_strtoul(page, NULL, 0);
+		if ((dev->base_addr & 3) != 0 || dev->base_addr < 0x300 
+		   || dev->base_addr > 0x3fc) {
+			printk(KERN_ERR "Invalid io value\n");
+			dev->base_addr = 0;
+		}
+		if ((ch->twin = comx_twin_check(dev)) != NULL) {
+			struct comx_channel *twin_ch = ch->twin->priv;
+
+			twin_ch->twin = dev;
+		}
+	} else if (strcmp(entry->name, FILENAME_MEMADDR) == 0) {
+		dev->mem_start = simple_strtoul(page, NULL, 0);
+		if (dev->mem_start <= 0xf000 && dev->mem_start >= 0xa000) {
+			dev->mem_start *= 16;
+		}
+		if ((dev->mem_start & 0xfff) != 0 || dev->mem_start < COMX_MEM_MIN
+		    || dev->mem_start + hw->memory_size > COMX_MEM_MAX) {
+			printk(KERN_ERR "Invalid memory page\n");
+			dev->mem_start = 0;
+		}
+		dev->mem_end = dev->mem_start + hw->memory_size;
+		if ((ch->twin = comx_twin_check(dev)) != NULL) {
+			struct comx_channel *twin_ch = ch->twin->priv;
+
+			twin_ch->twin = dev;
+		}
+	} else if (strcmp(entry->name, FILENAME_CLOCK) == 0) {
+		if (strncmp("ext", page, 3) == 0) {
+			hw->clock = 0;
+		} else {
+			int kbps;
+
+			kbps = simple_strtoul(page, NULL, 0);
+			hw->clock = kbps ? COMX_CLOCK_CONST/kbps : 0;
+		}
+	}
+
+	free_page((unsigned long)page);
+	return count;
+}
+
+static int comxhw_read_proc(char *page, char **start, off_t off, int count,
+	int *eof, void *data)
+{
+	struct proc_dir_entry *file = (struct proc_dir_entry *)data;
+	struct device *dev = file->parent->data;
+	struct comx_channel *ch = dev->priv;
+	struct comx_privdata *hw = ch->HW_privdata;
+	int len = 0;
+
+
+	if (strcmp(file->name, FILENAME_IO) == 0) {
+		len = sprintf(page, "0x%03x\n", (unsigned int)dev->base_addr);
+	} else if (strcmp(file->name, FILENAME_IRQ) == 0) {
+		len = sprintf(page, "0x%02x\n", dev->irq == 9 ? 2 : dev->irq);
+	} else if (strcmp(file->name, FILENAME_CHANNEL) == 0) {
+		len = sprintf(page, "%01d\n", hw->channel);
+	} else if (strcmp(file->name, FILENAME_MEMADDR) == 0) {
+		len = sprintf(page, "0x%05x\n", (unsigned int)dev->mem_start);
+	} else if (strcmp(file->name, FILENAME_TWIN) == 0) {
+		len = sprintf(page, "%s\n", ch->twin ? ch->twin->name : "none");
+	} else if (strcmp(file->name, FILENAME_CLOCK) == 0) {
+		if (hw->clock) {
+			len = sprintf(page, "%-8d\n", COMX_CLOCK_CONST/hw->clock);
+		} else {
+			len = sprintf(page, "external\n");
+		}
+	} else if (strcmp(file->name, FILENAME_FIRMWARE) == 0) {
+		len = min(FILE_PAGESIZE, min(count, 
+			hw->firmware ? (hw->firmware->len - off) :  0));
+		if (len < 0) {
+			len = 0;
+		}
+		*start = hw->firmware ? (hw->firmware->data + off) : NULL;
+		if (off + len >= (hw->firmware ? hw->firmware->len : 0) || len == 0) {
+			*eof = 1;
+		}
+		return len;
+	}	
+
+	if (off >= len) {
+		*eof = 1;
+		return 0;
+	}
+
+	*start = page + off;
+	if (count >= len - off) {
+		*eof = 1;
+	}
+	return(min(count, len - off));
+}
+
+/* Called on echo comx >boardtype */
+static int COMX_init(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct comx_privdata *hw;
+	struct proc_dir_entry *new_file;
+
+	if ((ch->HW_privdata = kmalloc(sizeof(struct comx_privdata), 
+	    GFP_KERNEL)) == NULL) {
+	    	return -ENOMEM;
+	}
+	memset(hw = ch->HW_privdata, 0, sizeof(struct comx_privdata));
+
+	if (ch->hardware == &comx_hw || ch->hardware == &cmx_hw) {
+		hw->memory_size = COMX_MEMORY_SIZE;
+		hw->io_extent = COMX_IO_EXTENT;
+		dev->base_addr = COMX_DEFAULT_IO;
+		dev->irq = COMX_DEFAULT_IRQ;
+		dev->mem_start = COMX_DEFAULT_MEMADDR;
+		dev->mem_end = COMX_DEFAULT_MEMADDR + COMX_MEMORY_SIZE;
+	} else if (ch->hardware == &hicomx_hw) {
+		hw->memory_size = HICOMX_MEMORY_SIZE;
+		hw->io_extent = HICOMX_IO_EXTENT;
+		dev->base_addr = HICOMX_DEFAULT_IO;
+		dev->irq = HICOMX_DEFAULT_IRQ;
+		dev->mem_start = HICOMX_DEFAULT_MEMADDR;
+		dev->mem_end = HICOMX_DEFAULT_MEMADDR + HICOMX_MEMORY_SIZE;
+	} else {
+		printk(KERN_ERR "SERIOUS INTERNAL ERROR in %s, line %d\n", __FILE__, __LINE__);
+	}
+
+	if ((new_file = create_proc_entry(FILENAME_IO, S_IFREG | 0644, ch->procdir))
+	    == NULL) {
+	    	return -EIO;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &comxhw_read_proc;
+	new_file->write_proc = &comxhw_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->size = 6;
+	new_file->nlink = 1;
+
+	if ((new_file = create_proc_entry(FILENAME_IRQ, S_IFREG | 0644, ch->procdir))
+	    == NULL) {
+	    	return -EIO;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &comxhw_read_proc;
+	new_file->write_proc = &comxhw_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->size = 5;
+	new_file->nlink = 1;
+
+	if ((new_file = create_proc_entry(FILENAME_CHANNEL, S_IFREG | 0644, 
+	    ch->procdir)) == NULL) {
+	    	return -EIO;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &comxhw_read_proc;
+	new_file->write_proc = &comxhw_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->size = 2;		// Ezt tudjuk
+	new_file->nlink = 1;
+
+	if (ch->hardware == &hicomx_hw || ch->hardware == &cmx_hw) {
+		if ((new_file = create_proc_entry(FILENAME_CLOCK, S_IFREG | 0644, 
+		   ch->procdir)) == NULL) {
+		   	return -EIO;
+		}
+		new_file->data = (void *)new_file;
+		new_file->read_proc = &comxhw_read_proc;
+		new_file->write_proc = &comxhw_write_proc;
+		new_file->ops = &comx_normal_inode_ops;
+		new_file->size = 9;
+		new_file->nlink = 1;
+	}
+
+	if ((new_file = create_proc_entry(FILENAME_MEMADDR, S_IFREG | 0644, 
+	    ch->procdir)) == NULL) {
+	    	return -EIO;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &comxhw_read_proc;
+	new_file->write_proc = &comxhw_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->size = 8;
+	new_file->nlink = 1;
+
+	if ((new_file = create_proc_entry(FILENAME_TWIN, S_IFREG | 0444, 
+	    ch->procdir)) == NULL) {
+		return -EIO;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &comxhw_read_proc;
+	new_file->write_proc = NULL;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->nlink = 1;
+
+	if ((new_file = create_proc_entry(FILENAME_FIRMWARE, S_IFREG | 0644, 
+	    ch->procdir)) == NULL) {
+	    	return -EIO;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &comxhw_read_proc;
+	new_file->write_proc = &comxhw_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->nlink = 1;
+
+	if (ch->hardware == &comx_hw) {
+		ch->HW_board_on = COMX_board_on;
+		ch->HW_board_off = COMX_board_off;
+		ch->HW_load_board = COMX_load_board;
+	} else if (ch->hardware == &cmx_hw) {
+		ch->HW_board_on = COMX_board_on;
+		ch->HW_board_off = COMX_board_off;
+		ch->HW_load_board = CMX_load_board;
+		ch->HW_set_clock = COMX_set_clock;
+	} else if (ch->hardware == &hicomx_hw) {
+		ch->HW_board_on = HICOMX_board_on;
+		ch->HW_board_off = HICOMX_board_off;
+		ch->HW_load_board = HICOMX_load_board;
+		ch->HW_set_clock = COMX_set_clock;
+	} else {
+		printk(KERN_ERR "SERIOUS INTERNAL ERROR in %s, line %d\n", __FILE__, __LINE__);
+	}
+
+	ch->HW_access_board = COMX_access_board;
+	ch->HW_release_board = COMX_release_board;
+	ch->HW_txe = COMX_txe;
+	ch->HW_open = COMX_open;
+	ch->HW_close = COMX_close;
+	ch->HW_send_packet = COMX_send_packet;
+	ch->HW_statistics = COMX_statistics;
+
+	if ((ch->twin = comx_twin_check(dev)) != NULL) {
+		struct comx_channel *twin_ch = ch->twin->priv;
+
+		twin_ch->twin = dev;
+	}
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/* Called on echo valami >boardtype */
+static int COMX_exit(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct comx_privdata *hw = ch->HW_privdata;
+
+	if (hw->firmware) {
+		if (hw->firmware->data) kfree(hw->firmware->data);
+		kfree(hw->firmware);
+	} if (ch->twin) {
+		struct comx_channel *twin_ch = ch->twin->priv;
+
+		twin_ch->twin = NULL;
+	}
+	
+	kfree(ch->HW_privdata);
+	remove_proc_entry(FILENAME_IO, ch->procdir);
+	remove_proc_entry(FILENAME_IRQ, ch->procdir);
+	remove_proc_entry(FILENAME_CHANNEL, ch->procdir);
+	remove_proc_entry(FILENAME_MEMADDR, ch->procdir);
+	remove_proc_entry(FILENAME_FIRMWARE, ch->procdir);
+	remove_proc_entry(FILENAME_TWIN, ch->procdir);
+	if (ch->hardware == &hicomx_hw || ch->hardware == &cmx_hw) {
+		remove_proc_entry(FILENAME_CLOCK, ch->procdir);
+	}
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int COMX_dump(struct device *dev)
+{
+	printk(KERN_INFO "%s: COMX_dump called, why ?\n", dev->name);
+	return 0;
+}
+
+static struct comx_hardware comx_hw = {
+	"comx",
+	VERSION,
+	COMX_init,
+	COMX_exit,
+	COMX_dump,
+	NULL
+};
+
+static struct comx_hardware cmx_hw = {
+	"cmx",
+	VERSION,
+	COMX_init,
+	COMX_exit,
+	COMX_dump,
+	NULL
+};
+
+static struct comx_hardware hicomx_hw = {
+	"hicomx",
+	VERSION,
+	COMX_init,
+	COMX_exit,
+	COMX_dump,
+	NULL
+};
+
+#ifdef MODULE
+#define comx_hw_comx_init init_module
+#endif
+
+__initfunc(int comx_hw_comx_init(void))
+{
+	comx_register_hardware(&comx_hw);
+	comx_register_hardware(&cmx_hw);
+	comx_register_hardware(&hicomx_hw);
+	memset(memory_used, 0, sizeof(memory_used));
+	return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	comx_unregister_hardware("comx");
+	comx_unregister_hardware("cmx");
+	comx_unregister_hardware("hicomx");
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/comx-hw-locomx.c linux.14p16/drivers/net/comx-hw-locomx.c
--- linux.vanilla/drivers/net/comx-hw-locomx.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/comx-hw-locomx.c	Thu Dec  9 15:33:37 1999
@@ -0,0 +1,498 @@
+/*
+ * Hardware driver for the LoCOMX card, using the generic z85230
+ * functions
+ *
+ * Author: Gergely Madarasz <gorgo@itc.hu>
+ *
+ * Based on skeleton code and old LoCOMX driver by Tivadar Szemethy <tiv@itc.hu> 
+ * and the hostess_sv11 driver
+ *
+ * Copyright (C) 1999 ITConsult-Pro Co. <info@itc.hu>
+ *
+ * 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.
+ *
+ * Version 0.10 (99/06/17):
+ *		- rewritten for the z85230 layer
+ *
+ * Version 0.11 (99/06/21):
+ *		- some printk's fixed
+ *		- get rid of a memory leak (it was impossible though :))
+ * 
+ * Version 0.12 (99/07/07):
+ *		- check CTS for modem lines, not DCD (which is always high
+ *		  in case of this board)
+ * Version 0.13 (99/07/08):
+ *		- Fix the transmitter status check
+ *		- Handle the net device statistics better
+ */
+
+#define VERSION "0.13"
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <asm/types.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+
+#include "comx.h"
+#include "z85230.h"
+
+MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
+MODULE_DESCRIPTION("Hardware driver for the LoCOMX board");
+
+#define RX_DMA 3
+#define TX_DMA 1
+#define LOCOMX_ID 0x33
+#define LOCOMX_IO_EXTENT 8
+#define LOCOMX_DEFAULT_IO 0x368
+#define LOCOMX_DEFAULT_IRQ 7
+
+u8 z8530_locomx[] = {
+	11,     TCRTxCP,
+	14,     DTRREQ,
+	255
+};
+
+struct locomx_data {
+	int	io_extent;
+	struct	z8530_dev board;
+	struct timer_list status_timer;
+};
+
+static int LOCOMX_txe(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct locomx_data *hw = ch->HW_privdata;
+
+	return (!hw->board.chanA.tx_next_skb);
+}
+
+
+static void locomx_rx(struct z8530_channel *c, struct sk_buff *skb)
+{
+	struct device *dev=c->netdevice;
+	struct comx_channel *ch=dev->priv;
+	
+	if (ch->debug_flags & DEBUG_HW_RX) {
+		comx_debug_skb(dev, skb, "locomx_rx receiving");
+	}
+	ch->LINE_rx(dev,skb);
+}
+
+static int LOCOMX_send_packet(struct device *dev, struct sk_buff *skb) 
+{
+	struct comx_channel *ch = (struct comx_channel *)dev->priv;
+	struct locomx_data *hw = ch->HW_privdata;
+
+	if (ch->debug_flags & DEBUG_HW_TX) {
+		comx_debug_bytes(dev, skb->data, skb->len, "LOCOMX_send_packet");
+	}
+
+	if (!(ch->line_status & LINE_UP)) {
+		return FRAME_DROPPED;
+	}
+
+	if(z8530_queue_xmit(&hw->board.chanA,skb)) {
+		printk(KERN_WARNING "%s: FRAME_DROPPED\n",dev->name);
+		return FRAME_DROPPED;
+	}
+
+	if (ch->debug_flags & DEBUG_HW_TX) {
+		comx_debug(dev, "%s: LOCOMX_send_packet was successful\n\n", dev->name);
+	}
+
+	if(!hw->board.chanA.tx_next_skb) {
+		return FRAME_QUEUED;
+	} else {
+		return FRAME_ACCEPTED;
+	}
+}
+
+static void locomx_status_timerfun(unsigned long d)
+{
+	struct device *dev=(struct device *)d;
+	struct comx_channel *ch=dev->priv;
+	struct locomx_data *hw=ch->HW_privdata;
+
+	if(!(ch->line_status & LINE_UP) &&
+	    (hw->board.chanA.status & CTS)) {
+		ch->LINE_status(dev, ch->line_status | LINE_UP);
+	}
+	if((ch->line_status & LINE_UP) &&
+	    !(hw->board.chanA.status & CTS)) {
+		ch->LINE_status(dev, ch->line_status & ~LINE_UP);
+	}
+	mod_timer(&hw->status_timer,jiffies + ch->lineup_delay * HZ);
+}
+
+
+static int LOCOMX_open(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct locomx_data *hw = ch->HW_privdata;
+	struct proc_dir_entry *procfile = ch->procdir->subdir;
+	unsigned long flags;
+	int ret;
+
+	if (!dev->base_addr || !dev->irq) {
+		return -ENODEV;
+	}
+
+	if (check_region(dev->base_addr, hw->io_extent)) {
+		return -EAGAIN;
+	}
+
+	request_region(dev->base_addr, hw->io_extent, dev->name);
+
+	hw->board.chanA.ctrlio=dev->base_addr + 5;
+	hw->board.chanA.dataio=dev->base_addr + 7;
+	
+	hw->board.irq=dev->irq;
+	hw->board.chanA.netdevice=dev;
+	hw->board.chanA.dev=&hw->board;
+	hw->board.name=dev->name;
+	hw->board.chanA.txdma=TX_DMA;
+	hw->board.chanA.rxdma=RX_DMA;
+	hw->board.chanA.irqs=&z8530_nop;
+	hw->board.chanB.irqs=&z8530_nop;
+
+	if(request_irq(dev->irq, z8530_interrupt, SA_INTERRUPT, 
+	    dev->name, &hw->board)) {
+		printk(KERN_ERR "%s: unable to obtain irq %d\n", dev->name, 
+			dev->irq);
+		ret=-EAGAIN;
+		goto irq_fail;
+	}
+	if(request_dma(TX_DMA,"LoCOMX (TX)")) {
+		printk(KERN_ERR "%s: unable to obtain TX DMA (DMA channel %d)\n", 
+			dev->name, TX_DMA);
+		ret=-EAGAIN;
+		goto dma1_fail;
+	}
+
+	if(request_dma(RX_DMA,"LoCOMX (RX)")) {
+		printk(KERN_ERR "%s: unable to obtain RX DMA (DMA channel %d)\n", 
+			dev->name, RX_DMA);
+		ret=-EAGAIN;
+		goto dma2_fail;
+	}
+	
+	save_flags(flags); 
+	cli();
+
+	if(z8530_init(&hw->board)!=0)
+	{
+		printk(KERN_ERR "%s: Z8530 device not found.\n",dev->name);
+		ret=-ENODEV;
+		goto z8530_fail;
+	}
+
+	hw->board.chanA.dcdcheck=CTS;
+
+	z8530_channel_load(&hw->board.chanA, z8530_hdlc_kilostream_85230);
+	z8530_channel_load(&hw->board.chanA, z8530_locomx);
+	z8530_channel_load(&hw->board.chanB, z8530_dead_port);
+
+	z8530_describe(&hw->board, "I/O", dev->base_addr);
+
+	if((ret=z8530_sync_dma_open(dev, &hw->board.chanA))!=0) {
+		goto z8530_fail;
+	}
+
+	restore_flags(flags);
+
+
+	hw->board.active=1;
+	hw->board.chanA.rx_function=locomx_rx;
+
+	ch->init_status |= HW_OPEN;
+	if (hw->board.chanA.status & DCD) {
+		ch->line_status |= LINE_UP;
+	} else {
+		ch->line_status &= ~LINE_UP;
+	}
+
+	comx_status(dev, ch->line_status);
+
+	init_timer(&hw->status_timer);
+	hw->status_timer.function=locomx_status_timerfun;
+	hw->status_timer.data=(unsigned long)dev;
+	hw->status_timer.expires=jiffies + ch->lineup_delay * HZ;
+	add_timer(&hw->status_timer);
+
+	for (; procfile ; procfile = procfile->next) {
+		if (strcmp(procfile->name, FILENAME_IO) == 0 ||
+		     strcmp(procfile->name, FILENAME_IRQ) == 0) {
+			procfile->mode = S_IFREG |  0444;
+		}
+	}
+	return 0;
+
+z8530_fail:
+	restore_flags(flags);
+	free_dma(RX_DMA);
+dma2_fail:
+	free_dma(TX_DMA);
+dma1_fail:
+	free_irq(dev->irq, &hw->board);
+irq_fail:
+	release_region(dev->base_addr, hw->io_extent);
+	return ret;
+}
+
+static int LOCOMX_close(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct locomx_data *hw = ch->HW_privdata;
+	struct proc_dir_entry *procfile = ch->procdir->subdir;
+
+	hw->board.chanA.rx_function=z8530_null_rx;
+	dev->tbusy=1;
+	z8530_sync_dma_close(dev, &hw->board.chanA);
+
+	z8530_shutdown(&hw->board);
+
+	del_timer(&hw->status_timer);
+	free_dma(RX_DMA);
+	free_dma(TX_DMA);
+	free_irq(dev->irq,&hw->board);
+	release_region(dev->base_addr,8);
+
+	for (; procfile ; procfile = procfile->next) {
+		if (strcmp(procfile->name, FILENAME_IO) == 0 ||
+		    strcmp(procfile->name, FILENAME_IRQ) == 0) {
+			procfile->mode = S_IFREG |  0644;
+		}
+	}
+
+	ch->init_status &= ~HW_OPEN;
+	return 0;
+}
+
+static int LOCOMX_statistics(struct device *dev,char *page)
+{
+	int len = 0;
+
+	len += sprintf(page + len, "Hello\n");
+
+	return len;
+}
+
+static int LOCOMX_dump(struct device *dev) {
+	printk(KERN_INFO "LOCOMX_dump called\n");
+	return(-1);
+}
+
+static int locomx_read_proc(char *page, char **start, off_t off, int count,
+	int *eof, void *data)
+{
+	struct proc_dir_entry *file = (struct proc_dir_entry *)data;
+	struct device *dev = file->parent->data;
+	int len = 0;
+
+	if (strcmp(file->name, FILENAME_IO) == 0) {
+		len = sprintf(page, "0x%x\n", (unsigned int)dev->base_addr);
+	} else if (strcmp(file->name, FILENAME_IRQ) == 0) {
+		len = sprintf(page, "%d\n", (unsigned int)dev->irq);
+	} else {
+		printk(KERN_ERR "hw_read_proc: internal error, filename %s\n", 
+			file->name);
+		return -EBADF;
+	}
+
+	if (off >= len) {
+		*eof = 1;
+		return 0;
+	}
+
+	*start = page + off;
+	if (count >= len - off) {
+		*eof = 1;
+	}
+	return ( min(count, len - off) );
+}
+
+static int locomx_write_proc(struct file *file, const char *buffer,
+	u_long count, void *data)
+{
+	struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
+	struct device *dev = (struct device *)entry->parent->data;
+	int val;
+	char *page;
+
+	if (file->f_dentry->d_inode->i_ino != entry->low_ino) {
+		printk(KERN_ERR "hw_write_proc: file <-> data internal error\n");
+		return -EIO;
+	}
+
+	if (!(page = (char *)__get_free_page(GFP_KERNEL))) {
+		return -ENOMEM;
+	}
+
+	copy_from_user(page, buffer, count = min(count, PAGE_SIZE));
+	if (*(page + count - 1) == '\n') {
+		*(page + count - 1) = 0;
+	}
+
+	if (strcmp(entry->name, FILENAME_IO) == 0) {
+		val = simple_strtoul(page, NULL, 0);
+		if (val != 0x360 && val != 0x368 && val != 0x370 && 
+		   val != 0x378) {
+			printk(KERN_ERR "LoCOMX: incorrect io address!\n");	
+		} else {
+			dev->base_addr = val;
+		}
+	} else if (strcmp(entry->name, FILENAME_IRQ) == 0) {
+		val = simple_strtoul(page, NULL, 0);
+		if (val != 3 && val != 4 && val != 5 && val != 6 && val != 7) {
+			printk(KERN_ERR "LoCOMX: incorrect irq value!\n");
+		} else {
+			dev->irq = val;
+		}	
+	} else {
+		printk(KERN_ERR "locomx_write_proc: internal error, filename %s\n", 
+			entry->name);
+		free_page((unsigned long)page);
+		return -EBADF;
+	}
+
+	free_page((unsigned long)page);
+	return count;
+}
+
+
+
+static int LOCOMX_init(struct device *dev) 
+{
+	struct comx_channel *ch = (struct comx_channel *)dev->priv;
+	struct locomx_data *hw;
+	struct proc_dir_entry *new_file;
+
+	/* Alloc data for private structure */
+	if ((ch->HW_privdata = kmalloc(sizeof(struct locomx_data), 
+	   GFP_KERNEL)) == NULL) {
+	   	return -ENOMEM;
+	}
+
+	memset(hw = ch->HW_privdata, 0, sizeof(struct locomx_data));
+	hw->io_extent = LOCOMX_IO_EXTENT;
+
+	/* Register /proc files */
+	if ((new_file = create_proc_entry(FILENAME_IO, S_IFREG | 0644, 
+	    ch->procdir)) == NULL) {
+		return -EIO;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &locomx_read_proc;
+	new_file->write_proc = &locomx_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->nlink = 1;
+
+	if ((new_file = create_proc_entry(FILENAME_IRQ, S_IFREG | 0644, 
+	    ch->procdir)) == NULL)  {
+		return -EIO;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &locomx_read_proc;
+	new_file->write_proc = &locomx_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->nlink = 1;
+
+/* 	No clock yet */
+/*
+	if ((new_file = create_proc_entry(FILENAME_CLOCK, S_IFREG | 0644, 
+	    ch->procdir)) == NULL) {
+		return -EIO;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &locomx_read_proc;
+	new_file->write_proc = &locomx_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->nlink = 1;
+*/
+
+	ch->HW_access_board = NULL;
+	ch->HW_release_board = NULL;
+	ch->HW_txe = LOCOMX_txe;
+	ch->HW_open = LOCOMX_open;
+	ch->HW_close = LOCOMX_close;
+	ch->HW_send_packet = LOCOMX_send_packet;
+	ch->HW_statistics = LOCOMX_statistics;
+	ch->HW_set_clock = NULL;
+
+	ch->current_stats = &hw->board.chanA.stats;
+	memcpy(ch->current_stats, &ch->stats, sizeof(struct net_device_stats));
+
+	dev->base_addr = LOCOMX_DEFAULT_IO;
+	dev->irq = LOCOMX_DEFAULT_IRQ;
+	
+	
+	/* O.K. Count one more user on this module */
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+
+static int LOCOMX_exit(struct device *dev)
+{
+	struct comx_channel *ch = (struct comx_channel *)dev->priv;
+
+	ch->HW_access_board = NULL;
+	ch->HW_release_board = NULL;
+	ch->HW_txe = NULL;
+	ch->HW_open = NULL;
+	ch->HW_close = NULL;
+	ch->HW_send_packet = NULL;
+	ch->HW_statistics = NULL;
+	ch->HW_set_clock = NULL;
+	memcpy(&ch->stats, ch->current_stats, sizeof(struct net_device_stats));
+	ch->current_stats = &ch->stats;
+
+	kfree(ch->HW_privdata);
+
+	remove_proc_entry(FILENAME_IO, ch->procdir);
+	remove_proc_entry(FILENAME_IRQ, ch->procdir);
+//	remove_proc_entry(FILENAME_CLOCK, ch->procdir);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static struct comx_hardware locomx_hw = {
+	"locomx",
+	VERSION,
+	LOCOMX_init, 
+	LOCOMX_exit,
+	LOCOMX_dump,
+	NULL
+};
+	
+#ifdef MODULE
+#define comx_hw_locomx_init init_module
+#endif
+
+__initfunc(int comx_hw_locomx_init(void))
+{
+	comx_register_hardware(&locomx_hw);
+	return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	comx_unregister_hardware("locomx");
+	return;
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/comx-hw-mixcom.c linux.14p16/drivers/net/comx-hw-mixcom.c
--- linux.vanilla/drivers/net/comx-hw-mixcom.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/comx-hw-mixcom.c	Thu Dec  9 15:33:37 1999
@@ -0,0 +1,945 @@
+/* 
+ * Hardware driver for the MixCom synchronous serial board 
+ *
+ * Author: Gergely Madarasz <gorgo@itc.hu>
+ *
+ * based on skeleton driver code and a preliminary hscx driver by 
+ * Tivadar Szemethy <tiv@itc.hu>
+ *
+ * Copyright (C) 1998-1999 ITConsult-Pro Co. <info@itc.hu>
+ *
+ * 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.
+ *
+ * Version 0.60 (99/06/11):
+ *		- ported to the kernel, now works as builtin code
+ *
+ * Version 0.61 (99/06/11):
+ *		- recognize the one-channel MixCOM card (id byte = 0x13)
+ *		- printk fixes
+ * 
+ * Version 0.62 (99/07/15):
+ *		- fixes according to the new hw docs 
+ *		- report line status when open
+ *
+ * Version 0.63 (99/09/21):
+ *		- line status report fixes
+ */
+
+#define VERSION "0.63"
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <asm/types.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include "comx.h"
+#include "mixcom.h"
+#include "hscx.h"
+
+MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
+MODULE_DESCRIPTION("Hardware-level driver for the serial port of the MixCom board");
+
+#define MIXCOM_DATA(d) ((struct mixcom_privdata *)(COMX_CHANNEL(d)-> \
+	HW_privdata))
+
+#define MIXCOM_BOARD_BASE(d) (d->base_addr - MIXCOM_SERIAL_OFFSET - \
+	(1 - MIXCOM_DATA(d)->channel) * MIXCOM_CHANNEL_OFFSET)
+
+#define MIXCOM_DEV_BASE(port,channel) (port + MIXCOM_SERIAL_OFFSET + \
+	(1 - channel) * MIXCOM_CHANNEL_OFFSET)
+
+/* Values used to set the IRQ line */
+static unsigned char mixcom_set_irq[]={0xFF, 0xFF, 0xFF, 0x0, 0xFF, 0x2, 0x4, 0x6, 0xFF, 0xFF, 0x8, 0xA, 0xC, 0xFF, 0xE, 0xFF};
+
+static unsigned char* hscx_versions[]={"A1", NULL, "A2", NULL, "A3", "2.1"};
+
+struct mixcom_privdata {
+	u16	clock;
+	char	channel;
+	char	txbusy;
+	struct sk_buff *sending;
+	unsigned tx_ptr;
+	struct sk_buff *recving;
+	unsigned rx_ptr;
+	unsigned char status;
+	char	card_has_status;
+};
+
+static inline void wr_hscx(struct device *dev, int reg, unsigned char val) 
+{
+	outb(val, dev->base_addr + reg);
+}
+
+static inline unsigned char rd_hscx(struct device *dev, int reg)
+{
+	return inb(dev->base_addr + reg);
+}
+
+static inline void hscx_cmd(struct device *dev, int cmd)
+{
+	unsigned long jiffs = jiffies;
+	unsigned char cec;
+	unsigned delay = 0;
+
+	while ((cec = (rd_hscx(dev, HSCX_STAR) & HSCX_CEC) != 0) && 
+	    (jiffs + HZ > jiffies)) {
+		udelay(1);
+		if (++delay > (100000 / HZ)) break;
+	}
+	if (cec) {
+		printk(KERN_WARNING "%s: CEC stuck, probably no clock!\n",dev->name);
+	} else {
+		wr_hscx(dev, HSCX_CMDR, cmd);
+	}
+}
+
+static inline void hscx_fill_fifo(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct mixcom_privdata *hw = ch->HW_privdata;
+	register word to_send = hw->sending->len - hw->tx_ptr;
+
+
+	outsb(dev->base_addr + HSCX_FIFO,
+        	&(hw->sending->data[hw->tx_ptr]), min(to_send, 32));
+	if (to_send <= 32) {
+        	hscx_cmd(dev, HSCX_XTF | HSCX_XME);
+	        kfree_skb(hw->sending);
+        	hw->sending = NULL; 
+        	hw->tx_ptr = 0;
+        } else {
+	        hscx_cmd(dev, HSCX_XTF);
+        	hw->tx_ptr += 32;
+        }
+}
+
+static inline void hscx_empty_fifo(struct device *dev, int cnt)
+{
+	struct comx_channel *ch = dev->priv;
+	struct mixcom_privdata *hw = ch->HW_privdata;
+
+	if (hw->recving == NULL) {
+        	if (!(hw->recving = dev_alloc_skb(HSCX_MTU + 16))) {
+	                ch->stats.rx_dropped++;
+        	        hscx_cmd(dev, HSCX_RHR);
+                } else {
+	                skb_reserve(hw->recving, 16);
+        	        skb_put(hw->recving, HSCX_MTU);
+                }
+	        hw->rx_ptr = 0;
+        }
+	if (cnt > 32 || !cnt || hw->recving == NULL) {
+        	printk(KERN_ERR "hscx_empty_fifo: cnt is %d, hw->recving %p\n",
+		        cnt, (void *)hw->recving);
+	        return;
+        }
+        
+	insb(dev->base_addr + HSCX_FIFO, &(hw->recving->data[hw->rx_ptr]),cnt);
+	hw->rx_ptr += cnt;
+	hscx_cmd(dev, HSCX_RMC);
+}
+
+
+static int MIXCOM_txe(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct mixcom_privdata *hw = ch->HW_privdata;
+
+	return !test_bit(0, &hw->txbusy);
+}
+
+static int mixcom_probe(struct device *dev)
+{
+	unsigned long flags;
+	int id, vstr, ret=0;
+
+	save_flags(flags); cli();
+
+	id=inb_p(MIXCOM_BOARD_BASE(dev) + MIXCOM_ID_OFFSET);
+
+ 	if (id != MIXCOM_ID ) {
+		ret=-ENODEV;
+		printk(KERN_WARNING "%s: no MixCOM board found at 0x%04lx\n",dev->name, dev->base_addr);
+		goto out;
+	}
+
+	vstr=inb_p(dev->base_addr + HSCX_VSTR) & 0x0f;
+	if(vstr>=sizeof(hscx_versions)/sizeof(char*) || 
+	    hscx_versions[vstr]==NULL) {
+		printk(KERN_WARNING "%s: board found but no HSCX chip detected at 0x%4lx (vstr = 0x%1x)\n",dev->name,dev->base_addr,vstr);
+		ret = -ENODEV;
+	} else {
+		printk(KERN_INFO "%s: HSCX chip version %s\n",dev->name,hscx_versions[vstr]);
+		ret = 0;
+	}
+
+out:
+
+	restore_flags(flags);
+	return ret;
+}
+
+#if 0
+static void MIXCOM_set_clock(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct mixcom_privdata *hw = ch->HW_privdata;
+
+	if (hw->clock) {
+		;
+	} else {
+		;
+	}
+}
+#endif
+
+static void mixcom_board_on(struct device *dev)
+{
+	outb_p(MIXCOM_OFF , MIXCOM_BOARD_BASE(dev) + MIXCOM_IT_OFFSET);
+	udelay(1000);
+	outb_p(mixcom_set_irq[dev->irq] | MIXCOM_ON, 
+		MIXCOM_BOARD_BASE(dev) + MIXCOM_IT_OFFSET);
+	udelay(1000);
+}
+
+static void mixcom_board_off(struct device *dev)
+{
+	outb_p(MIXCOM_OFF , MIXCOM_BOARD_BASE(dev) + MIXCOM_IT_OFFSET);
+	udelay(1000);
+}
+
+static void mixcom_off(struct device *dev)
+{
+	wr_hscx(dev, HSCX_CCR1, 0x0);
+}
+
+static void mixcom_on(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+
+	wr_hscx(dev, HSCX_CCR1, HSCX_PU | HSCX_ODS | HSCX_ITF); // power up, push-pull
+	wr_hscx(dev, HSCX_CCR2, HSCX_CIE /* | HSCX_RIE */ );
+	wr_hscx(dev, HSCX_MODE, HSCX_TRANS | HSCX_ADM8 | HSCX_RAC | HSCX_RTS );
+	wr_hscx(dev, HSCX_RLCR, HSCX_RC | 47); // 1504 bytes
+	wr_hscx(dev, HSCX_MASK, HSCX_RSC | HSCX_TIN );
+	hscx_cmd(dev, HSCX_XRES | HSCX_RHR);
+
+	if (ch->HW_set_clock) ch->HW_set_clock(dev);
+
+}
+
+static int MIXCOM_send_packet(struct device *dev, struct sk_buff *skb) 
+{
+	struct comx_channel *ch = dev->priv;
+	struct mixcom_privdata *hw = ch->HW_privdata;
+	unsigned long flags;
+
+	if (ch->debug_flags & DEBUG_HW_TX) {
+		comx_debug_bytes(dev, skb->data, skb->len, "MIXCOM_send_packet");
+	}
+
+	if (!(ch->line_status & LINE_UP)) {
+		return FRAME_DROPPED;
+	}
+
+	if (skb->len > HSCX_MTU) {
+		ch->stats.tx_errors++;	
+		return FRAME_ERROR;
+	}
+
+	save_flags(flags); cli();
+
+	if (test_and_set_bit(0, &hw->txbusy)) {
+		printk(KERN_ERR "%s: transmitter called while busy... dropping frame (length %d)\n", dev->name, skb->len);
+		restore_flags(flags);
+		return FRAME_DROPPED;
+	}
+
+
+	hw->sending = skb;
+	hw->tx_ptr = 0;
+	hw->txbusy = 1;
+//	atomic_inc(&skb->users);	// save it
+	hscx_fill_fifo(dev);
+	restore_flags(flags);
+
+	ch->stats.tx_packets++;
+	ch->stats.tx_bytes += skb->len; 
+
+	if (ch->debug_flags & DEBUG_HW_TX) {
+		comx_debug(dev, "MIXCOM_send_packet was successful\n\n");
+	}
+
+	return FRAME_ACCEPTED;
+}
+
+static inline void mixcom_receive_frame(struct device *dev) 
+{
+	struct comx_channel *ch=dev->priv;
+	struct mixcom_privdata *hw=ch->HW_privdata;
+	register byte rsta;
+	register word length;
+
+	rsta = rd_hscx(dev, HSCX_RSTA) & (HSCX_VFR | HSCX_RDO | 
+		HSCX_CRC | HSCX_RAB);
+	length = ((rd_hscx(dev, HSCX_RBCH) & 0x0f) << 8) | 
+		rd_hscx(dev, HSCX_RBCL);
+
+	if ( length > hw->rx_ptr ) {
+		hscx_empty_fifo(dev, length - hw->rx_ptr);
+	}
+	
+	if (!(rsta & HSCX_VFR)) {
+		ch->stats.rx_length_errors++;
+	}
+	if (rsta & HSCX_RDO) {
+		ch->stats.rx_over_errors++;
+	}
+	if (!(rsta & HSCX_CRC)) {
+		ch->stats.rx_crc_errors++;
+	}
+	if (rsta & HSCX_RAB) {
+		ch->stats.rx_frame_errors++;
+	}
+	ch->stats.rx_packets++; 
+	ch->stats.rx_bytes += length;
+
+	if (rsta == (HSCX_VFR | HSCX_CRC) && hw->recving) {
+		skb_trim(hw->recving, hw->rx_ptr - 1);
+		if (ch->debug_flags & DEBUG_HW_RX) {
+			comx_debug_skb(dev, hw->recving,
+				"MIXCOM_interrupt receiving");
+		}
+		hw->recving->dev = dev;
+		if (ch->LINE_rx) {
+			ch->LINE_rx(dev, hw->recving);
+		}
+	}
+	else if(hw->recving) {
+		kfree_skb(hw->recving);
+	}
+	hw->recving = NULL; 
+	hw->rx_ptr = 0;
+}
+
+
+static inline void mixcom_extended_interrupt(struct device *dev) 
+{
+	struct comx_channel *ch=dev->priv;
+	struct mixcom_privdata *hw=ch->HW_privdata;
+	register byte exir;
+
+	exir = rd_hscx(dev, HSCX_EXIR) & (HSCX_XDU | HSCX_RFO | HSCX_CSC );
+
+	if (exir & HSCX_RFO) {
+		ch->stats.rx_over_errors++;
+		if (hw->rx_ptr) {
+			kfree_skb(hw->recving);
+			hw->recving = NULL; hw->rx_ptr = 0;
+		}
+		printk(KERN_ERR "MIXCOM: rx overrun\n");
+		hscx_cmd(dev, HSCX_RHR);
+	}
+
+	if (exir & HSCX_XDU) { // xmit underrun
+		ch->stats.tx_errors++;
+		ch->stats.tx_aborted_errors++;
+		if (hw->tx_ptr) {
+			kfree_skb(hw->sending);
+			hw->sending = NULL; 
+			hw->tx_ptr = 0;
+		}
+		hscx_cmd(dev, HSCX_XRES);
+		clear_bit(0, &hw->txbusy);
+		if (ch->LINE_tx) {
+			ch->LINE_tx(dev);
+		}
+		printk(KERN_ERR "MIXCOM: tx underrun\n");
+	}
+
+	if (exir & HSCX_CSC) {        
+		ch->stats.tx_carrier_errors++;
+		if ((rd_hscx(dev, HSCX_STAR) & HSCX_CTS) == 0) { // Vonal le
+			if (test_and_clear_bit(0, &ch->lineup_pending)) {
+               			del_timer(&ch->lineup_timer);
+			} else if (ch->line_status & LINE_UP) {
+        		       	ch->line_status &= ~LINE_UP;
+                		if (ch->LINE_status) {
+                      			ch->LINE_status(dev,ch->line_status);
+                      		}
+		      	}
+		}
+		if (!(ch->line_status & LINE_UP) && (rd_hscx(dev, HSCX_STAR) & 
+		    HSCX_CTS)) { // Vonal fol
+			if (!test_and_set_bit(0,&ch->lineup_pending)) {
+				ch->lineup_timer.function = comx_lineup_func;
+	        	        ch->lineup_timer.data = (unsigned long)dev;
+        	        	ch->lineup_timer.expires = jiffies + HZ * 
+        	        		ch->lineup_delay;
+	                	add_timer(&ch->lineup_timer);
+		                hscx_cmd(dev, HSCX_XRES);
+        		        clear_bit(0, &hw->txbusy);
+                		if (hw->sending) {
+					kfree_skb(hw->sending);
+				}
+				hw->sending=NULL;
+				hw->tx_ptr = 0;
+			}
+		}
+	}
+}
+
+
+static void MIXCOM_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+	struct device *dev = (struct device *)dev_id;
+	struct comx_channel *ch, *twin_ch;
+	struct mixcom_privdata *hw, *twin_hw;
+	register unsigned char ista;
+
+	if (dev==NULL) {
+		printk(KERN_ERR "comx_interrupt: irq %d for unknown device\n",irq);
+		return;
+	}
+
+	ch = dev->priv; 
+	hw = ch->HW_privdata;
+
+	save_flags(flags); cli(); 
+
+	while((ista = (rd_hscx(dev, HSCX_ISTA) & (HSCX_RME | HSCX_RPF | 
+	    HSCX_XPR | HSCX_EXB | HSCX_EXA | HSCX_ICA)))) {
+		register byte ista2 = 0;
+
+		if (ista & HSCX_RME) {
+			mixcom_receive_frame(dev);
+		}
+		if (ista & HSCX_RPF) {
+			hscx_empty_fifo(dev, 32);
+		}
+		if (ista & HSCX_XPR) {
+			if (hw->tx_ptr) {
+				hscx_fill_fifo(dev);
+			} else {
+				clear_bit(0, &hw->txbusy);
+               			ch->LINE_tx(dev);
+			}
+		}
+		
+		if (ista & HSCX_EXB) {
+			mixcom_extended_interrupt(dev);
+		}
+		
+		if ((ista & HSCX_EXA) && ch->twin)  {
+			mixcom_extended_interrupt(ch->twin);
+		}
+	
+		if ((ista & HSCX_ICA) && ch->twin &&
+		    (ista2 = rd_hscx(ch->twin, HSCX_ISTA) &
+		    (HSCX_RME | HSCX_RPF | HSCX_XPR ))) {
+			if (ista2 & HSCX_RME) {
+				mixcom_receive_frame(ch->twin);
+			}
+			if (ista2 & HSCX_RPF) {
+				hscx_empty_fifo(ch->twin, 32);
+			}
+			if (ista2 & HSCX_XPR) {
+				twin_ch=ch->twin->priv;
+				twin_hw=twin_ch->HW_privdata;
+				if (twin_hw->tx_ptr) {
+					hscx_fill_fifo(ch->twin);
+				} else {
+					clear_bit(0, &twin_hw->txbusy);
+					ch->LINE_tx(ch->twin);
+				}
+			}
+		}
+	}
+
+	restore_flags(flags);
+	return;
+}
+
+static int MIXCOM_open(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct mixcom_privdata *hw = ch->HW_privdata;
+	struct proc_dir_entry *procfile = ch->procdir->subdir;
+	unsigned long flags; 
+
+	if (!dev->base_addr || !dev->irq) return -ENODEV;
+
+
+	if(hw->channel==1) {
+		if(!TWIN(dev) || !(COMX_CHANNEL(TWIN(dev))->init_status & 
+		    IRQ_ALLOCATED)) {
+			printk(KERN_ERR "%s: channel 0 not yet initialized\n",dev->name);
+			return -EAGAIN;
+		}
+	}
+
+
+	/* Is our hw present at all ? Not checking for channel 0 if it is already 
+	   open */
+	if(hw->channel!=0 || !(ch->init_status & IRQ_ALLOCATED)) {
+		if (check_region(dev->base_addr, MIXCOM_IO_EXTENT)) {
+			return -EAGAIN;
+		}
+		if (mixcom_probe(dev)) {
+			return -ENODEV;
+		}
+	}
+
+	save_flags(flags); cli();
+
+	if(hw->channel==1) {
+		request_region(dev->base_addr, MIXCOM_IO_EXTENT, dev->name);
+	} 
+
+	if(hw->channel==0 && !(ch->init_status & IRQ_ALLOCATED)) {
+		if (request_irq(dev->irq, MIXCOM_interrupt, 0, 
+		    dev->name, (void *)dev)) {
+			printk(KERN_ERR "MIXCOM: unable to obtain irq %d\n", dev->irq);
+			return -EAGAIN;
+		}
+		ch->init_status|=IRQ_ALLOCATED;
+		request_region(dev->base_addr, MIXCOM_IO_EXTENT, dev->name);
+		mixcom_board_on(dev);
+	}
+
+	mixcom_on(dev);
+
+	restore_flags(flags);
+
+	hw->status=inb(MIXCOM_BOARD_BASE(dev) + MIXCOM_STATUS_OFFSET);
+	if(hw->status != 0xff) {
+		printk(KERN_DEBUG "%s: board has status register, good\n", dev->name);
+		hw->card_has_status=1;
+	}
+
+	hw->txbusy = 0;
+	ch->init_status |= HW_OPEN;
+	
+	if (rd_hscx(dev, HSCX_STAR) & HSCX_CTS) {
+		ch->line_status |= LINE_UP;
+	} else {
+		ch->line_status &= ~LINE_UP;
+	}
+
+	ch->LINE_status(dev, ch->line_status);
+
+	for (; procfile ; procfile = procfile->next) {
+		if (strcmp(procfile->name, FILENAME_IO) == 0 ||
+		    strcmp(procfile->name, FILENAME_CHANNEL) == 0 ||
+		    strcmp(procfile->name, FILENAME_CLOCK) == 0 ||
+		    strcmp(procfile->name, FILENAME_IRQ) == 0) {
+			procfile->mode = S_IFREG |  0444;
+		}
+	}
+
+	return 0;
+}
+
+static int MIXCOM_close(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct mixcom_privdata *hw = ch->HW_privdata;
+	struct proc_dir_entry *procfile = ch->procdir->subdir;
+	unsigned long flags;
+
+
+	save_flags(flags); cli();
+
+	mixcom_off(dev);
+
+	/* This is channel 0, twin is not open, we can safely turn off everything */
+	if(hw->channel==0 && (!(TWIN(dev)) || 
+	    !(COMX_CHANNEL(TWIN(dev))->init_status & HW_OPEN))) {
+		mixcom_board_off(dev);
+		free_irq(dev->irq, dev);
+		release_region(dev->base_addr, MIXCOM_IO_EXTENT);
+		ch->init_status &= ~IRQ_ALLOCATED;
+	}
+
+	/* This is channel 1, channel 0 has already been shutdown, we can release
+	   this one too */
+	if(hw->channel==1 && !(COMX_CHANNEL(TWIN(dev))->init_status & HW_OPEN)) {
+		if(COMX_CHANNEL(TWIN(dev))->init_status & IRQ_ALLOCATED) {
+			mixcom_board_off(TWIN(dev));
+			free_irq(TWIN(dev)->irq, TWIN(dev));
+			release_region(TWIN(dev)->base_addr, MIXCOM_IO_EXTENT);
+			COMX_CHANNEL(TWIN(dev))->init_status &= ~IRQ_ALLOCATED;
+		}
+	}
+
+	/* the ioports for channel 1 can be safely released */
+	if(hw->channel==1) {
+		release_region(dev->base_addr, MIXCOM_IO_EXTENT);
+	}
+
+	restore_flags(flags);
+
+	/* If we don't hold any hardware open */
+	if(!(ch->init_status & IRQ_ALLOCATED)) {
+		for (; procfile ; procfile = procfile->next) {
+			if (strcmp(procfile->name, FILENAME_IO) == 0 ||
+			    strcmp(procfile->name, FILENAME_CHANNEL) == 0 ||
+			    strcmp(procfile->name, FILENAME_CLOCK) == 0 ||
+			    strcmp(procfile->name, FILENAME_IRQ) == 0) {
+				procfile->mode = S_IFREG |  0644;
+			}
+		}
+	}
+
+	/* channel 0 was only waiting for us to close channel 1 
+	   close it completely */
+   
+	if(hw->channel==1 && !(COMX_CHANNEL(TWIN(dev))->init_status & HW_OPEN)) {
+		for (procfile=COMX_CHANNEL(TWIN(dev))->procdir->subdir; 
+		    procfile ; procfile = procfile->next) {
+			if (strcmp(procfile->name, FILENAME_IO) == 0 ||
+			    strcmp(procfile->name, FILENAME_CHANNEL) == 0 ||
+			    strcmp(procfile->name, FILENAME_CLOCK) == 0 ||
+			    strcmp(procfile->name, FILENAME_IRQ) == 0) {
+				procfile->mode = S_IFREG |  0644;
+			}
+		}
+	}
+	
+	ch->init_status &= ~HW_OPEN;
+	return 0;
+}
+
+static int MIXCOM_statistics(struct device *dev,char *page)
+{
+	struct comx_channel *ch = dev->priv;
+	// struct mixcom_privdata *hw = ch->HW_privdata;
+	int len = 0;
+
+	if(ch->init_status && IRQ_ALLOCATED) {
+		len += sprintf(page + len, "Mixcom board: hardware open\n");
+	}
+
+	return len;
+}
+
+static int MIXCOM_dump(struct device *dev) {
+	return 0;
+}
+
+static int mixcom_read_proc(char *page, char **start, off_t off, int count,
+	int *eof, void *data)
+{
+	struct proc_dir_entry *file = (struct proc_dir_entry *)data;
+	struct device *dev = file->parent->data;
+	struct comx_channel *ch = dev->priv;
+	struct mixcom_privdata *hw = ch->HW_privdata;
+	int len = 0;
+
+	if (strcmp(file->name, FILENAME_IO) == 0) {
+		len = sprintf(page, "0x%x\n", 
+			(unsigned int)MIXCOM_BOARD_BASE(dev));
+	} else if (strcmp(file->name, FILENAME_IRQ) == 0) {
+		len = sprintf(page, "%d\n", (unsigned int)dev->irq);
+	} else if (strcmp(file->name, FILENAME_CLOCK) == 0) {
+		if (hw->clock) len = sprintf(page, "%d\n", hw->clock);
+			else len = sprintf(page, "external\n");
+	} else if (strcmp(file->name, FILENAME_CHANNEL) == 0) {
+		len = sprintf(page, "%01d\n", hw->channel);
+	} else if (strcmp(file->name, FILENAME_TWIN) == 0) {
+		if (ch->twin) {
+			len = sprintf(page, "%s\n",ch->twin->name);
+		} else {
+			len = sprintf(page, "none\n");
+		}
+	} else {
+		printk(KERN_ERR "mixcom_read_proc: internal error, filename %s\n", file->name);
+		return -EBADF;
+	}
+
+	if (off >= len) {
+		*eof = 1;
+		return 0;
+	}
+	*start = page + off;
+	if (count >= len - off) *eof = 1;
+	return ( min(count, len - off) );
+}
+
+
+static struct device *mixcom_twin_check(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct proc_dir_entry *procfile = ch->procdir->parent->subdir;
+	struct mixcom_privdata *hw = ch->HW_privdata;
+
+	struct device *twin;
+	struct comx_channel *ch_twin;
+	struct mixcom_privdata *hw_twin;
+
+
+	for ( ; procfile ; procfile = procfile->next) {
+		if(!S_ISDIR(procfile->mode)) continue;
+                
+        	twin = procfile->data;
+	        ch_twin = twin->priv;
+        	hw_twin = ch_twin->HW_privdata;
+
+
+	        if (twin != dev && dev->irq && dev->base_addr && 
+        	    dev->irq == twin->irq && 
+        	    ch->hardware == ch_twin->hardware &&
+		    dev->base_addr == twin->base_addr + 
+		    (1-2*hw->channel)*MIXCOM_CHANNEL_OFFSET &&
+		    hw->channel == (1 - hw_twin->channel)) {
+	        	if  (!TWIN(twin) || TWIN(twin)==dev) {
+	        		return twin;
+	        	}
+		}
+        }
+	return NULL;
+}
+
+
+static void setup_twin(struct device* dev) 
+{
+
+	if(TWIN(dev) && TWIN(TWIN(dev))) {
+		TWIN(TWIN(dev))=NULL;
+	}
+	if ((TWIN(dev) = mixcom_twin_check(dev)) != NULL) {
+		if (TWIN(TWIN(dev)) && TWIN(TWIN(dev)) != dev) {
+			TWIN(dev)=NULL;
+		} else {
+			TWIN(TWIN(dev))=dev;
+		}
+	}	
+}
+
+static int mixcom_write_proc(struct file *file, const char *buffer,
+	u_long count, void *data)
+{
+	struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
+	struct device *dev = (struct device *)entry->parent->data;
+	struct comx_channel *ch = dev->priv;
+	struct mixcom_privdata *hw = ch->HW_privdata;
+	char *page;
+	int value;
+
+	if (file->f_dentry->d_inode->i_ino != entry->low_ino) {
+		printk(KERN_ERR "mixcom_write_proc: file <-> data internal error\n");
+		return -EIO;
+	}
+
+	if (!(page = (char *)__get_free_page(GFP_KERNEL))) {
+		return -ENOMEM;
+	}
+
+	copy_from_user(page, buffer, count = min(count, PAGE_SIZE));
+	if (*(page + count - 1) == '\n') {
+		*(page + count - 1) = 0;
+	}
+
+	if (strcmp(entry->name, FILENAME_IO) == 0) {
+		value = simple_strtoul(page, NULL, 0);
+		if (value != 0x180 && value != 0x280 && value != 0x380) {
+			printk(KERN_ERR "MIXCOM: incorrect io address!\n");
+		} else {
+			dev->base_addr = MIXCOM_DEV_BASE(value,hw->channel);
+		}
+	} else if (strcmp(entry->name, FILENAME_IRQ) == 0) {
+		value = simple_strtoul(page, NULL, 0); 
+		if (value < 0 || value > 15 || mixcom_set_irq[value]==0xFF) {
+			printk(KERN_ERR "MIXCOM: incorrect irq value!\n");
+		} else {
+			dev->irq = value;	
+		}
+	} else if (strcmp(entry->name, FILENAME_CLOCK) == 0) {
+		if (strncmp("ext", page, 3) == 0) {
+			hw->clock = 0;
+		} else {
+			int kbps;
+
+			kbps = simple_strtoul(page, NULL, 0);
+			if (!kbps) {
+				hw->clock = 0;
+			} else {
+				hw->clock = kbps;
+			}
+			if (hw->clock < 32 || hw->clock > 2000) {
+				hw->clock = 0;
+				printk(KERN_ERR "MIXCOM: invalid clock rate!\n");
+			}
+		}
+		if (ch->init_status & HW_OPEN && ch->HW_set_clock) {
+			ch->HW_set_clock(dev);
+		}
+	} else if (strcmp(entry->name, FILENAME_CHANNEL) == 0) {
+		value = simple_strtoul(page, NULL, 0);
+        	if (value > 2) {
+                	printk(KERN_ERR "Invalid channel number\n");
+	        } else {
+        		dev->base_addr+=(hw->channel - value) * MIXCOM_CHANNEL_OFFSET;
+	        	hw->channel = value;
+		}	        
+	} else {
+		printk(KERN_ERR "hw_read_proc: internal error, filename %s\n", 
+			entry->name);
+		return -EBADF;
+	}
+
+	setup_twin(dev);
+
+	free_page((unsigned long)page);
+	return count;
+}
+
+static int MIXCOM_init(struct device *dev) {
+	struct comx_channel *ch = dev->priv;
+	struct mixcom_privdata *hw;
+	struct proc_dir_entry *new_file;
+
+	if ((ch->HW_privdata = kmalloc(sizeof(struct mixcom_privdata), 
+	    GFP_KERNEL)) == NULL) {
+	    	return -ENOMEM;
+	}
+
+	memset(hw = ch->HW_privdata, 0, sizeof(struct mixcom_privdata));
+
+	if ((new_file = create_proc_entry(FILENAME_IO, S_IFREG | 0644, 
+	    ch->procdir)) == NULL) {
+		return -EIO;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &mixcom_read_proc;
+	new_file->write_proc = &mixcom_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->nlink = 1;
+
+	if ((new_file = create_proc_entry(FILENAME_IRQ, S_IFREG | 0644, 
+	    ch->procdir)) == NULL) {
+	    	return -EIO;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &mixcom_read_proc;
+	new_file->write_proc = &mixcom_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->nlink = 1;
+
+#if 0
+	if ((new_file = create_proc_entry(FILENAME_CLOCK, S_IFREG | 0644, 
+	    ch->procdir)) == NULL) {
+	    	return -EIO;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &mixcom_read_proc;
+	new_file->write_proc = &mixcom_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->nlink = 1;
+#endif
+
+	if ((new_file = create_proc_entry(FILENAME_CHANNEL, S_IFREG | 0644, 
+	    ch->procdir)) == NULL) {
+	    	return -EIO;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &mixcom_read_proc;
+	new_file->write_proc = &mixcom_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->nlink = 1;
+
+	if ((new_file = create_proc_entry(FILENAME_TWIN, S_IFREG | 0444, 
+	    ch->procdir)) == NULL) {
+	    	return -EIO;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &mixcom_read_proc;
+	new_file->write_proc = &mixcom_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->nlink = 1;
+
+	setup_twin(dev);
+
+	/* Fill in ch_struct hw specific pointers */
+	ch->HW_access_board = NULL;
+	ch->HW_release_board = NULL;
+	ch->HW_txe = MIXCOM_txe;
+	ch->HW_open = MIXCOM_open;
+	ch->HW_close = MIXCOM_close;
+	ch->HW_send_packet = MIXCOM_send_packet;
+	ch->HW_statistics = MIXCOM_statistics;
+	ch->HW_set_clock = NULL;
+
+	dev->base_addr = MIXCOM_DEV_BASE(MIXCOM_DEFAULT_IO,0);
+	dev->irq = MIXCOM_DEFAULT_IRQ;
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int MIXCOM_exit(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct mixcom_privdata *hw = ch->HW_privdata;
+
+	if(hw->channel==0 && TWIN(dev)) {
+		return -EBUSY;
+	}
+
+	if(hw->channel==1 && TWIN(dev)) {
+		TWIN(TWIN(dev))=NULL;
+	}
+
+	kfree(ch->HW_privdata);
+	remove_proc_entry(FILENAME_IO, ch->procdir);
+	remove_proc_entry(FILENAME_IRQ, ch->procdir);
+#if 0
+	remove_proc_entry(FILENAME_CLOCK, ch->procdir);
+#endif
+	remove_proc_entry(FILENAME_CHANNEL, ch->procdir);
+	remove_proc_entry(FILENAME_TWIN, ch->procdir);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static struct comx_hardware mixcomhw = {
+	"mixcom",
+	VERSION,
+	MIXCOM_init, 
+	MIXCOM_exit,
+	MIXCOM_dump,
+	NULL
+};
+	
+/* Module management */
+
+#ifdef MODULE
+#define comx_hw_mixcom_init init_module
+#endif
+
+__initfunc(int comx_hw_mixcom_init(void))
+{
+	return(comx_register_hardware(&mixcomhw));
+}
+
+#ifdef MODULE
+void
+cleanup_module(void)
+{
+	comx_unregister_hardware("mixcom");
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/comx-proto-fr.c linux.14p16/drivers/net/comx-proto-fr.c
--- linux.vanilla/drivers/net/comx-proto-fr.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/comx-proto-fr.c	Thu Dec  9 15:33:37 1999
@@ -0,0 +1,1012 @@
+/*
+ * Frame-relay protocol module for the COMX driver 
+ * for Linux 2.2.X
+ *
+ * Original author: Tivadar Szemethy <tiv@itc.hu>
+ * Maintainer: Gergely Madarasz <gorgo@itc.hu>
+ *
+ * Copyright (C) 1998-1999 ITConsult-Pro Co. <info@itc.hu>
+ *
+ * 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.
+ *
+ * Version 0.70 (99/06/14):
+ *		- cleaned up the source code a bit
+ *		- ported back to kernel, now works as builtin code 
+ *
+ * Version 0.71 (99/06/25):
+ *		- use skb priorities and queues for sending keepalive
+ * 		- use device queues for slave->master data transmit
+ *		- set IFF_RUNNING only line protocol up
+ *		- fixes on slave device flags
+ * 
+ * Version 0.72 (99/07/09):
+ *		- handle slave tbusy with master tbusy (should be fixed)
+ *		- fix the keepalive timer addition/deletion
+ */
+
+#define VERSION "0.72"
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/if_arp.h>
+#include <linux/inetdevice.h>
+#include <linux/pkt_sched.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+#include "comx.h"
+#include "comxhw.h"
+
+MODULE_AUTHOR("Author: Tivadar Szemethy <tiv@itc.hu>");
+MODULE_DESCRIPTION("Frame Relay protocol implementation for the COMX drivers"
+	"for Linux kernel 2.2.X");
+
+#define	FRAD_UI		0x03
+#define	NLPID_IP	0xcc
+#define	NLPID_Q933_LMI	0x08
+#define	NLPID_CISCO_LMI	0x09	
+#define Q933_ENQ	0x75
+#define	Q933_LINESTAT	0x51
+#define	Q933_COUNTERS	0x53
+
+#define	MAXALIVECNT	3		/* No. of failures */
+
+struct fr_data {
+	u16	dlci;
+	struct	device *master;
+	char	keepa_pend;
+	char	keepa_freq;
+	char	keepalivecnt, keeploopcnt;
+	struct	timer_list keepa_timer;
+	u8	local_cnt, remote_cnt;
+};
+
+static struct comx_protocol fr_master_protocol;
+static struct comx_protocol fr_slave_protocol;
+static struct comx_hardware fr_dlci;
+
+static void fr_keepalive_send(struct device *dev) 
+{
+	struct comx_channel *ch = dev->priv;
+	struct fr_data *fr = ch->LINE_privdata;
+	struct sk_buff *skb;
+	u8 *fr_packet;
+	
+	skb=alloc_skb(dev->hard_header_len + 13, GFP_ATOMIC);
+	
+	if(skb==NULL)
+		return;
+               
+        skb_reserve(skb, dev->hard_header_len);
+        
+        fr_packet=(u8*)skb_put(skb, 13);
+                 
+	fr_packet[0] = (fr->dlci & (1024 - 15)) >> 2;
+	fr_packet[1] = (fr->dlci & 15) << 4 | 1;	// EA bit 1
+	fr_packet[2] = FRAD_UI;
+	fr_packet[3] = NLPID_Q933_LMI;
+	fr_packet[4] = 0;
+	fr_packet[5] = Q933_ENQ;
+	fr_packet[6] = Q933_LINESTAT;
+	fr_packet[7] = 0x01;
+	fr_packet[8] = 0x01;
+	fr_packet[9] = Q933_COUNTERS;
+	fr_packet[10] = 0x02;
+	fr_packet[11] = ++fr->local_cnt;
+	fr_packet[12] = fr->remote_cnt;
+
+	skb->dev = dev;
+	skb->priority = TC_PRIO_CONTROL;
+	dev_queue_xmit(skb);
+}
+
+static void fr_keepalive_timerfun(unsigned long d) 
+{
+	struct device *dev = (struct device *)d;
+	struct comx_channel *ch = dev->priv;
+	struct fr_data *fr = ch->LINE_privdata;
+	struct proc_dir_entry *dir = ch->procdir->parent->subdir;
+	struct comx_channel *sch;
+	struct fr_data *sfr;
+	struct device *sdev;
+
+	if (ch->init_status & LINE_OPEN) {
+		if (fr->keepalivecnt == MAXALIVECNT) {
+			comx_status(dev, ch->line_status & ~PROTO_UP);
+			dev->flags &= ~IFF_RUNNING;
+			for (; dir ; dir = dir->next) {
+				if(!S_ISDIR(dir->mode)) {
+				    continue;
+				}
+	
+				if ((sdev = dir->data) && (sch = sdev->priv) && 
+				    (sdev->type == ARPHRD_DLCI) && 
+				    (sfr = sch->LINE_privdata) 
+				    && (sfr->master == dev) && 
+				    (sdev->flags & IFF_UP)) {
+					sdev->flags &= ~IFF_RUNNING;
+					comx_status(sdev, 
+						sch->line_status & ~PROTO_UP);
+				}
+			}
+		}
+		if (fr->keepalivecnt <= MAXALIVECNT) {
+			++fr->keepalivecnt;
+		}
+		fr_keepalive_send(dev);
+	}
+	mod_timer(&fr->keepa_timer, jiffies + HZ * fr->keepa_freq);
+}
+
+static void fr_rx_lmi(struct device *dev, struct sk_buff *skb, 
+	u16 dlci, u8 nlpid) 
+{
+	struct comx_channel *ch = dev->priv;
+	struct fr_data *fr = ch->LINE_privdata;
+	struct proc_dir_entry *dir = ch->procdir->parent->subdir;
+	struct comx_channel *sch;
+	struct fr_data *sfr;
+	struct device *sdev;
+
+	if (dlci != fr->dlci || nlpid != NLPID_Q933_LMI || !fr->keepa_freq) {
+		return;
+	}
+
+	fr->remote_cnt = skb->data[7];
+	if (skb->data[8] == fr->local_cnt) { // keepalive UP!
+		fr->keepalivecnt = 0;
+		if ((ch->line_status & LINE_UP) && 
+		    !(ch->line_status & PROTO_UP)) {
+			comx_status(dev, ch->line_status |= PROTO_UP);
+			dev->flags |= IFF_RUNNING;
+			for (; dir ; dir = dir->next) {
+				if(!S_ISDIR(dir->mode)) {
+				    continue;
+				}
+	
+				if ((sdev = dir->data) && (sch = sdev->priv) && 
+				    (sdev->type == ARPHRD_DLCI) && 
+				    (sfr = sch->LINE_privdata) 
+				    && (sfr->master == dev) && 
+				    (sdev->flags & IFF_UP)) {
+					sdev->flags |= IFF_RUNNING;
+					comx_status(sdev, 
+						sch->line_status | PROTO_UP);
+				}
+			}
+		}
+	}
+}
+
+static void fr_set_keepalive(struct device *dev, int keepa) 
+{
+	struct comx_channel *ch = dev->priv;
+	struct fr_data *fr = ch->LINE_privdata;
+
+	if (!keepa && fr->keepa_freq) { // switch off
+		fr->keepa_freq = 0;
+		if (ch->line_status & LINE_UP) {
+			comx_status(dev, ch->line_status | PROTO_UP);
+			dev->flags |= IFF_RUNNING;
+			del_timer(&fr->keepa_timer);
+		}
+		return;
+	}
+
+	if (keepa) { // bekapcs
+		if(fr->keepa_freq && (ch->line_status & LINE_UP)) {
+			del_timer(&fr->keepa_timer);
+		}
+		fr->keepa_freq = keepa;
+		fr->local_cnt = fr->remote_cnt = 0;
+		fr->keepa_timer.expires = jiffies + HZ;
+		fr->keepa_timer.function = fr_keepalive_timerfun;
+		fr->keepa_timer.data = (unsigned long)dev;
+		ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
+		dev->flags &= ~IFF_RUNNING;
+		comx_status(dev, ch->line_status);
+		if(ch->line_status & LINE_UP) {
+			add_timer(&fr->keepa_timer);
+		}
+	}
+}
+
+static void fr_rx(struct device *dev, struct sk_buff *skb) 
+{
+	struct comx_channel *ch = dev->priv;
+	struct proc_dir_entry *dir = ch->procdir->parent->subdir;
+	struct device *sdev = dev;
+	struct comx_channel *sch;
+	struct fr_data *sfr;
+	u16 dlci;
+	u8 nlpid;
+
+	if(skb->len <= 4 || skb->data[2] != FRAD_UI) {
+		kfree_skb(skb);
+		return;
+	}
+
+	/* Itt majd ki kell talalni, melyik slave kapja a csomagot */
+	dlci = ((skb->data[0] & 0xfc) << 2) | ((skb->data[1] & 0xf0) >> 4);
+	if ((nlpid = skb->data[3]) == 0) { // Optional padding 
+		nlpid = skb->data[4];
+		skb_pull(skb, 1);
+	}
+	skb_pull(skb, 4);	/* DLCI and header throw away */
+
+	if (ch->debug_flags & DEBUG_COMX_DLCI) {
+		comx_debug(dev, "Frame received, DLCI: %d, NLPID: 0x%02x\n", 
+			dlci, nlpid);
+		comx_debug_skb(dev, skb, "Contents");
+	}
+
+	/* Megkeressuk, kihez tartozik */
+	for (; dir ; dir = dir->next) {
+		if(!S_ISDIR(dir->mode)) {
+			continue;
+		}
+		if ((sdev = dir->data) && (sch = sdev->priv) && 
+		    (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&
+		    (sfr->master == dev) && (sfr->dlci == dlci)) {
+			skb->dev = sdev;	
+			if (ch->debug_flags & DEBUG_COMX_DLCI) {
+				comx_debug(dev, "Passing it to %s\n",sdev->name);
+			}
+			if (dev != sdev) {
+				sch->stats.rx_packets++;
+				sch->stats.rx_bytes += skb->len;
+			}
+			break;
+		}
+	}
+	switch(nlpid) {
+		case NLPID_IP:
+			skb->protocol = htons(ETH_P_IP);
+			skb->mac.raw = skb->data;
+			comx_rx(sdev, skb);
+			break;
+		case NLPID_Q933_LMI:
+			fr_rx_lmi(dev, skb, dlci, nlpid);
+		default:
+			kfree_skb(skb);
+			break;
+	}
+}
+
+static int fr_tx(struct device *dev) 
+{
+	struct comx_channel *ch = dev->priv;
+	struct proc_dir_entry *dir = ch->procdir->parent->subdir;
+	struct device *sdev;
+	struct comx_channel *sch;
+	struct fr_data *sfr;
+	int cnt = 1;
+
+	/* Ha minden igaz, 2 helyen fog allni a tbusy: a masternel, 
+	   es annal a slave-nel aki eppen kuldott.
+	   Egy helyen akkor all, ha a master kuldott.
+	   Ez megint jo lesz majd, ha utemezni akarunk */
+	   
+	/* This should be fixed, the slave tbusy should be set when 
+	   the masters queue is full and reset when not */
+
+	for (; dir ; dir = dir->next) {
+		if(!S_ISDIR(dir->mode)) {
+		    continue;
+		}
+		if ((sdev = dir->data) && (sch = sdev->priv) && 
+		    (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&
+		    (sfr->master == dev) && (sdev->tbusy)) {
+			clear_bit(0, &sdev->tbusy);
+//			printk("%s: clearing tbusy\n",sdev->name);
+			cnt++;
+		}
+	}
+
+	clear_bit(0, &dev->tbusy);	// ezt nem talalja meg, mert ez FRAD
+//	printk("%s: clearing tbusy\n", dev->name);
+
+
+	mark_bh(NET_BH);
+	return 0;
+}
+
+static void fr_status(struct device *dev, unsigned short status)
+{
+	struct comx_channel *ch = dev->priv;
+	struct fr_data *fr = ch->LINE_privdata;
+	struct proc_dir_entry *dir = ch->procdir->parent->subdir;
+	struct device *sdev;
+	struct comx_channel *sch;
+	struct fr_data *sfr;
+
+	if (status & LINE_UP) {
+		if (!fr->keepa_freq) {
+			status |= PROTO_UP;
+		}
+	} else {
+		status &= ~(PROTO_UP | PROTO_LOOP);
+	}
+
+	if (dev == fr->master && fr->keepa_freq) {
+		if (status & LINE_UP) {
+			fr->keepa_timer.expires = jiffies + HZ;
+			add_timer(&fr->keepa_timer);
+			fr->keepalivecnt = MAXALIVECNT + 1;
+			fr->keeploopcnt = 0;
+		} else {
+			del_timer(&fr->keepa_timer);
+		}
+	}
+		
+	/* Itt a status valtozast vegig kell vinni az osszes slave-n */
+	for (; dir ; dir = dir->next) {
+		if(!S_ISDIR(dir->mode)) {
+		    continue;
+		}
+	
+		if ((sdev = dir->data) && (sch = sdev->priv) && 
+		    (sdev->type == ARPHRD_FRAD || sdev->type == ARPHRD_DLCI) && 
+		    (sfr = sch->LINE_privdata) && (sfr->master == dev)) {
+			if(status & LINE_UP) {
+				sdev->tbusy = 0; 
+//				printk("%s: clearing tbusy\n",sdev->name);
+			}
+			comx_status(sdev, status);
+			if(status & (PROTO_UP | PROTO_LOOP)) {
+				dev->flags |= IFF_RUNNING;
+			} else {
+				dev->flags &= ~IFF_RUNNING;
+			}
+		}
+	}
+}
+
+static int fr_open(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct fr_data *fr = ch->LINE_privdata;
+	struct proc_dir_entry *comxdir = ch->procdir;
+	struct comx_channel *mch;
+
+	if (!(ch->init_status & HW_OPEN)) {
+		return -ENODEV;
+	}
+
+	if ((ch->hardware == &fr_dlci && ch->protocol != &fr_slave_protocol) ||
+	    (ch->protocol == &fr_slave_protocol && ch->hardware != &fr_dlci)) {
+		printk(KERN_ERR "Trying to open an improperly set FR interface, giving up\n");
+		return -EINVAL;
+	}
+
+	if (!fr->master) {
+		return -ENODEV;
+	}
+	mch = fr->master->priv;
+	if (fr->master != dev && (!(mch->init_status & LINE_OPEN) 
+	   || (mch->protocol != &fr_master_protocol))) {
+		printk(KERN_ERR "Master %s is inactive, or incorrectly set up, "
+			"unable to open %s\n", fr->master->name, dev->name);
+		return -ENODEV;
+	}
+
+	ch->init_status |= LINE_OPEN;
+	ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
+	dev->flags &= ~IFF_RUNNING;
+
+	if (fr->master == dev) {
+		if (fr->keepa_freq) {
+			fr->keepa_timer.function = fr_keepalive_timerfun;
+			fr->keepa_timer.data = (unsigned long)dev;
+			add_timer(&fr->keepa_timer);
+		} else {
+			if (ch->line_status & LINE_UP) {
+				ch->line_status |= PROTO_UP;
+				dev->flags |= IFF_RUNNING;
+			}
+		}
+	} else {
+		ch->line_status = mch->line_status;
+		if(fr->master->flags & IFF_RUNNING) {
+			dev->flags |= IFF_RUNNING;
+		}
+	}
+
+	for (; comxdir ; comxdir = comxdir->next) {
+		if (strcmp(comxdir->name, FILENAME_DLCI) == 0 ||
+		   strcmp(comxdir->name, FILENAME_MASTER) == 0 ||
+		   strcmp(comxdir->name, FILENAME_KEEPALIVE) == 0) {
+			comxdir->mode = S_IFREG | 0444;
+		}
+	}
+//	comx_status(dev, ch->line_status);
+	return 0;
+}
+
+static int fr_close(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct fr_data *fr = ch->LINE_privdata;
+	struct proc_dir_entry *comxdir = ch->procdir;
+
+	if (fr->master == dev) { // Ha master 
+		struct proc_dir_entry *dir = ch->procdir->parent->subdir;
+		struct device *sdev = dev;
+		struct comx_channel *sch;
+		struct fr_data *sfr;
+
+		if (!(ch->init_status & HW_OPEN)) {
+			return -ENODEV;
+		}
+
+		if (fr->keepa_freq) {
+			del_timer(&fr->keepa_timer);
+		}
+		
+		for (; dir ; dir = dir->next) {
+			if(!S_ISDIR(dir->mode)) {
+				continue;
+			}
+			if ((sdev = dir->data) && (sch = sdev->priv) && 
+			    (sdev->type == ARPHRD_DLCI) && 
+			    (sfr = sch->LINE_privdata) &&
+			    (sfr->master == dev) && 
+			    (sch->init_status & LINE_OPEN)) {
+				dev_close(sdev);
+			}
+		}
+	}
+
+	ch->init_status &= ~LINE_OPEN;
+	ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
+	dev->flags &= ~IFF_RUNNING;
+
+	for (; comxdir ; comxdir = comxdir->next) {
+		if (strcmp(comxdir->name, FILENAME_DLCI) == 0 ||
+		    strcmp(comxdir->name, FILENAME_MASTER) == 0 ||
+		    strcmp(comxdir->name, FILENAME_KEEPALIVE) == 0) {
+			comxdir->mode = S_IFREG | 0444;
+		}
+	}
+
+	return 0;
+}
+
+static int fr_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct comx_channel *sch, *mch;
+	struct fr_data *fr = ch->LINE_privdata;
+	struct fr_data *sfr;
+	struct device *sdev;
+	struct proc_dir_entry *dir = ch->procdir->parent->subdir;
+
+	if (!fr->master) {
+		printk(KERN_ERR "BUG: fr_xmit without a master!!! dev: %s\n", dev->name);
+		return 0;
+	}
+
+	mch = fr->master->priv;
+
+	/* Ennek majd a slave utemezeskor lesz igazan jelentosege */
+	if (ch->debug_flags & DEBUG_COMX_DLCI) {
+		comx_debug_skb(dev, skb, "Sending frame");
+	}
+
+	if (dev != fr->master) {
+		struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);
+		newskb->dev=fr->master;
+		dev_queue_xmit(newskb);
+		dev_kfree_skb(skb);
+		ch->stats.tx_packets++;
+		ch->stats.tx_bytes += skb->len;
+	} else {
+		set_bit(0, &dev->tbusy);
+		for (; dir ; dir = dir->next) {
+			if(!S_ISDIR(dir->mode)) {
+			    continue;
+			}
+			if ((sdev = dir->data) && (sch = sdev->priv) && 
+			    (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&
+			    (sfr->master == dev) && (sdev->tbusy)) {
+				set_bit(0, &sdev->tbusy);
+//				printk("%s: clearing tbusy\n",sdev->name);
+			}
+		}
+		 	
+//		printk("%s: set tbusy\n", dev->name);
+		switch(mch->HW_send_packet(dev, skb)) {
+			case FRAME_QUEUED:
+				clear_bit(0, &dev->tbusy);
+//				printk("%s: clear tbusy\n", dev->name);
+				break;
+			case FRAME_ACCEPTED:
+			case FRAME_DROPPED:
+				break;
+			case FRAME_ERROR:
+				printk(KERN_ERR "%s: Transmit frame error (len %d)\n", 
+					dev->name, skb->len);
+				break;
+		}
+	}
+	return 0;
+}
+
+static int fr_header(struct sk_buff *skb, struct device *dev, 
+	unsigned short type, void *daddr, void *saddr, unsigned len) 
+{
+	struct comx_channel *ch = dev->priv;
+	struct fr_data *fr = ch->LINE_privdata;
+
+	skb_push(skb, dev->hard_header_len);	  
+	/* Put in DLCI */
+	skb->data[0] = (fr->dlci & (1024 - 15)) >> 2;
+	skb->data[1] = (fr->dlci & 15) << 4 | 1;	// EA bit 1
+	skb->data[2] = FRAD_UI;
+	skb->data[3] = NLPID_IP;
+
+	return dev->hard_header_len;  
+}
+
+static int fr_statistics(struct device *dev, char *page) 
+{
+	struct comx_channel *ch = dev->priv;
+	struct fr_data *fr = ch->LINE_privdata;
+	int len = 0;
+
+	if (fr->master == dev) {
+		struct proc_dir_entry *dir = ch->procdir->parent->subdir;
+		struct device *sdev;
+		struct comx_channel *sch;
+		struct fr_data *sfr;
+		int slaves = 0;
+
+		len += sprintf(page + len, 
+			"This is a Frame Relay master device\nSlaves: ");
+		for (; dir ; dir = dir->next) {
+			if(!S_ISDIR(dir->mode)) {
+				continue;
+			}
+			if ((sdev = dir->data) && (sch = sdev->priv) && 
+			    (sdev->type == ARPHRD_DLCI) &&
+			    (sfr = sch->LINE_privdata) && 
+			    (sfr->master == dev) && (sdev != dev)) {
+				slaves++;
+				len += sprintf(page + len, "%s ", sdev->name);
+			}
+		}
+		len += sprintf(page + len, "%s\n", slaves ? "" : "(none)");
+		if (fr->keepa_freq) {
+			len += sprintf(page + len, "Line keepalive (value %d) "
+				"status %s [%d]\n", fr->keepa_freq, 
+				ch->line_status & PROTO_LOOP ? "LOOP" :
+				ch->line_status & PROTO_UP ? "UP" : "DOWN", 
+				fr->keepalivecnt);
+		} else {
+			len += sprintf(page + len, "Line keepalive protocol "
+				"is not set\n");
+		}
+	} else {		// if slave
+		len += sprintf(page + len, 
+			"This is a Frame Relay slave device, master: %s\n",
+			fr->master ? fr->master->name : "(not set)");
+	}
+	return len;
+}
+
+static int fr_read_proc(char *page, char **start, off_t off, int count,
+	int *eof, void *data)
+{
+	struct proc_dir_entry *file = (struct proc_dir_entry *)data;
+	struct device *dev = file->parent->data;
+	struct comx_channel *ch = dev->priv;
+	struct fr_data *fr = NULL;
+	int len = 0;
+
+	if (ch) {
+		fr = ch->LINE_privdata;
+	}
+
+	if (strcmp(file->name, FILENAME_DLCI) == 0) {
+		len = sprintf(page, "%04d\n", fr->dlci);
+	} else if (strcmp(file->name, FILENAME_MASTER) == 0) {
+		len = sprintf(page, "%-9s\n", fr->master ? fr->master->name :
+			"(none)");
+	} else if (strcmp(file->name, FILENAME_KEEPALIVE) == 0) {
+		len = fr->keepa_freq ? sprintf(page, "% 3d\n", fr->keepa_freq) 
+			: sprintf(page, "off\n");
+	} else {
+		printk(KERN_ERR "comxfr: internal error, filename %s\n", file->name);
+		return -EBADF;
+	}
+
+	if (off >= len) {
+		*eof = 1;
+		return 0;
+	}
+
+	*start = page + off;
+	if (count >= len - off) *eof = 1;
+	return ( min(count, len - off) );
+}
+
+static int fr_write_proc(struct file *file, const char *buffer, 
+	u_long count, void *data)
+{
+	struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
+	struct device *dev = entry->parent->data;
+	struct comx_channel *ch = dev->priv;
+	struct fr_data *fr = NULL; 
+	char *page;
+
+	if (ch) {
+		fr = ch->LINE_privdata;
+	}
+
+	if (file->f_dentry->d_inode->i_ino != entry->low_ino) {
+		printk(KERN_ERR "comxfr_write_proc: file <-> data internal error\n");
+		return -EIO;
+	}
+
+	if (!(page = (char *)__get_free_page(GFP_KERNEL))) {
+		return -ENOMEM;
+	}
+
+	copy_from_user(page, buffer, count);
+	if (*(page + count - 1) == '\n') {
+		*(page + count - 1) = 0;
+	}
+
+	if (strcmp(entry->name, FILENAME_DLCI) == 0) {
+		u16 dlci_new = simple_strtoul(page, NULL, 10);
+
+		if (dlci_new > 1023) {
+			printk(KERN_ERR "Invalid DLCI value\n");
+		}
+		else fr->dlci = dlci_new;
+	} else if (strcmp(entry->name, FILENAME_MASTER) == 0) {
+		struct device *new_master = dev_get(page);
+
+		if (new_master && new_master->type == ARPHRD_FRAD) {
+			struct comx_channel *sch = new_master->priv;
+			struct fr_data *sfr = sch->LINE_privdata;
+
+			if (sfr && sfr->master == new_master) {
+				fr->master = new_master;
+				/* Megorokli a master statuszat */
+				ch->line_status = sch->line_status;
+			}
+		}
+	} else if (strcmp(entry->name, FILENAME_KEEPALIVE) == 0) {
+		int keepa_new = -1;
+
+		if (strcmp(page, KEEPALIVE_OFF) == 0) {
+			keepa_new = 0;
+		} else {
+			keepa_new = simple_strtoul(page, NULL, 10);
+		}
+
+		if (keepa_new < 0 || keepa_new > 100) {
+			printk(KERN_ERR "invalid keepalive\n");
+		} else {
+			if (fr->keepa_freq && keepa_new != fr->keepa_freq) {
+				fr_set_keepalive(dev, 0);
+			}
+			if (keepa_new) {
+				fr_set_keepalive(dev, keepa_new);
+			}
+		}
+	} else {
+		printk(KERN_ERR "comxfr_write_proc: internal error, filename %s\n", 
+			entry->name);
+		return -EBADF;
+	}
+
+	free_page((unsigned long)page);
+	return count;
+}
+
+static int fr_exit(struct device *dev) 
+{
+	struct comx_channel *ch = dev->priv;
+	struct fr_data *fr = ch->LINE_privdata;
+	struct device *sdev = dev;
+	struct comx_channel *sch;
+	struct fr_data *sfr;
+	struct proc_dir_entry *dir = ch->procdir->parent->subdir;
+
+	/* Ha lezarunk egy master-t, le kell kattintani a slave-eket is */
+	if (fr->master && fr->master == dev) {
+		for (; dir ; dir = dir->next) {
+			if(!S_ISDIR(dir->mode)) {
+				continue;
+			}
+			if ((sdev = dir->data) && (sch = sdev->priv) && 
+			    (sdev->type == ARPHRD_DLCI) && 
+			    (sfr = sch->LINE_privdata) && (sfr->master == dev)) {
+				dev_close(sdev);
+				sfr->master = NULL;
+			}
+		}
+	}
+	dev->flags		= 0;
+	dev->type		= 0;
+	dev->mtu		= 0;
+	dev->hard_header_len    = 0;
+
+	ch->LINE_rx	= NULL;
+	ch->LINE_tx	= NULL;
+	ch->LINE_status = NULL;
+	ch->LINE_open	= NULL;
+	ch->LINE_close	= NULL;
+	ch->LINE_xmit	= NULL;
+	ch->LINE_header	= NULL;
+	ch->LINE_rebuild_header	= NULL;
+	ch->LINE_statistics = NULL;
+
+	ch->LINE_status = 0;
+
+	if (fr->master != dev) { // if not master, remove dlci
+		remove_proc_entry(FILENAME_DLCI, ch->procdir);
+		remove_proc_entry(FILENAME_MASTER, ch->procdir);
+	} else {
+		if (fr->keepa_freq) {
+			fr_set_keepalive(dev, 0);
+		}
+		remove_proc_entry(FILENAME_KEEPALIVE, ch->procdir);
+		remove_proc_entry(FILENAME_DLCI, ch->procdir);
+	}
+
+	kfree(fr);
+	ch->LINE_privdata = NULL;
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int fr_master_init(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct fr_data *fr;
+	struct proc_dir_entry *new_file;
+
+	if ((fr = ch->LINE_privdata = kmalloc(sizeof(struct fr_data), 
+	    GFP_KERNEL)) == NULL) {
+		return -ENOMEM;
+	}
+	memset(fr, 0, sizeof(struct fr_data));
+	fr->master = dev;	// this means master
+	fr->dlci = 0;		// let's say default
+
+	dev->flags	= IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
+	dev->type	= ARPHRD_FRAD;
+	dev->mtu	= 1500;
+	dev->hard_header_len    = 4;		
+	dev->addr_len	= 0;
+
+	ch->LINE_rx	= fr_rx;
+	ch->LINE_tx	= fr_tx;
+	ch->LINE_status = fr_status;
+	ch->LINE_open	= fr_open;
+	ch->LINE_close	= fr_close;
+	ch->LINE_xmit	= fr_xmit;
+	ch->LINE_header	= fr_header;
+	ch->LINE_rebuild_header	= NULL;
+	ch->LINE_statistics = fr_statistics;
+
+	if ((new_file = create_proc_entry(FILENAME_DLCI, S_IFREG | 0644, 
+	    ch->procdir)) == NULL) {
+		return -ENOMEM;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &fr_read_proc;
+	new_file->write_proc = &fr_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->size = 5;
+	new_file->nlink = 1;
+
+	if ((new_file = create_proc_entry(FILENAME_KEEPALIVE, S_IFREG | 0644, 
+	    ch->procdir)) == NULL) {
+		return -ENOMEM;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &fr_read_proc;
+	new_file->write_proc = &fr_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->size = 4;
+	new_file->nlink = 1;
+
+	fr_set_keepalive(dev, 0);
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int fr_slave_init(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct fr_data *fr;
+	struct proc_dir_entry *new_file;
+
+	if ((fr = ch->LINE_privdata = kmalloc(sizeof(struct fr_data), 
+	    GFP_KERNEL)) == NULL) {
+		return -ENOMEM;
+	}
+	memset(fr, 0, sizeof(struct fr_data));
+
+	dev->flags	= IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
+	dev->type	= ARPHRD_DLCI;
+	dev->mtu	= 1500;
+	dev->hard_header_len    = 4;		
+	dev->addr_len	= 0;
+
+	ch->LINE_rx	= fr_rx;
+	ch->LINE_tx	= fr_tx;
+	ch->LINE_status = fr_status;
+	ch->LINE_open	= fr_open;
+	ch->LINE_close	= fr_close;
+	ch->LINE_xmit	= fr_xmit;
+	ch->LINE_header	= fr_header;
+	ch->LINE_rebuild_header	= NULL;
+	ch->LINE_statistics = fr_statistics;
+
+	if ((new_file = create_proc_entry(FILENAME_DLCI, S_IFREG | 0644, 
+	    ch->procdir)) == NULL) {
+		return -ENOMEM;
+	}
+	
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &fr_read_proc;
+	new_file->write_proc = &fr_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->size = 5;
+	new_file->nlink = 1;
+
+	if ((new_file = create_proc_entry(FILENAME_MASTER, S_IFREG | 0644, 
+	    ch->procdir)) == NULL) {
+		return -EIO;
+	}
+	new_file->data = (void *)new_file;
+	new_file->read_proc = &fr_read_proc;
+	new_file->write_proc = &fr_write_proc;
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->size = 10;
+	new_file->nlink = 1;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int dlci_open(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+
+	ch->init_status |= HW_OPEN;
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int dlci_close(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+
+	ch->init_status &= ~HW_OPEN;
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int dlci_txe(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct fr_data *fr = ch->LINE_privdata;
+
+	if (!fr->master) {
+		return 0;
+	}
+
+	ch = fr->master->priv;
+	fr = ch->LINE_privdata;
+	return ch->HW_txe(fr->master);
+}
+
+static int dlci_statistics(struct device *dev, char *page) 
+{
+	return 0;
+}
+
+static int dlci_init(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+
+	ch->HW_open = dlci_open;
+	ch->HW_close = dlci_close;
+	ch->HW_txe = dlci_txe;
+	ch->HW_statistics = dlci_statistics;
+
+	/* Nincs egyeb hw info, mert ugyis a fr->master-bol fog minden kiderulni */
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int dlci_exit(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+
+	ch->HW_open = NULL;
+	ch->HW_close = NULL;
+	ch->HW_txe = NULL;
+	ch->HW_statistics = NULL;
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int dlci_dump(struct device *dev)
+{
+	printk(KERN_INFO "dlci_dump %s, HOGY MI ???\n", dev->name);
+	return -1;
+}
+
+static struct comx_protocol fr_master_protocol = {
+	"frad", 
+	VERSION,
+	ARPHRD_FRAD, 
+	fr_master_init, 
+	fr_exit, 
+	NULL 
+};
+
+static struct comx_protocol fr_slave_protocol = {
+	"ietf-ip", 
+	VERSION,
+	ARPHRD_DLCI, 
+	fr_slave_init, 
+	fr_exit, 
+	NULL 
+};
+
+static struct comx_hardware fr_dlci = { 
+	"dlci", 
+	VERSION,
+	dlci_init, 
+	dlci_exit, 
+	dlci_dump, 
+	NULL 
+};
+
+#ifdef MODULE
+#define comx_proto_fr_init init_module
+#endif
+
+__initfunc(int comx_proto_fr_init(void))
+{
+	int ret; 
+
+	if ((ret = comx_register_hardware(&fr_dlci))) {
+		return ret;
+	}
+	if ((ret = comx_register_protocol(&fr_master_protocol))) {
+		return ret;
+	}
+	return comx_register_protocol(&fr_slave_protocol);
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	comx_unregister_hardware(fr_dlci.name);
+	comx_unregister_protocol(fr_master_protocol.name);
+	comx_unregister_protocol(fr_slave_protocol.name);
+}
+#endif /* MODULE */
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/comx-proto-lapb.c linux.14p16/drivers/net/comx-proto-lapb.c
--- linux.vanilla/drivers/net/comx-proto-lapb.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/comx-proto-lapb.c	Thu Dec  9 15:33:37 1999
@@ -0,0 +1,553 @@
+/*
+ * LAPB protocol module for the COMX driver 
+ * for Linux kernel 2.2.X
+ *
+ * Original author: Tivadar Szemethy <tiv@itc.hu>
+ * Maintainer: Gergely Madarasz <gorgo@itc.hu>
+ *
+ * Copyright (C) 1997-1999 (C) ITConsult-Pro Co. <info@itc.hu>
+ *
+ * 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.
+ *
+ * Version 0.80 (99/06/14):
+ *		- cleaned up the source code a bit
+ *		- ported back to kernel, now works as non-module
+ * 
+ */
+
+#define VERSION "0.80"
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/if_arp.h>
+#include <linux/inetdevice.h>
+#include <asm/uaccess.h>
+#include <linux/lapb.h>
+#include <linux/init.h>
+
+#include	"comx.h"
+#include	"comxhw.h"
+
+static struct proc_dir_entry *create_comxlapb_proc_entry(char *name, int mode,
+	int size, struct proc_dir_entry *dir);
+
+static void comxlapb_rx(struct device *dev, struct sk_buff *skb) 
+{
+	if (!dev || !dev->priv) {
+		dev_kfree_skb(skb);
+	} else {
+		lapb_data_received(dev->priv, skb);
+	}
+}
+
+static int comxlapb_tx(struct device *dev) 
+{
+	clear_bit(0, &dev->tbusy);
+	mark_bh(NET_BH);
+	return 0;
+}
+
+static int comxlapb_header(struct sk_buff *skb, struct device *dev, 
+	unsigned short type, void *daddr, void *saddr, unsigned len) 
+{
+	return dev->hard_header_len;  
+}
+
+static void comxlapb_status(struct device *dev, unsigned short status)
+{
+	struct comx_channel *ch;
+
+	if (!dev || !(ch = dev->priv)) {
+		return;
+	}
+	if (status & LINE_UP) {
+		clear_bit(0, &dev->tbusy);
+	}
+	comx_status(dev, status);
+}
+
+static int comxlapb_open(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	int err = 0;
+
+	if (!(ch->init_status & HW_OPEN)) {
+		return -ENODEV;
+	}
+
+	err = lapb_connect_request(ch);
+
+	if (ch->debug_flags & DEBUG_COMX_LAPB) {
+		comx_debug(dev, "%s: lapb opened, error code: %d\n", 
+			dev->name, err);
+	}
+
+	if (!err) {
+		ch->init_status |= LINE_OPEN;
+		MOD_INC_USE_COUNT;
+	}
+	return err;
+}
+
+static int comxlapb_close(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+
+	if (!(ch->init_status & HW_OPEN)) {
+		return -ENODEV;
+	}
+
+	if (ch->debug_flags & DEBUG_COMX_LAPB) {
+		comx_debug(dev, "%s: lapb closed\n", dev->name);
+	}
+
+	lapb_disconnect_request(ch);
+
+	ch->init_status &= ~LINE_OPEN;
+	ch->line_status &= ~PROTO_UP;
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int comxlapb_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct sk_buff *skb2;
+
+	if (!dev || !(ch = dev->priv) || !(dev->flags & (IFF_UP | IFF_RUNNING))) {
+		return -ENODEV;
+	}
+
+	if (dev->type == ARPHRD_X25) { // first byte tells what to do 
+		switch(skb->data[0]) {
+			case 0x00:	
+				break;	// transmit
+			case 0x01:	
+				lapb_connect_request(ch);
+				kfree_skb(skb);
+				return 0;
+			case 0x02:	
+				lapb_disconnect_request(ch);
+			default:
+				kfree_skb(skb);
+				return 0;
+		}
+		skb_pull(skb,1);
+	}
+
+	if (test_and_set_bit(0, &dev->tbusy)) {
+		ch->stats.tx_errors++;
+		return 1;
+	}
+
+	if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
+		lapb_data_request(ch, skb2);
+	}
+
+	return FRAME_ACCEPTED;
+}
+
+static int comxlapb_statistics(struct device *dev, char *page) 
+{
+	struct lapb_parms_struct parms;
+	int len = 0;
+
+	len += sprintf(page + len, "Line status: ");
+	if (lapb_getparms(dev->priv, &parms) != LAPB_OK) {
+		len += sprintf(page + len, "not initialized\n");
+		return len;
+	}
+	len += sprintf(page + len, "%s (%s), T1: %d/%d, T2: %d/%d, N2: %d/%d, "
+		"window: %d\n", parms.mode & LAPB_DCE ? "DCE" : "DTE", 
+		parms.mode & LAPB_EXTENDED ? "EXTENDED" : "STANDARD",
+		parms.t1timer, parms.t1, parms.t2timer, parms.t2, 
+		parms.n2count, parms.n2, parms.window);
+
+	return len;
+}
+
+static int comxlapb_read_proc(char *page, char **start, off_t off, int count,
+	int *eof, void *data)
+{
+	struct proc_dir_entry *file = (struct proc_dir_entry *)data;
+	struct device *dev = file->parent->data;
+	struct lapb_parms_struct parms;
+	int len = 0;
+
+	if (lapb_getparms(dev->priv, &parms)) {
+		return -ENODEV;
+	}
+
+	if (strcmp(file->name, FILENAME_T1) == 0) {
+		len += sprintf(page + len, "%02u / %02u\n", 
+			parms.t1timer, parms.t1);
+	} else if (strcmp(file->name, FILENAME_T2) == 0) {
+		len += sprintf(page + len, "%02u / %02u\n", 
+			parms.t2timer, parms.t2);
+	} else if (strcmp(file->name, FILENAME_N2) == 0) {
+		len += sprintf(page + len, "%02u / %02u\n", 
+			parms.n2count, parms.n2);
+	} else if (strcmp(file->name, FILENAME_WINDOW) == 0) {
+		len += sprintf(page + len, "%u\n", parms.window);
+	} else if (strcmp(file->name, FILENAME_MODE) == 0) {
+		len += sprintf(page + len, "%s, %s\n", 
+			parms.mode & LAPB_DCE ? "DCE" : "DTE",
+			parms.mode & LAPB_EXTENDED ? "EXTENDED" : "STANDARD");
+	} else {
+		printk(KERN_ERR "comxlapb: internal error, filename %s\n", file->name);
+		return -EBADF;
+	}
+
+	if (off >= len) {
+		*eof = 1;
+		return 0;
+	}
+
+	*start = page + off;
+	if (count >= len - off) {
+		*eof = 1;
+	}
+	return ( min(count, len - off) );
+}
+
+static int comxlapb_write_proc(struct file *file, const char *buffer, 
+	u_long count, void *data)
+{
+	struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
+	struct device *dev = entry->parent->data;
+	struct lapb_parms_struct parms;
+	unsigned long parm;
+	char *page;
+
+	if (file->f_dentry->d_inode->i_ino != entry->low_ino) {
+		printk(KERN_ERR "comxlapb_write_proc: file <-> data internal error\n");
+		return -EIO;
+	}
+
+	if (lapb_getparms(dev->priv, &parms)) {
+		return -ENODEV;
+	}
+
+	if (!(page = (char *)__get_free_page(GFP_KERNEL))) {
+		return -ENOMEM;
+	}
+
+	copy_from_user(page, buffer, count);
+	if (*(page + count - 1) == '\n') {
+		*(page + count - 1) = 0;
+	}
+
+	if (strcmp(entry->name, FILENAME_T1) == 0) {
+		parm=simple_strtoul(page,NULL,10);
+		if (parm > 0 && parm < 100) {
+			parms.t1=parm;
+			lapb_setparms(dev->priv, &parms);
+		}
+	} else if (strcmp(entry->name, FILENAME_T2) == 0) {
+		parm=simple_strtoul(page, NULL, 10);
+		if (parm > 0 && parm < 100) {
+			parms.t2=parm;
+			lapb_setparms(dev->priv, &parms);
+		}
+	} else if (strcmp(entry->name, FILENAME_N2) == 0) {
+		parm=simple_strtoul(page, NULL, 10);
+		if (parm > 0 && parm < 100) {
+			parms.n2=parm;
+			lapb_setparms(dev->priv, &parms);
+		}
+	} else if (strcmp(entry->name, FILENAME_WINDOW) == 0) {
+		parms.window = simple_strtoul(page, NULL, 10);
+		lapb_setparms(dev->priv, &parms);
+	} else if (strcmp(entry->name, FILENAME_MODE) == 0) {
+		if (comx_strcasecmp(page, "dte") == 0) {
+			parms.mode &= ~(LAPB_DCE | LAPB_DTE); 
+			parms.mode |= LAPB_DTE;
+		} else if (comx_strcasecmp(page, "dce") == 0) {
+			parms.mode &= ~(LAPB_DTE | LAPB_DCE); 
+			parms.mode |= LAPB_DCE;
+		} else if (comx_strcasecmp(page, "std") == 0 || 
+		    comx_strcasecmp(page, "standard") == 0) {
+			parms.mode &= ~LAPB_EXTENDED; 
+			parms.mode |= LAPB_STANDARD;
+		} else if (comx_strcasecmp(page, "ext") == 0 || 
+		    comx_strcasecmp(page, "extended") == 0) {
+			parms.mode &= ~LAPB_STANDARD; 
+			parms.mode |= LAPB_EXTENDED;
+		}
+		lapb_setparms(dev->priv, &parms);
+	} else {
+		printk(KERN_ERR "comxlapb_write_proc: internal error, filename %s\n", 
+			entry->name);
+		return -EBADF;
+	}
+
+	free_page((unsigned long)page);
+	return count;
+}
+
+static void comxlapb_connected(void *token, int reason)
+{
+	struct comx_channel *ch = token; 
+	struct proc_dir_entry *comxdir = ch->procdir->subdir;
+
+	if (ch->debug_flags & DEBUG_COMX_LAPB) {
+		comx_debug(ch->dev, "%s: lapb connected, reason: %d\n", 
+			ch->dev->name, reason);
+	}
+
+	if (ch->dev->type == ARPHRD_X25) {
+		unsigned char *p;
+		struct sk_buff *skb;
+
+		if ((skb = dev_alloc_skb(1)) == NULL) {
+			printk(KERN_ERR "comxlapb: out of memory!\n");
+			return;
+		}
+		p = skb_put(skb,1);
+		*p = 0x01;		// link established
+		skb->dev = ch->dev;
+		skb->protocol = htons(ETH_P_X25);
+		skb->mac.raw = skb->data;
+		skb->pkt_type = PACKET_HOST;
+
+		netif_rx(skb);
+	}
+
+	for (; comxdir; comxdir = comxdir->next) {
+		if (strcmp(comxdir->name, FILENAME_MODE) == 0) {
+			comxdir->mode = S_IFREG | 0444;
+		}
+	}
+
+
+	ch->line_status |= PROTO_UP;
+	comx_status(ch->dev, ch->line_status);
+}
+
+static void comxlapb_disconnected(void *token, int reason)
+{
+	struct comx_channel *ch = token; 
+	struct proc_dir_entry *comxdir = ch->procdir->subdir;
+
+	if (ch->debug_flags & DEBUG_COMX_LAPB) {
+		comx_debug(ch->dev, "%s: lapb disconnected, reason: %d\n", 
+			ch->dev->name, reason);
+	}
+
+	if (ch->dev->type == ARPHRD_X25) {
+		unsigned char *p;
+		struct sk_buff *skb;
+
+		if ((skb = dev_alloc_skb(1)) == NULL) {
+			printk(KERN_ERR "comxlapb: out of memory!\n");
+			return;
+		}
+		p = skb_put(skb,1);
+		*p = 0x02;		// link disconnected
+		skb->dev = ch->dev;
+		skb->protocol = htons(ETH_P_X25);
+		skb->mac.raw = skb->data;
+		skb->pkt_type = PACKET_HOST;
+
+		netif_rx(skb);
+	}
+
+	for (; comxdir; comxdir = comxdir->next) {
+		if (strcmp(comxdir->name, FILENAME_MODE) == 0) {
+			comxdir->mode = S_IFREG | 0644;
+		}
+	}
+	
+	ch->line_status &= ~PROTO_UP;
+	comx_status(ch->dev, ch->line_status);
+}
+
+static void comxlapb_data_indication(void *token, struct sk_buff *skb)
+{
+	struct comx_channel *ch = token; 
+
+	if (ch->dev->type == ARPHRD_X25) {
+		skb_push(skb, 1);
+		skb->data[0] = 0;	// indicate data for X25
+		skb->protocol = htons(ETH_P_X25);
+	} else {
+		skb->protocol = htons(ETH_P_IP);
+	}
+
+	skb->dev = ch->dev;
+	skb->mac.raw = skb->data;
+	comx_rx(ch->dev, skb);
+}
+
+static void comxlapb_data_transmit(void *token, struct sk_buff *skb)
+{
+	struct comx_channel *ch = token; 
+
+	if (ch->HW_send_packet) {
+		ch->HW_send_packet(ch->dev, skb);
+	}
+}
+
+static int comxlapb_exit(struct device *dev) 
+{
+	struct comx_channel *ch = dev->priv;
+
+	dev->flags		= 0;
+	dev->type		= 0;
+	dev->mtu		= 0;
+	dev->hard_header_len    = 0;
+
+	ch->LINE_rx	= NULL;
+	ch->LINE_tx	= NULL;
+	ch->LINE_status = NULL;
+	ch->LINE_open	= NULL;
+	ch->LINE_close	= NULL;
+	ch->LINE_xmit	= NULL;
+	ch->LINE_header	= NULL;
+	ch->LINE_statistics = NULL;
+
+	if (ch->debug_flags & DEBUG_COMX_LAPB) {
+		comx_debug(dev, "%s: unregistering lapb\n", dev->name);
+	}
+	lapb_unregister(dev->priv);
+
+	remove_proc_entry(FILENAME_T1, ch->procdir);
+	remove_proc_entry(FILENAME_T2, ch->procdir);
+	remove_proc_entry(FILENAME_N2, ch->procdir);
+	remove_proc_entry(FILENAME_MODE, ch->procdir);
+	remove_proc_entry(FILENAME_WINDOW, ch->procdir);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int comxlapb_init(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct lapb_register_struct lapbreg;
+
+	dev->mtu		= 1500;
+	dev->hard_header_len    = 4;
+	dev->addr_len		= 0;
+
+	ch->LINE_rx	= comxlapb_rx;
+	ch->LINE_tx	= comxlapb_tx;
+	ch->LINE_status = comxlapb_status;
+	ch->LINE_open	= comxlapb_open;
+	ch->LINE_close	= comxlapb_close;
+	ch->LINE_xmit	= comxlapb_xmit;
+	ch->LINE_header	= comxlapb_header;
+	ch->LINE_statistics = comxlapb_statistics;
+
+	lapbreg.connect_confirmation = comxlapb_connected;
+	lapbreg.connect_indication = comxlapb_connected;
+	lapbreg.disconnect_confirmation = comxlapb_disconnected;
+	lapbreg.disconnect_indication = comxlapb_disconnected;
+	lapbreg.data_indication = comxlapb_data_indication;
+	lapbreg.data_transmit = comxlapb_data_transmit;
+	if (lapb_register(dev->priv, &lapbreg)) {
+		return -ENOMEM;
+	}
+	if (ch->debug_flags & DEBUG_COMX_LAPB) {
+		comx_debug(dev, "%s: lapb registered\n", dev->name);
+	}
+
+	if (!create_comxlapb_proc_entry(FILENAME_T1, 0644, 8, ch->procdir)) {
+		return -ENOMEM;
+	}
+	if (!create_comxlapb_proc_entry(FILENAME_T2, 0644, 8, ch->procdir)) {
+		return -ENOMEM;
+	}
+	if (!create_comxlapb_proc_entry(FILENAME_N2, 0644, 8, ch->procdir)) {
+		return -ENOMEM;
+	}
+	if (!create_comxlapb_proc_entry(FILENAME_MODE, 0644, 14, ch->procdir)) {
+		return -ENOMEM;
+	}
+	if (!create_comxlapb_proc_entry(FILENAME_WINDOW, 0644, 0, ch->procdir)) {
+		return -ENOMEM;
+	}
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int comxlapb_init_lapb(struct device *dev) 
+{
+	dev->flags	= IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
+	dev->type	= ARPHRD_LAPB;
+
+	return(comxlapb_init(dev));
+}
+
+static int comxlapb_init_x25(struct device *dev)
+{
+	dev->flags		= IFF_NOARP;
+	dev->type		= ARPHRD_X25;
+
+	return(comxlapb_init(dev));
+}
+
+static struct proc_dir_entry *create_comxlapb_proc_entry(char *name, int mode,
+	int size, struct proc_dir_entry *dir)
+{
+	struct proc_dir_entry *new_file;
+
+	if ((new_file = create_proc_entry(name, S_IFREG | mode, dir)) != NULL) {
+		new_file->data = (void *)new_file;
+		new_file->read_proc = &comxlapb_read_proc;
+		new_file->write_proc = &comxlapb_write_proc;
+		new_file->ops = &comx_normal_inode_ops;
+		new_file->size = size;
+		new_file->nlink = 1;
+	}
+	return(new_file);
+}
+
+static struct comx_protocol comxlapb_protocol = {
+	"lapb", 
+	VERSION,
+	ARPHRD_LAPB, 
+	comxlapb_init_lapb, 
+	comxlapb_exit, 
+	NULL 
+};
+
+static struct comx_protocol comx25_protocol = {
+	"x25", 
+	VERSION,
+	ARPHRD_X25, 
+	comxlapb_init_x25, 
+	comxlapb_exit, 
+	NULL 
+};
+
+#ifdef MODULE
+#define comx_proto_lapb_init init_module
+#endif
+
+__initfunc(int comx_proto_lapb_init(void))
+{
+	int ret;
+
+	if ((ret = comx_register_protocol(&comxlapb_protocol)) != 0) {
+		return ret;
+	}
+	return comx_register_protocol(&comx25_protocol);
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	comx_unregister_protocol(comxlapb_protocol.name);
+	comx_unregister_protocol(comx25_protocol.name);
+}
+#endif /* MODULE */
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/comx-proto-ppp.c linux.14p16/drivers/net/comx-proto-ppp.c
--- linux.vanilla/drivers/net/comx-proto-ppp.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/comx-proto-ppp.c	Thu Dec  9 15:33:37 1999
@@ -0,0 +1,265 @@
+/*
+ * Synchronous PPP / Cisco-HDLC driver for the COMX boards
+ *
+ * Author: Gergely Madarasz <gorgo@itc.hu>
+ *
+ * based on skeleton code by Tivadar Szemethy <tiv@itc.hu>
+ *
+ * Copyright (C) 1999 ITConsult-Pro Co. <info@itc.hu>
+ *
+ * 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.
+ *
+ *
+ * Version 0.10 (99/06/10):
+ *		- written the first code :)
+ *
+ * Version 0.20 (99/06/16):
+ *		- added hdlc protocol 
+ *		- protocol up is IFF_RUNNING
+ *
+ * Version 0.21 (99/07/15):
+ *		- some small fixes with the line status
+ *
+ * Version 0.22 (99/08/05):
+ *		- don't test IFF_RUNNING but the pp_link_state of the sppp
+ *
+ */
+
+#define VERSION "0.22"
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/if_arp.h>
+#include <linux/inetdevice.h>
+#include <asm/uaccess.h>
+#include <linux/init.h>
+
+#include	"syncppp.h"
+#include	"comx.h"
+
+MODULE_AUTHOR("Author: Gergely Madarasz <gorgo@itc.hu>");
+MODULE_DESCRIPTION("Cisco-HDLC / Synchronous PPP driver for the COMX sync serial boards");
+
+static struct comx_protocol syncppp_protocol;
+static struct comx_protocol hdlc_protocol;
+
+struct syncppp_data {
+	struct timer_list status_timer;
+};
+
+static void syncppp_status_timerfun(unsigned long d) {
+	struct device *dev=(struct device *)d;
+	struct comx_channel *ch=dev->priv;
+	struct syncppp_data *spch=ch->LINE_privdata;
+	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
+        
+	if(!(ch->line_status & PROTO_UP) && 
+	    (sp->pp_link_state==SPPP_LINK_UP)) {
+    		comx_status(dev, ch->line_status | PROTO_UP);
+	}
+	if((ch->line_status & PROTO_UP) &&
+	    (sp->pp_link_state==SPPP_LINK_DOWN)) {
+	    	comx_status(dev, ch->line_status & ~PROTO_UP);
+	}
+	mod_timer(&spch->status_timer,jiffies + HZ*3);
+}
+
+static int syncppp_tx(struct device *dev) 
+{
+	clear_bit(0, &dev->tbusy);
+	mark_bh(NET_BH);
+	return 0;
+}
+
+static void syncppp_status(struct device *dev, unsigned short status)
+{
+	status &= ~(PROTO_UP | PROTO_LOOP);
+	if(status & LINE_UP) {
+		dev->tbusy = 0; /* Just to be sure */
+		sppp_open(dev);
+	} else 	{
+		/* Line went down */
+		sppp_close(dev);
+	}
+	comx_status(dev, status);
+}
+
+static int syncppp_open(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct syncppp_data *spch = ch->LINE_privdata;
+
+	if (!(ch->init_status & HW_OPEN)) return -ENODEV;
+
+	ch->init_status |= LINE_OPEN;
+	ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
+
+	if(ch->line_status & LINE_UP) {
+		sppp_open(dev);
+	}
+
+	init_timer(&spch->status_timer);
+	spch->status_timer.function=syncppp_status_timerfun;
+	spch->status_timer.data=(unsigned long)dev;
+	spch->status_timer.expires=jiffies + HZ*3;
+	add_timer(&spch->status_timer);
+	
+	return 0;
+}
+
+static int syncppp_close(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct syncppp_data *spch = ch->LINE_privdata;
+
+	if (!(ch->init_status & HW_OPEN)) return -ENODEV;
+	del_timer(&spch->status_timer);
+	
+	sppp_close(dev);
+
+	ch->init_status &= ~LINE_OPEN;
+	ch->line_status &= ~(PROTO_UP | PROTO_LOOP);
+
+	return 0;
+}
+
+static int syncppp_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+
+	if (test_and_set_bit(0, &dev->tbusy)) {
+		ch->stats.tx_errors++;
+        	return 0;
+	}	
+	switch(ch->HW_send_packet(dev, skb)) {
+		case FRAME_QUEUED:
+			clear_bit(0, &dev->tbusy);
+			break;
+		case FRAME_ACCEPTED:
+		case FRAME_DROPPED:
+			break;
+		case FRAME_ERROR:
+			printk(KERN_ERR "%s: Transmit frame error (len %d)\n", 
+				dev->name, skb->len);
+		break;
+	}
+	return 0;
+}
+
+
+static int syncppp_statistics(struct device *dev, char *page) 
+{
+	int len = 0;
+
+	len += sprintf(page + len, " ");
+	return len;
+}
+
+
+static int syncppp_exit(struct device *dev) 
+{
+	struct comx_channel *ch = dev->priv;
+
+	sppp_detach(dev);
+
+	dev->flags = 0;
+	dev->type = 0;
+	dev->mtu = 0;
+
+	ch->LINE_rx = NULL;
+	ch->LINE_tx = NULL;
+	ch->LINE_status = NULL;
+	ch->LINE_open = NULL;
+	ch->LINE_close = NULL;
+	ch->LINE_xmit = NULL;
+	ch->LINE_header	= NULL;
+	ch->LINE_rebuild_header	= NULL;
+	ch->LINE_statistics = NULL;
+
+	kfree(ch->LINE_privdata);
+	ch->LINE_privdata = NULL;
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int syncppp_init(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct ppp_device *pppdev = (struct ppp_device*)dev;
+
+	ch->LINE_privdata = kmalloc(sizeof(struct syncppp_data), GFP_KERNEL);
+
+	sppp_attach(pppdev);
+
+	if(ch->protocol == &hdlc_protocol) {
+		pppdev->sppp.pp_flags |= PP_CISCO;
+		dev->type = ARPHRD_HDLC;
+	} else {
+		pppdev->sppp.pp_flags &= ~PP_CISCO;
+		dev->type = ARPHRD_PPP;
+	}
+
+	ch->LINE_rx = sppp_input;
+	ch->LINE_tx = syncppp_tx;
+	ch->LINE_status = syncppp_status;
+	ch->LINE_open = syncppp_open;
+	ch->LINE_close = syncppp_close;
+	ch->LINE_xmit = syncppp_xmit;
+	ch->LINE_header	= NULL;
+	ch->LINE_statistics = syncppp_statistics;
+
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct comx_protocol syncppp_protocol = {
+	"ppp", 
+	VERSION,
+	ARPHRD_PPP, 
+	syncppp_init, 
+	syncppp_exit, 
+	NULL 
+};
+
+static struct comx_protocol hdlc_protocol = {
+	"hdlc", 
+	VERSION,
+	ARPHRD_PPP, 
+	syncppp_init, 
+	syncppp_exit, 
+	NULL 
+};
+
+
+#ifdef MODULE
+#define comx_proto_ppp_init init_module
+#endif
+
+__initfunc(int comx_proto_ppp_init(void))
+{
+	int ret;
+
+	if(0!=(ret=comx_register_protocol(&hdlc_protocol))) {
+		return ret;
+	}
+	return comx_register_protocol(&syncppp_protocol);
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	comx_unregister_protocol(syncppp_protocol.name);
+	comx_unregister_protocol(hdlc_protocol.name);
+}
+#endif /* MODULE */
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/comx.c linux.14p16/drivers/net/comx.c
--- linux.vanilla/drivers/net/comx.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/comx.c	Thu Dec  9 15:33:37 1999
@@ -0,0 +1,1234 @@
+/* 
+ * Device driver framework for the COMX line of synchronous serial boards
+ * 
+ * for Linux kernel 2.2.X
+ *
+ * Original authors:  Arpad Bakay <bakay.arpad@synergon.hu>,
+ *                    Peter Bajan <bajan.peter@synergon.hu>,
+ * Previous maintainer: Tivadar Szemethy <tiv@itc.hu>
+ * Current maintainer: Gergely Madarasz <gorgo@itc.hu>
+ *
+ * Copyright (C) 1995-1999 ITConsult-Pro Co.
+ *
+ * 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.
+ *
+ * Version 0.80 (99/06/11):
+ *		- clean up source code (playing a bit of indent)
+ *		- port back to kernel, add support for non-module versions
+ *		- add support for board resets when channel protocol is down
+ *		- reset the device structure after protocol exit
+ *		  the syncppp driver needs it
+ *		- add support for /proc/comx/protocols and 
+ *		  /proc/comx/boardtypes
+ *
+ * Version 0.81 (99/06/21):
+ *		- comment out the board reset support code, the locomx
+ *		  driver seems not buggy now
+ *		- printk() levels fixed
+ *
+ * Version 0.82 (99/07/08):
+ *		- Handle stats correctly if the lowlevel driver is
+ *		  is not a comx one (locomx - z85230)
+ *
+ * Version 0.83 (99/07/15):
+ *		- reset line_status when interface is down
+ *
+ */
+
+#define VERSION "0.82"
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+#ifndef CONFIG_PROC_FS
+#error For now, COMX really needs the /proc filesystem
+#endif
+
+#include "comx.h"
+#include "syncppp.h"
+
+MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
+MODULE_DESCRIPTION("Common code for the COMX synchronous serial adapters");
+
+extern int comx_hw_comx_init(void);
+extern int comx_hw_locomx_init(void);
+extern int comx_hw_mixcom_init(void);
+extern int comx_proto_hdlc_init(void);
+extern int comx_proto_ppp_init(void);
+extern int comx_proto_syncppp_init(void);
+extern int comx_proto_lapb_init(void);
+extern int comx_proto_fr_init(void);
+
+static struct comx_hardware *comx_channels = NULL;
+static struct comx_protocol *comx_lines = NULL;
+
+struct inode_operations comx_normal_inode_ops; 
+static struct inode_operations comx_root_inode_ops; // for mkdir
+static struct inode_operations comx_debug_inode_ops; // mas a file_ops
+static struct file_operations comx_normal_file_ops;  // with open/relase
+static struct file_operations comx_debug_file_ops;  // with lseek+read
+
+static void comx_delete_dentry(struct dentry *dentry);
+static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode,
+	int size, struct proc_dir_entry *dir);
+
+static void comx_fill_inode(struct inode *inode, int fill);
+
+static struct dentry_operations comx_dentry_operations = {
+	NULL,			/* revalidate */
+	NULL,			/* d_hash */
+	NULL, 			/* d_compare */
+	&comx_delete_dentry	/* d_delete */
+};
+
+
+struct proc_dir_entry comx_root_dir = {
+	0, 4, "comx",
+	S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, 2, 0, 0,
+	0, &comx_root_inode_ops,
+	NULL, comx_fill_inode,
+	NULL, &proc_root, NULL 
+};
+
+struct comx_debugflags_struct	comx_debugflags[] = {
+	{ "comx_rx",		DEBUG_COMX_RX		},
+	{ "comx_tx", 		DEBUG_COMX_TX		},
+	{ "hw_tx",		DEBUG_HW_TX		},
+	{ "hw_rx", 		DEBUG_HW_RX		},
+	{ "hdlc_keepalive",	DEBUG_HDLC_KEEPALIVE	},
+	{ "comxppp",		DEBUG_COMX_PPP		},
+	{ "comxlapb",		DEBUG_COMX_LAPB		},
+	{ "dlci",		DEBUG_COMX_DLCI		},
+	{ NULL,			0			} 
+};
+
+static void comx_fill_inode(struct inode *inode, int fill)
+{
+	if (fill)
+		MOD_INC_USE_COUNT;
+	else
+		MOD_DEC_USE_COUNT;
+}
+
+
+int comx_debug(struct device *dev, char *fmt, ...)
+{
+	struct comx_channel *ch = dev->priv;
+	char *page,*str;
+	va_list args;
+	int len;
+
+	if (!ch->debug_area) return 0;
+
+	if (!(page = (char *)__get_free_page(GFP_ATOMIC))) return -ENOMEM;
+
+	va_start(args, fmt);
+	len = vsprintf(str = page, fmt, args);
+	va_end(args);
+
+	if (len >= PAGE_SIZE) {
+		printk(KERN_ERR "comx_debug: PANIC! len = %d !!!\n", len);
+		free_page((unsigned long)page);
+		return -EINVAL;
+	}
+
+	while (len) {
+		int to_copy;
+		int free = (ch->debug_start - ch->debug_end + ch->debug_size) 
+			% ch->debug_size;
+
+		to_copy = min( free ? free : ch->debug_size, 
+			min (ch->debug_size - ch->debug_end, len) );
+		memcpy(ch->debug_area + ch->debug_end, str, to_copy);
+		str += to_copy;
+		len -= to_copy;
+		ch->debug_end = (ch->debug_end + to_copy) % ch->debug_size;
+		if (ch->debug_start == ch->debug_end) // Full ? push start away
+			ch->debug_start = (ch->debug_start + len + 1) % 
+					ch->debug_size;
+		ch->debug_file->size = (ch->debug_end - ch->debug_start +
+					ch->debug_size) % ch->debug_size;
+	} 
+
+	free_page((unsigned long)page);
+	return 0;
+}
+
+int comx_debug_skb(struct device *dev, struct sk_buff *skb, char *msg)
+{
+	struct comx_channel *ch = dev->priv;
+
+	if (!ch->debug_area) return 0;
+	if (!skb) comx_debug(dev, "%s: %s NULL skb\n\n", dev->name, msg);
+	if (!skb->len) comx_debug(dev, "%s: %s empty skb\n\n", dev->name, msg);
+
+	return comx_debug_bytes(dev, skb->data, skb->len, msg);
+}
+
+int comx_debug_bytes(struct device *dev, unsigned char *bytes, int len, 
+		char *msg)
+{
+	int pos = 0;
+	struct comx_channel *ch = dev->priv;
+
+	if (!ch->debug_area) return 0;
+
+	comx_debug(dev, "%s: %s len %d\n", dev->name, msg, len);
+
+	while (pos != len) {
+		char line[80];
+		int i = 0;
+
+		memset(line, 0, 80);
+		sprintf(line,"%04d ", pos);
+		do {
+			sprintf(line + 5 + (pos % 16) * 3, "%02x", bytes[pos]);
+			sprintf(line + 60 + (pos % 16), "%c", 
+				isprint(bytes[pos]) ? bytes[pos] : '.');
+			pos++;
+		} while (pos != len && pos % 16);
+
+		while ( i++ != 78 ) if (line[i] == 0) line[i] = ' ';
+		line[77] = '\n';
+		line[78] = 0;
+	
+		comx_debug(dev, "%s", line);
+	}
+	comx_debug(dev, "\n");
+	return 0;
+}
+
+static void comx_loadavg_timerfun(unsigned long d)
+{
+	struct device *dev = (struct device *)d;
+	struct comx_channel *ch = dev->priv;
+
+	ch->avg_bytes[ch->loadavg_counter] = ch->current_stats->rx_bytes;
+	ch->avg_bytes[ch->loadavg_counter + ch->loadavg_size] = 
+		ch->current_stats->tx_bytes;
+
+	ch->loadavg_counter = (ch->loadavg_counter + 1) % ch->loadavg_size;
+
+	mod_timer(&ch->loadavg_timer,jiffies + HZ * ch->loadavg[0]);
+}
+
+#if 0
+static void comx_reset_timerfun(unsigned long d)
+{ 
+	struct device *dev = (struct device *)d;
+	struct comx_channel *ch = dev->priv;
+
+	if(!(ch->line_status & (PROTO_LOOP | PROTO_UP))) {
+		if(test_and_set_bit(0,&ch->reset_pending) && ch->HW_reset) {
+			ch->HW_reset(dev);
+		}
+	}
+
+	mod_timer(&ch->reset_timer, jiffies + HZ * ch->reset_timeout);
+}
+#endif                                            
+
+static int comx_open(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct proc_dir_entry *comxdir = ch->procdir->subdir;
+	int ret=0;
+
+	if (!ch->protocol || !ch->hardware) return -ENODEV;
+
+	if ((ret = ch->HW_open(dev))) return ret;
+	if ((ret = ch->LINE_open(dev))) { 
+		ch->HW_close(dev); 
+		return ret; 
+	};
+
+	for (; comxdir ; comxdir = comxdir->next) {
+		if (strcmp(comxdir->name, FILENAME_HARDWARE) == 0 ||
+		   strcmp(comxdir->name, FILENAME_PROTOCOL) == 0)
+			comxdir->mode = S_IFREG | 0444;
+	}
+
+#if 0
+	ch->reset_pending = 1;
+	ch->reset_timeout = 30;
+	ch->reset_timer.function = comx_reset_timerfun;
+	ch->reset_timer.data = (unsigned long)dev;
+	ch->reset_timer.expires = jiffies + HZ * ch->reset_timeout;
+	add_timer(&ch->reset_timer);
+#endif
+
+	return 0;
+}
+
+static int comx_close(struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	struct proc_dir_entry *comxdir = ch->procdir->subdir;
+	int ret = -ENODEV;
+
+	if (test_and_clear_bit(0, &ch->lineup_pending)) {
+		del_timer(&ch->lineup_timer);
+	}
+
+#if 0	
+	del_timer(&ch->reset_timer);
+#endif
+
+	if (ch->init_status & LINE_OPEN && ch->protocol && ch->LINE_close) {
+		ret = ch->LINE_close(dev);
+	}
+
+	if (ret) return ret;
+
+	if (ch->init_status & HW_OPEN && ch->hardware && ch->HW_close) {
+		ret = ch->HW_close(dev);
+	}
+	
+	ch->line_status=0;
+
+	for (; comxdir ; comxdir = comxdir->next) {
+		if (strcmp(comxdir->name, FILENAME_HARDWARE) == 0 ||
+		    strcmp(comxdir->name, FILENAME_PROTOCOL) == 0)
+			comxdir->mode = S_IFREG | 0644;
+	}
+
+	return ret;
+}
+
+void comx_status(struct device *dev, int status)
+{
+	struct comx_channel *ch = dev->priv;
+
+#if 0
+	if(status & (PROTO_UP | PROTO_LOOP)) {
+		clear_bit(0,&ch->reset_pending);
+	}
+#endif
+
+	if (dev->flags & IFF_UP) {
+		printk(KERN_NOTICE "Interface %s: modem status %s, line protocol %s\n",
+		    dev->name, status & LINE_UP ? "UP" : "DOWN", 
+		    status & PROTO_LOOP ? "LOOP" : status & PROTO_UP ? 
+		    "UP" : "DOWN");
+	}
+	
+	ch->line_status = status;
+}
+
+static int comx_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct comx_channel *ch = dev->priv;
+	int rc;
+
+	if (skb->len > dev->mtu + dev->hard_header_len) {
+		printk(KERN_ERR "comx_xmit: %s: skb->len %d > dev->mtu %d\n", dev->name,
+		(int)skb->len, dev->mtu);
+	}
+	
+	if (ch->debug_flags & DEBUG_COMX_TX) {
+		comx_debug_skb(dev, skb, "comx_xmit skb");
+	}
+	
+	rc=ch->LINE_xmit(skb, dev);
+//	if (!rc) dev_kfree_skb(skb);
+
+	return rc;
+}
+
+static int comx_header(struct sk_buff *skb, struct device *dev, 
+	unsigned short type, void *daddr, void *saddr, unsigned len) 
+{
+	struct comx_channel *ch = dev->priv;
+
+	if (ch->LINE_header) {
+		return (ch->LINE_header(skb, dev, type, daddr, saddr, len));
+	} else {
+		return 0;
+	}
+}
+
+static int comx_rebuild_header(struct sk_buff *skb) 
+{
+	struct device *dev = skb->dev;
+	struct comx_channel *ch = dev->priv;
+
+	if (ch->LINE_rebuild_header) {
+		return(ch->LINE_rebuild_header(skb));
+	} else {
+		return 0;
+	}
+}
+
+int comx_rx(struct device *dev, struct sk_buff *skb)
+{
+	struct comx_channel *ch = dev->priv;
+
+	if (ch->debug_flags & DEBUG_COMX_RX) {
+		comx_debug_skb(dev, skb, "comx_rx skb");
+	}
+	if (skb) {
+		netif_rx(skb);
+	}
+	return 0;
+}
+
+static struct net_device_stats *comx_stats(struct device *dev)
+{
+	struct comx_channel *ch = (struct comx_channel *)dev->priv;
+
+	return ch->current_stats;
+}
+
+void comx_lineup_func(unsigned long d)
+{
+	struct device *dev = (struct device *)d;
+	struct comx_channel *ch = dev->priv;
+
+	del_timer(&ch->lineup_timer);
+	clear_bit(0, &ch->lineup_pending);
+
+	if (ch->LINE_status) {
+		ch->LINE_status(dev, ch->line_status |= LINE_UP);
+	}
+}
+
+#define LOADAVG(avg, off) (int) \
+	((ch->avg_bytes[(ch->loadavg_counter - 1 + ch->loadavg_size * 2) \
+	% ch->loadavg_size + off] -  ch->avg_bytes[(ch->loadavg_counter - 1 \
+		- ch->loadavg[avg] / ch->loadavg[0] + ch->loadavg_size * 2) \
+		% ch->loadavg_size + off]) / ch->loadavg[avg] * 8)
+
+static int comx_statistics(struct device *dev, char *page)
+{
+	struct comx_channel *ch = dev->priv;
+	int len = 0;
+	int tmp;
+	int i = 0;
+	char tmpstr[20];
+	int tmpstrlen = 0;
+
+	len += sprintf(page + len, "Interface administrative status is %s, "
+		"modem status is %s, protocol is %s\n", 
+		dev->flags & IFF_UP ? "UP" : "DOWN",
+		ch->line_status & LINE_UP ? "UP" : "DOWN",
+		ch->line_status & PROTO_LOOP ? "LOOP" : 
+		ch->line_status & PROTO_UP ? "UP" : "DOWN");
+	len += sprintf(page + len, "Modem status changes: %lu, Transmitter status "
+		"is %s, tbusy: %d\n", ch->current_stats->tx_carrier_errors, ch->HW_txe ? 
+		ch->HW_txe(dev) ? "IDLE" : "BUSY" : "NOT READY", (int)dev->tbusy);
+	len += sprintf(page + len, "Interface load (input): %d / %d / %d bits/s (",
+		LOADAVG(0,0), LOADAVG(1, 0), LOADAVG(2, 0));
+	tmpstr[0] = 0;
+	for (i=0; i != 3; i++) {
+		char tf;
+
+		tf = ch->loadavg[i] % 60 == 0 && 
+			ch->loadavg[i] / 60 > 0 ? 'm' : 's';
+		tmpstrlen += sprintf(tmpstr + tmpstrlen, "%d%c%s", 
+			ch->loadavg[i] / (tf == 'm' ? 60 : 1), tf, 
+			i == 2 ? ")\n" : "/");
+	}
+	len += sprintf(page + len, 
+		"%s              (output): %d / %d / %d bits/s (%s", tmpstr, 
+		LOADAVG(0,ch->loadavg_size), LOADAVG(1, ch->loadavg_size), 
+		LOADAVG(2, ch->loadavg_size), tmpstr);
+
+	len += sprintf(page + len, "Debug flags: ");
+	tmp = len; i = 0;
+	while (comx_debugflags[i].name) {
+		if (ch->debug_flags & comx_debugflags[i].value) 
+			len += sprintf(page + len, "%s ", 
+				comx_debugflags[i].name);
+		i++;
+	}
+	len += sprintf(page + len, "%s\n", tmp == len ? "none" : "");
+
+	len += sprintf(page + len, "RX errors: len: %lu, overrun: %lu, crc: %lu, "
+		"aborts: %lu\n           buffer overrun: %lu, pbuffer overrun: %lu\n"
+		"TX errors: underrun: %lu\n",
+		ch->current_stats->rx_length_errors, ch->current_stats->rx_over_errors, 
+		ch->current_stats->rx_crc_errors, ch->current_stats->rx_frame_errors, 
+		ch->current_stats->rx_missed_errors, ch->current_stats->rx_fifo_errors,
+		ch->current_stats->tx_fifo_errors);
+
+	if (ch->LINE_statistics && (ch->init_status & LINE_OPEN)) {
+		len += ch->LINE_statistics(dev, page + len);
+	} else {
+		len += sprintf(page+len, "Line status: driver not initialized\n");
+	}
+	if (ch->HW_statistics && (ch->init_status & HW_OPEN)) {
+		len += ch->HW_statistics(dev, page + len);
+	} else {
+		len += sprintf(page+len, "Board status: driver not initialized\n");
+	}
+
+	return len;
+}
+
+static int comx_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+	struct comx_channel *ch = dev->priv;
+
+	if (ch->LINE_ioctl) {
+		return(ch->LINE_ioctl(dev, ifr, cmd));
+	}
+	return -EINVAL;
+}
+
+static void comx_reset_dev(struct device *dev)
+{
+	dev->open = comx_open;
+	dev->stop = comx_close;
+	dev->hard_start_xmit = comx_xmit;
+	dev->hard_header = comx_header;
+	dev->rebuild_header = comx_rebuild_header;
+	dev->get_stats = comx_stats;
+	dev->do_ioctl = comx_ioctl;
+	dev->change_mtu = NULL;
+	dev->tx_queue_len = 20;
+	dev->flags = IFF_NOARP;
+}
+
+static int comx_init_dev(struct device *dev)
+{
+	struct comx_channel *ch;
+
+	if ((ch = kmalloc(sizeof(struct comx_channel), GFP_KERNEL)) == NULL) {
+		return -ENOMEM;
+	}
+	memset(ch, 0, sizeof(struct comx_channel));
+
+	ch->loadavg[0] = 5;
+	ch->loadavg[1] = 300;
+	ch->loadavg[2] = 900;
+	ch->loadavg_size = ch->loadavg[2] / ch->loadavg[0] + 1; 
+	if ((ch->avg_bytes = kmalloc(ch->loadavg_size * 
+		sizeof(unsigned long) * 2, GFP_KERNEL)) == NULL) {
+		return -ENOMEM;
+	}
+
+	memset(ch->avg_bytes, 0, ch->loadavg_size * sizeof(unsigned long) * 2);
+	ch->loadavg_counter = 0;
+	ch->loadavg_timer.function = comx_loadavg_timerfun;
+	ch->loadavg_timer.data = (unsigned long)dev;
+	ch->loadavg_timer.expires = jiffies + HZ * ch->loadavg[0];
+	add_timer(&ch->loadavg_timer);
+
+	dev->priv = (void *)ch;
+	ch->dev = dev;
+	ch->line_status &= ~LINE_UP;
+
+	ch->current_stats = &ch->stats;
+
+	comx_reset_dev(dev);
+	return 0;
+}
+
+static int comx_read_proc(char *page, char **start, off_t off, int count, 
+	int *eof, void *data)
+{
+	struct proc_dir_entry *file = (struct proc_dir_entry *)data;
+	struct device *dev = file->parent->data;
+	struct comx_channel *ch=(struct comx_channel *)dev->priv;
+	int len = 0;
+
+	if (strcmp(file->name, FILENAME_STATUS) == 0) {
+		len = comx_statistics(dev, page);
+	} else if (strcmp(file->name, FILENAME_HARDWARE) == 0) {
+		len = sprintf(page, "%s\n", ch->hardware ? 
+			ch->hardware->name : HWNAME_NONE);
+	} else if (strcmp(file->name, FILENAME_PROTOCOL) == 0) {
+		len = sprintf(page, "%s\n", ch->protocol ? 
+			ch->protocol->name : PROTONAME_NONE);
+	} else if (strcmp(file->name, FILENAME_LINEUPDELAY) == 0) {
+		len = sprintf(page, "%01d\n", ch->lineup_delay);
+	}
+
+	if (off >= len) {
+		*eof = 1;
+		return 0;
+	}
+
+	*start = page + off;
+	if (count >= len - off) {
+		*eof = 1;
+	}
+	return( min(count, len - off) );
+}
+
+
+static int comx_root_read_proc(char *page, char **start, off_t off, int count, 
+	int *eof, void *data)
+{
+	struct proc_dir_entry *file = (struct proc_dir_entry *)data;
+	struct comx_hardware *hw;
+	struct comx_protocol *line;
+
+	int len = 0;
+
+	if (strcmp(file->name, FILENAME_HARDWARELIST) == 0) {
+		for(hw=comx_channels;hw;hw=hw->next) 
+			len+=sprintf(page+len, "%s\n", hw->name);
+	} else if (strcmp(file->name, FILENAME_PROTOCOLLIST) == 0) {
+		for(line=comx_lines;line;line=line->next)
+			len+=sprintf(page+len, "%s\n", line->name);
+	}
+
+	if (off >= len) {
+		*eof = 1;
+		return 0;
+	}
+
+	*start = page + off;
+	if (count >= len - off) {
+		*eof = 1;
+	}
+	return( min(count, len - off) );
+}
+
+
+
+static int comx_write_proc(struct file *file, const char *buffer, u_long count,
+	void *data)
+{
+	struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
+	struct device *dev = (struct device *)entry->parent->data;
+	struct comx_channel *ch=(struct comx_channel *)dev->priv;
+	char *page;
+	struct comx_hardware *hw = comx_channels;
+	struct comx_protocol *line = comx_lines;
+	char str[30];
+	int ret=0;
+
+	if (file->f_dentry->d_inode->i_ino != entry->low_ino) {
+		printk(KERN_ERR "comx_write_proc: file <-> data internal error\n");
+		return -EIO;
+	}
+
+	if (count > PAGE_SIZE) {
+		printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
+		return -ENOSPC;
+	}
+
+	if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
+
+	copy_from_user(page, buffer, count);
+
+	if (*(page + count - 1) == '\n') *(page + count - 1) = 0;
+
+	if (strcmp(entry->name, FILENAME_DEBUG) == 0) {
+		int i;
+		int ret = 0;
+
+		if ((i = simple_strtoul(page, NULL, 10)) != 0) {
+			unsigned long flags;
+
+			save_flags(flags); cli();
+			if (ch->debug_area) kfree(ch->debug_area);
+			if ((ch->debug_area = kmalloc(ch->debug_size = i, 
+				GFP_KERNEL)) == NULL) {
+				ret = -ENOMEM;
+			}
+			ch->debug_start = ch->debug_end = 0;
+			restore_flags(flags);
+			free_page((unsigned long)page);
+			return count;
+		}
+		
+		if (*page != '+' && *page != '-') {
+			free_page((unsigned long)page);
+			return -EINVAL;
+		}
+		while (comx_debugflags[i].value && 
+			strncmp(comx_debugflags[i].name, page + 1, 
+			strlen(comx_debugflags[i].name))) {
+			i++;
+		}
+	
+		if (comx_debugflags[i].value == 0) {
+			printk(KERN_ERR "Invalid debug option\n");
+			free_page((unsigned long)page);
+			return -EINVAL;
+		}
+		if (*page == '+') {
+			ch->debug_flags |= comx_debugflags[i].value;
+		} else {
+			ch->debug_flags &= ~comx_debugflags[i].value;
+		}
+	} else if (strcmp(entry->name, FILENAME_HARDWARE) == 0) {
+		if(strlen(page)>10) {
+			free_page((unsigned long)page);
+			return -EINVAL;
+		}
+		while (hw) { 
+			if (strcmp(hw->name, page) == 0) {
+				break;
+			} else {
+				hw = hw->next;
+			}
+		}
+#ifdef CONFIG_KMOD
+		if(!hw && comx_strcasecmp(HWNAME_NONE,page) != 0){
+			sprintf(str,"comx-hw-%s",page);
+			request_module(str);
+		}		
+		hw=comx_channels;
+		while (hw) {
+			if (comx_strcasecmp(hw->name, page) == 0) {
+				break;
+			} else {
+				hw = hw->next;
+			}
+		}
+#endif
+
+		if (comx_strcasecmp(HWNAME_NONE, page) != 0 && !hw)  {
+			free_page((unsigned long)page);
+			return -ENODEV;
+		}
+		if (ch->init_status & HW_OPEN) {
+			free_page((unsigned long)page);
+			return -EBUSY;
+		}
+		if (ch->hardware && ch->hardware->hw_exit && 
+		   (ret=ch->hardware->hw_exit(dev))) {
+			free_page((unsigned long)page);
+			return ret;
+		}
+		ch->hardware = hw;
+		entry->size = strlen(page) + 1;
+		if (hw && hw->hw_init) hw->hw_init(dev);
+	} else if (strcmp(entry->name, FILENAME_PROTOCOL) == 0) {
+		if(strlen(page)>10) {
+			free_page((unsigned long)page);
+			return -EINVAL;
+		}
+		while (line) {
+			if (comx_strcasecmp(line->name, page) == 0) {
+				break;
+			} else {
+				line = line->next;
+			}
+		}
+#ifdef CONFIG_KMOD
+		if(!line && comx_strcasecmp(PROTONAME_NONE, page) != 0) {
+			sprintf(str,"comx-proto-%s",page);
+			request_module(str);
+		}		
+		line=comx_lines;
+		while (line) {
+			if (comx_strcasecmp(line->name, page) == 0) {
+				break;
+			} else {
+				line = line->next;
+			}
+		}
+#endif
+		
+		if (comx_strcasecmp(PROTONAME_NONE, page) != 0 && !line) {
+			free_page((unsigned long)page);
+			return -ENODEV;
+		}
+		
+		if (ch->init_status & LINE_OPEN) {
+			free_page((unsigned long)page);
+			return -EBUSY;
+		}
+		
+		if (ch->protocol && ch->protocol->line_exit && 
+		    (ret=ch->protocol->line_exit(dev))) {
+			free_page((unsigned long)page);
+			return ret;
+		}
+		ch->protocol = line;
+		entry->size = strlen(page) + 1;
+		comx_reset_dev(dev);
+		if (line && line->line_init) line->line_init(dev);
+	} else if (strcmp(entry->name, FILENAME_LINEUPDELAY) == 0) {
+		int i;
+
+		if ((i = simple_strtoul(page, NULL, 10)) != 0) {
+			if (i >=0 && i < 10) { 
+				ch->lineup_delay = i; 
+			} else {
+				printk(KERN_ERR "comx: invalid lineup_delay value\n");
+			}
+		}
+	}
+
+	free_page((unsigned long)page);
+	return count;
+}
+
+static loff_t comx_debug_lseek(struct file *file, loff_t offset, int orig)
+{
+	switch(orig) {
+		case 0:	
+			file->f_pos = max(0, min(offset, 
+				file->f_dentry->d_inode->i_size));
+			return(file->f_pos);
+		case 1: 
+			file->f_pos = max(0, min(offset + file->f_pos, 
+				file->f_dentry->d_inode->i_size));
+			return(file->f_pos);
+		case 2: 
+			file->f_pos = max(0, 
+				min(offset + file->f_dentry->d_inode->i_size, 
+				file->f_dentry->d_inode->i_size));
+			return(file->f_pos);
+	}
+	return(file->f_pos);
+}
+
+static int comx_file_open(struct inode *inode, struct file *file)
+{
+
+	if((file->f_mode & FMODE_WRITE) && !(inode->i_mode & 0200)) {
+		return -EACCES;
+	}
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int comx_file_release(struct inode *inode, struct file *file)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static ssize_t comx_debug_read(struct file *file, char *buffer, size_t count,
+	loff_t *ppos)
+{
+	struct proc_dir_entry *de = file->f_dentry->d_inode->u.generic_ip;
+	struct device *dev = de->parent->data;
+	struct comx_channel *ch = dev->priv;
+	loff_t copied = 0;
+	unsigned long flags;
+
+	save_flags(flags); cli(); // We may run into trouble when debug_area is filled
+				  // from irq inside read. no problem if the buffer is
+				  // large enough
+
+	while (count > 0 && ch->debug_start != ch->debug_end) {
+		int len;
+
+		len = min( (ch->debug_end - ch->debug_start + ch->debug_size)
+			%ch->debug_size, min (ch->debug_size - 
+			ch->debug_start, count));
+
+		if (len) copy_to_user(buffer + copied, 
+			ch->debug_area + ch->debug_start, len);
+		ch->debug_start = (ch->debug_start + len) % ch->debug_size;
+
+		de->size -= len;
+		count -= len;
+		copied += len;
+	}
+
+	restore_flags(flags);
+	return copied;
+}
+
+static int comx_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+	struct proc_dir_entry *new_dir, *debug_file;
+	struct device *dev;
+	struct comx_channel *ch;
+
+	if (dir->i_ino != comx_root_dir.low_ino) return -ENOTDIR;
+
+	if ((new_dir = create_proc_entry(dentry->d_name.name, mode | S_IFDIR, 
+		&comx_root_dir)) == NULL) {
+		return -EIO;
+	}
+
+	new_dir->ops = &proc_dir_inode_operations;  // ez egy normalis /proc konyvtar
+	new_dir->nlink = 2;
+	new_dir->data = NULL; // ide jon majd a struct dev
+
+	/* Ezek kellenek */
+	if (!create_comx_proc_entry(FILENAME_HARDWARE, 0644, 
+	    strlen(HWNAME_NONE) + 1, new_dir)) {
+		return -ENOMEM;
+	}
+	if (!create_comx_proc_entry(FILENAME_PROTOCOL, 0644, 
+	    strlen(PROTONAME_NONE) + 1, new_dir)) {
+		return -ENOMEM;
+	}
+	if (!create_comx_proc_entry(FILENAME_STATUS, 0444, 0, new_dir)) {
+		return -ENOMEM;
+	}
+	if (!create_comx_proc_entry(FILENAME_LINEUPDELAY, 0644, 2, new_dir)) {
+		return -ENOMEM;
+	}
+
+	if ((debug_file = create_proc_entry(FILENAME_DEBUG, 
+	    S_IFREG | 0644, new_dir)) == NULL) {
+		return -ENOMEM;
+	}
+	debug_file->ops = &comx_debug_inode_ops;
+	debug_file->data = (void *)debug_file; 
+	debug_file->read_proc = NULL; // see below
+	debug_file->write_proc = &comx_write_proc;
+	debug_file->nlink = 1;
+
+	/* struct ppp_device is a bit larger then struct device and the
+	   syncppp driver needs it */
+	if ((dev = kmalloc(sizeof(struct ppp_device), GFP_KERNEL)) == NULL) {
+		return -ENOMEM;
+	}
+	memset(dev, 0, sizeof(struct ppp_device));
+	dev->name = (char *)new_dir->name;
+	dev->init = comx_init_dev;
+
+	if (register_netdevice(dev)) {
+		return -EIO;
+	}
+	ch=dev->priv;
+	ch->debug_file = debug_file; 
+	ch->procdir = new_dir;
+	new_dir->data = dev;
+
+	ch->debug_start = ch->debug_end = 0;
+	if ((ch->debug_area = kmalloc(ch->debug_size = DEFAULT_DEBUG_SIZE, 
+	    GFP_KERNEL)) == NULL) {
+		return -ENOMEM;
+	}
+
+	ch->lineup_delay = DEFAULT_LINEUP_DELAY;
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int comx_rmdir(struct inode *dir, struct dentry *dentry)
+{
+	struct proc_dir_entry *entry = dentry->d_inode->u.generic_ip;
+	struct device *dev = entry->data;
+	struct comx_channel *ch = dev->priv;
+	int ret;
+
+	/* Egyelore miert ne ? */
+	if (dir->i_ino != comx_root_dir.low_ino) return -ENOTDIR;
+
+	if (dev->flags & IFF_UP) {
+		printk(KERN_ERR "%s: down interface before removing it\n", dev->name);
+		return -EBUSY;
+	}
+
+	if (ch->protocol && ch->protocol->line_exit && 
+	    (ret=ch->protocol->line_exit(dev))) {
+		return ret;
+	}
+	if (ch->hardware && ch->hardware->hw_exit && 
+	   (ret=ch->hardware->hw_exit(dev))) { 
+		if(ch->protocol && ch->protocol->line_init) {
+			ch->protocol->line_init(dev);
+		}
+		return ret;
+	}
+	ch->protocol = NULL;
+	ch->hardware = NULL;
+
+	del_timer(&ch->loadavg_timer);
+	kfree(ch->avg_bytes);
+
+	unregister_netdev(dev);
+	if (ch->debug_area) {
+		kfree(ch->debug_area);
+	}
+	if (dev->priv) {
+		kfree(dev->priv);
+	}
+	kfree(dev);
+
+	remove_proc_entry(FILENAME_DEBUG, entry);
+	remove_proc_entry(FILENAME_LINEUPDELAY, entry);
+	remove_proc_entry(FILENAME_STATUS, entry);
+	remove_proc_entry(FILENAME_HARDWARE, entry);
+	remove_proc_entry(FILENAME_PROTOCOL, entry);
+	remove_proc_entry(dentry->d_name.name, &comx_root_dir);
+//	proc_unregister(&comx_root_dir, dentry->d_inode->i_ino);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static struct dentry *comx_lookup(struct inode *dir, struct dentry *dentry)
+{
+	struct proc_dir_entry *de;
+	struct inode *inode = NULL;
+
+	if (!dir || !S_ISDIR(dir->i_mode)) {
+		return ERR_PTR(-ENOTDIR);
+	}
+
+	if ((de = (struct proc_dir_entry *) dir->u.generic_ip) != NULL) {
+		for (de = de->subdir ; de ; de = de->next) {
+			if ((de && de->low_ino) && 
+			    (de->namelen == dentry->d_name.len) &&
+			    (memcmp(dentry->d_name.name, de->name, 
+			    de->namelen) == 0))	{
+			 	if ((inode = proc_get_inode(dir->i_sb, 
+			 	    de->low_ino, de)) == NULL) { 
+			 		printk(KERN_ERR "COMX: lookup error\n"); 
+			 		return ERR_PTR(-EINVAL); 
+			 	}
+				break;
+			}
+		}
+	}
+	dentry->d_op = &comx_dentry_operations;
+	d_add(dentry, inode);
+	return NULL;
+}
+
+int comx_strcasecmp(const char *cs, const char *ct)
+{
+	register signed char __res;
+
+	while (1) {
+		if ((__res = toupper(*cs) - toupper(*ct++)) != 0 || !*cs++) {
+			break;
+		}
+	}
+	return __res;
+}
+
+static void comx_delete_dentry(struct dentry *dentry)
+{
+	d_drop(dentry);
+}
+
+static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode,
+	int size, struct proc_dir_entry *dir)
+{
+	struct proc_dir_entry *new_file;
+
+	if ((new_file = create_proc_entry(name, S_IFREG | mode, dir)) != NULL) {
+		new_file->ops = &comx_normal_inode_ops;
+		new_file->data = (void *)new_file;
+		new_file->read_proc = &comx_read_proc;
+		new_file->write_proc = &comx_write_proc;
+		new_file->size = size;
+		new_file->nlink = 1;
+	}
+	return(new_file);
+}
+
+int comx_register_hardware(struct comx_hardware *comx_hw)
+{
+	struct comx_hardware *hw = comx_channels;
+
+	if (!hw) {
+		comx_channels = comx_hw;
+	} else {
+		while (hw->next != NULL && strcmp(comx_hw->name, hw->name) != 0) {
+			hw = hw->next;
+		}
+		if (strcmp(comx_hw->name, hw->name) == 0) {
+			return -1;
+		}
+		hw->next = comx_hw;
+	}
+
+	printk(KERN_INFO "COMX: driver for hardware type %s, version %s\n", comx_hw->name, comx_hw->version);
+	return 0;
+}
+
+int comx_unregister_hardware(char *name)
+{
+	struct comx_hardware *hw = comx_channels;
+
+	if (!hw) {
+		return -1;
+	}
+
+	if (strcmp(hw->name, name) == 0) {
+		comx_channels = comx_channels->next;
+		return 0;
+	}
+
+	while (hw->next != NULL && strcmp(hw->next->name,name) != 0) {
+		hw = hw->next;
+	}
+
+	if (hw->next != NULL && strcmp(hw->next->name, name) == 0) {
+		hw->next = hw->next->next;
+		return 0;
+	}
+	return -1;
+}
+
+int comx_register_protocol(struct comx_protocol *comx_line)
+{
+	struct comx_protocol *pr = comx_lines;
+
+	if (!pr) {
+		comx_lines = comx_line;
+	} else {
+		while (pr->next != NULL && strcmp(comx_line->name, pr->name) !=0) {
+			pr = pr->next;
+		}
+		if (strcmp(comx_line->name, pr->name) == 0) {
+			return -1;
+		}
+		pr->next = comx_line;
+	}
+
+	printk(KERN_INFO "COMX: driver for protocol type %s, version %s\n", comx_line->name, comx_line->version);
+	return 0;
+}
+
+int comx_unregister_protocol(char *name)
+{
+	struct comx_protocol *pr = comx_lines;
+
+	if (!pr) {
+		return -1;
+	}
+
+	if (strcmp(pr->name, name) == 0) {
+		comx_lines = comx_lines->next;
+		return 0;
+	}
+
+	while (pr->next != NULL && strcmp(pr->next->name,name) != 0) {
+		pr = pr->next;
+	}
+
+	if (pr->next != NULL && strcmp(pr->next->name, name) == 0) {
+		pr->next = pr->next->next;
+		return 0;
+	}
+	return -1;
+}
+
+#ifdef MODULE
+#define comx_init init_module
+#endif
+
+__initfunc(int comx_init(void))
+{
+	struct proc_dir_entry *new_file;
+
+	memcpy(&comx_root_inode_ops, &proc_dir_inode_operations, 
+		sizeof(struct inode_operations));
+	comx_root_inode_ops.lookup = &comx_lookup;
+	comx_root_inode_ops.mkdir = &comx_mkdir;
+	comx_root_inode_ops.rmdir = &comx_rmdir;
+
+	memcpy(&comx_normal_inode_ops, &proc_net_inode_operations, 
+		sizeof(struct inode_operations));
+	comx_normal_inode_ops.default_file_ops = &comx_normal_file_ops;
+	comx_normal_inode_ops.lookup = &comx_lookup;
+
+	memcpy(&comx_debug_inode_ops, &comx_normal_inode_ops, 
+		sizeof(struct inode_operations));
+	comx_debug_inode_ops.default_file_ops = &comx_debug_file_ops;
+
+	memcpy(&comx_normal_file_ops, proc_net_inode_operations.default_file_ops,
+		sizeof(struct file_operations));
+	comx_normal_file_ops.open = &comx_file_open;
+	comx_normal_file_ops.release = &comx_file_release;
+
+	memcpy(&comx_debug_file_ops, &comx_normal_file_ops, 
+		sizeof(struct file_operations));
+	comx_debug_file_ops.llseek = &comx_debug_lseek;
+	comx_debug_file_ops.read = &comx_debug_read;
+
+	if (proc_register(&proc_root, &comx_root_dir) < 0) return -ENOMEM;
+
+
+	if ((new_file = create_proc_entry(FILENAME_HARDWARELIST, 
+	   S_IFREG | 0444, &comx_root_dir)) == NULL) {
+		return -ENOMEM;
+	}
+	
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->data = new_file;
+	new_file->read_proc = &comx_root_read_proc;
+	new_file->write_proc = NULL;
+	new_file->nlink = 1;
+
+	if ((new_file = create_proc_entry(FILENAME_PROTOCOLLIST, 
+	   S_IFREG | 0444, &comx_root_dir)) == NULL) {
+		return -ENOMEM;
+	}
+	
+	new_file->ops = &comx_normal_inode_ops;
+	new_file->data = new_file;
+	new_file->read_proc = &comx_root_read_proc;
+	new_file->write_proc = NULL;
+	new_file->nlink = 1;
+
+
+	printk(KERN_INFO "COMX: driver version %s (C) 1995-1999 ITConsult-Pro Co. <info@itc.hu>\n", 
+		VERSION);
+
+#ifndef MODULE
+#ifdef CONFIG_COMX_HW_COMX
+	comx_hw_comx_init();
+#endif
+#ifdef CONFIG_COMX_HW_LOCOMX
+	comx_hw_locomx_init();
+#endif
+#ifdef CONFIG_COMX_HW_MIXCOM
+	comx_hw_mixcom_init();
+#endif
+#ifdef CONFIG_COMX_PROTO_HDLC
+	comx_proto_hdlc_init();
+#endif
+#ifdef CONFIG_COMX_PROTO_PPP
+	comx_proto_ppp_init();
+#endif
+#ifdef CONFIG_COMX_PROTO_LAPB
+	comx_proto_lapb_init();
+#endif
+#ifdef CONFIG_COMX_PROTO_FR
+	comx_proto_fr_init();
+#endif
+#endif
+
+	return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	remove_proc_entry(FILENAME_HARDWARELIST, &comx_root_dir);
+	remove_proc_entry(FILENAME_PROTOCOLLIST, &comx_root_dir);
+	proc_unregister(&proc_root, comx_root_dir.low_ino);
+}
+#endif
+
+EXPORT_SYMBOL(comx_register_hardware);
+EXPORT_SYMBOL(comx_unregister_hardware);
+EXPORT_SYMBOL(comx_register_protocol);
+EXPORT_SYMBOL(comx_unregister_protocol);
+EXPORT_SYMBOL(comx_debug_skb);
+EXPORT_SYMBOL(comx_debug_bytes);
+EXPORT_SYMBOL(comx_debug);
+EXPORT_SYMBOL(comx_lineup_func);
+EXPORT_SYMBOL(comx_status);
+EXPORT_SYMBOL(comx_rx);
+EXPORT_SYMBOL(comx_strcasecmp);
+EXPORT_SYMBOL(comx_normal_inode_ops);
+EXPORT_SYMBOL(comx_root_dir);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/comx.h linux.14p16/drivers/net/comx.h
--- linux.vanilla/drivers/net/comx.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/comx.h	Thu Dec  9 15:33:37 1999
@@ -0,0 +1,238 @@
+/*
+ * General definitions for the COMX driver 
+ * 
+ * Original authors:  Arpad Bakay <bakay.arpad@synergon.hu>,
+ *                    Peter Bajan <bajan.peter@synergon.hu>,
+ * Previous maintainer: Tivadar Szemethy <tiv@itc.hu>
+ * Currently maintained by: Gergely Madarasz <gorgo@itc.hu>
+ *
+ * Copyright (C) 1995-1999 ITConsult-Pro Co. <info@itc.hu>
+ *
+ * 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.
+ *
+ *
+ * net_device_stats:
+ *	rx_length_errors	rec_len < 4 || rec_len > 2000
+ *	rx_over_errors		receive overrun (OVR)
+ *	rx_crc_errors		rx crc error
+ *	rx_frame_errors		aborts rec'd (ABO)
+ *	rx_fifo_errors		status fifo overrun (PBUFOVR)
+ *	rx_missed_errors	receive buffer overrun (BUFOVR)
+ *	tx_aborted_errors	?
+ *	tx_carrier_errors	modem line status changes
+ *	tx_fifo_errors		tx underrun (locomx)
+ */
+
+struct comx_protocol {
+	char	*name;
+	char	*version;
+	unsigned short encap_type;
+	int	(*line_init)(struct device *dev);
+	int	(*line_exit)(struct device *dev);
+	struct comx_protocol *next;
+	};
+
+struct comx_hardware {
+	char *name; 
+	char *version;
+	int	(*hw_init)(struct device *dev);
+	int	(*hw_exit)(struct device *dev);
+	int	(*hw_dump)(struct device *dev);
+	struct comx_hardware *next;
+	};
+
+struct comx_channel {
+	struct device 	*dev;		// Where we belong to
+	struct device	*twin;		// On dual-port cards
+	struct proc_dir_entry *procdir;	// the directory
+
+	unsigned char	init_status;
+	unsigned char	line_status;
+
+	struct timer_list lineup_timer;	// against line jitter
+	int		lineup_pending;
+	unsigned char	lineup_delay;
+
+#if 0
+	struct timer_list reset_timer; // for board resetting
+	int		reset_pending;
+	int		reset_timeout;
+#endif
+
+	struct net_device_stats	stats;	
+	struct net_device_stats *current_stats;
+#if 0
+	unsigned long	board_resets;
+#endif
+	unsigned long 	*avg_bytes;
+	int		loadavg_counter, loadavg_size;
+	int		loadavg[3];
+	struct timer_list loadavg_timer;
+	int		debug_flags;
+	char 		*debug_area;
+	int		debug_start, debug_end, debug_size;
+	struct proc_dir_entry *debug_file;
+#ifdef	CONFIG_COMX_DEBUG_RAW
+	char		*raw;
+	int		raw_len;
+#endif
+	// LINE specific	
+	struct comx_protocol *protocol;
+	void		(*LINE_rx)(struct device *dev, struct sk_buff *skb);
+	int		(*LINE_tx)(struct device *dev);
+	void		(*LINE_status)(struct device *dev, u_short status);
+	int		(*LINE_open)(struct device *dev);
+	int		(*LINE_close)(struct device *dev);
+	int		(*LINE_xmit)(struct sk_buff *skb, struct device *dev);
+	int		(*LINE_header)(struct sk_buff *skb, struct device *dev,
+				u_short type,void *daddr, void *saddr, 
+				unsigned len);
+	int		(*LINE_rebuild_header)(struct sk_buff *skb);
+	int		(*LINE_statistics)(struct device *dev, char *page);
+	int		(*LINE_parameter_check)(struct device *dev);
+	int		(*LINE_ioctl)(struct device *dev, struct ifreq *ifr,
+				int cmd);
+	void		(*LINE_mod_use)(int);
+	void *		LINE_privdata;
+
+	// HW specific
+
+	struct comx_hardware *hardware;
+	void	(*HW_board_on)(struct device *dev);
+	void	(*HW_board_off)(struct device *dev);
+	struct device *(*HW_access_board)(struct device *dev);
+	void	(*HW_release_board)(struct device *dev, struct device *savep);
+	int	(*HW_txe)(struct device *dev);
+	int	(*HW_open)(struct device *dev);
+	int	(*HW_close)(struct device *dev);
+	int	(*HW_send_packet)(struct device *dev,struct sk_buff *skb);
+	int	(*HW_statistics)(struct device *dev, char *page);
+#if 0
+	int	(*HW_reset)(struct device *dev, char *page);
+#endif
+	int	(*HW_load_board)(struct device *dev);
+	void	(*HW_set_clock)(struct device *dev);
+	void	*HW_privdata;
+	};
+
+struct comx_debugflags_struct {
+	char *name;
+	int  value;
+	};
+
+#define	COMX_ROOT_DIR_NAME	"comx"
+
+#define	FILENAME_HARDWARE	"boardtype"
+#define FILENAME_HARDWARELIST	"boardtypes"
+#define FILENAME_PROTOCOL	"protocol"
+#define FILENAME_PROTOCOLLIST	"protocols"
+#define FILENAME_DEBUG		"debug"
+#define FILENAME_CLOCK		"clock"
+#define	FILENAME_STATUS		"status"
+#define	FILENAME_IO		"io"
+#define FILENAME_IRQ		"irq"
+#define	FILENAME_KEEPALIVE	"keepalive"
+#define FILENAME_LINEUPDELAY	"lineup_delay"
+#define FILENAME_CHANNEL	"channel"
+#define FILENAME_FIRMWARE	"firmware"
+#define FILENAME_MEMADDR	"memaddr"
+#define	FILENAME_TWIN		"twin"
+#define FILENAME_T1		"t1"
+#define FILENAME_T2		"t2"
+#define FILENAME_N2		"n2"
+#define FILENAME_WINDOW		"window"
+#define FILENAME_MODE		"mode"
+#define	FILENAME_DLCI		"dlci"
+#define	FILENAME_MASTER		"master"
+#ifdef	CONFIG_COMX_DEBUG_RAW
+#define	FILENAME_RAW		"raw"
+#endif
+
+#define PROTONAME_NONE		"none"
+#define HWNAME_NONE		"none"
+#define KEEPALIVE_OFF		"off"
+
+#define FRAME_ACCEPTED		0		/* sending and xmitter busy */
+#define FRAME_DROPPED		1
+#define FRAME_ERROR		2		/* xmitter error */
+#define	FRAME_QUEUED		3		/* sending but more can come */
+
+#define	LINE_UP			1		/* Modem UP */
+#define PROTO_UP		2
+#define PROTO_LOOP		4
+
+#define	HW_OPEN			1
+#define	LINE_OPEN		2
+#define FW_LOADED		4
+#define IRQ_ALLOCATED		8
+
+#define DEBUG_COMX_RX		2
+#define	DEBUG_COMX_TX		4
+#define	DEBUG_HW_TX		16
+#define	DEBUG_HW_RX		32
+#define	DEBUG_HDLC_KEEPALIVE	64
+#define	DEBUG_COMX_PPP		128
+#define DEBUG_COMX_LAPB		256
+#define	DEBUG_COMX_DLCI		512
+
+#define	DEBUG_PAGESIZE		3072
+#define DEFAULT_DEBUG_SIZE	4096
+#define	DEFAULT_LINEUP_DELAY	1
+#define	FILE_PAGESIZE		3072
+
+#ifndef	COMX_PPP_MAJOR
+#define	COMX_PPP_MAJOR		88
+#endif
+
+
+#ifndef min
+#define min(a,b)		((a) > (b) ? (b) : (a))
+#endif
+#ifndef max
+#define max(a,b)		((a) > (b) ? (a) : (b))
+#endif
+
+
+#define COMX_CHANNEL(dev) ((struct comx_channel*)dev->priv)
+
+#define TWIN(dev) (COMX_CHANNEL(dev)->twin)
+
+
+#ifndef byte
+typedef u8	byte;
+#endif
+#ifndef word
+typedef u16	word;
+#endif
+
+#ifndef	SEEK_SET
+#define	SEEK_SET	0
+#endif
+#ifndef	SEEK_CUR
+#define	SEEK_CUR	1
+#endif
+#ifndef	SEEK_END
+#define	SEEK_END	2
+#endif
+
+extern struct proc_dir_entry comx_root_dir;
+
+extern int	comx_register_hardware(struct comx_hardware *comx_hw);
+extern int	comx_unregister_hardware(char *name);
+extern int	comx_register_protocol(struct comx_protocol *comx_line);
+extern int	comx_unregister_protocol(char *name);
+
+extern int	comx_rx(struct device *dev, struct sk_buff *skb);
+extern void	comx_status(struct device *dev, int status);
+extern void	comx_lineup_func(unsigned long d);
+
+extern int	comx_debug(struct device *dev, char *fmt, ...);
+extern int	comx_debug_skb(struct device *dev, struct sk_buff *skb, char *msg);
+extern int	comx_debug_bytes(struct device *dev, unsigned char *bytes, int len,
+		char *msg);
+extern int	comx_strcasecmp(const char *cs, const char *ct);
+
+extern struct inode_operations comx_normal_inode_ops;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/comxhw.h linux.14p16/drivers/net/comxhw.h
--- linux.vanilla/drivers/net/comxhw.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/comxhw.h	Thu Dec  9 15:33:37 1999
@@ -0,0 +1,112 @@
+/*
+ * Defines for comxhw.c
+ *
+ * Original authors:  Arpad Bakay <bakay.arpad@synergon.hu>,
+ *                    Peter Bajan <bajan.peter@synergon.hu>,
+ * Previous maintainer: Tivadar Szemethy <tiv@itc.hu>
+ * Current maintainer: Gergely Madarasz <gorgo@itc.hu>
+ *
+ * Copyright (C) 1995-1999 ITConsult-Pro Co. <info@itc.hu>
+ *
+ * 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.
+ *
+ */
+
+#define	LOCOMX_IO_EXTENT	8
+#define COMX_IO_EXTENT		4
+#define	HICOMX_IO_EXTENT	16
+
+#define COMX_MAX_TX_SIZE	1600
+
+#define COMX_JAIL_OFFSET	0xffff
+#define COMX_JAIL_VALUE		0xfe
+#define	COMX_MEMORY_SIZE	65536
+#define HICOMX_MEMORY_SIZE	16384
+#define COMX_MEM_MIN		0xa0000
+#define COMX_MEM_MAX		0xf0000
+
+#define	COMX_DEFAULT_IO		0x360
+#define	COMX_DEFAULT_IRQ	10
+#define	COMX_DEFAULT_MEMADDR	0xd0000
+#define	HICOMX_DEFAULT_IO	0x320
+#define	HICOMX_DEFAULT_IRQ	10
+#define	HICOMX_DEFAULT_MEMADDR	0xd0000
+#define	LOCOMX_DEFAULT_IO	0x368
+#define	LOCOMX_DEFAULT_IRQ	7
+
+#define MAX_CHANNELNO		2
+
+#define	COMX_CHANNEL_OFFSET	0x2000
+
+#define COMX_ENABLE_BOARD_IT    0x40
+#define COMX_BOARD_RESET       	0x20
+#define COMX_ENABLE_BOARD_MEM   0x10
+#define COMX_DISABLE_BOARD_MEM  0
+#define COMX_DISABLE_ALL	0x00
+
+#define HICOMX_DISABLE_ALL	0x00
+#define HICOMX_ENABLE_BOARD_MEM	0x02
+#define HICOMX_DISABLE_BOARD_MEM 0x0
+#define HICOMX_BOARD_RESET	0x01
+#define HICOMX_PRG_MEM		4
+#define HICOMX_DATA_MEM		0
+#define HICOMX_ID_BYTE		0x55
+
+#define CMX_ID_BYTE		0x31
+#define COMX_CLOCK_CONST	8000
+
+#define	LINKUP_READY		3
+
+#define	OFF_FW_L1_ID	0x01e	 /* ID bytes */
+#define OFF_FW_L2_ID	0x1006
+#define	FW_L1_ID_1	0xab
+#define FW_L1_ID_2_COMX		0xc0
+#define FW_L1_ID_2_HICOMX	0xc1
+#define	FW_L2_ID_1	0xab
+
+#define OFF_A_L2_CMD     0x130   /* command register for L2 */
+#define OFF_A_L2_CMDPAR  0x131   /* command parameter byte */
+#define OFF_A_L1_STATB   0x122   /* stat. block for L1 */
+#define OFF_A_L1_ABOREC  0x122   /* receive ABORT counter */
+#define OFF_A_L1_OVERRUN 0x123   /* receive overrun counter */
+#define OFF_A_L1_CRCREC  0x124   /* CRC error counter */
+#define OFF_A_L1_BUFFOVR 0x125   /* buffer overrun counter */
+#define OFF_A_L1_PBUFOVR 0x126   /* priority buffer overrun counter */
+#define OFF_A_L1_MODSTAT 0x127   /* current state of modem ctrl lines */
+#define OFF_A_L1_STATE   0x127   /* end of stat. block for L1 */
+#define OFF_A_L1_TXPC    0x128   /* Tx counter for the PC */
+#define OFF_A_L1_TXZ80   0x129   /* Tx counter for the Z80 */
+#define OFF_A_L1_RXPC    0x12a   /* Rx counter for the PC */
+#define OFF_A_L1_RXZ80   0x12b   /* Rx counter for the Z80 */
+#define OFF_A_L1_REPENA  0x12c   /* IT rep disable */
+#define OFF_A_L1_CHNR    0x12d   /* L1 channel logical number */
+#define OFF_A_L1_CLKINI  0x12e   /* Timer Const */
+#define OFF_A_L2_LINKUP	 0x132	 /* Linkup byte */
+#define OFF_A_L2_DAV	 0x134   /* Rx DAV */
+#define OFF_A_L2_RxBUFP  0x136	 /* Rx buff relative to membase */
+#define OFF_A_L2_TxEMPTY 0x138   /* Tx Empty */
+#define OFF_A_L2_TxBUFP  0x13a   /* Tx Buf */
+#define OFF_A_L2_NBUFFS	 0x144	 /* Number of buffers to fetch */
+
+#define OFF_A_L2_SABMREC 0x164	 /* LAPB no. of SABMs received */
+#define OFF_A_L2_SABMSENT 0x165	 /* LAPB no. of SABMs sent */
+#define OFF_A_L2_REJREC  0x166	 /* LAPB no. of REJs received */
+#define OFF_A_L2_REJSENT 0x167	 /* LAPB no. of REJs sent */
+#define OFF_A_L2_FRMRREC 0x168	 /* LAPB no. of FRMRs received */
+#define OFF_A_L2_FRMRSENT 0x169	 /* LAPB no. of FRMRs sent */
+#define OFF_A_L2_PROTERR 0x16A	 /* LAPB no. of protocol errors rec'd */
+#define OFF_A_L2_LONGREC 0x16B	 /* LAPB no. of long frames */
+#define OFF_A_L2_INVNR   0x16C	 /* LAPB no. of invalid N(R)s rec'd */
+#define OFF_A_L2_UNDEFFR 0x16D	 /* LAPB no. of invalid frames */
+
+#define	OFF_A_L2_T1	0x174	 /* T1 timer */
+#define	OFF_A_L2_ADDR	0x176	 /* DCE = 1, DTE = 3 */
+
+#define	COMX_CMD_INIT	1
+#define COMX_CMD_EXIT	2
+#define COMX_CMD_OPEN	16
+#define COMX_CMD_CLOSE	17
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/hamradio/Config.in linux.14p16/drivers/net/hamradio/Config.in
--- linux.vanilla/drivers/net/hamradio/Config.in	Sat Aug 14 02:27:29 1999
+++ linux.14p16/drivers/net/hamradio/Config.in	Thu Dec  9 15:33:27 1999
@@ -11,12 +11,12 @@
   bool '   support for TRX that feedback the tx signal to rx' CONFIG_SCC_TRXECHO
 fi
     
-tristate 'BAYCOM ser12 fullduplex driver for AX.25' CONFIG_BAYCOM_SER_FDX
-tristate 'BAYCOM ser12 halfduplex driver for AX.25' CONFIG_BAYCOM_SER_HDX
-dep_tristate 'BAYCOM picpar and par96 driver for AX.25' CONFIG_BAYCOM_PAR $CONFIG_PARPORT
-dep_tristate 'BAYCOM epp driver for AX.25' CONFIG_BAYCOM_EPP $CONFIG_PARPORT
+dep_tristate 'BAYCOM ser12 fullduplex driver for AX.25' CONFIG_BAYCOM_SER_FDX $CONFIG_AX25
+dep_tristate 'BAYCOM ser12 halfduplex driver for AX.25' CONFIG_BAYCOM_SER_HDX $CONFIG_AX25
+dep_tristate 'BAYCOM picpar and par96 driver for AX.25' CONFIG_BAYCOM_PAR $CONFIG_PARPORT $CONFIG_AX25
+dep_tristate 'BAYCOM epp driver for AX.25' CONFIG_BAYCOM_EPP $CONFIG_PARPORT $CONFIG_AX25
 
-tristate 'Soundcard modem driver' CONFIG_SOUNDMODEM
+dep_tristate 'Soundcard modem driver' CONFIG_SOUNDMODEM $CONFIG_AX25
 if [ "$CONFIG_SOUNDMODEM" != "n" ]; then
   bool '   soundmodem support for Soundblaster and compatible cards' CONFIG_SOUNDMODEM_SBC
   bool '   soundmodem support for WSS and Crystal cards' CONFIG_SOUNDMODEM_WSS
@@ -29,4 +29,4 @@
   bool '   soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600
 fi
 
-tristate 'YAM driver for AX.25' CONFIG_YAM
+dep_tristate 'YAM driver for AX.25' CONFIG_YAM $CONFIG_AX25
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/hamradio/yam.c linux.14p16/drivers/net/hamradio/yam.c
--- linux.vanilla/drivers/net/hamradio/yam.c	Sat Aug 14 02:27:29 1999
+++ linux.14p16/drivers/net/hamradio/yam.c	Thu Dec  9 15:33:30 1999
@@ -894,10 +894,12 @@
 }
 
 #ifdef CONFIG_INET
+
 #ifndef PROC_NET_YAM
 #define PROC_NET_YAM (PROC_NET_LAST+10)		/* Sorry again... */
 #endif
 
+#ifdef CONFIG_PROC_FS
 struct proc_dir_entry yam_proc_dir_entry =
 {
 	PROC_NET_YAM, 3, "yam", S_IFREG | S_IRUGO, 1, 0, 0, 0,
@@ -906,6 +908,10 @@
 
 #define yam_net_procfs_init()   proc_net_register(&yam_proc_dir_entry);
 #define yam_net_procfs_remove() proc_net_unregister(PROC_NET_YAM);
+#else
+#define yam_net_procfs_init()
+#define yam_net_procfs_remove()
+#endif
 #else
 #define yam_net_procfs_init()
 #define yam_net_procfs_remove()
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/hscx.h linux.14p16/drivers/net/hscx.h
--- linux.vanilla/drivers/net/hscx.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/hscx.h	Thu Dec  9 15:33:37 1999
@@ -0,0 +1,103 @@
+#define	HSCX_MTU	1600
+
+#define	HSCX_ISTA	0x00
+#define HSCX_MASK	0x00
+#define HSCX_STAR	0x01
+#define HSCX_CMDR	0x01
+#define HSCX_MODE	0x02
+#define HSCX_TIMR	0x03
+#define HSCX_EXIR	0x04
+#define HSCX_XAD1	0x04
+#define HSCX_RBCL	0x05
+#define HSCX_SAD2	0x05
+#define HSCX_RAH1	0x06
+#define HSCX_RSTA	0x07
+#define HSCX_RAH2	0x07
+#define HSCX_RAL1	0x08
+#define HSCX_RCHR	0x09
+#define HSCX_RAL2	0x09
+#define HSCX_XBCL	0x0a
+#define HSCX_BGR	0x0b
+#define HSCX_CCR2	0x0c
+#define HSCX_RBCH	0x0d
+#define HSCX_XBCH	0x0d
+#define HSCX_VSTR	0x0e
+#define HSCX_RLCR	0x0e
+#define HSCX_CCR1	0x0f
+#define HSCX_FIFO	0x1e
+
+#define HSCX_HSCX_CHOFFS	0x400
+#define HSCX_SEROFFS	0x1000
+
+#define HSCX_RME	0x80
+#define HSCX_RPF	0x40
+#define HSCX_RSC	0x20
+#define HSCX_XPR	0x10
+#define HSCX_TIN	0x08
+#define HSCX_ICA	0x04
+#define HSCX_EXA	0x02
+#define HSCX_EXB	0x01
+
+#define HSCX_XMR	0x80
+#define HSCX_XDU	0x40
+#define HSCX_EXE	0x40
+#define HSCX_PCE	0x20
+#define HSCX_RFO	0x10
+#define HSCX_CSC	0x08
+#define HSCX_RFS	0x04
+
+#define HSCX_XDOV	0x80
+#define HSCX_XFW	0x40
+#define HSCX_XRNR	0x20
+#define HSCX_RRNR	0x10
+#define HSCX_RLI	0x08
+#define HSCX_CEC	0x04
+#define HSCX_CTS	0x02
+#define HSCX_WFA	0x01
+
+#define HSCX_RMC	0x80
+#define HSCX_RHR	0x40
+#define HSCX_RNR	0x20
+#define HSCX_XREP	0x20
+#define HSCX_STI	0x10
+#define HSCX_XTF	0x08
+#define HSCX_XIF	0x04
+#define HSCX_XME	0x02
+#define HSCX_XRES	0x01
+
+#define HSCX_AUTO	0x00
+#define HSCX_NONAUTO	0x40
+#define HSCX_TRANS	0x80
+#define HSCX_XTRANS	0xc0
+#define HSCX_ADM16	0x20
+#define HSCX_ADM8	0x00
+#define HSCX_TMD_EXT	0x00
+#define HSCX_TMD_INT	0x10
+#define HSCX_RAC	0x08
+#define HSCX_RTS	0x04
+#define HSCX_TLP	0x01
+
+#define HSCX_VFR	0x80
+#define HSCX_RDO	0x40
+#define HSCX_CRC	0x20
+#define HSCX_RAB	0x10
+
+#define HSCX_CIE	0x04
+#define HSCX_RIE	0x02
+
+#define HSCX_DMA	0x80
+#define HSCX_NRM	0x40
+#define HSCX_CAS	0x20
+#define HSCX_XC	0x10
+
+#define HSCX_OV	0x10
+
+#define HSCX_CD	0x80
+
+#define HSCX_RC	0x80
+
+#define HSCX_PU	0x80
+#define HSCX_NRZ	0x00
+#define HSCX_NRZI	0x40
+#define HSCX_ODS	0x10
+#define HSCX_ITF	0x08
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/lance.c linux.14p16/drivers/net/lance.c
--- linux.vanilla/drivers/net/lance.c	Sat Aug 14 02:27:29 1999
+++ linux.14p16/drivers/net/lance.c	Thu Dec  9 15:33:26 1999
@@ -40,12 +40,16 @@
     8/20/96 Fixed 7990 autoIRQ failure and reversed unneeded alignment -djb
     v1.12 10/27/97 Module support -djb
     v1.14  2/3/98 Module support modified, made PCI support optional -djb
+    v1.15 5/27/99 Fixed bug in the cleanup_module(). dev->priv was freed
+                  before unregister_netdev() which caused NULL pointer
+                  reference later in the chain (in rtnetlink_fill_ifinfo())
+                  -- Mika Kuoppala <miku@iki.fi>
     
     Forward ported v1.14 to 2.1.129, merged the PCI and misc changes from
     the 2.1 version of the old driver - Alan Cox
 */
 
-static const char *version = "lance.c:v1.14ac 1998/11/20 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
+static const char *version = "lance.c:v1.15ac 1999/11/13 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -349,11 +353,11 @@
 	for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
 		struct device *dev = &dev_lance[this_dev];
 		if (dev->priv != NULL) {
-			kfree(dev->priv);
-			dev->priv = NULL;
+			unregister_netdev(dev);	
 			free_dma(dev->dma);
 			release_region(dev->base_addr, LANCE_TOTAL_SIZE);
-			unregister_netdev(dev);
+			kfree(dev->priv);
+			dev->priv = NULL;
 		}
 	}
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/mixcom.h linux.14p16/drivers/net/mixcom.h
--- linux.vanilla/drivers/net/mixcom.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/mixcom.h	Thu Dec  9 15:33:37 1999
@@ -0,0 +1,35 @@
+/*
+ * Defines for the mixcom board
+ *
+ * Author: Gergely Madarasz <gorgo@itc.hu>
+ *
+ * Copyright (C) 1999 ITConsult-Pro Co. <info@itc.hu>
+ *
+ * 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.
+ *
+ */
+
+#define	MIXCOM_IO_EXTENT	0x20
+
+#define	MIXCOM_DEFAULT_IO	0x180
+#define	MIXCOM_DEFAULT_IRQ	5
+
+#define MIXCOM_ID		0x11
+#define MIXCOM_SERIAL_OFFSET	0x1000
+#define MIXCOM_CHANNEL_OFFSET	0x400
+#define MIXCOM_IT_OFFSET	0xc14
+#define MIXCOM_STATUS_OFFSET	0xc14
+#define MIXCOM_ID_OFFSET	0xc10
+#define MIXCOM_ON		0x1
+#define MIXCOM_OFF		0x0
+
+/* Status register bits */
+
+#define MIXCOM_CTSB		0x1
+#define MIXCOM_CTSA		0x2
+#define MIXCOM_CHANNELNO	0x20
+#define MIXCOM_POWERFAIL	0x40
+#define MIXCOM_BOOT		0x80
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/myri_sbus.c linux.14p16/drivers/net/myri_sbus.c
--- linux.vanilla/drivers/net/myri_sbus.c	Fri Mar 26 21:57:41 1999
+++ linux.14p16/drivers/net/myri_sbus.c	Thu Dec  9 15:33:30 1999
@@ -222,11 +222,11 @@
 	}
 
 	if(i == 5000)
-		printk("myricom: Chip would not reset after firmware load.\n");
+		printk(KERN_ERR "myricom: Chip would not reset after firmware load.\n");
 
 	i = myri_do_handshake(mp);
 	if(i)
-		printk("myricom: Handshake with LANAI failed.\n");
+		printk(KERN_ERR "myricom: Handshake with LANAI failed.\n");
 
 	if(mp->eeprom.cpuvers == CPUVERS_4_0)
 		mp->lregs->vers = 0;
@@ -575,7 +575,7 @@
 			return 1;
 		} else {
 			DTX(("resetting, return 0\n"));
-			printk("%s: transmit timed out, resetting\n", dev->name);
+			printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
 			mp->enet_stats.tx_errors++;
 			myri_init(mp, in_interrupt());
 			dev->tbusy = 0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/ncr885_debug.h linux.14p16/drivers/net/ncr885_debug.h
--- linux.vanilla/drivers/net/ncr885_debug.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/ncr885_debug.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,54 @@
+#ifndef _H_NCR885_DEBUG
+#define _H_NCR885_DEBUG
+
+struct ncr885e_regs {
+  unsigned long tx_status;
+  unsigned long rx_status;
+  unsigned long mac_config;
+  unsigned long tx_control;
+  unsigned long rx_control;
+  unsigned long tx_cmd_ptr;
+  unsigned long rx_cmd_ptr;
+  unsigned long int_status;
+};
+
+#ifndef __KERNEL__
+
+struct ncr885e_private {
+
+  struct dbdma_cmd *head;
+  struct dbdma_cmd *tx_cmds;
+  struct dbdma_cmd *rx_cmds;
+  struct dbdma_cmd *stop_cmd;
+
+  struct sk_buff *tx_skbufs[NR_TX_RING];
+  struct sk_buff *rx_skbufs[NR_RX_RING];
+
+  int rx_current;
+  int rx_dirty;
+
+  int tx_dirty;
+  int tx_current;
+
+  unsigned short tx_status[NR_TX_RING];
+
+  unsigned char tx_fullup;
+  unsigned char tx_active;
+  
+  struct net_device_stats  stats;
+
+  struct device *dev;
+
+  struct timer_list tx_timeout;
+  int timeout_active;
+
+  spinlock_t lock;
+};
+
+#endif /* __KERNEL__ */
+
+
+#define NCR885E_GET_PRIV   _IOR('N',1,sizeof( struct ncr885e_private ))
+#define NCR885E_GET_REGS   _IOR('N',2,sizeof( struct ncr885e_regs ))
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/ncr885e.c linux.14p16/drivers/net/ncr885e.c
--- linux.vanilla/drivers/net/ncr885e.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/ncr885e.c	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,1458 @@
+/*
+ *  An Ethernet driver for the dual-function NCR 53C885 SCSI/Ethernet
+ *  controller.
+ *
+ *
+ *  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.
+ *
+ */
+
+static const char *version =
+"ncr885e.c:v0.8 11/30/98 dan@synergymicro.com\n";
+
+#include <linux/config.h>
+
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#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/timer.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+#include <asm/uaccess.h>
+
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "ncr885e.h"
+#include "ncr885_debug.h"
+
+static const char *chipname = "ncr885e";
+
+/* debugging flags */
+#if 0
+#define DEBUG_FUNC    0x0001
+#define DEBUG_PACKET  0x0002
+#define DEBUG_CMD     0x0004
+#define DEBUG_CHANNEL 0x0008
+#define DEBUG_INT     0x0010
+#define DEBUG_RX      0x0020
+#define DEBUG_TX      0x0040
+#define DEBUG_DMA     0x0080
+#define DEBUG_MAC     0x0100
+#define DEBUG_DRIVER  0x0200
+#define DEBUG_ALL     0x1fff
+#endif
+
+#ifdef DEBUG_NCR885E
+#define NCR885E_DEBUG   0
+#else
+#define NCR885E_DEBUG   0
+#endif
+
+/* The 885's Ethernet PCI device id. */
+#ifndef PCI_DEVICE_ID_NCR_53C885_ETHERNET
+#define PCI_DEVICE_ID_NCR_53C885_ETHERNET  0x0701
+#endif
+
+#define NR_RX_RING    8
+#define NR_TX_RING    8
+#define MAX_TX_ACTIVE (NR_TX_RING-1)
+#define NCMDS_TX      NR_TX_RING
+
+#define RX_BUFLEN     (ETH_FRAME_LEN + 8)
+#define TX_TIMEOUT    5*HZ
+
+#define NCR885E_TOTAL_SIZE 0xe0
+
+#define TXSR          (1<<6)   /* tx: xfer status written */
+#define TXABORT       (1<<7)   /* tx: abort */
+#define EOP           (1<<7)   /* rx: end of packet written to buffer */
+
+int ncr885e_debug = NCR885E_DEBUG;
+static int print_version = 0;
+
+struct ncr885e_private {
+
+	/* preserve a 1-1 marking with buffs */
+	struct dbdma_cmd *head;
+	struct dbdma_cmd *tx_cmds;
+	struct dbdma_cmd *rx_cmds;
+	struct dbdma_cmd *stop_cmd;
+
+	struct sk_buff *tx_skbufs[NR_TX_RING];
+	struct sk_buff *rx_skbufs[NR_RX_RING];
+
+	int rx_current;
+	int rx_dirty;
+
+	int tx_dirty;
+	int tx_current;
+
+	unsigned short tx_status[NR_TX_RING];
+
+	unsigned char tx_fullup;
+	unsigned char tx_active;
+  
+	struct net_device_stats  stats;
+
+	struct device *dev;
+
+	struct timer_list tx_timeout;
+	int timeout_active;
+
+	spinlock_t lock;
+};
+
+#ifdef MODULE
+static struct device *root_dev = NULL;
+#endif
+
+
+static int ncr885e_open( struct device *dev );
+static int ncr885e_close( struct device *dev );
+static void ncr885e_rx( struct device *dev );
+static void ncr885e_tx( struct device *dev );
+static int ncr885e_probe1( struct device *dev, unsigned long ioaddr,
+			   unsigned char irq );
+static int ncr885e_xmit_start( struct sk_buff *skb, struct device *dev );
+static struct net_device_stats *ncr885e_stats( struct device *dev );
+static void ncr885e_set_multicast( struct device *dev );
+static void ncr885e_config( struct device *dev );
+static int ncr885e_set_address( struct device *dev, void *addr );
+static void ncr885e_interrupt( int irq, void *dev_id, struct pt_regs *regs );
+static void show_dbdma_cmd( volatile struct dbdma_cmd *cmd );
+#if 0
+static int read_eeprom( unsigned int ioadddr, int location );
+#endif
+
+#ifdef NCR885E_DEBUG_MII
+static void show_mii( unsigned long ioaddr );
+static int read_mii( unsigned long ioaddr, int reg );
+static void write_mii( unsigned long ioaddr, int reg, int data );
+#endif /* NCR885E_DEBUG_MII */
+
+#define TX_RESET_FLAGS    (TX_CHANNEL_RUN|TX_CHANNEL_PAUSE|TX_CHANNEL_WAKE)
+#define RX_RESET_FLAGS    (RX_CHANNEL_RUN|RX_CHANNEL_PAUSE|RX_CHANNEL_WAKE)
+
+
+#if 0
+static int
+debug_ioctl( struct device *dev, struct ifreq *req, int cmd )
+{
+	unsigned long ioaddr = dev->base_addr;
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	struct ncr885e_private *data;
+	struct ncr885e_regs *regs;
+	unsigned long flags;
+
+	union {
+		struct ncr885e_regs dump;
+		struct ncr885e_private priv;    
+	} temp;
+
+	switch( cmd ) {
+
+		/* dump the rx ring status */
+	case NCR885E_GET_PRIV:
+
+		data = (struct ncr885e_private *) &req->ifr_data;    
+
+		if ( verify_area(VERIFY_WRITE, &req->ifr_data,
+				 sizeof( struct ncr885e_private )))
+			return -EFAULT;
+
+		memcpy((char *) &temp.priv, sp, sizeof( struct ncr885e_private ));
+		copy_to_user( data, (char *) &temp.priv, sizeof( struct ncr885e_private));
+		break;
+
+	case NCR885E_GET_REGS:
+
+		regs = (struct ncr885e_regs *) &req->ifr_data;
+  
+		if ( verify_area( VERIFY_WRITE, &req->ifr_data,
+				  sizeof( struct ncr885e_regs )))
+			return -EFAULT;
+
+		spin_lock_irqsave( &sp->lock, flags ); 
+
+		temp.dump.tx_status = inl( ioaddr + TX_CHANNEL_STATUS );
+		temp.dump.rx_status = inl( ioaddr + RX_CHANNEL_STATUS );
+		temp.dump.mac_config = inl( ioaddr + MAC_CONFIG );
+		temp.dump.tx_control = inl( ioaddr + TX_CHANNEL_CONTROL );
+		temp.dump.rx_control = inl( ioaddr + RX_CHANNEL_CONTROL );
+		temp.dump.tx_cmd_ptr = inl( ioaddr + TX_CMD_PTR_LO );
+		temp.dump.rx_cmd_ptr = inl( ioaddr + RX_CMD_PTR_LO );
+		temp.dump.int_status = inl( ioaddr + INTERRUPT_STATUS_REG );
+
+		spin_unlock_irqrestore( &sp->lock, flags );
+		copy_to_user( regs, (char *) &temp.dump, sizeof( struct ncr885e_regs ));
+
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+#endif
+
+/*  Enable interrupts on the 53C885 */
+static inline void
+ncr885e_enable( struct device *dev )
+
+{
+	unsigned long ioaddr = dev->base_addr;
+	unsigned short reg;
+
+	reg = inw(ioaddr + INTERRUPT_ENABLE);
+	outw(reg | INTERRUPT_INTE, ioaddr + INTERRUPT_ENABLE);
+}
+
+/*  Disable interrupts on the 53c885 */
+static inline void
+ncr885e_disable( struct device *dev )
+
+{
+	unsigned long ioaddr = dev->base_addr;
+	unsigned short reg;
+
+	reg = inw( ioaddr + INTERRUPT_ENABLE );
+	outw( reg & ~INTERRUPT_INTE, ioaddr + INTERRUPT_ENABLE );
+}
+
+
+static inline void
+ncr885e_reset( struct device *dev )
+
+{
+	unsigned short reg;  
+	unsigned long cntl;
+	int i;
+	unsigned long ioaddr = dev->base_addr;
+
+	if (ncr885e_debug > 1)
+		printk( KERN_INFO "%s: Resetting 53C885...\n", dev->name );
+
+	/* disable interrupts on the 53C885 */
+	ncr885e_disable( dev );
+  
+	/* disable rx in the MAC */
+	reg = inw( ioaddr + MAC_CONFIG );
+	outw( reg & ~MAC_CONFIG_RXEN, ioaddr + MAC_CONFIG );
+  
+	for( i=0; i < 100; i++ ) {
+
+		if ( !(inw( ioaddr + MAC_CONFIG ) & MAC_CONFIG_RXEN ))
+			break;
+		udelay( 10 );
+	}
+  
+	reg = inw( ioaddr + MAC_CONFIG );
+	outw( reg | MAC_CONFIG_SRST, ioaddr + MAC_CONFIG );
+	outw( reg, ioaddr + MAC_CONFIG );
+
+	/* disable both rx and tx DBDMA channels */
+	outl( TX_DBDMA_ENABLE << 16, ioaddr + TX_CHANNEL_CONTROL );
+	outl( RX_DBDMA_ENABLE << 16, ioaddr + RX_CHANNEL_CONTROL );
+
+	for( i=0; i < 100; i++ ) {
+    
+		if ( !(inw( ioaddr + TX_CHANNEL_STATUS ) & TX_DBDMA_ENABLE ) &&
+		     !(inw( ioaddr + RX_CHANNEL_STATUS ) & RX_DBDMA_ENABLE ))
+			break;
+		udelay( 10 );
+	}
+
+	/* perform a "software reset" */
+	cntl = inl( ioaddr + DBDMA_CONTROL );
+	outl( cntl | DBDMA_SRST, ioaddr + DBDMA_CONTROL );
+
+	for( i=0; i < 100; i++ ) {
+  
+		if ( !(inl( ioaddr + DBDMA_CONTROL ) & DBDMA_SRST ))
+			break;
+		udelay( 10 );
+	}
+
+	/* books says that a software reset should be done to the MAC, as
+	   well.  This true??? */
+
+	if (ncr885e_debug > 3) 
+		printk( KERN_INFO "%s: reset complete\n", dev->name );
+
+}
+
+
+/*  configure the 53C885 chip.
+
+    The DBDMA command descriptors on the 53C885 can be programmed to
+    branch, interrupt or pause conditionally or always by using the
+    interrupt, branch and wait select registers.  */
+
+static void
+ncr885e_config( struct device *dev )
+
+{
+	unsigned long ioaddr = dev->base_addr;
+
+	if (ncr885e_debug > 3)
+		printk( KERN_INFO "%s: Configuring 53C885.\n", dev->name );
+
+	ncr885e_reset( dev );
+ 
+	/* The 53C885 can be programmed to perform conditional DBDMA
+	   branches, interrupts or waits.
+  
+	   Neither channel makes use of "wait", as it requires that the
+	   DBDMA engine to be restarted.  Don't go there.  The rx channel
+	   will branch upon the successful reception of a packet ('EOP' in
+	   the xfer_status field).  The branch address is to the STOP
+	   DBDMA command descriptor, which shuts down the rx channel until
+	   the interrupt is serviced.   */
+     
+	/* cause tx channel to stop after "status received" */
+	outl( 0, ioaddr + TX_INT_SELECT );
+	outl( (TX_WAIT_STAT_RECV << 16) | TX_WAIT_STAT_RECV, 
+	      ioaddr + TX_WAIT_SELECT );
+	outl( 0, ioaddr + TX_BRANCH_SELECT );
+
+	/* cause rx channel to branch to the STOP descriptor on "End-of-Packet" */
+#if 0
+	outl( (RX_INT_SELECT_EOP << 16) | RX_INT_SELECT_EOP,
+	      ioaddr + RX_INT_SELECT );
+#else
+	outl( 0, ioaddr + RX_INT_SELECT );
+#endif
+#if 0
+	outl( 0, ioaddr + RX_WAIT_SELECT );
+#else
+	outl( (RX_WAIT_SELECT_EOP << 16) | RX_WAIT_SELECT_EOP, 
+	      ioaddr + RX_WAIT_SELECT );
+#endif
+#if 1
+	outl( 0, ioaddr + RX_BRANCH_SELECT );
+#else
+	outl( (RX_BRANCH_SELECT_EOP << 16) | RX_BRANCH_SELECT_EOP,
+	      ioaddr + RX_BRANCH_SELECT );
+#endif
+
+	/* configure DBDMA */
+	outl( (DBDMA_BE | DBDMA_DPMRLE | DBDMA_TDPCE |
+	       DBDMA_DDPE | DBDMA_TDPE |
+	       (DBDMA_BURST_4 << DBDMA_TX_BST_SHIFT) |
+	       (DBDMA_BURST_4 << DBDMA_RX_BST_SHIFT) |
+	       (DBDMA_TX_ARBITRATION_DEFAULT) |
+	       (DBDMA_RX_ARBITRATION_DEFAULT)), ioaddr + DBDMA_CONTROL );
+
+	outl( 0, ioaddr + TX_THRESHOLD );
+
+	/* disable MAC loopback */
+	outl( (MAC_CONFIG_ITXA | MAC_CONFIG_RXEN | MAC_CONFIG_RETRYL |
+	       MAC_CONFIG_PADEN | (0x18 << 16)),
+	      ioaddr + MAC_CONFIG );
+
+	/* configure MAC */
+	outl( (MAC_CONFIG_ITXA | MAC_CONFIG_RXEN | MAC_CONFIG_RETRYL |
+	       MAC_CONFIG_PADEN | ( 0x18 << 16)), ioaddr + MAC_CONFIG );
+
+	outw( (0x1018), ioaddr + NBTOB_INTP_GAP );
+
+	/* clear and enable interrupts */
+	inw( ioaddr + INTERRUPT_CLEAR );
+	ncr885e_enable( dev );
+
+	/* and enable them in the chip */
+	outl( (INTERRUPT_INTE|INTERRUPT_TX_MASK|INTERRUPT_RX_MASK)<<16,
+	      ioaddr + INTERRUPT_ENABLE - 2);
+
+	if (ncr885e_debug > 3)
+		printk( KERN_INFO "%s: 53C885 config complete.\n", dev->name );
+
+	return;
+}
+
+
+
+/*
+   transmit interrupt  */
+
+static void
+ncr885e_tx( struct device *dev )
+
+{
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	volatile struct dbdma_cmd *cp, *dp;
+	unsigned short txbits, xfer;
+	int i;
+
+	del_timer( &sp->tx_timeout );
+
+	if (ncr885e_debug > 3)
+		printk( KERN_INFO "%s: ncr885e_tx: active=%d, dirty=%d, current=%d\n", 
+			dev->name, sp->tx_active, sp->tx_dirty, sp->tx_current );
+
+	sp->timeout_active = 0;
+
+	i = sp->tx_dirty;
+	cp = sp->tx_cmds + (i*3);
+	dp = cp+1;
+	sp->tx_active--;
+
+	xfer = inw( &dp->xfer_status );
+	txbits = inw( &sp->tx_status[i] );
+
+	if (ncr885e_debug > 4) {
+		show_dbdma_cmd( cp );
+		show_dbdma_cmd( dp );
+	}
+
+	/* get xmit result */
+	txbits = inw( &sp->tx_status[i] );
+
+	if (ncr885e_debug > 3)
+		printk( KERN_INFO "%s: tx xfer=%04x, txbits=%04x\n", dev->name,
+			xfer, txbits );
+
+	/* look for any channel status (?) */
+	if ( xfer ) {
+
+		dev_kfree_skb( sp->tx_skbufs[i] );
+		mark_bh( NET_BH );
+
+		if ( txbits & TX_STATUS_TXOK ) {
+			sp->stats.tx_packets++;
+			sp->stats.tx_bytes += inw( &cp->req_count );
+		}
+
+		/* dropped packets */
+		if ( txbits & (TX_STATUS_TDLC|TX_STATUS_TDEC) ) {
+			sp->stats.tx_dropped++;
+		}
+
+		/* add the collisions */
+		sp->stats.collisions += ( txbits & 0x04 );
+
+	}
+
+	dev->tbusy = 0;
+  
+	return;
+}
+
+/*  rx interrupt handling */
+static void
+ncr885e_rx( struct device *dev )
+
+{
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	volatile struct dbdma_cmd *cp;
+	struct sk_buff *skb;
+	int i, nb;
+	unsigned short status;
+	unsigned char *data, *stats;
+	unsigned long rxbits, ioaddr = dev->base_addr;
+
+	i = sp->rx_current;
+	cp = sp->rx_cmds + (i*2);
+
+	if (ncr885e_debug > 3)
+		printk( KERN_INFO "%s: ncr885e_rx dirty=%d, current=%d (cp@%p)\n",
+			dev->name, sp->rx_dirty, sp->rx_current, cp );
+
+	nb = inw( &cp->req_count ) - inw( &cp->res_count );
+	status = inw( &cp->xfer_status );
+
+	if (ncr885e_debug > 3)
+		printk( KERN_INFO "%s: (rx %d) bytes=%d, xfer_status=%04x\n", 
+			dev->name, i, nb, status );
+
+	if ( status ) {
+
+		skb = sp->rx_skbufs[i];
+		data = skb->data;
+		stats = data + nb - 3;
+		rxbits = (stats[0]|stats[1]<<8|stats[2]<<16);
+  
+		if (ncr885e_debug > 3)
+			printk( KERN_INFO "  rx_bits=%06lx\n", rxbits );
+
+		skb->dev = dev;
+		skb_put( skb, nb-3 );
+		skb->protocol = eth_type_trans( skb, dev );
+		netif_rx( skb );
+		sp->rx_skbufs[i] = 0;
+
+		if ( rxbits & RX_STATUS_RXOK ) {
+			sp->stats.rx_packets++;
+			sp->stats.rx_bytes += nb;
+		}
+
+		if ( rxbits & RX_STATUS_MCAST )
+			sp->stats.multicast++;
+
+	}
+
+	sp->rx_dirty = sp->rx_current;
+
+	if ( ++sp->rx_current >= NR_RX_RING )
+		sp->rx_current = 0;
+
+	/* fix up the one we just trashed */
+	cp = sp->rx_cmds + (sp->rx_dirty * 2);
+
+	skb = dev_alloc_skb( RX_BUFLEN + 2 );
+	if ( skb != 0 ) {
+		skb_reserve( skb, 2 );
+		sp->rx_skbufs[sp->rx_dirty] = skb;
+	}
+
+	if (ncr885e_debug > 2)
+		printk( KERN_INFO "%s: ncr885e_rx: using ring index %d, filling cp @ %p\n", 
+			dev->name, sp->rx_current, cp );
+  
+	outw( RX_BUFLEN, &cp->req_count );
+	outw( 0, &cp->res_count );
+	data = skb->data;
+	outl( virt_to_bus( data ), &cp->phy_addr );
+	outw( 0, &cp->xfer_status );
+
+	cp = sp->rx_cmds + (sp->rx_current * 2);
+
+	/* restart rx DMA */
+	outl( virt_to_bus( cp ), ioaddr + RX_CMD_PTR_LO );
+	outl( (RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN,
+	      ioaddr + RX_CHANNEL_CONTROL );
+
+	return;
+}
+
+static void
+ncr885e_misc_ints( struct device *dev, unsigned short status )
+
+{
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	struct dbdma_cmd *cp;
+	unsigned long ioaddr = dev->base_addr;
+
+	if (ncr885e_debug > 1)
+		printk( KERN_INFO "miscellaneous interrupt handled; status=%02x\n", 
+			status );
+
+	/* various transmit errors */
+	if ( status & 
+	     (INTERRUPT_PPET | INTERRUPT_PBFT | INTERRUPT_IIDT) ) {
+
+		/* illegal instruction in tx dma */
+		if ( status & INTERRUPT_IIDT ) {
+
+			cp = (struct dbdma_cmd *) bus_to_virt( inl( ioaddr + TX_CMD_PTR_LO ));
+			printk( KERN_INFO "%s: tx illegal insn:\n", dev->name );
+			printk( KERN_INFO " tx DBDMA - cmd = %p, status = %04x\n", 
+				cp, inw( ioaddr + TX_CHANNEL_STATUS ));
+			printk( KERN_INFO " command = %04x, phy_addr=%08x, req_count=%04x\n",
+				inw( &cp->command ), inw( &cp->phy_addr ), inw( &cp->req_count ));
+		}
+
+		if ( status & INTERRUPT_PPET )
+			printk( KERN_INFO "%s: tx PCI parity error\n", dev->name );
+ 
+		if ( status & INTERRUPT_PBFT )
+			printk( KERN_INFO "%s: tx PCI bus fault\n", dev->name );
+	}
+
+	/* look for rx errors */
+	if ( status &
+	     (INTERRUPT_PPER | INTERRUPT_PBFR | INTERRUPT_IIDR)) {
+
+		/* illegal instruction in rx dma */
+		if ( status & INTERRUPT_IIDR ) {
+#if 0
+			cmd = inl( ioaddr + RX_CMD_PTR_LO );      
+#endif
+			printk( KERN_ERR "%s: rx illegal DMA instruction:\n", dev->name );
+			printk( KERN_ERR "    channel status=%04x,\n",
+				inl( ioaddr + RX_CHANNEL_STATUS ));
+#if 0
+			show_dbdma_cmd( bus_to_virt( inl( ioaddr + RX_CMD_PTR_LO )));
+			printk( KERN_ERR "    instr (%08x) %08x %08x %08x\n",
+				(int) cmd, cmd[0], cmd[1], cmd[2] );
+#endif
+		}
+
+		/* PCI parity error */
+		if ( status & INTERRUPT_PPER )
+			printk( KERN_INFO "%s: rx PCI parity error\n", dev->name );
+
+		if ( status & INTERRUPT_PBFR )
+			printk( KERN_INFO "%s: rx PCI bus fault\n", dev->name );
+
+		sp->stats.rx_errors++;
+	}
+
+	if ( status & INTERRUPT_WI ) {
+		printk( KERN_INFO "%s: link pulse\n", dev->name );
+	}
+
+	/* bump any counters */
+  
+
+	return;
+}
+
+static void
+ncr885e_interrupt( int irq, void *dev_id, struct pt_regs *regs )
+
+{
+	struct device  *dev = (struct device *) dev_id;
+	struct ncr885e_private *sp;
+	unsigned short status;
+	int ioaddr;
+
+	if ( dev == NULL ) {
+		printk( KERN_ERR "symba: Interrupt IRQ %d for unknown device\n", irq );
+		return;
+	}
+
+	ioaddr = dev->base_addr;
+	sp = (struct ncr885e_private *) dev->priv;
+	spin_lock( &sp->lock );
+  
+	if ( dev->interrupt ) {
+		printk( KERN_ERR "%s: Re-entering interrupt handler...\n", 
+			dev->name );
+	}
+
+	dev->interrupt = 1;
+	status = inw( ioaddr + INTERRUPT_CLEAR );
+
+	if (ncr885e_debug > 2)
+		printk( KERN_INFO "%s: 53C885 interrupt 0x%02x\n", dev->name, status );
+
+	/* handle non-tx and rx interrupts first */
+	if ( status & ~(INTERRUPT_DIT|INTERRUPT_DIR))
+		ncr885e_misc_ints( dev, status );
+
+	/* look for tx interrupt: more to transmit, DBDMA stopped, or tx done */
+	if ( ( status & INTERRUPT_DIT ) ) {
+
+		if (ncr885e_debug > 2)
+			printk( KERN_INFO "%s: tx int; int=%02x, chan stat=%02x\n", 
+				dev->name, status, inw( ioaddr + TX_CHANNEL_STATUS ));
+
+		/* turn off timer */
+		del_timer( &sp->tx_timeout );
+		sp->timeout_active = 0;
+
+		/* stop DMA */
+		outl( TX_DBDMA_ENABLE << 16, ioaddr + TX_CHANNEL_CONTROL );
+
+		ncr885e_tx( dev );
+	}
+
+	if ( status & INTERRUPT_DIR ) {
+
+		if ( ncr885e_debug > 2 )
+			printk( KERN_INFO "%s: rx interrupt; int=%02x, rx channel stat=%02x\n", 
+				dev->name, status, inw( ioaddr + RX_CHANNEL_STATUS ));
+
+		/* stop DMA */
+		outl( RX_DBDMA_ENABLE << 16, ioaddr + RX_CHANNEL_CONTROL );
+    
+		/* and handle the interrupt */
+		ncr885e_rx( dev );
+	}
+  
+	dev->interrupt = 0;
+	spin_unlock( &sp->lock );
+
+	return;
+}
+
+
+/*  doesn't set the address permanently, however... */
+static int 
+ncr885e_set_address( struct device *dev, void *addr )
+
+{
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	struct sockaddr *saddr = addr;
+	unsigned long  flags;
+	unsigned short reg[3];
+	unsigned char *ioaddr, *p;
+	int i;
+
+	memcpy( dev->dev_addr, saddr->sa_data, dev->addr_len );
+
+	p = (unsigned char *) dev->dev_addr;
+	printk( KERN_INFO "%s: setting new MAC address - ", dev->name );
+#if 0
+	for( p = (unsigned char *) dev->dev_addr, i=0; i < 6; i++, p++ ) 
+		printk("%c%2.2x", i ? ':' : ' ', *p );
+#endif
+
+
+	p = (unsigned char *) &reg;
+	for( i=0; i < 6; i++ )
+		p[i] = dev->dev_addr[i];
+
+#if 0
+	printk("%s: Setting new mac address - ", dev->name );
+	for( i=0; i < 6; i++ ) {
+		printk("%02x", i ? ':' : ' ', p[i] );
+	}
+
+	printk("\n");
+#endif
+
+	/* stop rx for the change */
+	outl( RX_DBDMA_ENABLE << 16, ioaddr + RX_CHANNEL_CONTROL );
+  
+	spin_lock_irqsave( &sp->lock, flags );
+
+	ioaddr = (unsigned char *) dev->base_addr;
+
+	for( i = 0; i < 3; i++ ) {
+		reg[i] = ((reg[i] & 0xff) << 8) | ((reg[i] >> 8) & 0xff);
+		printk("%04x ", reg[i] );
+		outw( reg[i], ioaddr + STATION_ADDRESS_0 + (i*2));
+	}
+	printk("\n");
+
+	spin_unlock_irqrestore( &sp->lock, flags );
+
+	/* restart rx */
+	outl((RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN, 
+	     ioaddr + RX_CHANNEL_CONTROL );
+
+	return 0;
+}
+
+static void 
+ncr885e_tx_timeout( unsigned long data )
+
+{
+	struct device *dev = (struct device *) data;
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	unsigned long flags, ioaddr;
+	int i;
+  
+	save_flags( flags );
+	cli();
+
+	ioaddr = dev->base_addr;
+	sp->timeout_active = 0;
+	i = sp->tx_dirty;
+
+	/* if we weren't active, bail... */
+	if ( sp->tx_active == 0 ) {
+		printk( KERN_INFO "%s: ncr885e_timeout...tx not active!\n", dev->name );
+		goto out;
+	}
+
+	printk( KERN_ERR "%s: 53C885 timed out.  Resetting...\n", dev->name );
+
+	/* disable rx and tx DMA */
+	outl( (TX_DBDMA_ENABLE << 16), ioaddr + TX_CHANNEL_CONTROL );
+	outl( (RX_DBDMA_ENABLE << 16), ioaddr + RX_CHANNEL_CONTROL );
+
+	/* reset the chip */
+	ncr885e_config( dev );
+	ncr885e_enable( dev );
+
+	/* clear the wedged skb in the tx ring */
+	sp->tx_active = 0;
+	++sp->stats.tx_errors;
+  
+	if ( sp->tx_skbufs[i] ) {
+		dev_kfree_skb( sp->tx_skbufs[i] );
+		sp->tx_skbufs[i] = 0;
+	}
+
+	/* start anew from the beginning of the ring buffer (why not?) */
+	sp->tx_current = 0;
+	dev->tbusy = 0;
+	mark_bh( NET_BH );
+
+	/* restart rx dma */
+	outl( (RX_DBDMA_ENABLE << 16) | RX_CHANNEL_RUN,
+	      ioaddr + RX_CHANNEL_CONTROL );  
+ out:
+
+	restore_flags( flags );
+}
+
+static inline void
+ncr885e_set_timeout( struct device *dev )
+
+{
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	if ( sp->timeout_active )
+		del_timer( &sp->tx_timeout );
+
+	sp->tx_timeout.expires = jiffies + TX_TIMEOUT;
+	sp->tx_timeout.function = ncr885e_tx_timeout;
+	sp->tx_timeout.data = (unsigned long) dev;
+	add_timer( &sp->tx_timeout );
+	sp->timeout_active = 1;
+	restore_flags( flags );
+}
+
+
+/*
+ *  The goal is to set up DBDMA such that the rx ring contains only
+ *  one DMA descriptor per ring element and the tx ring has two (using
+ *  the cool features of branch- and wait-select.  However, I'm not sure
+ *  if it's possible.  For now, we plod through it with 3 descriptors
+ *  for tx, and two for rx.
+ */
+
+static int
+ncr885e_open( struct device *dev )
+
+{
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	struct sk_buff *skb;
+	int i, size;
+	char *data;
+	struct dbdma_cmd *cp;
+	unsigned long flags;
+
+	/* allocate enough space for the tx and rx rings and a STOP descriptor */  
+	size = (sizeof( struct dbdma_cmd ) *
+		((NR_TX_RING * 3) + (NR_RX_RING * 2) + 1));
+
+	cp = kmalloc( size, GFP_KERNEL );
+
+	if ( cp == 0 ) {
+		printk( KERN_ERR "Insufficient memory (%d bytes) for DBDMA\n", size );
+		return -ENOMEM;
+	}
+
+	spin_lock_init( &sp->lock );
+	spin_lock_irqsave( &sp->lock, flags );
+
+	memset((char *) cp, 0, size );
+	sp->head = cp;
+
+	sp->stop_cmd = cp;
+	outl( DBDMA_STOP, &cp->command );
+  
+	sp->rx_cmds = ++cp;
+
+	for( i = 0; i < NR_RX_RING; i++ ) {
+
+		cp = sp->rx_cmds + (i*2);
+		skb = dev_alloc_skb( RX_BUFLEN + 2 );
+
+		/* if there is insufficient memory, make this last ring use a 
+		   static buffer and leave the loop with that skb as final one */
+		if ( skb == 0 ) {
+			printk( KERN_ERR "%s: insufficient memory for rx ring buffer\n",
+				dev->name );
+			break;
+		}
+
+		skb_reserve( skb, 2 );
+		sp->rx_skbufs[i] = skb;
+		data = skb->data;
+
+		/* The DMA commands here are done such that an EOP is the only
+		   way that we should get an interrupt.  This means that we could
+		   fill more than one skbuff before getting the interrupt at EOP. */
+
+		/* Handle rx DMA such that it always interrupts.... */
+		outw( (INPUT_MORE|INTR_ALWAYS), &cp->command );
+		outw( RX_BUFLEN, &cp->req_count );
+		outw( 0, &cp->res_count );
+		outl( virt_to_bus( data ), &cp->phy_addr );
+		outl( virt_to_bus( sp->stop_cmd ), &cp->cmd_dep );
+		outw( 0, &cp->xfer_status );
+#if 0
+		printk( KERN_INFO "rx at %p\n", cp );
+		show_dbdma_cmd( cp );
+#endif
+		++cp;
+
+		outw( DBDMA_STOP, &cp->command );
+
+	}
+
+	/* initialize to all rx buffers are available, fill limit is the end */
+	sp->rx_dirty = 0;
+	sp->rx_current = 0;
+
+	/* fill the tx ring */
+	sp->tx_cmds = cp+1;
+
+	for( i = 0; i < NR_TX_RING; i++ ) {
+
+		/* minimal setup for tx command */
+		cp = sp->tx_cmds + (i*3);
+		outw( OUTPUT_LAST, &cp->command );
+		if (ncr885e_debug > 3) {
+			printk( KERN_INFO "tx OUTPUT_LAST at %p\n", cp );
+			show_dbdma_cmd( cp );
+		}
+
+		/* full setup for the status cmd */
+		cp++;
+		outw( INPUT_LAST|INTR_ALWAYS|WAIT_IFCLR, &cp->command );
+		outl( virt_to_bus( &sp->tx_status[i] ), &cp->phy_addr );
+		outw( 2, &cp->req_count );
+		if ( ncr885e_debug > 3) {
+			printk( KERN_INFO "tx INPUT_LAST cmd at %p\n", cp );
+			show_dbdma_cmd( cp );
+		}
+
+		++cp;
+		outw( DBDMA_STOP, &cp->command );
+ 
+	}
+#if 0
+	/* chain the last tx DMA command to the STOP cmd */
+	outw((INPUT_LAST|INTR_ALWAYS|BR_ALWAYS), &cp->command );
+	outl( virt_to_bus( sp->stop_cmd ), &cp->cmd_dep );
+#endif
+	sp->tx_active = 0;
+	sp->tx_current = 0;
+	sp->tx_dirty = 0;
+
+	spin_unlock_irqrestore( &sp->lock, flags );
+
+	/* the order seems important here for some reason.  If the MPIC isn't
+	   enabled before the ethernet chip is enabled, shrapnel from the
+	   bootloader causes us to receive interrupts even though we've not 
+	   yet enabled the tx channel.  Go figure.  It'd be better to configure
+	   the chip in the probe1() routine, but then we don't see interrupts
+	   at all.  Everything looks all right on the logic analyzer, but... */
+
+	ncr885e_config( dev );
+
+	/* enable ethernet interrupts */
+	if ( request_irq( dev->irq, &ncr885e_interrupt, SA_SHIRQ, chipname, dev )) {
+		printk( KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq );
+		return -EAGAIN;
+	}
+
+	(void) inw( ioaddr + INTERRUPT_CLEAR );
+
+	ncr885e_enable( dev );
+
+	/* start rx DBDMA */
+	outl( virt_to_bus( sp->rx_cmds ), ioaddr + RX_CMD_PTR_LO );
+	outl( (RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN,
+	      ioaddr + RX_CHANNEL_CONTROL );
+
+	dev->start = 1;
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static int
+ncr885e_xmit_start( struct sk_buff *skb, struct device *dev )
+
+{
+	struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+	volatile struct dbdma_cmd *cp, *dp;
+	unsigned long flags, ioaddr = dev->base_addr;
+	int len, next, fill, entry;
+
+	if ( ncr885e_debug > 3)
+		printk( KERN_INFO "%s: xmit_start len=%d, dirty=%d, current=%d, active=%d\n",
+			dev->name, skb->len, sp->tx_dirty, sp->tx_current, sp->tx_active );
+
+	spin_lock_irqsave( &sp->lock, flags );
+
+	/* find the free slot in the ring buffer */
+	fill = sp->tx_current;
+	next = fill + 1;
+
+	if ( next >= NR_TX_RING )
+		next = 0;
+
+	/* mark ourselves as busy, even if we have too many packets waiting */
+	dev->tbusy = 1;
+
+	/* see if it's necessary to defer this packet */
+	if ( sp->tx_active >= MAX_TX_ACTIVE ) {
+		spin_unlock_irqrestore( &sp->lock, flags );
+		return -1;
+	}
+
+	sp->tx_active++;  /* bump "active tx" count */
+	sp->tx_current = next;  /* and show that we've used this buffer */
+	sp->tx_dirty = fill;     /* and mark this one to get picked up */
+
+	len = skb->len;
+
+	if ( len > ETH_FRAME_LEN ) {
+		printk( KERN_DEBUG "%s: xmit frame too long (%d)\n", dev->name, len );
+		len = ETH_FRAME_LEN;
+	}  
+
+	/* get index into the tx DBDMA chain */
+	entry = fill * 3;
+	sp->tx_skbufs[fill] = skb;
+	cp = sp->tx_cmds + entry;
+	dp = cp + 1;
+
+	/* update the rest of the OUTPUT_MORE descriptor */
+	outw( len, &cp->req_count );
+	outl( virt_to_bus( skb->data ), &cp->phy_addr );
+	outw( 0, &cp->xfer_status );
+	outw( 0, &cp->res_count );
+
+	/* and finish off the INPUT_MORE */
+	outw( 0, &dp->xfer_status );
+	outw( 0, &dp->res_count );
+	sp->tx_status[fill] = 0;
+	outl( virt_to_bus( &sp->tx_status[fill] ), &dp->phy_addr );
+
+	if ( ncr885e_debug > 2 )
+		printk(KERN_INFO "%s: xmit_start: active %d, tx_current %d, tx_dirty %d\n",
+		       dev->name, sp->tx_active, sp->tx_current, sp->tx_dirty );
+
+	if ( ncr885e_debug > 4 ) {
+		show_dbdma_cmd( cp );
+		show_dbdma_cmd( dp );
+	}
+
+
+	/* restart the tx DMA engine */
+	outl( virt_to_bus( cp ), ioaddr + TX_CMD_PTR_LO );
+	outl( (TX_DBDMA_ENABLE << 16)|TX_CHANNEL_RUN, 
+	      ioaddr + TX_CHANNEL_CONTROL );
+
+	ncr885e_set_timeout( dev );
+
+	spin_unlock_irqrestore( &sp->lock, flags );
+	dev->trans_start = jiffies;
+
+	return 0;      
+}
+
+static int
+ncr885e_close(struct device *dev)
+
+{
+	int i;
+	struct ncr885e_private *np = (struct ncr885e_private *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	spin_lock( &np->lock );
+
+	printk(KERN_INFO "%s: NCR885E Ethernet closing...\n", dev->name );
+
+	if (ncr885e_debug > 1)
+		printk(KERN_DEBUG "%s: Shutting down Ethernet chip\n", dev->name);
+
+	ncr885e_disable(dev);
+
+	del_timer(&np->tx_timeout);
+
+	/* flip off rx and tx */
+	outl( (RX_DBDMA_ENABLE << 16), ioaddr + RX_CHANNEL_CONTROL );
+	outl( (TX_DBDMA_ENABLE << 16), ioaddr + TX_CHANNEL_CONTROL );  
+
+	/* free up the IRQ */
+	free_irq( dev->irq, dev );
+
+	for( i = 0; i < NR_RX_RING; i++ ) {
+		if (np->rx_skbufs[i])
+			dev_kfree_skb( np->rx_skbufs[i] );
+		np->rx_skbufs[i] = 0;
+	}
+#if 0
+	for (i = 0; i < NR_TX_RING; i++) {
+		if (np->tx_skbufs[i])
+			dev_kfree_skb(np->tx_skbufs[i]);
+		np->tx_skbufs[i] = 0;
+	}
+#endif
+	spin_unlock( &np->lock );
+
+	kfree( np->head );
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+
+/*
+ *  multicast promiscuous mode isn't used here.  Allow code in the
+ *  IP stack to determine which multicast packets are good or bad....
+ *  (this avoids having to use the hash table registers)
+ */
+static void
+ncr885e_set_multicast( struct device *dev )
+
+{
+	int ioaddr = dev->base_addr;
+
+	if ( ncr885e_debug > 3 )
+		printk("%s: set_multicast: dev->flags = %x, AF=%04x\n", 
+		       dev->name, dev->flags, inw( ioaddr + ADDRESS_FILTER ));
+
+	if ( dev->flags & IFF_PROMISC ) {
+		printk( KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name );
+		outw( ADDRESS_RPPRO, ioaddr + ADDRESS_FILTER );
+	}
+
+	/* accept all multicast packets without checking the mc_list.  */
+	else if ( dev->flags & IFF_ALLMULTI ) {
+		printk( KERN_INFO "%s: Enabling all multicast packets.\n", 
+			dev->name );
+		outw( ADDRESS_RPPRM, ioaddr + ADDRESS_FILTER );
+	}
+
+	/* enable broadcast rx */
+	else {
+		outw( ADDRESS_RPABC, ioaddr + ADDRESS_FILTER );
+	}  
+}
+
+static struct net_device_stats *
+ncr885e_stats( struct device *dev )
+
+{
+	struct ncr885e_private *np = (struct ncr885e_private *) dev->priv;
+
+	return &np->stats;
+}
+
+/*  By this function, we're certain that we have a 885 Ethernet controller
+ *  so we finish setting it up and wrap up all the required Linux ethernet
+ *  configuration.
+ */
+
+static int
+ncr885e_probe1( struct device *dev, unsigned long ioaddr, unsigned char irq )
+
+{
+	struct ncr885e_private *sp;
+	unsigned short station_addr[3], val;
+	unsigned char *p;
+	int  i;
+
+	dev = init_etherdev( dev, 0 );
+
+	/* construct private data for the 885 ethernet */
+	dev->priv = kmalloc( sizeof( struct ncr885e_private ), GFP_KERNEL );
+
+	if ( dev->priv == NULL )
+		return -ENOMEM;
+
+	sp = (struct ncr885e_private *) dev->priv;
+	memset( sp, 0, sizeof( struct ncr885e_private ));
+
+	/* snag the station address and display it */
+	for( i = 0; i < 3; i++ ) {
+		val = inw( ioaddr + STATION_ADDRESS_0 + (i*2));
+		station_addr[i] = ((val >> 8) & 0xff) | ((val << 8) & 0xff00);
+	}
+
+	printk( KERN_INFO "%s: %s at %08lx,", dev->name, chipname, ioaddr );
+
+	p = (unsigned char *) &station_addr;
+
+	for( i=0; i < 6; i++ ) {
+		dev->dev_addr[i] = *p;
+		printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i] );
+		p++;
+	}
+
+	printk(", IRQ %d.\n", irq );
+
+	request_region( ioaddr, NCR885E_TOTAL_SIZE, dev->name );
+
+	/* set up a timer */
+	init_timer( &sp->tx_timeout );
+	sp->timeout_active = 0;
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+
+	ether_setup( dev );
+
+	/* everything else */
+	dev->open = ncr885e_open;
+	dev->stop = ncr885e_close;
+	dev->get_stats = ncr885e_stats;
+	dev->hard_start_xmit = ncr885e_xmit_start;
+	dev->set_multicast_list = ncr885e_set_multicast;
+	dev->set_mac_address = ncr885e_set_address;
+
+	return 0;
+}
+
+/*  Since the NCR 53C885 is a multi-function chip, I'm not worrying about
+ *  trying to get the the device(s) in slot order.  For our (Synergy's)
+ *  purpose, there's just a single 53C885 on the board and we don't 
+ *  worry about the rest.
+ */
+
+int __init ncr885e_probe( struct device *dev )
+{
+	struct pci_dev *pdev = NULL;
+	unsigned int ioaddr, chips = 0;
+	unsigned short cmd;
+	unsigned char irq, latency;
+
+	while(( pdev = pci_find_device( PCI_VENDOR_ID_NCR, 
+					PCI_DEVICE_ID_NCR_53C885_ETHERNET,
+					pdev )) != NULL ) {
+
+		if ( !print_version ) {
+			print_version++;
+			printk( KERN_INFO "%s", version );
+		}
+
+		/* Use I/O space */
+		pci_read_config_dword( pdev, PCI_BASE_ADDRESS_0, &ioaddr );
+		pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq );
+
+		ioaddr &= ~3;
+		/* Adjust around the Grackle... */
+#ifdef CONFIG_GEMINI
+		ioaddr |= 0xfe000000;
+#endif
+
+		if ( check_region( ioaddr, NCR885E_TOTAL_SIZE ))
+			continue;
+
+		/* finish off the probe */
+		if ( !(ncr885e_probe1( dev, ioaddr, irq ))) {
+
+			chips++;
+
+			/* Access is via I/O space, bus master enabled... */
+			pci_read_config_word( pdev, PCI_COMMAND, &cmd );
+
+			if ( !(cmd & PCI_COMMAND_MASTER) ) {
+				printk( KERN_INFO "  PCI master bit not set! Now setting.\n");
+				cmd |= PCI_COMMAND_MASTER;
+				pci_write_config_word( pdev, PCI_COMMAND, cmd );
+			}
+
+			if ( !(cmd & PCI_COMMAND_IO) ) {
+				printk( KERN_INFO "  Enabling I/O space.\n" );
+				cmd |= PCI_COMMAND_IO;
+				pci_write_config_word( pdev, PCI_COMMAND, cmd );
+			}
+
+			pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &latency );
+
+			if ( latency < 10 ) {
+				printk( KERN_INFO "  PCI latency timer (CFLT) is unreasonably"
+					" low at %d.  Setting to 255.\n", latency );
+				pci_write_config_byte( pdev, PCI_LATENCY_TIMER, 255 );
+			}
+		}
+	}
+
+	if ( !chips )
+		return -ENODEV;
+	else
+		return 0;
+}
+
+/* debugging to peek at dma descriptors */
+static void
+show_dbdma_cmd( volatile struct dbdma_cmd *cmd )
+
+{
+	printk( KERN_INFO " cmd %04x, physaddr %08x, req_count %04x\n",
+		inw( &cmd->command ), inl( &cmd->phy_addr ), inw( &cmd->req_count ));
+	printk( KERN_INFO " res_count %04x, xfer_status %04x, branch %08x\n", 
+		inw( &cmd->res_count ), inw( &cmd->xfer_status ),inl( &cmd->cmd_dep ));
+}
+
+#if 0
+static int
+read_eeprom( unsigned int ioaddr, int location )
+
+{
+	int loop;
+	unsigned char val;
+
+	outb( (location & 0xff), ioaddr + EE_WORD_ADDR );
+
+	/* take spillover from location in control reg */
+	outb(EE_CONTROL_RND_READB | (location & (0x7<<8)), ioaddr + EE_CONTROL);
+
+	loop = 1000;
+	while( (inb( ioaddr + EE_STATUS) & EE_SEB) &&
+	       (loop > 0) ) {
+		udelay( 10 );
+		loop--;
+	}
+
+	if ( inb( ioaddr + EE_STATUS ) & EE_SEE ) {
+		printk("%s: Serial EEPROM read error\n", chipname);
+		val = 0xff;
+	}
+
+	else 
+		val = inb( ioaddr + EE_READ_DATA );
+
+	return (int) val;
+}
+#endif
+
+#ifdef NCR885E_DEBUG_MII
+static void
+show_mii( unsigned long ioaddr )
+
+{
+	int   phyctrl, phystat, phyadvert, phypartner, phyexpan;
+
+	phyctrl = read_mii( ioaddr, MII_AUTO_NEGOTIATION_CONTROL );
+	phystat = read_mii( ioaddr, MII_AUTO_NEGOTIATION_STATUS );
+	phyadvert = read_mii( ioaddr, MII_AUTO_NEGOTIATION_ADVERTISEMENT );
+	phypartner = read_mii( ioaddr, MII_AUTO_NEGOTIATION_LINK_PARTNER );
+	phyexpan = read_mii( ioaddr, MII_AUTO_NEGOTIATION_EXPANSION );
+
+	printk( KERN_INFO "PHY: advert=%d %s, partner=%s %s, link=%d, %s%s\n",
+		(phyadvert & MANATECH_100BASETX_FULL_DUPLEX ? 100 : 10),
+		(phyctrl & MANC_AUTO_NEGOTIATION_ENABLE ? "auto" : "fixed"),
+		(phypartner & MANLP_ACKNOWLEDGE ?
+		 (phypartner & MANATECH_100BASETX_FULL_DUPLEX ? "100" : "10") :
+		 "?"),
+		(phyexpan & MANE_LINK_PARTNER_AUTO_ABLE ? "auto" : "fixed"),
+		(phyctrl & MANC_PHY_SPEED_100 ? 100 : 10),
+		(phystat & MANS_LINK_STATUS ? "up" : "down"),
+		(phyexpan & MANE_PARALLEL_DETECTION_FAULT ? " PD-fault" : "" ));
+	return;
+}
+
+
+static int
+read_mii( unsigned long ioaddr, int reg )
+
+{
+	int    timeout;
+
+
+	timeout = 100000;
+
+	while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) {
+
+		if ( timeout-- < 0 ) {
+			printk( KERN_INFO "Timed out waiting for MII\n" );
+			return -1;
+		}
+	}
+
+	outw( (1<<8) + reg, ioaddr + MII_ADDRESS );
+	outw( MIIM_RSTAT, ioaddr + MIIM_COMMAND );
+
+	timeout = 100000;
+	while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) {
+		if ( timeout-- < 0 ) {
+			printk( KERN_INFO "Timed out waiting for MII\n" );
+			return -1;
+		}
+	}
+
+	return( inw( ioaddr + MII_READ_DATA ));
+}
+
+static void
+write_mii( unsigned long ioaddr, int reg, int data )
+
+{
+	int timeout=100000;
+
+	printk( KERN_INFO "MII indicator: %02x\n", inw( ioaddr + MII_INDICATOR ));
+
+	while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) {
+		if ( timeout-- <= 0 ) {
+			printk( KERN_INFO "Timeout waiting to write to MII\n" );
+			return;
+		}
+		udelay( 10 );
+	}
+
+	outw( (1<<8) + reg, ioaddr + MII_ADDRESS );
+	outw( data, ioaddr + MII_WRITE_DATA );
+
+	return;
+}
+
+#endif /* NCR885E_DEBUG_MII */
+
+#ifdef MODULE
+#if defined(LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("dan@synergymicro.com");
+MODULE_DESCRIPTION("Symbios 53C885 Ethernet driver");
+MODULE_PARM(debug, "i");
+#endif 
+
+static int debug = 1;
+
+int
+init_module(void)
+{
+	if ( debug >= 0)
+		ncr885e_debug = debug;
+
+	return ncr885e_probe( NULL );
+}
+
+void
+cleanup_module(void)
+{
+	struct ncr885e_private *np;
+
+	if ( root_dev ) {
+
+		unregister_netdev( root_dev );
+		np = (struct ncr885e_private *) root_dev->priv;
+		release_region( root_dev->base_addr, NCR885E_TOTAL_SIZE );
+		kfree( root_dev->priv );
+		root_dev = NULL;
+	}  
+}
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O6 -c symba.c"
+ * End:
+ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/ncr885e.h linux.14p16/drivers/net/ncr885e.h
--- linux.vanilla/drivers/net/ncr885e.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/ncr885e.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,367 @@
+#ifndef _NET_H_SYMBA
+#define _NET_H_SYMBA
+
+/* transmit status bit definitions */
+#define TX_STATUS_TXOK         (1<<13)     /* success */
+#define TX_STATUS_TDLC         (1<<12)     /* dropped for late colls */
+#define TX_STATUS_TCXSDFR      (1<<11)     /* excessive deferral */
+#define TX_STATUS_TDEC         (1<<10)     /* excessive collisions */
+#define TX_STATUS_TAUR         (1<<9)      /* abort on underrun/"jumbo" */
+#define TX_STATUS_PDFRD        (1<<8)      /* packet deferred */
+#define TX_STATUS_BCAST        (1<<7)      /* broadcast ok */
+#define TX_STATUS_MCAST        (1<<6)      /* multicast ok */
+#define TX_STATUS_CRCERR       (1<<5)      /* CRC error */
+#define TX_STATUS_LC           (1<<4)      /* late collision */
+#define TX_STATUS_CCNT_MASK    0xf         /* collision count */
+
+#define T_TXOK      (1<<13)
+#define T_TDLC      (1<<12)
+#define T_TCXSDFR   (1<<11)
+#define T_TDEC      (1<<10)
+#define T_TAUR      (1<<9)
+#define T_PDFRD     (1<<8)
+#define T_BCAST     (1<<7)
+#define T_MCAST     (1<<6)
+#define T_LC        (1<<4)
+#define T_CCNT_MASK 0xf
+
+/* receive status bit definitions */
+#define RX_STATUS_RXOVRN       (1<<23)     /* overrun */
+#define RX_STATUS_CEPS         (1<<22)     /* carrier event already seen */
+#define RX_STATUS_RXOK         (1<<21)     /* success */
+#define RX_STATUS_BCAST        (1<<20)     /* broadcast ok */
+#define RX_STATUS_MCAST        (1<<19)     /* multicast ok */
+#define RX_STATUS_CRCERR       (1<<18)     /* CRC error */
+#define RX_STATUS_DR           (1<<17)     /* dribble nibble */
+#define RX_STATUS_RCV          (1<<16)     /* rx code violation */
+#define RX_STATUS_PTL          (1<<15)     /* pkt > 1518 bytes */
+#define RX_STATUS_PTS          (1<<14)     /* pkt < 64 bytes */
+#define RX_STATUS_LEN_MASK     0x1fff      /* length mask */
+
+#define EEPROM_LENGTH          100
+
+
+/*  Serial EEPROM interface  */
+#define EE_STATUS              0xf0
+#define EE_CONTROL             0xf1
+#define EE_WORD_ADDR           0xf2
+#define EE_READ_DATA           0xf3
+#define EE_WRITE_DATA          0xf4
+#define EE_FEATURE_ENB         0xf5
+
+/*  Use on EE_STATUS  */
+#define EE_SEB                 (1<<8)
+#define EE_SEE                     1
+
+/*  Serial EEPROM commands */
+#define EE_CONTROL_SEQ_READB   (1<<4)
+#define EE_CONTROL_RND_WRITEB  (1<<5)
+#define EE_CONTROL_RND_READB   ((1<<4)|(1<<5))
+
+/*  Enable writing to serial EEPROM */
+#define EE_WRITE_ENB                1
+
+/*  The 885 configuration register */
+#define MAC_CONFIG             0xa0
+#define  MAC_CONFIG_SRST       1<<15
+#define  MAC_CONFIG_ITXA       1<<13
+#define  MAC_CONFIG_RXEN       1<<12
+#define  MAC_CONFIG_INTLB      1<<10
+#define  MAC_CONFIG_MODE_MASK  (1<<8|1<<9)
+#define  MAC_CONFIG_MODE_TP    1<<8
+#define  MAC_CONFIG_HUGEN      1<<5
+#define  MAC_CONFIG_RETRYL     1<<4
+#define  MAC_CONFIG_CRCEN      1<<3
+#define  MAC_CONFIG_PADEN      1<<2
+#define  MAC_CONFIG_FULLD      1<<1
+#define  MAC_CONFIG_NOCFR      1<<0
+
+
+
+
+
+#define TX_WAIT_SELECT         0x18
+#define RX_CHANNEL_CONTROL     0x40
+
+/* Tx channel status */
+#define TX_DBDMA_REG           0x00
+#define TX_CHANNEL_CONTROL     0x00
+#define TX_CHANNEL_STATUS      0x04
+#define  TX_STATUS_RUN         1<<15
+#define  TX_STATUS_PAUSE       1<<14
+#define  TX_STATUS_WAKE        1<<12
+#define  TX_STATUS_DEAD        1<<11
+#define  TX_STATUS_ACTIVE      1<<10
+#define  TX_STATUS_BT          1<<8
+#define  TX_STATUS_TXABORT     1<<7
+#define  TX_STATUS_TXSR        1<<6
+
+#define  TX_CHANNEL_RUN        TX_STATUS_RUN
+#define  TX_CHANNEL_PAUSE      TX_STATUS_PAUSE
+#define  TX_CHANNEL_WAKE       TX_STATUS_WAKE
+#define  TX_CHANNEL_DEAD       TX_STATUS_DEAD
+#define  TX_CHANNEL_ACTIVE     TX_STATUS_ACTIVE
+#define  TX_CHANNEL_BT         TX_STATUS_BT
+#define  TX_CHANNEL_TXABORT    TX_STATUS_TXABORT
+#define  TX_CHANNEL_TXSR       TX_STATUS_TXSR
+
+#define  TX_DBDMA_ENABLE       (TX_CHANNEL_WAKE | TX_CHANNEL_PAUSE | \
+                                TX_CHANNEL_RUN )
+
+/* Transmit command ptr lo register */
+#define TX_CMD_PTR_LO          0x0c
+
+/* Transmit interrupt select register */
+#define TX_INT_SELECT          0x10
+
+/* Transmit branch select register */
+#define TX_BRANCH_SELECT       0x14
+
+/* Transmit wait select register */
+#define TX_WAIT_SELECT         0x18
+#define  TX_WAIT_STAT_RECV     0x40
+
+/* Rx channel status */
+#define RX_DBDMA_REG           0x40
+#define RX_CHANNEL_CONTROL     0x40
+#define RX_CHANNEL_STATUS      0x44
+#define  RX_STATUS_RUN         1<<15
+#define  RX_STATUS_PAUSE       1<<14
+#define  RX_STATUS_WAKE        1<<12
+#define  RX_STATUS_DEAD        1<<11
+#define  RX_STATUS_ACTIVE      1<<10
+#define  RX_STATUS_BT          1<<8
+#define  RX_STATUS_EOP         1<<6
+
+#define  RX_CHANNEL_RUN        RX_STATUS_RUN
+#define  RX_CHANNEL_PAUSE      RX_STATUS_PAUSE
+#define  RX_CHANNEL_WAKE       RX_STATUS_WAKE
+#define  RX_CHANNEL_DEAD       RX_STATUS_DEAD
+#define  RX_CHANNEL_ACTIVE     RX_STATUS_ACTIVE
+#define  RX_CHANNEL_BT         RX_STATUS_BT
+#define  RX_CHANNEL_EOP        RX_STATUS_EOP
+
+#define  RX_DBDMA_ENABLE       (RX_CHANNEL_WAKE | RX_CHANNEL_PAUSE | \
+                                RX_CHANNEL_RUN)
+
+/*  Receive command ptr lo  */
+#define RX_CMD_PTR_LO          0x4c
+
+/*  Receive interrupt select register */
+#define RX_INT_SELECT          0x50
+#define  RX_INT_SELECT_EOP     0x40
+
+/*  Receive branch select  */
+#define RX_BRANCH_SELECT       0x54
+#define  RX_BRANCH_SELECT_EOP  0x40
+
+/*  Receive wait select  */
+#define RX_WAIT_SELECT         0x58
+#define  RX_WAIT_SELECT_EOP    0x40
+
+/*  Event status register  */
+#define EVENT_STATUS           0x80
+#define  EVENT_TXSR            1<<2
+#define  EVENT_EOP             1<<1
+#define  EVENT_TXABORT         1<<0
+
+/*  Interrupt enable register  */
+#define INTERRUPT_ENABLE       0x82
+
+/*  Interrupt clear register  */
+#define INTERRUPT_CLEAR        0x84
+
+/*  Interrupt status register  */
+#define INTERRUPT_STATUS_REG   0x86
+
+/*  bits for the above three interrupt registers */
+#define  INTERRUPT_INTE        1<<15   /* interrupt enable */
+#define  INTERRUPT_WI          1<<9    /* wakeup interrupt */
+#define  INTERRUPT_ERI         1<<8    /* early recieve interrupt */
+#define  INTERRUPT_PPET        1<<7    /* PCI Tx parity error */
+#define  INTERRUPT_PBFT        1<<6    /* PCI Tx bus fault */
+#define  INTERRUPT_IIDT        1<<5    /* illegal instruction Tx */
+#define  INTERRUPT_DIT         1<<4    /* DBDMA Tx interrupt */
+#define  INTERRUPT_PPER        1<<3    /* PCI Rx parity error */
+#define  INTERRUPT_PBFR        1<<2    /* PCI Rx bus fault */
+#define  INTERRUPT_IIDR        1<<1    /* illegal instruction Rx */
+#define  INTERRUPT_DIR         1<<0    /* DBDMA Rx interrupt */
+
+#define  INTERRUPT_TX_MASK     (INTERRUPT_PBFT|INTERRUPT_IIDT| \
+                                INTERRUPT_PPET|INTERRUPT_DIT)
+#define  INTERRUPT_RX_MASK     (INTERRUPT_PBFR|INTERRUPT_IIDR| \
+                                INTERRUPT_PPER|INTERRUPT_DIR)
+
+/*  chip revision register */
+#define CHIP_REVISION_REG      0x8c
+#define  CHIP_PCIREV_MASK      (0xf<<16)
+#define  CHIP_PCIDEV_MASK      0xff
+
+/*  Tx threshold register */
+#define TX_THRESHOLD           0x94
+
+/*  General purpose register */
+#define GEN_PURPOSE_REG        0x9e
+
+/*  General purpose pin control reg */
+#define GEN_PIN_CONTROL_REG    0x9f
+
+/*  DBDMA control register  */
+#define DBDMA_CONTROL          0x90
+#define  DBDMA_SRST            1<<31
+#define  DBDMA_TDPCE           1<<23
+#define  DBDMA_BE              1<<22
+#define  DBDMA_TAP_MASK        (1<<19|1<<20|1<<21)
+#define  DBDMA_RAP_MASK        (1<<16|1<<17|1<<18)
+#define  DBDMA_DPMRLE          1<<15
+#define  DBDMA_WIE             1<<14
+#define  DBDMA_MP              1<<13
+#define  DBDMA_SME             1<<12
+#define  DBDMA_CME             1<<11
+#define  DBDMA_DDPE            1<<10
+#define  DBDMA_TDPE            1<<9
+#define  DBDMA_EXTE            1<<8
+#define  DBDMA_BST_MASK        (1<<4|1<<5|1<<6)
+#define  DBDMA_BSR_MASK        (1<<0|1<<1|1<<2)
+
+#define  DBDMA_BURST_1         (0x00)
+#define  DBDMA_BURST_2         (0x01)
+#define  DBDMA_BURST_4         (0x02)
+#define  DBDMA_BURST_8         (0x03)
+#define  DBDMA_BURST_16        (0x04)
+#define  DBDMA_BURST_32        (0x05)
+#define  DBDMA_BURST_64        (0x06)
+#define  DBDMA_BURST_128       (0x07)
+
+#define  DBDMA_TX_BST_SHIFT    (4)
+#define  DBDMA_RX_BST_SHIFT    (0)
+
+#define  DBDMA_TX_ARBITRATION_DEFAULT ( 1 << 19 )
+#define  DBDMA_RX_ARBITRATION_DEFAULT ( 2 << 16 )
+
+
+/*  Back-to-back interpacket gap register */
+#define BTOB_INTP_GAP          0xa2
+#define  BTOB_INTP_DEFAULT     0x18
+
+/*  Non-back-to-back interpacket gap register */
+#define NBTOB_INTP_GAP         0xa4
+
+/*  MIIM command register */
+#define MIIM_COMMAND           0xa6
+#define  MIIM_SCAN             1<<1
+#define  MIIM_RSTAT            1<<0
+
+/*  MII address register */
+#define MII_ADDRESS            0xa8
+#define  MII_FIAD_MASK         (1<<8|1<<9|1<<10|1<<11|1<<12)
+#define  MII_RGAD_MASK         (1<<0|1<<1|1<<2|1<<3|1<<4)
+
+#define TPPMD_CONTROL_REG      0xa8
+#define  TPPMD_FO              1<<1
+#define  TPPMD_LB              1<<0
+
+/*  MII read and write registers */
+#define MII_WRITE_DATA         0xaa
+#define MII_READ_DATA          0xac
+
+/*  MII indicators */
+#define MII_INDICATOR          0xae
+#define  MII_NVALID            1<<2
+#define  MII_SCAN              1<<1
+#define  MII_BUSY              1<<0
+
+/*  Address filter  */
+#define ADDRESS_FILTER         0xd0
+#define  ADDRESS_RPPRM         1<<3       /* multicast promis. mode */
+#define  ADDRESS_RPPRO         1<<2       /* promiscuous mode */
+#define  ADDRESS_RPAMC         1<<1       /* accept multicasts */
+#define  ADDRESS_RPABC         1<<0       /* accept broadcasts */
+
+/*  Station addresses
+
+    Note that if the serial EEPROM is disabled, these values are all
+    zero.  If, like us, you get the chips when they're fresh, they're
+    also zero and you have to initialize the address */
+#define STATION_ADDRESS_0      0xd2
+#define STATION_ADDRESS_1      0xd4
+#define STATION_ADDRESS_2      0xd6
+
+/*  Hash tables  */
+#define HASH_TABLE_0           0xd8
+#define HASH_TABLE_1           0xda
+#define HASH_TABLE_2           0xdc
+#define HASH_TABLE_3           0xde
+
+/* PHY indentifiers */
+#define PHY_IDENTIFIER_0       0xe4
+#define PHY_IDENTIFIER_1       0xe6
+
+/*  MII Auto-negotiation register definitions  */
+
+#define MII_AUTO_NEGOTIATION_CONTROL        (0x0000)
+#define   MANC_PHY_RESET                      (0x8000)
+#define   MANC_PHY_LOOPBACK_ENABLE            (0x4000)
+#define   MANC_PHY_LOOPBACK_DISABLE           (0x0000)
+#define   MANC_PHY_SPEED_100                  (0x2000)
+#define   MANC_PHY_SPEED_10                   (0x0000)
+#define   MANC_AUTO_NEGOTIATION_ENABLE        (0x1000)
+#define   MANC_AUTO_NEGOTIATION_DISABLE       (0x0000)
+#define   MANC_PHY_POWER_DOWN                 (0x0800)
+#define   MANC_PHY_POWER_UP                   (0x0000)
+#define   MANC_ISOLATE_ENABLE                 (0x0400)
+#define   MANC_ISOLATE_DISABLE                (0x0000)
+#define   MANC_RESTART_AUTO_NEGOTIATION       (0x0200)
+#define   MANC_FULL_DUPLEX                    (0x0100)
+#define   MANC_HALF_DUPLEX                    (0x0000)
+
+#define MII_AUTO_NEGOTIATION_STATUS         (0x0001)
+#define   MANS_100BASE_T4_HALF_DUPLEX         (0x8000)
+#define   MANS_100BASE_X_FULL_DUPLEX          (0x4000)
+#define   MANS_100BASE_X_HALF_DUPLEX          (0x2000)
+#define   MANS_10MBS_FULL_DUPLEX              (0x1000)
+#define   MANS_10MBS_HALF_DUPLEX              (0x0800)
+#define   MANS_AUTO_NEGOTIATION_COMPLETE      (0x0020)
+#define   MANS_REMOTE_FAULT                   (0x0010)
+#define   MANS_AUTO_NEGOTIATION_ABILITY       (0x0008)
+#define   MANS_LINK_STATUS                    (0x0004)
+#define   MANS_JABBER_DETECT                  (0x0002)
+#define   MANS_EXTENDED_CAPABILITY            (0x0001)
+
+#define MII_PHY_IDENTIFIER_1                (0x0002)
+#define MII_PHY_IDENTIFIER_2                (0x0003)
+
+#define MII_AUTO_NEGOTIATION_ADVERTISEMENT  (0x0004)
+#define   MANA_NEXT_PAGE                      (0x8000)
+#define   MANA_REMOTE_FAULT                   (0x2000)
+#define   MANA_TECHNOLOGY_ABILITY_MASK        (0x1FE0)
+#define     MANATECH_10BASET_HALF_DUPLEX        (0x0020)
+#define     MANATECH_10BASET_FULL_DUPLEX        (0x0040)
+#define     MANATECH_100BASETX_HALF_DUPLEX      (0x0080)
+#define     MANATECH_100BASETX_FULL_DUPLEX      (0x0100)
+#define     MANATECH_100BASET4                  (0x0200)
+#define   MANA_SELECTOR_MASK                  (0x001F)
+#define     MANASELECTOR_802_3                  (0x0001)
+
+#define MII_AUTO_NEGOTIATION_LINK_PARTNER   (0x0005)
+#define   MANLP_NEXT_PAGE                     (0x8000)
+#define   MANLP_ACKNOWLEDGE                   (0x4000)
+#define   MANLP_REMOTE_FAULT                  (0x2000)
+#define   MANLP_TECHNOLOGY_ABILITY_MASK       (0x1FE0)
+#define   MANLP_SELECTOR_MASK                 (0x001F)
+
+#define MII_AUTO_NEGOTIATION_EXPANSION      (0x0006)
+#define   MANE_PARALLEL_DETECTION_FAULT       (0x0010)
+#define   MANE_LINK_PARTNER_NEXT_PAGE_ABLE    (0x0008)
+#define   MANE_NEXT_PAGE_ABLE                 (0x0004)
+#define   MANE_PAGE_RECEIVED                  (0x0002)
+#define   MANE_LINK_PARTNER_AUTO_ABLE         (0x0001)
+
+#define MII_AUTO_NEGOTIATION_NEXT_PAGE_TRANSMIT (0x0007)
+#define   MANNPT_NEXT_PAGE                    (0x8000)
+#define   MANNPT_MESSAGE_PAGE                 (0x2000)
+#define   MANNPT_ACKNOWLEDGE_2                (0x1000)
+#define   MANNPT_TOGGLE                       (0x0800)
+#define   MANNPT_MESSAGE_FIELD_MASK           (0x07FF)
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/old_tulip.c linux.14p16/drivers/net/old_tulip.c
--- linux.vanilla/drivers/net/old_tulip.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/old_tulip.c	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,2853 @@
+/* tulip.c: A DEC 21040-family ethernet driver for Linux. */
+/*
+	Written 1994-1998 by Donald Becker.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+
+	This driver is for the Digital "Tulip" ethernet adapter interface.
+	It should work with most DEC 21*4*-based chips/ethercards, as well as
+	PNIC and MXIC chips.
+
+	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+	Center of Excellence in Space Data and Information Sciences
+	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+	Support and updates available at
+	http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
+*/
+
+#define SMP_CHECK
+static const char version[] = "tulip.c:v0.89H 5/23/98 becker@cesdis.gsfc.nasa.gov\n";
+
+/* A few user-configurable values. */
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 25;
+
+#define MAX_UNITS 8
+/* Used to pass the full-duplex flag, etc. */
+static int full_duplex[MAX_UNITS] = {0, };
+static int options[MAX_UNITS] = {0, };
+static int mtu[MAX_UNITS] = {0, };			/* Jumbo MTU for interfaces. */
+
+/*  The possible media types that can be set in options[] are: */
+static const char * const medianame[] = {
+	"10baseT", "10base2", "AUI", "100baseTx",
+	"10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx",
+	"100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII",
+	"10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
+};
+
+/* Set if the PCI BIOS detects the chips on a multiport board backwards. */
+#ifdef REVERSE_PROBE_ORDER
+static int reverse_probe = 1;
+#else
+static int reverse_probe = 0;
+#endif
+
+/* Keep the ring sizes a power of two for efficiency.
+   Making the Tx ring too large decreases the effectiveness of channel
+   bonding and packet priority.
+   There are no ill effects from too-large receive rings. */
+#define TX_RING_SIZE	16
+#define RX_RING_SIZE	32
+
+/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
+#ifdef __alpha__
+static int rx_copybreak = 1518;
+#else
+static int rx_copybreak = 100;
+#endif
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (4*HZ)
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+
+#include <asm/processor.h>		/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+/* Kernel compatibility defines, common to David Hind's PCMCIA package.
+   This is only in the support-all-kernels source code. */
+#include <linux/version.h>		/* Evil, but neccessary */
+
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10300
+#define RUN_AT(x) (x)			/* What to put in timer->expires.  */
+#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
+#define virt_to_bus(addr)  ((unsigned long)addr)
+#define bus_to_virt(addr) ((void*)addr)
+
+#else  /* 1.3.0 and later */
+#define RUN_AT(x) (jiffies + (x))
+#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+#endif
+
+#if (LINUX_VERSION_CODE >= 0x10344)
+#define NEW_MULTICAST
+#include <linux/delay.h>
+#endif
+#ifdef SA_SHIRQ
+#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
+#else
+#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
+#endif
+
+#if (LINUX_VERSION_CODE < 0x20123)
+#define hard_smp_processor_id() smp_processor_id()
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#endif
+
+/* This my implementation of shared IRQs, now only used for 1.2.13. */
+#ifdef HAVE_SHARED_IRQ
+#define USE_SHARED_IRQ
+#include <linux/shared_irq.h>
+#endif
+
+/* The total size is unusually large: The 21040 aligns each of its 16
+   longword-wide registers on a quadword boundary. */
+#define TULIP_TOTAL_SIZE 0x80
+
+#ifdef HAVE_DEVLIST
+struct netdev_entry tulip_drv =
+{"Tulip", tulip_pci_probe, TULIP_TOTAL_SIZE, NULL};
+#endif
+
+#ifdef TULIP_DEBUG
+int tulip_debug = TULIP_DEBUG;
+#else
+int tulip_debug = 1;
+#endif
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the DECchip "Tulip", Digital's
+single-chip ethernet controllers for PCI.  Supported members of the family
+are the 21040, 21041, 21140, 21140A, 21142, and 21143.  These chips are used on
+many PCI boards including the SMC EtherPower series.
+
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board.  The system BIOS preferably should assign the
+PCI INTA signal to an otherwise unused system IRQ line.
+Note: Kernel versions earlier than 1.3.73 do not support shared PCI
+interrupt lines.
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+The Tulip can use either ring buffers or lists of Tx and Rx descriptors.
+This driver uses statically allocated rings of Rx and Tx descriptors, set at
+compile time by RX/TX_RING_SIZE.  This version of the driver allocates skbuffs
+for the Rx ring buffers at open() time and passes the skb->data field to the
+Tulip as receive data buffers.  When an incoming frame is less than
+RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is
+copied to the new skbuff.  When the incoming frame is larger, the skbuff is
+passed directly up the protocol stack and replaced by a newly allocated
+skbuff.
+
+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
+using a full-sized skbuff for small frames vs. the copying costs of larger
+frames.  For small frames the copying cost is negligible (esp. considering
+that we are pre-loading the cache with immediately useful header
+information).  For large frames the copying cost is non-trivial, and the
+larger copy might flush the cache of useful data.  A subtle aspect of this
+choice is that the Tulip only receives into longword aligned buffers, thus
+the IP header at offset 14 isn't longword aligned for further processing.
+Copied frames are put into the new skbuff at an offset of "+2", thus copying
+has the beneficial effect of aligning the IP header and preloading the
+cache.
+
+IIIC. Synchronization
+The driver runs as two independent, single-threaded flows of control.  One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag.  The other thread is the interrupt handler, which is single
+threaded by the hardware and other software.
+
+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+the 'tp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring.  (The Tx-done interrupt can't be selectively turned off, so
+we can't avoid the interrupt overhead by having the Tx routine reap the Tx
+stats.)	 After reaping the stats, it marks the queue entry as empty by setting
+the 'base' to zero.	 Iff the 'tp->tx_full' flag is set, it clears both the
+tx_full and tbusy flags.
+
+IV. Notes
+
+Thanks to Duke Kamstra of SMC for providing an EtherPower board.
+
+IVb. References
+
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+http://www.digital.com  (search for current 21*4* datasheets and "21X4 SROM")
+http://www.national.com/pf/DP/DP83840.html
+
+IVc. Errata
+
+The DEC databook doesn't document which Rx filter settings accept broadcast
+packets.  Nor does it document how to configure the part to configure the
+serial subsystem for normal (vs. loopback) operation or how to have it
+autoswitch between internal 10baseT, SIA and AUI transceivers.
+
+The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last
+register of the set CSR12-15 written.  Hmmm, now how is that possible?  */
+
+
+/* A few values that may be tweaked. */
+#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
+
+/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
+   to support a pre-NWay full-duplex signaling mechanism using short frames.
+   No one knows what it should be, but if left at its default value some
+   10base2(!) packets trigger a full-duplex-request interrupt. */
+#define FULL_DUPLEX_MAGIC	0x6969
+
+#ifndef PCI_VENDOR_ID_DEC		/* Now defined in linux/pci.h */
+#define PCI_VENDOR_ID_DEC			0x1011
+#define PCI_DEVICE_ID_TULIP			0x0002		/* 21040. */
+#define PCI_DEVICE_ID_TULIP_FAST	0x0009		/* 21140. */
+#endif
+
+#ifndef PCI_DEVICE_ID_DEC_TULIP_PLUS
+#define PCI_DEVICE_ID_DEC_TULIP_PLUS	0x0014		/* 21041. */
+#endif
+#ifndef PCI_DEVICE_ID_DEC_TULIP_21142
+#define PCI_DEVICE_ID_DEC_TULIP_21142	0x0019
+#endif
+
+#ifndef PCI_VENDOR_ID_LITEON
+#define PCI_VENDOR_ID_LITEON	0x11AD
+#endif
+
+#ifndef PCI_VENDOR_ID_MXIC
+#define	PCI_VENDOR_ID_MXIC		0x10d9
+#define PCI_DEVICE_ID_MX98713	0x0512
+#define PCI_DEVICE_ID_MX98715	0x0531
+#define PCI_DEVICE_ID_MX98725	0x0531
+#endif
+
+/* The rest of these values should never change. */
+
+static void tulip_timer(unsigned long data);
+static void t21142_timer(unsigned long data);
+static void mxic_timer(unsigned long data);
+static void pnic_timer(unsigned long data);
+
+/* A table describing the chip types. */
+enum tbl_flag { HAS_MII=1, HAS_MEDIA_TABLE = 2, CSR12_IN_SROM = 4,};
+static struct tulip_chip_table {
+	int vendor_id, device_id;
+	char *chip_name;
+	int io_size;
+	int valid_intrs;			/* CSR7 interrupt enable settings */
+	int flags;
+	void (*media_timer)(unsigned long data);
+} tulip_tbl[] = {
+  { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP,
+	"Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
+  { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS,
+	"Digital DC21041 Tulip", 128, 0x0001ebef, HAS_MEDIA_TABLE, tulip_timer },
+  { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST,
+	"Digital DS21140 Tulip", 128, 0x0001ebef,
+	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM,
+	tulip_timer },
+  { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_21142,
+	"Digital DS21142/3 Tulip", 128, 0x0801fbff,
+	HAS_MII | HAS_MEDIA_TABLE, t21142_timer },
+  { PCI_VENDOR_ID_LITEON, 0x0002,
+	"Lite-On 82c168 PNIC", 256, 0x0001ebef, HAS_MII, pnic_timer },
+  { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98713,
+	"Macronix 98713 PMAC", 128, 0x0001ebef,
+	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer /* Tulip-like! */ },
+  { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98715,
+	"Macronix 98715 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer },
+  { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98725,
+	"Macronix 98725 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer },
+  { 0x125B, 0x1400, "ASIX AX88140", 128, 0x0001fbff,
+	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
+  {0, 0, 0, 0},
+};
+/* This matches the table above. */
+enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
+			 LC82C168, MX98713, MX98715, MX98725};
+
+/* A full-duplex map for media types. */
+enum MediaIs {MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
+		  MediaIs100=16};
+static const char media_cap[] =
+{0,0,0,16,  3,19,16,24,  27,4,7,5, 0,20,23,20 };
+/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
+static u16 t21041_csr13[] = { 0xEF05, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
+static u16 t21041_csr14[] = { 0x7F3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
+static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
+
+static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };
+static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, };
+static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
+
+/* Offsets to the Command and Status Registers, "CSRs".  All accesses
+   must be longword instructions and quadword aligned. */
+enum tulip_offsets {
+	CSR0=0,    CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
+	CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
+	CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 };
+
+/* The bits in the CSR5 status registers, mostly interrupt sources. */
+enum status_bits {
+	TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10,
+	NormalIntr=0x10000, AbnormalIntr=0x8000,
+	RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40,
+	TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
+};
+
+enum desc_status_bits {
+	DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300,
+};
+        
+/* The Tulip Rx and Tx buffer descriptors. */
+struct tulip_rx_desc {
+	s32 status;
+	s32 length;
+	u32 buffer1, buffer2;
+};
+
+struct tulip_tx_desc {
+	s32 status;
+	s32 length;
+	u32 buffer1, buffer2;				/* We use only buffer 1.  */
+};
+
+struct medialeaf {
+	u8 type;
+	u8 media;
+	unsigned char *leafdata;
+};
+
+struct mediatable {
+	u16 defaultmedia;
+	u8 leafcount, csr12dir;				/* General purpose pin directions. */
+	unsigned has_mii:1, has_nonmii:1;
+	struct medialeaf mleaf[0];
+};
+
+struct mediainfo {
+	struct mediainfo *next;
+	int info_type;
+	int index;
+	unsigned char *info;
+};
+
+struct tulip_private {
+	char devname[8];			/* Used only for kernel debugging. */
+	const char *product_name;
+	struct device *next_module;
+	struct tulip_rx_desc rx_ring[RX_RING_SIZE];
+	struct tulip_tx_desc tx_ring[TX_RING_SIZE];
+	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
+	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+	/* The addresses of receive-in-place skbuffs. */
+	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+	char *rx_buffs;				/* Address of temporary Rx buffers. */
+	u32 setup_frame[48];		/* Pseudo-Tx frame to init address table. */
+	int chip_id;
+	int revision;
+#if LINUX_VERSION_CODE > 0x20139
+	struct net_device_stats stats;
+#else
+	struct enet_statistics stats;
+#endif
+	struct timer_list timer;	/* Media selection timer. */
+	int interrupt;				/* In-interrupt flag. */
+#ifdef SMP_CHECK
+	int smp_proc_id;			/* Which processor in IRQ handler. */
+#endif
+	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
+	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+	unsigned int tx_full:1;				/* The Tx queue is full. */
+	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
+	unsigned int full_duplex_lock:1;
+	unsigned int fake_addr:1;			/* Multiport board faked address. */
+	unsigned int default_port:4;		/* Last dev->if_port value. */
+	unsigned int media2:4;				/* Secondary monitored media port. */
+	unsigned int medialock:1;			/* Don't sense media type. */
+	unsigned int mediasense:1;			/* Media sensing in progress. */
+	unsigned int csr6;					/* Current CSR6 control settings. */
+	unsigned char eeprom[128];			/* Serial EEPROM contents. */
+	u16 to_advertise;					/* NWay capabilities advertised.  */
+	u16 advertising[4];
+	signed char phys[4], mii_cnt;		/* MII device addresses. */
+	struct mediatable *mtable;
+	int cur_index;						/* Current media index. */
+	unsigned char pci_bus, pci_dev_fn;
+	int pad0, pad1;						/* Used for 8-byte alignment */
+};
+
+static struct device *tulip_probe1(int pci_bus, int pci_devfn,
+								   struct device *dev,
+								   int chip_id, int options);
+static void parse_eeprom(struct device *dev);
+static int read_eeprom(long ioaddr, int location);
+static int mdio_read(struct device *dev, int phy_id, int location);
+static void mdio_write(struct device *dev, int phy_id, int location, int value);
+static void select_media(struct device *dev, int startup);
+static int tulip_open(struct device *dev);
+static void tulip_timer(unsigned long data);
+static void tulip_tx_timeout(struct device *dev);
+static void tulip_init_ring(struct device *dev);
+static int tulip_start_xmit(struct sk_buff *skb, struct device *dev);
+static int tulip_rx(struct device *dev);
+static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs);
+static int tulip_close(struct device *dev);
+static struct enet_statistics *tulip_get_stats(struct device *dev);
+#ifdef HAVE_PRIVATE_IOCTL
+static int private_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+#endif
+#ifdef NEW_MULTICAST
+static void set_rx_mode(struct device *dev);
+#else
+static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+
+
+/* A list of all installed Tulip devices, for removing the driver module. */
+static struct device *root_tulip_dev = NULL;
+
+/* This 21040 probe no longer uses a large fixed contiguous Rx buffer region,
+   but now receives directly into full-sized skbuffs that are allocated
+   at open() time.
+   This allows the probe routine to use the old driver initialization
+   interface. */
+
+int tulip_probe(struct device *dev)
+{
+	int cards_found = 0;
+	static int pci_index = 0;	/* Static, for multiple probe calls. */
+	unsigned char pci_bus, pci_device_fn;
+
+	/* Ideally we would detect all network cards in slot order.  That would
+	   be best done a central PCI probe dispatch, which wouldn't work
+	   well with the current structure.  So instead we detect just the
+	   Tulip cards in slot order. */
+
+#if LINUX_VERSION_CODE >= 0x20155
+	if (! pci_present())
+		return -ENODEV;
+#else
+	if (! pcibios_present())
+		return -ENODEV;
+#endif
+	for (;pci_index < 0xff; pci_index++) {
+		u16 vendor, device, pci_command, new_command;
+		unsigned long pci_ioaddr = 0;
+		int chip_idx = 0;
+
+		if (pcibios_find_class
+			(PCI_CLASS_NETWORK_ETHERNET << 8,
+			 reverse_probe ? 0xfe - pci_index : pci_index,
+			 &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
+			if (reverse_probe)
+				continue;
+			else
+				break;
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+								 PCI_VENDOR_ID, &vendor);
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+								 PCI_DEVICE_ID, &device);
+
+		for (chip_idx = 0; tulip_tbl[chip_idx].chip_name; chip_idx++)
+			if (vendor == tulip_tbl[chip_idx].vendor_id  &&
+				device == tulip_tbl[chip_idx].device_id)
+				break;
+		if (tulip_tbl[chip_idx].chip_name == 0) {
+			if (vendor == PCI_VENDOR_ID_DEC  ||
+				vendor == PCI_VENDOR_ID_LITEON)
+				printk(KERN_INFO "Unknown Tulip-style PCI ethernet chip type"
+					   " %4.4x %4.4x"" detected: not configured.\n",
+					   vendor, device);
+			continue;
+		}
+#if LINUX_VERSION_CODE >= 0x20155
+		pci_ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0];
+#else
+		pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
+								  &pci_ioaddr);
+#endif
+		/* Remove I/O space marker in bit 0. */
+		pci_ioaddr &= ~3;
+
+		if (tulip_debug > 2)
+			printk(KERN_DEBUG "Found %s at I/O %#lx.\n",
+				   tulip_tbl[chip_idx].chip_name, pci_ioaddr);
+
+		if (check_region(pci_ioaddr, tulip_tbl[chip_idx].io_size))
+			continue;
+
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+								 PCI_COMMAND, &pci_command);
+		new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+		if (pci_command != new_command) {
+			printk(KERN_INFO "  The PCI BIOS has not enabled this"
+				   " device!  Updating PCI command %4.4x->%4.4x.\n",
+				   pci_command, new_command);
+			pcibios_write_config_word(pci_bus, pci_device_fn,
+									  PCI_COMMAND, new_command);
+		}
+
+		dev = tulip_probe1(pci_bus, pci_device_fn, dev, chip_idx, cards_found);
+
+		/* Get and check the bus-master and latency values. */
+		if (dev) {
+			unsigned char pci_latency;
+			pcibios_read_config_byte(pci_bus, pci_device_fn,
+									 PCI_LATENCY_TIMER, &pci_latency);
+			if (pci_latency < 10) {
+				printk(KERN_INFO "  PCI latency timer (CFLT) is "
+					   "unreasonably low at %d.  Setting to 64 clocks.\n",
+					   pci_latency);
+				pcibios_write_config_byte(pci_bus, pci_device_fn,
+										  PCI_LATENCY_TIMER, 64);
+			} else if (tulip_debug > 1)
+				printk(KERN_INFO "  PCI latency timer (CFLT) is %#x, "
+					   " PCI command is %4.4x.\n",
+					   pci_latency, new_command);
+			/* Bring the 21143 out power-down mode. */
+			if (device == PCI_DEVICE_ID_DEC_TULIP_21142)
+				pcibios_write_config_dword(pci_bus, pci_device_fn,
+										   0x40, 0x40000000);
+			dev = 0;
+			cards_found++;
+		}
+	}
+
+	return cards_found ? 0 : -ENODEV;
+}
+
+static struct device *tulip_probe1(int pci_bus, int pci_device_fn,
+								   struct device *dev,
+								   int chip_id, int board_idx)
+{
+	static int did_version = 0;			/* Already printed version info. */
+	struct tulip_private *tp;
+	long ioaddr;
+	int irq;
+	/* See note below on the multiport cards. */
+	static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
+	static int last_irq = 0;
+	static int multiport_cnt = 0;		/* For four-port boards w/one EEPROM */
+	int i;
+	unsigned short sum;
+
+	if (tulip_debug > 0  &&  did_version++ == 0)
+		printk(KERN_INFO "%s", version);
+
+	dev = init_etherdev(dev, 0);
+
+#if LINUX_VERSION_CODE >= 0x20155
+	irq = pci_find_slot(pci_bus, pci_device_fn)->irq;
+	ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0];
+#else
+	{
+		u8 pci_irq_line;
+		u32 pci_ioaddr;
+		pcibios_read_config_byte(pci_bus, pci_device_fn,
+								 PCI_INTERRUPT_LINE, &pci_irq_line);
+		pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
+								  &pci_ioaddr);
+		irq = pci_irq_line;
+		ioaddr = pci_ioaddr;
+	}
+#endif
+	/* Remove I/O space marker in bit 0. */
+	ioaddr &= ~3;
+
+	printk(KERN_INFO "%s: %s at %#3lx,",
+		   dev->name, tulip_tbl[chip_id].chip_name, ioaddr);
+
+	/* Stop the chip's Tx and Rx processes. */
+	outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
+	/* Clear the missed-packet counter. */
+	(volatile int)inl(ioaddr + CSR8);
+
+	if (chip_id == DC21041) {
+		if (inl(ioaddr + CSR9) & 0x8000) {
+			printk(" 21040 compatible mode,");
+			chip_id = DC21040;
+		} else {
+			printk(" 21041 mode,");
+		}
+	}
+
+	/* The station address ROM is read byte serially.  The register must
+	   be polled, waiting for the value to be read bit serially from the
+	   EEPROM.
+	   */
+	sum = 0;
+	if (chip_id == DC21040) {
+		outl(0, ioaddr + CSR9);		/* Reset the pointer with a dummy write. */
+		for (i = 0; i < 6; i++) {
+			int value, boguscnt = 100000;
+			do
+				value = inl(ioaddr + CSR9);
+			while (value < 0  && --boguscnt > 0);
+			dev->dev_addr[i] = value;
+			sum += value & 0xff;
+		}
+	} else if (chip_id == LC82C168) {
+		for (i = 0; i < 3; i++) {
+			int value, boguscnt = 100000;
+			outl(0x600 | i, ioaddr + 0x98);
+			do
+				value = inl(ioaddr + CSR9);
+			while (value < 0  && --boguscnt > 0);
+			((u16*)dev->dev_addr)[i] = value;
+			sum += value & 0xffff;
+		}
+	} else {	/* Must be a new chip, with a serial EEPROM interface. */
+		/* We read the whole EEPROM, and sort it out later.  DEC has a
+		   specification _Digital Semiconductor 21X4 Serial ROM Format_
+		   but early vendor boards just put the address in the first six
+		   EEPROM locations. */
+		unsigned char ee_data[128];
+		int sa_offset = 0;
+
+		for (i = 0; i < sizeof(ee_data)/2; i++)
+			((u16 *)ee_data)[i] = read_eeprom(ioaddr, i);
+
+		/* Detect the simple EEPROM format by the duplicated station addr. */
+		for (i = 0; i < 8; i ++)
+			if (ee_data[i] != ee_data[16+i])
+				sa_offset = 20;
+		if (ee_data[0] == 0xff  &&  ee_data[1] == 0xff &&  ee_data[2] == 0) {
+			sa_offset = 2;		/* Grrr, damn Matrox boards. */
+			multiport_cnt = 4;
+		}
+		for (i = 0; i < 6; i ++) {
+			dev->dev_addr[i] = ee_data[i + sa_offset];
+			sum += ee_data[i + sa_offset];
+		}
+	}
+	/* Lite-On boards have the address byte-swapped. */
+	if (dev->dev_addr[0] == 0xA0  &&  dev->dev_addr[1] == 0x00)
+		for (i = 0; i < 6; i+=2) {
+			char tmp = dev->dev_addr[i];
+			dev->dev_addr[i] = dev->dev_addr[i+1];
+			dev->dev_addr[i+1] = tmp;
+		}
+	/* On the Zynx 315 Etherarray and other multiport boards only the
+	   first Tulip has an EEPROM.
+	   The addresses of the subsequent ports are derived from the first.
+	   Many PCI BIOSes also incorrectly report the IRQ line, so we correct
+	   that here as well. */
+	if (sum == 0  || sum == 6*0xff) {
+		printk(" EEPROM not present,");
+		for (i = 0; i < 5; i++)
+			dev->dev_addr[i] = last_phys_addr[i];
+		dev->dev_addr[i] = last_phys_addr[i] + 1;
+#if defined(__i386__)		/* This BIOS bug doesn't exist on Alphas. */
+		irq = last_irq;
+#endif
+	}
+
+	for (i = 0; i < 6; i++)
+		printk(" %2.2x", last_phys_addr[i] = dev->dev_addr[i]);
+	printk(", IRQ %d.\n", irq);
+	last_irq = irq;
+
+	/* We do a request_region() only to register /proc/ioports info. */
+	/* Note that proper size is tulip_tbl[chip_id].chip_name, but... */
+	request_region(ioaddr, TULIP_TOTAL_SIZE, dev->name);
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+
+	/* Make certain the data structures are quadword aligned. */
+	tp = (void *)(((long)kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA) + 7) & ~7);
+	memset(tp, 0, sizeof(*tp));
+	dev->priv = tp;
+
+	tp->next_module = root_tulip_dev;
+	root_tulip_dev = dev;
+
+	tp->pci_bus = pci_bus;
+	tp->pci_dev_fn = pci_device_fn;
+	tp->chip_id = chip_id;
+
+#ifdef TULIP_FULL_DUPLEX
+	tp->full_duplex = 1;
+	tp->full_duplex_lock = 1;
+#endif
+#ifdef TULIP_DEFAULT_MEDIA
+	tp->default_port = TULIP_DEFAULT_MEDIA;
+#endif
+#ifdef TULIP_NO_MEDIA_SWITCH
+	tp->medialock = 1;
+#endif
+
+	/* The lower four bits are the media type. */
+	if (board_idx >= 0  &&  board_idx < MAX_UNITS) {
+		tp->default_port = options[board_idx] & 15;
+		if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)
+			tp->full_duplex = 1;
+		if (mtu[board_idx] > 0)
+			dev->mtu = mtu[board_idx];
+	}
+	if (dev->mem_start)
+		tp->default_port = dev->mem_start;
+	if (tp->default_port) {
+		tp->medialock = 1;
+		if (media_cap[tp->default_port] & MediaAlwaysFD)
+			tp->full_duplex = 1;
+	}
+	if (tp->full_duplex)
+		tp->full_duplex_lock = 1;
+
+	/* This is logically part of probe1(), but too complex to write inline. */
+	if (tulip_tbl[chip_id].flags & HAS_MEDIA_TABLE)
+		parse_eeprom(dev);
+
+	if (media_cap[tp->default_port] & MediaIsMII) {
+		u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
+		tp->to_advertise = media2advert[tp->default_port - 9];
+	} else
+		tp->to_advertise = 0x03e1;
+
+	if ((tp->mtable  &&  tp->mtable->has_mii) ||
+		( ! tp->mtable  &&  (tulip_tbl[tp->chip_id].flags & HAS_MII))) {
+		int phy, phy_idx;
+		/* Find the connected MII xcvrs.
+		   Doing this in open() would allow detecting external xcvrs later,
+		   but takes much time. */
+		for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
+			 phy++) {
+			int mii_status = mdio_read(dev, phy, 1);
+			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+				int mii_reg0 = mdio_read(dev, phy, 0);
+				int reg4 = ((mii_status>>6) & tp->to_advertise) | 1;
+				tp->phys[phy_idx] = phy;
+				tp->advertising[phy_idx++] = reg4;
+				printk(KERN_INFO "%s:  MII transceiver found at MDIO address "
+					   "%d, config %4.4x status %4.4x.\n",
+					   dev->name, phy, mii_reg0, mii_status);
+				if (1 || (media_cap[tp->default_port] & MediaIsMII)) {
+					printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d,"
+						   " previously advertising %4.4x.\n",
+						   dev->name, reg4, phy, mdio_read(dev, phy, 4));
+					mdio_write(dev, phy, 4, reg4);
+				}
+				/* Enable autonegotiation: some boards default to off. */
+				mdio_write(dev, phy, 0, mii_reg0 |
+						   (tp->full_duplex ? 0x1100 : 0x1000) |
+						   (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0));
+			}
+		}
+		tp->mii_cnt = phy_idx;
+		if (tp->mtable  &&  tp->mtable->has_mii  &&  phy_idx == 0) {
+			printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
+				   dev->name);
+			tp->phys[0] = 1;
+		}
+	}
+
+	/* The Tulip-specific entries in the device structure. */
+	dev->open = &tulip_open;
+	dev->hard_start_xmit = &tulip_start_xmit;
+	dev->stop = &tulip_close;
+	dev->get_stats = &tulip_get_stats;
+#ifdef HAVE_PRIVATE_IOCTL
+	dev->do_ioctl = &private_ioctl;
+#endif
+#ifdef HAVE_MULTICAST
+	dev->set_multicast_list = &set_rx_mode;
+#endif
+
+	/* Reset the xcvr interface and turn on heartbeat. */
+	switch (chip_id) {
+	case DC21041:
+		outl(0x00000000, ioaddr + CSR13);
+		outl(0xFFFFFFFF, ioaddr + CSR14);
+		outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
+		outl(inl(ioaddr + CSR6) | 0x0200, ioaddr + CSR6);
+		outl(0x0000EF05, ioaddr + CSR13);
+		break;
+	case DC21040:
+		outl(0x00000000, ioaddr + CSR13);
+		outl(0x00000004, ioaddr + CSR13);
+		break;
+	case DC21140: default:
+		if (tp->mtable)
+			outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
+		break;
+	case DC21142:
+		outl(0x82420200, ioaddr + CSR6);
+		outl(0x0001, ioaddr + CSR13);
+		outl(0x0003FFFF, ioaddr + CSR14);
+		outl(0x0008, ioaddr + CSR15);
+		outl(0x0001, ioaddr + CSR13);
+		outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+		break;
+	case LC82C168:
+		if ( ! tp->mii_cnt) {
+			outl(0x00420000, ioaddr + CSR6);
+			outl(0x30, ioaddr + CSR12);
+			outl(0x0001F078, ioaddr + 0xB8);
+			outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
+		}
+		break;
+	case MX98713: case MX98715: case MX98725:
+		outl(0x00000000, ioaddr + CSR6);
+		outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
+		outl(0x00000001, ioaddr + CSR13);
+		break;
+	}
+
+	return dev;
+}
+
+/* Serial EEPROM section. */
+/* The main routine to parse the very complicated SROM structure.
+   Search www.digital.com for "21X4 SROM" to get details.
+   This code is very complex, and will require changes to support
+   additional cards, so I'll be verbose about what is going on.
+   */
+
+/* Known cards that have old-style EEPROMs. */
+static struct fixups {
+  char *name;
+  unsigned char addr0, addr1, addr2;
+  u16 newtable[32];				/* Max length below. */
+} eeprom_fixups[] = {
+  {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c,
+						  0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }},
+  {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x021f,
+							   0x0000, 0x009E, /* 10baseT */
+							   0x0903, 0x006D, /* 100baseTx */ }},
+  {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x033f,
+								 0x0107, 0x8021, /* 100baseFx */
+								 0x0108, 0x8021, /* 100baseFx-FD */
+								 0x0103, 0x006D, /* 100baseTx */ }},
+  {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0313,
+							   0x1001, 0x009E, /* 10base2, CSR12 0x10*/
+							   0x0000, 0x009E, /* 10baseT */
+							   0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ }},
+  {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x031F,
+							0x1B01, 0x0000, /* 10base2,   CSR12 0x1B */
+							0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ 
+							0x0B00, 0x009E, /* 10baseT,   CSR12 0x0B */
+   }},
+  {0, 0, 0, 0, {}}};
+
+static const char * block_name[] = {"21140 non-MII", "21140 MII PHY",
+ "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};
+
+#define EEPROM_SIZE 128
+#if defined(__i386__)
+#define get_u16(ptr) (*(u16 *)(ptr))
+#else
+#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8))
+#endif
+
+static void parse_eeprom(struct device *dev)
+{
+	/* The last media info list parsed, for multiport boards.  */
+	static struct mediatable *last_mediatable = NULL;
+	static unsigned char *last_ee_data = NULL;
+	static int controller_index = 0;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	unsigned char *ee_data = tp->eeprom;
+	int i;
+
+	tp->mtable = 0;
+	for (i = 0; i < EEPROM_SIZE/2; i++)
+		((u16 *)ee_data)[i] = read_eeprom(ioaddr, i);
+
+	/* Detect an old-style (SA only) EEPROM layout:
+	   memcmp(eedata, eedata+16, 8). */
+	for (i = 0; i < 8; i ++)
+		if (ee_data[i] != ee_data[16+i])
+			break;
+	if (i >= 8) {
+		if (ee_data[0] == 0xff) {
+			if (last_mediatable) {
+				controller_index++;
+				printk(KERN_INFO "%s:  Controller %d of multiport board.\n",
+					   dev->name, controller_index);
+				tp->mtable = last_mediatable;
+				ee_data = last_ee_data;
+				goto subsequent_board;
+			} else
+				printk(KERN_INFO "%s:  Missing EEPROM, this interface may "
+					   "not work correctly!\n",
+			   dev->name);
+			return;
+		}
+	  /* Do a fix-up based on the vendor half of the station address prefix. */
+	  for (i = 0; eeprom_fixups[i].name; i++) {
+		if (dev->dev_addr[0] == eeprom_fixups[i].addr0
+			&&  dev->dev_addr[1] == eeprom_fixups[i].addr1
+			&&  dev->dev_addr[2] == eeprom_fixups[i].addr2) {
+		  if (dev->dev_addr[2] == 0xE8  &&  ee_data[0x1a] == 0x55)
+			  i++;			/* An Accton EN1207, not an outlaw Maxtech. */
+		  memcpy(ee_data + 26, eeprom_fixups[i].newtable,
+				 sizeof(eeprom_fixups[i].newtable));
+		  printk(KERN_INFO "%s: Old format EEPROM on '%s' board.  Using"
+				 " substitute media control info.\n",
+				 dev->name, eeprom_fixups[i].name);
+		  break;
+		}
+	  }
+	  if (eeprom_fixups[i].name == NULL) { /* No fixup found. */
+		printk(KERN_INFO "%s: Old style EEPROM -- no media selection information.\n",
+			   dev->name);
+		return;
+	  }
+	}
+	if (tulip_debug > 1) {
+	  printk(KERN_DEBUG "read_eeprom:");
+	  for (i = 0; i < 64; i++) {
+		printk("%s%4.4x", (i & 7) == 0 ? "\n" KERN_DEBUG : " ",
+			   read_eeprom(ioaddr, i));
+	  }
+	  printk("\n");
+	}
+	
+	controller_index = 0;
+	if (ee_data[19] > 1) {		/* Multiport board. */
+		last_ee_data = ee_data;
+	}
+subsequent_board:
+
+	if (ee_data[27] == 0) {		/* No valid media table. */
+	} else if (tp->chip_id == DC21041) {
+		unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3];
+		short media;
+		int count;
+
+		media = get_u16(p);
+		p += 2;
+		count = *p++;
+
+		printk(KERN_INFO "%s:21041 Media information at %d, default media "
+			   "%4.4x (%s).\n", dev->name, ee_data[27], media,
+			   media & 0x0800 ? "Autosense" : medianame[media & 15]);
+		for (i = 0; i < count; i++) {
+			unsigned char media_code = *p++;
+			u16 csrvals[3];
+			int idx;
+			for (idx = 0; idx < 3; idx++) {
+				csrvals[idx] = get_u16(p);
+				p += 2;
+			}
+			if (media_code & 0x40) {
+				printk(KERN_INFO "%s:  21041 media %2.2x (%s),"
+					   " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n",
+					   dev->name, media_code & 15, medianame[media_code & 15],
+					   csrvals[0], csrvals[1], csrvals[2]);
+			} else
+				printk(KERN_INFO "%s:  21041 media #%d, %s.\n",
+					   dev->name, media_code & 15, medianame[media_code & 15]);
+		}
+	} else {
+		unsigned char *p = (void *)ee_data + ee_data[27];
+		unsigned char csr12dir = 0;
+		int count;
+		struct mediatable *mtable;
+		u16 media = get_u16(p);
+
+		p += 2;
+		if (tulip_tbl[tp->chip_id].flags & CSR12_IN_SROM)
+			csr12dir = *p++;
+		count = *p++;
+		mtable = (struct mediatable *)
+			kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf),
+					GFP_KERNEL);
+		if (mtable == NULL)
+			return;				/* Horrible, impossible failure. */
+		last_mediatable = tp->mtable = mtable;
+		mtable->defaultmedia = media;
+		mtable->leafcount = count;
+		mtable->csr12dir = csr12dir;
+		mtable->has_nonmii = mtable->has_mii = 0;
+
+		printk(KERN_INFO "%s:  EEPROM default media type %s.\n", dev->name,
+			   media & 0x0800 ? "Autosense" : medianame[media & 15]);
+		for (i = 0; i < count; i++) {
+			struct medialeaf *leaf = &mtable->mleaf[i];
+			
+			if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */
+				leaf->type = 0;
+				leaf->media = p[0] & 0x3f;
+				leaf->leafdata = p;
+				if ((p[2] & 0x61) == 0x01)	/* Bogus, but Znyx boards do it. */
+					mtable->has_mii = 1;
+				p += 4;
+			} else {
+				leaf->type = p[1];
+				if (p[1] & 1) {
+					mtable->has_mii = 1;
+					leaf->media = 11;
+				} else {
+					mtable->has_nonmii = 1;
+					leaf->media = p[2] & 0x0f;
+				}
+				leaf->leafdata = p + 2;
+				p += (p[0] & 0x3f) + 1;
+			}
+			if (tulip_debug > 1  &&  leaf->media == 11) {
+				unsigned char *bp = leaf->leafdata;
+				printk(KERN_INFO "%s:  MII interface PHY %d, setup/reset "
+					   "sequences %d/%d long, capabilities %2.2x %2.2x.\n",
+					   dev->name, bp[0], bp[1], bp[1 + bp[1]*2],
+					   bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]);
+			}
+			printk(KERN_INFO "%s:  Index #%d - Media %s (#%d) described "
+				   "by a %s (%d) block.\n",
+				   dev->name, i, medianame[leaf->media], leaf->media,
+				   block_name[leaf->type], leaf->type);
+		}
+	}
+}
+/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/
+
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK	0x02	/* EEPROM shift clock. */
+#define EE_CS			0x01	/* EEPROM chip select. */
+#define EE_DATA_WRITE	0x04	/* EEPROM chip data in. */
+#define EE_WRITE_0		0x01
+#define EE_WRITE_1		0x05
+#define EE_DATA_READ	0x08	/* EEPROM chip data out. */
+#define EE_ENB			(0x4800 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+   The 1.2 code is a "nasty" timing loop, but PC compatible machines are
+   *supposed* to delay an ISA-compatible period for the SLOW_DOWN_IO macro.  */
+#ifdef _LINUX_DELAY_H
+#define eeprom_delay(nanosec)	udelay((nanosec + 999)/1000)
+#else
+#define eeprom_delay(nanosec)	do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
+#endif
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD	(5 << 6)
+#define EE_READ_CMD		(6 << 6)
+#define EE_ERASE_CMD	(7 << 6)
+
+static int read_eeprom(long ioaddr, int location)
+{
+	int i;
+	unsigned short retval = 0;
+	long ee_addr = ioaddr + CSR9;
+	int read_cmd = location | EE_READ_CMD;
+	
+	outl(EE_ENB & ~EE_CS, ee_addr);
+	outl(EE_ENB, ee_addr);
+	
+	/* Shift the read command bits out. */
+	for (i = 10; i >= 0; i--) {
+		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+		outl(EE_ENB | dataval, ee_addr);
+		eeprom_delay(100);
+		outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay(150);
+		outl(EE_ENB | dataval, ee_addr);	/* Finish EEPROM a clock tick. */
+		eeprom_delay(250);
+	}
+	outl(EE_ENB, ee_addr);
+	
+	for (i = 16; i > 0; i--) {
+		outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay(100);
+		retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+		outl(EE_ENB, ee_addr);
+		eeprom_delay(100);
+	}
+
+	/* Terminate the EEPROM access. */
+	outl(EE_ENB & ~EE_CS, ee_addr);
+	return retval;
+}
+
+/* MII transceiver control section.
+   Read and write the MII registers using software-generated serial
+   MDIO protocol.  See the MII specifications or DP83840A data sheet
+   for details. */
+
+/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+   "overclocking" issues or future 66Mhz PCI. */
+#define mdio_delay() inl(mdio_addr)
+
+/* Read and write the MII registers using software-generated serial
+   MDIO protocol.  It is just different enough from the EEPROM protocol
+   to not share code.  The maxium data clock rate is 2.5 Mhz. */
+#define MDIO_SHIFT_CLK	0x10000
+#define MDIO_DATA_WRITE0 0x00000
+#define MDIO_DATA_WRITE1 0x20000
+#define MDIO_ENB		0x00000		/* Ignore the 0x02000 databook setting. */
+#define MDIO_ENB_IN		0x40000
+#define MDIO_DATA_READ	0x80000
+
+static int mdio_read(struct device *dev, int phy_id, int location)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int i;
+	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+	int retval = 0;
+	long mdio_addr = dev->base_addr + CSR9;
+
+	if (tp->chip_id == LC82C168) {
+		long ioaddr = dev->base_addr;
+		int i = 1000;
+		outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
+		while (--i > 0)
+			if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
+				return retval & 0xffff;
+		return 0xffff;
+	}
+
+	/* Establish sync by sending at least 32 logic ones. */ 
+	for (i = 32; i >= 0; i--) {
+		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+		mdio_delay();
+		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Shift the read command bits out. */
+	for (i = 15; i >= 0; i--) {
+		int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+
+		outl(MDIO_ENB | dataval, mdio_addr);
+		mdio_delay();
+		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 19; i > 0; i--) {
+		outl(MDIO_ENB_IN, mdio_addr);
+		mdio_delay();
+		retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	return (retval>>1) & 0xffff;
+}
+
+static void mdio_write(struct device *dev, int phy_id, int location, int value)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int i;
+	int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+	long mdio_addr = dev->base_addr + CSR9;
+
+	if (tp->chip_id == LC82C168) {
+		long ioaddr = dev->base_addr;
+		int i = 1000;
+		outl(cmd, ioaddr + 0xA0);
+		do
+			if ( ! (inl(ioaddr + 0xA0) & 0x80000000))
+				break;
+		while (--i > 0);
+		return;
+	}
+
+	/* Establish sync by sending 32 logic ones. */ 
+	for (i = 32; i >= 0; i--) {
+		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+		mdio_delay();
+		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Shift the command bits out. */
+	for (i = 31; i >= 0; i--) {
+		int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+		outl(MDIO_ENB | dataval, mdio_addr);
+		mdio_delay();
+		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Clear out extra bits. */
+	for (i = 2; i > 0; i--) {
+		outl(MDIO_ENB_IN, mdio_addr);
+		mdio_delay();
+		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	return;
+}
+
+
+static int
+tulip_open(struct device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int i = 0;
+
+	/* On some chip revs we must set the MII/SYM port before the reset!? */
+	if (tp->mii_cnt  ||  (tp->mtable  &&  tp->mtable->has_mii))
+		outl(0x00040000, ioaddr + CSR6);
+
+	/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
+	outl(0x00000001, ioaddr + CSR0);
+#ifdef _LINUX_DELAY_H
+	udelay(2);
+#else
+	SLOW_DOWN_IO;
+#endif
+	/* Deassert reset.
+	   486: Set 8 longword cache alignment, 8 longword burst.
+	   586: Set 16 longword cache alignment, no burst limit.
+	   Cache alignment bits 15:14	     Burst length 13:8
+		0000	No alignment  0x00000000 unlimited		0800 8 longwords
+		4000	8  longwords		0100 1 longword		1000 16 longwords
+		8000	16 longwords		0200 2 longwords	2000 32 longwords
+		C000	32  longwords		0400 4 longwords
+	   Wait the specified 50 PCI cycles after a reset by initializing
+	   Tx and Rx queues and the address filter list. */
+#if defined(__alpha__)
+	/* ToDo: Alpha setting could be better. */
+	outl(0x01A00000 | 0xE000, ioaddr + CSR0);
+#elif defined(__powerpc__)
+	outl(0x01A00080 | 0x8000, ioaddr + CSR0);
+#elif defined(__i386__)
+#if defined(MODULE)
+	/* When a module we don't have 'x86' to check. */
+	outl(0x01A00000 | 0x4800, ioaddr + CSR0);
+#else
+#if (LINUX_VERSION_CODE > 0x2014c)
+#define x86 boot_cpu_data.x86
+#endif
+	outl(0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0);
+	if (x86 <= 4)
+	  printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache "
+			 "alignment to %x.\n", dev->name,
+			 0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000));
+#endif
+#else
+	outl(0x01A00000 | 0x4800, ioaddr + CSR0);
+#warning Processor architecture undefined!
+#endif
+
+#ifdef SA_SHIRQ
+	if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) {
+		return -EAGAIN;
+	}
+#else
+	if (irq2dev_map[dev->irq] != NULL
+		|| (irq2dev_map[dev->irq] = dev) == NULL
+		|| dev->irq == 0
+		|| request_irq(dev->irq, &tulip_interrupt, 0,
+					   tulip_tbl[tp->chip_id].chip_name)) {
+		return -EAGAIN;
+	}
+#endif
+
+	if (tulip_debug > 1)
+		printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq);
+
+	MOD_INC_USE_COUNT;
+
+	tulip_init_ring(dev);
+
+	/* This is set_rx_mode(), but without starting the transmitter. */
+	/* Fill the whole address filter table with our physical address. */
+	{
+		u16 *eaddrs = (u16 *)dev->dev_addr;
+		u32 *setup_frm = tp->setup_frame, i;
+
+		/* You must add the broadcast address when doing perfect filtering! */
+		*setup_frm++ = 0xffff;
+		*setup_frm++ = 0xffff;
+		*setup_frm++ = 0xffff;
+		/* Fill the rest of the accept table with our physical address. */
+		for (i = 1; i < 16; i++) {
+			*setup_frm++ = eaddrs[0];
+			*setup_frm++ = eaddrs[1];
+			*setup_frm++ = eaddrs[2];
+		}
+		/* Put the setup frame on the Tx list. */
+		tp->tx_ring[0].length = 0x08000000 | 192;
+		tp->tx_ring[0].buffer1 = virt_to_bus(tp->setup_frame);
+		tp->tx_ring[0].status = 0x80000000;
+
+		tp->cur_tx++;
+	}
+
+	outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3);
+	outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
+
+	if (dev->if_port == 0)
+		dev->if_port = tp->default_port;
+	if (tp->chip_id == DC21041  &&  dev->if_port > 4)
+		/* Invalid: Select initial TP, autosense, autonegotiate.  */
+		dev->if_port = 4;
+
+	/* Allow selecting a default media. */
+	if (tp->mtable == NULL)
+		goto media_picked;
+	if (dev->if_port) {
+		int looking_for = media_cap[dev->if_port] & MediaIsMII ? 11 :
+			(dev->if_port == 12 ? 0 : dev->if_port);
+		for (i = 0; i < tp->mtable->leafcount; i++)
+			if (tp->mtable->mleaf[i].media == looking_for) {
+				printk(KERN_INFO "%s: Using user-specified media %s.\n",
+					   dev->name, medianame[dev->if_port]);
+				goto media_picked;
+			}
+	}
+	if ((tp->mtable->defaultmedia & 0x0800) == 0)
+		for (i = 0; i < tp->mtable->leafcount; i++)
+		  if (tp->mtable->mleaf[i].media == (tp->mtable->defaultmedia & 15)) {
+			printk(KERN_INFO "%s: Using EEPROM-set media %s.\n",
+				   dev->name, medianame[tp->mtable->mleaf[i].media]);
+			goto media_picked;
+		  }
+	/* Start sensing first non-full-duplex media. */
+	for (i = tp->mtable->leafcount - 1;
+		 (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--)
+	  ;
+media_picked:
+
+	tp->csr6 = 0;
+	tp->cur_index = i;
+	if (dev->if_port == 0  &&  tp->chip_id == DC21142) {
+		tp->csr6 = 0x82420200;
+		outl(0x0003FFFF, ioaddr + CSR14);
+		outl(0x0008, ioaddr + CSR15);
+		outl(0x0001, ioaddr + CSR13);
+		outl(0x1301, ioaddr + CSR12);
+	} else if (tp->chip_id == LC82C168  &&  tp->mii_cnt && ! tp->medialock) {
+		dev->if_port = 11;
+		tp->csr6 = 0x816C0000 | (tp->full_duplex ? 0x0200 : 0);
+		outl(0x0001, ioaddr + CSR15);
+	} else
+		select_media(dev, 1);
+
+	/* Start the chip's Tx to process setup frame. */
+	outl(tp->csr6, ioaddr + CSR6);
+	outl(tp->csr6 | 0x2000, ioaddr + CSR6);
+
+	dev->tbusy = 0;
+	tp->interrupt = 0;
+	dev->start = 1;
+
+	/* Enable interrupts by setting the interrupt mask. */
+	outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
+	outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
+	outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+	outl(0, ioaddr + CSR2);		/* Rx poll demand */
+
+	if (tulip_debug > 2) {
+		printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
+			   dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5),
+			   inl(ioaddr + CSR6));
+	}
+	/* Set the timer to switch to check for link beat and perhaps switch
+	   to an alternate media type. */
+	init_timer(&tp->timer);
+	tp->timer.expires = RUN_AT(5*HZ);
+	tp->timer.data = (unsigned long)dev;
+	tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
+	add_timer(&tp->timer);
+
+	return 0;
+}
+
+/* Set up the transceiver control registers for the selected media type. */
+static void select_media(struct device *dev, int startup)
+{
+	long ioaddr = dev->base_addr;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct mediatable *mtable = tp->mtable;
+	u32 new_csr6;
+	int check_mii =0, i;
+
+	if (mtable) {
+		struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index];
+		unsigned char *p = mleaf->leafdata;
+		switch (mleaf->type) {
+		case 0:					/* 21140 non-MII xcvr. */
+			if (tulip_debug > 1)
+				printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver"
+					   " with control setting %2.2x.\n",
+					   dev->name, p[1]);
+			dev->if_port = p[0];
+			if (startup)
+				outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+			outl(p[1], ioaddr + CSR12);
+			new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
+			break;
+		case 2: case 4: {
+			u16 setup[3];
+			for (i = 0; i < 3; i++)
+				setup[i] = get_u16(&p[i*2 + 1]);
+
+			dev->if_port = p[0] & 15;
+			if (tulip_debug > 1)
+				printk(KERN_DEBUG "%s: 21142 non-MII %s transceiver control %4.4x/%4.4x.\n",
+					   dev->name, medianame[dev->if_port], setup[0], setup[1]);
+			if (p[0] & 0x40) {	/* SIA (CSR13-15) setup values are provided. */
+				outl(0, ioaddr + CSR13);
+				outl(setup[1], ioaddr + CSR14);
+				outl(setup[2], ioaddr + CSR15);
+				outl(setup[0], ioaddr + CSR13);
+				for (i = 0; i < 3; i++)			/* Re-fill setup[]  */
+					setup[i] = get_u16(&p[i*2 + 7]);
+			} else if (dev->if_port <= 4) {
+				outl(0, ioaddr + CSR13);
+				outl(t21142_csr14[dev->if_port], ioaddr + CSR14);
+				outl(t21142_csr15[dev->if_port], ioaddr + CSR15);
+				outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+			} else {
+				outl(0, ioaddr + CSR14);
+				outl(8, ioaddr + CSR15);
+				outl(0, ioaddr + CSR13);
+			}
+			outl(setup[0]<<16, ioaddr + CSR15);	/* Direction */
+			outl(setup[1]<<16, ioaddr + CSR15);	/* Data */
+			if (mleaf->type == 4)
+				new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
+			else
+				new_csr6 = 0x82420000;
+			break;
+		}
+		case 1: case 3: {
+			int phy_num = p[0];
+			int init_length = p[1];
+			u16 *misc_info;
+			u16 to_advertise;
+
+			dev->if_port = 11;
+			check_mii = 1;
+			new_csr6 = 0x020E0000;
+			if (mleaf->type == 3) {	/* 21142 */
+				u16 *init_sequence = (u16*)(p+2);
+				u16 *reset_sequence = &((u16*)(p+3))[init_length];
+				int reset_length = p[2 + init_length*2];
+				misc_info = reset_sequence + reset_length;
+				if (startup)
+					for (i = 0; i < reset_length; i++)
+						outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
+				for (i = 0; i < init_length; i++)
+					outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
+			} else {
+				u8 *init_sequence = p + 2;
+				u8 *reset_sequence = p + 3 + init_length;
+				int reset_length = p[2 + init_length];
+				misc_info = (u16*)(reset_sequence + reset_length);
+				if (startup) {
+					outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+					for (i = 0; i < reset_length; i++)
+						outl(reset_sequence[i], ioaddr + CSR12);
+				}
+				for (i = 0; i < init_length; i++)
+					outl(init_sequence[i], ioaddr + CSR12);
+			}
+			to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1;
+			tp->advertising[phy_num] = to_advertise;
+			if (tulip_debug > 1 || 1)
+				printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d (%d).\n",
+					   dev->name, to_advertise, phy_num, tp->phys[phy_num]);
+			/* Bogus: put in by a committee?  */
+			mdio_write(dev, tp->phys[phy_num], 4, to_advertise);
+			break;
+		}
+		default:
+		  new_csr6 = 0x020E0000;
+		}
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n",
+				   dev->name, medianame[dev->if_port],
+				   inl(ioaddr + CSR12) & 0xff);
+	} else if (tp->chip_id == DC21041) {
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n",
+				   dev->name, medianame[dev->if_port & 15],
+				   inl(ioaddr + CSR12) & 0xffff);
+		outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
+		outl(t21041_csr14[dev->if_port], ioaddr + CSR14);
+		outl(t21041_csr15[dev->if_port], ioaddr + CSR15);
+		outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
+		new_csr6 = 0x80020000;
+	} else if (tp->chip_id == LC82C168) {
+		if (startup && ! tp->medialock)
+			dev->if_port = tp->mii_cnt ? 11 : 0;
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, CSR12 %4.4x,"
+				   " media %s.\n",
+				   dev->name, inl(ioaddr + 0xB8), inl(ioaddr + CSR12),
+				   medianame[dev->if_port]);
+		if (tp->mii_cnt) {
+			new_csr6 = 0x812C0000;
+			outl(0x0001, ioaddr + CSR15);
+			outl(0x0201B07A, ioaddr + 0xB8);
+		} else if (startup) {
+			/* Start with 10mbps to do autonegotiation. */
+			outl(0x32, ioaddr + CSR12);
+			new_csr6 = 0x00420000;
+			outl(0x0001B078, ioaddr + 0xB8);
+			outl(0x0201B078, ioaddr + 0xB8);
+		} else if (dev->if_port == 3  ||  dev->if_port == 5) {
+			outl(0x33, ioaddr + CSR12);
+			new_csr6 = 0x01860000;
+			if (startup)
+				outl(0x0201F868, ioaddr + 0xB8); /* Trigger autonegotiation. */
+			else
+				outl(0x1F868, ioaddr + 0xB8);
+		} else {
+			outl(0x32, ioaddr + CSR12);
+			new_csr6 = 0x00420000;
+			outl(0x1F078, ioaddr + 0xB8);
+		}
+	} else if (tp->chip_id == DC21040) {					/* 21040 */
+		/* Turn on the xcvr interface. */
+		int csr12 = inl(ioaddr + CSR12);
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n",
+				   dev->name, dev->if_port ? "AUI" : "10baseT", csr12);
+		new_csr6 = (dev->if_port ? 0x01860000 : 0x00420000);
+		/* Set the full duplux match frame. */
+		outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11);
+		outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
+		outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
+	} else {					/* Unknown chip type with no media table. */
+		if (tp->default_port == 0)
+			if (tp->mii_cnt) {
+				dev->if_port = 11;
+			} else
+				dev->if_port = 3;
+		if (media_cap[dev->if_port] & MediaIsMII) {
+			new_csr6 = 0x020E0000;
+		} else if (media_cap[dev->if_port] & MediaIsFx) {
+			new_csr6 = 0x028600000;
+		} else
+			new_csr6 = 0x038600000;
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: No media description table, assuming "
+				   "%s transceiver, CSR12 %2.2x.\n",
+				   dev->name, medianame[dev->if_port],
+				   inl(ioaddr + CSR12));
+	}
+
+	tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
+	return;
+}
+
+static void tulip_timer(unsigned long data)
+{
+	struct device *dev = (struct device *)data;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	u32 csr12 = inl(ioaddr + CSR12);
+	int next_tick = 0;
+
+	if (tulip_debug > 3) {
+		printk(KERN_DEBUG "%s: Media selection tick, status %8.8x mode %8.8x "
+			   "SIA %8.8x %8.8x %8.8x %8.8x.\n",
+			   dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR6),
+			   csr12, inl(ioaddr + CSR13),
+			   inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+	}
+	switch (tp->chip_id) {
+	case DC21040:
+		if (csr12 & 0x0002) { /* Network error */
+			printk(KERN_INFO "%s: No 10baseT link beat found, switching to %s media.\n",
+				   dev->name, dev->if_port ? "10baseT" : "AUI");
+			dev->if_port ^= 1;
+			outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
+			dev->trans_start = jiffies;
+		}
+		break;
+	case DC21041:
+		if (tulip_debug > 2)
+			printk(KERN_DEBUG "%s: 21041 media tick  CSR12 %8.8x.\n",
+				   dev->name, csr12);
+		switch (dev->if_port) {
+		case 0: case 3: case 4:
+		  if (csr12 & 0x0004) { /*LnkFail */
+			/* 10baseT is dead.  Check for activity on alternate port. */
+			tp->mediasense = 1;
+			if (csr12 & 0x0200)
+				dev->if_port = 2;
+			else
+				dev->if_port = 1;
+			printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n",
+				   dev->name, medianame[dev->if_port]);
+			outl(0, ioaddr + CSR13); /* Reset */
+			outl(t21041_csr14[dev->if_port], ioaddr + CSR14);
+			outl(t21041_csr15[dev->if_port], ioaddr + CSR15);
+			outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
+			next_tick = 10*HZ;			/* 2.4 sec. */
+		  } else
+			next_tick = 30*HZ;
+		  break;
+		case 1:					/* 10base2 */
+		case 2:					/* AUI */
+		  if (csr12 & 0x0100) {
+			next_tick = (30*HZ);			/* 30 sec. */
+			tp->mediasense = 0;
+		  } else if ((csr12 & 0x0004) == 0) {
+			printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n", dev->name);
+			dev->if_port = 0;
+			select_media(dev, 0);
+			next_tick = (24*HZ)/10;				/* 2.4 sec. */
+		  } else if (tp->mediasense || (csr12 & 0x0002)) {
+			dev->if_port = 3 - dev->if_port; /* Swap ports. */
+			select_media(dev, 0);
+			next_tick = 20*HZ;
+		  } else {
+			next_tick = 20*HZ;
+		  }
+		  break;
+		}
+		break;
+	case DC21140:  case DC21142: case MX98713: default: {
+		struct medialeaf *mleaf;
+		unsigned char *p;
+		if (tp->mtable == NULL) {	/* No EEPROM info, use generic code. */
+			/* Not much that can be done.
+			   Assume this a generic MII or SYM transceiver. */
+			next_tick = 60*HZ;
+			if (tulip_debug > 2)
+				printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x "
+					   "CSR12 0x%2.2x.\n",
+					   dev->name, inl(ioaddr + CSR6), csr12 & 0xff);
+			break;
+		}
+		mleaf = &tp->mtable->mleaf[tp->cur_index];
+		p = mleaf->leafdata;
+		switch (mleaf->type) {
+		case 0: case 4: {
+			/* Type 0 serial or 4 SYM transceiver.  Check the link beat bit. */
+			int offset = mleaf->type == 4 ? 5 : 2;
+			s8 bitnum = p[offset];
+			if (p[offset+1] & 0x80) {
+				if (tulip_debug > 1)
+					printk(KERN_DEBUG"%s: Transceiver monitor tick "
+						   "CSR12=%#2.2x, no media sense.\n",
+						   dev->name, csr12);
+				if (mleaf->type == 4) {
+					if (mleaf->media == 3 && (csr12 & 0x02))
+						goto select_next_media;
+				}
+				break;
+			}
+			if (tulip_debug > 2)
+				printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x"
+					   " bit %d is %d, expecting %d.\n",
+					   dev->name, csr12, (bitnum >> 1) & 7,
+					   (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
+					   (bitnum >= 0));
+			/* Check that the specified bit has the proper value. */
+			if ((bitnum < 0) !=
+				((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
+				if (tulip_debug > 1)
+					printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
+						   medianame[mleaf->media]);
+				if ((p[2] & 0x61) == 0x01)	/* Bogus Znyx board. */
+					goto actually_mii;
+				break;
+			}
+			if (tp->medialock)
+				break;
+	  select_next_media:
+			if (--tp->cur_index < 0) {
+				/* We start again, but should instead look for default. */
+				tp->cur_index = tp->mtable->leafcount - 1;
+			}
+			dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
+			if (media_cap[dev->if_port] & MediaIsFD)
+				goto select_next_media; /* Skip FD entries. */
+			if (tulip_debug > 1)
+				printk(KERN_DEBUG "%s: No link beat on media %s,"
+					   " trying transceiver type %s.\n",
+					   dev->name, medianame[mleaf->media & 15],
+					   medianame[tp->mtable->mleaf[tp->cur_index].media]);
+			select_media(dev, 0);
+			/* Restart the transmit process. */
+			outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+			outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+			next_tick = (24*HZ)/10;
+			break;
+		}
+		case 1:  case 3: {		/* 21140, 21142 MII */
+			int mii_reg1, mii_reg5;
+		actually_mii:
+			mii_reg1 = mdio_read(dev, tp->phys[0], 1);
+			mii_reg5 = mdio_read(dev, tp->phys[0], 5);
+			if (tulip_debug > 1)
+				printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
+					   "%4.4x, CSR12 %2.2x, %cD.\n",
+					   dev->name, mii_reg1, mii_reg5, csr12,
+					   tp->full_duplex ? 'F' : 'H');
+			if (mii_reg1 != 0xffff  &&  (mii_reg1 & 0x0004) == 0) {
+				int new_reg1 = mdio_read(dev, tp->phys[0], 1);
+				if ((new_reg1 & 0x0004) == 0) {
+					printk(KERN_INFO "%s: No link beat on the MII interface,"
+						   " status then %4.4x now %4.4x.\n",
+						   dev->name, mii_reg1, new_reg1);
+					if (tp->mtable  &&  tp->mtable->has_nonmii)
+						goto select_next_media;
+				}
+			}
+			if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000)
+				;				/* No MII device or no link partner report */
+			else if (tp->full_duplex_lock)
+				;
+			else {
+				int negotiated = mii_reg5 & tp->advertising[0];
+				int duplex = ((negotiated & 0x0100) != 0
+							  || (negotiated & 0x00C0) == 0x0040);
+				/* 100baseTx-FD  or  10T-FD, but not 100-HD */
+				if (tp->full_duplex != duplex) {
+					tp->full_duplex = duplex;
+					if (tp->full_duplex)
+						tp->csr6 |= 0x0200;
+					else
+						tp->csr6 &= ~0x0200;
+					outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+					outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+					if (tulip_debug > 0) /* Gurppp, should be >1 */
+						printk(KERN_INFO "%s: Setting %s-duplex based on MII"
+							   " Xcvr #%d parter capability of %4.4x.\n",
+							   dev->name, tp->full_duplex ? "full" : "half",
+							   tp->phys[0], mii_reg5);
+				}
+			}
+			next_tick = 60*HZ;
+			break;
+		}
+		case 2:					/* 21142 serial block has no link beat. */
+		default:
+			break;
+		}
+	}
+	break;
+	}
+	if (next_tick) {
+		tp->timer.expires = RUN_AT(next_tick);
+		add_timer(&tp->timer);
+	}
+}
+
+/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
+   of available transceivers.  */
+static void t21142_timer(unsigned long data)
+{
+	struct device *dev = (struct device *)data;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int csr12 = inl(ioaddr + CSR12);
+	int next_tick = 60*HZ;
+	int new_csr6 = 0;
+
+	if (tulip_debug > 1)
+		printk(KERN_INFO"%s: 21142 negotiation status %8.8x, %s.\n",
+			   dev->name, csr12, medianame[dev->if_port]);
+	if (dev->if_port == 3) {
+		if (csr12 & 2) {		/* No 100mbps link beat, revert to 10mbps. */
+			new_csr6 = 0x82420200;
+			outl(new_csr6, ioaddr + CSR6);
+			outl(0x0000, ioaddr + CSR13);
+			outl(0x0003FFFF, ioaddr + CSR14);
+			outl(0x0008, ioaddr + CSR15);
+			outl(0x0001, ioaddr + CSR13);
+			outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+		}
+	} else if ((csr12 & 0x7000) != 0x5000) {
+		/* Negotiation failed.  Search media types. */
+		if (tulip_debug > 1)
+			printk(KERN_INFO"%s: 21142 negotiation failed, status %8.8x.\n",
+				   dev->name, csr12);
+		if (!(csr12 & 4)) {		/* 10mbps link beat good. */
+			new_csr6 = 0x82420000;
+			dev->if_port = 0;
+			outl(0, ioaddr + CSR13);
+			outl(0x0003FFFF, ioaddr + CSR14);
+			outl(t21142_csr15[dev->if_port], ioaddr + CSR15);
+			outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+		} else if (csr12 & 0x100) {
+			new_csr6 = 0x82420200;
+			dev->if_port = 2;
+			outl(0, ioaddr + CSR13);
+			outl(0x0003FFFF, ioaddr + CSR14);
+			outl(0x0008, ioaddr + CSR15);
+			outl(0x0001, ioaddr + CSR13);
+		} else {
+			/* Select 100mbps port to check for link beat. */
+			new_csr6 = 0x83860000;
+			dev->if_port = 3;
+			outl(0, ioaddr + CSR13);
+			outl(0x0003FF7F, ioaddr + CSR14);
+			outl(8, ioaddr + CSR15);
+			outl(1, ioaddr + CSR13);
+		}
+		if (tulip_debug > 1)
+			printk(KERN_INFO"%s: Testing new 21142 media %s.\n",
+				   dev->name, medianame[dev->if_port]);
+		if (new_csr6 != (tp->csr6 & ~0x00D5)) {
+			tp->csr6 &= 0x00D5;
+			tp->csr6 |= new_csr6;
+			outl(0x0301, ioaddr + CSR12);
+			outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+			outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		}
+	}
+	tp->timer.expires = RUN_AT(next_tick);
+	add_timer(&tp->timer);
+}
+
+static void t21142_lnk_change( struct device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int csr12 = inl(ioaddr + CSR12);
+
+	if (tulip_debug > 1)
+		printk(KERN_INFO"%s: 21142 link status interrupt %8.8x, CSR5 %x.\n",
+			   dev->name, csr12, inl(ioaddr + CSR5));
+
+	if ((csr12 & 0x7000) == 0x5000) {
+		if (csr12 & 0x01800000) {
+			/* Switch to 100mbps mode. */
+			outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+			if (csr12 & 0x01000000) {
+				dev->if_port = 5;
+				tp->csr6 = 0x83860200;
+			} else {
+				dev->if_port = 3;
+				tp->csr6 = 0x83860000;
+			}
+			outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		} /* Else 10baseT-FD is handled automatically. */
+	} else if (dev->if_port == 3) {
+		if (!(csr12 & 2))
+			printk(KERN_INFO"%s: 21142 100baseTx link beat good.\n",
+				   dev->name);
+		else
+			dev->if_port = 0;
+	} else if (dev->if_port == 0) {
+		if (!(csr12 & 4))
+			printk(KERN_INFO"%s: 21142 10baseT link beat good.\n",
+				   dev->name);
+	} else if (!(csr12 & 4)) {		/* 10mbps link beat good. */
+			printk(KERN_INFO"%s: 21142 10mpbs sensed media.\n",
+				   dev->name);
+			dev->if_port = 0;
+	} else  {		/* 100mbps link beat good. */
+		printk(KERN_INFO"%s: 21142 100baseTx sensed media.\n",
+			   dev->name);
+		dev->if_port = 3;
+		tp->csr6 = 0x83860000;
+		outl(0x0003FF7F, ioaddr + CSR14);
+		outl(0x0301, ioaddr + CSR12);
+		outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+	}
+}
+	
+
+static void mxic_timer(unsigned long data)
+{
+	struct device *dev = (struct device *)data;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int next_tick = 60*HZ;
+
+	if (tulip_debug > 3) {
+		printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name,
+			   inl(ioaddr + CSR12));
+	}
+	if (next_tick) {
+		tp->timer.expires = RUN_AT(next_tick);
+		add_timer(&tp->timer);
+	}
+}
+
+static void pnic_timer(unsigned long data)
+{
+	struct device *dev = (struct device *)data;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int csr12 = inl(ioaddr + CSR12);
+	int next_tick = 60*HZ;
+	int new_csr6 = tp->csr6 & ~0x40C40200;
+
+	if (media_cap[dev->if_port] & MediaIsMII) {
+		int negotiated = mdio_read(dev, tp->phys[0], 5) & tp->advertising[0];
+
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: LC82C168 negotiated capability %8.8x, "
+				   "CSR5 %8.8x.\n",
+				   dev->name, negotiated, inl(ioaddr + CSR5));
+
+		if (negotiated & 0x0380) 				/* 10 vs 100mbps */
+			new_csr6 |= 0x812E0000;
+		else
+			new_csr6 |= 0x816E0000;
+		if (((negotiated & 0x0300) == 0x0100)			/* Duplex */
+			|| (negotiated & 0x00C0) == 0x0040
+			|| tp->full_duplex_lock) {
+			tp->full_duplex = 1;
+			new_csr6 |= 0x0200;
+		}
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: LC82C168 MII PHY status %4.4x, Link "
+				   "partner report %4.4x, csr6 %8.8x/%8.8x.\n",
+			   dev->name, mdio_read(dev, tp->phys[0], 1), negotiated,
+				   tp->csr6, inl(ioaddr + CSR6));
+	} else {
+		int phy_reg = inl(ioaddr + 0xB8);
+		int csr5 = inl(ioaddr + CSR5);
+
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: LC82C168 phy status %8.8x, CSR5 %8.8x.\n",
+				   dev->name, phy_reg, csr5);
+
+		if (phy_reg & 0x04000000) {	/* Remote link fault */
+			/*outl(0x0201F078, ioaddr + 0xB8);*/
+			next_tick = 3*HZ;
+		}
+		if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */
+			if (tulip_debug > 1)
+				printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
+					   "CSR5 %8.8x, PHY %3.3x.\n",
+					   dev->name, medianame[dev->if_port], csr12,
+					   inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
+			if (tp->medialock) {
+			} else if (dev->if_port == 0) {
+				dev->if_port = 3;
+				outl(0x33, ioaddr + CSR12);
+				new_csr6 = 0x01860000;
+				outl(0x1F868, ioaddr + 0xB8);
+			} else {
+				dev->if_port = 0;
+				outl(0x32, ioaddr + CSR12);
+				new_csr6 = 0x00420000;
+				outl(0x1F078, ioaddr + 0xB8);
+			}
+			new_csr6 |= (tp->csr6 & 0xfdff);
+			next_tick = 3*HZ;
+		} else
+			new_csr6 = tp->csr6;
+		if (tp->full_duplex_lock  ||  (phy_reg & 0x30000000) != 0) {
+			tp->full_duplex = 1;
+			new_csr6 |= 0x00000200;
+		}
+	}
+	if (tp->csr6 != new_csr6) {
+		tp->csr6 = new_csr6;
+		outl(tp->csr6 | 0x0002, ioaddr + CSR6);	/* Restart Tx */
+		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		dev->trans_start = jiffies;
+		if (tulip_debug > 0) /* Gurppp, should be >1 */
+			printk(KERN_INFO "%s: Changing PNIC configuration to %s-duplex, "
+				   "CSR6 %8.8x.\n",
+				   dev->name, tp->full_duplex ? "full" : "half", new_csr6);
+	}
+	tp->timer.expires = RUN_AT(next_tick);
+	add_timer(&tp->timer);
+}
+
+static void tulip_tx_timeout(struct device *dev)
+{
+  struct tulip_private *tp = (struct tulip_private *)dev->priv;
+  long ioaddr = dev->base_addr;
+
+  if (media_cap[dev->if_port] & MediaIsMII) {
+	  /* Do nothing -- the media monitor should handle this. */
+	  if (tulip_debug > 1)
+		  printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
+				 dev->name);
+	  dev->trans_start = jiffies;
+	  return;
+  } else if (tp->chip_id == DC21040) {
+	  if (inl(ioaddr + CSR12) & 0x0002) {
+		  printk(KERN_INFO "%s: transmit timed out, switching to %s media.\n",
+				 dev->name, dev->if_port ? "10baseT" : "AUI");
+		  dev->if_port ^= 1;
+		  outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
+	  }
+	  dev->trans_start = jiffies;
+	  return;
+  } else if (tp->chip_id == DC21041) {
+	u32 csr12 = inl(ioaddr + CSR12);
+
+	printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, CSR12 %8.8x,"
+		   " CSR13 %8.8x, CSR14 %8.8x, resetting...\n",
+		   dev->name, inl(ioaddr + CSR5), csr12,
+		   inl(ioaddr + CSR13), inl(ioaddr + CSR14));
+	tp->mediasense = 1;
+	if (dev->if_port == 1 || dev->if_port == 2)
+		if (csr12 & 0x0004) {
+			dev->if_port = 2 - dev->if_port;
+		} else
+			dev->if_port = 0;
+	else
+		dev->if_port = 1;
+	select_media(dev, 0);
+	tp->stats.tx_errors++;
+	dev->trans_start = jiffies;
+	return;
+  } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
+			 || tp->chip_id == MX98713) {
+	  /* Stop the transmit process. */
+	  outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+	  printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
+			 "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
+			 dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
+			 inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+	  if (tp->mtable) {
+		  if (--tp->cur_index < 0) {
+			  /* We start again, but should instead look for default. */
+			  tp->cur_index = tp->mtable->leafcount - 1;
+		  }
+		  select_media(dev, 0);
+		  printk(KERN_WARNING "%s: transmit timed out, switching to %s media.\n",
+				 dev->name, dev->if_port ? "100baseTx" : "10baseT");
+	  }
+	  outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+	  tp->stats.tx_errors++;
+	  dev->trans_start = jiffies;
+	  return;
+  } else
+	printk(KERN_WARNING "%s: transmit timed out, status %8.8x, CSR12 %8.8x,"
+		   " resetting...\n",
+		   dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12));
+#ifdef way_too_many_messages
+  printk("  Rx ring %8.8x: ", (int)tp->rx_ring);
+  for (i = 0; i < RX_RING_SIZE; i++)
+	printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
+  printk("\n  Tx ring %8.8x: ", (int)tp->tx_ring);
+  for (i = 0; i < TX_RING_SIZE; i++)
+	printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
+  printk("\n");
+#endif
+
+  /* Perhaps we should reinitialize the hardware here. */
+  dev->if_port = 0;
+  /* Stop and restart the chip's Tx processes . */
+  outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+  outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+  /* Trigger an immediate transmit demand. */
+  outl(0, ioaddr + CSR1);
+
+  dev->trans_start = jiffies;
+  tp->stats.tx_errors++;
+  return;
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void
+tulip_init_ring(struct device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int i;
+
+	tp->tx_full = 0;
+	tp->cur_rx = tp->cur_tx = 0;
+	tp->dirty_rx = tp->dirty_tx = 0;
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		tp->rx_ring[i].status = 0x80000000;	/* Owned by Tulip chip */
+		tp->rx_ring[i].length = PKT_BUF_SZ;
+		{
+			/* Note the receive buffer must be longword aligned.
+			   dev_alloc_skb() provides 16 byte alignment.  But do *not*
+			   use skb_reserve() to align the IP header! */
+			struct sk_buff *skb;
+			skb = DEV_ALLOC_SKB(PKT_BUF_SZ);
+			tp->rx_skbuff[i] = skb;
+			if (skb == NULL)
+				break;			/* Bad news!  */
+			skb->dev = dev;			/* Mark as being used by this device. */
+#if LINUX_VERSION_CODE > 0x10300
+			tp->rx_ring[i].buffer1 = virt_to_bus(skb->tail);
+#else
+			tp->rx_ring[i].buffer1 = virt_to_bus(skb->data);
+#endif
+		}
+		tp->rx_ring[i].buffer2 = virt_to_bus(&tp->rx_ring[i+1]);
+	}
+	/* Mark the last entry as wrapping the ring. */
+	tp->rx_ring[i-1].length = PKT_BUF_SZ | 0x02000000;
+	tp->rx_ring[i-1].buffer2 = virt_to_bus(&tp->rx_ring[0]);
+
+	/* The Tx buffer descriptor is filled in as needed, but we
+	   do need to clear the ownership bit. */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		tp->tx_skbuff[i] = 0;
+		tp->tx_ring[i].status = 0x00000000;
+		tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]);
+	}
+	tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]);
+}
+
+static int
+tulip_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int entry;
+	u32 flag;
+
+	/* Block a timer-based transmit from overlapping.  This could better be
+	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+		if (jiffies - dev->trans_start < TX_TIMEOUT)
+			return 1;
+		tulip_tx_timeout(dev);
+		return 1;
+	}
+
+	/* Caution: the write order is important here, set the base address
+	   with the "ownership" bits last. */
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = tp->cur_tx % TX_RING_SIZE;
+
+	tp->tx_skbuff[entry] = skb;
+	tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
+
+	if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
+	  flag = 0x60000000; /* No interrupt */
+	  dev->tbusy = 0;
+	} else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {
+	  flag = 0xe0000000; /* Tx-done intr. */
+	  dev->tbusy = 0;
+	} else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
+	  flag = 0x60000000; /* No Tx-done intr. */
+	  dev->tbusy = 0;
+	} else {
+	  /* Leave room for set_rx_mode() to fill entries. */
+	  flag = 0xe0000000; /* Tx-done intr. */
+	  tp->tx_full = 1;
+	}
+	if (entry == TX_RING_SIZE-1)
+		flag |= 0xe2000000;
+
+	tp->tx_ring[entry].length = skb->len | flag;
+	tp->tx_ring[entry].status = 0x80000000;	/* Pass ownership to the chip. */
+	tp->cur_tx++;
+	/* Trigger an immediate transmit demand. */
+	outl(0, dev->base_addr + CSR1);
+
+	dev->trans_start = jiffies;
+
+	return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs)
+{
+#ifdef SA_SHIRQ		/* Use the now-standard shared IRQ implementation. */
+	struct device *dev = (struct device *)dev_instance;
+#else
+	struct device *dev = (struct device *)(irq2dev_map[irq]);
+#endif
+
+	struct tulip_private *tp;
+	long ioaddr;
+	int csr5, work_budget = max_interrupt_work;
+
+	if (dev == NULL) {
+		printk (KERN_ERR" tulip_interrupt(): irq %d for unknown device.\n",
+				irq);
+		return;
+	}
+
+	ioaddr = dev->base_addr;
+	tp = (struct tulip_private *)dev->priv;
+	if (test_and_set_bit(0, (void*)&tp->interrupt)) {
+#ifdef SMP_CHECK
+		printk(KERN_ERR "%s: Re-entering the interrupt handler with proc %d,"
+			   " proc %d already handling.\n", dev->name,
+			   tp->smp_proc_id, hard_smp_processor_id());
+#else
+		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
+#endif
+		return;
+	}
+	dev->interrupt = 1;
+#ifdef SMP_CHECK
+	tp->smp_proc_id = hard_smp_processor_id();
+#endif
+
+	do {
+		csr5 = inl(ioaddr + CSR5);
+		/* Acknowledge all of the current interrupt sources ASAP. */
+		outl(csr5 & 0x0001ffff, ioaddr + CSR5);
+
+		if (tulip_debug > 4)
+			printk(KERN_DEBUG "%s: interrupt  csr5=%#8.8x new csr5=%#8.8x.\n",
+				   dev->name, csr5, inl(dev->base_addr + CSR5));
+
+		if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
+			break;
+
+		if (csr5 & (RxIntr | RxNoBuf))
+			work_budget -= tulip_rx(dev);
+
+		if (csr5 & (TxNoBuf | TxDied | TxIntr)) {
+			unsigned int dirty_tx;
+
+			for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
+				 dirty_tx++) {
+				int entry = dirty_tx % TX_RING_SIZE;
+				int status = tp->tx_ring[entry].status;
+
+				if (status < 0)
+					break;			/* It still hasn't been Txed */
+				/* Check for Rx filter setup frames. */
+				if (tp->tx_skbuff[entry] == NULL)
+				  continue;
+
+				if (status & 0x8000) {
+					/* There was an major error, log it. */
+#ifndef final_version
+					if (tulip_debug > 1)
+						printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
+							   dev->name, status);
+#endif
+					tp->stats.tx_errors++;
+					if (status & 0x4104) tp->stats.tx_aborted_errors++;
+					if (status & 0x0C00) tp->stats.tx_carrier_errors++;
+					if (status & 0x0200) tp->stats.tx_window_errors++;
+					if (status & 0x0002) tp->stats.tx_fifo_errors++;
+					if ((status & 0x0080) && tp->full_duplex == 0)
+						tp->stats.tx_heartbeat_errors++;
+#ifdef ETHER_STATS
+					if (status & 0x0100) tp->stats.collisions16++;
+#endif
+				} else {
+#ifdef ETHER_STATS
+					if (status & 0x0001) tp->stats.tx_deferred++;
+#endif
+#if LINUX_VERSION_CODE > 0x20127
+					tp->stats.tx_bytes += tp->tx_ring[entry].length & 0x7ff;
+#endif
+					tp->stats.collisions += (status >> 3) & 15;
+					tp->stats.tx_packets++;
+				}
+
+				/* Free the original skb. */
+#if (LINUX_VERSION_CODE > 0x20155)
+				dev_kfree_skb(tp->tx_skbuff[entry]);
+#else
+				dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE);
+#endif
+				tp->tx_skbuff[entry] = 0;
+			}
+
+#ifndef final_version
+			if (tp->cur_tx - dirty_tx > TX_RING_SIZE) {
+				printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+					   dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
+				dirty_tx += TX_RING_SIZE;
+			}
+#endif
+
+			if (tp->tx_full && dev->tbusy
+				&& tp->cur_tx - dirty_tx  < TX_RING_SIZE - 2) {
+				/* The ring is no longer full, clear tbusy. */
+				tp->tx_full = 0;
+				dev->tbusy = 0;
+				mark_bh(NET_BH);
+			}
+
+			tp->dirty_tx = dirty_tx;
+			if (csr5 & TxDied) {
+				if (tulip_debug > 1)
+					printk(KERN_WARNING "%s: The transmitter stopped!"
+						   "  CSR5 is %x, CSR6 %x.\n",
+						   dev->name, csr5, inl(ioaddr + CSR6));
+				outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+			}
+		}
+
+		/* Log errors. */
+		if (csr5 & AbnormalIntr) {	/* Abnormal error summary bit. */
+			if (csr5 & TxJabber) tp->stats.tx_errors++;
+			if (csr5 & TxFIFOUnderflow) {
+				if ((tp->csr6 & 0xC000) != 0xC000)
+					tp->csr6 += 0x4000;	/* Bump up the Tx threshold */
+				else
+					tp->csr6 |= 0x00200000;  /* Store-n-forward. */
+				/* Restart the transmit process. */
+				outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+			}
+			if (csr5 & RxDied) {		/* Missed a Rx frame. */
+				tp->stats.rx_errors++;
+				tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+			}
+			if (csr5 & TimerInt) {
+				printk(KERN_ERR "%s: Something Wicked happened! %8.8x.\n",
+					   dev->name, csr5);
+				/* Hmmmmm, it's not clear what to do here. */
+			}
+			if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)
+				&& tp->chip_id == DC21142) {
+				if (tulip_debug > 1)
+					printk(KERN_INFO"%s: 21142 link change, CSR5 = %8.8x.\n",
+						   dev->name, csr5);
+				t21142_lnk_change(dev);
+			}
+			/* Clear all error sources, included undocumented ones! */
+			outl(0x0800f7ba, ioaddr + CSR5);
+		}
+		if (--work_budget < 0) {
+			if (tulip_debug > 1)
+				printk(KERN_WARNING "%s: Too much work at interrupt, "
+					   "csr5=0x%8.8x.\n", dev->name, csr5);
+			/* Acknowledge all interrupt sources. */
+			outl(0x8001ffff, ioaddr + CSR5);
+#ifdef notdef
+			/* Clear all but standard interrupt sources. */
+			outl((~csr5) & 0x0001ebef, ioaddr + CSR7);
+#endif
+			break;
+		}
+	} while (1);
+
+	if (tulip_debug > 3)
+		printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
+			   dev->name, inl(ioaddr + CSR5));
+
+	dev->interrupt = 0;
+	clear_bit(0, (void*)&tp->interrupt);
+	return;
+}
+
+static int
+tulip_rx(struct device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int entry = tp->cur_rx % RX_RING_SIZE;
+	int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
+	int work_done = 0;
+
+	if (tulip_debug > 4)
+		printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
+			   tp->rx_ring[entry].status);
+	/* If we own the next entry, it's a new packet. Send it up. */
+	while (tp->rx_ring[entry].status >= 0) {
+		s32 status = tp->rx_ring[entry].status;
+
+		if (--rx_work_limit < 0)
+			break;
+		if ((status & 0x0300) != 0x0300) {
+			if ((status & 0xffff) != 0x7fff) { /* Ingore earlier buffers. */
+				if (tulip_debug > 1)
+					printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
+						   "multiple buffers, status %8.8x!\n",
+						   dev->name, status);
+			  tp->stats.rx_length_errors++;
+			}
+		} else if (status & 0x8000) {
+			/* There was a fatal error. */
+			if (tulip_debug > 2)
+				printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
+					   dev->name, status);
+			tp->stats.rx_errors++; /* end of a packet.*/
+			if (status & 0x0890) tp->stats.rx_length_errors++;
+			if (status & 0x0004) tp->stats.rx_frame_errors++;
+			if (status & 0x0002) tp->stats.rx_crc_errors++;
+			if (status & 0x0001) tp->stats.rx_fifo_errors++;
+		} else {
+			/* Omit the four octet CRC from the length. */
+			short pkt_len = (status >> 16) - 4;
+			struct sk_buff *skb;
+
+			/* Check if the packet is long enough to just accept without
+			   copying to a properly sized skbuff. */
+			if (pkt_len < rx_copybreak
+				&& (skb = DEV_ALLOC_SKB(pkt_len+2)) != NULL) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);	/* 16 byte align the IP header */
+#if LINUX_VERSION_CODE < 0x10300
+				memcpy(skb->data, tp->rx_ring[entry].buffer1, pkt_len);
+#elif LINUX_VERSION_CODE < 0x20200  || defined(__alpha__)
+				memcpy(skb_put(skb, pkt_len),
+					   bus_to_virt(tp->rx_ring[entry].buffer1), pkt_len);
+#else
+				eth_copy_and_sum(skb, bus_to_virt(tp->rx_ring[entry].buffer1),
+								 pkt_len, 0);
+				skb_put(skb, pkt_len);
+#endif
+				work_done++;
+			} else { 	/* Pass up the skb already on the Rx ring. */
+				skb = tp->rx_skbuff[entry];
+				tp->rx_skbuff[entry] = NULL;
+#ifndef final_version
+				{
+					void *temp = skb_put(skb, pkt_len);
+					if (bus_to_virt(tp->rx_ring[entry].buffer1) != temp)
+						printk(KERN_ERR "%s: Internal consistency error! The "
+						   "skbuff addresses do not match in tulip_rx:"
+							   " %p vs. %p / %p.\n", dev->name,
+							   bus_to_virt(tp->rx_ring[entry].buffer1),
+							   skb->head, temp);
+				}
+#else
+				skb_put(skb, pkt_len);
+#endif
+			}
+#if LINUX_VERSION_CODE > 0x10300
+			skb->protocol = eth_type_trans(skb, dev);
+#else
+			skb->len = pkt_len;
+#endif
+			netif_rx(skb);
+			dev->last_rx = jiffies;
+			tp->stats.rx_packets++;
+#if LINUX_VERSION_CODE > 0x20127
+			tp->stats.rx_bytes += pkt_len;
+#endif
+		}
+		entry = (++tp->cur_rx) % RX_RING_SIZE;
+	}
+
+	/* Refill the Rx ring buffers. */
+	for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
+		entry = tp->dirty_rx % RX_RING_SIZE;
+		if (tp->rx_skbuff[entry] == NULL) {
+			struct sk_buff *skb;
+			skb = tp->rx_skbuff[entry] = DEV_ALLOC_SKB(PKT_BUF_SZ);
+			if (skb == NULL)
+				break;
+			skb->dev = dev;			/* Mark as being used by this device. */
+#if LINUX_VERSION_CODE > 0x10300
+			tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail);
+#else
+			tp->rx_ring[entry].buffer1 = virt_to_bus(skb->data);
+#endif
+			work_done++;
+		}
+		tp->rx_ring[entry].status = 0x80000000;
+	}
+
+	return work_done;
+}
+
+static int
+tulip_close(struct device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int i;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	if (tulip_debug > 1)
+		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
+			   dev->name, inl(ioaddr + CSR5));
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	outl(0x00000000, ioaddr + CSR7);
+	/* Stop the chip's Tx and Rx processes. */
+	outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
+	/* 21040 -- Leave the card in 10baseT state. */
+	if (tp->chip_id == DC21040)
+		outl(0x00000004, ioaddr + CSR13);
+
+	tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+
+	del_timer(&tp->timer);
+
+#ifdef SA_SHIRQ
+	free_irq(dev->irq, dev);
+#else
+	free_irq(dev->irq);
+	irq2dev_map[dev->irq] = 0;
+#endif
+
+	/* Free all the skbuffs in the Rx queue. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb = tp->rx_skbuff[i];
+		tp->rx_skbuff[i] = 0;
+		tp->rx_ring[i].status = 0;		/* Not owned by Tulip chip. */
+		tp->rx_ring[i].length = 0;
+		tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */
+		if (skb) {
+#if LINUX_VERSION_CODE < 0x20100
+			skb->free = 1;
+#endif
+#if (LINUX_VERSION_CODE > 0x20155)
+			dev_kfree_skb(skb);
+#else
+			dev_kfree_skb(skb, FREE_WRITE);
+#endif
+		}
+	}
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (tp->tx_skbuff[i])
+#if (LINUX_VERSION_CODE > 0x20155)
+			dev_kfree_skb(tp->tx_skbuff[i]);
+#else
+			dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE);
+#endif
+		tp->tx_skbuff[i] = 0;
+	}
+
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static struct enet_statistics *
+tulip_get_stats(struct device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+
+	if (dev->start)
+		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+
+	return &tp->stats;
+}
+
+#ifdef HAVE_PRIVATE_IOCTL
+/* Provide ioctl() calls to examine the MII xcvr state. */
+static int private_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	u16 *data = (u16 *)&rq->ifr_data;
+	int phy = tp->phys[0] & 0x1f;
+	long flags;
+
+	switch(cmd) {
+	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
+		if (tp->mtable  &&  tp->mtable->has_mii)
+			data[0] = phy;
+		else if (tp->chip_id == DC21142)
+			data[0] = 32;
+		else
+			return -ENODEV;
+		return 0;
+	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
+		if (data[0] == 32) {  /* 21142 pseudo-MII */
+			int csr12 = inl(ioaddr + CSR12);
+			int csr14 = inl(ioaddr + CSR14);
+			switch (data[1]) {
+			case 0: {
+				data[3] = ((csr14<<13)&0x4000) + ((csr14<<5)&0x1000);
+				break; }
+			case 1:
+				data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0)
+					+ (csr12&0x06 ? 0x04 : 0);
+				break;
+			case 4: {
+				int csr14 = inl(ioaddr + CSR14);
+				data[3] = ((csr14>>9)&0x0380) + ((csr14>>1)&0x20) + 1;
+				break;
+			}
+			case 5: data[3] = inl(ioaddr + CSR12) >> 16; break;
+			default: data[3] = 0; break;
+			}
+		} else {
+			save_flags(flags);
+			cli();
+			data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
+			restore_flags(flags);
+		}
+		return 0;
+	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
+		if (!suser())
+			return -EPERM;
+		if (data[0] == 32) {  /* 21142 pseudo-MII */
+		} else {
+			save_flags(flags);
+			cli();
+			mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+			restore_flags(flags);
+		}
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return -EOPNOTSUPP;
+}
+#endif  /* HAVE_PRIVATE_IOCTL */
+
+/* Set or clear the multicast filter for this adaptor.
+   Note that we only use exclusion around actually queueing the
+   new frame, not around filling tp->setup_frame.  This is non-deterministic
+   when re-entered but still correct. */
+
+/* The little-endian AUTODIN32 ethernet CRC calculation.
+   N.B. Do not use for bulk data, use a table-based routine instead.
+   This is common code and should be moved to net/core/crc.c */
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline unsigned ether_crc_le(int length, unsigned char *data)
+{
+	unsigned int crc = 0xffffffff;	/* Initial value. */
+	while(--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 8; --bit >= 0; current_octet >>= 1) {
+			if ((crc ^ current_octet) & 1) {
+				crc >>= 1;
+				crc ^= ethernet_polynomial_le;
+			} else
+				crc >>= 1;
+		}
+	}
+	return crc;
+}
+
+#ifdef NEW_MULTICAST
+static void set_rx_mode(struct device *dev)
+#else
+static void set_rx_mode(struct device *dev, int num_addrs, void *addrs)
+#endif
+{
+	long ioaddr = dev->base_addr;
+	int csr6 = inl(ioaddr + CSR6) & ~0x00D5;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+	tp->csr6 &= ~0x00D5;
+	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
+		outl(csr6 | 0x00C0, ioaddr + CSR6);
+		/* Unconditionally log net taps. */
+		printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
+		tp->csr6 |= 0xC0;
+	} else if ((dev->mc_count > 1000)  ||  (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to filter perfectly -- accept all multicasts. */
+		outl(csr6 | 0x0080, ioaddr + CSR6);
+		tp->csr6 |= 0x80;
+	} else {
+		u32 *setup_frm = tp->setup_frame;
+		struct dev_mc_list *mclist;
+		u16 *eaddrs;
+		u32 tx_flags;
+		int i;
+
+		if (dev->mc_count > 14) { /* Must use a multicast hash table. */
+		  u16 hash_table[32];
+		  memset(hash_table, 0, sizeof(hash_table));
+		  /* This should work on big-endian machines as well. */
+		  for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+			   i++, mclist = mclist->next)
+			  set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
+					  hash_table);
+		  /* Copy the hash table to the setup frame.
+			 NOTE that only the LOW SHORTWORD of setup_frame[] is valid! */
+		  for (i = 0; i < 32; i++)
+			*setup_frm++ = hash_table[i];
+		  setup_frm += 7;
+		  tx_flags = 0x08400000 | 192;
+		  /* Too clever: i > 15 for fall-though. */
+		} else {
+		  /* We have <= 15 addresses so we can use the wonderful
+			 16 address perfect filtering of the Tulip. */
+		  for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
+			   i++, mclist = mclist->next) {
+			/* Note that only the low shortword of setup_frame[] is valid!
+			   This code may require tweaking for non-x86 architectures! */
+			eaddrs = (u16 *)mclist->dmi_addr;
+			*setup_frm++ = *eaddrs++;
+			*setup_frm++ = *eaddrs++;
+			*setup_frm++ = *eaddrs++;
+		  }
+		  /* Fill the rest of the table with our physical address.
+			 Once again, only the low shortword or setup_frame[] is valid! */
+		  *setup_frm++ = 0xffff;
+		  *setup_frm++ = 0xffff;
+		  *setup_frm++ = 0xffff;
+		  tx_flags = 0x08000000 | 192;
+		}
+		eaddrs = (u16 *)dev->dev_addr;
+		do {
+			*setup_frm++ = eaddrs[0];
+			*setup_frm++ = eaddrs[1];
+			*setup_frm++ = eaddrs[2];
+		} while (++i < 15);
+		/* Now add this frame to the Tx list. */
+		if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {
+			/* Same setup recently queued, we need not add it. */
+		} else {
+			unsigned long flags;
+			unsigned int entry, dummy = 0;
+
+			save_flags(flags); cli();
+			entry = tp->cur_tx++ % TX_RING_SIZE;
+
+			if (entry != 0) {
+				/* Avoid a chip errata by prefixing a dummy entry. */
+				tp->tx_skbuff[entry] = 0;
+				tp->tx_ring[entry].length =
+					(entry == TX_RING_SIZE-1) ? 0x02000000 : 0;
+				tp->tx_ring[entry].buffer1 = 0;
+				/* race with chip, set DescOwned later */
+				dummy = entry;
+				entry = tp->cur_tx++ % TX_RING_SIZE;
+			}
+
+			tp->tx_skbuff[entry] = 0;
+			/* Put the setup frame on the Tx list. */
+			if (entry == TX_RING_SIZE-1)
+				tx_flags |= 0x02000000;		/* Wrap ring. */
+			tp->tx_ring[entry].length = tx_flags;
+			tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);
+			tp->tx_ring[entry].status = 0x80000000;
+			if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {
+				dev->tbusy = 1;
+				tp->tx_full = 1;
+			}
+			if (dummy >= 0)
+				tp->tx_ring[dummy].status = DescOwned;
+			restore_flags(flags);
+			/* Trigger an immediate transmit demand. */
+			outl(0, ioaddr + CSR1);
+		}
+		outl(csr6 | 0x0000, ioaddr + CSR6);
+	}
+}
+
+#ifdef CARDBUS
+
+#include <pcmcia/driver_ops.h>
+
+static dev_node_t *tulip_attach(dev_locator_t *loc)
+{
+	u16 dev_id;
+	u32 io;
+	u8 bus, devfn;
+	struct device *dev;
+
+	if (loc->bus != LOC_PCI) return NULL;
+	bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+	printk(KERN_INFO "tulip_attach(bus %d, function %d)\n", bus, devfn);
+	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
+	pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
+	io &= ~3;
+	dev = tulip_probe1(bus, devfn, NULL, DC21142, -1);
+	if (dev) {
+		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
+		strcpy(node->dev_name, dev->name);
+		node->major = node->minor = 0;
+		node->next = NULL;
+		MOD_INC_USE_COUNT;
+		return node;
+	}
+	return NULL;
+}
+
+static void tulip_detach(dev_node_t *node)
+{
+	struct device **devp, **next;
+	printk(KERN_INFO "tulip_detach(%s)\n", node->dev_name);
+	for (devp = &root_tulip_dev; *devp; devp = next) {
+		next = &((struct tulip_private *)(*devp)->priv)->next_module;
+		if (strcmp((*devp)->name, node->dev_name) == 0) break;
+	}
+	if (*devp) {
+		unregister_netdev(*devp);
+		kfree(*devp);
+		*devp = *next;
+		kfree(node);
+		MOD_DEC_USE_COUNT;
+	}
+}
+
+struct driver_operations tulip_ops = {
+	"tulip_cb", tulip_attach, NULL, NULL, tulip_detach
+};
+
+#endif  /* Cardbus support */
+
+
+#ifdef MODULE
+#if LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(reverse_probe, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+#endif
+
+/* An additional parameter that may be passed in... */
+static int debug = -1;
+
+int
+init_module(void)
+{
+	if (debug >= 0)
+		tulip_debug = debug;
+
+#ifdef CARDBUS
+	register_driver(&tulip_ops);
+	return 0;
+#else
+	return tulip_probe(NULL);
+#endif
+}
+
+void
+cleanup_module(void)
+{
+	struct device *next_dev;
+
+#ifdef CARDBUS
+	unregister_driver(&tulip_ops);
+#endif
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_tulip_dev) {
+		next_dev = ((struct tulip_private *)root_tulip_dev->priv)->next_module;
+		unregister_netdev(root_tulip_dev);
+		release_region(root_tulip_dev->base_addr, TULIP_TOTAL_SIZE);
+		kfree(root_tulip_dev);
+		root_tulip_dev = next_dev;
+	}
+}
+
+#endif  /* MODULE */
+
+/*
+ * Local variables:
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/pcnet32.c linux.14p16/drivers/net/pcnet32.c
--- linux.vanilla/drivers/net/pcnet32.c	Wed Oct 20 01:12:39 1999
+++ linux.14p16/drivers/net/pcnet32.c	Thu Dec  9 15:33:31 1999
@@ -13,7 +13,7 @@
  * 	This driver is for PCnet32 and PCnetPCI based ethercards
  */
 
-static const char *version = "pcnet32.c:v1.23 6.7.1999 tsbogend@alpha.franken.de\n";
+static const char *version = "pcnet32.c:v1.25kf 26.9.1999 tsbogend@alpha.franken.de\n";
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -39,16 +39,18 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <asm/spinlock.h>
 
 static unsigned int pcnet32_portlist[] __initdata = {0x300, 0x320, 0x340, 0x360, 0};
 
 static int pcnet32_debug = 1;
+static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */
 
 #ifdef MODULE
 static struct device *pcnet32_dev = NULL;
 #endif
 
-static const int max_interrupt_work = 20;
+static const int max_interrupt_work = 80;
 static const int rx_copybreak = 200;
 
 #define PORT_AUI      0x00
@@ -156,6 +158,12 @@
  *	   Michael Richard <mcr@solidum.com>)
  *         added chip id for 79c973/975 (thanks to Zach Brown <zab@zabbo.net>)
  * v1.23   fixed small bug, when manual selecting MII speed/duplex
+ * v1.24   Applied Thomas' patch to use TxStartPoint and thus decrease TxFIFO
+ *         underflows.  Added tx_start_pt module parameter. Increased
+ *         TX_RING_SIZE from 16 to 32.  Added #ifdef'd code to use DXSUFLO
+ *         for FAST[+] chipsets. <kaf@fc.hp.com>
+ * v1.24ac Added SMP spinlocking - Alan Cox <alan@redhat.com>
+ * v1.25kf Added No Interrupt on successful Tx for some Tx's <kaf@fc.hp.com>
  */
 
 
@@ -166,7 +174,7 @@
  */
 #ifndef PCNET32_LOG_TX_BUFFERS
 #define PCNET32_LOG_TX_BUFFERS 4
-#define PCNET32_LOG_RX_BUFFERS 4
+#define PCNET32_LOG_RX_BUFFERS 5
 #endif
 
 #define TX_RING_SIZE			(1 << (PCNET32_LOG_TX_BUFFERS))
@@ -255,12 +263,17 @@
     struct sk_buff *rx_skbuff[RX_RING_SIZE];
     struct pcnet32_access a;
     void *origmem;
-    int cur_rx, cur_tx;			/* The next free ring entry */
-    int dirty_rx, dirty_tx;		        /* The ring entries to be free()ed. */
+    spinlock_t lock;				/* Guard lock */
+    unsigned int cur_rx, cur_tx;		/* The next free ring entry */
+    unsigned int dirty_rx, dirty_tx;		/* The ring entries to be free()ed. */
     struct net_device_stats stats;
     char tx_full;
     int  options;
     int  shared_irq:1,                      /* shared irq possible */
+	 ltint:1,
+#ifdef DO_DXSUFLO
+	 dxsuflo:1,			    /* disable transmit stop on uflo */
+#endif
          full_duplex:1,                     /* full duplex possible */
          mii:1;                             /* mii port available */
 #ifdef MODULE
@@ -299,6 +312,10 @@
 	PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0, 0,
 	PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
 	pcnet32_probe1},
+    { "AMD PCnetPCI series (IBM)",
+	PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000,
+	PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
+	pcnet32_probe1},
     { "AMD PCnetHome series",
 	PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PCNETHOME, 0, 0,
 	PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
@@ -448,8 +465,8 @@
 	    int chip_idx;
 	    u16 sdid,svid;
 
-	    pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &sdid);
-	    pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &svid);
+	    pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &svid);
+	    pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sdid);
 	    for (chip_idx = 0; pcnet32_tbl[chip_idx].vendor_id; chip_idx++)
 		if ((pdev->vendor == pcnet32_tbl[chip_idx].vendor_id) &&
 		    (pdev->device == pcnet32_tbl[chip_idx].device_id) &&
@@ -514,6 +531,10 @@
 {
     struct pcnet32_private *lp;
     int i,media,fdx = 0, mii = 0;
+#ifdef DO_DXSUFLO
+    int dxsuflo = 0;
+#endif
+    int ltint = 0;
     int chip_version;
     char *chipname;
     char *priv;
@@ -532,12 +553,14 @@
 	    return ENODEV;
     }
 
+
     chip_version = a->read_csr (ioaddr, 88) | (a->read_csr (ioaddr,89) << 16);
     if (pcnet32_debug > 2)
 	printk("  PCnet chip version is %#x.\n", chip_version);
     if ((chip_version & 0xfff) != 0x003)
 	return ENODEV;
     chip_version = (chip_version >> 12) & 0xffff;
+
     switch (chip_version) {
      case 0x2420:
 	chipname = "PCnet/PCI 79C970";
@@ -554,11 +577,33 @@
 	break;
      case 0x2623:
 	chipname = "PCnet/FAST 79C971";
+	/* To prevent Tx FIFO underflows ... (may increase Tx latency) */
+	/* Set BCR18:NOUFLO to not start Tx until reach Tx start point */
+	/* Looks like EEPROM sets BCR18:5/6 for BurstWrite/Read */
+        a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800));
+	/* Set CSR80:XMTSP, Tx start point = 20|64|128|248 bytes or size of frame */
+        i = a->read_csr(ioaddr, 80) & ~0x0C00; /* Clear bits we are touching */
+        a->write_csr(ioaddr, 80, i | (tx_start << 10));
 	fdx = 1; mii = 1;
+#ifdef DO_DXSUFLO
+	dxsuflo = 1;
+#endif
+	ltint = 1;
 	break;
      case 0x2624:
 	chipname = "PCnet/FAST+ 79C972";
+	/* To prevent Tx FIFO underflows ... (may increase Tx latency) */
+	/* Set BCR18:NOUFLO to not start Tx until reach Tx start point */
+	/* Looks like EEPROM sets BCR18:5/6 for BurstWrite/Read */
+        a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800));
+	/* Set CSR80:XMTSP, Tx start point = 20|64|128|220 bytes or size of frame */
+        i = a->read_csr(ioaddr, 80) & ~0x0C00; /* Clear bits we are touching */
+        a->write_csr(ioaddr, 80, i | (tx_start << 10));
 	fdx = 1; mii = 1;
+#ifdef DO_DXSUFLO
+	dxsuflo = 1;
+#endif
+	ltint = 1;
 	break;
      case 0x2625:
 	chipname = "PCnet/FAST III 79C973";
@@ -602,6 +647,29 @@
     for (i = 0; i < 6; i++)
       printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
 
+    if (((chip_version + 1) & 0xfffe) == 0x2624) { /* Version 0x2623 or 0x2624 */
+        i = a->read_csr(ioaddr, 80) & 0x0C00;  /* Check tx_start_pt */
+	printk("\n    tx_start_pt(0x%04x):",i);
+	switch(i>>10) {
+	    case 0: printk("  20 bytes,"); break;
+	    case 1: printk("  64 bytes,"); break;
+	    case 2: printk(" 128 bytes,"); break;
+	    case 3: printk("~220 bytes,"); break;
+	}
+        i = a->read_bcr(ioaddr, 18);  /* Check Burst/Bus control */
+        printk(" BCR18(%x):",i&0xffff);
+	if (i & (1<<5)) printk("BurstWrEn ");
+	if (i & (1<<6)) printk("BurstRdEn ");
+	if (i & (1<<7)) printk("DWordIO ");
+	if (i & (1<<11)) printk("NoUFlow ");
+        i = a->read_bcr(ioaddr, 25);
+        printk("\n    SRAMSIZE=0x%04x,",i<<8);
+        i = a->read_bcr(ioaddr, 26);
+        printk(" SRAM_BND=0x%04x,",i<<8);
+        i = a->read_bcr(ioaddr, 27);
+	if (i & (1<<14)) printk("LowLatRx,");
+    }
+
     dev->base_addr = ioaddr;
     request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
     
@@ -615,10 +683,17 @@
     lp = (struct pcnet32_private *)(((unsigned long)priv+15) & ~15);
       
     memset(lp, 0, sizeof(*lp));
+    
+    spin_lock_init(&lp->lock);
+    
     dev->priv = lp;
     lp->name = chipname;
     lp->shared_irq = shared;
     lp->full_duplex = fdx;
+#ifdef DO_DXSUFLO
+    lp->dxsuflo = dxsuflo;
+#endif
+    lp->ltint = ltint;
     lp->mii = mii;
     if (options[card_idx] > sizeof (options_mapping))
 	lp->options = PORT_ASEL;
@@ -746,7 +821,7 @@
 	lp->a.write_bcr (ioaddr, 9, val);
     }
     
-    /* set/reset GPSI bit in test register */
+    /* NOOP ??? set/reset GPSI bit in test register */
     val = lp->a.read_csr (ioaddr, 124) & ~0x10;
     if ((lp->options & PORT_PORTSEL) == PORT_GPSI)
 	val |= 0x10;
@@ -760,6 +835,19 @@
 	    val |= 0x08;
 	lp->a.write_bcr (ioaddr, 32, val);
     }
+
+#ifdef DO_DXSUFLO 
+    if (lp->dxsuflo) { /* Disable transmit stop on underflow */
+        val = lp->a.read_csr (ioaddr, 3);
+	val |= 0x40;
+        lp->a.write_csr (ioaddr, 3, val);
+    }
+#endif
+    if (lp->ltint) { /* Enable TxDone-intr inhibitor */
+        val = lp->a.read_csr (ioaddr, 5);
+	val |= (1<<14);
+        lp->a.write_csr (ioaddr, 5, val);
+    }
     
     lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
     lp->init_block.filter[0] = 0x00000000;
@@ -856,7 +944,7 @@
 	lp->tx_ring[i].status = 0;
     }
 
-    lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS;
+    lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); 
     for (i = 0; i < 6; i++)
 	lp->init_block.phys_addr[i] = dev->dev_addr[i];
     lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring));
@@ -890,6 +978,7 @@
 {
     struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
     unsigned int ioaddr = dev->base_addr;
+    u16 status;
     int entry;
     unsigned long flags;
 
@@ -937,8 +1026,23 @@
 	return 1;
     }
 
-    save_flags (flags);
-    cli ();
+    spin_lock_irqsave(&lp->lock, flags);
+
+    /* Default status -- will not enable Successful-TxDone
+     * interrupt when that option is available to us.
+     */
+    status = 0x8300;
+    if ((lp->ltint) &&
+	((lp->cur_tx - lp->dirty_tx == TX_RING_SIZE/2) ||
+	 (lp->cur_tx - lp->dirty_tx >= TX_RING_SIZE-2)))
+    {
+	/* Enable Successful-TxDone interrupt if we have
+	 * 1/2 of, or nearly all of, our ring buffer Tx'd
+	 * but not yet cleaned up.  Thus, most of the time,
+	 * we will not enable Successful-TxDone interrupts.
+	 */
+	status = 0x9300;
+    }
 
     /* Fill in a Tx ring entry */
 
@@ -954,7 +1058,8 @@
 
     lp->tx_skbuff[entry] = skb;
     lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data));
-    lp->tx_ring[entry].status = le16_to_cpu(0x8300);
+
+    lp->tx_ring[entry].status = le16_to_cpu(status);
 
     lp->cur_tx++;
     lp->stats.tx_bytes += skb->len;
@@ -968,7 +1073,7 @@
 	clear_bit (0, (void *)&dev->tbusy);
     else
 	lp->tx_full = 1;
-    restore_flags(flags);
+    spin_unlock_irqrestore(&lp->lock, flags);
     return 0;
 }
 
@@ -990,6 +1095,9 @@
 
     ioaddr = dev->base_addr;
     lp = (struct pcnet32_private *)dev->priv;
+
+    spin_lock(&lp->lock);
+
     if (dev->interrupt)
 	printk("%s: Re-entering the interrupt handler.\n", dev->name);
 
@@ -1010,7 +1118,7 @@
 	    pcnet32_rx(dev);
 
 	if (csr0 & 0x0200) {		/* Tx-done interrupt */
-	    int dirty_tx = lp->dirty_tx;
+	    unsigned int dirty_tx = lp->dirty_tx;
 
 	    while (dirty_tx < lp->cur_tx) {
 		int entry = dirty_tx & TX_RING_MOD_MASK;
@@ -1028,14 +1136,27 @@
 		    if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;
 		    if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
 		    if (err_status & 0x10000000) lp->stats.tx_window_errors++;
+#ifndef DO_DXSUFLO
 		    if (err_status & 0x40000000) {
-			/* Ackk!  On FIFO errors the Tx unit is turned off! */
 			lp->stats.tx_fifo_errors++;
+			/* Ackk!  On FIFO errors the Tx unit is turned off! */
 			/* Remove this verbosity later! */
-			printk("%s: Tx FIFO error! Status %4.4x.\n",
-			       dev->name, csr0);
+			printk("%s: Tx FIFO error! CSR0=%4.4x\n",
+					    dev->name, csr0);
 			must_restart = 1;
 					}
+#else
+		    if (err_status & 0x40000000) {
+			lp->stats.tx_fifo_errors++;
+			if (! lp->dxsuflo) {  /* If controller doesn't recover ... */
+			    /* Ackk!  On FIFO errors the Tx unit is turned off! */
+			    /* Remove this verbosity later! */
+			    printk("%s: Tx FIFO error! CSR0=%4.4x\n",
+					   	dev->name, csr0);
+			    must_restart = 1;
+			}
+		    }
+#endif
 		} else {
 		    if (status & 0x1800)
 			lp->stats.collisions++;
@@ -1104,6 +1225,8 @@
 	       dev->name, lp->a.read_csr (ioaddr, 0));
 
     dev->interrupt = 0;
+
+    spin_unlock(&lp->lock);
     return;
 }
 
@@ -1252,12 +1375,11 @@
     u16 saved_addr;
     unsigned long flags;
 
-    save_flags(flags);
-    cli();
+    spin_lock_irqsave(&lp->lock, flags);
     saved_addr = lp->a.read_rap(ioaddr);
     lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);
     lp->a.write_rap(ioaddr, saved_addr);
-    restore_flags(flags);
+    spin_unlock_irqrestore(&lp->lock, flags);
 
     return &lp->stats;
 }
@@ -1371,18 +1493,22 @@
 MODULE_PARM(debug, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(tx_start_pt, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 					     
 
 /* An additional parameter that may be passed in... */
 static int debug = -1;
+static int tx_start_pt = -1;
 
 int
 init_module(void)
 {
     if (debug > 0)
 	pcnet32_debug = debug;
+    if ((tx_start_pt >= 0) && (tx_start_pt <= 3))
+	tx_start = tx_start_pt;
     
     pcnet32_dev = NULL;
     return pcnet32_probe(NULL);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/plip.c linux.14p16/drivers/net/plip.c
--- linux.vanilla/drivers/net/plip.c	Sun Mar  7 23:47:46 1999
+++ linux.14p16/drivers/net/plip.c	Wed Dec 15 16:39:22 1999
@@ -1257,6 +1257,7 @@
 			if (!dev_plip[i]->name) {
 				printk(KERN_ERR "plip: memory squeeze.\n");
 				kfree(dev_plip[i]);
+				dev_plip[i] = NULL;
 				break;
 			}
 			sprintf(dev_plip[i]->name, "plip%d", i);
@@ -1264,6 +1265,7 @@
 			if (plip_init_dev(dev_plip[i],pb) || register_netdev(dev_plip[i])) {
 				kfree(dev_plip[i]->name);
 				kfree(dev_plip[i]);
+				dev_plip[i] = NULL;
 			} else {
 				i++;
 			}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sbni.c linux.14p16/drivers/net/sbni.c
--- linux.vanilla/drivers/net/sbni.c	Wed Oct 20 01:12:39 1999
+++ linux.14p16/drivers/net/sbni.c	Thu Dec  9 15:33:33 1999
@@ -1371,7 +1371,7 @@
 		"movl %%edx,%%eax"
 		: 
 		: "S" (mem), "D" (&crc32tab[0]), "c" (len), "d" (initial)
-		: "eax", "edx", "ecx"
+		: "eax"
 	);
 	/* return crc; */
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla.c linux.14p16/drivers/net/sdla.c
--- linux.vanilla/drivers/net/sdla.c	Tue Dec 29 19:32:06 1998
+++ linux.14p16/drivers/net/sdla.c	Thu Dec  9 15:33:27 1999
@@ -1666,7 +1666,7 @@
 	return(0);
 }
 
-__initfunc(void sdla_setup(void))
+__initfunc(void sdla_c_setup(void))
 {
 	printk("%s.\n", version);
 	register_frad(devname);
@@ -1679,7 +1679,7 @@
 {
 	int result;
 
-	sdla_setup();
+	sdla_c_setup();
 	if ((result = register_netdev(&sdla0)) != 0)
 		return result;
 	return 0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_chdlc.c linux.14p16/drivers/net/sdla_chdlc.c
--- linux.vanilla/drivers/net/sdla_chdlc.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sdla_chdlc.c	Wed Dec 15 16:25:08 1999
@@ -0,0 +1,2785 @@
+/*****************************************************************************
+* sdla_chdlc.c	WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module.
+*
+* Authors: 	Nenad Corbic <ncorbic@sangoma.com>
+*		Gideon Hack  
+*
+* Copyright:	(c) 1995-1999 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.
+* ============================================================================
+* Nov 20, 1999  Nenad Corbic 	Fixed zero length API bug.
+* Sep 30, 1999  Nenad Corbic    Fixed dynamic IP and route setup.
+* Sep 23, 1999  Nenad Corbic    Added SMP support, fixed tracing 
+* Sep 13, 1999  Nenad Corbic	Split up Port 0 and 1 into separate devices.
+* Jun 02, 1999  Gideon Hack     Added support for the S514 adapter.
+* Oct 30, 1998	Jaspreet Singh	Added Support for CHDLC API (HDLC STREAMING).
+* Oct 28, 1998	Jaspreet Singh	Added Support for Dual Port CHDLC.
+* Aug 07, 1998	David Fong	Initial version.
+*****************************************************************************/
+
+#include <linux/version.h>
+#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/wanrouter.h>	/* WAN router definitions */
+#include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
+#include <linux/if_arp.h>	/* ARPHRD_* defines */
+#include <linux/inetdevice.h>
+#include <asm/uaccess.h>
+#include <linux/in.h>		/* sockaddr_in */
+#include <linux/inet.h>	
+#include <linux/if.h>
+#include <asm/byteorder.h>	/* htons(), etc. */
+#include <linux/sdlapci.h>
+#include <asm/io.h>
+
+#include <linux/sdla_chdlc.h>		/* CHDLC firmware API definitions */
+
+/****** Defines & Macros ****************************************************/
+
+#ifdef	_DEBUG_
+#define	STATIC
+#else
+#define	STATIC		static
+#endif
+
+/* reasons for enabling the timer interrupt on the adapter */
+#define TMR_INT_ENABLED_UDP   	0x0001
+#define TMR_INT_ENABLED_UPDATE	0x0002
+ 
+#define	CHDLC_DFLT_DATA_LEN	1500		/* default MTU */
+#define CHDLC_HDR_LEN		1
+
+#define IFF_POINTTOPOINT 0x10
+
+#define WANPIPE 0x00
+#define API	0x01
+#define CHDLC_API 0x01
+
+#define PORT(x)   (x == 0 ? "PRIMARY" : "SECONDARY" )
+
+ 
+/******Data Structures*****************************************************/
+
+/* This structure is placed in the private data area of the device structure.
+ * The card structure used to occupy the private area but now the following 
+ * structure will incorporate the card structure along with CHDLC specific data
+ */
+
+typedef struct chdlc_private_area
+{
+	sdla_t		*card;
+	int 		TracingEnabled;		/* For enabling Tracing */
+	unsigned long 	curr_trace_addr;	/* Used for Tracing */
+	unsigned long 	start_trace_addr;
+	unsigned long 	end_trace_addr;
+	unsigned long 	base_addr_trace_buffer;
+	unsigned long 	end_addr_trace_buffer;
+	unsigned short 	number_trace_elements;
+	unsigned  	available_buffer_space;
+	unsigned long 	router_start_time;
+	unsigned char 	route_status;
+	unsigned char 	route_removed;
+	unsigned long 	tick_counter;		/* For 5s timeout counter */
+	unsigned long 	router_up_time;
+        u32             IP_address;		/* IP addressing */
+        u32             IP_netmask;
+	unsigned char  mc;			/* Mulitcast support on/off */
+	unsigned short udp_pkt_lgth;		/* udp packet processing */
+	char udp_pkt_src;
+	char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT];
+	unsigned short timer_int_enabled;
+	char update_comms_stats;		/* updating comms stats */
+	//FIXME: add driver stats as per frame relay!
+
+} chdlc_private_area_t;
+
+/* Route Status options */
+#define NO_ROUTE	0x00
+#define ADD_ROUTE	0x01
+#define ROUTE_ADDED	0x02
+#define REMOVE_ROUTE	0x03
+
+
+/* variable for keeping track of enabling/disabling FT1 monitor status */
+static int rCount = 0;
+
+/* variable for tracking how many interfaces to open for WANPIPE on the
+   two ports */
+
+extern void disable_irq(unsigned int);
+extern void enable_irq(unsigned int);
+
+/****** 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);
+#ifdef LINUX_2_1
+static int if_rebuild_hdr (struct sk_buff *skb);
+#else
+static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
+        struct sk_buff* skb);
+#endif
+static int if_send (struct sk_buff* skb, struct device* dev);
+static struct enet_statistics* if_stats (struct device* dev);
+
+/* CHDLC Firmware interface functions */
+static int chdlc_configure 	(sdla_t* card, void* data);
+static int chdlc_comm_enable 	(sdla_t* card);
+static int chdlc_comm_disable 	(sdla_t* card);
+static int chdlc_read_version 	(sdla_t* card, char* str);
+static int chdlc_set_intr_mode 	(sdla_t* card, unsigned mode);
+static int chdlc_send (sdla_t* card, void* data, unsigned len);
+static int chdlc_read_comm_err_stats (sdla_t* card);
+static int chdlc_read_op_stats (sdla_t* card);
+
+
+/* Miscellaneous CHDLC Functions */
+static int set_chdlc_config (sdla_t* card);
+static void init_chdlc_tx_rx_buff( sdla_t* card, struct device *dev );
+static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb);
+static int process_chdlc_exception(sdla_t *card);
+static int process_global_exception(sdla_t *card);
+static int update_comms_stats(sdla_t* card,
+        chdlc_private_area_t* chdlc_priv_area);
+static int configure_ip (sdla_t* card);
+static int unconfigure_ip (sdla_t* card);
+static void process_route(sdla_t *card);
+static void port_set_state (sdla_t *card, int);
+
+
+/* Interrupt handlers */
+static void wpc_isr (sdla_t* card);
+static void rx_intr (sdla_t* card);
+static void timer_intr(sdla_t *);
+
+/* Miscellaneous functions */
+static int chk_bcast_mcast_addr(sdla_t* card, struct device* dev,
+				struct sk_buff *skb);
+static int reply_udp( unsigned char *data, unsigned int mbox_len );
+static int intr_test( sdla_t* card, struct device *dev );
+static int udp_pkt_type( struct sk_buff *skb , sdla_t* card);
+static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
+                                struct sk_buff *skb, struct device* dev,
+                                chdlc_private_area_t* chdlc_priv_area);
+static int process_udp_mgmt_pkt(sdla_t* card, struct device* dev,  
+				chdlc_private_area_t* chdlc_priv_area);
+static unsigned short calc_checksum (char *, int);
+static void s508_lock (sdla_t *card, unsigned long *smp_flags);
+static void s508_unlock (sdla_t *card, unsigned long *smp_flags);
+
+
+static int  Intr_test_counter;
+/****** Public Functions ****************************************************/
+
+/*============================================================================
+ * Cisco HDLC 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 wpc_init (sdla_t* card, wandev_conf_t* conf)
+{
+	unsigned char port_num;
+	int err;
+	unsigned long max_permitted_baud = 0;
+
+	union
+		{
+		char str[80];
+		} u;
+	volatile CHDLC_MAILBOX_STRUCT* mb;
+	CHDLC_MAILBOX_STRUCT* mb1;
+	unsigned long timeout;
+
+	/* Verify configuration ID */
+	if (conf->config_id != WANCONFIG_CHDLC) {
+		printk(KERN_INFO "%s: invalid configuration ID %u!\n",
+				  card->devname, conf->config_id);
+		return -EINVAL;
+	}
+
+	/* Find out which Port to use */
+	if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){
+		if (card->next){
+
+			if (conf->comm_port != card->next->u.c.comm_port){
+				card->u.c.comm_port = conf->comm_port;
+			}else{
+				printk(KERN_ERR "%s: ERROR - %s port used!\n",
+        		        	card->wandev.name, PORT(conf->comm_port));
+				return -EINVAL;
+			}
+		}else{
+			card->u.c.comm_port = conf->comm_port;
+		}
+	}else{
+		printk(KERN_ERR "%s: ERROR - Invalid Port Selected!\n",
+                			card->wandev.name);
+		return -EINVAL;
+	}
+	
+
+	/* Initialize protocol-specific fields */
+	if(card->hw.type != SDLA_S514){
+
+		if (card->u.c.comm_port == WANOPT_PRI){	
+			card->mbox  = (void *) card->hw.dpmbase;
+		}else{
+			card->mbox  = (void *) card->hw.dpmbase + 
+				SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT;
+		}	
+	}else{ 
+		/* for a S514 adapter, set a pointer to the actual mailbox in the */
+		/* allocated virtual memory area */
+		if (card->u.c.comm_port == WANOPT_PRI){
+			card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT;
+		}else{
+			card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT;
+		}	
+	}
+
+	mb = mb1 = card->mbox;
+
+	if (!card->configured){
+
+		/* The board will place an 'I' in the return code to indicate that it is
+	   	ready to accept commands.  We expect this to be completed in less
+           	than 1 second. */
+
+		timeout = jiffies;
+		while (mb->return_code != 'I')	/* Wait 1s for board to initialize */
+			if ((jiffies - timeout) > 1*HZ) break;
+
+		if (mb->return_code != 'I') {
+			printk(KERN_INFO
+				"%s: Initialization not completed by adapter\n",
+				card->devname);
+			printk(KERN_INFO "Please contact Sangoma representative.\n");
+			return -EIO;
+		}
+	}
+
+	/* 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 (chdlc_read_version(card, u.str))
+		return -EIO;
+
+	printk(KERN_INFO "%s: Running Cisco HDLC firmware v%s\n",
+		card->devname, u.str); 
+
+	card->isr			= &wpc_isr;
+	card->poll			= NULL;
+	card->exec			= NULL;
+	card->wandev.update		= &update;
+ 	card->wandev.new_if		= &new_if;
+	card->wandev.del_if		= &del_if;
+	card->wandev.state		= WAN_DUALPORT;
+	card->wandev.udp_port   	= conf->udp_port;
+
+	card->wandev.new_if_cnt = 0;
+
+	/* This is for the ports link state */
+	card->u.c.state = WAN_DISCONNECTED;
+	
+	/* reset the number of times the 'update()' proc has been called */
+	card->u.c.update_call_count = 0;
+	
+	card->wandev.ttl = conf->ttl;
+	card->wandev.interface = conf->interface; 
+
+	if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&&
+	    card->hw.type != SDLA_S514){
+		printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n",
+			card->devname, PORT(card->u.c.comm_port));
+		return -EIO;
+	}
+
+	card->wandev.clocking = conf->clocking;
+
+	port_num = card->u.c.comm_port;
+
+	/* Setup Port Bps */
+
+	if(card->wandev.clocking) {
+                      
+		if(port_num == WANOPT_PRI) {
+			/* For Primary Port 0 */
+               		max_permitted_baud =
+				(card->hw.type == SDLA_S514) ?
+				PRI_MAX_BAUD_RATE_S514 : 
+				PRI_MAX_BAUD_RATE_S508;
+		}
+		else if(port_num == WANOPT_SEC) {
+			/* For Secondary Port 1 */
+                        max_permitted_baud =
+                               (card->hw.type == SDLA_S514) ?
+                                SEC_MAX_BAUD_RATE_S514 :
+                                SEC_MAX_BAUD_RATE_S508;
+                        }
+  
+			if(conf->bps > max_permitted_baud) {
+				conf->bps = max_permitted_baud;
+				printk(KERN_INFO "%s: Baud too high!\n",
+					card->wandev.name);
+ 				printk(KERN_INFO "%s: Baud rate set to %lu bps\n", 
+					card->wandev.name, max_permitted_baud);
+			}
+                             
+			card->wandev.bps = conf->bps;
+	}else{
+        	card->wandev.bps = 0;
+  	}
+
+	/* Setup the Port MTU */
+	if(port_num == WANOPT_PRI) {
+		/* For Primary Port 0 */
+		card->wandev.mtu =
+			(conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ?
+			min(conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) :
+			CHDLC_DFLT_DATA_LEN;
+	} else if(port_num == WANOPT_SEC) { 
+		/* For Secondary Port 1 */
+		card->wandev.mtu =
+			(conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ?
+			min(conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) :
+			CHDLC_DFLT_DATA_LEN;
+	}
+
+	/* Set up the interrupt status area */
+	/* Read the CHDLC Configuration and obtain: 
+	 *	Ptr to shared memory infor struct
+         * Use this pointer to calculate the value of card->u.c.flags !
+ 	 */
+	mb1->buffer_length = 0;
+	mb1->command = READ_CHDLC_CONFIGURATION;
+	err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT;
+	if(err != COMMAND_OK) {
+		clear_bit(1, (void*)&card->wandev.critical);
+
+                if(card->hw.type != SDLA_S514)
+                	enable_irq(card->hw.irq);
+
+		chdlc_error(card, err, mb1);
+		return -EIO;
+	}
+
+	if(card->hw.type == SDLA_S514){
+               	card->u.c.flags = (void *)(card->hw.dpmbase +
+               		(((CHDLC_CONFIGURATION_STRUCT *)mb1->data)->
+			ptr_shared_mem_info_struct));
+        }else{
+                card->u.c.flags = (void *)(card->hw.dpmbase +
+                        (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)->
+			ptr_shared_mem_info_struct % SDLA_WINDOWSIZE));
+	}
+
+	return 0;
+}
+
+/******* WAN Device Driver Entry Points *************************************/
+
+/*============================================================================
+ * Update device status & statistics
+ * This procedure is called when updating the PROC file system and returns
+ * various communications statistics. These statistics are accumulated from 3 
+ * different locations:
+ * 	1) The 'if_stats' recorded for the device.
+ * 	2) Communication error statistics on the adapter.
+ *      3) CHDLC operational statistics on the adapter.
+ * The board level statistics are read during a timer interrupt. Note that we 
+ * read the error and operational statistics during consecitive timer ticks so
+ * as to minimize the time that we are inside the interrupt handler.
+ *
+ */
+static int update (wan_device_t* wandev)
+{
+	sdla_t* card = wandev->private;
+ 	struct device* dev = card->wandev.dev;
+        volatile chdlc_private_area_t* chdlc_priv_area = dev->priv;
+        SHARED_MEMORY_INFO_STRUCT *flags;
+	unsigned long timeout;
+
+	/* sanity checks */
+	if((wandev == NULL) || (wandev->private == NULL))
+		return -EFAULT;
+	
+	if(wandev->state == WAN_UNCONFIGURED)
+		return -ENODEV;
+
+	/* more sanity checks */
+        if(!card->u.c.flags)
+                return -ENODEV;
+	if(test_bit(1, (void*)&card->wandev.critical))
+                return -EAGAIN;
+
+	if(!dev->start)
+		return -ENODEV;
+
+      	flags = card->u.c.flags;
+       	if(chdlc_priv_area->update_comms_stats){
+		return -EAGAIN;
+	}
+			
+	/* we will need 2 timer interrupts to complete the */
+	/* reading of the statistics */
+	chdlc_priv_area->update_comms_stats = 2;
+       	flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER;
+	chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE;
+  
+	/* wait a maximum of 1 second for the statistics to be updated */ 
+        timeout = jiffies;
+        for(;;) {
+		if(chdlc_priv_area->update_comms_stats == 0)
+			break;
+                if ((jiffies - timeout) > (1 * HZ)){
+    			chdlc_priv_area->update_comms_stats = 0;
+ 			chdlc_priv_area->timer_int_enabled &=
+				~TMR_INT_ENABLED_UPDATE; 
+ 			return -EAGAIN;
+		}
+        }
+
+	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;
+	chdlc_private_area_t* chdlc_priv_area;
+
+	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 */
+	chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL);
+	
+	if(chdlc_priv_area == NULL) 
+		return -ENOMEM;
+
+	memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t));
+	
+	chdlc_priv_area->card = card; 
+	
+	/* initialize data */
+	strcpy(card->u.c.if_name, conf->name);
+
+	if(card->wandev.new_if_cnt > 0) {
+                kfree(chdlc_priv_area);
+		return -EEXIST;
+	}
+
+	card->wandev.new_if_cnt++;
+
+	chdlc_priv_area->TracingEnabled = 0;
+	chdlc_priv_area->route_status = NO_ROUTE;
+	chdlc_priv_area->route_removed = 0;
+
+	/* Setup protocol options */
+
+	card->u.c.protocol_options = 0;
+
+	if (conf->ignore_dcd == WANOPT_YES){
+		card->u.c.protocol_options |= IGNORE_DCD_FOR_LINK_STAT;
+	}
+
+	if (conf->ignore_cts == WANOPT_YES){
+		card->u.c.protocol_options |= IGNORE_CTS_FOR_LINK_STAT;
+	}
+
+	if (conf->ignore_keepalive == WANOPT_YES) {
+		card->u.c.protocol_options |= IGNORE_KPALV_FOR_LINK_STAT;
+		card->u.c.kpalv_tx  = MIN_Tx_KPALV_TIMER; 
+		card->u.c.kpalv_rx  = MIN_Rx_KPALV_TIMER; 
+		card->u.c.kpalv_err = MIN_KPALV_ERR_TOL; 
+
+	} else {   /* Do not ignore keepalives */
+
+		card->u.c.kpalv_tx =
+  	   		(conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) >= 0 ?
+	   		min (conf->keepalive_tx_tmr, MAX_Tx_KPALV_TIMER) :
+	   					DEFAULT_Tx_KPALV_TIMER;
+
+		card->u.c.kpalv_rx =
+	   		(conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) >= 0 ?
+	   		min (conf->keepalive_rx_tmr, MAX_Rx_KPALV_TIMER) :
+	   					DEFAULT_Rx_KPALV_TIMER;
+
+		card->u.c.kpalv_err =
+	   		(conf->keepalive_err_margin - MIN_KPALV_ERR_TOL) >= 0 ?
+	   		min (conf->keepalive_err_margin, MAX_KPALV_ERR_TOL) : 
+	   					DEFAULT_KPALV_ERR_TOL;
+	}
+
+
+	/* Setup slarp timer to control delay between slarps 
+         */ 
+	card->u.c.slarp_timer = 
+		(conf->slarp_timer - MIN_SLARP_REQ_TIMER) >=0 ?
+		min (conf->slarp_timer, MAX_SLARP_REQ_TIMER) :
+					DEFAULT_SLARP_REQ_TIMER;
+
+
+	/* If HDLC_STRAMING is enabled then IGNORE DCD, CTS and KEEPALIVES
+         * are automatically ignored 
+	 */
+	if (conf->hdlc_streaming == WANOPT_YES) {
+		printk(KERN_INFO "%s: Enabling HDLC STREAMING Mode\n",
+			wandev->name);
+		card->u.c.protocol_options = HDLC_STREAMING_MODE;
+	}
+
+
+        /* Setup wanpipe as a router (WANPIPE) or as an API */
+	if( strcmp(conf->usedby, "WANPIPE") == 0) {
+		printk(KERN_INFO "%s: Running in WANPIPE mode !\n",wandev->name);
+		card->u.c.usedby = WANPIPE;
+
+	} else if( strcmp(conf->usedby, "API") == 0){
+
+#ifdef CHDLC_API 
+		card->u.c.usedby = API;
+		printk(KERN_INFO "%s: Running in API mode !\n",wandev->name);
+#else
+		printk(KERN_INFO "%s: API Mode is not supported!\n",
+			wandev->name);
+		printk(KERN_INFO "%s: Chdlc API patch can be obtained from Sangoma Tech.\n",
+					wandev->name);
+                kfree(chdlc_priv_area);
+		return -EINVAL;
+#endif
+	}
+
+
+	/* Get Multicast Information */
+	chdlc_priv_area->mc = conf->mc;
+
+	/* prepare network device data space for registration */
+	dev->name = card->u.c.if_name;
+	dev->init = &if_init;
+	dev->priv = chdlc_priv_area;
+
+	return 0;
+}
+
+/*============================================================================
+ * Delete logical channel.
+ */
+static int del_if (wan_device_t* wandev, struct device* dev)
+{
+
+/* FIXME: This code generates kernel panic during
+          router stop!. Investigate futher.
+	  (Error is dereferencing a NULL pointer)
+
+	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)
+	{
+	chdlc_private_area_t* chdlc_priv_area = dev->priv;
+	sdla_t* card = chdlc_priv_area->card;
+	wan_device_t* wandev = &card->wandev;
+#ifndef LINUX_2_1
+	int i;
+#endif
+
+	/* 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->flags		|= IFF_POINTTOPOINT;
+
+	/* Enable Mulitcasting if user selected */
+	if (chdlc_priv_area->mc == WANOPT_YES){
+		dev->flags 	|= IFF_MULTICAST;
+	}
+
+#ifndef LINUX_2_1
+	dev->family		= AF_INET;
+#endif	
+	dev->type		= ARPHRD_PPP;	/* ARP hw type -- dummy value */
+	dev->mtu		= card->wandev.mtu;
+	dev->hard_header_len	= CHDLC_HDR_LEN;
+
+	/* Initialize hardware parameters */
+	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;
+
+	/* Set transmit buffer queue length 
+	 * If too low packets will not be retransmitted 
+         * by stack.
+	 */
+        dev->tx_queue_len = 100;
+   
+	/* Initialize socket buffers */
+#ifdef LINUX_2_1
+	dev_init_buffers(dev);
+#else
+        for (i = 0; i < DEV_NUMBUFFS; ++i)
+                skb_queue_head_init(&dev->buffs[i]);
+#endif
+
+	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)
+{
+	chdlc_private_area_t* chdlc_priv_area = dev->priv;
+	sdla_t* card = chdlc_priv_area->card;
+	SHARED_MEMORY_INFO_STRUCT* flags = card->u.c.flags;
+	struct timeval tv;
+	int err = 0;
+
+	/* Only one open per interface is allowed */
+
+	if(dev->start)
+		return -EBUSY;
+	
+	if(test_and_set_bit(1, (void*)&card->wandev.critical)) {
+		return -EAGAIN;
+	}
+	
+	/* Setup the Board for CHDLC */
+	if (set_chdlc_config(card)) {
+		clear_bit(1, (void*)&card->wandev.critical);
+		return -EIO;
+	}
+
+	if (!card->configured && !card->wandev.piggyback){	
+		/* Perform interrupt testing */
+		err = intr_test(card, dev);
+
+		if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { 
+			printk(KERN_ERR "%s: Interrupt test failed (%i)\n",
+					card->devname, Intr_test_counter);
+			printk(KERN_ERR "%s: Please choose another interrupt\n",
+					card->devname);
+			clear_bit(1, (void*)&card->wandev.critical);
+			return -EIO;
+		}
+		
+		printk(KERN_INFO "%s: Interrupt test passed (%i)\n", 
+				card->devname, Intr_test_counter);
+		card->configured = 1;
+	}else{
+		printk(KERN_INFO "%s: Card configured, skip interrupt test\n", 
+				card->devname);
+	}
+
+	/* Initialize Rx/Tx buffer control fields */
+	init_chdlc_tx_rx_buff(card, dev);
+
+	/* Set interrupt mode and mask */
+        if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME |
+                		APP_INT_ON_GLOBAL_EXCEP_COND |
+                		APP_INT_ON_TX_FRAME |
+                		APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){
+
+			clear_bit(1, (void*)&card->wandev.critical);
+                        return -EIO;
+        }
+	
+
+	/* Mask the Transmit and Timer interrupt */
+	flags->interrupt_info_struct.interrupt_permission &= 
+		~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER);
+
+
+	/* Enable communications */
+	if (chdlc_comm_enable(card)) {
+		clear_bit(1, (void*)&card->wandev.critical);
+		return -EIO;
+	}
+
+	clear_bit(1, (void*)&card->wandev.critical);
+
+	port_set_state(card, WAN_CONNECTING);
+	do_gettimeofday(&tv);
+	chdlc_priv_area->router_start_time = tv.tv_sec;
+ 
+	dev->interrupt = 0;
+	dev->tbusy = 0;
+	dev->start = 1;
+	dev->flags |= IFF_POINTTOPOINT;
+	wanpipe_open(card);
+
+	return err;
+}
+
+/*============================================================================
+ * Close network interface.
+ * o if this is the last close, then disable communications and interrupts.
+ * o reset flags.
+ */
+static int if_close (struct device* dev)
+{
+	chdlc_private_area_t* chdlc_priv_area = dev->priv;
+	sdla_t* card = chdlc_priv_area->card;
+
+	if(test_and_set_bit(1, (void*)&card->wandev.critical))
+		return -EAGAIN;
+
+	dev->start = 0;
+	wanpipe_close(card);
+	port_set_state(card, WAN_DISCONNECTED);
+	chdlc_set_intr_mode(card, 0);
+	chdlc_comm_disable(card);
+
+	clear_bit(1, (void*)&card->wandev.critical);
+
+	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)
+{
+	skb->protocol = htons(type);
+
+	return CHDLC_HDR_LEN;
+}
+
+/*============================================================================
+ * Re-build media header.
+ *
+ * Return:	1	physical address resolved.
+ *		0	physical address not resolved
+ */
+#ifdef LINUX_2_1
+static int if_rebuild_hdr (struct sk_buff *skb)
+{
+	return 1;
+}
+#else
+static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
+                           struct sk_buff* skb)
+{
+        return 1;
+}
+#endif
+
+/*============================================================================
+ * 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)
+{
+	chdlc_private_area_t *chdlc_priv_area = dev->priv;
+	sdla_t *card = chdlc_priv_area->card;
+	SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
+	INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct;
+	int udp_type = 0;
+	unsigned long smp_flags;
+
+	if(skb == NULL) {
+		/* If we get here, some higher layer thinks we've missed an
+		 * tx-done interrupt.
+		 */
+		printk(KERN_INFO "%s: interface %s got kicked!\n",
+			card->devname, dev->name);
+		mark_bh(NET_BH);
+		return 0;
+	}
+
+	if(dev->tbusy) {
+
+		/* If our device stays busy for at least 5 seconds then we will
+		 * kick start the device by making dev->tbusy = 0.  We expect 
+		 * that our device never stays busy more than 5 seconds. So this
+		 * is only used as a last resort. 
+		 */
+                ++card->wandev.stats.collisions;
+
+		if((jiffies - chdlc_priv_area->tick_counter) < (5 * HZ)) {
+			return 1;
+		}
+
+		printk (KERN_INFO "%s: Transmit timeout !\n",
+			card->devname);
+
+		/* unbusy the interface */
+		dev->tbusy = 0;
+	}
+	
+   	if(ntohs(skb->protocol) != 0x16) {
+
+		/* check the udp packet type */
+		udp_type = udp_pkt_type(skb, card);
+		if(udp_type == UDP_CPIPE_TYPE) {
+                        if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev,
+                                chdlc_priv_area))
+	                	chdlc_int->interrupt_permission |=
+					APP_INT_ON_TIMER;
+			return 0;
+		}
+
+		/* check to see if the source IP address is a broadcast or */
+		/* multicast IP address */
+                if(chk_bcast_mcast_addr(card, dev, skb))
+                        return 0;
+        }
+
+	/* Lock the 508 Card: SMP is supported */
+      	if(card->hw.type != SDLA_S514){
+		s508_lock(card,&smp_flags);
+	} 
+
+    	if(test_and_set_bit(0, (void*)&card->wandev.critical)) {
+	
+		printk(KERN_INFO "%s: Critical in if_send: %x\n",
+					card->wandev.name,card->wandev.critical);
+                ++card->wandev.stats.tx_dropped;
+#ifdef LINUX_2_1
+    		dev_kfree_skb(skb);
+#else
+                dev_kfree_skb(skb, FREE_WRITE);
+#endif	
+		if(card->hw.type != SDLA_S514){
+			s508_unlock(card,&smp_flags);
+		}
+		return 0;
+	}
+
+	if(card->u.c.state != WAN_CONNECTED)
+       		++card->wandev.stats.tx_dropped;
+
+	else if(!skb->protocol)
+        	++card->wandev.stats.tx_errors;
+
+	else {
+		void* data = skb->data;
+		unsigned len = skb->len;
+		unsigned char attr;
+
+		/* If it's an API packet pull off the API
+		 * header. Also check that the packet size
+		 * is larger than the API header
+	         */
+		if (card->u.c.usedby == API){
+			api_tx_hdr_t* api_tx_hdr;
+
+			if (len <= sizeof(api_tx_hdr_t)){
+#ifdef LINUX_2_1
+ 		               	dev_kfree_skb(skb);
+#else
+                		dev_kfree_skb(skb, FREE_WRITE);
+#endif
+				++card->wandev.stats.tx_dropped;
+				clear_bit(0, (void*)&card->wandev.critical);
+				if(card->hw.type != SDLA_S514){
+					s508_unlock(card,&smp_flags);
+				}
+                		return 0;
+			}
+				
+			api_tx_hdr = (api_tx_hdr_t *)data;
+			attr = api_tx_hdr->attr;
+			data += sizeof(api_tx_hdr_t);
+			len -= sizeof(api_tx_hdr_t);
+		}
+
+		if(chdlc_send(card, data, len)) {
+			dev->tbusy = 1;
+			chdlc_priv_area->tick_counter = jiffies;
+			chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME;
+		}
+		else {
+			++card->wandev.stats.tx_packets;
+#ifdef LINUX_2_1
+                        card->wandev.stats.tx_bytes += len;
+#endif
+		}	
+	}
+
+	if (!dev->tbusy) {
+#ifdef LINUX_2_1
+		dev_kfree_skb(skb);
+#else
+                dev_kfree_skb(skb, FREE_WRITE);
+#endif
+	}
+
+	clear_bit(0, (void*)&card->wandev.critical);
+	if(card->hw.type != SDLA_S514){
+		s508_unlock(card,&smp_flags);
+	}
+	return dev->tbusy;
+}
+
+
+/*============================================================================
+ * Check to see if the packet to be transmitted contains a broadcast or
+ * multicast source IP address.
+ */
+
+static int chk_bcast_mcast_addr(sdla_t *card, struct device* dev,
+				struct sk_buff *skb)
+{
+	u32 src_ip_addr;
+        u32 broadcast_ip_addr = 0;
+#ifdef LINUX_2_1
+        struct in_device *in_dev;
+#endif
+        /* read the IP source address from the outgoing packet */
+        src_ip_addr = *(u32 *)(skb->data + 12);
+
+	/* read the IP broadcast address for the device */
+#ifdef LINUX_2_1
+        in_dev = dev->ip_ptr;
+        if(in_dev != NULL) {
+                struct in_ifaddr *ifa= in_dev->ifa_list;
+                if(ifa != NULL)
+                        broadcast_ip_addr = ifa->ifa_broadcast;
+                else
+                        return 0;
+        }
+#else
+        broadcast_ip_addr = dev->pa_brdaddr;
+#endif
+ 
+        /* check if the IP Source Address is a Broadcast address */
+        if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) {
+                printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n",
+				card->devname);
+#ifdef LINUX_2_1
+                dev_kfree_skb(skb);
+#else
+                dev_kfree_skb(skb, FREE_WRITE);
+#endif
+                ++card->wandev.stats.tx_dropped;
+                return 1;
+        } 
+
+        /* check if the IP Source Address is a Multicast address */
+        if((ntohl(src_ip_addr) >= 0xE0000001) &&
+		(ntohl(src_ip_addr) <= 0xFFFFFFFE)) {
+                printk(KERN_INFO "%s: Multicast Source Address silently discarded\n",
+				card->devname);
+#ifdef LINUX_2_1
+                dev_kfree_skb(skb);
+#else
+                dev_kfree_skb(skb, FREE_WRITE);
+#endif
+                ++card->wandev.stats.tx_dropped;
+                return 1;
+        }
+
+        return 0;
+}
+
+
+/*============================================================================
+ * Reply to UDP Management system.
+ * Return length of reply.
+ */
+static int reply_udp( unsigned char *data, unsigned int mbox_len )
+{
+
+	unsigned short len, udp_length, temp, ip_length;
+	unsigned long ip_temp;
+	int even_bound = 0;
+  	chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data;
+	 
+	/* Set length of packet */
+	len = sizeof(ip_pkt_t)+ 
+	      sizeof(udp_pkt_t)+
+	      sizeof(wp_mgmt_t)+
+	      sizeof(cblock_t)+
+	      sizeof(trace_info_t)+ 
+	      mbox_len;
+
+	/* fill in UDP reply */
+	c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY;
+   
+	/* fill in UDP length */
+	udp_length = sizeof(udp_pkt_t)+ 
+		     sizeof(wp_mgmt_t)+
+		     sizeof(cblock_t)+
+	             sizeof(trace_info_t)+
+		     mbox_len; 
+
+ 	/* put it on an even boundary */
+	if ( udp_length & 0x0001 ) {
+		udp_length += 1;
+		len += 1;
+		even_bound = 1;
+	}  
+
+	temp = (udp_length<<8)|(udp_length>>8);
+	c_udp_pkt->udp_pkt.udp_length = temp;
+		 
+	/* swap UDP ports */
+	temp = c_udp_pkt->udp_pkt.udp_src_port;
+	c_udp_pkt->udp_pkt.udp_src_port = 
+			c_udp_pkt->udp_pkt.udp_dst_port; 
+	c_udp_pkt->udp_pkt.udp_dst_port = temp;
+
+	/* add UDP pseudo header */
+	temp = 0x1100;
+	*((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp;	
+	temp = (udp_length<<8)|(udp_length>>8);
+	*((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp;
+
+		 
+	/* calculate UDP checksum */
+	c_udp_pkt->udp_pkt.udp_checksum = 0;
+	c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET);
+
+	/* fill in IP length */
+	ip_length = len;
+	temp = (ip_length<<8)|(ip_length>>8);
+	c_udp_pkt->ip_pkt.total_length = temp;
+  
+	/* swap IP addresses */
+	ip_temp = c_udp_pkt->ip_pkt.ip_src_address;
+	c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address;
+	c_udp_pkt->ip_pkt.ip_dst_address = ip_temp;
+
+	/* fill in IP checksum */
+	c_udp_pkt->ip_pkt.hdr_checksum = 0;
+	c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t));
+
+	return len;
+
+} /* reply_udp */
+
+unsigned short calc_checksum (char *data, int len)
+{
+	unsigned short temp; 
+	unsigned long sum=0;
+	int i;
+
+	for( i = 0; i <len; i+=2 ) {
+		memcpy(&temp,&data[i],2);
+		sum += (unsigned long)temp;
+	}
+
+	while (sum >> 16 ) {
+		sum = (sum & 0xffffUL) + (sum >> 16);
+	}
+
+	temp = (unsigned short)sum;
+	temp = ~temp;
+
+	if( temp == 0 ) 
+		temp = 0xffff;
+
+	return temp;	
+}
+
+
+/*============================================================================
+ * Get ethernet-style interface statistics.
+ * Return a pointer to struct enet_statistics.
+ */
+#ifdef LINUX_2_1
+static struct net_device_stats* if_stats (struct device* dev)
+{
+	sdla_t *my_card;
+	chdlc_private_area_t* chdlc_priv_area = dev->priv;
+
+	my_card = chdlc_priv_area->card;
+	return &my_card->wandev.stats; 
+}
+#else
+static struct enet_statistics* if_stats (struct device* dev)
+{
+        sdla_t *my_card;
+        chdlc_private_area_t* chdlc_priv_area = dev->priv;
+
+        my_card = chdlc_priv_area->card;
+        return &my_card->wandev.stats;
+}
+#endif
+
+/****** Cisco HDLC Firmware Interface Functions *******************************/
+
+/*============================================================================
+ * Read firmware code version.
+ *	Put code version as ASCII string in str. 
+ */
+static int chdlc_read_version (sdla_t* card, char* str)
+{
+	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+	int len;
+	char err;
+	mb->buffer_length = 0;
+	mb->command = READ_CHDLC_CODE_VERSION;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+
+	if(err != COMMAND_OK) {
+		chdlc_error(card,err,mb);
+	}
+	else if (str) {  /* is not null */
+		len = mb->buffer_length;
+		memcpy(str, mb->data, len);
+		str[len] = '\0';
+	}
+	return (err);
+}
+
+/*-----------------------------------------------------------------------------
+ *  Configure CHDLC firmware.
+ */
+static int chdlc_configure (sdla_t* card, void* data)
+{
+	int err;
+	CHDLC_MAILBOX_STRUCT *mailbox = card->mbox;
+	int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT);
+	
+	mailbox->buffer_length = data_length;  
+	memcpy(mailbox->data, data, data_length);
+	mailbox->command = SET_CHDLC_CONFIGURATION;
+	err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT;
+	
+	if (err != COMMAND_OK) chdlc_error (card, err, mailbox);
+                           
+	return err;
+}
+
+
+/*============================================================================
+ * Set interrupt mode -- HDLC Version.
+ */
+
+static int chdlc_set_intr_mode (sdla_t* card, unsigned mode)
+{
+	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+	CHDLC_INT_TRIGGERS_STRUCT* int_data =
+		 (CHDLC_INT_TRIGGERS_STRUCT *)mb->data;
+	int err;
+
+	int_data->CHDLC_interrupt_triggers 	= mode;
+	int_data->IRQ				= card->hw.irq;
+	int_data->interrupt_timer               = 1;
+   
+	mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT);
+	mb->command = SET_CHDLC_INTERRUPT_TRIGGERS;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+	if (err != COMMAND_OK)
+		chdlc_error (card, err, mb);
+	return err;
+}
+
+
+/*============================================================================
+ * Enable communications.
+ */
+
+static int chdlc_comm_enable (sdla_t* card)
+{
+	int err;
+	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+
+	mb->buffer_length = 0;
+	mb->command = ENABLE_CHDLC_COMMUNICATIONS;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+	if (err != COMMAND_OK)
+		chdlc_error(card, err, mb);
+	return err;
+}
+
+/*============================================================================
+ * Disable communications and Drop the Modem lines (DCD and RTS).
+ */
+static int chdlc_comm_disable (sdla_t* card)
+{
+	int err;
+	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+
+	mb->buffer_length = 0;
+	mb->command = DISABLE_CHDLC_COMMUNICATIONS;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+	if (err != COMMAND_OK)
+		chdlc_error(card,err,mb);
+
+	mb->command = SET_MODEM_STATUS;
+	mb->buffer_length = 1;
+	mb->data[0] = 0;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+	if (err != COMMAND_OK)
+		chdlc_error(card,err,mb);
+
+	return err;
+}
+
+/*============================================================================
+ * Read communication error statistics.
+ */
+static int chdlc_read_comm_err_stats (sdla_t* card)
+{
+        int err;
+        CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+
+        mb->buffer_length = 0;
+        mb->command = READ_COMMS_ERROR_STATS;
+        err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+        if (err != COMMAND_OK)
+                chdlc_error(card,err,mb);
+        return err;
+}
+
+
+/*============================================================================
+ * Read CHDLC operational statistics.
+ */
+static int chdlc_read_op_stats (sdla_t* card)
+{
+        int err;
+        CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+
+        mb->buffer_length = 0;
+        mb->command = READ_CHDLC_OPERATIONAL_STATS;
+        err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+        if (err != COMMAND_OK)
+                chdlc_error(card,err,mb);
+        return err;
+}
+
+
+/*============================================================================
+ * Update communications error and general packet statistics.
+ */
+static int update_comms_stats(sdla_t* card,
+	chdlc_private_area_t* chdlc_priv_area)
+{
+        CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+  	COMMS_ERROR_STATS_STRUCT* err_stats;
+        CHDLC_OPERATIONAL_STATS_STRUCT *op_stats;
+
+	/* on the first timer interrupt, read the comms error statistics */
+	if(chdlc_priv_area->update_comms_stats == 2) {
+		if(chdlc_read_comm_err_stats(card))
+			return 1;
+		err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data;
+		card->wandev.stats.rx_over_errors = 
+				err_stats->Rx_overrun_err_count;
+		card->wandev.stats.rx_crc_errors = 
+				err_stats->CRC_err_count;
+		card->wandev.stats.rx_frame_errors = 
+				err_stats->Rx_abort_count;
+		card->wandev.stats.rx_fifo_errors = 
+				err_stats->Rx_dis_pri_bfrs_full_count; 
+		card->wandev.stats.rx_missed_errors =
+				card->wandev.stats.rx_fifo_errors;
+		card->wandev.stats.tx_aborted_errors =
+				err_stats->sec_Tx_abort_count;
+	}
+
+        /* on the second timer interrupt, read the operational statistics */
+	else {
+        	if(chdlc_read_op_stats(card))
+                	return 1;
+		op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data;
+		card->wandev.stats.rx_length_errors =
+			(op_stats->Rx_Data_discard_short_count +
+			op_stats->Rx_Data_discard_long_count);
+	}
+
+	return 0;
+}
+
+/*============================================================================
+ * Send packet.
+ *	Return:	0 - o.k.
+ *		1 - no transmit buffers available
+ */
+static int chdlc_send (sdla_t* card, void* data, unsigned len)
+{
+	CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf;
+
+	if (txbuf->opp_flag)
+		return 1;
+	
+	sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len);
+
+	txbuf->frame_length = len;
+	txbuf->opp_flag = 1;		/* start transmission */
+	
+	/* Update transmit buffer control fields */
+	card->u.c.txbuf = ++txbuf;
+
+	if ((void*)txbuf > card->u.c.txbuf_last)
+		card->u.c.txbuf = card->u.c.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 chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb)
+{
+	unsigned cmd = mb->command;
+
+	switch (err) {
+
+	case CMD_TIMEOUT:
+		printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+			card->devname, cmd);
+		break;
+
+	case S514_BOTH_PORTS_SAME_CLK_MODE:
+		if(cmd == SET_CHDLC_CONFIGURATION) {
+			printk(KERN_INFO
+			 "%s: Configure both ports for the same clock source\n",
+				card->devname);
+			break;
+		}
+
+	default:
+		printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
+			card->devname, cmd, err);
+	}
+
+	return 0;
+}
+
+/****** Interrupt Handlers **************************************************/
+
+/*============================================================================
+ * Cisco HDLC interrupt service routine.
+ */
+STATIC void wpc_isr (sdla_t* card)
+{
+	struct device* dev;
+	chdlc_private_area_t* chdlc_priv_area;
+	SHARED_MEMORY_INFO_STRUCT* flags = NULL;
+	int i, interrupt_serviced = 0;
+	sdla_t *my_card;
+
+
+	/* Check for which port the interrupt has been generated
+	 * Since Secondary Port is piggybacking on the Primary
+         * the check must be done here. 
+	 */
+
+	flags = card->u.c.flags;
+	if (!flags->interrupt_info_struct.interrupt_type){
+		/* Check for a second port (piggybacking) */
+		if((my_card = card->next)){
+			flags = my_card->u.c.flags;
+			if (flags->interrupt_info_struct.interrupt_type){
+				card = my_card;
+			}
+		}
+	}
+
+	dev = card->wandev.dev;
+	
+	card->in_isr = 1;
+	
+	/* if critical due to peripheral operations
+	 * ie. update() or getstats() then reset the interrupt and
+	 * wait for the board to retrigger.
+	 */
+	if(test_bit(1, (void*)&card->wandev.critical)) {
+               	if(card->u.c.flags != NULL) {
+                       	flags = card->u.c.flags;
+			if(flags->interrupt_info_struct.
+					interrupt_type) {
+					flags->interrupt_info_struct.
+						interrupt_type = 0;
+			}
+		}
+		card->in_isr = 0;
+		return;
+	}
+
+
+	/* On a 508 Card, if critical due to if_send 
+         * Major Error !!!
+	 */
+	if(card->hw.type != SDLA_S514) {
+		if(test_and_set_bit(0, (void*)&card->wandev.critical)) {
+			printk(KERN_INFO "%s: Critical while in ISR: %x\n",
+				card->devname, card->wandev.critical);
+			card->in_isr = 0;
+			return;
+		}
+	}
+
+	/* FIXME: Take this check out later in the future */
+	if(card->u.c.flags != NULL) {
+	
+		flags = card->u.c.flags;
+
+		switch(flags->interrupt_info_struct.interrupt_type) {
+
+		case RX_APP_INT_PEND:	/* 0x01: receive interrupt */
+			interrupt_serviced = 1;
+			rx_intr(card);
+			break;
+
+		case TX_APP_INT_PEND:	/* 0x02: transmit interrupt */
+			interrupt_serviced = 1;
+			flags->interrupt_info_struct.interrupt_permission &=
+				 ~APP_INT_ON_TX_FRAME;
+
+			chdlc_priv_area = dev->priv;
+			dev->tbusy = 0;	
+			mark_bh(NET_BH);
+			break;
+
+		case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */
+			interrupt_serviced = 1;
+			++ Intr_test_counter;
+			break;
+
+		case CHDLC_EXCEP_COND_APP_INT_PEND:	/* 0x20 */
+			interrupt_serviced = 1;
+			process_chdlc_exception(card);
+			break;
+
+		case GLOBAL_EXCEP_COND_APP_INT_PEND:
+			interrupt_serviced = 1;
+			process_global_exception(card);
+			break;
+
+		case TIMER_APP_INT_PEND:
+			interrupt_serviced = 1;
+			timer_intr(card);
+			break;
+
+		default:
+			break;
+		}	
+	}
+
+	if(!interrupt_serviced) {
+		printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", 
+			card->devname,
+			flags->interrupt_info_struct.interrupt_type);
+		printk(KERN_INFO "Code name: ");
+		for(i = 0; i < 4; i ++)
+			printk(KERN_INFO "%c",
+				flags->global_info_struct.codename[i]); 
+		printk(KERN_INFO "\nCode version: ");
+	 	for(i = 0; i < 4; i ++)
+			printk(KERN_INFO "%c", 
+				flags->global_info_struct.codeversion[i]); 
+		printk(KERN_INFO "\n");	
+	}
+
+	card->in_isr = 0;
+	flags->interrupt_info_struct.interrupt_type = 0;
+        if(card->hw.type != SDLA_S514){
+        	clear_bit(0, (void*)&card->wandev.critical);
+	}
+        
+}
+
+/*============================================================================
+ * Receive interrupt handler.
+ */
+static void rx_intr (sdla_t* card)
+{
+	struct device 			*dev;
+	chdlc_private_area_t		*chdlc_priv_area;
+	SHARED_MEMORY_INFO_STRUCT 	*flags = card->u.c.flags;
+	CHDLC_DATA_RX_STATUS_EL_STRUCT	*rxbuf = card->u.c.rxmb;
+	struct sk_buff			*skb;
+	unsigned 			len;
+	void				*buf;
+	int 				i,udp_type;
+	
+	if (rxbuf->opp_flag != 0x01) {
+		printk(KERN_INFO 
+			"%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", 
+			card->devname, (unsigned)rxbuf, rxbuf->opp_flag);
+                printk(KERN_INFO "Code name: ");
+                for(i = 0; i < 4; i ++)
+                        printk(KERN_INFO "%c",
+                                flags->global_info_struct.codename[i]);
+                printk(KERN_INFO "\nCode version: ");
+                for(i = 0; i < 4; i ++)
+                        printk(KERN_INFO "%c",
+                                flags->global_info_struct.codeversion[i]);
+                printk(KERN_INFO "\n");
+		return;
+	}
+
+	dev = card->wandev.dev;
+	chdlc_priv_area = dev->priv;
+
+	if(dev && dev->start) {
+
+		len  = rxbuf->frame_length;
+
+		/* Allocate socket buffer */
+		skb = dev_alloc_skb(len);
+
+		if (skb != NULL) {
+			/* Copy data to the socket buffer */
+			unsigned addr = rxbuf->ptr_data_bfr;
+		
+			if((addr + len) >
+			card->u.c.rx_top + 1) {
+				unsigned tmp = 
+				card->u.c.rx_top - addr + 1;
+				buf = skb_put(skb, tmp);
+				sdla_peek(&card->hw, addr, buf, tmp);
+				addr = card->u.c.rx_base;
+				len -= tmp;
+			}
+		
+			buf = skb_put(skb, len);
+			sdla_peek(&card->hw, addr, buf, len);
+
+			/* Decapsulate packet */
+			skb->protocol = htons(ETH_P_IP);
+
+			card->wandev.stats.rx_packets ++;
+#ifdef LINUX_2_1
+			card->wandev.stats.rx_bytes += skb->len;
+#endif
+			udp_type = udp_pkt_type( skb, card );
+
+			if(udp_type == UDP_CPIPE_TYPE) {
+				if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK,
+					card, skb, dev, chdlc_priv_area)) {
+       				        flags->interrupt_info_struct.
+						interrupt_permission |= 
+							APP_INT_ON_TIMER; 
+				}
+
+			} else {
+ 
+				if(card->u.c.usedby == API) {
+					api_rx_hdr_t* api_rx_hdr;
+              				skb_push(skb, sizeof(api_rx_hdr_t));
+                                        api_rx_hdr =
+						(api_rx_hdr_t*)&skb->data[0x00];
+					api_rx_hdr->error_flag =
+						rxbuf->error_flag;
+          				api_rx_hdr->time_stamp =
+                                                rxbuf->time_stamp;
+                                	skb->protocol = htons(0x16);
+                                	skb->pkt_type = PACKET_HOST;
+				}
+
+/* FIXME: we should check to see if the received packet is a multicast packet so that we can increment the multicast statistic
+                                ++ chdlc_priv_area->if_stats.multicast;
+*/
+                               	/* Pass it up the protocol stack */
+                                skb->dev = dev;
+                                skb->mac.raw  = skb->data;
+                                netif_rx(skb);
+			}
+
+		} else {
+			printk(KERN_INFO
+				"%s: no socket buffers available!\n",
+					card->devname);
+			++card->wandev.stats.rx_dropped;
+		}
+     	}
+
+	/* Release buffer element and calculate a pointer to the next one */
+	rxbuf->opp_flag = 0x00;
+	card->u.c.rxmb = ++ rxbuf;
+	if((void*)rxbuf > card->u.c.rxbuf_last)
+		card->u.c.rxmb = card->u.c.rxbuf_base;
+}
+
+/*============================================================================
+ * Timer interrupt handler.
+ * The timer interrupt is used for two purposes:
+ *    1) Processing udp calls from 'cpipemon'.
+ *    2) Reading board-level statistics for updating the proc file system.
+ */
+void timer_intr(sdla_t *card)
+{
+        struct device* dev;
+        chdlc_private_area_t* chdlc_priv_area = NULL;
+        SHARED_MEMORY_INFO_STRUCT* flags = NULL;
+
+        dev = card->wandev.dev; 
+        chdlc_priv_area = dev->priv;
+
+	/* process a udp call if pending */
+       	if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) {
+               	process_udp_mgmt_pkt(card, dev,
+                       chdlc_priv_area);
+		chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP;
+        }
+
+	/* read the communications statistics if required */
+	if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) {
+		update_comms_stats(card, chdlc_priv_area);
+                if(!(-- chdlc_priv_area->update_comms_stats)) {
+			chdlc_priv_area->timer_int_enabled &= 
+				~TMR_INT_ENABLED_UPDATE;
+		}
+        }
+
+	/* only disable the timer interrupt if there are no udp or statistic */
+	/* updates pending */
+        if(!chdlc_priv_area->timer_int_enabled) {
+                flags = card->u.c.flags;
+                flags->interrupt_info_struct.interrupt_permission &=
+                        ~APP_INT_ON_TIMER;
+        }
+}
+
+/*------------------------------------------------------------------------------
+  Miscellaneous Functions
+	- set_chdlc_config() used to set configuration options on the board
+------------------------------------------------------------------------------*/
+
+static int set_chdlc_config(sdla_t* card)
+{
+
+	struct device * dev = card->wandev.dev;
+	chdlc_private_area_t *chdlc_priv_area = dev->priv;
+	CHDLC_CONFIGURATION_STRUCT cfg;
+
+	memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT));
+
+	if(card->wandev.clocking)
+		cfg.baud_rate = card->wandev.bps;
+
+	cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ?
+		INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35;
+
+	cfg.modem_config_options	= 0;
+	cfg.modem_status_timer		= 100;
+
+	cfg.CHDLC_protocol_options	= card->u.c.protocol_options;
+	cfg.percent_data_buffer_for_Tx	= 50;
+	cfg.CHDLC_statistics_options	= (CHDLC_TX_DATA_BYTE_COUNT_STAT |
+		CHDLC_RX_DATA_BYTE_COUNT_STAT);
+	cfg.max_CHDLC_data_field_length	= card->wandev.mtu;
+	cfg.transmit_keepalive_timer	= card->u.c.kpalv_tx;
+	cfg.receive_keepalive_timer	= card->u.c.kpalv_rx;
+	cfg.keepalive_error_tolerance	= card->u.c.kpalv_err;
+	cfg.SLARP_request_timer		= card->u.c.slarp_timer;
+
+	if (cfg.SLARP_request_timer) {
+		cfg.IP_address		= 0;
+		cfg.IP_netmask		= 0;
+	}
+	else {
+#ifdef LINUX_2_1
+                struct in_device *in_dev = dev->ip_ptr;
+
+		if(in_dev != NULL) {
+			struct in_ifaddr *ifa = in_dev->ifa_list;
+
+			if (ifa != NULL ) {
+				cfg.IP_address	= ntohl(ifa->ifa_local);
+				cfg.IP_netmask	= ntohl(ifa->ifa_mask); 
+				chdlc_priv_area->IP_address = 
+					ntohl(ifa->ifa_local);
+				chdlc_priv_area->IP_netmask =
+					ntohl(ifa->ifa_mask); 
+			}
+		}
+#else
+                cfg.IP_address          = ntohl(dev->pa_addr);
+                cfg.IP_netmask          = ntohl(dev->pa_mask);
+		chdlc_priv_area->IP_address = ntohl(dev->pa_addr);
+		chdlc_priv_area->IP_netmask = ntohl(dev->pa_mask);
+#endif
+
+		/* FIXME: We must re-think this message in next release
+		if((cfg.IP_address & 0x000000FF) > 2) {
+			printk(KERN_WARNING "\n");
+	                printk(KERN_WARNING "  WARNING:%s configured with an\n",
+				card->devname);
+			printk(KERN_WARNING "  invalid local IP address.\n");
+                        printk(KERN_WARNING "  Slarp pragmatics will fail.\n");
+                        printk(KERN_WARNING "  IP address should be of the\n");
+			printk(KERN_WARNING "  format A.B.C.1 or A.B.C.2.\n");
+		}
+		*/		
+	}
+	
+	return chdlc_configure(card, &cfg);
+}
+
+
+
+/*============================================================================
+ * Process global exception condition
+ */
+static int process_global_exception(sdla_t *card)
+{
+	CHDLC_MAILBOX_STRUCT* mbox = card->mbox;
+	int err;
+
+	mbox->buffer_length = 0;
+	mbox->command = READ_GLOBAL_EXCEPTION_CONDITION;
+	err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT;
+
+	if(err != CMD_TIMEOUT ){
+	
+		switch(mbox->return_code) {
+         
+	      	case EXCEP_MODEM_STATUS_CHANGE:
+
+			printk(KERN_INFO "%s: Modem status change\n",
+				card->devname);
+
+			switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) {
+				case (DCD_HIGH):
+					printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname);
+					break;
+				case (CTS_HIGH):
+                                        printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname);                                        break;
+                                case ((DCD_HIGH | CTS_HIGH)):
+                                        printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname);
+                                        break;
+				default:
+                                        printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname);
+                                        break;
+			}
+			break;
+
+                case EXCEP_TRC_DISABLED:
+                        printk(KERN_INFO "%s: Line trace disabled\n",
+				card->devname);
+                        break;
+
+		case EXCEP_IRQ_TIMEOUT:
+			printk(KERN_INFO "%s: IRQ timeout occurred\n",
+				card->devname); 
+			break;
+
+                default:
+                        printk(KERN_INFO "%s: Global exception %x\n",
+				card->devname, mbox->return_code);
+                        break;
+                }
+	}
+	return 0;
+}
+
+
+/*============================================================================
+ * Process chdlc exception condition
+ */
+static int process_chdlc_exception(sdla_t *card)
+{
+	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+	int err;
+
+	mb->buffer_length = 0;
+	mb->command = READ_CHDLC_EXCEPTION_CONDITION;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+	if(err != CMD_TIMEOUT) {
+	
+		switch (err) {
+
+		case EXCEP_LINK_ACTIVE:
+			port_set_state(card, WAN_CONNECTED);
+			break;
+
+		case EXCEP_LINK_INACTIVE_MODEM:
+			port_set_state(card, WAN_DISCONNECTED);
+			unconfigure_ip(card);
+			break;
+
+		case EXCEP_LINK_INACTIVE_KPALV:
+			port_set_state(card, WAN_DISCONNECTED);
+			printk(KERN_INFO "%s: Keepalive timer expired.\n",
+				 		card->devname);
+			unconfigure_ip(card);
+			break;
+
+		case EXCEP_IP_ADDRESS_DISCOVERED:
+			if (configure_ip(card)) 
+				return -1;
+			break;
+
+		case EXCEP_LOOPBACK_CONDITION:
+			printk(KERN_INFO "%s: Loopback Condition Detected.\n",
+						card->devname);
+			break;
+
+		case NO_CHDLC_EXCEP_COND_TO_REPORT:
+			printk(KERN_INFO "%s: No exceptions reported.\n",
+						card->devname);
+			break;
+		}
+
+	}
+	return 0;
+}
+
+
+/*============================================================================
+ * Configure IP from SLARP negotiation
+ * This adds dynamic routes when SLARP has provided valid addresses
+ */
+
+static int configure_ip (sdla_t* card)
+{
+	struct device *dev = card->wandev.dev;
+        chdlc_private_area_t *chdlc_priv_area = dev->priv;
+        char err;
+
+        /* set to discover */
+        if(card->u.c.slarp_timer != 0x00) {
+		CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+		CHDLC_CONFIGURATION_STRUCT *cfg;
+
+     		mb->buffer_length = 0;
+		mb->command = READ_CHDLC_CONFIGURATION;
+		err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+	
+		if(err != COMMAND_OK) {
+			chdlc_error(card,err,mb);
+			return -1;
+		}
+
+		cfg = (CHDLC_CONFIGURATION_STRUCT *)mb->data;
+                chdlc_priv_area->IP_address = cfg->IP_address;
+                chdlc_priv_area->IP_netmask = cfg->IP_netmask;
+        }
+
+	/* Set flag to add route */
+	chdlc_priv_area->route_status = ADD_ROUTE;
+
+	/* The idea here is to add the route in the poll routine.
+	   This way, we aren't in interrupt context when adding routes */
+	card->poll = process_route;
+
+	return 0;
+}
+
+
+/*============================================================================
+ * Un-Configure IP negotiated by SLARP
+ * This removes dynamic routes when the link becomes inactive.
+ */
+
+static int unconfigure_ip (sdla_t* card)
+{
+	struct device *dev = card->wandev.dev;
+	chdlc_private_area_t *chdlc_priv_area= dev->priv;
+
+	if (chdlc_priv_area->route_status == ROUTE_ADDED) {
+	      	chdlc_priv_area->route_status = REMOVE_ROUTE;
+		/* The idea here is to delete the route in 
+		 * the poll routine.
+	   	 * This way, we aren't in interrupt context 
+		 * when adding routes 
+		 */
+                card->poll = process_route;
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Routine to add/remove routes 
+ * Called like a polling routine when Routes are flagged to be added/removed.
+ */
+
+static void process_route (sdla_t *card)
+{
+        struct device *dev = card->wandev.dev;
+        unsigned char port_num;
+        chdlc_private_area_t *chdlc_priv_area = NULL;
+	u32 local_IP_addr = 0;
+	u32 remote_IP_addr = 0;
+	u32 IP_netmask, IP_addr;
+        int err = 0;
+#ifdef LINUX_2_1
+	struct in_device *in_dev;
+	mm_segment_t fs;
+	struct ifreq if_info;
+        struct sockaddr_in *if_data1, *if_data2;
+#else
+	unsigned long fs = 0;
+        struct rtentry route;
+#endif
+	
+        chdlc_priv_area = dev->priv;
+        port_num = card->u.c.comm_port;
+
+	if((chdlc_priv_area->route_status == ADD_ROUTE) &&
+		((chdlc_priv_area->IP_address & 0x000000FF) > 2)) {
+		printk(KERN_INFO "%s: Dynamic route failure.\n",card->devname);
+                if(card->u.c.slarp_timer) {
+			printk(KERN_INFO "%s: Bad IP address %s received\n",
+				card->devname,
+				in_ntoa(ntohl(chdlc_priv_area->IP_address)));
+                        printk(KERN_INFO "%s: from remote station.\n",
+				card->devname);
+                }else{ 
+                        printk(KERN_INFO "%s: Bad IP address %s issued\n",
+				card->devname,
+				in_ntoa(ntohl(chdlc_priv_area->IP_address)));
+                        printk(KERN_INFO "%s: to remote station. Local\n",
+				card->devname);
+			printk(KERN_INFO "%s: IP address must be A.B.C.1\n",
+				card->devname);
+			printk(KERN_INFO "%s: or A.B.C.2.\n",card->devname);
+		}
+
+		/* remove the route due to the IP address error condition */
+		chdlc_priv_area->route_status = REMOVE_ROUTE;
+		err = 1;
+   	}
+
+	/* If we are removing a route with bad IP addressing, then use the */
+	/* locally configured IP addresses */
+        if((chdlc_priv_area->route_status == REMOVE_ROUTE) && err) {
+
+ 	        /* do not remove a bad route that has already been removed */
+        	if(chdlc_priv_area->route_removed) {
+                	card->poll = NULL;
+	                return;
+        	}
+
+#ifdef LINUX_2_1
+                in_dev = dev->ip_ptr;
+
+                if(in_dev != NULL) {
+                        struct in_ifaddr *ifa = in_dev->ifa_list;
+                        if (ifa != NULL ) {
+                                local_IP_addr = ifa->ifa_local;
+                                IP_netmask  = ifa->ifa_mask;
+                        }
+                }
+#else
+                local_IP_addr = dev->pa_addr;
+                remote_IP_addr = dev->pa_dstaddr;
+                IP_netmask = dev->pa_mask;
+#endif
+	}else{ 
+       		/* According to Cisco HDLC, if the point-to-point address is
+		   A.B.C.1, then we are the opposite (A.B.C.2), and vice-versa.
+		*/
+		IP_netmask = ntohl(chdlc_priv_area->IP_netmask);
+	        remote_IP_addr = ntohl(chdlc_priv_area->IP_address);
+        	local_IP_addr = (remote_IP_addr & ntohl(0xFFFFFF00)) +
+                	(~remote_IP_addr & ntohl(0x0003));
+
+	        if(!card->u.c.slarp_timer) {
+			IP_addr = local_IP_addr;
+			local_IP_addr = remote_IP_addr;
+			remote_IP_addr = IP_addr;
+       		}
+	}
+
+        fs = get_fs();                  /* Save file system  */
+        set_fs(get_ds());               /* Get user space block */
+
+#ifdef LINUX_2_1
+        /* Setup a structure for adding/removing routes */
+        memset(&if_info, 0, sizeof(if_info));
+        strcpy(if_info.ifr_name, dev->name);
+
+#else
+	/* Setup a structure for adding/removing routes */
+	dev->pa_mask = IP_netmask;
+	dev->pa_dstaddr = remote_IP_addr;
+	dev->pa_addr = local_IP_addr;
+
+	memset(&route, 0, sizeof(route));
+	route.rt_dev = dev->name;
+	route.rt_flags = 0;
+	((struct sockaddr_in *)&(route.rt_dst))->sin_addr.s_addr =
+			dev->pa_dstaddr;
+	((struct sockaddr_in *)&(route.rt_dst))->sin_family = AF_INET;
+	((struct sockaddr_in *)&(route.rt_genmask))->sin_addr.s_addr =
+			0xFFFFFFFF;
+        ((struct sockaddr_in *)&(route.rt_genmask))->sin_family =
+			AF_INET;
+#endif
+
+	switch (chdlc_priv_area->route_status) {
+
+	case ADD_ROUTE:
+
+		if(!card->u.c.slarp_timer) {
+#ifdef LINUX_2_1
+			if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr;
+			if_data2->sin_addr.s_addr = remote_IP_addr;
+			if_data2->sin_family = AF_INET;
+			err = devinet_ioctl(SIOCSIFDSTADDR, &if_info);
+#else
+                        err = ip_rt_new(&route);
+#endif
+		} else { 
+#ifdef LINUX_2_1
+			if_data1 = (struct sockaddr_in *)&if_info.ifr_addr;
+			if_data1->sin_addr.s_addr = local_IP_addr;
+			if_data1->sin_family = AF_INET;
+			if(!(err = devinet_ioctl(SIOCSIFADDR, &if_info))){
+				if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr;
+				if_data2->sin_addr.s_addr = remote_IP_addr;
+				if_data2->sin_family = AF_INET;
+				err = devinet_ioctl(SIOCSIFDSTADDR, &if_info);
+			}
+#else
+               		err = ip_rt_new(&route);
+#endif
+		}
+
+               if(err) {
+			printk(KERN_INFO "%s: Add route %s failed (%d)\n", 
+				card->devname, in_ntoa(remote_IP_addr), err);
+		} else {
+			((chdlc_private_area_t *)dev->priv)->route_status = ROUTE_ADDED;
+			printk(KERN_INFO "%s: Dynamic route added.\n",
+				card->devname);
+			printk(KERN_INFO "%s:    Local IP addr : %s\n",
+				card->devname, in_ntoa(local_IP_addr));
+			printk(KERN_INFO "%s:    Remote IP addr: %s\n",
+				card->devname, in_ntoa(remote_IP_addr));
+			chdlc_priv_area->route_removed = 0;
+		}
+		break;
+
+
+	case REMOVE_ROUTE:
+	
+#ifdef LINUX_2_1
+		/* Change the local ip address of the interface to 0.
+		 * This will also delete the destination route.
+		 */
+		if(!card->u.c.slarp_timer) {
+			if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr;
+			if_data2->sin_addr.s_addr = 0;
+			if_data2->sin_family = AF_INET;
+			err = devinet_ioctl(SIOCSIFDSTADDR, &if_info);
+		} else {
+			if_data1 = (struct sockaddr_in *)&if_info.ifr_addr;
+			if_data1->sin_addr.s_addr = 0;
+			if_data1->sin_family = AF_INET;
+			err = devinet_ioctl(SIOCSIFADDR,&if_info);
+		
+		}
+#else
+		/* set the point-to-point IP address to 0.0.0.0 */
+		dev->pa_dstaddr = 0; 
+		err = ip_rt_kill(&route);
+#endif
+		if(err) {
+			printk(KERN_INFO
+				"%s: Remove route %s failed, (err %d)\n",
+					card->devname, in_ntoa(remote_IP_addr),
+					err);
+		} else {
+			((chdlc_private_area_t *)dev->priv)->route_status =
+				NO_ROUTE;
+                        printk(KERN_INFO "%s: Dynamic route removed: %s\n",
+                                        card->devname, in_ntoa(local_IP_addr)); 
+			chdlc_priv_area->route_removed = 1;
+		}
+		break;
+	}
+
+        set_fs(fs);                     /* Restore file system */
+
+        /* Once we've processed the route, stop polling */
+        card->poll = NULL;
+
+}
+
+
+/*=============================================================================
+ * Store a UDP management packet for later processing.
+ */
+
+static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
+                                struct sk_buff *skb, struct device* dev,
+                                chdlc_private_area_t* chdlc_priv_area )
+{
+	int udp_pkt_stored = 0;
+
+	if(!chdlc_priv_area->udp_pkt_lgth &&
+	  (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) {
+        	chdlc_priv_area->udp_pkt_lgth = skb->len;
+		chdlc_priv_area->udp_pkt_src = udp_pkt_src;
+       		memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len);
+		chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP;
+		udp_pkt_stored = 1;
+	}
+
+#ifdef LINUX_2_1
+	dev_kfree_skb(skb);
+#else
+	if(udp_pkt_src == UDP_PKT_FRM_STACK)
+		dev_kfree_skb(skb, FREE_WRITE);
+	else
+                dev_kfree_skb(skb, FREE_READ);
+#endif
+	
+	return(udp_pkt_stored);
+}
+
+
+/*=============================================================================
+ * Process UDP management packet.
+ */
+
+static int process_udp_mgmt_pkt(sdla_t* card, struct device* dev,
+				chdlc_private_area_t* chdlc_priv_area ) 
+{
+	unsigned char *buf;
+	unsigned int frames, len;
+	struct sk_buff *new_skb;
+	unsigned short buffer_length, real_len;
+	unsigned long data_ptr;
+	unsigned data_length;
+	int udp_mgmt_req_valid = 1;
+	CHDLC_MAILBOX_STRUCT *mb = card->mbox;
+	SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
+	chdlc_udp_pkt_t *chdlc_udp_pkt;
+	struct timeval tv;
+	int err;
+	char ut_char;
+
+	chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data;
+
+	switch(chdlc_udp_pkt->cblock.command) {
+
+	   	case FT1_MONITOR_STATUS_CTRL:
+		case CPIPE_ENABLE_TRACING:
+	   	case CPIPE_DISABLE_TRACING:
+ 	  	case CPIPE_GET_TRACE_INFO:
+	   	case SET_FT1_MODE:
+			if(chdlc_priv_area->udp_pkt_src == 
+				UDP_PKT_FRM_NETWORK) {
+			     udp_mgmt_req_valid = 0;
+       			}	 
+       			break;
+	   
+		default:
+       			break;
+  	} 
+	
+  	if(!udp_mgmt_req_valid) {
+
+		/* set length to 0 */
+		chdlc_udp_pkt->cblock.buffer_length = 0;
+
+    		/* set return code */
+		chdlc_udp_pkt->cblock.return_code = 0xCD;
+
+   	} else {
+	   	unsigned long trace_status_cfg_addr = 0;
+		TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct;
+		TRACE_STATUS_ELEMENT_STRUCT trace_element_struct;
+
+		switch(chdlc_udp_pkt->cblock.command) {
+
+		case CPIPE_ENABLE_TRACING:
+		     if (!chdlc_priv_area->TracingEnabled) {
+
+			/* OPERATE_DATALINE_MONITOR */
+
+			mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT);
+			mb->command = SET_TRACE_CONFIGURATION;
+
+    			((LINE_TRACE_CONFIG_STRUCT *)mb->data)->
+				trace_config = TRACE_ACTIVE;
+			/* Trace delay mode is not used because it slows
+			   down transfer and results in a standoff situation
+			   when there is a lot of data */
+
+			/* Configure the Trace based on user inputs */
+			((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |= 
+					chdlc_udp_pkt->data[0];
+
+			((LINE_TRACE_CONFIG_STRUCT *)mb->data)->
+			   trace_deactivation_timer = 4000;
+
+
+			err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+			if (err != COMMAND_OK) {
+				chdlc_error(card,err,mb);
+				card->TracingEnabled = 0;
+				chdlc_udp_pkt->cblock.return_code = err;
+				mb->buffer_length = 0;
+				break;
+	    		} 
+
+			/* Get the base address of the trace element list */
+			mb->buffer_length = 0;
+			mb->command = READ_TRACE_CONFIGURATION;
+			err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+
+			if (err != COMMAND_OK) {
+				chdlc_error(card,err,mb);
+				chdlc_priv_area->TracingEnabled = 0;
+				chdlc_udp_pkt->cblock.return_code = err;
+				mb->buffer_length = 0;
+				break;
+	    		} 	
+
+	   		trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *)
+				mb->data) -> ptr_trace_stat_el_cfg_struct;
+
+			sdla_peek(&card->hw, trace_status_cfg_addr,
+				 &trace_cfg_struct, sizeof(trace_cfg_struct));
+		    
+			chdlc_priv_area->start_trace_addr = trace_cfg_struct.
+				base_addr_trace_status_elements;
+
+			chdlc_priv_area->number_trace_elements = 
+					trace_cfg_struct.number_trace_status_elements;
+
+			chdlc_priv_area->end_trace_addr = (unsigned long)
+					((TRACE_STATUS_ELEMENT_STRUCT *)
+					 chdlc_priv_area->start_trace_addr + 
+					 (chdlc_priv_area->number_trace_elements - 1));
+
+			chdlc_priv_area->base_addr_trace_buffer = 
+					trace_cfg_struct.base_addr_trace_buffer;
+
+			chdlc_priv_area->end_addr_trace_buffer = 
+					trace_cfg_struct.end_addr_trace_buffer;
+
+		    	chdlc_priv_area->curr_trace_addr = 
+					trace_cfg_struct.next_trace_element_to_use;
+
+	    		chdlc_priv_area->available_buffer_space = 2000 - 
+								  sizeof(ip_pkt_t) -
+								  sizeof(udp_pkt_t) -
+							      	  sizeof(wp_mgmt_t) -
+								  sizeof(cblock_t) -
+							          sizeof(trace_info_t);	
+	       	     }
+		     chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
+		     mb->buffer_length = 0;
+	       	     chdlc_priv_area->TracingEnabled = 1;
+	       	     break;
+	   
+
+		case CPIPE_DISABLE_TRACING:
+		     if (chdlc_priv_area->TracingEnabled) {
+
+			/* OPERATE_DATALINE_MONITOR */
+			mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT);
+			mb->command = SET_TRACE_CONFIGURATION;
+    			((LINE_TRACE_CONFIG_STRUCT *)mb->data)->
+				trace_config = TRACE_INACTIVE;
+			err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+		     }		
+
+		     chdlc_priv_area->TracingEnabled = 0;
+		     chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
+		     mb->buffer_length = 0;
+		     break;
+	   
+
+		case CPIPE_GET_TRACE_INFO:
+
+		     if (!chdlc_priv_area->TracingEnabled) {
+			chdlc_udp_pkt->cblock.return_code = 1;
+			mb->buffer_length = 0;
+			break;
+		     }
+
+  		     chdlc_udp_pkt->trace_info.ismoredata = 0x00;
+		     buffer_length = 0;	/* offset of packet already occupied */
+
+		     for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){
+
+			trace_pkt_t *trace_pkt = (trace_pkt_t *)
+				&chdlc_udp_pkt->data[buffer_length];
+
+			sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr,
+			   	  (unsigned char *)&trace_element_struct,
+			   	  sizeof(TRACE_STATUS_ELEMENT_STRUCT));
+
+     			if (trace_element_struct.opp_flag == 0x00) {
+			 	break;
+			}
+
+			/* get pointer to real data */
+			data_ptr = trace_element_struct.ptr_data_bfr;
+
+			/* See if there is actual data on the trace buffer */
+			if (data_ptr){
+				data_length = trace_element_struct.trace_length;
+			}else{
+				data_length = 0;
+				chdlc_udp_pkt->trace_info.ismoredata = 0x01;
+			}
+	
+   			if( (chdlc_priv_area->available_buffer_space - buffer_length)
+				< ( sizeof(trace_pkt_t) + data_length) ) {
+
+                            /* indicate there are more frames on board & exit */
+				chdlc_udp_pkt->trace_info.ismoredata = 0x01;
+                               	break;
+                         }
+
+			trace_pkt->status = trace_element_struct.trace_type;
+
+			trace_pkt->time_stamp =
+				trace_element_struct.trace_time_stamp;
+
+			trace_pkt->real_length =
+				trace_element_struct.trace_length;
+
+			/* see if we can fit the frame into the user buffer */
+			real_len = trace_pkt->real_length;
+
+			if (data_ptr == 0) {
+			     	trace_pkt->data_avail = 0x00;
+			} else {
+				unsigned tmp = 0;
+
+				/* get the data from circular buffer
+				    must check for end of buffer */
+			        trace_pkt->data_avail = 0x01;
+
+				if ((data_ptr + real_len) >
+					     chdlc_priv_area->end_addr_trace_buffer + 1){
+
+				    	tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1;
+				    	sdla_peek(&card->hw, data_ptr,
+					       	  trace_pkt->data,tmp);
+				    	data_ptr = chdlc_priv_area->base_addr_trace_buffer;
+				}
+	
+		        	sdla_peek(&card->hw, data_ptr,
+					  &trace_pkt->data[tmp], real_len - tmp);
+			}	
+
+			/* zero the opp flag to show we got the frame */
+			ut_char = 0x00;
+			sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1);
+
+       			/* now move onto the next frame */
+       			chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT);
+
+       			/* check if we went over the last address */
+			if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) {
+				chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr;
+       			}
+
+            		if(trace_pkt->data_avail == 0x01) {
+				buffer_length += real_len - 1;
+			}
+	 
+	       	    	/* for the header */
+	            	buffer_length += sizeof(trace_pkt_t);
+
+		     }  /* For Loop */
+
+		     if (frames == chdlc_priv_area->number_trace_elements){
+			chdlc_udp_pkt->trace_info.ismoredata = 0x01;
+	             }
+ 		     chdlc_udp_pkt->trace_info.num_frames = frames;
+		 
+    		     mb->buffer_length = buffer_length;
+		     chdlc_udp_pkt->cblock.buffer_length = buffer_length; 
+		 
+		     chdlc_udp_pkt->cblock.return_code = COMMAND_OK; 
+		     
+		     break;
+
+
+		case CPIPE_FT1_READ_STATUS:
+			((unsigned char *)chdlc_udp_pkt->data )[0] =
+				flags->FT1_info_struct.parallel_port_A_input;
+
+			((unsigned char *)chdlc_udp_pkt->data )[1] =
+				flags->FT1_info_struct.parallel_port_B_input;
+				 
+			chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
+			mb->buffer_length = 2;
+			break;
+		
+		case CPIPE_ROUTER_UP_TIME:
+			do_gettimeofday( &tv );
+			chdlc_priv_area->router_up_time = tv.tv_sec - 
+					chdlc_priv_area->router_start_time;
+			*(unsigned long *)&chdlc_udp_pkt->data = 
+					chdlc_priv_area->router_up_time;	
+			mb->buffer_length = sizeof(unsigned long);
+			break;
+
+   		case FT1_MONITOR_STATUS_CTRL:
+			/* Enable FT1 MONITOR STATUS */
+	        	if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) ||  
+				(chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) {
+			
+			     	if( rCount++ != 0 ) {
+					chdlc_udp_pkt->cblock.
+					return_code = COMMAND_OK;
+					mb->buffer_length = 1;
+		  			break;
+		    	     	}
+	      		}
+
+	      		/* Disable FT1 MONITOR STATUS */
+	      		if( chdlc_udp_pkt->data[0] == 0) {
+
+	      	   	     	if( --rCount != 0) {
+		  			chdlc_udp_pkt->cblock.
+					return_code = COMMAND_OK;
+					mb->buffer_length = 1;
+		  			break;
+	   	    	     	} 
+	      		} 	
+	
+		default:
+			/* it's a board command */
+			mb->command = chdlc_udp_pkt->cblock.command;
+			mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length;
+			if (mb->buffer_length) {
+				memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt->
+							data, mb->buffer_length);
+	      		} 
+			/* run the command on the board */
+			err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+			if (err != COMMAND_OK) {
+				break;
+			}
+
+			/* copy the result back to our buffer */
+	         	memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t)); 
+			
+			if (mb->buffer_length) {
+	         		memcpy(&chdlc_udp_pkt->data, &mb->data, 
+								mb->buffer_length); 
+	      		}
+
+		} /* end of switch */
+     	} /* end of else */
+
+     	/* Fill UDP TTL */
+	chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl; 
+
+     	len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length);
+	
+     	if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+		if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) {
+			++ card->wandev.stats.tx_packets;
+#ifdef LINUX_2_1
+			card->wandev.stats.tx_bytes += len;
+#endif
+		}
+	} else {	
+	
+		/* Pass it up the stack
+    		   Allocate socket buffer */
+		if ((new_skb = dev_alloc_skb(len)) != NULL) {
+			/* copy data into new_skb */
+
+ 	    		buf = skb_put(new_skb, len);
+  	    		memcpy(buf, chdlc_priv_area->udp_pkt_data, len);
+
+            		/* Decapsulate pkt and pass it up the protocol stack */
+	    		new_skb->protocol = htons(ETH_P_IP);
+            		new_skb->dev = dev;
+	    		new_skb->mac.raw  = new_skb->data;
+	
+			netif_rx(new_skb);
+		} else {
+	    	
+			printk(KERN_INFO "%s: no socket buffers available!\n",
+					card->devname);
+  		}
+    	}
+ 
+	chdlc_priv_area->udp_pkt_lgth = 0;
+ 	
+	return 0;
+}
+
+/*============================================================================
+ * Initialize Receive and Transmit Buffers.
+ */
+
+static void init_chdlc_tx_rx_buff( sdla_t* card, struct device *dev )
+{
+	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+	CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config;
+	CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config;
+	char err;
+	
+	mb->buffer_length = 0;
+	mb->command = READ_CHDLC_CONFIGURATION;
+	err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+
+	if(err != COMMAND_OK) {
+		chdlc_error(card,err,mb);
+		return;
+	}
+
+	if(card->hw.type == SDLA_S514) {
+		tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase +
+                (((CHDLC_CONFIGURATION_STRUCT *)mb->data)->
+                            ptr_CHDLC_Tx_stat_el_cfg_struct));
+        	rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase +
+                (((CHDLC_CONFIGURATION_STRUCT *)mb->data)->
+                            ptr_CHDLC_Rx_stat_el_cfg_struct));
+
+       		/* Setup Head and Tails for buffers */
+        	card->u.c.txbuf_base = (void *)(card->hw.dpmbase +
+                tx_config->base_addr_Tx_status_elements);
+        	card->u.c.txbuf_last = 
+		(CHDLC_DATA_TX_STATUS_EL_STRUCT *)  
+                card->u.c.txbuf_base +
+		(tx_config->number_Tx_status_elements - 1);
+
+        	card->u.c.rxbuf_base = (void *)(card->hw.dpmbase +
+                rx_config->base_addr_Rx_status_elements);
+        	card->u.c.rxbuf_last =
+		(CHDLC_DATA_RX_STATUS_EL_STRUCT *)
+                card->u.c.rxbuf_base +
+		(rx_config->number_Rx_status_elements - 1);
+
+ 		/* Set up next pointer to be used */
+        	card->u.c.txbuf = (void *)(card->hw.dpmbase +
+                tx_config->next_Tx_status_element_to_use);
+        	card->u.c.rxmb = (void *)(card->hw.dpmbase +
+                rx_config->next_Rx_status_element_to_use);
+	}
+        else {
+                tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase +
+			(((CHDLC_CONFIGURATION_STRUCT *)mb->data)->
+			ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE));
+
+                rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase +
+			(((CHDLC_CONFIGURATION_STRUCT *)mb->data)->
+			ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE));
+
+                /* Setup Head and Tails for buffers */
+                card->u.c.txbuf_base = (void *)(card->hw.dpmbase +
+		(tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE));
+                card->u.c.txbuf_last =
+		(CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base
+		+ (tx_config->number_Tx_status_elements - 1);
+                card->u.c.rxbuf_base = (void *)(card->hw.dpmbase +
+		(rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE));
+                card->u.c.rxbuf_last = 
+		(CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base
+		+ (rx_config->number_Rx_status_elements - 1);
+
+                 /* Set up next pointer to be used */
+                card->u.c.txbuf = (void *)(card->hw.dpmbase +
+		(tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE));
+                card->u.c.rxmb = (void *)(card->hw.dpmbase +
+		(rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE));
+        }
+
+        /* Setup Actual Buffer Start and end addresses */
+        card->u.c.rx_base = rx_config->base_addr_Rx_buffer;
+        card->u.c.rx_top  = rx_config->end_addr_Rx_buffer;
+
+}
+
+/*=============================================================================
+ * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR
+ * _TEST_COUNTER times.
+ */
+static int intr_test( sdla_t* card, struct device *dev )
+{
+	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
+	int err,i;
+
+	Intr_test_counter = 0;
+
+	/* The critical flag is unset because during intialization (if_open) 
+	 * we want the interrupts to be enabled so that when the wpc_isr is
+	 * called it does not exit due to critical flag set.
+	 */ 
+
+	clear_bit(1, (void*)&card->wandev.critical);
+	err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE);
+
+	if (err == CMD_OK) { 
+		for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) {	
+			mb->buffer_length  = 0;
+			mb->command = READ_CHDLC_CODE_VERSION;
+			err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
+			if (err != CMD_OK) 
+				chdlc_error(card, err, mb);
+		}
+	}
+	else {
+		return err;
+	}
+
+	err = chdlc_set_intr_mode(card, 0);
+	set_bit(1, (void*)&card->wandev.critical);
+
+
+	if (err != CMD_OK)
+		return err;
+
+	return 0;
+}
+
+/*==============================================================================
+ * Determine what type of UDP call it is. CPIPEAB ?
+ */
+static int udp_pkt_type(struct sk_buff *skb, sdla_t* card)
+{
+	 chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data;
+
+	if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) &&
+	   (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) &&
+	   (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) &&
+	   (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) {
+		return UDP_CPIPE_TYPE;
+	}
+	else return UDP_INVALID_TYPE;
+}
+
+/*============================================================================
+ * Set PORT state.
+ */
+static void port_set_state (sdla_t *card, int state)
+{
+        if (card->u.c.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 = card->u.c.state = state;
+        }
+}
+
+void s508_lock (sdla_t *card, unsigned long *smp_flags)
+{
+#ifdef __SMP__
+                spin_lock_irqsave(&card->lock, *smp_flags);
+                if (card->next){
+                        spin_lock(&card->next->lock);
+                }
+#else
+                disable_irq(card->hw.irq);
+#endif                                                                     
+}
+
+void s508_unlock (sdla_t *card, unsigned long *smp_flags)
+{
+#ifdef __SMP__
+                        if (card->next){
+                                spin_unlock(&card->next->lock);
+                        }
+                        spin_unlock_irqrestore(&card->lock, *smp_flags);
+#else
+                        enable_irq(card->hw.irq);
+#endif           
+}
+
+/****** End ****************************************************************/
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_fr.c linux.14p16/drivers/net/sdla_fr.c
--- linux.vanilla/drivers/net/sdla_fr.c	Mon Jan  4 19:37:29 1999
+++ linux.14p16/drivers/net/sdla_fr.c	Wed Dec 15 16:23:52 1999
@@ -1,16 +1,38 @@
 /*****************************************************************************
 * sdla_fr.c	WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module.
 *
-* Author(s):	Gene Kozin	
-*		Jaspreet Singh		<jaspreet@sangoma.com>
+* Author(s):	Nenad Corbic  <ncorbic@sangoma.com>
+*		Gideon Hack
 *
-* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-1999 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.
 * ============================================================================
+* Nov 08, 1999  Nenad Corbic    o Combined all debug UDP calls into one function
+*                               o Removed the ARP support. This has to be done
+*                                 in the next version.
+*                               o Only a Node can implement NO signalling.
+*                                 Initialize DLCI during if_open() if NO 
+*				  signalling.
+*				o Took out IPX support, implement in next
+*                                 version
+* Sep 29, 1999  Nenad Corbic	o Added SMP support and changed the update
+*                                 function to use timer interrupt.
+*				o Fixed the CIR bug:  Set the value of BC
+*                                 to CIR when the CIR is enabled.
+*  				o Updated comments, statistics and tracing.
+* Jun 02, 1999	Gideon Hack	o Updated for S514 support.
+* Sep 18, 1998	Jaspreet Singh	o Updated for 2.2.X kernels.
+* Jul 31, 1998	Jaspreet Singh	o Removed wpf_poll routine.  The channel/DLCI 
+*				  status is received through an event interrupt.
+* Jul 08, 1998	David Fong	o Added inverse ARP support.
+* Mar 26, 1997	Jaspreet Singh	o Returning return codes for failed UDP cmds.
+* Jan 28, 1997	Jaspreet Singh  o Improved handling of inactive DLCIs.
+* Dec 30, 1997	Jaspreet Singh	o Replaced dev_tint() with mark_bh(NET_BH)
+* Dec 16, 1997	Jaspreet Singh	o Implemented Multiple IPX support.
 * Nov 26, 1997	Jaspreet Singh	o Improved load sharing with multiple boards
 *				o Added Cli() to protect enabling of interrupts
 *				  while polling is called.
@@ -42,7 +64,8 @@
 *				 o Added ability to discard multicast and 
 *				   broadcast source addressed packets
 * Jun 27, 1997	Jaspreet Singh	 o Added FT1 monitor capabilities 
-*				   New case (0x44) statement in if_send routine *				   Added a global variable rCount to keep track
+*				   New case (0x44) statement in if_send routine 
+*				   Added a global variable rCount to keep track
 *			 	   of FT1 status enabled on the board.
 * May 29, 1997	Jaspreet Singh	 o Fixed major Flow Control Problem
 *				   With multiple boards a problem was seen where
@@ -50,13 +73,15 @@
 *				   packet after running for a while. The code
 *				   got into a stage where the interrupts were
 *				   disabled and dev->tbusy was set to 1.
-*                  		   This caused the If_send() routine to get into*                                  the if clause for it(0,dev->tbusy) 
+*                  		   This caused the If_send() routine to get into
+*                                  the if clause for it(0,dev->tbusy) 
 *				   forever.
 *				   The code got into this stage due to an 
-*				   interrupt occurring within the if clause for 
+*				   interrupt occuring within the if clause for 
 *				   set_bit(0,dev->tbusy).  Since an interrupt 
 *				   disables furhter transmit interrupt and 
-* 				   makes dev->tbusy = 0, this effect was undone *                                  by making dev->tbusy = 1 in the if clause.
+* 				   makes dev->tbusy = 0, this effect was undone 
+*                                  by making dev->tbusy = 1 in the if clause.
 *				   The Fix checks to see if Transmit interrupts
 *				   are disabled then do not make dev->tbusy = 1
 * 	   			   Introduced a global variable: int_occur and
@@ -83,6 +108,7 @@
 * Jan 02, 1997	Gene Kozin	Initial version.
 *****************************************************************************/
 
+#include <linux/version.h>
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
@@ -93,140 +119,133 @@
 #include <linux/if_arp.h>	/* ARPHRD_* defines */
 #include <asm/byteorder.h>	/* htons(), etc. */
 #include <asm/io.h>		/* for inb(), outb(), etc. */
-#include <linux/time.h>		/* for do_gettimeofday */
-#define	_GNUC_
-#include <linux/sdla_fr.h>	/* frame relay firmware API definitions */
+#include <linux/time.h>	 	/* for do_gettimeofday */	
+#include <linux/in.h>		/* sockaddr_in */
+#include <linux/inet.h>		/* in_ntoa(), etc... */
 #include <asm/uaccess.h>
+#include <linux/inetdevice.h>
+#include <linux/ip.h>
+#include <net/route.h>          /* Dynamic Route Creation */
+#include <linux/if.h>
 
+#include <linux/sdla_fr.h>	/* frame relay firmware API definitions */
+#if LINUX_VERSION_CODE < 0x020125
+#define test_and_set_bit set_bit
+#endif
+ 
 /****** Defines & Macros ****************************************************/
 
-#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 */
+#define	MAX_CMD_RETRY	10		/* max number of firmware retries */
 
-/* Q.922 frame types */
+#define	FR_HEADER_LEN	8		/* max encapsulation header size */
+#define	FR_CHANNEL_MTU	1500		/* unfragmented logical channel MTU */
 
-#define	Q922_UI		0x03	/* Unnumbered Info frame */
-#define	Q922_XID	0xAF	/* ??? */
+/* Q.922 frame types */
+#define	Q922_UI		0x03		/* Unnumbered Info frame */
+#define	Q922_XID	0xAF		
 
 /* DLCI configured or not */
-
 #define DLCI_NOT_CONFIGURED	0x00
 #define DLCI_CONFIG_PENDING	0x01
 #define DLCI_CONFIGURED		0x02
 
 /* CIR enabled or not */
-
 #define CIR_ENABLED	0x00
 #define CIR_DISABLED	0x01
 
-/* Interrupt mode for DLCI = 0 */
-
-#define BUFFER_INTR_MODE	0x00
-#define DLCI_LIST_INTR_MODE	0x01
-
-/* Transmit Interrupt Status */
-
-#define DISABLED 		0x00
-#define WAITING_TO_BE_ENABLED	0x01
+#define WANPIPE 0x00
+#define API     0x01
+#define FRAME_RELAY_API 1
 
 /* For handle_IPXWAN() */
-
 #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
-
+ 
 /****** 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_configured;	/* check whether configured or not */
-	unsigned cir_status;	/* check whether CIR enabled or not */
-	unsigned dlci;		/* logical channel number */
-	unsigned cir;		/* committed information rate */
-	unsigned bc;		/* committed burst size */
-	unsigned be;		/* excess burst size */
-	unsigned mc;		/* multicast support on or off */
-	unsigned tx_int_status;	/* Transmit Interrupt Status */
+typedef struct fr_channel
+{
+	char name[WAN_IFNAME_SZ+1];	/* interface name, ASCIIZ */
+	unsigned dlci_configured  ;	/* check whether configured or not */
+	unsigned cir_status;		/* check whether CIR enabled or not */
+	unsigned dlci;			/* logical channel number */
+	unsigned cir;			/* committed information rate */
+	unsigned bc;			/* committed burst size */
+	unsigned be;			/* excess burst size */
+	unsigned mc;			/* multicast support on or off */
+	unsigned tx_int_status;		/* Transmit Interrupt Status */	
 	unsigned short pkt_length;	/* Packet Length */
-	unsigned long router_start_time;	/* Router start time in seconds */
+	unsigned long router_start_time;/* Router start time in seconds */
 	unsigned long tick_counter;	/* counter for transmit time out */
 	char dev_pending_devtint;	/* interface pending dev_tint() */
-	char state;		/* channel state */
-	void *dlci_int_interface;	/* pointer to the DLCI Interface */
-	unsigned long IB_addr;	/* physical address of Interface Byte */
+	char state;			/* channel state */
+	void *dlci_int_interface;	/* pointer to the DLCI Interface */ 
+	unsigned long IB_addr;		/* physical address of Interface Byte */
 	unsigned long state_tick;	/* time of the last state change */
-	sdla_t *card;		/* -> owner */
-	struct net_device_stats ifstats;		/* interface statistics */
-	unsigned long if_send_entry;
-	unsigned long if_send_skb_null;
-	unsigned long if_send_broadcast;
-	unsigned long if_send_multicast;
-	unsigned long if_send_critical_ISR;
-	unsigned long if_send_critical_non_ISR;
-	unsigned long if_send_busy;
-	unsigned long if_send_busy_timeout;
-	unsigned long if_send_FPIPE_request;
-	unsigned long if_send_DRVSTATS_request;
-	unsigned long if_send_wan_disconnected;
-	unsigned long if_send_dlci_disconnected;
-	unsigned long if_send_no_bfrs;
-	unsigned long if_send_adptr_bfrs_full;
-	unsigned long if_send_bfrs_passed_to_adptr;
-	unsigned long rx_intr_no_socket;
-	unsigned long rx_intr_dev_not_started;
-	unsigned long rx_intr_FPIPE_request;
-	unsigned long rx_intr_DRVSTATS_request;
-	unsigned long rx_intr_bfr_not_passed_to_stack;
-	unsigned long rx_intr_bfr_passed_to_stack;
-	unsigned long UDP_FPIPE_mgmt_kmalloc_err;
-	unsigned long UDP_FPIPE_mgmt_direction_err;
-	unsigned long UDP_FPIPE_mgmt_adptr_type_err;
-	unsigned long UDP_FPIPE_mgmt_adptr_cmnd_OK;
-	unsigned long UDP_FPIPE_mgmt_adptr_cmnd_timeout;
-	unsigned long UDP_FPIPE_mgmt_adptr_send_passed;
-	unsigned long UDP_FPIPE_mgmt_adptr_send_failed;
-	unsigned long UDP_FPIPE_mgmt_not_passed_to_stack;
-	unsigned long UDP_FPIPE_mgmt_passed_to_stack;
-	unsigned long UDP_FPIPE_mgmt_no_socket;
-	unsigned long UDP_DRVSTATS_mgmt_kmalloc_err;
-	unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
-	unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
-	unsigned long UDP_DRVSTATS_mgmt_adptr_send_passed;
-	unsigned long UDP_DRVSTATS_mgmt_adptr_send_failed;
-	unsigned long UDP_DRVSTATS_mgmt_not_passed_to_stack;
-	unsigned long UDP_DRVSTATS_mgmt_passed_to_stack;
-	unsigned long UDP_DRVSTATS_mgmt_no_socket;
+	unsigned char enable_IPX;	/* Enable/Disable the use of IPX */
+	unsigned long network_number;	/* Internal Network Number for IPX*/
+	sdla_t *card;			/* -> owner */
+	unsigned route_flag;		/* Add/Rem dest addr in route tables */
+	unsigned inarp;			/* Inverse Arp Request status */ 
+	int inarp_interval;		/* Time between InArp Requests */
+	unsigned long inarp_tick;	/* InArp jiffies tick counter */
+	struct net_device_stats ifstats;	/* interface statistics */
+	if_send_stat_t drvstats_if_send;
+        rx_intr_stat_t drvstats_rx_intr;
+        pipe_mgmt_stat_t drvstats_gen;
+
+	unsigned char usedby;  /* Used by WANPIPE or API */
+
 	unsigned long router_up_time;
+
+	unsigned short transmit_length;
+	char transmit_buffer[FR_MAX_NO_DATA_BYTES_IN_FRAME];
 } fr_channel_t;
 
-typedef struct dlci_status {
-	unsigned short dlci PACKED;
-	unsigned char state PACKED;
+/* Route Flag options */
+#define NO_ROUTE	0x00
+#define ADD_ROUTE 	0x01
+#define ROUTE_ADDED	0x02
+#define REMOVE_ROUTE 	0x03
+
+/* inarp options */
+#define INARP_NONE		0x00
+#define INARP_REQUEST		0x01
+#define INARP_CONFIGURED	0x02
+
+/* reasons for enabling the timer interrupt on the adapter */
+#define TMR_INT_ENABLED_UDP   	0x01
+#define TMR_INT_ENABLED_UPDATE 	0x02
+
+
+typedef struct dlci_status
+{
+	unsigned short dlci	PACKED;
+	unsigned char state	PACKED;
 } dlci_status_t;
 
-typedef struct dlci_IB_mapping {
-	unsigned short dlci PACKED;
-	unsigned long addr_value PACKED;
+typedef struct dlci_IB_mapping
+{
+	unsigned short dlci		PACKED;
+	unsigned long  addr_value	PACKED;
 } dlci_IB_mapping_t;
 
 /* This structure is used for DLCI list Tx interrupt mode.  It is used to
    enable interrupt bit and set the packet length for transmission
  */
+typedef struct fr_dlci_interface 
+{
+	unsigned char gen_interrupt	PACKED;
+	unsigned short packet_length	PACKED;
+	unsigned char reserved		PACKED;
+} fr_dlci_interface_t; 
 
-typedef struct fr_dlci_interface {
-	unsigned char gen_interrupt PACKED;
-	unsigned short packet_length PACKED;
-	unsigned char reserved PACKED;
-} fr_dlci_interface_t;
-
-static unsigned short num_frames;
-static unsigned long curr_trace_addr;
-static unsigned long start_trace_addr;
-static unsigned short available_buffer_space;
-static char TracingEnabled; /* variable for keeping track of enabling/disabling FT1 monitor status */
+/* variable for keeping track of enabling/disabling FT1 monitor status */
 static int rCount = 0;
+
+extern int ip_rt_ioctl(unsigned int, void *);
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
 
@@ -234,70 +253,96 @@
  * interrupt test routine 
  */
 static int Intr_test_counter;
-
 /****** 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);
+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);
+
 /* WANPIPE-specific entry points */
 static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data);
+
 /* 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_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len);
 static int if_rebuild_hdr(struct sk_buff *skb);
 static int if_send(struct sk_buff *skb, struct device *dev);
+static int chk_bcast_mcast_addr(sdla_t *card, struct device* dev,
+                                struct sk_buff *skb);
 static struct net_device_stats *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);
+static void fr_isr(sdla_t *card);
+static void rx_intr(sdla_t *card);
+static void tx_intr(sdla_t *card);
+static void timer_intr(sdla_t *card);
+static void spur_intr(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_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci);
-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_get_err_stats(sdla_t * card);
-static int fr_get_stats(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);
+static int fr_read_version(sdla_t *card, char *str);
+static int fr_configure(sdla_t *card, fr_conf_t *conf);
+static int fr_dlci_configure(sdla_t *card, fr_dlc_conf_t *conf, unsigned dlci);
+static int fr_init_dlci (sdla_t *card, fr_channel_t *chan);
+static int fr_set_intr_mode (sdla_t *card, unsigned mode, unsigned mtu, unsigned short timeout);
+static int fr_comm_enable(sdla_t *card);
+static int fr_comm_disable(sdla_t *card);
+static int fr_get_err_stats(sdla_t *card);
+static int fr_get_stats(sdla_t *card);
+static int fr_add_dlci(sdla_t *card, int dlci);
+static int fr_activate_dlci(sdla_t *card, int dlci);
+static int fr_delete_dlci (sdla_t* card, int dlci);
+static int fr_issue_isf(sdla_t *card, int isf);
+static int fr_send(sdla_t *card, int dlci, unsigned char 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);
+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, fr_channel_t * chan);
+static struct device *find_channel(sdla_t *card, unsigned dlci);
+static int is_tx_ready(sdla_t *card, fr_channel_t *chan);
 static unsigned int dec_to_uint(unsigned char *str, int len);
-static int reply_udp(unsigned char *data, unsigned int mbox_len);
-static int intr_test(sdla_t * card);
-static void init_chan_statistics(fr_channel_t * chan);
-static void init_global_statistics(sdla_t * card);
-static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan);
+static int reply_udp( unsigned char *data, unsigned int mbox_len );
+
+static int intr_test( sdla_t* card );
+static void init_chan_statistics( fr_channel_t* chan );
+static void init_global_statistics( sdla_t* card );
+static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan );
+static void setup_for_delayed_transmit(struct device* dev, void* buf,
+	unsigned len);
+
+
+/* Inverse ARP and Dynamic routing functions */
+int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct device *dev);
+int is_arp(void *buf);
+int send_inarp_request(sdla_t *card, struct device *dev);
+
 /* Udp management functions */
-static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan);
-static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan);
-static int udp_pkt_type(struct sk_buff *skb, sdla_t * card);
+static int process_udp_mgmt_pkt(sdla_t *card);
+static int udp_pkt_type( struct sk_buff *skb, sdla_t *card );
+static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card,
+                                struct sk_buff *skb, int dlci);
+
 /* IPX functions */
-static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming);
-static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number);
+static void switch_net_numbers(unsigned char *sendpacket,
+	unsigned long network_number, unsigned char incoming);
+
+static int handle_IPXWAN(unsigned char *sendpacket, char *devname,
+	unsigned char enable_IPX, unsigned long network_number);
+
+/* Lock Functions: SMP supported */
+void 	s508_s514_unlock(sdla_t *card, unsigned long *smp_flags);
+void 	s508_s514_lock(sdla_t *card, unsigned long *smp_flags);
+
+unsigned short calc_checksum (char *, int);
+
 
 /****** Public Functions ****************************************************/
 
@@ -313,154 +358,251 @@
  * Return:	0	o.k.
  *		< 0	failure.
  */
-int wpf_init(sdla_t * card, wandev_conf_t * conf)
+int wpf_init(sdla_t *card, wandev_conf_t *conf)
 {
-	union {
+
+	int err;
+
+	union
+	{
 		char str[80];
 		fr_conf_t cfg;
 	} u;
+	fr_buf_info_t* buf_info;
 	int i;
+
 	/* Verify configuration ID */
-	if (conf->config_id != WANCONFIG_FR) 
-	{
+	if (conf->config_id != WANCONFIG_FR) {
+		
 		printk(KERN_INFO "%s: invalid configuration ID %u!\n",
-		       card->devname, conf->config_id);
+			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;
+	switch (card->hw.fwid) {
+	
 		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;
+			card->mbox  = (void*)(card->hw.dpmbase + 
+					FR508_MBOX_OFFS);
+			card->flags = (void*)(card->hw.dpmbase + 
+					FR508_FLAG_OFFS);
+			if(card->hw.type == SDLA_S514) {
+				card->mbox += FR_MB_VECTOR;
+                                card->flags += FR_MB_VECTOR;
+			}
+                        card->isr = &fr_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);
+		card->devname, u.str);
+
 	/* Adjust configuration */
-	conf->mtu = max(min(conf->mtu, 4080), FR_CHANNEL_MTU + FR_HEADER_LEN);
+	conf->mtu += FR_HEADER_LEN;
+	conf->mtu = (conf->mtu >= MIN_LGTH_FR_DATA_CFG) ?
+			min(conf->mtu, FR_MAX_NO_DATA_BYTES_IN_FRAME) :
+                        FR_CHANNEL_MTU + FR_HEADER_LEN;
+     
 	conf->bps = min(conf->bps, 2048000);
-	/* Configure adapter firmware */
+
+	/* Initialze the configuration structure sent to the board to zero */
 	memset(&u.cfg, 0, sizeof(u.cfg));
-	u.cfg.mtu = conf->mtu;
-	u.cfg.kbps = conf->bps / 1000;
-	u.cfg.cir_fwd = u.cfg.cir_bwd = 16;
-	u.cfg.bc_fwd = u.cfg.bc_bwd = 16;
-	if (conf->station == WANOPT_CPE) 
-	{
-		u.cfg.options = 0x0080;
-		printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname);
-	}
-	else
-	{
-		u.cfg.options = 0x0081;
-	}
-	switch (conf->u.fr.signalling) 
-	{
-		case WANOPT_FR_Q933:
-			u.cfg.options |= 0x0200;
+
+	memset(card->u.f.dlci_to_dev_map, 0, sizeof(card->u.f.dlci_to_dev_map));
+ 	
+	/* Configure adapter firmware */
+	
+	u.cfg.mtu	= conf->mtu;
+	u.cfg.kbps	= conf->bps / 1000;
+
+    	u.cfg.cir_fwd = u.cfg.cir_bwd = 16;
+        u.cfg.bc_fwd  = u.cfg.bc_bwd = 16;
+	
+	u.cfg.options	= 0x0000;
+	printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname);
+	
+	switch (conf->u.fr.signalling) {
+
+		case WANOPT_FR_ANSI:
+			u.cfg.options = 0x0000; 
+			break;		
+	
+		case WANOPT_FR_Q933:	
+			u.cfg.options |= 0x0200; 
+			break;
+	
+		case WANOPT_FR_LMI:	
+			u.cfg.options |= 0x0400; 
 			break;
-		case WANOPT_FR_LMI:
-			u.cfg.options |= 0x0400;
+
+		case WANOPT_NO:
+			u.cfg.options |= 0x0800; 
 			break;
+		default:
+			printk(KERN_INFO "%s: Illegal Signalling option\n",
+					card->wandev.name);
+			return -EINVAL;
 	}
-	if (conf->station == WANOPT_CPE) 
-	{
+
+
+	card->wandev.signalling = conf->u.fr.signalling;
+
+	if (conf->station == WANOPT_CPE) {
+
+
+		if (conf->u.fr.signalling == WANOPT_NO){
+			printk(KERN_INFO 
+				"%s: ERROR - For NO signalling, station must be set to Node!",
+				 	 card->devname);
+			return -EINVAL;
+		}
+
+		u.cfg.station = 0;
 		u.cfg.options |= 0x8000;	/* auto config DLCI */
-		card->u.f.dlci_num = 0;
-	}
-	else
-	{
+		card->u.f.dlci_num  = 0;
+	
+	} else {
+
 		u.cfg.station = 1;	/* switch emulation mode */
+
 		/* For switch emulation we have to create a list of dlci(s)
 		 * that will be sent to be global SET_DLCI_CONFIGURATION 
 		 * command in fr_configure() routine. 
 		 */
-		card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100);
-		for (i = 0; i < card->u.f.dlci_num; i++) 
-		{
-			card->u.f.node_dlci[i] = (unsigned short)
-			    conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16;
+
+		card->u.f.dlci_num  = min(max(conf->u.fr.dlci_num, 1), 100);
+	
+		for ( i = 0; i < card->u.f.dlci_num; i++) {
+
+			card->u.f.node_dlci[i] = (unsigned short) 
+				conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16;
+	
 		}
 	}
+
 	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);
 	else
 		u.cfg.t391 = 5;
+
 	if (conf->u.fr.t392)
 		u.cfg.t392 = min(conf->u.fr.t392, 30);
 	else
 		u.cfg.t392 = 15;
+
 	if (conf->u.fr.n391)
 		u.cfg.n391 = min(conf->u.fr.n391, 255);
 	else
 		u.cfg.n391 = 2;
+
 	if (conf->u.fr.n392)
 		u.cfg.n392 = min(conf->u.fr.n392, 10);
 	else
-		u.cfg.n392 = 3;
+		u.cfg.n392 = 3;	
+
 	if (conf->u.fr.n393)
 		u.cfg.n393 = min(conf->u.fr.n393, 10);
 	else
 		u.cfg.n393 = 4;
+
 	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->exec = &wpf_exec;
-	card->wandev.update = &update;
-	card->wandev.new_if = &new_if;
-	card->wandev.del_if = &del_if;
-	card->wandev.state = WAN_DISCONNECTED;
-	card->wandev.ttl = conf->ttl;
-	card->wandev.udp_port = conf->udp_port;
-	card->wandev.enable_tx_int = 0;
-	card->irq_dis_if_send_count = 0;
-	card->irq_dis_poll_count = 0;
-	card->wandev.enable_IPX = conf->enable_IPX;
-	if (conf->network_number)
-		card->wandev.network_number = conf->network_number;
-	else
-		card->wandev.network_number = 0xDEADBEEF;
+
+	if (card->hw.type == SDLA_S514) {
+	
+                buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR +
+			FR508_RXBC_OFFS);
+
+                card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase);
+
+                card->u.f.rxmb_base =
+                        (void*)(buf_info->rse_base + card->hw.dpmbase); 
+
+                card->u.f.rxmb_last =
+                        (void*)(buf_info->rse_base +
+                        (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) +
+                        card->hw.dpmbase);
+	}
+
+	else {	
+		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_rx_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->u.f.tx_interrupts_pending = 0;
+
+	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		= NULL; 
+	card->exec		= &wpf_exec;
+	card->wandev.update	= &update;
+	card->wandev.new_if	= &new_if;
+	card->wandev.del_if	= &del_if;
+	card->wandev.state	= WAN_DISCONNECTED;
+	card->wandev.ttl	= conf->ttl;
+        card->wandev.udp_port 	= conf->udp_port;       
+
 	/* Intialize global statistics for a card */
-	init_global_statistics(card);
-	TracingEnabled = 0;
-	return 0;
+	init_global_statistics( card );
+
+        card->TracingEnabled          = 0;
+
+	/* Interrupt Test */
+	Intr_test_counter = 0;
+	card->intr_mode = INTR_TEST_MODE;
+	err = intr_test( card );
+
+	if (err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) {
+		printk( 
+			"%s: Interrupt Test Failed, Counter: %i\n", 
+			card->devname, Intr_test_counter);
+		printk( "Please choose another interrupt\n");
+		err = -EIO;
+		return err;
+	}
+
+	printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n",
+			card->devname, Intr_test_counter);
+
+
+        return 0;
 }
 
 /******* WAN Device Driver Entry Points *************************************/
@@ -468,21 +610,38 @@
 /*============================================================================
  * Update device status & statistics.
  */
-
-static int update(wan_device_t * wandev)
+static int update (wan_device_t* wandev)
 {
-	sdla_t *card;
+	volatile sdla_t* card;
+	unsigned long timeout;
+	fr508_flags_t* flags;
+
 	/* sanity checks */
 	if ((wandev == NULL) || (wandev->private == NULL))
 		return -EFAULT;
+
 	if (wandev->state == WAN_UNCONFIGURED)
 		return -ENODEV;
-	if (test_and_set_bit(0, (void *) &wandev->critical))
+
+	if (test_bit(1, (void*)&wandev->critical))
 		return -EAGAIN;
+
 	card = wandev->private;
-	fr_get_err_stats(card);
-	fr_get_stats(card);
-	wandev->critical = 0;
+	flags = card->flags;
+
+
+	card->u.f.update_comms_stats = 1;
+	card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE;
+	flags->imask |= FR_INTR_TIMER;
+       	timeout = jiffies;
+       	for(;;) {
+		if(card->u.f.update_comms_stats == 0)
+			break;
+                if ((jiffies - timeout) > (1 * HZ)){
+    			card->u.f.update_comms_stats = 0;
+ 			return -EAGAIN;
+		}
+        }
 	return 0;
 }
 
@@ -498,85 +657,216 @@
  * 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)
+static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf)
 {
-	sdla_t *card = wandev->private;
-	fr_channel_t *chan;
+	sdla_t* card = wandev->private;
+	fr_channel_t* chan;
+	int dlci = 0;
 	int err = 0;
-	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) 
-	{
+	
+	if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
+		
 		printk(KERN_INFO "%s: invalid interface name!\n",
-		       card->devname);
+			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)) 
-		{
+	if (is_digit(conf->addr[0])) {
+
+		dlci = dec_to_uint(conf->addr, 0);
+
+		if (dlci && (dlci <= HIGHEST_VALID_DLCI)) {
+		
 			chan->dlci = dlci;
-		}
-		else
-		{
-			printk(KERN_ERR "%s: invalid DLCI %u on interface %s!\n",
-			       wandev->name, dlci, chan->name);
+		
+		} 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);
+
+	} else {
+		printk(KERN_ERR
+			"%s: invalid media address on interface %s!\n",
+			wandev->name, chan->name);
 		err = -EINVAL;
 	}
-	if (err) 
-	{
+
+        /* Setup wanpipe as a router (WANPIPE) or as an API */
+        if(strcmp(conf->usedby, "WANPIPE") == 0){
+                printk(KERN_INFO "%s: Running in WANPIPE mode %s\n",
+			wandev->name, chan->name);
+                chan->usedby = WANPIPE;
+
+        } else if(strcmp(conf->usedby, "API") == 0){
+
+#ifdef FRAME_RELAY_API
+                chan->usedby = API;
+                printk(KERN_INFO "%s: Running in API mode %s\n",
+			wandev->name, chan->name);
+#else
+                printk(KERN_INFO "%s: API Mode is not supported !\n",
+			wandev->name);
+                printk(KERN_INFO
+			"%s: API patch can be obtained from Sangoma Tech.\n",
+                        	wandev->name);
+                err = -EINVAL;
+#endif
+        }
+
+	if (err) {
+		
 		kfree(chan);
 		return err;
 	}
+
+	card->u.f.dlci_to_dev_map[dlci] = dev;
+ 
 	/* place cir,be,bc and other channel specific information into the
 	 * chan structure 
-	 */
-	if (conf->cir) 
-	{
-		chan->cir = max(1, min(conf->cir, 512));
-		chan->cir_status = CIR_ENABLED;
-		if (conf->bc)
-			chan->bc = max(1, min(conf->bc, 512));
-		if (conf->be)
-			chan->be = max(0, min(conf->be, 511));
-	}
-	else
+         */
+	if (conf->cir) {
+
+		chan->cir = max( 1, min( conf->cir, 512 ) );
+		chan->cir_status = CIR_ENABLED; 
+
+		
+		/* If CIR is enabled, force BC to equal CIR
+                 * this solves number of potential problems if CIR is 
+                 * set and BC is not 
+		 */
+		chan->bc = chan->cir;
+
+		if (conf->be){
+			chan->be = max( 0, min( conf->be, 511) ); 
+		}else{	
+			conf->be = 0;
+		}
+
+		printk (KERN_INFO "%s: CIR enabled for DLCI %i \n",
+				wandev->name,chan->dlci);
+		printk (KERN_INFO "%s:     CIR = %i ; BC = %i ; BE = %i\n",
+				wandev->name,chan->cir,chan->bc,chan->be);
+
+
+	}else{
 		chan->cir_status = CIR_DISABLED;
+		printk (KERN_INFO "%s: CIR disabled for DLCI %i\n",
+				wandev->name,chan->dlci);
+	}
+
 	chan->mc = conf->mc;
-	chan->dlci_configured = DLCI_NOT_CONFIGURED;
-	chan->tx_int_status = DISABLED;
+
+	/* FIXME: ARP is not supported by this frame relay verson */
+	if (conf->inarp == WANOPT_YES){
+		printk(KERN_INFO "%s: ERROR - This version of WANPIPE doesn't support ARPs\n",
+				card->devname);
+	
+		//chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE;
+		//chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10;
+		kfree(chan);
+		return -EINVAL;
+	}else{
+		chan->inarp = INARP_NONE;
+		chan->inarp_interval = 10;
+	}
+
+	chan->dlci_configured = DLCI_NOT_CONFIGURED;	
+
+
+	/*FIXME: IPX disabled in this WANPIPE version */
+	if (conf->enable_IPX == WANOPT_YES){
+		printk(KERN_INFO "%s: ERROR - This version of WANPIPE doesn't support IPX\n",
+				card->devname);
+		kfree(chan);
+		return -EINVAL;
+	}else{
+		chan->enable_IPX = WANOPT_NO;
+	}	
+
+	if (conf->network_number){
+		chan->network_number = conf->network_number;
+	}else{
+		chan->network_number = 0xDEADBEEF;
+	}
+
+	chan->route_flag = NO_ROUTE;
+	
 	init_chan_statistics(chan);
+
+	chan->transmit_length = 0;
+
 	/* prepare network device data space for registration */
 	dev->name = chan->name;
 	dev->init = &if_init;
 	dev->priv = chan;
+
+
+	/* Enable Interrupts and Communications */
+	if (!wandev->new_if_cnt){
+		fr508_flags_t* flags = card->flags;
+
+		wandev->new_if_cnt++;
+
+		/* 
+		If you enable comms and then set ints, you get a Tx int as you
+		perform the SET_INT_TRIGGERS command. So, we only set int
+		triggers and then adjust the interrupt mask (to disable Tx ints)
+		before enabling comms. 
+		*/	
+                if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY |
+			FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) ,
+			card->wandev.mtu, 0)) {
+			kfree(chan);
+			return -EIO;
+		}
+
+		flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER);
+ 
+		if (fr_comm_enable(card)) {
+			kfree(chan);
+			return -EIO;
+		}	
+		wanpipe_set_state(card, WAN_CONNECTED);
+	}
+
 	return 0;
 }
+
 /*============================================================================
  * Delete logical channel.
  */
-static int del_if(wan_device_t * wandev, struct device *dev)
+static int del_if (wan_device_t* wandev, struct device* dev)
 {
-	if (dev->priv) 
-	{
+	sdla_t *card = wandev->private;
+
+	/* Execute shutdown very first time we enter del_if */
+
+	if (!wandev->del_if_cnt) {
+		wandev->del_if_cnt++;
+		wanpipe_set_state(card, WAN_DISCONNECTED);
+		fr_set_intr_mode(card, 0, 0, 0);
+		fr_comm_disable(card);
+	}
+
+	if (dev->priv) {
 		kfree(dev->priv);
 		dev->priv = NULL;
 	}
+
 	return 0;
 }
 
@@ -585,41 +875,47 @@
 /*============================================================================
  * Execute adapter interface command.
  */
-static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data)
+static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data)
 {
-	fr_mbox_t *mbox = card->mbox;
+	fr_mbox_t* mbox = card->mbox;
 	int retry = MAX_CMD_RETRY;
 	int err, len;
 	fr_cmd_t cmd;
-	if(copy_from_user((void *) &cmd, u_cmd, sizeof(cmd)))
-		return -EFAULT;		
+
+	if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd)))
+		return -EFAULT;
+	
 	/* execute command */
-	do 
+	do
 	{
 		memcpy(&mbox->cmd, &cmd, sizeof(cmd));
-		if (cmd.length)
-		{
-			if(copy_from_user((void *) &mbox->data, u_data, cmd.length))
+		
+		if (cmd.length){
+			if( copy_from_user((void*)&mbox->data, u_data, cmd.length))
 				return -EFAULT;
 		}
+		
 		if (sdla_exec(mbox))
 			err = mbox->cmd.result;
-		else
-			return -EIO;
-	} 
-	while (err && retry-- && fr_event(card, err, mbox));
 
-	/* return result */
+		else return -EIO;
+	
+	} while (err && retry-- && fr_event(card, err, mbox));
 
-	if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(fr_cmd_t)))
+	/* return result */
+	if (copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t)))
 		return -EFAULT;
+
 	len = mbox->cmd.length;
-	if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len))
+
+	if (len && u_data && !copy_to_user(u_data, (void*)&mbox->data, len))
 		return -EFAULT;
 	return 0;
+
 }
 
 /****** Network Device Interface ********************************************/
+
 /*============================================================================
  * Initialize Linux network interface.
  *
@@ -627,35 +923,55 @@
  * interface registration.  Returning anything but zero will fail interface
  * registration.
  */
-static int if_init(struct device *dev)
+static int if_init (struct device* dev)
 {
-	fr_channel_t *chan = dev->priv;
-	sdla_t *card = chan->card;
-	wan_device_t *wandev = &card->wandev;
+	fr_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+	wan_device_t* wandev = &card->wandev;
 
 	/* 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;
+	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->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);
+	dev->type		= ARPHRD_DLCI;	/* ARP h/w type */
+	dev->flags		|= IFF_POINTOPOINT;	
+
+	/* Enable Multicast addressing */
+	if (chan->mc == WANOPT_YES){
+		dev->flags 	|= IFF_MULTICAST;
+	}
+
+	dev->mtu		= wandev->mtu - FR_HEADER_LEN;
+	/* For an API, the maximum number of bytes that the stack will pass
+	   to the driver is (dev->mtu + dev->hard_header_len). So, adjust the
+	   mtu so that a frame of maximum size can be transmitted by the API. 
+	*/
+	if(chan->usedby == API) {
+		dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN);
+	}
+	
+	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 = (unsigned long)wandev->maddr;
-	dev->mem_end = dev->mem_start + wandev->msize - 1;
-	/* Set transmit buffer queue length */
-	dev->tx_queue_len = 10;
+	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;
+
+        /* Set transmit buffer queue length */
+        dev->tx_queue_len = 100;
+   
 	/* Initialize socket buffers */
 	dev_init_buffers(dev);
+
 	set_chan_state(dev, WAN_DISCONNECTED);
 	return 0;
 }
@@ -667,127 +983,62 @@
  *
  * Return 0 if O.k. or errno.
  */
-
-static int if_open(struct device *dev)
+static int if_open (struct device* dev)
 {
-	fr_channel_t *chan = dev->priv;
-	sdla_t *card = chan->card;
-	struct device *dev2;
+	fr_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
 	int err = 0;
-	fr508_flags_t *flags = card->flags;
 	struct timeval tv;
+
 	if (dev->start)
-		return -EBUSY;	/* only one open is allowed */
-	if (test_and_set_bit(0, (void *) &card->wandev.critical))
+		return -EBUSY;		/* only one open is allowed */
+
+	if (test_and_set_bit(1, (void*)&card->wandev.critical))
 		return -EAGAIN;
-	if (!card->open_cnt) 
-	{
-		Intr_test_counter = 0;
-		card->intr_mode = INTR_TEST_MODE;
-		err = intr_test(card);
-		if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) {
-			printk(KERN_INFO
-			       "%s: Interrupt Test Failed, Counter: %i\n",
-			       card->devname, Intr_test_counter);
-			err = -EIO;
-			card->wandev.critical = 0;
-			return err;
-		}
-		printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n"
-		       ,card->devname, Intr_test_counter);
-		/* The following allocates and intializes a circular
-		 * link list of interfaces per card.
-		 */
-		card->devs_struct = kmalloc(sizeof(load_sharing_t), GFP_KERNEL);
-		if (card->devs_struct == NULL)
-			return -ENOMEM;
-		card->dev_to_devtint_next = card->devs_struct;
-		for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) {
-			(card->devs_struct)->dev_ptr = dev2;
-			if (dev2->slave == NULL)
-				(card->devs_struct)->next = card->dev_to_devtint_next;
-			else {
-				(card->devs_struct)->next = kmalloc(
-				     sizeof(load_sharing_t), GFP_KERNEL);
-				if ((card->devs_struct)->next == NULL)
-					return -ENOMEM;
-				card->devs_struct = (card->devs_struct)->next;
-			}
-		}
-		card->devs_struct = card->dev_to_devtint_next;
-		card->intr_mode = BUFFER_INTR_MODE;
-		/* 
-		   check all the interfaces for the device to see if CIR has
-		   been enabled for any DLCI(s). If so then use the DLCI list
-		   Interrupt mode for fr_set_intr_mode(), otherwise use the                     default global interrupt mode
-		 */
-		for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) {
-			if (((fr_channel_t *) dev2->priv)->cir_status
-			    == CIR_ENABLED) {
-				card->intr_mode = DLCI_LIST_INTR_MODE;
-				break;
-			}
-		}
-		/* 
-		   If you enable comms and then set ints, you get a Tx int as you
-		   perform the SET_INT_TRIGGERS command. So, we only set int
-		   triggers and then adjust the interrupt mask (to disable Tx ints)             before enabling comms. 
-		 */
-		if (card->intr_mode == BUFFER_INTR_MODE) {
-			if (fr_set_intr_mode(card, 0x03, card->wandev.mtu)) {
-				err = -EIO;
-				card->wandev.critical = 0;
-				return err;
-			}
-			printk(KERN_INFO
-			       "%s: Global Buffering Tx Interrupt Mode\n"
-			       ,card->devname);
-		} else if (card->intr_mode == DLCI_LIST_INTR_MODE) {
-			if (fr_set_intr_mode(card, 0x83, card->wandev.mtu)) {
-				err = -EIO;
-				card->wandev.critical = 0;
-				return err;
-			}
-			printk(KERN_INFO
-			       "%s: DLCI list Tx Interrupt Mode\n",
-			       card->devname);
-		}
-		flags->imask &= ~0x02;
-		if (fr_comm_enable(card)) {
-			err = -EIO;
-			card->wandev.critical = 0;
-			return err;
-		}
-		wanpipe_set_state(card, WAN_CONNECTED);
-		if (card->wandev.station == WANOPT_CPE) {
-			/* CPE: issue full status enquiry */
-			fr_issue_isf(card, FR_ISF_FSE);
-		} else {	/* FR switch: activate DLCI(s) */
-			/* For Switch emulation we have to ADD and ACTIVATE
-			 * the DLCI(s) that were configured with the SET_DLCI_
-			 * CONFIGURATION command. Add and Activate will fail if
-			 * DLCI specified is not included in the list.
-			 *
-			 * Also If_open is called once for each interface. But
-			 * it does not get in here for all the interface. So
-			 * we have to pass the entire list of DLCI(s) to add 
-			 * activate routines.  
-			 */
-			fr_add_dlci(card,
-			     card->u.f.node_dlci[0], card->u.f.dlci_num);
-			fr_activate_dlci(card,
-			     card->u.f.node_dlci[0], card->u.f.dlci_num);
+	
+
+	/* If signalling is set to NO, then setup 
+         * DLCI addresses right away.  Don't have to wait for
+	 * link to connect. 
+	 */
+	if (card->wandev.signalling == WANOPT_NO){
+		printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n",
+					card->wandev.name);
+		if (fr_init_dlci(card,chan)){
+			return -EAGAIN;
 		}
 	}
-	dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN);
+
+	if (card->wandev.station == WANOPT_CPE) {
+
+		/* CPE: issue full status enquiry */
+		fr_issue_isf(card, FR_ISF_FSE);
+
+	} else {	/* FR switch: activate DLCI(s) */
+		
+		/* For Switch emulation we have to ADD and ACTIVATE
+		 * the DLCI(s) that were configured with the SET_DLCI_
+		 * CONFIGURATION command. Add and Activate will fail if
+		 * DLCI specified is not included in the list.
+		 *
+		 * Also If_open is called once for each interface. But
+		 * it does not get in here for all the interface. So
+	 	 * we have to pass the entire list of DLCI(s) to add 
+		 * activate routines.  
+		 */ 
+	
+		fr_add_dlci(card, chan->dlci);
+		fr_activate_dlci(card, chan->dlci);
+	}
+
 	dev->interrupt = 0;
 	dev->tbusy = 0;
 	dev->start = 1;
 	wanpipe_open(card);
 	update_chan_state(dev);
-	do_gettimeofday(&tv);
+	do_gettimeofday( &tv );
 	chan->router_start_time = tv.tv_sec;
-	card->wandev.critical = 0;
+        clear_bit(1, (void*)&card->wandev.critical);
 	return err;
 }
 
@@ -796,22 +1047,21 @@
  * o if this is the last open, then disable communications and interrupts.
  * o reset flags.
  */
-
-static int if_close(struct device *dev)
+static int if_close (struct device* dev)
 {
-	fr_channel_t *chan = dev->priv;
-	sdla_t *card = chan->card;
-	if (test_and_set_bit(0, (void *) &card->wandev.critical))
+	fr_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+
+	if (test_and_set_bit(1, (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);
+	if (card->wandev.station == WANOPT_NODE) {
+		fr_delete_dlci (card,chan->dlci);
 	}
-	card->wandev.critical = 0;
+
+        clear_bit(1, (void*)&card->wandev.critical);
 	return 0;
 }
 
@@ -825,15 +1075,15 @@
  *
  * Return:	media header length.
  */
-
-static int if_header(struct sk_buff *skb, struct device *dev,
-	     unsigned short type, void *daddr, void *saddr, unsigned len)
+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 = wanrouter_encapsulate(skb, dev);
-	if (hdr_len < 0) 
-	{
+
+	if (hdr_len < 0) {
 		hdr_len = 0;
 		skb->protocol = 0;
 	}
@@ -849,14 +1099,14 @@
  * Return:	1	physical address resolved.
  *		0	physical address not resolved
  */
-
-static int if_rebuild_hdr(struct sk_buff *skb)
+static int if_rebuild_hdr (struct sk_buff* skb)
 {
-	struct device *dev=skb->dev;
-	fr_channel_t *chan = dev->priv;
-	sdla_t *card = chan->card;
+	struct device *dev = skb->dev;
+	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);
+		card->devname, dev->name);
 	return 1;
 }
 
@@ -864,6 +1114,7 @@
  * 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 set critical flag when accessing board.
  * 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.
@@ -878,876 +1129,952 @@
  * 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)
+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, err;
-	unsigned char *sendpacket;
-	struct device *dev2;
-	unsigned long check_braddr, check_mcaddr;
-	fr508_flags_t *adptr_flags = card->flags;
+    	fr_channel_t* chan = dev->priv;
+    	sdla_t* card = chan->card;
+        int err;
+    	unsigned char *sendpacket;
+    	fr508_flags_t* adptr_flags = card->flags;
 	int udp_type, send_data;
-	fr_dlci_interface_t *dlci_interface = chan->dlci_int_interface;
-	unsigned long host_cpu_flags;
-	++chan->if_send_entry;
+	unsigned long smp_flags=0;
+	void* data;
+	unsigned len;
+
+	chan->drvstats_if_send.if_send_entry++;
+
+        if (skb == NULL) {             
+		/* if we get here, some higher layer thinks we've missed an
+		 * tx-done interrupt.
+		 */
+		printk(KERN_INFO "%s: interface %s got kicked!\n", 
+			card->devname, dev->name);
+		chan->drvstats_if_send.if_send_skb_null ++;
+		mark_bh(NET_BH);
+		return 0;
+	}
+
+	/* We must set the 'tbusy' flag if we already have a packet queued for
+	   transmission in the transmit interrupt handler. However, we must
+	   ensure that the transmit interrupt does not reset the 'tbusy' flag
+	   just before we set it, as this will result in a "transmit timeout".
+	*/
+	set_bit(2, (void*)&card->wandev.critical);
+        if(chan->transmit_length) {
+        	dev->tbusy = 1;
+	        chan->tick_counter = jiffies;
+ 		clear_bit(2, (void*)&card->wandev.critical);
+		return 1;
+	}
+       	clear_bit(2, (void*)&card->wandev.critical);
+  
+    	if (dev->tbusy) {
 
-	if (dev->tbusy) 
-	{
 		/* If our device stays busy for at least 5 seconds then we will
-		 * kick start the device by making dev->tbusy = 0.  We expect
-		 * that our device never stays busy more than 5 seconds. So this                 * is only used as a last resort.
-		 */
-		++chan->if_send_busy;
+                 * kick start the device by making dev->tbusy = 0.  We expect
+                 * that our device never stays busy more than 5 seconds. So this                 
+		 * is only used as a last resort.
+                 */
+		
+		chan->drvstats_if_send.if_send_tbusy++;
 		++chan->ifstats.collisions;
-		if ((jiffies - chan->tick_counter) < (5 * HZ))
+
+		if ((jiffies - chan->tick_counter) < (5 * HZ)) {
 			return 1;
+		}
 
 		printk(KERN_INFO "%s: Transmit timed out\n", chan->name);
-		++chan->if_send_busy_timeout;
-		/* unbusy all the interfaces on the card */
-		for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
-			dev2->tbusy = 0;
-	}
+		chan->drvstats_if_send.if_send_tbusy_timeout ++;
+		dev->tbusy = 0;
+    	}
+
+	data = skb->data;
 	sendpacket = skb->data;
+        len = skb->len;
+
 	udp_type = udp_pkt_type(skb, card);
-	if (udp_type == UDP_DRVSTATS_TYPE) 
-	{
-		++chan->if_send_DRVSTATS_request;
-		process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, 0,
-					chan);
-		dev_kfree_skb(skb);
-		return 0;
-	}
-	else if (udp_type == UDP_FPIPE_TYPE)
-		++chan->if_send_FPIPE_request;
-	/* retreive source address in two forms: broadcast & multicast */
-	check_braddr = sendpacket[17];
-	check_mcaddr = sendpacket[14];
-	check_braddr = check_braddr << 8;
-	check_mcaddr = check_mcaddr << 8;
-	check_braddr |= sendpacket[16];
-	check_mcaddr |= sendpacket[15];
-	check_braddr = check_braddr << 8;
-	check_mcaddr = check_mcaddr << 8;
-	check_braddr |= sendpacket[15];
-	check_mcaddr |= sendpacket[16];
-	check_braddr = check_braddr << 8;
-	check_mcaddr = check_mcaddr << 8;
-	check_braddr |= sendpacket[14];
-	check_mcaddr |= sendpacket[17];
-	/* if the Source Address is a Multicast address */
-	if ((chan->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) &&
-	    (check_mcaddr <= 0xFFFFFFFE)) 
-	{
-		printk(KERN_INFO "%s: Multicast Src. Addr. silently discarded\n"
-		       ,card->devname);
-		dev_kfree_skb(skb);
-		++chan->ifstats.tx_dropped;
-		++chan->if_send_multicast;
+
+        if(udp_type != UDP_INVALID_TYPE) {
+                if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb,
+                        chan->dlci)) {
+                        adptr_flags->imask |= FR_INTR_TIMER;
+                        if (udp_type == UDP_FPIPE_TYPE){
+                                chan->drvstats_if_send.
+					if_send_PIPE_request ++;
+			}
+                }
 		return 0;
 	}
-	disable_irq(card->hw.irq);
-	++card->irq_dis_if_send_count;
-	if (test_and_set_bit(0, (void *) &card->wandev.critical)) 
-	{
-		if (card->wandev.critical == CRITICAL_IN_ISR) 
-		{
-			++chan->if_send_critical_ISR;
-			if (card->intr_mode == DLCI_LIST_INTR_MODE) 
-			{
-				/* The enable_tx_int flag is set here so that if
-				 * the critical flag is set due to an interrupt 
-				 * then we want to enable transmit interrupts 
-				 * again.
-				 */
-				card->wandev.enable_tx_int = 1;
-				/* Setting this flag to WAITING_TO_BE_ENABLED 
-				 * specifies that interrupt bit has to be 
-				 * enabled for that particular interface. 
-				 * (delayed interrupt)
-				 */
-				chan->tx_int_status = WAITING_TO_BE_ENABLED;
-				/* This is used for enabling dynamic calculation
-				 * of CIRs relative to the packet length.
-				 */
-				chan->pkt_length = skb->len;
-				dev->tbusy = 1;
-				chan->tick_counter = jiffies;
-			}
-			else
-			{
-				card->wandev.enable_tx_int = 1;
-				dev->tbusy = 1;
-				chan->tick_counter = jiffies;
-			}
-			save_flags(host_cpu_flags);
-			cli();
-			if ((!(--card->irq_dis_if_send_count)) &&
-			    (!card->irq_dis_poll_count))
-				enable_irq(card->hw.irq);
-			restore_flags(host_cpu_flags);
-			return 1;
-		}
-		++chan->if_send_critical_non_ISR;
-		++chan->ifstats.tx_dropped;
+
+	if((chan->usedby == API) && (len <= sizeof(api_tx_hdr_t))) {
+		//FIXME: increment some error statistic
+                dev_kfree_skb(skb);
+                return 0;
+ 	}
+ 
+	//FIXME: can we do better than sendpacket[2]?
+  	if ((chan->usedby == WANPIPE) && (sendpacket[2] == 0x45)) {
+               	/* check to see if the source IP address is a broadcast or */
+                /* multicast IP address */
+                if(chk_bcast_mcast_addr(card, dev, skb))
+                        return 0;
+	}
+
+	/* Lock the 508 card: SMP Supported */
+    	s508_s514_lock(card,&smp_flags);
+
+	if (test_and_set_bit(0, (void*)&card->wandev.critical)) {
+		chan->drvstats_if_send.if_send_critical_non_ISR ++;
+		chan->ifstats.tx_dropped ++;
+		printk(KERN_INFO "%s Critical in IF_SEND %02X\n", 
+				card->devname, card->wandev.critical);
 		dev_kfree_skb(skb);
-		save_flags(host_cpu_flags);
-		cli();
-		if ((!(--card->irq_dis_if_send_count)) &&
-		    (!card->irq_dis_poll_count))
-			enable_irq(card->hw.irq);
-		restore_flags(host_cpu_flags);
+		/* Unlock the 508 card */
+               	s508_s514_unlock(card,&smp_flags);
 		return 0;
 	}
-	card->wandev.critical = 0x21;
-	if (udp_type == UDP_FPIPE_TYPE) 
-	{
-		err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb,
-					   dev, 0, chan);
-	}
-	else if (card->wandev.state != WAN_CONNECTED) 
-	{
-		++chan->if_send_wan_disconnected;
+ 	
+	if (card->wandev.state != WAN_CONNECTED) {
+		chan->drvstats_if_send.if_send_wan_disconnected ++;
 		++chan->ifstats.tx_dropped;
-		++card->wandev.stats.tx_dropped;
-	}
-	else if (chan->state != WAN_CONNECTED) 
-	{
-		++chan->if_send_dlci_disconnected;
+        	++card->wandev.stats.tx_dropped;
+	
+	} else if (chan->state != WAN_CONNECTED) {
+		chan->drvstats_if_send.if_send_dlci_disconnected ++;
+		/* Critical area on 514, since disabl_irq is not used
+                 * thus, interrupt would execute a command at
+		 * the same time as if_send.
+                 */
+     		set_bit(1, (void*)&card->wandev.critical);
 		update_chan_state(dev);
-		++chan->ifstats.tx_dropped;
-		++card->wandev.stats.tx_dropped;
-	}
-	else if (!is_tx_ready(card, chan)) 
-	{
-		if (card->intr_mode == DLCI_LIST_INTR_MODE) 
-		{
-			dlci_interface->gen_interrupt |= 0x40;
-			dlci_interface->packet_length = skb->len;
-		}
-		dev->tbusy = 1;
-		chan->tick_counter = jiffies;
-		adptr_flags->imask |= 0x02;
-		++chan->if_send_no_bfrs;
-		retry = 1;
-	}
-	else
-	{
+		clear_bit(1, (void*)&card->wandev.critical);
+        	++chan->ifstats.tx_dropped;
+        	++card->wandev.stats.tx_dropped;
+
+	} else if (!is_tx_ready(card, chan)) {
+		printk(KERN_INFO "%s: Supporting for delayed transmit\n",card->devname);
+		setup_for_delayed_transmit(dev, data, len);
+		chan->drvstats_if_send.if_send_no_bfrs++;
+ 	} else {
 		send_data = 1;
-		/* If it's an IPX packet */
-		if (sendpacket[1] == 0x00 &&
-		    sendpacket[2] == 0x80 &&
-		    sendpacket[6] == 0x81 &&
-		    sendpacket[7] == 0x37) 
-		{
-			if (card->wandev.enable_IPX) 
-			{
-				switch_net_numbers(sendpacket,
-					 card->wandev.network_number, 0);
-			} 
-			else 
-			{
-				/* increment some statistic here! */
+		//FIXME: IPX is not implemented in this version of Frame Relay ?
+		if((chan->usedby == WANPIPE) &&
+		 	sendpacket[1] == 0x00 &&
+		    	sendpacket[2] == 0x80 &&
+		    	sendpacket[6] == 0x81 &&
+		    	sendpacket[7] == 0x37) {
+			
+			if( chan->enable_IPX ) {
+				switch_net_numbers(sendpacket, 
+						chan->network_number, 0);
+			} else {
+				//FIXME: Take this out when IPX is fixed 
+				printk(KERN_INFO 
+				"%s: WARNING: Unsupported IPX data in send, packet dropped\n",
+					card->devname);
 				send_data = 0;
 			}
 		}
-		if (send_data) 
-		{
-			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) 
-			{
-				if (card->intr_mode == DLCI_LIST_INTR_MODE) 
-				{
-					dlci_interface->gen_interrupt |= 0x40;
-					dlci_interface->packet_length = skb->len;
+
+		if (send_data) {
+			unsigned char attr = 0;
+
+			/* For an API transmission, get rid of the API header */
+                        if (chan->usedby == API) {
+                                api_tx_hdr_t* api_tx_hdr;
+           			api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00];
+                      		attr = api_tx_hdr->attr;
+				data += sizeof(api_tx_hdr_t);
+				len -= sizeof(api_tx_hdr_t);
+			}
+
+        		err = fr_send(card, chan->dlci, attr, len, data);
+			if (err) {
+				switch(err) {
+				case FRRES_CIR_OVERFLOW:
+				case FRRES_BUFFER_OVERFLOW:
+                			setup_for_delayed_transmit(dev, data,
+						len);
+           				chan->drvstats_if_send.
+						if_send_adptr_bfrs_full ++;
+					break;	
+				default:
+					chan->drvstats_if_send.
+						if_send_dlci_disconnected ++;
+        				++chan->ifstats.tx_dropped;
+        				++card->wandev.stats.tx_dropped;
+					break;
 				}
-				dev->tbusy = 1;
-				chan->tick_counter = jiffies;
-				adptr_flags->imask |= 0x02;
-				retry = 1;
-				++chan->if_send_adptr_bfrs_full;
-				++chan->ifstats.tx_errors;
-				++card->wandev.stats.tx_errors;
-			}
-			else 
-			{
-				++chan->if_send_bfrs_passed_to_adptr;
+			} else {
+				chan->drvstats_if_send.
+					if_send_bfr_passed_to_adptr++;
 				++chan->ifstats.tx_packets;
 				++card->wandev.stats.tx_packets;
-				chan->ifstats.tx_bytes += skb->len;
-				card->wandev.stats.tx_bytes += skb->len;
+                                chan->ifstats.tx_bytes += len;
+                                card->wandev.stats.tx_bytes += len;
 			}
 		}
 	}
-	if (!retry)
+
+        if (!dev->tbusy) {
 		dev_kfree_skb(skb);
+	}
 
-	card->wandev.critical = 0;
-	save_flags(host_cpu_flags);
-	cli();
-	if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
-		enable_irq(card->hw.irq);
-	restore_flags(host_cpu_flags);
-	return retry;
+        clear_bit(0, (void*)&card->wandev.critical);
+
+	s508_s514_unlock(card,&smp_flags);
+
+        return (dev->tbusy);
+}
+
+
+
+/*============================================================================
+ * Setup so that a frame can be transmitted on the occurence of a transmit
+ * interrupt.
+ */
+static void setup_for_delayed_transmit (struct device* dev, void* buf,
+	unsigned len)
+{
+        fr_channel_t* chan = dev->priv;
+        sdla_t* card = chan->card;
+        fr508_flags_t* adptr_flags = card->flags;
+        fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface;
+
+        if(chan->transmit_length) {
+                printk(KERN_INFO "%s: Big mess in setup_for_del...\n",
+				card->devname);
+                return;
+        }
+
+	if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) {
+		//FIXME: increment some statistic */
+		return;
+	}
+
+        chan->transmit_length = len;
+        memcpy(chan->transmit_buffer, buf, len);
+
+        dlci_interface->gen_interrupt |= FR_INTR_TXRDY;
+        dlci_interface->packet_length = len;
+        adptr_flags->imask |= FR_INTR_TXRDY;
+
+	card->u.f.tx_interrupts_pending ++;
+}
+
+
+/*============================================================================
+ * Check to see if the packet to be transmitted contains a broadcast or
+ * multicast source IP address.
+ * Return 0 if not broadcast/multicast address, otherwise return 1.
+ */
+
+static int chk_bcast_mcast_addr(sdla_t *card, struct device* dev,
+                                struct sk_buff *skb)
+{
+        u32 src_ip_addr;
+        u32 broadcast_ip_addr = 0;
+        struct in_device *in_dev;
+        fr_channel_t* chan = dev->priv;
+ 
+        /* read the IP source address from the outgoing packet */
+        src_ip_addr = *(u32 *)(skb->data + 14);
+
+        /* read the IP broadcast address for the device */
+        in_dev = dev->ip_ptr;
+        if(in_dev != NULL) {
+                struct in_ifaddr *ifa= in_dev->ifa_list;
+                if(ifa != NULL)
+                        broadcast_ip_addr = ifa->ifa_broadcast;
+                else
+                        return 0;
+        }
+
+        /* check if the IP Source Address is a Broadcast address */
+        if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) {                printk(KERN_INFO
+                        "%s: Broadcast Source Address silently discarded\n",
+                        card->devname);
+                dev_kfree_skb(skb);
+                ++ chan->ifstats.tx_dropped;
+                return 1;
+        }
+
+        /* check if the IP Source Address is a Multicast address */
+        if((chan->mc == WANOPT_NO) && (ntohl(src_ip_addr) >= 0xE0000001) &&
+                (ntohl(src_ip_addr) <= 0xFFFFFFFE)) {
+                printk(KERN_INFO
+                        "%s: Multicast Source Address silently discarded\n",
+                        card->devname);
+                dev_kfree_skb(skb);
+                ++ chan->ifstats.tx_dropped;
+                return 1;
+        }
+
+        return 0;
 }
 
 /*============================================================================
  * Reply to UDP Management system.
  * Return nothing.
  */
-
-static int reply_udp(unsigned char *data, unsigned int mbox_len)
+static int reply_udp( unsigned char *data, unsigned int mbox_len ) 
 {
-	unsigned short len, udp_length, temp, i, ip_length;
-	unsigned long sum;
+	unsigned short len, udp_length, temp, ip_length;
+	unsigned long ip_temp;
+	int even_bound = 0;
+
+  
+	fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)data; 
+
 	/* Set length of packet */
-	len = mbox_len + 62;
+	len = sizeof(fr_encap_hdr_t)+
+	      sizeof(ip_pkt_t)+ 
+	      sizeof(udp_pkt_t)+
+	      sizeof(wp_mgmt_t)+
+	      sizeof(cblock_t)+
+	      mbox_len;
+ 
+
 	/* fill in UDP reply */
-	data[38] = 0x02;
+	fr_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY;
+  
 	/* fill in UDP length */
-	udp_length = mbox_len + 40;
+	udp_length = sizeof(udp_pkt_t)+ 
+		     sizeof(wp_mgmt_t)+
+		     sizeof(cblock_t)+
+		     mbox_len; 
+
+
 	/* put it on an even boundary */
-	if (udp_length & 0x0001) 
-	{
+	if ( udp_length & 0x0001 ) {
 		udp_length += 1;
 		len += 1;
+		even_bound = 1;
 	}
-	temp = (udp_length << 8) | (udp_length >> 8);
-	memcpy(&data[26], &temp, 2);
+
+	temp = (udp_length<<8)|(udp_length>>8);
+	fr_udp_pkt->udp_pkt.udp_length = temp;
+	 
 	/* swap UDP ports */
-	memcpy(&temp, &data[22], 2);
-	memcpy(&data[22], &data[24], 2);
-	memcpy(&data[24], &temp, 2);
+	temp = fr_udp_pkt->udp_pkt.udp_src_port;
+	fr_udp_pkt->udp_pkt.udp_src_port = 
+			fr_udp_pkt->udp_pkt.udp_dst_port; 
+	fr_udp_pkt->udp_pkt.udp_dst_port = temp;
+
+
+
 	/* add UDP pseudo header */
 	temp = 0x1100;
-	memcpy(&data[udp_length + 22], &temp, 2);
-	temp = (udp_length << 8) | (udp_length >> 8);
-	memcpy(&data[udp_length + 24], &temp, 2);
+	*((unsigned short *)
+		(fr_udp_pkt->data+mbox_len+even_bound)) = temp;	
+	temp = (udp_length<<8)|(udp_length>>8);
+	*((unsigned short *)
+		(fr_udp_pkt->data+mbox_len+even_bound+2)) = temp;
+		 
 	/* calculate UDP checksum */
-	data[28] = data[29] = 0;
-	sum = 0;
-	for (i = 0; i < udp_length + 12; i += 2) 
-	{
-		memcpy(&temp, &data[14 + i], 2);
-		sum += (unsigned long) temp;
-	}
-	while (sum >> 16)
-		sum = (sum & 0xffffUL) + (sum >> 16);
+	fr_udp_pkt->udp_pkt.udp_checksum = 0;
+
+	fr_udp_pkt->udp_pkt.udp_checksum = 
+		calc_checksum(&data[UDP_OFFSET+sizeof(fr_encap_hdr_t)],
+			      udp_length+UDP_OFFSET);
 
-	temp = (unsigned short) sum;
-	temp = ~temp;
-	if (temp == 0)
-		temp = 0xffff;
-	memcpy(&data[28], &temp, 2);
 	/* fill in IP length */
-	ip_length = udp_length + 20;
-	temp = (ip_length << 8) | (ip_length >> 8);
-	memcpy(&data[4], &temp, 2);
+	ip_length = udp_length + sizeof(ip_pkt_t);
+	temp = (ip_length<<8)|(ip_length>>8);
+	fr_udp_pkt->ip_pkt.total_length = temp;
+  
 	/* swap IP addresses */
-	memcpy(&temp, &data[14], 2);
-	memcpy(&data[14], &data[18], 2);
-	memcpy(&data[18], &temp, 2);
-	memcpy(&temp, &data[16], 2);
-	memcpy(&data[16], &data[20], 2);
-	memcpy(&data[20], &temp, 2);
+	ip_temp = fr_udp_pkt->ip_pkt.ip_src_address;
+	fr_udp_pkt->ip_pkt.ip_src_address = 
+				fr_udp_pkt->ip_pkt.ip_dst_address;
+	fr_udp_pkt->ip_pkt.ip_dst_address = ip_temp;
+
+		 
 	/* fill in IP checksum */
-	data[12] = data[13] = 0;
-	sum = 0;
-	for (i = 0; i < 20; i += 2) 
-	{
-		memcpy(&temp, &data[2 + i], 2);
-		sum += (unsigned long) temp;
+	fr_udp_pkt->ip_pkt.hdr_checksum = 0;
+	fr_udp_pkt->ip_pkt.hdr_checksum = 
+		calc_checksum(&data[sizeof(fr_encap_hdr_t)],
+		      	      sizeof(ip_pkt_t));
+
+	return len;
+} /* reply_udp */
+
+unsigned short calc_checksum (char *data, int len)
+{
+	unsigned short temp; 
+	unsigned long sum=0;
+	int i;
+
+	for( i = 0; i <len; i+=2 ) {
+		memcpy(&temp,&data[i],2);
+		sum += (unsigned long)temp;
 	}
-	while (sum >> 16)
+
+	while (sum >> 16 ) {
 		sum = (sum & 0xffffUL) + (sum >> 16);
-	temp = (unsigned short) sum;
+	}
+
+	temp = (unsigned short)sum;
 	temp = ~temp;
-	if (temp == 0)
+
+	if( temp == 0 ) 
 		temp = 0xffff;
-	memcpy(&data[12], &temp, 2);
-	return len;
-}				/* reply_udp */
+
+	return temp;	
+}
+
 /*
    If incoming is 0 (outgoing)- if the net numbers is ours make it 0
    if incoming is 1 - if the net number is 0 make it ours 
- */
 
+*/
 static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
 {
 	unsigned long pnetwork_number;
-	pnetwork_number = (unsigned long) ((sendpacket[14] << 24) +
-			 (sendpacket[15] << 16) + (sendpacket[16] << 8) +
-					   sendpacket[17]);
+
+	pnetwork_number = (unsigned long)((sendpacket[14] << 24) + 
+			  (sendpacket[15] << 16) + (sendpacket[16] << 8) + 
+			  sendpacket[17]);
+
 	if (!incoming) {
 		/* If the destination network number is ours, make it 0 */
-		if (pnetwork_number == network_number) {
-			sendpacket[14] = sendpacket[15] = sendpacket[16] =
-			    sendpacket[17] = 0x00;
+		if( pnetwork_number == network_number) {
+			sendpacket[14] = sendpacket[15] = sendpacket[16] = 
+					 sendpacket[17] = 0x00;
 		}
 	} else {
 		/* If the incoming network is 0, make it ours */
-		if (pnetwork_number == 0) 
-		{
-			sendpacket[14] = (unsigned char) (network_number >> 24);
-			sendpacket[15] = (unsigned char) ((network_number &
-						      0x00FF0000) >> 16);
-			sendpacket[16] = (unsigned char) ((network_number &
-						       0x0000FF00) >> 8);
-			sendpacket[17] = (unsigned char) (network_number &
-							  0x000000FF);
+		if( pnetwork_number == 0) {
+			sendpacket[14] = (unsigned char)(network_number >> 24);
+			sendpacket[15] = (unsigned char)((network_number & 
+					 0x00FF0000) >> 16);
+			sendpacket[16] = (unsigned char)((network_number & 
+					 0x0000FF00) >> 8);
+			sendpacket[17] = (unsigned char)(network_number & 
+					 0x000000FF);
 		}
 	}
-	pnetwork_number = (unsigned long) ((sendpacket[26] << 24) +
-			 (sendpacket[27] << 16) + (sendpacket[28] << 8) +
-					   sendpacket[29]);
-	if (!incoming) {
+
+
+	pnetwork_number = (unsigned long)((sendpacket[26] << 24) + 
+			  (sendpacket[27] << 16) + (sendpacket[28] << 8) + 
+			  sendpacket[29]);
+
+	if( !incoming ) {
 		/* If the source network is ours, make it 0 */
-		if (pnetwork_number == network_number) 
-		{
-			sendpacket[26] = sendpacket[27] = sendpacket[28] =
-			    sendpacket[29] = 0x00;
+		if( pnetwork_number == network_number) {
+			sendpacket[26] = sendpacket[27] = sendpacket[28] = 
+					 sendpacket[29] = 0x00;
 		}
 	} else {
 		/* If the source network is 0, make it ours */
-		if (pnetwork_number == 0) {
-			sendpacket[26] = (unsigned char) (network_number >> 24);
-			sendpacket[27] = (unsigned char) ((network_number &
-						      0x00FF0000) >> 16);
-			sendpacket[28] = (unsigned char) ((network_number &
-						       0x0000FF00) >> 8);
-			sendpacket[29] = (unsigned char) (network_number &
-							  0x000000FF);
+		if( pnetwork_number == 0 ) {
+			sendpacket[26] = (unsigned char)(network_number >> 24);
+			sendpacket[27] = (unsigned char)((network_number & 
+					 0x00FF0000) >> 16);
+			sendpacket[28] = (unsigned char)((network_number & 
+					 0x0000FF00) >> 8);
+			sendpacket[29] = (unsigned char)(network_number & 
+					 0x000000FF);
 		}
 	}
-}				/* switch_net_numbers */
+} /* switch_net_numbers */
 
 /*============================================================================
- * Get Ethernet-style interface statistics.
- * Return a pointer to struct net_device_stats.
+ * Get ethernet-style interface statistics.
+ * Return a pointer to struct enet_statistics.
  */
-
-static struct net_device_stats *if_stats(struct device *dev)
+static struct enet_statistics* if_stats (struct device* dev)
 {
-	fr_channel_t *chan = dev->priv;
-	if(chan==NULL)
+	fr_channel_t* chan = dev->priv;
+	
+	if(chan == NULL)
 		return NULL;
-		
+
 	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)
+static void fr_isr (sdla_t* card)
 {
-	fr508_flags_t *flags = card->flags;
-	fr_buf_ctl_t *bctl;
+	fr508_flags_t* flags = card->flags;
 	char *ptr = &flags->iflag;
-	struct device *dev = card->wandev.dev;
-	struct device *dev2;
-	int i;
-	unsigned long host_cpu_flags;
-	unsigned disable_tx_intr = 1;
-	fr_channel_t *chan;
-	fr_dlci_interface_t *dlci_interface;
+	int i,err;
+	fr_mbox_t* mbox = card->mbox;
+
 	/* This flag prevents nesting of interrupts.  See sdla_isr() routine
-	 * in sdlamain.c. 
+         * in sdlamain.c. 
 	 */
 	card->in_isr = 1;
+	
 	++card->statistics.isr_entry;
-	if (test_and_set_bit(0, (void *) &card->wandev.critical)) 
-	{
-		printk(KERN_INFO "fr508_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, flags->iflag);
-		++card->statistics.isr_already_critical;
+
+	if(test_bit(1, (void*)&card->wandev.critical)) {
+		card->wandev.critical = 0;
+		flags->iflag = 0;
 		card->in_isr = 0;
 		return;
 	}
-	/* For all interrupts set the critical flag to CRITICAL_RX_INTR.
-	 * If the if_send routine is called with this flag set it will set
-	 * the enable transmit flag to 1. (for a delayed interrupt)
-	 */
-	card->wandev.critical = CRITICAL_IN_ISR;
-	card->dlci_int_mode_unbusy = 0;
-	card->buff_int_mode_unbusy = 0;
-	switch (flags->iflag) 
-	{
-		case 0x01:		/* receive interrupt */
-			++card->statistics.isr_rx;
-			fr508_rx_intr(card);
-			break;
-		case 0x02:		/* transmit interrupt */
-			++card->statistics.isr_tx;
-			bctl = (void *) (flags->tse_offs - FR_MB_VECTOR +
-				 card->hw.dpmbase);
-			bctl->flag = 0xA0;
-			if (card->intr_mode == DLCI_LIST_INTR_MODE) 
-			{
-				/* Find the structure and make it unbusy */
-				dev = find_channel(card, flags->dlci);
-				dev->tbusy = 0;
-				/* This is used to perform devtint at the
-				 * end of the isr 
-				 */
-				card->dlci_int_mode_unbusy = 1;
-				/* check to see if any other interfaces are
-				 * busy. If so then do not disable the tx
-				 * interrupts 
-				 */
-				for (dev2 = card->wandev.dev; dev2;
-					dev2 = dev2->slave) 
-				{
-					if (dev2->tbusy == 1) 
-					{
-						disable_tx_intr = 0;
-						break;
-					}
-				}
-				if (disable_tx_intr)
-					flags->imask &= ~0x02;
-			} 
-			else if (card->intr_mode == BUFFER_INTR_MODE) 
-			{
-				for (dev2 = card->wandev.dev; dev2;
-					dev2 = dev2->slave) 
-				{
-					if (!dev2 || !dev2->start) 
-					{
-						++card->statistics.tx_intr_dev_not_started;
-						continue;
-					}
-					if (dev2->tbusy) 
-					{
-						card->buff_int_mode_unbusy = 1;
-						((fr_channel_t *) dev2->priv)->dev_pending_devtint = 1;
-						dev2->tbusy = 0;
-					} 
-					else
-						((fr_channel_t *) dev2->priv)->dev_pending_devtint = 0;
-				}
-				flags->imask &= ~0x02;
-			}
-			break;
-		case 0x08:
-			Intr_test_counter++;
+
+        if(card->hw.type != SDLA_S514) {
+		if (test_and_set_bit(0, (void*)&card->wandev.critical)) {
+                        printk(KERN_INFO "%s: Critical while in ISR (0x%02X)\n",
+                                card->devname, card->wandev.critical);
+			++card->statistics.isr_already_critical;
+			card->in_isr = 0;
+			return;
+		}
+	}
+
+	switch (flags->iflag) {
+
+                case FR_INTR_RXRDY:  /* receive interrupt */
+	    		++card->statistics.isr_rx;
+          		rx_intr(card);
+            		break;
+
+
+                case FR_INTR_TXRDY:  /* transmit interrupt */
+	    		++ card->statistics.isr_tx; 
+			tx_intr(card); 
+            		break;
+
+                case FR_INTR_READY:
+	    		Intr_test_counter++;
 			++card->statistics.isr_intr_test;
+	    		break;	
+
+                case FR_INTR_DLC: /* Event interrupt occured */
+			mbox->cmd.command = FR_READ_STATUS;
+			mbox->cmd.length = 0;
+			err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+			if (err)
+				fr_event(card, err, mbox);
+			break;
+
+                case FR_INTR_TIMER:  /* Timer interrupt */
+			timer_intr(card);
 			break;
+	
 		default:
-			++card->statistics.isr_spurious;
-			spur_intr(card);
-			printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n",
-			       card->devname, flags->iflag);
-			printk(KERN_INFO "%s: ID Bytes = ", card->devname);
-			for (i = 0; i < 8; i++)
+	    		++card->statistics.isr_spurious;
+            		spur_intr(card);
+	    		printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", 
+				card->devname, flags->iflag);
+	    
+			printk(KERN_INFO "%s: ID Bytes = ",card->devname);
+ 	    		for(i = 0; i < 8; i ++)
 				printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
-			printk(KERN_INFO "\n");
+	   	 	printk(KERN_INFO "\n");	
+            
 			break;
-	}
-	card->wandev.critical = CRITICAL_INTR_HANDLED;
-	if (card->wandev.enable_tx_int) 
-	{
-		if (card->intr_mode == DLCI_LIST_INTR_MODE) 
-		{
-			for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) 
-			{
-				chan = dev2->priv;
-				if (chan->tx_int_status == WAITING_TO_BE_ENABLED) 
-				{
-					dlci_interface = chan->dlci_int_interface;
-					dlci_interface->gen_interrupt |= 0x40;
-					dlci_interface->packet_length = chan->pkt_length;
-					chan->tx_int_status = DISABLED;
-				}
-			}
-		}
-		card->wandev.enable_tx_int = 0;
-		flags->imask |= 0x02;
-		++card->statistics.isr_enable_tx_int;
-	}
-	save_flags(host_cpu_flags);
-	cli();
+    	}
+
 	card->in_isr = 0;
-	card->wandev.critical = 0xD1;
 	flags->iflag = 0;
-	card->wandev.critical = 0;
-	restore_flags(host_cpu_flags);
-	/* Device is now ready to send. The instant this is executed the If_Send
-	   routine is called. That is why this is put at the bottom of the ISR
-	   to prevent a endless loop condition caused by repeated Interrupts and
-	   enable_tx_int flag.
-	 */
-	if (card->dlci_int_mode_unbusy)
-		mark_bh(NET_BH);
-	if (card->buff_int_mode_unbusy) 
-	{
-		for (;;) 
-		{
-			if (((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint == 1) 
-			{
-				((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint = 0;
-				mark_bh(NET_BH);
-			}
-			if ((card->devs_struct)->next == card->dev_to_devtint_next)
-				break;
-			card->devs_struct = (card->devs_struct)->next;
-		}
-		card->devs_struct = (card->dev_to_devtint_next)->next;
-		card->dev_to_devtint_next = card->devs_struct;
-	}
+        if(card->hw.type != SDLA_S514)
+                clear_bit(0, (void*)&card->wandev.critical);
 }
+
+
+
 /*============================================================================
  * Receive interrupt handler.
- */
+ * When a receive interrupt occurs do the following:
+ *	1- Find the structure for the dlci that the interrupt occured on
+ *      2- If it doesn't exist then print appropriate msg and goto step 8. 
+ * 	3- If it exist then copy data to a skb.
+ * 	4- If skb contains Sangoma UDP data then process them
+ *	5- If skb contains IPXWAN data then send IPXWAN reply packets
+ *	6- If skb contains Inverse Arp data then send Inv Arp replies
+ *	7- If skb contains any other data then decapsulate the packet and
+ *	   send it to the stack.
+ * 	8- Release the receive element and update receive pointers on the board 
+ */
+static void rx_intr (sdla_t* card)
+{
+	fr_rx_buf_ctl_t* frbuf = card->rxmb;
+	fr508_flags_t* flags = card->flags;
+	fr_channel_t* chan;
+	char *ptr = &flags->iflag;
+	struct sk_buff* skb;
+	struct device* dev;
+	void* buf;
+	unsigned dlci, len, offs, len_incl_hdr;
+	int i, udp_type;	
+
+	if (frbuf->flag != 0x01) {
+
+		printk(KERN_INFO 
+			"%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", 
+			card->devname, (unsigned)frbuf, frbuf->flag);
+      
+		printk(KERN_INFO "%s: ID Bytes = ",card->devname);
+ 		for(i = 0; i < 8; i ++)
+			printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
+		printk(KERN_INFO "\n");
+	
+		++card->statistics.rx_intr_corrupt_rx_bfr;
+		return;
+	}
+
+	len  = frbuf->length;
+	dlci = frbuf->dlci;
+	offs = frbuf->offset;
 
-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;
-	unsigned char *sendpacket;
-	unsigned char buf2[3];
-	int udp_type;
-	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);
-		sdla_mapmem(&card->hw, FR_MB_VECTOR);
-	}
-	chan = dev->priv;
-	if (!dev->start) 
-	{
-		++chan->ifstats.rx_dropped;
-		sdla_mapmem(&card->hw, FR_MB_VECTOR);
-	}
-	/* 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;
-		sdla_mapmem(&card->hw, FR_MB_VECTOR);
-	}
-	/* Copy data to the socket buffer */
-	buf = skb_put(skb, len);
-	memcpy(buf, mbox->data, len);
-	sdla_mapmem(&card->hw, FR_MB_VECTOR);
-	/* Check if it's a UDP management packet */
-	sendpacket = skb->data;
-	memcpy(&buf2, &card->wandev.udp_port, 2);
-	udp_type = udp_pkt_type(skb, card);
-	if ((udp_type == UDP_FPIPE_TYPE) || (udp_type == UDP_DRVSTATS_TYPE)) 
-	{
-		if (udp_type == UDP_DRVSTATS_TYPE) 
-		{
-			++chan->rx_intr_DRVSTATS_request;
-			process_udp_driver_call(UDP_PKT_FRM_NETWORK, card, skb,
-						dev, dlci, chan);
-		}
-		else
-		{
-			++chan->rx_intr_FPIPE_request;
-			process_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb,
-					     dev, dlci, chan);
-		}
-	}
-	else
-	{
-		/* Decapsulate packet and pass it up the protocol stack */
-		skb->dev = dev;
-		buf = skb_pull(skb, 1);		/* remove hardware header */
-		if (!wanrouter_type_trans(skb, dev)) 
-		{
-			/* can't decapsulate packet */
-			dev_kfree_skb(skb);
-			++chan->ifstats.rx_errors;
-			++card->wandev.stats.rx_errors;
-		}
-		else 
-		{
-			netif_rx(skb);
-			++chan->ifstats.rx_packets;
-			++card->wandev.stats.rx_packets;
-			chan->ifstats.rx_bytes += skb->len;
-			card->wandev.stats.rx_bytes += skb->len;
-		}
-	}
-	sdla_mapmem(&card->hw, FR_MB_VECTOR);
-}
-/*============================================================================
- * Receive interrupt handler.
- */
+        
+	if (dev == NULL) {
 
-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;
-	unsigned rx_count = 0;
-	fr508_flags_t *flags = card->flags;
-	char *ptr = &flags->iflag;
-	int i, err, udp_type;
-	if (frbuf->flag != 0x01) 
-	{
-		printk(KERN_INFO
-		       "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n",
-		       card->devname, (unsigned) frbuf, frbuf->flag);
-		printk(KERN_INFO "%s: ID Bytes = ", card->devname);
-		for (i = 0; i < 8; i++)
-			printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
-		printk(KERN_INFO "\n");
-		++card->statistics.rx_intr_corrupt_rx_bfr;
-		return;
-	}
-	
-	do 
-	{
-		len = frbuf->length;
-		dlci = frbuf->dlci;
-		offs = frbuf->offset;
-		/* Find network interface for this packet */
-		dev = find_channel(card, dlci);
+		/* unconfigured DLCI, so discard packet */
+   		printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n",
+                                                card->devname, dlci);
+		++card->statistics.rx_intr_on_orphaned_DLCI; 
+
+       	} else {
 		chan = dev->priv;
-		if (dev == NULL) 
-		{
-			/* Invalid channel, discard packet */
-			printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n"
-			       ,card->devname, dlci);
-			++card->statistics.rx_intr_on_orphaned_DLCI;
-		}
-		else
-		{
-			skb = dev_alloc_skb(len);
-			if (!dev->start || (skb == NULL)) 
-			{
-				++chan->ifstats.rx_dropped;
-				if (dev->start) 
-				{
-					printk(KERN_INFO
-					       "%s: no socket buffers available!\n",
-					       card->devname);
-					++chan->rx_intr_no_socket;
-				} else
-					++chan->rx_intr_dev_not_started;
+
+   		skb = dev_alloc_skb(len); 
+
+		if (!dev->start || (skb == NULL)) { 
+			++chan->ifstats.rx_dropped;
+		
+			if(dev->start) {
+
+				printk(KERN_INFO 
+				"%s: no socket buffers available!\n", 
+				card->devname);
+	    			chan->drvstats_rx_intr.rx_intr_no_socket ++;
+                		
+			} else
+				chan->drvstats_rx_intr.
+					rx_intr_dev_not_started ++;
+		} else {
+			/* Copy data to the socket buffer */
+			if ((offs + len) > card->u.f.rx_top + 1) {
+				unsigned tmp = card->u.f.rx_top - offs + 1;
+
+				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);
+
+			udp_type = udp_pkt_type( skb, card );
+
+                        if(udp_type != UDP_INVALID_TYPE) {
+                                if(store_udp_mgmt_pkt(udp_type,
+                                        UDP_PKT_FRM_NETWORK, card, skb, dlci)) {
+                                        flags->imask |= FR_INTR_TIMER;
+                                        if (udp_type == UDP_FPIPE_TYPE){
+                                                chan->drvstats_rx_intr.
+						    rx_intr_PIPE_request ++;
+					}
+				}			
 			}
-			else
-			{
-				/* Copy data to the socket buffer */
-				if ((offs + len) > card->u.f.rx_top + 1) 
-				{
-					unsigned tmp = card->u.f.rx_top - offs + 1;
-					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);
-				udp_type = udp_pkt_type(skb, card);
-				if (udp_type == UDP_DRVSTATS_TYPE) 
-				{
-					++chan->rx_intr_DRVSTATS_request;
-					process_udp_driver_call(
-					  UDP_PKT_FRM_NETWORK, card, skb,
-							dev, dlci, chan);
+
+			else if (chan->usedby == API) {
+				api_rx_hdr_t* api_rx_hdr;
+				chan->drvstats_rx_intr.
+                                	rx_intr_bfr_passed_to_stack ++;
+				chan->ifstats.rx_packets ++;
+                                card->wandev.stats.rx_packets ++;
+				chan->ifstats.rx_bytes += skb->len;
+				card->wandev.stats.rx_bytes += skb->len;
+
+				skb_push(skb, sizeof(api_rx_hdr_t));
+				api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00];
+				api_rx_hdr->attr = frbuf->attr;
+				api_rx_hdr->time_stamp = frbuf->tmstamp;
+				skb->protocol = htons(0x16);
+				skb->pkt_type = PACKET_HOST;
+                                /* Pass it up the protocol stack */
+                                skb->dev = dev;
+                                skb->mac.raw  = skb->data;
+                                netif_rx(skb);
+
+			} else if (handle_IPXWAN(skb->data,chan->name,
+				chan->enable_IPX, chan->network_number)) {
+				if (chan->enable_IPX) {
+                                        fr_send(card, dlci, 0, skb->len,
+						skb->data);
 				}
-				else if (udp_type == UDP_FPIPE_TYPE) 
-				{
-					++chan->rx_intr_FPIPE_request;
-					err = process_udp_mgmt_pkt(
-					       UDP_PKT_FRM_NETWORK, card,
-						   skb, dev, dlci, chan);
+				dev_kfree_skb(skb);
+
+/*FIXME: Fix the ARPS in next release
+
+			} else if (is_arp(skb->data)) {
+				if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) {
+					printk (KERN_INFO "%s: Error processing ARP Packet.\n", card->devname);
 				}
-				else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number)) 
-				{
-					if (card->wandev.enable_IPX) 
-						fr508_send(card, dlci, 0, skb->len, skb->data);
-				} 
-				else
-				{
-					/* Decapsulate packet and pass it up the
-					   protocol stack */
-					skb->dev = dev;
-					/* remove hardware header */
-					buf = skb_pull(skb, 1);
-					if (!wanrouter_type_trans(skb, dev)) 
-					{
-						/* can't decapsulate packet */
-						dev_kfree_skb(skb);
-						++chan->
-						    rx_intr_bfr_not_passed_to_stack;
-						++chan->
-						    ifstats.rx_errors;
-						++card->
-						    wandev.stats.rx_errors;
-					}
-					else
-					{
-						netif_rx(skb);
-						++chan->rx_intr_bfr_passed_to_stack;
-						++chan->ifstats.rx_packets;
-						++card->wandev.stats.rx_packets;
-						chan->ifstats.rx_bytes += skb->len;
-						card->wandev.stats.rx_bytes += skb->len;
-					}
+				dev_kfree_skb(skb);
+*/
+
+			} else if ( skb->data[0] != 0x03) {
+				printk(KERN_INFO "%s: Non IETF packet discarded.\n", card->devname);
+				dev_kfree_skb(skb);
+
+			} else {
+
+				len_incl_hdr = skb->len;
+                    		/* Decapsulate packet and pass it up the
+			   	   protocol stack */
+				skb->dev = dev;
+
+				/* remove hardware header */
+				buf = skb_pull(skb, 1); 
+
+				if (!wanrouter_type_trans(skb, dev)) {
+					
+					/* can't decapsulate packet */
+					dev_kfree_skb(skb);
+					chan->drvstats_rx_intr.
+					     rx_intr_bfr_not_passed_to_stack ++;
+ 					++ chan->ifstats.rx_errors;
+		                       	++ card->wandev.stats.rx_errors;
+					
+				} else {
+					netif_rx(skb);
+					chan->drvstats_rx_intr.
+						rx_intr_bfr_passed_to_stack ++;
+					++ chan->ifstats.rx_packets;
+					++ card->wandev.stats.rx_packets;
+                                        chan->ifstats.rx_bytes += len_incl_hdr;
+                                        card->wandev.stats.rx_bytes += 
+						len_incl_hdr;
 				}
-			}
-		}
-		/* 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;
-		/* The loop put in is temporary, that is why the break is
-		 * placed here. (?????)
-		 */
-		break;
-		frbuf = card->rxmb;
-	}
-	while (frbuf->flag && ((++rx_count) < 4));
+                	}
+            	}
+       	}
+
+       	/* 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)
+static void tx_intr(sdla_t *card)
 {
-	struct device *dev = card->wandev.dev;
-	if (card->intr_mode == BUFFER_INTR_MODE) 
-	{
-		for (; dev; dev = dev->slave) 
-		{
-			if (!dev || !dev->start) 
-			{
-				++card->statistics.tx_intr_dev_not_started;
-				continue;
+        fr508_flags_t* flags = card->flags;
+        fr_tx_buf_ctl_t* bctl;
+        struct device* dev = card->wandev.dev;
+        fr_channel_t* chan;
+
+        if(card->hw.type == SDLA_S514){
+                bctl = (void*)(flags->tse_offs + card->hw.dpmbase);
+        }else{
+                bctl = (void*)(flags->tse_offs - FR_MB_VECTOR +
+                        card->hw.dpmbase);
+	}
+
+        /* Find the structure and make it unbusy */
+        dev = find_channel(card, flags->dlci);
+        chan = dev->priv;
+
+        if(!chan->transmit_length) {
+                printk(KERN_INFO "%s: tx int error - transmit length zero\n",
+				card->wandev.name);
+                return;
+        }
+
+	/* If the 'if_send()' procedure is currently checking the 'tbusy'
+	   status, then we cannot transmit. Instead, we configure the microcode
+	   so as to re-issue this transmit interrupt at a later stage. 
+	*/
+	if (test_bit(2, (void*)&card->wandev.critical)) {
+		fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface;
+		bctl->flag = 0xA0;
+		dlci_interface->gen_interrupt |= FR_INTR_TXRDY;
+		printk(KERN_INFO "%s: TX Interrupt Detected busy if_send\n",card->devname);
+
+ 	} else {
+        	bctl->dlci = flags->dlci;
+	        bctl->length = chan->transmit_length;
+        	sdla_poke(&card->hw, bctl->offset, chan->transmit_buffer,
+                	chan->transmit_length);
+	        bctl->flag = 0xC0;
+
+		++chan->ifstats.tx_packets;
+		++card->wandev.stats.tx_packets;
+		chan->ifstats.tx_bytes += chan->transmit_length;
+		card->wandev.stats.tx_bytes += chan->transmit_length;
+        	chan->transmit_length = 0;
+
+	        /* if any other interfaces have transmit interrupts pending, */
+		/* do not disable the global transmit interrupt */
+		if(!(-- card->u.f.tx_interrupts_pending))
+        	        flags->imask &= ~FR_INTR_TXRDY;
+
+ 		dev->tbusy = 0;
+		mark_bh(NET_BH);
+	}
+}
+
+
+/*============================================================================
+ * Timer interrupt handler.
+ FIXME: update comments as we modify the code
+ * The timer interrupt is used for three purposes:
+ *    1) Processing udp calls from 'fpipemon'.
+ *    2) Processing update calls from /proc file system
+ *    2) Reading board-level statistics for updating the proc file system.
+ *    3) Sending inverse ARP request packets.
+ */
+static void timer_intr(sdla_t *card)
+{
+	fr508_flags_t* flags = card->flags;
+
+        if(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) {
+		if(card->u.f.udp_type == UDP_FPIPE_TYPE) {
+                    	if(process_udp_mgmt_pkt(card)) {
+		                card->u.f.timer_int_enabled &=
+					~TMR_INT_ENABLED_UDP;
 			}
-			dev->tbusy = 0;
-			mark_bh(NET_BH);
 		}
+        }
+
+	if(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) {
+		fr_get_err_stats(card);
+		fr_get_stats(card);
+		card->u.f.update_comms_stats = 0;
+		card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE;
 	}
-	else
-	{
-		dev->tbusy = 0;
-		mark_bh(NET_BH);
+
+
+//FIXME: Fix the dynamic IP addressing
+/*
+goto L4;
+
+	// Used to send inarp request at given interval 
+	if (card->wandev.state == WAN_CONNECTED) {
+        	int num_remaining = 0;
+                for (dev=card->wandev.dev;dev;dev=dev->slave) {
+                	fr_channel_t *chan = dev->priv;
+
+                        if (chan->inarp == INARP_REQUEST &&
+                        	chan->state == WAN_CONNECTED) {
+                                num_remaining++;
+
+                                if ((jiffies - chan->inarp_tick) > (chan->inarp_interval * HZ)) {
+                                	send_inarp_request(card,dev);
+                                	chan->inarp_tick = jiffies;
+                                }
+			}
+		}
+		if (!num_remaining) {   // no more to process 
+                        flags->imask &= ~FR_INTR_TIMER;
+		}
 	}
+L4:
+	;
+*/
+        if(!card->u.f.timer_int_enabled)
+                flags->imask &= ~FR_INTR_TIMER;
 }
 
+
 /*============================================================================
  * Spurious interrupt handler.
  * o print a warning
  * o 
- * If number of spurious interrupts exceeded some limit, then ???
  */
-
-static void spur_intr(sdla_t * card)
+static void spur_intr (sdla_t* card)
 {
 	printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
 }
 
-/*
-   Return 0 for non-IPXWAN packet
-   1 for IPXWAN packet or IPX is not enabled!
+//FIXME: Fix the IPX in next version
+/*===========================================================================
+ *  Return 0 for non-IPXWAN packet
+ *         1 for IPXWAN packet or IPX is not enabled!
+ *  FIXME: Use a IPX structure here not offsets
  */
-
 static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number)
 {
 	int i;
-	if (sendpacket[1] == 0x00 &&
+
+	if( sendpacket[1] == 0x00 &&
 	    sendpacket[2] == 0x80 &&
 	    sendpacket[6] == 0x81 &&
-	    sendpacket[7] == 0x37) 
-	{
+	    sendpacket[7] == 0x37) { 
+
 		/* It's an IPX packet */
-		if (!enable_IPX) {
+		if(!enable_IPX) {
 			/* Return 1 so we don't pass it up the stack. */
+			//FIXME: Take this out when IPX is fixed
+			printk (KERN_INFO 
+				"%s: WARNING: Unsupported IPX packet received and dropped\n",
+					devname);
 			return 1;
 		}
-	}
-	else
-	{
+	} else {
 		/* It's not IPX so return and pass it up the stack. */
 		return 0;
 	}
-	if (sendpacket[24] == 0x90 &&
-	    sendpacket[25] == 0x04) 
+
+	if( sendpacket[24] == 0x90 &&
+	    sendpacket[25] == 0x04)
 	{
 		/* It's IPXWAN */
-		if (sendpacket[10] == 0x02 &&
-		    sendpacket[42] == 0x00) 
+
+		if( sendpacket[10] == 0x02 &&
+		    sendpacket[42] == 0x00)
 		{
 			/* It's a timer request packet */
-			printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname);
-			/* Go through the routing options and answer no to every */
-			/* option except Unnumbered RIP/SAP */
-			for (i = 49; sendpacket[i] == 0x00; i += 5) 
+			printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname);
+
+			/* Go through the routing options and answer no to every
+			 * option except Unnumbered RIP/SAP
+			 */
+			for(i = 49; sendpacket[i] == 0x00; i += 5)
 			{
 				/* 0x02 is the option for Unnumbered RIP/SAP */
-				if (sendpacket[i + 4] != 0x02) 
+				if( sendpacket[i + 4] != 0x02)
 				{
 					sendpacket[i + 1] = 0;
 				}
 			}
+
 			/* Skip over the extended Node ID option */
-			if (sendpacket[i] == 0x04) 
+			if( sendpacket[i] == 0x04 )
+			{
 				i += 8;
-			/* We also want to turn off all header compression opt. */
-			for (; sendpacket[i] == 0x80;) 
+			}
+
+			/* We also want to turn off all header compression opt.
+			 */
+			for(; sendpacket[i] == 0x80 ;)
 			{
 				sendpacket[i + 1] = 0;
 				i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
 			}
+
 			/* Set the packet type to timer response */
 			sendpacket[42] = 0x01;
-			printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname);
+
+			printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname);
 		}
-		else if (sendpacket[42] == 0x02) 
+		else if( sendpacket[42] == 0x02 )
 		{
 			/* This is an information request packet */
-			printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname);
+			printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname);
+
 			/* Set the packet type to information response */
 			sendpacket[42] = 0x03;
+
 			/* Set the router name */
 			sendpacket[59] = 'F';
 			sendpacket[60] = 'P';
@@ -1756,465 +2083,558 @@
 			sendpacket[63] = 'E';
 			sendpacket[64] = '-';
 			sendpacket[65] = CVHexToAscii(network_number >> 28);
-			sendpacket[66] = CVHexToAscii((network_number & 0x0F000000) >> 24);
-			sendpacket[67] = CVHexToAscii((network_number & 0x00F00000) >> 20);
-			sendpacket[68] = CVHexToAscii((network_number & 0x000F0000) >> 16);
-			sendpacket[69] = CVHexToAscii((network_number & 0x0000F000) >> 12);
-			sendpacket[70] = CVHexToAscii((network_number & 0x00000F00) >> 8);
-			sendpacket[71] = CVHexToAscii((network_number & 0x000000F0) >> 4);
+			sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24);
+			sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20);
+			sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16);
+			sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12);
+			sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8);
+			sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4);
 			sendpacket[72] = CVHexToAscii(network_number & 0x0000000F);
-			for (i = 73; i < 107; i += 1) 
+			for(i = 73; i < 107; i+= 1)
+			{
 				sendpacket[i] = 0;
-			printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname);
+			}
+
+			printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname);
 		}
 		else
 		{
-			printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname);
+			printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname);
 			return 0;
 		}
+
 		/* Set the WNodeID to our network address */
-		sendpacket[43] = (unsigned char) (network_number >> 24);
-		sendpacket[44] = (unsigned char) ((network_number & 0x00FF0000) >> 16);
-		sendpacket[45] = (unsigned char) ((network_number & 0x0000FF00) >> 8);
-		sendpacket[46] = (unsigned char) (network_number & 0x000000FF);
+		sendpacket[43] = (unsigned char)(network_number >> 24);
+		sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16);
+		sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8);
+		sendpacket[46] = (unsigned char)(network_number & 0x000000FF);
+
 		return 1;
 	}
-	/* If we get here, its an IPX-data packet so it'll get passed up the stack. */
-	/* switch the network numbers */
-	switch_net_numbers(sendpacket, network_number, 1);
+
+	/* If we get here, its an IPX-data packet so it'll get passed up the 
+	 * stack.
+	 * switch the network numbers 
+	 */
+	switch_net_numbers(sendpacket, network_number ,1);
 	return 0;
 }
+/*============================================================================
+ * Process Route.
+ * This routine is called as a polling routine to dynamically add/delete routes
+ * negotiated by inverse ARP.  It is in this "task" because we don't want routes
+ * to be added while in interrupt context.
+*/
+
+static void process_route (sdla_t* card)
+{
+	struct device* dev;
+	struct in_device *in_dev;
+    	struct rtentry route;
+        int err = 0;
+        mm_segment_t fs;
+
+
+	/* Dynamic Route adding/removing */
+	for (dev = card->wandev.dev; dev ; dev = dev->slave) {
+	     if ( ((fr_channel_t*)dev->priv)->route_flag == ADD_ROUTE   ||
+		((fr_channel_t*)dev->priv)->route_flag == REMOVE_ROUTE ) {
+		fs = get_fs();
+		
+		in_dev = dev->ip_ptr;
 
-/****** Background Polling Routines  ****************************************/
+		if( in_dev != NULL && in_dev->ifa_list != NULL) {
+			memset(&route, 0, sizeof(route));
+			route.rt_dev   = dev->name;
+			route.rt_flags = 0;
+
+			((struct sockaddr_in *) &(route.rt_dst)) ->
+				sin_addr.s_addr=in_dev->ifa_list->ifa_address;
+			((struct sockaddr_in *) &(route.rt_dst)) ->
+				sin_family = AF_INET;
+			((struct sockaddr_in *) &(route.rt_genmask)) ->
+				sin_addr.s_addr = 0xFFFFFFFF;
+			((struct sockaddr_in *) &(route.rt_genmask)) ->
+				sin_family = AF_INET;
+
+			switch(((fr_channel_t*)dev->priv)->route_flag) {
+
+			case ADD_ROUTE:
+				set_fs(get_ds());     /* get user space block */
+				err = ip_rt_ioctl( SIOCADDRT, &route);	
+				set_fs(fs);	      /* restore old block */
+
+				if (err) {
+					printk(KERN_INFO "%s: Adding of route failed.  Error: %d\n", card->devname,err);
+					printk(KERN_INFO "%s: Address: %s\n",
+					((fr_channel_t*)dev->priv)->name,
+					in_ntoa(in_dev->ifa_list->ifa_address) );
+				}
+				else {
+					((fr_channel_t*)dev->priv)->
+						route_flag = ROUTE_ADDED;
+				}
+				break;
 
-/*============================================================================
- * 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!
- */
+			case REMOVE_ROUTE:
+				set_fs(get_ds());     /* get user space block */
+				err = ip_rt_ioctl( SIOCDELRT, &route);
+				set_fs(fs);	      /* restore old block */
+
+				if (err) {
+			     		printk(KERN_INFO "%s: Deleting of route failed.  Error: %d\n", card->devname,err);
+			    		printk(KERN_INFO "%s: Address: %s\n",
+					dev->name,in_ntoa(in_dev->ifa_list->ifa_address) );
+				} else {
+			    	 	printk(KERN_INFO "%s: Removed route.\n",
+					((fr_channel_t*)dev->priv)->name);
+			     		((fr_channel_t*)dev->priv)->route_flag = NO_ROUTE;
+				}
+				break;
+			} /* Case Statement */
+		}
+	     } /* If ADD/DELETE ROUTE */
+	}  /* Device 'For' Loop */
 
-static void wpf_poll(sdla_t * card)
-{
-/*      struct device* dev = card->wandev.dev;  */
-	fr508_flags_t *flags = card->flags;
-	unsigned long host_cpu_flags;
-	++card->statistics.poll_entry;
-	if (((jiffies - card->state_tick) < HZ) ||
-	    (card->intr_mode == INTR_TEST_MODE))
-		return;
-	disable_irq(card->hw.irq);
-	++card->irq_dis_poll_count;
-	if (test_and_set_bit(0, (void *) &card->wandev.critical)) 
-	{
-		++card->statistics.poll_already_critical;
-		save_flags(host_cpu_flags);
-		cli();
-		if ((!card->irq_dis_if_send_count) &&
-		    (!(--card->irq_dis_poll_count)))
-			enable_irq(card->hw.irq);
-		restore_flags(host_cpu_flags);
-		return;
-	}
-	card->wandev.critical = 0x11;
-	++card->statistics.poll_processed;
-	/* This is to be changed later ??? */
-	/*
-	   if( dev && dev->tbusy && !(flags->imask & 0x02) ) {
-	   printk(KERN_INFO "%s: Wpf_Poll: tbusy = 0x01, imask = 0x%02X\n",             card->devname, flags->imask);
-	   }
-	 */
-	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);
-	}
-	card->wandev.critical = 0;
-	save_flags(host_cpu_flags);
-	cli();
-	if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
-		enable_irq(card->hw.irq);
-	restore_flags(host_cpu_flags);
-	card->state_tick = jiffies;
+	card->poll = NULL;
 }
 
+
+
 /****** 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)
+static int fr_read_version (sdla_t* card, char* str)
 {
-	fr_mbox_t *mbox = card->mbox;
+	fr_mbox_t* mbox = card->mbox;
 	int retry = MAX_CMD_RETRY;
 	int err;
-	do 
+
+	do
 	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
 		mbox->cmd.command = FR_READ_CODE_VERSION;
+		mbox->cmd.length = 0;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
 	} while (err && retry-- && fr_event(card, err, mbox));
 	
-	if (!err && str) 
-	{
+	if (!err && str) {
 		int len = mbox->cmd.length;
 		memcpy(str, mbox->data, len);
-		str[len] = '\0';
+	        str[len] = '\0';
 	}
 	return err;
 }
+
 /*============================================================================
  * Set global configuration.
  */
- 
-static int fr_configure(sdla_t * card, fr_conf_t * conf)
+static int fr_configure (sdla_t* card, fr_conf_t *conf)
 {
-	fr_mbox_t *mbox = card->mbox;
+	fr_mbox_t* mbox = card->mbox;
 	int retry = MAX_CMD_RETRY;
 	int dlci_num = card->u.f.dlci_num;
 	int err, i;
-	do 
+
+	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] =
-				    card->u.f.node_dlci[i];
+
+		if (dlci_num) for (i = 0; i < dlci_num; ++i)
+			((fr_conf_t*)mbox->data)->dlci[i] = 
+					card->u.f.node_dlci[i]; 
+		
 		mbox->cmd.command = FR_SET_CONFIG;
 		mbox->cmd.length =
-		    sizeof(fr_conf_t) + dlci_num * sizeof(short);
+			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));
+	
+	} while (err && retry-- && fr_event(card, err, mbox));
 	
 	return err;
 }
+
 /*============================================================================
  * Set DLCI configuration.
  */
-static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci)
+static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci)
 {
-	fr_mbox_t *mbox = card->mbox;
+	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, conf, sizeof(fr_dlc_conf_t));
-		mbox->cmd.dlci = (unsigned short) dlci;
+		mbox->cmd.dlci = (unsigned short) dlci; 
 		mbox->cmd.command = FR_SET_CONFIG;
-		mbox->cmd.length = 0x0E;
+		mbox->cmd.length = sizeof(fr_dlc_conf_t);
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry--);
+	} while (err && retry--);
+	
 	return err;
 }
 /*============================================================================
  * Set interrupt mode.
  */
-static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu)
+static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu,
+	unsigned short timeout)
 {
-	fr_mbox_t *mbox = card->mbox;
+	fr_mbox_t* mbox = card->mbox;
+	fr508_intr_ctl_t* ictl = (void*)mbox->data;
 	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);
-		}
+		memset(ictl, 0, sizeof(fr508_intr_ctl_t));
+		ictl->mode   = mode;
+		ictl->tx_len = mtu;
+		ictl->irq    = card->hw.irq;
+
+		/* indicate timeout on timer */
+		if (mode & 0x20) ictl->timeout = timeout; 
+
+		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));
+
+	} while (err && retry-- && fr_event(card, err, mbox));
 	
 	return err;
 }
+
 /*============================================================================
  * Enable communications.
  */
-static int fr_comm_enable(sdla_t * card)
+static int fr_comm_enable (sdla_t* card)
 {
-	fr_mbox_t *mbox = card->mbox;
+	fr_mbox_t* mbox = card->mbox;
 	int retry = MAX_CMD_RETRY;
 	int err;
-	do 
+
+	do
 	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
 		mbox->cmd.command = FR_COMM_ENABLE;
+		mbox->cmd.length = 0;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
+	} while (err && retry-- && fr_event(card, err, mbox));
 	
 	return err;
 }
+
 /*============================================================================
  * Disable communications. 
  */
-static int fr_comm_disable(sdla_t * card)
+static int fr_comm_disable (sdla_t* card)
 {
-	fr_mbox_t *mbox = card->mbox;
+	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;
+		mbox->cmd.length = 0;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
+	} while (err && retry-- && fr_event(card, err, mbox));
+
+	retry = MAX_CMD_RETRY;
+
+	do {
+	mbox->cmd.command = FR_SET_MODEM_STATUS;
+	mbox->cmd.length = 1;
+	mbox->data[0] = 0;
+	err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && fr_event(card, err, mbox));
 	
 	return err;
 }
+
 /*============================================================================
  * Get communications error statistics. 
  */
-static int fr_get_err_stats(sdla_t * card)
+static int fr_get_err_stats (sdla_t* card)
 {
-	fr_mbox_t *mbox = card->mbox;
+	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_ERROR_STATS;
+		mbox->cmd.length = 0;
+		mbox->cmd.dlci = 0;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
-	
-	if (!err) 
-	{
-		fr_comm_stat_t *stats = (void *) mbox->data;
-		card->wandev.stats.rx_over_errors = stats->rx_overruns;
-		card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
-		card->wandev.stats.rx_missed_errors = stats->rx_aborts;
-		card->wandev.stats.rx_length_errors = stats->rx_too_long;
+	} while (err && retry-- && fr_event(card, err, mbox));
+
+	if (!err) {
+		fr_comm_stat_t* stats = (void*)mbox->data;
+		card->wandev.stats.rx_over_errors    = stats->rx_overruns;
+		card->wandev.stats.rx_crc_errors     = stats->rx_bad_crc;
+		card->wandev.stats.rx_missed_errors  = stats->rx_aborts;
+		card->wandev.stats.rx_length_errors  = stats->rx_too_long;
 		card->wandev.stats.tx_aborted_errors = stats->tx_aborts;
+	
 	}
+
 	return err;
 }
+
 /*============================================================================
  * Get statistics. 
  */
-static int fr_get_stats(sdla_t * card)
+static int fr_get_stats (sdla_t* card)
 {
-	fr_mbox_t *mbox = card->mbox;
+	fr_mbox_t* mbox = card->mbox;
 	int retry = MAX_CMD_RETRY;
 	int err;
-	do 
+
+
+	do
 	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
 		mbox->cmd.command = FR_READ_STATISTICS;
+		mbox->cmd.length = 0;
+		mbox->cmd.dlci = 0;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
-	
-	if (!err) 
-	{
-		fr_link_stat_t *stats = (void *) mbox->data;
+	} while (err && retry-- && fr_event(card, err, mbox));
+
+	if (!err) {
+		fr_link_stat_t* stats = (void*)mbox->data;
 		card->wandev.stats.rx_frame_errors = stats->rx_bad_format;
-		card->wandev.stats.rx_dropped = stats->rx_dropped + stats->rx_dropped2;
+		card->wandev.stats.rx_dropped =
+			stats->rx_dropped + stats->rx_dropped2;
 	}
+
 	return err;
 }
+
 /*============================================================================
  * Add DLCI(s) (Access Node only!).
  * This routine will perform the ADD_DLCIs command for the specified DLCI.
  */
-static int fr_add_dlci(sdla_t * card, int dlci, int num)
+static int fr_add_dlci (sdla_t* card, int dlci)
 {
-	fr_mbox_t *mbox = card->mbox;
+	fr_mbox_t* mbox = card->mbox;
 	int retry = MAX_CMD_RETRY;
-	int err, i;
-	do 
+	int err;
+
+	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] = card->u.f.node_dlci[i];
-		mbox->cmd.length = num * sizeof(short);
+		unsigned short* dlci_list = (void*)mbox->data;
+
+		mbox->cmd.length  = sizeof(short);
+		dlci_list[0] = dlci;
 		mbox->cmd.command = FR_ADD_DLCI;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
+
+	} while (err && retry-- && fr_event(card, err, mbox));
 	
 	return err;
 }
+
 /*============================================================================
  * Activate DLCI(s) (Access Node only!). 
- * This routine will perform the ACTIVATE_DLCIs command with a list of DLCIs. 
+ * This routine will perform the ACTIVATE_DLCIs command with a DLCI number. 
  */
-static int fr_activate_dlci(sdla_t * card, int dlci, int num)
+static int fr_activate_dlci (sdla_t* card, int dlci)
 {
-	fr_mbox_t *mbox = card->mbox;
+	fr_mbox_t* mbox = card->mbox;
 	int retry = MAX_CMD_RETRY;
-	int err, i;
+	int err;
+
 	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] = card->u.f.node_dlci[i];
-		mbox->cmd.length = num * sizeof(short);
+		unsigned short* dlci_list = (void*)mbox->data;
+
+		mbox->cmd.length  = sizeof(short);
+		dlci_list[0] = dlci;
 		mbox->cmd.command = FR_ACTIVATE_DLCI;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
+
+	} while (err && retry-- && fr_event(card, err, mbox));
 	
 	return err;
 }
+
 /*============================================================================
- * Issue in-channel signalling frame. 
+ * Delete DLCI(s) (Access Node only!). 
+ * This routine will perform the DELETE_DLCIs command with a DLCI number. 
  */
-static int fr_issue_isf(sdla_t * card, int isf)
+static int fr_delete_dlci (sdla_t* card, int dlci)
 {
-	fr_mbox_t *mbox = card->mbox;
+	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;
+		unsigned short* dlci_list = (void*)mbox->data;
+
+		mbox->cmd.length  = sizeof(short);
+		dlci_list[0] = dlci;
+		mbox->cmd.command = FR_DELETE_DLCI;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
+
+	} while (err && retry-- && fr_event(card, err, mbox));
 	
 	return err;
 }
+
+
+
 /*============================================================================
- * Send a frame (S502 version). 
+ * Issue in-channel signalling frame. 
  */
-static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf)
+static int fr_issue_isf (sdla_t* card, int isf)
 {
-	fr_mbox_t *mbox = card->mbox;
+	fr_mbox_t* mbox = card->mbox;
 	int retry = MAX_CMD_RETRY;
 	int err;
-	
-	do 
+
+	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;
+		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));
+	} while (err && retry-- && fr_event(card, err, mbox));
 	
 	return err;
 }
+
 /*============================================================================
- * Send a frame (S508 version). 
+ * Send a frame on a selected DLCI.  
  */
-static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf)
+static int fr_send (sdla_t* card, int dlci, unsigned char attr, int len,
+	void *buf)
 {
-	fr_mbox_t *mbox = card->mbox;
+	fr_mbox_t* mbox = card->mbox + 0x800;
 	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.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);
-		sdla_poke(&card->hw, frbuf->offset, buf, len);
-		frbuf->flag = 0x01;
-	}
+	} while (err && retry-- && fr_event(card, err, mbox));
+
+	if (!err) {
+
+		fr_tx_buf_ctl_t* frbuf;
+ 
+               	if(card->hw.type == SDLA_S514)
+			frbuf = (void*)(*(unsigned long*)mbox->data +
+                        	card->hw.dpmbase);
+		else
+			frbuf = (void*)(*(unsigned long*)mbox->data -
+                        	FR_MB_VECTOR + card->hw.dpmbase);
+
+		sdla_poke(&card->hw, frbuf->offset, buf, len);
+		frbuf->flag = 0x01;
+	}
+
 	return err;
 }
 
 /****** Firmware Asynchronous Event Handlers ********************************/
 
 /*============================================================================
- * Main asynchronous event/error handler.
+ * 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)
+static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox)
 {
-	fr508_flags_t *flags = card->flags;
+	fr508_flags_t* flags = card->flags;
 	char *ptr = &flags->iflag;
 	int i;
-	switch (event) 
-	{
+
+	switch (event) {
+
 		case FRRES_MODEM_FAILURE:
 			return fr_modem_failure(card, mbox);
+
 		case FRRES_CHANNEL_DOWN:
+			{
+			struct device *dev;
+
+			/* Remove all routes from associated DLCI's */
+			for (dev = card->wandev.dev; dev; dev = dev->slave) {
+				fr_channel_t *chan = dev->priv;
+				if (chan->route_flag == ROUTE_ADDED) {
+					chan->route_flag = REMOVE_ROUTE;
+					card->poll = &process_route;
+				}
+
+				if (chan->inarp == INARP_CONFIGURED) {
+					chan->inarp = INARP_REQUEST;
+				}
+			}
+
 			wanpipe_set_state(card, WAN_DISCONNECTED);
 			return 1;
+			}
+
 		case FRRES_CHANNEL_UP:
+			{
+			struct device *dev;
+			int num_requests = 0;
+
+			/* Remove all routes from associated DLCI's */
+			for (dev = card->wandev.dev; dev; dev = dev->slave) {
+				fr_channel_t *chan = dev->priv;	
+				if( chan->inarp == INARP_REQUEST ){
+					num_requests++;
+					chan->inarp_tick = jiffies;
+				}
+			}
+
+			/* Allow timer interrupts */
+			if (num_requests) flags->imask |= 0x20;	
 			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);
+			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);
-			printk(KERN_INFO "%s: ID Bytes = ", card->devname);
-			for (i = 0; i < 8; i++)
-				printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
-			printk(KERN_INFO "\n");
+				card->devname, mbox->cmd.command);
+			printk(KERN_INFO "%s: ID Bytes = ",card->devname);
+ 	    		for(i = 0; i < 8; i ++)
+				printk(KERN_INFO "0x%02X ", *(ptr + 0x18 + i));
+	   	 	printk(KERN_INFO "\n");	
+            
 			break;
+
 		case FRRES_DLCI_INACTIVE:
-			printk(KERN_ERR "%s: DLCI %u is inactive!\n",
-			       card->devname, mbox->cmd.dlci);
 			break;
+ 
 		case FRRES_CIR_OVERFLOW:
 			break;
 		case FRRES_BUFFER_OVERFLOW:
-			break;
+			break; 
 		default:
 			printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n"
-			       ,card->devname, mbox->cmd.command, event);
+				, card->devname, mbox->cmd.command, event);
 	}
+
 	return 0;
 }
 
@@ -2223,178 +2643,228 @@
  *
  * Return zero if previous command has to be cancelled.
  */
-static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox)
+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) 
-	{
+		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)
+static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox)
 {
-	dlci_status_t *status = (void *) mbox->data;
+	dlci_status_t* status = (void*)mbox->data;
 	int cnt = mbox->cmd.length / sizeof(dlci_status_t);
-	fr_dlc_conf_t cfg;
 	fr_channel_t *chan;
-	struct device *dev2;
-	for (; cnt; --cnt, ++status) 
-	{
-		unsigned short dlci = status->dlci;
-		struct device *dev = find_channel(card, dlci);
-		if (dev == NULL) 
-		{
-			printk(KERN_INFO
-			       "%s: CPE contains unconfigured DLCI= %d\n",
-			       card->devname, dlci);
-		}
-		else 
-		{
-			if (status->state & 0x01) 
-			{
+	struct device* dev2;
+	
+
+	for (; cnt; --cnt, ++status) {
+
+		unsigned short dlci= status->dlci;
+		struct device* dev = find_channel(card, dlci);
+		
+		if (dev == NULL){
+			printk(KERN_INFO 
+				"%s: CPE contains unconfigured DLCI= %d\n", 
+				card->devname, dlci); 	
+
+                      printk(KERN_INFO
+                                "%s: unconfigured DLCI %d reported by network\n"
+                                , card->devname, dlci);
+ 
+		}else{
+			if (status->state == FR_LINK_INOPER) {
 				printk(KERN_INFO
-				       "%s: DLCI %u has been deleted!\n",
-				       card->devname, dlci);
+					"%s: DLCI %u is inactive!\n",
+					card->devname, dlci);
+
 				if (dev && dev->start)
 					set_chan_state(dev, WAN_DISCONNECTED);
 			}
-			else if (status->state & 0x02) 
-			{
+	
+			if (status->state & FR_DLCI_DELETED) {
+
 				printk(KERN_INFO
-				       "%s: DLCI %u becomes active!\n",
-				       card->devname, dlci);
+					"%s: DLCI %u has been deleted!\n",
+					card->devname, dlci);
+
+				if (dev && dev->start) {
+					fr_channel_t *chan = dev->priv;
+
+					if (chan->route_flag == ROUTE_ADDED) {
+						chan->route_flag = REMOVE_ROUTE;
+						card->poll = &process_route;
+					}
+
+					if (chan->inarp == INARP_CONFIGURED) {
+						chan->inarp = INARP_REQUEST;
+					}
+
+					set_chan_state(dev, WAN_DISCONNECTED);
+				}
+
+			} else if (status->state & FR_DLCI_ACTIVE) {
+
 				chan = dev->priv;
+			
 				/* This flag is used for configuring specific 
 				   DLCI(s) when they become active.
-				 */
+			 	*/ 
 				chan->dlci_configured = DLCI_CONFIG_PENDING;
+			
 				if (dev && dev->start)
 					set_chan_state(dev, WAN_CONNECTED);
+		
 			}
 		}
 	}
-	for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) 
-	{
+	
+	for (dev2 =card->wandev.dev; dev2; dev2 = dev2->slave){
+		
 		chan = dev2->priv;
-		if (chan->dlci_configured == DLCI_CONFIG_PENDING) 
-		{
-			memset(&cfg, 0, sizeof(cfg));
-			if (chan->cir_status == CIR_DISABLED) 
-			{
-				cfg.cir_fwd = cfg.cir_bwd = 16;
-				cfg.bc_fwd = cfg.bc_bwd = 16;
-				cfg.conf_flags = 0x0001;
-				printk(KERN_INFO "%s: CIR Disabled for %s\n",
-				       card->devname, chan->name);
-			} else if (chan->cir_status == CIR_ENABLED) {
-				cfg.cir_fwd = cfg.cir_bwd = chan->cir;
-				cfg.bc_fwd = cfg.bc_bwd = chan->bc;
-				cfg.be_fwd = cfg.be_bwd = chan->be;
-				cfg.conf_flags = 0x0000;
-				printk(KERN_INFO "%s: CIR Enabled for %s\n",
-				       card->devname, chan->name);
-			}
-			if (fr_dlci_configure(card, &cfg, chan->dlci)) 
-			{
-				printk(KERN_INFO
-				    "%s: DLCI Configure failed for %d\n",
-				       card->devname, chan->dlci);
+	
+		if (chan->dlci_configured == DLCI_CONFIG_PENDING) {
+			if (fr_init_dlci(card, chan)){
 				return 1;
 			}
-			chan->dlci_configured = DLCI_CONFIGURED;
-			/* Read the interface byte mapping into the channel 
-			   structure.
-			 */
-			if (card->intr_mode == DLCI_LIST_INTR_MODE)
-				read_DLCI_IB_mapping(card, chan);
 		}
+
 	}
 	return 1;
 }
+
+
+static int fr_init_dlci (sdla_t *card, fr_channel_t *chan)
+{
+	fr_dlc_conf_t cfg;
+	fr508_flags_t* flags = card->flags;
+
+	memset(&cfg, 0, sizeof(cfg));
+
+	if ( chan->cir_status == CIR_DISABLED) {
+
+		cfg.cir_fwd = cfg.cir_bwd  = 16;
+		cfg.bc_fwd = cfg.bc_bwd = 16;
+		cfg.conf_flags = 0x0001;	
+
+	}else if (chan->cir_status == CIR_ENABLED) {
+	
+		cfg.cir_fwd = cfg.cir_bwd = chan->cir;
+		cfg.bc_fwd  = cfg.bc_bwd  = chan->bc;
+		cfg.be_fwd  = cfg.be_bwd  = chan->be;
+		cfg.conf_flags = 0x0000;
+	}
+	
+	if (fr_dlci_configure( card, &cfg , chan->dlci)){
+	printk(KERN_INFO 
+		"%s: DLCI Configure failed for %d\n",
+			card->devname, chan->dlci);
+		return 1;	
+	}
+	
+	chan->dlci_configured = DLCI_CONFIGURED;
+
+	/* Allow timer interrupts */
+	if( chan->inarp == INARP_REQUEST && card->wandev.state == WAN_CONNECTED) {
+		chan->inarp_tick = jiffies;
+		flags->imask |= 0x20;	
+	}	
+
+	/* Read the interface byte mapping into the channel 
+	   structure.
+	 */
+	read_DLCI_IB_mapping( card, chan );
+
+	return 0;
+}
 /******* Miscellaneous ******************************************************/
 
 /*============================================================================
  * Update channel state. 
  */
-static int update_chan_state(struct device *dev)
+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;
+	fr_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
+	fr_mbox_t* mbox = card->mbox;
 	int retry = MAX_CMD_RETRY;
 	int err;
-	int dlci_found = 0;
 
-	do 
+	do
 	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
 		mbox->cmd.command = FR_LIST_ACTIVE_DLCI;
+		mbox->cmd.length = 0;
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-	}
-	while (err && retry-- && fr_event(card, err, mbox));
+	} while (err && retry-- && fr_event(card, err, mbox));
 
-	if (!err) 
-	{
-		unsigned short *list = (void *) mbox->data;
+	if (!err) {
+
+		unsigned short* list = (void*)mbox->data;
 		int cnt = mbox->cmd.length / sizeof(short);
-		for (; cnt; --cnt, ++list) 
-		{
-			if (*list == chan->dlci) 
-			{
-				dlci_found = 1;
-				set_chan_state(dev, WAN_CONNECTED);
+
+		for (; cnt; --cnt, ++list) {
+
+			if (*list == chan->dlci) {
+ 				set_chan_state(dev, WAN_CONNECTED);
 				break;
 			}
 		}
-		if (!dlci_found)
-			printk(KERN_INFO "%s: DLCI %u is inactive\n",
-			       card->devname, chan->dlci);
 	}
-	
+
 	return err;
 }
+
 /*============================================================================
  * Set channel state.
  */
-static void set_chan_state(struct device *dev, int state)
+static void set_chan_state (struct device* dev, int state)
 {
-	fr_channel_t *chan = dev->priv;
-	sdla_t *card = chan->card;
+	fr_channel_t* chan = dev->priv;
+	sdla_t* card = chan->card;
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
-	
-	if (chan->state != state) 
-	{
-		switch (state) 
-		{
+
+	if (chan->state != state) {
+
+		switch (state) {
+
 			case WAN_CONNECTED:
-				printk(KERN_INFO "%s: interface %s connected!\n"
-				       ,card->devname, dev->name);
+				printk(KERN_INFO
+					"%s: Interface %s: DLCI %d connected\n",
+					card->devname, dev->name, chan->dlci);
 				break;
+
 			case WAN_CONNECTING:
-				printk(KERN_INFO
-				       "%s: interface %s connecting...\n",
-				       card->devname, dev->name);
+				printk(KERN_INFO 
+				      "%s: Interface %s: DLCI %d connecting\n",
+					card->devname, dev->name, chan->dlci);
 				break;
+
 			case WAN_DISCONNECTED:
-				printk(KERN_INFO
-				       "%s: interface %s disconnected!\n",
-				       card->devname, dev->name);
+				printk (KERN_INFO 
+				    "%s: Interface %s: DLCI %d disconnected!\n",
+					card->devname, dev->name, chan->dlci);
 				break;
 		}
+
 		chan->state = state;
 	}
+
 	chan->state_tick = jiffies;
 	restore_flags(flags);
 }
@@ -2402,14 +2872,15 @@
 /*============================================================================
  * Find network device by its channel number.
  */
-static struct device *find_channel(sdla_t * card, unsigned dlci)
+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;
+
+	if(dlci > HIGHEST_VALID_DLCI)
+		return NULL;
+
+	return(card->u.f.dlci_to_dev_map[dlci]);
 }
+
 /*============================================================================
  * Check to see if a frame can be sent. If no transmit buffers available,
  * enable transmit interrupts.
@@ -2417,22 +2888,17 @@
  * Return:	1 - Tx buffer(s) available
  *		0 - no buffers available
  */
-
-static int is_tx_ready(sdla_t * card, fr_channel_t * chan)
+static int is_tx_ready (sdla_t* card, fr_channel_t* chan)
 {
-	if (card->hw.fwid == SFID_FR508) 
-	{
-		unsigned char sb = inb(card->hw.port);
-		if (sb & 0x02)
-			return 1;
-	}
-	else 
-	{
-		fr502_flags_t *flags = card->flags;
-		if (flags->tx_ready)
-			return 1;
-		flags->imask |= 0x02;
-	}
+	unsigned char sb;
+
+        if(card->hw.type == SDLA_S514)
+		return 1;
+
+	sb = inb(card->hw.port);
+	if (sb & 0x02) 
+		return 1;
+
 	return 0;
 }
 
@@ -2440,688 +2906,790 @@
  * 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)
+static unsigned int dec_to_uint (unsigned char* str, int len)
 {
 	unsigned val;
-	if (!len)
+
+	if (!len) 
 		len = strlen(str);
+
 	for (val = 0; len && is_digit(*str); ++str, --len)
-		val = (val * 10) + (*str - (unsigned) '0');
+		val = (val * 10) + (*str - (unsigned)'0');
+
 	return val;
 }
 
+
+
+/*=============================================================================
+ * Store a UDP management packet for later processing.
+ */
+
+static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card,
+                                struct sk_buff *skb, int dlci)
+{
+        int udp_pkt_stored = 0;
+
+        if(!card->u.f.udp_pkt_lgth &&(skb->len <= MAX_LGTH_UDP_MGNT_PKT)){
+                card->u.f.udp_pkt_lgth = skb->len;
+                card->u.f.udp_type = udp_type;
+                card->u.f.udp_pkt_src = udp_pkt_src;
+                card->u.f.udp_dlci = dlci;
+                memcpy(card->u.f.udp_pkt_data, skb->data, skb->len);
+                card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UDP;
+                udp_pkt_stored = 1;
+
+        }else{
+                printk(KERN_INFO "ERROR: UDP packet not stored for DLCI %d\n", 
+							dlci);
+	}
+
+        dev_kfree_skb(skb);
+
+        return(udp_pkt_stored);
+}
+
+
 /*==============================================================================
  * Process UDP call of type FPIPE8ND
  */
-
-static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan)
+static int process_udp_mgmt_pkt(sdla_t* card)
 {
+
 	int c_retry = MAX_CMD_RETRY;
-	unsigned char *data;
 	unsigned char *buf;
-	unsigned char buf2[5];
-	unsigned int loops, frames, len;
-	unsigned long data_ptr;
-	unsigned short real_len, buffer_length;
+	unsigned char frames;
+	unsigned int len;
+	unsigned short buffer_length;
 	struct sk_buff *new_skb;
-	unsigned char *sendpacket;
-	fr_mbox_t *mbox = card->mbox;
+	fr_mbox_t* mbox = card->mbox;
 	int err;
 	struct timeval tv;
 	int udp_mgmt_req_valid = 1;
-	sendpacket = skb->data;
-	memcpy(&buf2, &card->wandev.udp_port, 2);
-	if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) 
-	{
-		printk(KERN_INFO
-		       "%s: Error allocating memory for UDP management cmnd 0x%02X",
-		       card->devname, data[47]);
-		++chan->UDP_FPIPE_mgmt_kmalloc_err;
-		return 1;
-	}
-	memcpy(data, sendpacket, skb->len);
-	switch (data[47]) 
-	{
-		/* FPIPE_ENABLE_TRACE */
-		case 0x41:
-		/* FPIPE_DISABLE_TRACE */
-		case 0x42:
-		/* FPIPE_GET_TRACE_INFO */
-		case 0x43:
-		/* SET FT1 MODE */
-		case 0x81:
-			if (udp_pkt_src == UDP_PKT_FRM_NETWORK) 
-			{
-				++chan->UDP_FPIPE_mgmt_direction_err;
+        struct device* dev;
+        fr_channel_t* chan;
+        fr_udp_pkt_t *fr_udp_pkt;
+	unsigned short num_trc_els;
+	fr_trc_el_t* ptr_trc_el;
+	fr_trc_el_t trc_el;
+	fpipemon_trc_t* fpipemon_trc;
+
+	char udp_pkt_src = card->u.f.udp_pkt_src; 
+	int dlci = card->u.f.udp_dlci;
+
+	/* Find network interface for this packet */
+	dev = find_channel(card, dlci);
+        chan = dev->priv;
+
+	/* If the UDP packet is from the network, we are going to have to 
+	   transmit a response. Before doing so, we must check to see that
+	   we are not currently transmitting a frame (in 'if_send()') and
+	   that we are not already in a 'delayed transmit' state.
+	*/
+	if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+		if (test_bit(0, (void*)&card->wandev.critical) ||
+			test_bit(2, (void*)&card->wandev.critical)) {
+			return 0;
+  		}
+		if((dev->tbusy) || (card->u.f.tx_interrupts_pending)) {
+			return 0;
+		}
+        }
+
+        fr_udp_pkt = (fr_udp_pkt_t *)card->u.f.udp_pkt_data;
+
+	switch(fr_udp_pkt->cblock.command) {
+
+		case FPIPE_ENABLE_TRACING:
+		case FPIPE_DISABLE_TRACING:
+		case FPIPE_GET_TRACE_INFO:
+		case FR_SET_FT1_MODE:
+			if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+                    		chan->drvstats_gen.
+					UDP_PIPE_mgmt_direction_err ++;
 				udp_mgmt_req_valid = 0;
 				break;
 			}
-		/* FPIPE_FT1_READ_STATUS */
-		case 0x44:
-		/* FT1 MONITOR STATUS */
-		case 0x80:
-			if (card->hw.fwid != SFID_FR508) 
-			{
-				++chan->UDP_FPIPE_mgmt_adptr_type_err;
-				udp_mgmt_req_valid = 0;
-			}
-			break;
+
 		default:
 			break;
-	}
-	if (!udp_mgmt_req_valid) 
-	{
+       	}
+
+	if(!udp_mgmt_req_valid) {
 		/* set length to 0 */
-		data[48] = data[49] = 0;
+		fr_udp_pkt->cblock.length = 0;
 		/* set return code */
-		data[50] = (card->hw.fwid != SFID_FR508) ? 0x1F : 0xCD;
-	}
-	else
-	{
-		switch (data[47]) 
-		{
-			/* FPIPE_ENABLE_TRACE */
-			case 0x41:
-				if (!TracingEnabled) 
-				{
-					do 
-					{
-						/* SET_TRACE_CONFIGURATION */
-						mbox->cmd.command = 0x60;
-						mbox->cmd.length = 1;
-						mbox->cmd.dlci = 0x00;
-						mbox->data[0] = 0x37;
-						err = sdla_exec(mbox) ?
-							mbox->cmd.result : CMD_TIMEOUT;
-					}
-					while (err && c_retry-- && fr_event(card, err, mbox));
-	
-					if (err) 
-					{
-						TracingEnabled = 0;
-						/* set the return code */
-						data[50] = mbox->cmd.result;
-						mbox->cmd.length = 0;
-						break;
-					}
-					/* get num_frames */
-					sdla_peek(&card->hw, 0x9000, &num_frames, 2);
-					sdla_peek(&card->hw, 0x9002, &curr_trace_addr,4);
-					start_trace_addr = curr_trace_addr;
-					/* MAX_SEND_BUFFER_SIZE - 
-					 * sizeof(UDP_MGMT_PACKET) - 41 */
-					available_buffer_space = 1926;
-					/* set return code */
-					data[50] = 0;
-				} 
-				else
-				{
-					/* set return code to line trace already 
-					   enabled */
-					data[50] = 1;
-				}
-				mbox->cmd.length = 0;
-				TracingEnabled = 1;
-				break;
-			/* FPIPE_DISABLE_TRACE */
-			case 0x42:
-				if (TracingEnabled) 
-				{
-					do 
-					{
-						/* SET_TRACE_CONFIGURATION */
-						mbox->cmd.command = 0x60;
-						mbox->cmd.length = 1;
-						mbox->cmd.dlci = 0x00;
-						mbox->data[0] = 0x36;
-						err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-					}
-					while (err && c_retry-- && fr_event(card, err, mbox));
-				}
-				/* set return code */
-				data[50] = 0;
-				mbox->cmd.length = 0;
-				TracingEnabled = 0;
-				break;
-			/* FPIPE_GET_TRACE_INFO */
-			case 0x43:
-				/* Line trace cannot be performed on the 502 */
-				if (!TracingEnabled) 
-				{
-					/* set return code */
-					data[50] = 1;
+		fr_udp_pkt->cblock.result = 0xCD; 
+	} else {   
+           
+		switch(fr_udp_pkt->cblock.command) {
+
+		case FPIPE_ENABLE_TRACING:
+			if(!card->TracingEnabled) {
+				do {
+                       			mbox->cmd.command = FR_SET_TRACE_CONFIG;
+                       			mbox->cmd.length = 1;
+                     			mbox->cmd.dlci = 0x00;
+                   			mbox->data[0] = fr_udp_pkt->data[0] | 
+						RESET_TRC;
+                    			err = sdla_exec(mbox) ? 
+					     		mbox->cmd.result : CMD_TIMEOUT;
+                       		} while (err && c_retry-- && fr_event(card, err,
+					 mbox));
+
+                        	if(err) {
+					card->TracingEnabled = 0;
+					/* set the return code */
+					fr_udp_pkt->cblock.result =
+  						mbox->cmd.result;
 					mbox->cmd.length = 0;
 					break;
 				}
-				buffer_length = 0;
-				loops = (num_frames < 20) ? num_frames : 20;
-				for (frames = 0; frames < loops; frames += 1) 
-				{
-					sdla_peek(&card->hw, curr_trace_addr, &buf2, 1);
-					/* no data on board so exit */
-					if (buf2[0] == 0x00)
-						break;
-					/* 1+sizeof(FRAME_DATA) = 9 */
-					if ((available_buffer_space - buffer_length) < 9) 
-					{
-						/* indicate we have more frames on board
-						   and exit */
-						data[62] |= 0x02;
-						break;
-					}
-					/* get frame status */
-					sdla_peek(&card->hw, curr_trace_addr + 0x05, &data[62 + buffer_length], 1);
-					/* get time stamp */
-					sdla_peek(&card->hw, curr_trace_addr + 0x06, &data[66 + buffer_length], 2);
-					/* get frame length */
-					sdla_peek(&card->hw, curr_trace_addr + 0x01, &data[64 + buffer_length], 2);
-					/* get pointer to real data */
-					sdla_peek(&card->hw, curr_trace_addr + 0x0C,&data_ptr, 4);
-					/* see if we can fit the frame into the user buffer */
-					memcpy(&real_len, &data[64 + buffer_length], 2);
-					if (data_ptr == 0 || real_len + 8 > available_buffer_space) 
-					{
-						data[63 + buffer_length] = 0x00;
-					}
-					else
-					{
-						/* we can take it next time */
-						if (available_buffer_space - buffer_length < real_len + 8) 
-						{
-							data[62] |= 0x02;
-							break;
-						}
-						/* ok, get the frame */
-						data[63 + buffer_length] = 0x01;
-						/* get the data */
-						sdla_peek(&card->hw, data_ptr, &data[68 + buffer_length], real_len);
-						/* zero the opp flag to show we got the frame */
-						buf2[0] = 0x00;
-						sdla_poke(&card->hw, curr_trace_addr, &buf2, 1);
-						/* now move onto the next frame */
-						curr_trace_addr += 16;
-						/* check if we passed the last address */
-						if (curr_trace_addr >= (start_trace_addr + num_frames * 16)) 
-							curr_trace_addr = start_trace_addr;
-						/* update buffer length and make sure 
-						   its even */
-						if (data[63 + buffer_length] == 0x01) 
-							buffer_length += real_len - 1;
-						/* for the header */
-						buffer_length += 8;
-						if (buffer_length & 0x0001)
-							buffer_length += 1;
-					}
-				}
-				/* ok now set the total number of frames passed in the 
-				   high 5 bits */
-				data[62] = (frames << 3) | data[62];
-				/* set the data length */
-				mbox->cmd.length = buffer_length;
-				memcpy(&data[48], &buffer_length, 2);
-				data[50] = 0;
-				break;
-			/* FPIPE_FT1_READ_STATUS */
-			case 0x44:
-				sdla_peek(&card->hw, 0xF020, &data[62], 2);
-				data[48] = 2;
-				data[49] = 0;
-				data[50] = 0;
-				mbox->cmd.length = 2;
-				break;
-			/* FPIPE_FLUSH_DRIVER_STATS */
-			case 0x48:
-				init_chan_statistics(chan);
-				init_global_statistics(card);
-				mbox->cmd.length = 0;
-				break;
-			case 0x49:
-				do_gettimeofday(&tv);
-				chan->router_up_time = tv.tv_sec - chan->router_start_time;
-				*(unsigned long *) &data[62] = chan->router_up_time;
-				mbox->cmd.length = 4;
-				break;
-			/* FPIPE_KILL_BOARD */
-			case 0x50:
-				break;
-			/* FT1 MONITOR STATUS */
-			case 0x80:
-				if (data[62] == 1) 
-				{
-					if (rCount++ != 0) 
-					{
-						data[50] = 0;
-						mbox->cmd.length = 1;
-						break;
-					}
-				}
-				/* Disable FT1 MONITOR STATUS */
-				if (data[62] == 0) 
-				{
-					if (--rCount != 0) 
-					{
-						data[50] = 0;
-						mbox->cmd.length = 1;
-						break;
-					}
-				}
-			default:
-				do 
-				{
-					memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t));
-					if (mbox->cmd.length) 
-						memcpy(&mbox->data, &sendpacket[62],mbox->cmd.length);
-					err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-				}
-				while (err && c_retry-- && fr_event(card, err, mbox));
+
+				sdla_peek(&card->hw, NO_TRC_ELEMENTS_OFF,
+						&num_trc_els, 2);
+				sdla_peek(&card->hw, BASE_TRC_ELEMENTS_OFF,
+						&card->u.f.trc_el_base, 4);
+				card->u.f.curr_trc_el = card->u.f.trc_el_base;
+             			card->u.f.trc_el_last = card->u.f.curr_trc_el +
+							((num_trc_els - 1) * 
+							sizeof(fr_trc_el_t));
+   
+				/* Calculate the maximum trace data area in */
+				/* the UDP packet */
+				card->u.f.trc_bfr_space=(MAX_LGTH_UDP_MGNT_PKT -
+					sizeof(fr_encap_hdr_t) -
+					sizeof(ip_pkt_t) -
+					sizeof(udp_pkt_t) -
+					sizeof(wp_mgmt_t) -
+					sizeof(cblock_t));
+
+				/* set return code */
+				fr_udp_pkt->cblock.result = 0;
 			
-				if (!err) 
-				{
-					++chan->UDP_FPIPE_mgmt_adptr_cmnd_OK;
-					memcpy(data, sendpacket, skb->len);
-					memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t));
-					if (mbox->cmd.length) 
-					{
-						memcpy(&data[62], &mbox->data,mbox->cmd.length);
-					}
+			} else {
+                        	/* set return code to line trace already 
+				   enabled */
+				fr_udp_pkt->cblock.result = 1;
+                    	}
+
+			mbox->cmd.length = 0;
+			card->TracingEnabled = 1;
+			break;
+
+
+                case FPIPE_DISABLE_TRACING:
+			if(card->TracingEnabled) {
+			
+				do {
+					mbox->cmd.command = FR_SET_TRACE_CONFIG;
+					mbox->cmd.length = 1;
+					mbox->cmd.dlci = 0x00;
+					mbox->data[0] = ~ACTIVATE_TRC;
+					err = sdla_exec(mbox) ? 
+							mbox->cmd.result : CMD_TIMEOUT;
+				} while (err && c_retry-- && fr_event(card, err, mbox));
+                    	}
+
+                    	/* set return code */
+			fr_udp_pkt->cblock.result = 0;
+			mbox->cmd.length = 0;
+			card->TracingEnabled = 0;
+			break;
+
+                case FPIPE_GET_TRACE_INFO:
+
+		        /* Line trace cannot be performed on the 502 */
+                        if(!card->TracingEnabled) {
+                                /* set return code */
+                                fr_udp_pkt->cblock.result = 1;
+                                mbox->cmd.length = 0;
+                                break;
+                        }
+
+			(void *)ptr_trc_el = card->u.f.curr_trc_el;
+
+                        buffer_length = 0;
+			fr_udp_pkt->data[0x00] = 0x00;
+
+                        for(frames = 0; frames < MAX_FRMS_TRACED; frames ++) {
+
+                                sdla_peek(&card->hw, (unsigned long)ptr_trc_el,
+					  (void *)&trc_el.flag,
+					  sizeof(fr_trc_el_t));
+                                if(trc_el.flag == 0x00) {
+                                        break;
 				}
-				else
-				{
-					++chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout;
+                                if((card->u.f.trc_bfr_space - buffer_length)
+                                        < sizeof(fpipemon_trc_hdr_t)) { 
+                                        fr_udp_pkt->data[0x00] |= MORE_TRC_DATA;
+                                        break;
+                                }
+
+				fpipemon_trc = 
+					(fpipemon_trc_t *)&fr_udp_pkt->data[buffer_length]; 
+				fpipemon_trc->fpipemon_trc_hdr.status =
+					trc_el.attr;
+                            	fpipemon_trc->fpipemon_trc_hdr.tmstamp =
+					trc_el.tmstamp;
+                            	fpipemon_trc->fpipemon_trc_hdr.length = 
+					trc_el.length;
+
+                                if(!trc_el.offset || !trc_el.length) {
+
+                                     	fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00;
+
+ 				}else if((trc_el.length + sizeof(fpipemon_trc_hdr_t) + 1) >
+					(card->u.f.trc_bfr_space - buffer_length)){
+
+                                        fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00;
+                                    	fr_udp_pkt->data[0x00] |= MORE_TRC_DATA;
+ 
+                                }else {
+                                        fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x01;
+                                        sdla_peek(&card->hw, trc_el.offset,
+                           			  fpipemon_trc->data,
+						  trc_el.length);
+				}			
+
+                                trc_el.flag = 0x00;
+                                sdla_poke(&card->hw, (unsigned long)ptr_trc_el,
+					  &trc_el.flag, 1);
+                               
+				ptr_trc_el ++;
+				if((void *)ptr_trc_el > card->u.f.trc_el_last)
+					(void*)ptr_trc_el = card->u.f.trc_el_base;
+
+				buffer_length += sizeof(fpipemon_trc_hdr_t);
+                               	if(fpipemon_trc->fpipemon_trc_hdr.data_passed) {
+                               		buffer_length += trc_el.length;
+                               	}
+
+				if(fr_udp_pkt->data[0x00] & MORE_TRC_DATA) {
+					break;
 				}
+                        }
+                      
+			if(frames == MAX_FRMS_TRACED) {
+                        	fr_udp_pkt->data[0x00] |= MORE_TRC_DATA;
+			}
+             
+			card->u.f.curr_trc_el = (void *)ptr_trc_el;
+
+                        /* set the total number of frames passed */
+			fr_udp_pkt->data[0x00] |=
+				((frames << 1) & (MAX_FRMS_TRACED << 1));
+
+                        /* set the data length and return code */
+			fr_udp_pkt->cblock.length = mbox->cmd.length = buffer_length;
+                        fr_udp_pkt->cblock.result = 0;
+                        break;
+
+                case FPIPE_FT1_READ_STATUS:
+			sdla_peek(&card->hw, 0xF020,
+				&fr_udp_pkt->data[0x00] , 2);
+			fr_udp_pkt->cblock.length = 2;
+			fr_udp_pkt->cblock.result = 0;
+			break;
+
+		case FPIPE_FLUSH_DRIVER_STATS:
+			init_chan_statistics(chan);
+			init_global_statistics(card);
+			mbox->cmd.length = 0;
+			break;
+		
+		case FPIPE_ROUTER_UP_TIME:
+			do_gettimeofday(&tv);
+			chan->router_up_time = tv.tv_sec - 
+						chan->router_start_time;
+    	                *(unsigned long *)&fr_udp_pkt->data =
+    				chan->router_up_time;	
+			mbox->cmd.length = 4;
+			break;
+
+
+		case FR_FT1_STATUS_CTRL:
+			if(fr_udp_pkt->data[0] == 1) {
+				if(rCount++ != 0 ){
+					fr_udp_pkt->cblock.result = 0;
+					mbox->cmd.length = 1;
+					break;
+				} 
 			}
-	}
-	/* Fill UDP TTL */
-	data[10] = card->wandev.ttl;
-	len = reply_udp(data, mbox->cmd.length);
-	if (udp_pkt_src == UDP_PKT_FRM_NETWORK) 
-	{
-		err = fr508_send(card, dlci, 0, len, data);
-		if (err)
-			++chan->UDP_FPIPE_mgmt_adptr_send_passed;
+           
+			/* Disable FT1 MONITOR STATUS */
+                        if(fr_udp_pkt->data[0] == 0) {
+				if( --rCount != 0) {
+                                        fr_udp_pkt->cblock.result = 0;
+					mbox->cmd.length = 1;
+					break;
+				} 
+			}  
+
+		case FPIPE_DRIVER_STAT_IFSEND:
+			memcpy(fr_udp_pkt->data,
+				&chan->drvstats_if_send.if_send_entry,
+				sizeof(if_send_stat_t));
+			mbox->cmd.length = sizeof(if_send_stat_t);	
+			break;
+	
+		case FPIPE_DRIVER_STAT_INTR:
+			memcpy(fr_udp_pkt->data,
+                                &card->statistics.isr_entry,
+                                sizeof(global_stats_t));
+                        memcpy(&fr_udp_pkt->data[sizeof(global_stats_t)],
+                                &chan->drvstats_rx_intr.rx_intr_no_socket,
+                                sizeof(rx_intr_stat_t));
+			mbox->cmd.length = sizeof(global_stats_t) +
+					sizeof(rx_intr_stat_t);
+			break;
+
+		case FPIPE_DRIVER_STAT_GEN:
+                        memcpy(fr_udp_pkt->data,
+                                &chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err,
+                                sizeof(pipe_mgmt_stat_t));
+
+                        memcpy(&fr_udp_pkt->data[sizeof(pipe_mgmt_stat_t)],
+                               &card->statistics, sizeof(global_stats_t));
+
+                        fr_udp_pkt->cblock.result = 0;
+                        fr_udp_pkt->cblock.length = sizeof(global_stats_t)+
+                                                     sizeof(rx_intr_stat_t);
+                        mbox->cmd.length = fr_udp_pkt->cblock.length;
+                        break;
+		
+		default:
+ 			do {
+				memcpy(&mbox->cmd,
+					&fr_udp_pkt->cblock.command,
+					sizeof(fr_cmd_t));
+				if(mbox->cmd.length) {
+					memcpy(&mbox->data,
+						(char *)fr_udp_pkt->data,
+						mbox->cmd.length);
+				}
+ 				
+				err = sdla_exec(mbox) ? mbox->cmd.result : 
+					CMD_TIMEOUT;
+			} while (err && c_retry-- && fr_event(card, err, mbox));
+
+			if(!err)
+				chan->drvstats_gen.
+					UDP_PIPE_mgmt_adptr_cmnd_OK ++;
+			else
+                                chan->drvstats_gen.
+					UDP_PIPE_mgmt_adptr_cmnd_timeout ++;
+
+       	                /* copy the result back to our buffer */
+			memcpy(&fr_udp_pkt->cblock.command,
+				&mbox->cmd, sizeof(fr_cmd_t));
+
+                       	if(mbox->cmd.length) {
+                               	memcpy(&fr_udp_pkt->data,
+					&mbox->data, mbox->cmd.length);
+			}
+		} 
+        }
+   
+        /* Fill UDP TTL */
+        fr_udp_pkt->ip_pkt.ttl = card->wandev.ttl;
+        len = reply_udp(card->u.f.udp_pkt_data, mbox->cmd.length);
+
+        if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+		
+                err = fr_send(card, dlci, 0, len, card->u.f.udp_pkt_data);
+		if (err) 
+			chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++;
 		else
-			++chan->UDP_FPIPE_mgmt_adptr_send_failed;
-		dev_kfree_skb(skb);
-	}
-	else 
-	{
+			chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++;
+	} else {
 		/* Allocate socket buffer */
-		if ((new_skb = dev_alloc_skb(len)) != NULL) 
-		{
+		if((new_skb = dev_alloc_skb(len)) != NULL) {
+
 			/* copy data into new_skb */
 			buf = skb_put(new_skb, len);
-			memcpy(buf, data, len);
+			memcpy(buf, card->u.f.udp_pkt_data, len);
+        
 			/* Decapsulate packet and pass it up the protocol 
 			   stack */
 			new_skb->dev = dev;
-			buf = skb_pull(new_skb, 1);	/* remove hardware header */
-			if (!wanrouter_type_trans(new_skb, dev)) 
-			{
-				++chan->UDP_FPIPE_mgmt_not_passed_to_stack;
+			buf = skb_pull(new_skb, 1);  /* remove hardware header*/
+			
+			if(!wanrouter_type_trans(new_skb, dev)) {
+
+				chan->drvstats_gen.
+					UDP_PIPE_mgmt_not_passed_to_stack ++;
 				/* can't decapsulate packet */
 				dev_kfree_skb(new_skb);
-			}
-			else 
-			{
-				++chan->UDP_FPIPE_mgmt_passed_to_stack;
+			} else {
+				chan->drvstats_gen.
+					UDP_PIPE_mgmt_passed_to_stack ++;
 				netif_rx(new_skb);
-			}
-		}
-		else 
-		{
-			++chan->UDP_FPIPE_mgmt_no_socket;
-			printk(KERN_INFO
-			       "%s: UDP mgmt cmnd, no socket buffers available!\n",
-			       card->devname);
-		}
-	}
-	kfree(data);
-	return 0;
+                	}
+            	
+		} else {
+			chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++;
+			printk(KERN_INFO 
+			"%s: UDP mgmt cmnd, no socket buffers available!\n", 
+			card->devname);
+            	}
+        }
+
+	card->u.f.udp_pkt_lgth = 0;
+
+	return 1;
 }
+
 /*==============================================================================
- * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_
- * TEST_COUNTER times.
+ * Send Inverse ARP Request
  */
- 
-static int intr_test(sdla_t * card)
+
+int send_inarp_request(sdla_t *card, struct device *dev)
 {
-	fr_mbox_t *mb = card->mbox;
-	int err, i;
-	/* The critical flag is unset here because we want to get into the
-	   ISR without the flag already set. The If_open sets the flag.
-	 */
-	card->wandev.critical = 0;
-	err = fr_set_intr_mode(card, 0x08, card->wandev.mtu);
-	if (err == CMD_OK) 
-	{
-		for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) 
-		{
-			/* Run command READ_CODE_VERSION */
-			memset(&mb->cmd, 0, sizeof(fr_cmd_t));
-			mb->cmd.length = 0;
-			mb->cmd.command = 0x40;
-			err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-			if (err != CMD_OK)
-				fr_event(card, err, mb);
-		}
-	} 
-	else 
-	{
-		return err;
+	arphdr_1490_t *ArpPacket;
+	arphdr_fr_t *arphdr;
+	fr_channel_t *chan = dev->priv;
+	struct in_device *in_dev;
+
+	in_dev = dev->ip_ptr;
+	
+	if(in_dev != NULL ) {	
+
+		ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC);
+		/* SNAP Header indicating ARP */
+		ArpPacket->control	= 0x03;
+		ArpPacket->pad		= 0x00;
+		ArpPacket->NLPID	= 0x80;
+		ArpPacket->OUI[0]	= 0;
+		ArpPacket->OUI[1]	= 0;
+		ArpPacket->OUI[2]	= 0;
+		ArpPacket->PID		= 0x0608;
+
+		arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet
+
+		/* InARP request */		
+		arphdr->ar_hrd = 0x0F00;	/* Frame Relay HW type */
+		arphdr->ar_pro = 0x0008;	/* IP Protocol	       */
+		arphdr->ar_hln = 2;		/* HW addr length      */
+		arphdr->ar_pln = 4;		/* IP addr length      */
+		arphdr->ar_op = htons(0x08);	/* InARP Request       */
+		arphdr->ar_sha = 0; 		/* src HW DLCI - Doesn't matter */
+		if(in_dev->ifa_list != NULL)
+			arphdr->ar_sip = in_dev->ifa_list->ifa_local;  /* Local Address       */else
+			arphdr->ar_sip = 0;
+		arphdr->ar_tha = 0; 		/* dst HW DLCI - Doesn't matter */
+		arphdr->ar_tip = 0;		/* Remote Address -- what we want */
+
+		printk(KERN_INFO "%s: Sending InARP request on DLCI %d.\n", card->devname, chan->dlci);
+                fr_send(card, chan->dlci, 0,
+		   sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t),
+		   (void *)ArpPacket);
+		kfree(ArpPacket);
 	}
-	err = fr_set_intr_mode(card, 0, card->wandev.mtu);
-	if (err != CMD_OK)
-		return err;
-	card->wandev.critical = 1;
-	return 0;
+
+	return 1;
 }
-/*============================================================================
- * Process UDP call of type DRVSTATS.  
+	
+
+/*==============================================================================
+ * Check packet for ARP Type
  */
-static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan)
+
+int is_arp(void *buf)
 {
-	int c_retry = MAX_CMD_RETRY;
-	unsigned char *sendpacket;
-	unsigned char buf2[5];
-	unsigned char *data;
-	unsigned char *buf;
-	unsigned int len;
-	fr_mbox_t *mbox = card->mbox;
-	struct sk_buff *new_skb;
-	int err;
-	sendpacket = skb->data;
-	memcpy(&buf2, &card->wandev.udp_port, 2);
-	if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) 
-	{
-		printk(KERN_INFO
-		       "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X"
-		       ,card->devname, data[45]);
-		++chan->UDP_DRVSTATS_mgmt_kmalloc_err;
+	arphdr_1490_t *arphdr = (arphdr_1490_t *)buf;
+	
+	if (arphdr->pad   == 0x00  &&
+	    arphdr->NLPID == 0x80  &&
+	    arphdr->PID   == 0x0608) 
 		return 1;
-	}
-	memcpy(data, sendpacket, skb->len);
-	switch (data[47]) 
-	{
-		case 0x45:
-			*(unsigned long *) &data[62] = chan->if_send_entry;
-			*(unsigned long *) &data[66] = chan->if_send_skb_null;
-			*(unsigned long *) &data[70] = chan->if_send_broadcast;
-			*(unsigned long *) &data[74] = chan->if_send_multicast;
-			*(unsigned long *) &data[78] = chan->if_send_critical_ISR;
-			*(unsigned long *) &data[82] = chan->if_send_critical_non_ISR;
-			*(unsigned long *) &data[86] = chan->if_send_busy;
-			*(unsigned long *) &data[90] = chan->if_send_busy_timeout;
-			*(unsigned long *) &data[94] = chan->if_send_DRVSTATS_request;
-			*(unsigned long *) &data[98] = chan->if_send_FPIPE_request;
-			*(unsigned long *) &data[102] = chan->if_send_wan_disconnected;
-			*(unsigned long *) &data[106] = chan->if_send_dlci_disconnected;
-			*(unsigned long *) &data[110] = chan->if_send_no_bfrs;
-			*(unsigned long *) &data[114] = chan->if_send_adptr_bfrs_full;
-			*(unsigned long *) &data[118] = chan->if_send_bfrs_passed_to_adptr;
-			*(unsigned long *) &data[120] = card->irq_dis_if_send_count;
-			mbox->cmd.length = 62;
-			break;
-		case 0x46:
-			*(unsigned long *) &data[62] = card->statistics.isr_entry;
-			*(unsigned long *) &data[66] = card->statistics.isr_already_critical;
-			*(unsigned long *) &data[70] = card->statistics.isr_rx;
-			*(unsigned long *) &data[74] = card->statistics.isr_tx;
-			*(unsigned long *) &data[78] = card->statistics.isr_intr_test;
-			*(unsigned long *) &data[82] = card->statistics.isr_spurious;
-			*(unsigned long *) &data[86] = card->statistics.isr_enable_tx_int;
-			*(unsigned long *) &data[90] = card->statistics.tx_intr_dev_not_started;
-			*(unsigned long *) &data[94] = card->statistics.rx_intr_corrupt_rx_bfr;
-			*(unsigned long *) &data[98] = card->statistics.rx_intr_on_orphaned_DLCI;
-			*(unsigned long *) &data[102] = chan->rx_intr_no_socket;
-			*(unsigned long *) &data[106] = chan->rx_intr_dev_not_started;
-			*(unsigned long *) &data[110] = chan->rx_intr_DRVSTATS_request;
-			*(unsigned long *) &data[114] = chan->rx_intr_FPIPE_request;
-			*(unsigned long *) &data[118] = chan->rx_intr_bfr_not_passed_to_stack;
-			*(unsigned long *) &data[122] = chan->rx_intr_bfr_passed_to_stack;
-			mbox->cmd.length = 64;
-			break;
-		case 0x47:
-			*(unsigned long *) &data[62] = chan->UDP_FPIPE_mgmt_kmalloc_err;
-			*(unsigned long *) &data[66] = chan->UDP_FPIPE_mgmt_adptr_type_err;
-			*(unsigned long *) &data[70] = chan->UDP_FPIPE_mgmt_direction_err;
-			*(unsigned long *) &data[74] = chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout;
-			*(unsigned long *) &data[78] = chan->UDP_FPIPE_mgmt_adptr_cmnd_OK;
-			*(unsigned long *) &data[82] = chan->UDP_FPIPE_mgmt_adptr_send_passed;
-			*(unsigned long *) &data[86] = chan->UDP_FPIPE_mgmt_adptr_send_failed;
-			*(unsigned long *) &data[90] = chan->UDP_FPIPE_mgmt_no_socket;
-			*(unsigned long *) &data[94] = chan->UDP_FPIPE_mgmt_not_passed_to_stack;
-			*(unsigned long *) &data[98] = chan->UDP_FPIPE_mgmt_passed_to_stack;
-			*(unsigned long *) &data[102] = chan->UDP_DRVSTATS_mgmt_kmalloc_err;
-			*(unsigned long *) &data[106] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
-			*(unsigned long *) &data[110] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
-			*(unsigned long *) &data[114] = chan->UDP_DRVSTATS_mgmt_adptr_send_passed;
-			*(unsigned long *) &data[118] = chan->UDP_DRVSTATS_mgmt_adptr_send_failed;
-			*(unsigned long *) &data[122] = chan->UDP_DRVSTATS_mgmt_no_socket;
-			*(unsigned long *) &data[126] = chan->UDP_DRVSTATS_mgmt_not_passed_to_stack;
-			*(unsigned long *) &data[130] = chan->UDP_DRVSTATS_mgmt_passed_to_stack;
-			*(unsigned long *) &data[134] = card->statistics.poll_entry;
-			*(unsigned long *) &data[138] = card->statistics.poll_already_critical;
-			*(unsigned long *) &data[142] = card->statistics.poll_processed;
-			*(unsigned long *) &data[144] = card->irq_dis_poll_count;
-			mbox->cmd.length = 86;
-			break;
-		default:
-			do 
-			{
-				memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t));
-				if (mbox->cmd.length) 
-					memcpy(&mbox->data, &sendpacket[62], mbox->cmd.length);
-				err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-			} 
-			while (err && c_retry-- && fr_event(card, err, mbox));
+	else return 0;
+}
+
+/*==============================================================================
+ * Process ARP Packet Type
+ */
+
+int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct device* dev)
+{
+
+	arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */
+	fr_rx_buf_ctl_t* frbuf = card->rxmb;
+	struct in_device *in_dev;
+
+
+	in_dev = dev->ip_ptr;
+	if( in_dev != NULL && in_dev->ifa_list != NULL) {
+		switch (ntohs(arphdr->ar_op)) {
+
+		case 0x08:  // Inverse ARP request  -- Send Reply, add route.
 			
-			if (!err) 
-			{
-				++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
-				memcpy(data, sendpacket, skb->len);
-				memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t));
-				if (mbox->cmd.length) 
-					memcpy(&data[62], &mbox->data, mbox->cmd.length);
-			} 
-			else 
-			{
-				++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
+			/* Check for valid Address */
+			printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Req\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip));
+
+			if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) {
+				printk(KERN_INFO "%s: Invalid PtP address.  InARP ignored.\n", card->devname);
+				printk(KERN_INFO "mask %X\n", in_dev->ifa_list->ifa_mask);
+				printk(KERN_INFO "local %X\n", in_dev->ifa_list->ifa_local);
+				return -1;
 			}
-	}
-	/* Fill UDP TTL */
-	data[10] = card->wandev.ttl;
-	len = reply_udp(data, mbox->cmd.length);
-	if (udp_pkt_src == UDP_PKT_FRM_NETWORK) 
-	{
-		err = fr508_send(card, dlci, 0, len, data);
-		if (err)
-			++chan->UDP_DRVSTATS_mgmt_adptr_send_failed;
-		else
-			++chan->UDP_DRVSTATS_mgmt_adptr_send_passed;
-		dev_kfree_skb(skb);
-	}
-	else
-	{
-		/* Allocate socket buffer */
-		if ((new_skb = dev_alloc_skb(len)) != NULL) 
-		{
-			/* copy data into new_skb */
-			buf = skb_put(new_skb, len);
-			memcpy(buf, data, len);
-			/* Decapsulate packet and pass it up the 
-			   protocol stack */
-			new_skb->dev = dev;
-			/* remove hardware header */
-			buf = skb_pull(new_skb, 1);
-			if (!wanrouter_type_trans(new_skb, dev)) 
+		
+			if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) {
+				printk(KERN_INFO "%s: Local addr = PtP addr.  InARP ignored.\n", card->devname);
+				return -1;
+			}
+	
+			arphdr->ar_op = htons(0x09);	/* InARP Reply */
+
+			/* Set addresses */
+			arphdr->ar_tip = arphdr->ar_sip;
+			arphdr->ar_sip = in_dev->ifa_list->ifa_local;
+
+                        fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket);
+
+			/* Modify Point-to-Point Address */
 			{
-				/* can't decapsulate packet */
-				++chan->UDP_DRVSTATS_mgmt_not_passed_to_stack;
-				dev_kfree_skb(new_skb);
+			struct ifreq if_info;
+			struct sockaddr_in *if_data;
+			mm_segment_t fs = get_fs();
+			int err;
+
+			/* Set remote addresses */
+			memset(&if_info, 0, sizeof(if_info));
+			strcpy(if_info.ifr_name, dev->name);
+
+          		set_fs(get_ds());     /* get user space block */ 
+	
+			if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr;
+			if_data->sin_addr.s_addr = arphdr->ar_tip;
+			if_data->sin_family = AF_INET;
+			err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
+
+                	set_fs(fs);           /* restore old block */
 			}
-			else
+				
+			/* Add Route Flag */
+			/* The route will be added in the polling routine so
+			   that it is not interrupt context. */
+
+			((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE;
+			card->poll	= &process_route;
+
+			break;
+
+		case 0x09:  // Inverse ARP reply
+
+			/* Check for valid Address */
+			printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip));
+
+			if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) {
+				printk(KERN_INFO "%s: Invalid PtP address.  InARP ignored.\n", card->devname);
+				return -1;
+			}
+
+			if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) {
+				printk(KERN_INFO "%s: Local addr = PtP addr.  InARP ignored.\n", card->devname);
+				return -1;
+			}			
+
+			/* Modify Point-to-Point Address */
 			{
-				++chan->UDP_DRVSTATS_mgmt_passed_to_stack;
-				netif_rx(new_skb);
+			struct ifreq if_info;
+			struct sockaddr_in *if_data;
+			mm_segment_t fs = get_fs();
+			int err;
+
+			/* Set remote addresses */
+			memset(&if_info, 0, sizeof(if_info));
+			strcpy(if_info.ifr_name, dev->name);
+
+          		set_fs(get_ds());     /* get user space block */ 
+	
+			if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr;
+			if_data->sin_addr.s_addr = arphdr->ar_sip;
+			if_data->sin_family = AF_INET;
+			err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
+
+                	set_fs(fs);           /* restore old block */
 			}
+
+			/* Add Route Flag */
+			/* The route will be added in the polling routine so
+			   that it is not interrupt context. */
+
+			((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE;
+			((fr_channel_t *) dev->priv)->inarp = INARP_CONFIGURED;
+			card->poll	= &process_route;
+			
+			break;
+		default:  // ARP's and RARP's -- Shouldn't happen.
 		}
-		else
-		{
-			++chan->UDP_DRVSTATS_mgmt_no_socket;
-			printk(KERN_INFO "%s: UDP mgmt cmnd, no socket buffers available!\n", card->devname);
+	}
+
+	return 0;	
+}
+	
+
+/*==============================================================================
+ * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_
+ * TEST_COUNTER times.
+ */
+static int intr_test( sdla_t* card )
+{
+	fr_mbox_t* mb = card->mbox;
+	int err,i;
+
+	/* The critical flag is unset here because we want to get into the
+	   ISR without the flag already set. The If_open sets the flag.
+	*/
+        clear_bit(1, (void*)&card->wandev.critical);
+
+        err = fr_set_intr_mode(card, FR_INTR_READY, card->wandev.mtu, 0 );
+	
+	if (err == CMD_OK) {
+
+		for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) {
+ 			/* Run command READ_CODE_VERSION */
+			mb->cmd.length  = 0;
+			mb->cmd.command = FR_READ_CODE_VERSION;
+			err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+			if (err != CMD_OK) 
+				fr_event(card, err, mb);
 		}
+	
+	} else {
+		return err;	
 	}
-	kfree(data);
+
+	err = fr_set_intr_mode( card, 0, card->wandev.mtu, 0 );
+
+	if( err != CMD_OK ) 
+		return err;
+
+	set_bit(1, (void*)&card->wandev.critical);
 	return 0;
 }
 
 /*==============================================================================
- * Determine what type of UDP call it is. DRVSTATS or FPIPE8ND ?
+ * Determine what type of UDP call it is. FPIPE8ND ?
  */
-
-static int udp_pkt_type(struct sk_buff *skb, sdla_t * card)
+static int udp_pkt_type( struct sk_buff *skb, sdla_t* card )
 {
-	unsigned char *sendpacket;
-	unsigned char buf2[5];
-	sendpacket = skb->data;
-	memcpy(&buf2, &card->wandev.udp_port, 2);
-	if (sendpacket[2] == 0x45 &&	/* IP packet */
-	    sendpacket[11] == 0x11 &&	/* UDP packet */
-	    sendpacket[24] == buf2[1] &&	/* UDP Port */
-	    sendpacket[25] == buf2[0] &&
-	    sendpacket[38] == 0x01) 
-	{
-		if (sendpacket[30] == 0x46 &&	/* FPIPE8ND: Signature */
-		    sendpacket[31] == 0x50 &&
-		    sendpacket[32] == 0x49 &&
-		    sendpacket[33] == 0x50 &&
-		    sendpacket[34] == 0x45 &&
-		    sendpacket[35] == 0x38 &&
-		    sendpacket[36] == 0x4E &&
-		    sendpacket[37] == 0x44) 
-		{
-			return UDP_FPIPE_TYPE;
-		} else if (sendpacket[30] == 0x44 &&	/* DRVSTATS: Signature */
-			   sendpacket[31] == 0x52 &&
-			   sendpacket[32] == 0x56 &&
-			   sendpacket[33] == 0x53 &&
-			   sendpacket[34] == 0x54 &&
-			   sendpacket[35] == 0x41 &&
-			   sendpacket[36] == 0x54 &&
-			   sendpacket[37] == 0x53) 
-		{
-			return UDP_DRVSTATS_TYPE;
-		}
-		else
-			return UDP_INVALID_TYPE;
+	fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)skb->data;
+
+        if((fr_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) &&
+		(fr_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) &&
+		(fr_udp_pkt->udp_pkt.udp_dst_port == 
+		ntohs(card->wandev.udp_port)) &&
+		(fr_udp_pkt->wp_mgmt.request_reply == 
+		UDPMGMT_REQUEST)) {
+                        if(!strncmp(fr_udp_pkt->wp_mgmt.signature,
+                                UDPMGMT_FPIPE_SIGNATURE, 8))
+                                return UDP_FPIPE_TYPE;
 	}
-	else
-		return UDP_INVALID_TYPE;
+
+        return UDP_INVALID_TYPE;
 }
+
+
 /*==============================================================================
  * Initializes the Statistics values in the fr_channel structure.
  */
- 
-void init_chan_statistics(fr_channel_t * chan)
+void init_chan_statistics( fr_channel_t* chan)
 {
-	chan->if_send_entry = 0;
-	chan->if_send_skb_null = 0;
-	chan->if_send_broadcast = 0;
-	chan->if_send_multicast = 0;
-	chan->if_send_critical_ISR = 0;
-	chan->if_send_critical_non_ISR = 0;
-	chan->if_send_busy = 0;
-	chan->if_send_busy_timeout = 0;
-	chan->if_send_FPIPE_request = 0;
-	chan->if_send_DRVSTATS_request = 0;
-	chan->if_send_wan_disconnected = 0;
-	chan->if_send_dlci_disconnected = 0;
-	chan->if_send_no_bfrs = 0;
-	chan->if_send_adptr_bfrs_full = 0;
-	chan->if_send_bfrs_passed_to_adptr = 0;
-	chan->rx_intr_no_socket = 0;
-	chan->rx_intr_dev_not_started = 0;
-	chan->rx_intr_FPIPE_request = 0;
-	chan->rx_intr_DRVSTATS_request = 0;
-	chan->rx_intr_bfr_not_passed_to_stack = 0;
-	chan->rx_intr_bfr_passed_to_stack = 0;
-	chan->UDP_FPIPE_mgmt_kmalloc_err = 0;
-	chan->UDP_FPIPE_mgmt_direction_err = 0;
-	chan->UDP_FPIPE_mgmt_adptr_type_err = 0;
-	chan->UDP_FPIPE_mgmt_adptr_cmnd_OK = 0;
-	chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout = 0;
-	chan->UDP_FPIPE_mgmt_adptr_send_passed = 0;
-	chan->UDP_FPIPE_mgmt_adptr_send_failed = 0;
-	chan->UDP_FPIPE_mgmt_not_passed_to_stack = 0;
-	chan->UDP_FPIPE_mgmt_passed_to_stack = 0;
-	chan->UDP_FPIPE_mgmt_no_socket = 0;
-	chan->UDP_DRVSTATS_mgmt_kmalloc_err = 0;
-	chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0;
-	chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0;
-	chan->UDP_DRVSTATS_mgmt_adptr_send_passed = 0;
-	chan->UDP_DRVSTATS_mgmt_adptr_send_failed = 0;
-	chan->UDP_DRVSTATS_mgmt_not_passed_to_stack = 0;
-	chan->UDP_DRVSTATS_mgmt_passed_to_stack = 0;
-	chan->UDP_DRVSTATS_mgmt_no_socket = 0;
+        memset(&chan->drvstats_if_send.if_send_entry, 0,
+		sizeof(if_send_stat_t));
+        memset(&chan->drvstats_rx_intr.rx_intr_no_socket, 0,
+                sizeof(rx_intr_stat_t));
+        memset(&chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, 0,
+                sizeof(pipe_mgmt_stat_t));
 }
+	
 /*==============================================================================
  * Initializes the Statistics values in the Sdla_t structure.
  */
-
-void init_global_statistics(sdla_t * card)
+void init_global_statistics( sdla_t* card )
 {
 	/* Intialize global statistics for a card */
-	card->statistics.isr_entry = 0;
-	card->statistics.isr_already_critical = 0;
-	card->statistics.isr_rx = 0;
-	card->statistics.isr_tx = 0;
-	card->statistics.isr_intr_test = 0;
-	card->statistics.isr_spurious = 0;
-	card->statistics.isr_enable_tx_int = 0;
-	card->statistics.rx_intr_corrupt_rx_bfr = 0;
-	card->statistics.rx_intr_on_orphaned_DLCI = 0;
-	card->statistics.tx_intr_dev_not_started = 0;
-	card->statistics.poll_entry = 0;
-	card->statistics.poll_already_critical = 0;
-	card->statistics.poll_processed = 0;
+        memset(&card->statistics.isr_entry, 0, sizeof(global_stats_t));
 }
 
-static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan)
+static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan )
 {
-	fr_mbox_t *mbox = card->mbox;
-	int retry = MAX_CMD_RETRY;
-	dlci_IB_mapping_t *result;
-	int err, counter, found;
-	do 
-	{
-		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+	fr_mbox_t* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;	
+	dlci_IB_mapping_t* result; 
+	int err, counter, found;	
+
+	do {
 		mbox->cmd.command = FR_READ_DLCI_IB_MAPPING;
+		mbox->cmd.length = 0;	
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- && fr_event(card, err, mbox));
+
+	if( mbox->cmd.result != 0){
+		printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", 
+			chan->name);
 	}
-	while (err && retry-- && fr_event(card, err, mbox));
-	
-	if (mbox->cmd.result != 0)
-		printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", chan->name);
 
 	counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t);
-	result = (void *) mbox->data;
+	result = (void *)mbox->data;
+	
 	found = 0;
-	for (; counter; --counter, ++result) 
-	{
-		if (result->dlci == chan->dlci) 
-		{
-			printk(KERN_INFO "%s: DLCI= %d, IB addr = %lx for %s\n"
-			 ,card->devname, result->dlci, result->addr_value ,chan->name);
+	for (; counter; --counter, ++result) {
+		if ( result->dlci == chan->dlci ) {
 			chan->IB_addr = result->addr_value;
-			chan->dlci_int_interface = (void *) (card->hw.dpmbase +
-					   (chan->IB_addr & 0x00001FFF));
+			if(card->hw.type == SDLA_S514){
+	             		chan->dlci_int_interface =
+					(void*)(card->hw.dpmbase +
+					chan->IB_addr);
+       			}else{ 
+				chan->dlci_int_interface = 
+					(void*)(card->hw.dpmbase + 
+					(chan->IB_addr & 0x00001FFF));
+
+			}
 			found = 1;
-			break;
-		}
+			break;	
+		} 
 	}
 	if (!found)
-		printk(KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n",
-		       card->devname, chan->dlci);
+		printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", 
+		card->devname, chan->dlci);
+}
+
+void s508_s514_lock(sdla_t *card, unsigned long *smp_flags)
+{
+
+	if (card->hw.type != SDLA_S514){
+#ifdef __SMP__
+		spin_lock_irqsave(&card->lock, *smp_flags);
+#else
+    		disable_irq(card->hw.irq);
+#endif
+	}
+#ifdef __SMP__
+	else{
+		spin_lock(&card->lock);
+	}	
+#endif
+}
+
+void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags)
+{
+	if (card->hw.type != SDLA_S514){
+#ifdef __SMP__
+		spin_unlock_irqrestore(&card->lock, *smp_flags);
+#else
+    		enable_irq(card->hw.irq);
+#endif
+	}
+#ifdef __SMP__
+	else{
+		spin_unlock(&card->lock);
+	}	
+#endif
+
 }
 
 /****** End *****************************************************************/
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_ppp.c linux.14p16/drivers/net/sdla_ppp.c
--- linux.vanilla/drivers/net/sdla_ppp.c	Mon Jan  4 19:37:29 1999
+++ linux.14p16/drivers/net/sdla_ppp.c	Wed Dec 15 16:27:09 1999
@@ -1,21 +1,39 @@
 /*****************************************************************************
 * sdla_ppp.c	WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module.
 *
-* Author: 	Jaspreet Singh 	<jaspreet@sangoma.com>
+* Author: 	Nenad Corbic <ncorbic@sangoma.com>
 *
-* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-1999 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.
 * ============================================================================
-* Mar 15, 1998  Alan Cox	o 2.1.8x basic port.
+*
+* Oct 25, 1999  Nenad Corbic    o Support for 2.0.X kernels
+*                                 Moved dynamic route processing into 
+*                                 a polling routine.
+* Oct 07, 1999  Nenad Corbic    o Support for S514 PCI card.  
+*               Gideon Hack     o UPD and Updates executed using timer interrupt
+* Sep 10, 1999  Nenad Corbic    o Fixed up the /proc statistics
+* Jul 20, 1999  Nenad Corbic    o Remove the polling routines and use 
+*                                 interrupts instead.
+* Sep 17, 1998	Jaspreet Singh	o Updates for 2.2.X Kernels.
+* Aug 13, 1998	Jaspreet Singh	o Improved Line Tracing.
+* Jun 22, 1998	David Fong	o Added remote IP address assignment
+* Mar 15, 1998	Alan Cox	o 2.1.8x basic port.
+* Apr 16, 1998	Jaspreet Singh	o using htons() for the IPX protocol.
+* Dec 09, 1997	Jaspreet Singh	o Added PAP and CHAP.
+*				o Implemented new routines like 
+*				  ppp_set_inbnd_auth(), ppp_set_outbnd_auth(),
+*				  tokenize() and strstrip().
 * Nov 27, 1997	Jaspreet Singh	o Added protection against enabling of irqs 
 *				  while they have been disabled.
 * Nov 24, 1997  Jaspreet Singh  o Fixed another RACE condition caused by
 *                                 disabling and enabling of irqs.
-*                               o Added new counters for stats on disable/enable*                                 IRQs.
+*                               o Added new counters for stats on disable/enable
+*                                 IRQs.
 * Nov 10, 1997	Jaspreet Singh	o Initialized 'skb->mac.raw' to 'skb->data'
 *				  before every netif_rx().
 *				o Free up the device structure in del_if().
@@ -56,6 +74,7 @@
 * Jan 06, 1997	Gene Kozin	Initial version.
 *****************************************************************************/
 
+#include <linux/version.h>
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
@@ -65,10 +84,16 @@
 #include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
 #include <linux/if_arp.h>	/* ARPHRD_* defines */
 #include <asm/byteorder.h>	/* htons(), etc. */
-#include <asm/uaccess.h>	/* copyto/from user */
-#define	_GNUC_
-#include <linux/sdla_ppp.h>	/* PPP firmware API definitions */
+#include <linux/in.h>		/* sockaddr_in */
+#include <linux/inet.h>		/* in_aton(), in_ntoa() prototypes */
+
+#include <linux/inetdevice.h>
+#include <asm/uaccess.h>
 
+#include <linux/if.h>
+#include <linux/wanpipe.h>
+#include <linux/sdla_ppp.h>		/* PPP firmware API definitions */
+#include <linux/sdlasfm.h>		/* S514 Type Definition */
 /****** Defines & Macros ****************************************************/
 
 #ifdef	_DEBUG_
@@ -76,130 +101,183 @@
 #else
 #define	STATIC		static
 #endif
-#define	PPP_DFLT_MTU	1500	/* default MTU */
-#define	PPP_MAX_MTU	4000	/* maximum MTU */
+
+#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 */
+
+#define	CONNECT_TIMEOUT	(90*HZ)		/* link connection timeout */
+#define	HOLD_DOWN_TIME	(5*HZ)		/* link hold down time : Changed from 30 to 5 */
 
 /* For handle_IPXWAN() */
 #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
 
+/* Macro for enabling/disabling debugging comments */
+//#define NEX_DEBUG
+#ifdef NEX_DEBUG
+#define NEX_PRINTK(format, a...) printk(format, ## a)
+#else
+#define NEX_PRINTK(format, a...)
+#endif /* NEX_DEBUG */ 
+
+#define DCD(a)   ( a & 0x08 ? "HIGH" : "LOW" )
+#define CTS(a)   ( a & 0x20 ? "HIGH" : "LOW" )
+#define LCP(a)   ( a == 0x09 ? "OPEN" : "CLOSED" )
+#define IP(a)    ( a == 0x09 ? "ENABLED" : "DISABLED" )
+
+#define TMR_INT_ENABLED_UPDATE  	1
+#define TMR_INT_ENABLED_PPP_EVENT	2
+#define TMR_INT_ENABLED_UDP		4
+
+/* Set Configuraton Command Definitions */
+#define PERCENT_TX_BUFF			60
+#define TIME_BETWEEN_CONF_REQ  		30
+#define TIME_BETWEEN_PAP_CHAP_REQ	30
+#define WAIT_PAP_CHAP_WITHOUT_REPLY     300
+#define WAIT_AFTER_DCD_CTS_LOW          5
+#define TIME_DCD_CTS_LOW_AFTER_LNK_DOWN 10
+#define WAIT_DCD_HIGH_AFTER_ENABLE_COMM 900
+#define MAX_CONF_REQ_WITHOUT_REPLY      10
+#define MAX_TERM_REQ_WITHOUT_REPLY      2
+#define NUM_CONF_NAK_WITHOUT_REPLY      5
+#define NUM_AUTH_REQ_WITHOUT_REPLY      10
+
+#define END_OFFSET 0x1F0
+#if LINUX_VERSION_CODE < 0x020125
+#define test_and_set_bit set_bit
+#endif
+
 /******Data Structures*****************************************************/
+
 /* This structure is placed in the private data area of the device structure.
  * The card structure used to occupy the private area but now the following 
  * structure will incorporate the card structure along with PPP specific data
  */
-
-typedef struct ppp_private_area 
+  
+typedef struct ppp_private_area
 {
-	sdla_t *card;
+	sdla_t* card;	
 	unsigned long router_start_time;	/*router start time in sec */
-	unsigned long tick_counter;	/*used for 5 second counter */
-	unsigned mc;		/*multicast support on or off */
+	unsigned long tick_counter;		/*used for 5 second counter*/
+	unsigned mc;				/*multicast support on or off*/
+	unsigned char enable_IPX;
+	unsigned long network_number;
+	unsigned char pap;
+	unsigned char chap;
+	unsigned char sysname[31];		/* system name for in-bnd auth*/
+	unsigned char userid[511];		/* list of user ids */
+	unsigned char passwd[511];		/* list of passwords */
+	unsigned protocol;			/* SKB Protocol */
+	u32 ip_local;				/* Local IP Address */
+	u32 ip_remote;				/* remote IP Address */
+
+	unsigned char timer_int_enabled;	/* Who enabled the timer inter*/
+	unsigned char update_comms_stats;	/* Used by update function */
+	unsigned long curr_trace_addr;		/* Trace information */
+	unsigned long start_trace_addr;
+	unsigned long end_trace_addr;
+
+	unsigned short udp_pkt_lgth;
+	char  udp_pkt_src;
+      	char  udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT];
+
 	/* PPP specific statistics */
-	unsigned long if_send_entry;
-	unsigned long if_send_skb_null;
-	unsigned long if_send_broadcast;
-	unsigned long if_send_multicast;
-	unsigned long if_send_critical_ISR;
-	unsigned long if_send_critical_non_ISR;
-	unsigned long if_send_busy;
-	unsigned long if_send_busy_timeout;
-	unsigned long if_send_DRVSTATS_request;
-	unsigned long if_send_PTPIPE_request;
-	unsigned long if_send_wan_disconnected;
-	unsigned long if_send_adptr_bfrs_full;
-	unsigned long if_send_protocol_error;
-	unsigned long if_send_tx_int_enabled;
-	unsigned long if_send_bfr_passed_to_adptr;
-	unsigned long rx_intr_no_socket;
-	unsigned long rx_intr_DRVSTATS_request;
-	unsigned long rx_intr_PTPIPE_request;
-	unsigned long rx_intr_bfr_not_passed_to_stack;
-	unsigned long rx_intr_bfr_passed_to_stack;
-	unsigned long UDP_PTPIPE_mgmt_kmalloc_err;
-	unsigned long UDP_PTPIPE_mgmt_adptr_type_err;
-	unsigned long UDP_PTPIPE_mgmt_direction_err;
-	unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_timeout;
-	unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_OK;
-	unsigned long UDP_PTPIPE_mgmt_passed_to_adptr;
-	unsigned long UDP_PTPIPE_mgmt_passed_to_stack;
-	unsigned long UDP_PTPIPE_mgmt_no_socket;
-	unsigned long UDP_DRVSTATS_mgmt_kmalloc_err;
-	unsigned long UDP_DRVSTATS_mgmt_adptr_type_err;
-	unsigned long UDP_DRVSTATS_mgmt_direction_err;
-	unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
-	unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
-	unsigned long UDP_DRVSTATS_mgmt_passed_to_adptr;
-	unsigned long UDP_DRVSTATS_mgmt_passed_to_stack;
-	unsigned long UDP_DRVSTATS_mgmt_no_socket;
-	unsigned long router_up_time;
-} ppp_private_area_t;
 
-/* variable for keeping track of enabling/disabling FT1 monitor status */
+	if_send_stat_t if_send_stat;
+	rx_intr_stat_t rx_intr_stat;
+	pipe_mgmt_stat_t pipe_mgmt_stat;
 
+	unsigned long router_up_time; 
+
+}ppp_private_area_t;
+
+/* variable for keeping track of enabling/disabling FT1 monitor status */
 static int rCount = 0;
+
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
 
 /****** 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);
+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);
+
 /* WANPIPE-specific entry points */
-static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data);
+static int wpp_exec (struct sdla *card, void *u_cmd, void *u_data);
+
 /* 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_header(struct sk_buff *skb, struct device *dev, unsigned short type, 
+		     void *daddr, void *saddr, unsigned len);
 static int if_rebuild_hdr(struct sk_buff *skb);
+static struct net_device_stats *if_stats(struct device *dev);
 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_get_err_stats(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);
+static int ppp_read_version(sdla_t *card, char *str);
+static int ppp_set_outbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area);
+static int ppp_set_inbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area);
+static int ppp_configure(sdla_t *card, void *data);
+static int ppp_set_intr_mode(sdla_t *card, unsigned char mode);
+static int ppp_comm_enable(sdla_t *card);
+static int ppp_comm_disable(sdla_t *card);
+static int ppp_get_err_stats(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);
+
+STATIC void wpp_isr(sdla_t *card);
+static void rx_intr(sdla_t *card);
+static void event_intr(sdla_t *card);
+static void timer_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);
+static void process_route(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 int read_info( sdla_t *card );
+static int read_connection_info (sdla_t *card);
+static int remove_route( sdla_t *card );
+static int config508(ppp_private_area_t *ppp_priv_area, sdla_t *card);
 static void show_disc_cause(sdla_t * card, unsigned cause);
-static unsigned char bps_to_speed_code(unsigned long bps);
-static int reply_udp(unsigned char *data, unsigned int mbox_len);
-static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, ppp_private_area_t * ppp_priv_area);
-static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, ppp_private_area_t * ppp_priv_area);
-static void init_ppp_tx_rx_buff(sdla_t * card);
-static int intr_test(sdla_t * card);
-static int udp_pkt_type(struct sk_buff *skb, sdla_t * card);
-static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area);
-static void init_global_statistics(sdla_t * card);
+static int reply_udp( unsigned char *data, unsigned int mbox_len );
+static void process_udp_mgmt_pkt(sdla_t *card, struct device *dev, 
+				ppp_private_area_t *ppp_priv_area);
+static void init_ppp_tx_rx_buff( sdla_t *card );
+static int intr_test( sdla_t *card );
+static int udp_pkt_type( struct sk_buff *skb , sdla_t *card);
+static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area);
+static void init_global_statistics( sdla_t *card );
+static int tokenize(char *str, char **tokens);
+static char* strstrip(char *str, char *s);
+static int chk_bcast_mcast_addr(sdla_t* card, struct device* dev,
+				struct sk_buff *skb);
+static int Read_connection_info;
 static int Intr_test_counter;
-static char TracingEnabled;
-static unsigned long curr_trace_addr;
-static unsigned long start_trace_addr;
 static unsigned short available_buffer_space;
+
 /* IPX functions */
-static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming);
-static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto);
+static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, 
+			       unsigned char incoming);
+static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_PX, 
+			 unsigned long network_number, unsigned short proto);
+
+/* Lock Functions */
+static void s508_lock (sdla_t *card, unsigned long *smp_flags);
+static void s508_unlock (sdla_t *card, unsigned long *smp_flags);
+
+static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
+                                struct sk_buff *skb, struct device* dev,
+                                ppp_private_area_t* ppp_priv_area );
+static unsigned short calc_checksum (char *data, int len);
+
+
+
 
 /****** Public Functions ****************************************************/
 
@@ -215,30 +293,40 @@
  * Return:	0	o.k.
  *		< 0	failure.
  */
-int wpp_init(sdla_t * card, wandev_conf_t * conf)
+int wpp_init(sdla_t *card, wandev_conf_t *conf)
 {
-	union {
+	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);
+			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;
+
+	/* Initialize miscellaneous pointers to structures on the adapter */
+	switch (card->hw.type) {
+
+		case SDLA_S508:
+			card->mbox =(void*)(card->hw.dpmbase + PPP508_MB_OFFS);
+			card->flags=(void*)(card->hw.dpmbase + PPP508_FLG_OFFS);
+			break;
+		
+		case SDLA_S514:
+			card->mbox =(void*)(card->hw.dpmbase + PPP514_MB_OFFS);
+			card->flags=(void*)(card->hw.dpmbase + PPP514_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
@@ -246,33 +334,36 @@
 	 */
 	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);
+	
+	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->exec = &wpp_exec;
-	card->wandev.update = &update;
-	card->wandev.new_if = &new_if;
-	card->wandev.del_if = &del_if;
-	card->wandev.state = WAN_DISCONNECTED;
-	card->wandev.udp_port = conf->udp_port;
-	card->wandev.ttl = conf->ttl;
+		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		= NULL; 
+	card->exec		= &wpp_exec;
+	card->wandev.update	= &update;
+	card->wandev.new_if	= &new_if;
+	card->wandev.del_if	= &del_if;
+	card->wandev.state	= WAN_DISCONNECTED;
+        card->wandev.udp_port   = conf->udp_port;
+	card->wandev.ttl	= conf->ttl;
 	card->irq_dis_if_send_count = 0;
-	card->irq_dis_poll_count = 0;
-	TracingEnabled = 0;
-	card->wandev.enable_IPX = conf->enable_IPX;
-	if (conf->network_number)
-		card->wandev.network_number = conf->network_number;
-	else
-		card->wandev.network_number = 0xDEADBEEF;
+        card->irq_dis_poll_count = 0;
+	card->u.p.authenticator = conf->u.ppp.authenticator;
+	card->u.p.ip_mode 	= conf->u.ppp.ip_mode ?
+				 conf->u.ppp.ip_mode : WANOPT_PPP_STATIC;
+        card->TracingEnabled    = 0;
+	Read_connection_info    = 1;
+
 	/* initialize global statistics */
-	init_global_statistics(card);
+	init_global_statistics( card );
+
 	return 0;
 }
 
@@ -281,19 +372,43 @@
 /*============================================================================
  * Update device status & statistics.
  */
-static int update(wan_device_t * wandev)
+static int update(wan_device_t *wandev)
 {
-	sdla_t *card;
+	sdla_t* card = wandev->private;
+ 	struct device* dev = card->wandev.dev;
+        volatile ppp_private_area_t *ppp_priv_area = dev->priv;
+	ppp_flags_t *flags = card->flags;
+	unsigned long timeout;
+
 	/* sanity checks */
 	if ((wandev == NULL) || (wandev->private == NULL))
 		return -EFAULT;
+	
 	if (wandev->state == WAN_UNCONFIGURED)
 		return -ENODEV;
-	if (test_and_set_bit(0, (void *) &wandev->critical))
+	
+	//FIXME: Do we need this
+	if (test_bit(0, (void*)&wandev->critical))
 		return -EAGAIN;
-	card = wandev->private;
-	ppp_get_err_stats(card);
-	wandev->critical = 0;
+	
+	ppp_priv_area->update_comms_stats = 2;
+	ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UPDATE;
+	flags->imask |= PPP_INTR_TIMER;	
+	
+	/* wait a maximum of 1 second for the statistics to be updated */ 
+        timeout = jiffies;
+        for(;;) {
+		if(ppp_priv_area->update_comms_stats == 0){
+			break;
+		}
+                if ((jiffies - timeout) > (1 * HZ)){
+    			ppp_priv_area->update_comms_stats = 0;
+ 			ppp_priv_area->timer_int_enabled &=
+				~TMR_INT_ENABLED_UPDATE; 
+ 			return -EAGAIN;
+		}
+        }
+
 	return 0;
 }
 
@@ -309,46 +424,98 @@
  * 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)
+static int new_if(wan_device_t *wandev, struct device *dev, wanif_conf_t *conf)
 {
 	sdla_t *card = wandev->private;
 	ppp_private_area_t *ppp_priv_area;
+	
 	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);
+			card->devname);
 		return -EINVAL;
+
 	}
+
 	/* allocate and initialize private data */
 	ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL);
-	if (ppp_priv_area == NULL)
-		return -ENOMEM;
+	
+	if( ppp_priv_area == NULL )
+		return	-ENOMEM;
+	
 	memset(ppp_priv_area, 0, sizeof(ppp_private_area_t));
-	ppp_priv_area->card = card;
+	
+	ppp_priv_area->card = card; 
+	
 	/* initialize data */
 	strcpy(card->u.p.if_name, conf->name);
+
 	/* initialize data in ppp_private_area structure */
-	init_ppp_priv_struct(ppp_priv_area);
+	
+	init_ppp_priv_struct( ppp_priv_area );
+
 	ppp_priv_area->mc = conf->mc;
+	ppp_priv_area->pap = conf->pap;
+	ppp_priv_area->chap = conf->chap;
+
+	/* If no user ids are specified */
+	if(!strlen(conf->userid) && (ppp_priv_area->pap||ppp_priv_area->chap)){
+		kfree(ppp_priv_area);
+		return -EINVAL;
+	}
+
+	/* If no passwords are specified */
+	if(!strlen(conf->passwd) && (ppp_priv_area->pap||ppp_priv_area->chap)){
+		kfree(ppp_priv_area);
+		return -EINVAL;
+	}
+
+	if(strlen(conf->sysname) > 31){
+		kfree(ppp_priv_area);
+		return -EINVAL;
+	}
+
+	/* If no system name is specified */
+	if(!strlen(conf->sysname) && (card->u.p.authenticator)){
+		kfree(ppp_priv_area);
+		return -EINVAL;
+	}
+
+	/* copy the data into the ppp private structure */
+	memcpy(ppp_priv_area->userid, conf->userid, strlen(conf->userid));
+	memcpy(ppp_priv_area->passwd, conf->passwd, strlen(conf->passwd));
+	memcpy(ppp_priv_area->sysname, conf->sysname, strlen(conf->sysname));
+
+	
+	ppp_priv_area->enable_IPX = conf->enable_IPX;
+	if (conf->network_number)
+		ppp_priv_area->network_number = conf->network_number;
+	else
+		ppp_priv_area->network_number = 0xDEADBEEF;
+
+
 	/* prepare network device data space for registration */
 	dev->name = card->u.p.if_name;
 	dev->init = &if_init;
 	dev->priv = ppp_priv_area;
+
 	return 0;
 }
 
 /*============================================================================
  * Delete logical channel.
  */
-
-static int del_if(wan_device_t * wandev, struct device *dev)
+static int del_if(wan_device_t *wandev, struct device *dev)
 {
 	if (dev->priv) {
-		kfree(dev->priv);
-		dev->priv = NULL;
-	}
+
+                kfree(dev->priv);
+                dev->priv = NULL;
+        }
+
 	return 0;
 }
 
@@ -358,26 +525,36 @@
  * Execute adapter interface command.
  */
 
+//FIXME: Why do we need this ????
 static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data)
 {
 	ppp_mbox_t *mbox = card->mbox;
 	int len;
-	if(copy_from_user((void *) &mbox->cmd, u_cmd, sizeof(ppp_cmd_t)))
+
+	if (copy_from_user((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t)))
 		return -EFAULT;
+
 	len = mbox->cmd.length;
+
 	if (len) {
-		if(copy_from_user((void *) &mbox->data, u_data, len))
+
+		if( copy_from_user((void*)&mbox->data, u_data, len))
 			return -EFAULT;
+
 	}
+
 	/* execute command */
 	if (!sdla_exec(mbox))
 		return -EIO;
+
 	/* return result */
-	if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(ppp_cmd_t)))
+	if( copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(ppp_cmd_t)))
 		return -EFAULT;
 	len = mbox->cmd.length;
-	if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len))
+
+	if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len))
 		return -EFAULT;
+
 	return 0;
 }
 
@@ -390,32 +567,49 @@
  * interface registration.  Returning anything but zero will fail interface
  * registration.
  */
-
 static int if_init(struct device *dev)
 {
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	sdla_t *card = ppp_priv_area->card;
 	wan_device_t *wandev = &card->wandev;
+#ifndef LINUX_2_1
+	int i;
+#endif
 
 	/* 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;
+	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->type = ARPHRD_PPP;	/* ARP h/w type */
-	dev->mtu = wandev->mtu;
-	dev->hard_header_len = PPP_HDR_LEN;	/* media header length */
+	dev->type		= ARPHRD_PPP;	/* ARP h/w type */
+	dev->flags	       |= IFF_POINTOPOINT;
+
+	/* Enable Mulitcasting if specified by user*/
+	if (ppp_priv_area->mc == WANOPT_YES){
+		dev->flags     |= IFF_MULTICAST;
+	}
+
+#ifndef LINUX_2_1
+	dev->family		= AF_INET;
+#endif	
+	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 = (unsigned long)wandev->maddr;
-	dev->mem_end = dev->mem_start + wandev->msize - 1;
-	/* Set transmit buffer queue length */
-	dev->tx_queue_len = 100;
+	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;
+
+        /* Set transmit buffer queue length */
+        dev->tx_queue_len = 100;
+   
 	/* Initialize socket buffers */
 	dev_init_buffers(dev);
 	return 0;
@@ -428,7 +622,6 @@
  *
  * Return 0 if O.k. or errno.
  */
-
 static int if_open(struct device *dev)
 {
 	ppp_private_area_t *ppp_priv_area = dev->priv;
@@ -436,48 +629,100 @@
 	ppp_flags_t *flags = card->flags;
 	struct timeval tv;
 	int err = 0;
+
 	if (dev->start)
-		return -EBUSY;	/* only one open is allowed */
-	if (test_and_set_bit(0, (void *) &card->wandev.critical))
+		return -EBUSY;		/* only one open is allowed */
+	
+	if (test_and_set_bit(0, (void*)&card->wandev.critical))
 		return -EAGAIN;
-	if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)) {
-		err = -EIO;
-		card->wandev.critical = 0;
-		return err;
-	}
-	Intr_test_counter = 0;
-	err = intr_test(card);
-	if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) {
-		printk(KERN_INFO "%s: Interrupt Test Failed, Counter: %i\n",
-		       card->devname, Intr_test_counter);
-		err = -EIO;
-		card->wandev.critical = 0;
-		return err;
+
+	if (!card->configured){
+
+		if (config508(ppp_priv_area, card)){
+
+			err = -EIO;
+			card->wandev.critical = 0;
+			return err;
+		}
+
+		Intr_test_counter = 0;
+		err = intr_test( card );
+
+		if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) {
+			printk("%s: Interrupt Test Failed, Counter: %i\n", 
+				card->devname, Intr_test_counter);
+			printk( "%s: Please choose another interrupt\n",card->devname);
+			err = -EIO;
+			card->wandev.critical = 0;
+			return err;
+		}
+		
+		printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", 
+			card->devname, Intr_test_counter);
+		card->configured = 1;
+
 	}
-	printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n",
-	       card->devname, Intr_test_counter);
+
 	/* Initialize Rx/Tx buffer control fields */
-	init_ppp_tx_rx_buff(card);
-	if (ppp_set_intr_mode(card, 0x03)) {
+	init_ppp_tx_rx_buff( card );
+
+	if (ppp_set_intr_mode(card, PPP_INTR_RXRDY|
+			    		PPP_INTR_TXRDY|
+				    	PPP_INTR_MODEM|
+				    	PPP_INTR_CMD  |
+				    	PPP_INTR_DISC |
+				    	PPP_INTR_OPEN |
+				    	PPP_INTR_DROP_DTR |
+					PPP_INTR_TIMER)) {
+	
 		err = -EIO;
 		card->wandev.critical = 0;
 		return err;
+
+	}
+
+        /* Turn off the transmit and timer interrupt */
+	flags->imask &= ~(PPP_INTR_TXRDY | PPP_INTR_TIMER) ;
+
+	/* If you are not the authenticator and any one of the protocol is 
+	 * enabled then we call the set_out_bound_authentication.
+	 */
+	if ( !card->u.p.authenticator  && (ppp_priv_area->pap || ppp_priv_area->chap)) {
+		if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){
+			err = -EIO;
+			card->wandev.critical = 0;
+			return err;
+		}
+	} 
+	
+	/* If you are the authenticator and any one of the protocol is enabled
+	 * then we call the set_in_bound_authentication.
+	 */
+	if ( card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) {
+		if ( ppp_set_inbnd_auth(card, ppp_priv_area) ){
+			err = -EIO;
+			card->wandev.critical = 0;
+			return err;
+		}
 	}
-	flags->imask &= ~0x02;
+
 	if (ppp_comm_enable(card)) {
 		err = -EIO;
 		card->wandev.critical = 0;
 		return err;
 	}
+	
+	
 	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;
-	do_gettimeofday(&tv);
+	do_gettimeofday( &tv );
 	ppp_priv_area->router_start_time = tv.tv_sec;
 	card->wandev.critical = 0;
+
 	return err;
 }
 
@@ -486,13 +731,14 @@
  * o if this is the last open, then disable communications and interrupts.
  * o reset flags.
  */
-
 static int if_close(struct device *dev)
 {
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	sdla_t *card = ppp_priv_area->card;
-	if (test_and_set_bit(0, (void *) &card->wandev.critical))
+
+	if (test_and_set_bit(0, (void*)&card->wandev.critical))
 		return -EAGAIN;
+	
 	dev->start = 0;
 	wanpipe_close(card);
 	wanpipe_set_state(card, WAN_DISCONNECTED);
@@ -511,19 +757,21 @@
  *
  * Return:	media header length.
  */
-
 static int if_header(struct sk_buff *skb, struct device *dev,
-	     unsigned short type, void *daddr, void *saddr, unsigned len)
+	unsigned short type, void *daddr, void *saddr, unsigned len)
 {
-	switch (type) 
+	switch (type)
 	{
 		case ETH_P_IP:
+	
 		case ETH_P_IPX:
-			skb->protocol = type;
+			skb->protocol = htons(type);
 			break;
+
 		default:
 			skb->protocol = 0;
 	}
+
 	return PPP_HDR_LEN;
 }
 
@@ -534,13 +782,14 @@
  *		0	physical address not resolved
  */
 
-static int if_rebuild_hdr(struct sk_buff *skb)
+static int if_rebuild_hdr (struct sk_buff *skb)
 {
-	struct device *dev=skb->dev;
+	struct device *dev = skb->dev;
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	sdla_t *card = ppp_priv_area->card;
+
 	printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
-	       card->devname, dev->name);
+		card->devname, dev->name);
 	return 1;
 }
 
@@ -561,303 +810,355 @@
  * 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)
+static int if_send (struct sk_buff *skb, struct device *dev)
 {
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	sdla_t *card = ppp_priv_area->card;
 	unsigned char *sendpacket;
-	unsigned long check_braddr, check_mcaddr;
-	unsigned long host_cpu_flags;
+	unsigned long smp_flags;
 	ppp_flags_t *flags = card->flags;
 	int retry = 0;
-	int err, udp_type;
-	++ppp_priv_area->if_send_entry;
+	int udp_type;
+	
+	
+	++ppp_priv_area->if_send_stat.if_send_entry;
+
 	if (skb == NULL) {
+
 		/* If we get here, some higher layer thinks we've missed an
 		 * tx-done interrupt.
 		 */
 		printk(KERN_INFO "%s: interface %s got kicked!\n",
-		       card->devname, dev->name);
-		++ppp_priv_area->if_send_skb_null;
+			card->devname, dev->name);
+		
+		++ppp_priv_area->if_send_stat.if_send_skb_null;
+		
 		mark_bh(NET_BH);
 		return 0;
+
 	}
+
 	if (dev->tbusy) {
+
 		/* If our device stays busy for at least 5 seconds then we will
 		 * kick start the device by making dev->tbusy = 0.  We expect 
 		 * that our device never stays busy more than 5 seconds. So this
 		 * is only used as a last resort. 
 		 */
-		++ppp_priv_area->if_send_busy;
-		++card->wandev.stats.collisions;
-		if ((jiffies - ppp_priv_area->tick_counter) < (5 * HZ)) {
+              
+		++ppp_priv_area->if_send_stat.if_send_tbusy;
+        	++card->wandev.stats.collisions;
+
+		if ((jiffies - ppp_priv_area->tick_counter) < (5*HZ)) {
 			return 1;
 		}
-		printk(KERN_INFO "%s: Transmit times out\n", card->devname);
-		++ppp_priv_area->if_send_busy_timeout;
-		/* unbusy the card (because only one interface per card) */
+
+		printk (KERN_INFO "%s: Transmit times out\n",card->devname);
+	
+		++ppp_priv_area->if_send_stat.if_send_tbusy_timeout;
+		++card->wandev.stats.collisions;
+
+		/* unbusy the card (because only one interface per card)*/
 		dev->tbusy = 0;
-	}
+	}	
 	sendpacket = skb->data;
-	udp_type = udp_pkt_type(skb, card);
-	if (udp_type == UDP_DRVSTATS_TYPE) {
-		++ppp_priv_area->if_send_DRVSTATS_request;
-		process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev,
-					ppp_priv_area);
-		dev_kfree_skb(skb);
-		return 0;
-	} else if (udp_type == UDP_PTPIPE_TYPE)
-		++ppp_priv_area->if_send_PTPIPE_request;
-	/* retreive source address in two forms: broadcast & multicast */
-	check_braddr = sendpacket[15];
-	check_mcaddr = sendpacket[12];
-	check_braddr = check_braddr << 8;
-	check_mcaddr = check_mcaddr << 8;
-	check_braddr |= sendpacket[14];
-	check_mcaddr |= sendpacket[13];
-	check_braddr = check_braddr << 8;
-	check_mcaddr = check_mcaddr << 8;
-	check_braddr |= sendpacket[13];
-	check_mcaddr |= sendpacket[14];
-	check_braddr = check_braddr << 8;
-	check_mcaddr = check_mcaddr << 8;
-	check_braddr |= sendpacket[12];
-	check_mcaddr |= sendpacket[15];
-	/* if the Source Address is a Multicast address */
-	if ((ppp_priv_area->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001)
-	    && (check_mcaddr <= 0xFFFFFFFE)) {
-		printk(KERN_INFO "%s: Mutlicast Src. Addr. silently discarded\n"
-		       ,card->devname);
-		dev_kfree_skb(skb);
-		++ppp_priv_area->if_send_multicast;
-		++card->wandev.stats.tx_dropped;
+
+	udp_type = udp_pkt_type( skb, card );
+
+
+	if (udp_type == UDP_PTPIPE_TYPE){
+		if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev,
+                	              ppp_priv_area)){
+	               	flags->imask |= PPP_INTR_TIMER;
+		}
+		++ppp_priv_area->if_send_stat.if_send_PIPE_request;
 		return 0;
+
 	}
-	disable_irq(card->hw.irq);
-	++card->irq_dis_if_send_count;
-	if (test_and_set_bit(0, (void *) &card->wandev.critical)) {
-		if (card->wandev.critical == CRITICAL_IN_ISR) {
-			/* If the critical flag is set due to an Interrupt
-			 * then set enable transmit interrupt flag to enable
-			 * transmit interrupt. (delay interrupt)
-			 */
-			card->wandev.enable_tx_int = 1;
-			dev->tbusy = 1;
-			/* set the counter to see if we get the interrupt in
-			 * 5 seconds. 
-			 */
-			ppp_priv_area->tick_counter = jiffies;
-			++ppp_priv_area->if_send_critical_ISR;
-			save_flags(host_cpu_flags);
-			cli();
-			if ((!(--card->irq_dis_if_send_count)) &&
-			    (!card->irq_dis_poll_count))
-				enable_irq(card->hw.irq);
-			restore_flags(host_cpu_flags);
-			return 1;
+
+	/* Check for broadcast and multicast addresses 
+	 * If found, drop (deallocate) a packet and return.
+	 */
+	if(chk_bcast_mcast_addr(card, dev, skb)){
+                        return 0;
+	}
+
+
+ 	if(card->hw.type != SDLA_S514){
+		s508_lock(card,&smp_flags);
+	}
+
+    	if (test_and_set_bit(0, (void*)&card->wandev.critical)) {
+
+		printk(KERN_INFO "%s: Critical in if_send: %x\n",
+				card->wandev.name,card->wandev.critical);
+    		dev_kfree_skb(skb);
+
+		++card->wandev.stats.tx_dropped;
+		++ppp_priv_area->if_send_stat.if_send_critical_non_ISR;
+	
+		if(card->hw.type != SDLA_S514){	
+			s508_unlock(card,&smp_flags);
 		}
-		dev_kfree_skb(skb);
-		++ppp_priv_area->if_send_critical_non_ISR;
-		save_flags(host_cpu_flags);
-		cli();
-		if ((!(--card->irq_dis_if_send_count)) &&
-		    (!card->irq_dis_poll_count))
-			enable_irq(card->hw.irq);
-		restore_flags(host_cpu_flags);
+
 		return 0;
 	}
-	if (udp_type == UDP_PTPIPE_TYPE) {
-		err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb,
-					   dev, ppp_priv_area);
-	} else if (card->wandev.state != WAN_CONNECTED) {
-		++ppp_priv_area->if_send_wan_disconnected;
-		++card->wandev.stats.tx_dropped;
-	} else if (!skb->protocol) {
-		++ppp_priv_area->if_send_protocol_error;
-		++card->wandev.stats.tx_errors;
+
+	if (card->wandev.state != WAN_CONNECTED) {
+
+		++ppp_priv_area->if_send_stat.if_send_wan_disconnected;
+        	++card->wandev.stats.tx_dropped;
+
+     	} else if (!skb->protocol) {
+		++ppp_priv_area->if_send_stat.if_send_protocol_error;
+        	++card->wandev.stats.tx_errors;
+
 	} else {
-		/*If it's IPX change the network numbers to 0 if they're ours. */
-		if (skb->protocol == ETH_P_IPX) {
-			if (card->wandev.enable_IPX) {
-				switch_net_numbers(skb->data,
-					 card->wandev.network_number, 0);
+
+		/*If it's IPX change the network numbers to 0 if they're ours.*/
+		if( skb->protocol == htons(ETH_P_IPX) ) {
+			if(ppp_priv_area->enable_IPX) {
+				switch_net_numbers( skb->data, 
+					ppp_priv_area->network_number, 0);
 			} else {
 				++card->wandev.stats.tx_dropped;
 				goto tx_done;
 			}
 		}
+
 		if (ppp_send(card, skb->data, skb->len, skb->protocol)) {
 			retry = 1;
 			dev->tbusy = 1;
-			++ppp_priv_area->if_send_adptr_bfrs_full;
-			++ppp_priv_area->if_send_tx_int_enabled;
+			++ppp_priv_area->if_send_stat.if_send_adptr_bfrs_full;
+			++ppp_priv_area->if_send_stat.if_send_tx_int_enabled;
 			ppp_priv_area->tick_counter = jiffies;
-			++card->wandev.stats.tx_errors;
 			flags->imask |= 0x02;	/* unmask Tx interrupts */
 		} else {
-			++ppp_priv_area->if_send_bfr_passed_to_adptr;
+			++ppp_priv_area->if_send_stat.if_send_bfr_passed_to_adptr;
 			++card->wandev.stats.tx_packets;
 			card->wandev.stats.tx_bytes += skb->len;
 		}
-	}
-tx_done:
-	if (!retry) {
+    	}
+	
+tx_done:	
+	if (!retry){
 		dev_kfree_skb(skb);
 	}
+
 	card->wandev.critical = 0;
-	save_flags(host_cpu_flags);
-	cli();
-	if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
-		enable_irq(card->hw.irq);
-	restore_flags(host_cpu_flags);
+	
+	if(card->hw.type != SDLA_S514){	
+		s508_unlock(card,&smp_flags);
+	}
+
+	
 	return retry;
 }
 
+
+/*=============================================================================
+ * Store a UDP management packet for later processing.
+ */
+
+static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
+                                struct sk_buff *skb, struct device* dev,
+                                ppp_private_area_t* ppp_priv_area )
+{
+	int udp_pkt_stored = 0;
+
+	if(!ppp_priv_area->udp_pkt_lgth && (skb->len<=MAX_LGTH_UDP_MGNT_PKT)){
+        	ppp_priv_area->udp_pkt_lgth = skb->len;
+		ppp_priv_area->udp_pkt_src = udp_pkt_src;
+       		memcpy(ppp_priv_area->udp_pkt_data, skb->data, skb->len);
+		ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UDP;
+		ppp_priv_area->protocol = skb->protocol;
+		udp_pkt_stored = 1;
+	}else{
+		if (skb->len > MAX_LGTH_UDP_MGNT_PKT){
+			printk(KERN_INFO "%s: PIPEMON UDP request too long : %i\n",
+				card->devname, skb->len);
+		}else{
+			printk(KERN_INFO "%s: PIPEMON UPD request already pending\n",
+				card->devname);
+		}
+		ppp_priv_area->udp_pkt_lgth = 0;
+	}
+
+	dev_kfree_skb(skb);
+	return(udp_pkt_stored);
+}
+
+
+
 /*============================================================================
  * Reply to UDP Management system.
  * Return length of reply.
  */
-
-static int reply_udp(unsigned char *data, unsigned int mbox_len)
+static int reply_udp( unsigned char *data, unsigned int mbox_len ) 
 {
-	unsigned short len, udp_length, temp, i, ip_length;
-	unsigned long sum;
+	unsigned short len, udp_length, temp, ip_length;
+	unsigned long ip_temp;
+	int even_bound = 0;
+	ppp_udp_pkt_t *p_udp_pkt = (ppp_udp_pkt_t *)data;
+ 
 	/* Set length of packet */
-	len = mbox_len + 60;
+	len = sizeof(ip_pkt_t)+ 
+	      sizeof(udp_pkt_t)+
+	      sizeof(wp_mgmt_t)+
+	      sizeof(cblock_t)+
+	      mbox_len;
+
 	/* fill in UDP reply */
-	data[36] = 0x02;
+  	p_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; 
+
 	/* fill in UDP length */
-	udp_length = mbox_len + 40;
+	udp_length = sizeof(udp_pkt_t)+ 
+		     sizeof(wp_mgmt_t)+
+		     sizeof(cblock_t)+
+		     mbox_len; 
+  
+ 
 	/* put it on an even boundary */
-	if (udp_length & 0x0001) {
+	if ( udp_length & 0x0001 ) {
 		udp_length += 1;
 		len += 1;
-	}
-	temp = (udp_length << 8) | (udp_length >> 8);
-	memcpy(&data[24], &temp, 2);
+		even_bound=1;
+	} 
+	
+	temp = (udp_length<<8)|(udp_length>>8);
+	p_udp_pkt->udp_pkt.udp_length = temp;		
+
+ 
 	/* swap UDP ports */
-	memcpy(&temp, &data[20], 2);
-	memcpy(&data[20], &data[22], 2);
-	memcpy(&data[22], &temp, 2);
+	temp = p_udp_pkt->udp_pkt.udp_src_port;
+	p_udp_pkt->udp_pkt.udp_src_port = 
+			p_udp_pkt->udp_pkt.udp_dst_port; 
+	p_udp_pkt->udp_pkt.udp_dst_port = temp;
+
+
 	/* add UDP pseudo header */
 	temp = 0x1100;
-	memcpy(&data[udp_length + 20], &temp, 2);
-	temp = (udp_length << 8) | (udp_length >> 8);
-	memcpy(&data[udp_length + 22], &temp, 2);
+	*((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound)) = temp;
+	temp = (udp_length<<8)|(udp_length>>8);
+	*((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound+2)) = temp;
+ 
 	/* calculate UDP checksum */
-	data[26] = data[27] = 0;
-	sum = 0;
-	for (i = 0; i < udp_length + 12; i += 2) {
-		memcpy(&temp, &data[12 + i], 2);
-		sum += (unsigned long) temp;
-	}
-	while (sum >> 16) {
-		sum = (sum & 0xffffUL) + (sum >> 16);
-	}
-	temp = (unsigned short) sum;
-	temp = ~temp;
-	if (temp == 0)
-		temp = 0xffff;
-	memcpy(&data[26], &temp, 2);
+	p_udp_pkt->udp_pkt.udp_checksum = 0;
+	p_udp_pkt->udp_pkt.udp_checksum = 
+		calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET);
+
 	/* fill in IP length */
-	ip_length = udp_length + 20;
-	temp = (ip_length << 8) | (ip_length >> 8);
-	memcpy(&data[2], &temp, 2);
+	ip_length = udp_length + sizeof(ip_pkt_t);
+	temp = (ip_length<<8)|(ip_length>>8);
+  	p_udp_pkt->ip_pkt.total_length = temp;
+ 
 	/* swap IP addresses */
-	memcpy(&temp, &data[12], 2);
-	memcpy(&data[12], &data[16], 2);
-	memcpy(&data[16], &temp, 2);
-	memcpy(&temp, &data[14], 2);
-	memcpy(&data[14], &data[18], 2);
-	memcpy(&data[18], &temp, 2);
+	ip_temp = p_udp_pkt->ip_pkt.ip_src_address;
+	p_udp_pkt->ip_pkt.ip_src_address = p_udp_pkt->ip_pkt.ip_dst_address;
+	p_udp_pkt->ip_pkt.ip_dst_address = ip_temp;
+
 	/* fill in IP checksum */
-	data[10] = data[11] = 0;
-	sum = 0;
-	for (i = 0; i < 20; i += 2) {
-		memcpy(&temp, &data[i], 2);
-		sum += (unsigned long) temp;
+	p_udp_pkt->ip_pkt.hdr_checksum = 0;
+	p_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t));
+
+	return len;
+
+} /* reply_udp */
+
+unsigned short calc_checksum (char *data, int len)
+{
+	unsigned short temp; 
+	unsigned long sum=0;
+	int i;
+
+	for( i = 0; i <len; i+=2 ) {
+		memcpy(&temp,&data[i],2);
+		sum += (unsigned long)temp;
 	}
-	while (sum >> 16) {
+
+	while (sum >> 16 ) {
 		sum = (sum & 0xffffUL) + (sum >> 16);
 	}
-	temp = (unsigned short) sum;
+
+	temp = (unsigned short)sum;
 	temp = ~temp;
-	if (temp == 0)
+
+	if( temp == 0 ) 
 		temp = 0xffff;
-	memcpy(&data[10], &temp, 2);
-	return len;
-}				/* reply_udp */
+
+	return temp;	
+}
 
 /*
    If incoming is 0 (outgoing)- if the net numbers is ours make it 0
    if incoming is 1 - if the net number is 0 make it ours 
- */
 
+*/
 static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
 {
 	unsigned long pnetwork_number;
-	pnetwork_number = (unsigned long) ((sendpacket[6] << 24) +
-			   (sendpacket[7] << 16) + (sendpacket[8] << 8) +
-					   sendpacket[9]);
+
+	pnetwork_number = (unsigned long)((sendpacket[6] << 24) + 
+			  (sendpacket[7] << 16) + (sendpacket[8] << 8) + 
+			  sendpacket[9]);
+
 	if (!incoming) {
-		/* If the destination network number is ours, make it 0 */
-		if (pnetwork_number == network_number) {
-			sendpacket[6] = sendpacket[7] = sendpacket[8] =
-			    sendpacket[9] = 0x00;
+		//If the destination network number is ours, make it 0
+		if( pnetwork_number == network_number) {
+			sendpacket[6] = sendpacket[7] = sendpacket[8] = 
+					 sendpacket[9] = 0x00;
 		}
 	} else {
-		/* If the incoming network is 0, make it ours */
-		if (pnetwork_number == 0) {
-			sendpacket[6] = (unsigned char) (network_number >> 24);
-			sendpacket[7] = (unsigned char) ((network_number &
-						      0x00FF0000) >> 16);
-			sendpacket[8] = (unsigned char) ((network_number &
-						       0x0000FF00) >> 8);
-			sendpacket[9] = (unsigned char) (network_number &
-							 0x000000FF);
+		//If the incoming network is 0, make it ours
+		if( pnetwork_number == 0) {
+			sendpacket[6] = (unsigned char)(network_number >> 24);
+			sendpacket[7] = (unsigned char)((network_number & 
+					 0x00FF0000) >> 16);
+			sendpacket[8] = (unsigned char)((network_number & 
+					 0x0000FF00) >> 8);
+			sendpacket[9] = (unsigned char)(network_number & 
+					 0x000000FF);
 		}
 	}
-	pnetwork_number = (unsigned long) ((sendpacket[18] << 24) +
-			 (sendpacket[19] << 16) + (sendpacket[20] << 8) +
-					   sendpacket[21]);
-	if (!incoming) {
-		/* If the source network is ours, make it 0 */
-		if (pnetwork_number == network_number) {
-			sendpacket[18] = sendpacket[19] = sendpacket[20] =
-			    sendpacket[21] = 0x00;
+
+
+	pnetwork_number = (unsigned long)((sendpacket[18] << 24) + 
+			  (sendpacket[19] << 16) + (sendpacket[20] << 8) + 
+			  sendpacket[21]);
+
+	if( !incoming ) {
+		//If the source network is ours, make it 0
+		if( pnetwork_number == network_number) {
+			sendpacket[18] = sendpacket[19] = sendpacket[20] = 
+					 sendpacket[21] = 0x00;
 		}
 	} else {
-		/* If the source network is 0, make it ours */
-		if (pnetwork_number == 0) {
-			sendpacket[18] = (unsigned char) (network_number >> 24);
-			sendpacket[19] = (unsigned char) ((network_number &
-						      0x00FF0000) >> 16);
-			sendpacket[20] = (unsigned char) ((network_number &
-						       0x0000FF00) >> 8);
-			sendpacket[21] = (unsigned char) (network_number &
-							  0x000000FF);
+		//If the source network is 0, make it ours
+		if( pnetwork_number == 0 ) {
+			sendpacket[18] = (unsigned char)(network_number >> 24);
+			sendpacket[19] = (unsigned char)((network_number & 
+					 0x00FF0000) >> 16);
+			sendpacket[20] = (unsigned char)((network_number & 
+					 0x0000FF00) >> 8);
+			sendpacket[21] = (unsigned char)(network_number & 
+					 0x000000FF);
 		}
 	}
-}				/* switch_net_numbers */
+} /* switch_net_numbers */
 
 /*============================================================================
- * Get Ethernet-style interface statistics.
- * Return a pointer to struct enet_statistics.
+ * Get ethernet-style interface statistics.
+ * Return a pointer to struct net_device_stats.
  */
-
-static struct enet_statistics *if_stats(struct device *dev)
+static struct net_device_stats *if_stats(struct device *dev)
 {
+
 	ppp_private_area_t *ppp_priv_area = dev->priv;
-	sdla_t *card;
+	sdla_t* card;
 	
-	/*
-	 *	Device is down:No statistics
-	 */
-	 
-	if(ppp_priv_area==NULL)
+	if( ppp_priv_area == NULL )
 		return NULL;
-	
+
 	card = ppp_priv_area->card;
 	return &card->wandev.stats;
 }
@@ -868,122 +1169,257 @@
  * Read firmware code version.
  *	Put code version as ASCII string in str. 
  */
-
-static int ppp_read_version(sdla_t * card, char *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;
+}
+/*===========================================================================
+ * Set Out-Bound Authentication.
+*/
+static int ppp_set_outbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area)
+{
+	ppp_mbox_t *mb = card->mbox;
+	int err;
+
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	memset(&mb->data, 0, (strlen(ppp_priv_area->userid) + 
+					strlen(ppp_priv_area->passwd) + 2 ) );
+	memcpy(mb->data, ppp_priv_area->userid, strlen(ppp_priv_area->userid));
+	memcpy((mb->data + strlen(ppp_priv_area->userid) + 1), 
+		ppp_priv_area->passwd, strlen(ppp_priv_area->passwd));	
+	
+	mb->cmd.length  = strlen(ppp_priv_area->userid) + 
+					strlen(ppp_priv_area->passwd) + 2 ;
+	
+	mb->cmd.command = PPP_SET_OUTBOUND_AUTH;
+
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+
+	if (err != CMD_OK)
+		ppp_error(card, err, mb);
+
+	return err;
+}
+
+/*===========================================================================
+ * Set In-Bound Authentication.
+*/
+static int ppp_set_inbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area)
+{
+	ppp_mbox_t *mb = card->mbox;
+	int err, i;
+	char* user_tokens[32];
+	char* pass_tokens[32];
+	int userids, passwds;
+	int add_ptr;
+
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	memset(&mb->data, 0, 1008);
+	memcpy(mb->data, ppp_priv_area->sysname, 
+						strlen(ppp_priv_area->sysname));
+	
+	/* Parse the userid string and the password string and build a string
+	   to copy it to the data area of the command structure.   The string
+	   will look like "SYS_NAME<NULL>USER1<NULL>PASS1<NULL>USER2<NULL>PASS2
+	   ....<NULL> " 
+	 */
+	userids = tokenize( ppp_priv_area->userid, user_tokens);
+	passwds = tokenize( ppp_priv_area->passwd, pass_tokens);
+	
+	if (userids != passwds){
+		printk(KERN_INFO "%s: Number of passwords does not equal the number of user ids\n", card->devname);
+		return 1;	
+	}
+
+	add_ptr = strlen(ppp_priv_area->sysname) + 1;
+	for (i=0; i<userids; i++){
+		memcpy((mb->data + add_ptr), user_tokens[i], 
+							strlen(user_tokens[i]));
+		memcpy((mb->data + add_ptr + strlen(user_tokens[i]) + 1), 
+					pass_tokens[i], strlen(pass_tokens[i]));
+		add_ptr = add_ptr + strlen(user_tokens[i]) + 1 + 
+						strlen(pass_tokens[i]) + 1;
 	}
+
+	mb->cmd.length  = add_ptr + 1;
+	mb->cmd.command = PPP_SET_INBOUND_AUTH;
+
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+
+	if (err != CMD_OK)
+		ppp_error(card, err, mb);
+
 	return err;
 }
 
+
+/*============================================================================
+ * Tokenize string.
+ *      Parse a string of the following syntax:
+ *              <arg1>,<arg2>,...
+ *      and fill array of tokens with pointers to string elements.
+ *
+ */
+static int tokenize (char *str, char **tokens)
+{
+        int cnt = 0;
+
+        tokens[0] = strtok(str, "/");
+        while (tokens[cnt] && (cnt < 32 - 1))
+        {
+                tokens[cnt] = strstrip(tokens[cnt], " \t");
+                tokens[++cnt] = strtok(NULL, "/");
+        }
+	return cnt;
+}
+
 /*============================================================================
- * Configure PPP firmware.
+ * Strip leading and trailing spaces off the string str.
  */
+static char* strstrip (char *str, char* s)
+{
+        char *eos = str + strlen(str);          /* -> end of string */
 
-static int ppp_configure(sdla_t * card, void *data)
+        while (*str && strchr(s, *str))
+                ++str                           /* strip leading spaces */
+        ;
+        while ((eos > str) && strchr(s, *(eos - 1)))
+                --eos                           /* strip trailing spaces */
+        ;
+        *eos = '\0';
+        return str;
+}
+/*============================================================================
+ * 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 data_len = 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.length  = data_len;
 	mb->cmd.command = PPP_SET_CONFIG;
 	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-	if (err != CMD_OK)
+
+	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)
+static int ppp_set_intr_mode(sdla_t *card, unsigned char mode)
 {
 	ppp_mbox_t *mb = card->mbox;
+        ppp_intr_info_t *ppp_intr_data = (ppp_intr_info_t *) &mb->data[0];
 	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;
-	}
+	ppp_intr_data->i_enable = mode;
+
+	ppp_intr_data->irq = card->hw.irq;
+	mb->cmd.length = 2;
+
+       /* If timer has been enabled, set the timer delay to 1sec */
+       if (mode & 0x80){
+       		ppp_intr_data->timer_len = 5;//100; //250;
+                mb->cmd.length = 4;
+        }
+	
 	mb->cmd.command = PPP_SET_INTR_FLAGS;
 	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-	if (err != CMD_OK)
+	
+	if (err != CMD_OK) 
 		ppp_error(card, err, mb);
+ 		
+
 	return err;
 }
 
 /*============================================================================
  * Enable communications.
  */
-
-static int ppp_comm_enable(sdla_t * card)
+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)
+	
+	if (err != CMD_OK) 
 		ppp_error(card, err, mb);
+	
 	return err;
 }
 
 /*============================================================================
  * Disable communications.
  */
-
-static int ppp_comm_disable(sdla_t * card)
+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)
+	if (err != CMD_OK) 
 		ppp_error(card, err, mb);
+
 	return err;
 }
 
 /*============================================================================
  * Get communications error statistics.
  */
-
-static int ppp_get_err_stats(sdla_t * card)
+static int ppp_get_err_stats(sdla_t *card)
 {
 	ppp_mbox_t *mb = card->mbox;
 	int err;
+
 	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
 	mb->cmd.command = PPP_READ_ERROR_STATS;
 	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+	
 	if (err == CMD_OK) {
-		ppp_err_stats_t *stats = (void *) mb->data;
-		card->wandev.stats.rx_over_errors = stats->rx_overrun;
-		card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
-		card->wandev.stats.rx_missed_errors = stats->rx_abort;
-		card->wandev.stats.rx_length_errors = stats->rx_lost;
+		
+		ppp_err_stats_t* stats = (void*)mb->data;
+		card->wandev.stats.rx_over_errors    = stats->rx_overrun;
+		card->wandev.stats.rx_crc_errors     = stats->rx_bad_crc;
+		card->wandev.stats.rx_missed_errors  = stats->rx_abort;
+		card->wandev.stats.rx_length_errors  = stats->rx_lost;
 		card->wandev.stats.tx_aborted_errors = stats->tx_abort;
-	} else
+	
+	} else 
 		ppp_error(card, err, mb);
+	
 	return err;
 }
 
@@ -992,27 +1428,30 @@
  *	Return:	0 - o.k.
  *		1 - no transmit buffers available
  */
-
-static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto)
+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;
+
 	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;
-	sdla_poke(&card->hw, addr, data, len);
-	txbuf->length = len;	/* frame length */
-	if (proto == ETH_P_IPX)
+                return 1;
+	
+	sdla_poke(&card->hw, txbuf->buf.ptr, data, len);
+
+	txbuf->length = len;		/* frame length */
+	
+	if (proto == htons(ETH_P_IPX))
 		txbuf->proto = 0x01;	/* protocol ID */
-	txbuf->flag = 1;	/* start transmission */
+	else
+		txbuf->proto = 0x00;	/* 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)
+
+	if ((void*)txbuf > card->u.p.txbuf_last)
 		card->u.p.txbuf = card->u.p.txbuf_base;
+
 	return 0;
 }
 
@@ -1025,19 +1464,22 @@
  *
  * Return zero if previous command has to be cancelled.
  */
-
-static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb)
+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);
+
+		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;
 }
 
@@ -1046,81 +1488,89 @@
 /*============================================================================
  * PPP interrupt service routine.
  */
-
-STATIC void wpp_isr(sdla_t * card)
+STATIC void wpp_isr(sdla_t *card)
 {
 	ppp_flags_t *flags = card->flags;
 	char *ptr = &flags->iflag;
-	unsigned long host_cpu_flags;
 	struct device *dev = card->wandev.dev;
+
+
 	int i;
+
 	card->in_isr = 1;
+	
 	++card->statistics.isr_entry;
-	if (test_and_set_bit(0, (void *) &card->wandev.critical)) {
-		++card->statistics.isr_already_critical;
-		printk(KERN_INFO "%s: Critical while in ISR!\n", card->devname);
-		card->in_isr = 0;
-		return;
+
+	//FIXME: Do we need this
+	card->force_enable_irq = 0;
+
+	if(card->hw.type != SDLA_S514){
+		if (test_and_set_bit(0, (void*)&card->wandev.critical)) {
+        	
+			++card->statistics.isr_already_critical;
+			printk (KERN_INFO "%s: Critical while in ISR!\n",
+					card->devname);
+			card->in_isr = 0;
+			return;
+	
+		}
 	}
-	/* For all interrupts set the critical flag to CRITICAL_IN_ISR. 
-	 * If the if_send routine is called with this flag set it will set 
-	 * the enable transmit flag to 1. (for a delayed interrupt) 
-	 */
-	card->wandev.critical = CRITICAL_IN_ISR;
+
 	card->buff_int_mode_unbusy = 0;
+
 	switch (flags->iflag) {
-	case 0x01:		/* receive interrupt */
-		++card->statistics.isr_rx;
-		rx_intr(card);
-		break;
-	case 0x02:		/* transmit interrupt */
-		++card->statistics.isr_tx;
-		flags->imask &= ~0x02;
-		dev->tbusy = 0;
-		card->buff_int_mode_unbusy = 1;
-		break;
-	case 0x08:
-		++Intr_test_counter;
-		++card->statistics.isr_intr_test;
-		break;
-	default:		/* unexpected interrupt */
-		++card->statistics.isr_spurious;
-		printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n",
-		       card->devname, flags->iflag);
-		printk(KERN_INFO "%s: ID Bytes = ", card->devname);
-		for (i = 0; i < 8; i++)
-			printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
-		printk(KERN_INFO "\n");
-	}
-	/* The critical flag is set to CRITICAL_INTR_HANDLED to let the
-	 * if_send call know that the interrupt is handled so that 
-	 * transmit interrupts are not enabled again.
-	 */
-	card->wandev.critical = CRITICAL_INTR_HANDLED;
-	/* If the enable transmit interrupt flag is set then enable transmit 
-	 * interrupt on the board. This only goes through if if_send is called 
-	 * and the critical flag is set due to an Interrupt. 
-	 */
-	if (card->wandev.enable_tx_int) {
-		flags->imask |= 0x02;
-		card->wandev.enable_tx_int = 0;
-		++card->statistics.isr_enable_tx_int;
+
+		case PPP_INTR_RXRDY:	/* receive interrupt  0x01  (bit 0)*/
+			++card->statistics.isr_rx;
+			rx_intr(card);
+			break;
+
+		case PPP_INTR_TXRDY:	/* transmit interrupt  0x02 (bit 1)*/
+			++card->statistics.isr_tx;
+			flags->imask &= ~PPP_INTR_TXRDY;
+			dev->tbusy = 0;		
+			card->buff_int_mode_unbusy = 1;
+			break;
+
+		case PPP_INTR_CMD:      /* interface command completed */
+			++Intr_test_counter;
+			++card->statistics.isr_intr_test;
+			break;
+
+		case PPP_INTR_MODEM:    /* modem status change (DCD, CTS) 0x04 (bit 2)*/
+		case PPP_INTR_DISC:  	/* Data link disconnected 0x10  (bit 4)*/	
+		case PPP_INTR_OPEN:   	/* Data link open 0x20  (bit 5)*/
+		case PPP_INTR_DROP_DTR:	/* DTR drop timeout expired  0x40 bit 6 */
+			event_intr(card);
+			break;
+	
+		case PPP_INTR_TIMER:
+			timer_intr(card);
+			break;	 
+
+		default:	/* unexpected interrupt */
+			++card->statistics.isr_spurious;
+			printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", 
+				card->devname, flags->iflag);
+			printk(KERN_INFO "%s: ID Bytes = ",card->devname);
+	 		for(i = 0; i < 8; i ++)
+				printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
+			printk(KERN_INFO "\n");	
 	}
-	save_flags(host_cpu_flags);
-	cli();
+	
 	card->in_isr = 0;
 	flags->iflag = 0;
 	card->wandev.critical = 0;
-	restore_flags(host_cpu_flags);
-	if (card->buff_int_mode_unbusy)
+
+	if(card->buff_int_mode_unbusy) {	
 		mark_bh(NET_BH);
+	}
 }
 
 /*============================================================================
  * Receive interrupt handler.
  */
-
-static void rx_intr(sdla_t * card)
+static void rx_intr(sdla_t *card)
 {
 	ppp_buf_ctl_t *rxbuf = card->rxmb;
 	struct device *dev = card->wandev.dev;
@@ -1128,160 +1578,338 @@
 	struct sk_buff *skb;
 	unsigned len;
 	void *buf;
-	int i, err;
-	ppp_flags_t *flags = card->flags;
-	char *ptr = &flags->iflag;
+	int i;
+        ppp_flags_t *flags = card->flags;
+        char *ptr = &flags->iflag;
 	int udp_type;
+	
+
 	if (rxbuf->flag != 0x01) {
-		printk(KERN_INFO
-		       "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n",
-		       card->devname, (unsigned) rxbuf, rxbuf->flag);
-		printk(KERN_INFO "%s: ID Bytes = ", card->devname);
-		for (i = 0; i < 8; i++)
+
+		printk(KERN_INFO 
+			"%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", 
+			card->devname, (unsigned)rxbuf, rxbuf->flag);
+	
+		printk(KERN_INFO "%s: ID Bytes = ",card->devname);
+	 	
+		for(i = 0; i < 8; i ++)
 			printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
-		printk(KERN_INFO "\n");
+		printk(KERN_INFO "\n");	
+		
 		++card->statistics.rx_intr_corrupt_rx_bfr;
 		return;
+
 	}
+
 	if (dev && dev->start) {
-		len = rxbuf->length;
+	
+		len  = rxbuf->length;
 		ppp_priv_area = dev->priv;
+
 		/* Allocate socket buffer */
 		skb = dev_alloc_skb(len);
+
 		if (skb != NULL) {
+		
 			/* 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 + 1) {
-					unsigned tmp = card->u.p.rx_top - addr
-					+ 1;
-					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);
+			unsigned addr = rxbuf->buf.ptr;
+
+			if ((addr + len) > card->u.p.rx_top + 1) {
+			
+				unsigned tmp = card->u.p.rx_top - addr + 1;
+				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 */
-			switch (rxbuf->proto) {
-			case 0x00:
-				skb->protocol = htons(ETH_P_IP);
-				break;
-			case 0x01:
-				skb->protocol = htons(ETH_P_IPX);
-				break;
+        		switch (rxbuf->proto) {
+	
+				case 0x00:
+					skb->protocol = htons(ETH_P_IP);
+					break;
+
+				case 0x01:
+					skb->protocol = htons(ETH_P_IPX);
+					break;
 			}
-			udp_type = udp_pkt_type(skb, card);
-			if (udp_type == UDP_DRVSTATS_TYPE) {
-				++ppp_priv_area->rx_intr_DRVSTATS_request;
-				process_udp_driver_call(
-					  UDP_PKT_FRM_NETWORK, card, skb,
-						     dev, ppp_priv_area);
-				dev_kfree_skb(skb);
-			} else if (udp_type == UDP_PTPIPE_TYPE) {
-				++ppp_priv_area->rx_intr_PTPIPE_request;
-				err = process_udp_mgmt_pkt(
-					       UDP_PKT_FRM_NETWORK, card,
-						skb, dev, ppp_priv_area);
-				dev_kfree_skb(skb);
-			} else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) {
-				if (card->wandev.enable_IPX) {
-					ppp_send(card, skb->data, skb->len, ETH_P_IPX);
-					dev_kfree_skb(skb);
+
+			udp_type = udp_pkt_type( skb, card );
+
+			if (udp_type == UDP_PTPIPE_TYPE){
+
+				/* Handle a UDP Request in Timer Interrupt */
+				if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, dev,
+                	              			ppp_priv_area)){
+	               			flags->imask |= PPP_INTR_TIMER;
+				}
+				++ppp_priv_area->rx_intr_stat.rx_intr_PIPE_request;
+
+
+			} else if (handle_IPXWAN(skb->data,card->devname, 
+						 ppp_priv_area->enable_IPX, 
+						 ppp_priv_area->network_number, 
+						 skb->protocol)) {
+			
+				/* Handle an IPXWAN packet */
+				if( ppp_priv_area->enable_IPX) {
+					ppp_send(card, skb->data, skb->len, htons(ETH_P_IPX));
+                        		dev_kfree_skb(skb);
+
+
 				} else {
 					++card->wandev.stats.rx_dropped;
 				}
 			} else {
-				/* Pass it up the protocol stack */
-				skb->dev = dev;
-				skb->mac.raw = skb->data;
+				/* Pass data up the protocol stack */
+	    			skb->dev = dev;
+				skb->mac.raw  = skb->data;
+
+			    	++card->wandev.stats.rx_packets;
+				card->wandev.stats.rx_bytes += skb->len;
+		    		++ppp_priv_area->rx_intr_stat.rx_intr_bfr_passed_to_stack;	
 				netif_rx(skb);
-				++card->wandev.stats.rx_packets;
- 				card->wandev.stats.rx_bytes += skb->len;
-				++ppp_priv_area->rx_intr_bfr_passed_to_stack;
 			}
+
 		} else {
+		
 			printk(KERN_INFO "%s: no socket buffers available!\n",
-			       card->devname);
+				card->devname);
 			++card->wandev.stats.rx_dropped;
-			++ppp_priv_area->rx_intr_no_socket;
+			++ppp_priv_area->rx_intr_stat.rx_intr_no_socket;
+			
+               		dev_kfree_skb(skb);
 		}
-	} else
+
+	} else {
 		++card->statistics.rx_intr_dev_not_started;
+	}
+
 	/* Release buffer element and calculate a pointer to the next one */
-	rxbuf->flag = (card->hw.fwid == SFID_PPP502) ? 0xFF : 0x00;
+	rxbuf->flag = 0x00;
 	card->rxmb = ++rxbuf;
-	if ((void *) rxbuf > card->u.p.rxbuf_last)
+	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)
+void event_intr (sdla_t *card)
 {
-	struct device *dev = card->wandev.dev;
-	if (!dev || !dev->start) {
-		++card->statistics.tx_intr_dev_not_started;
-		return;
+
+ 	struct device* dev = card->wandev.dev;
+        ppp_private_area_t* ppp_priv_area = dev->priv;
+	volatile ppp_flags_t *flags = card->flags;
+
+	switch (flags->iflag){
+
+		case PPP_INTR_MODEM:    /* modem status change (DCD, CTS) 0x04  (bit 2)*/
+			printk (KERN_INFO "%s: Modem status: DCD=%s CTS=%s\n",
+				card->devname, DCD(flags->mstatus), CTS(flags->mstatus));
+
+			break;
+
+		case PPP_INTR_DISC:  	/* Data link disconnected 0x10  (bit 4)*/	
+
+			NEX_PRINTK (KERN_INFO "Data link disconnected intr Cause %X\n",
+					       flags->disc_cause);
+
+			if (flags->disc_cause &
+				(PPP_LOCAL_TERMINATION | PPP_DCD_CTS_DROP |
+				PPP_REMOTE_TERMINATION)) {
+				if (card->u.p.ip_mode == WANOPT_PPP_PEER) { 
+					Read_connection_info = 1;
+					remove_route (card);
+				}
+				wanpipe_set_state(card, WAN_DISCONNECTED);
+				show_disc_cause(card, flags->disc_cause);
+				ppp_priv_area->timer_int_enabled |= 
+						TMR_INT_ENABLED_PPP_EVENT;
+				flags->imask |= PPP_INTR_TIMER;
+			}
+			break;
+
+		case PPP_INTR_OPEN:   	/* Data link open 0x20  (bit 5)*/
+
+			NEX_PRINTK (KERN_INFO "%s: PPP Link Open, LCP=%s IP=%s\n",
+					card->devname,LCP(flags->lcp_state),
+					IP(flags->ip_state));
+
+			if (flags->lcp_state == 0x09 && 
+                           (flags->ip_state == 0x09 || flags->ipx_state == 0x09)){
+                                /* Initialize the polling timer and set the state
+                                 * to WAN_CONNNECTED 
+                                 */
+                                card->state_tick = jiffies;
+				wanpipe_set_state(card, WAN_CONNECTED);
+				ppp_priv_area->timer_int_enabled |= 
+						TMR_INT_ENABLED_PPP_EVENT;
+				flags->imask |= PPP_INTR_TIMER;
+
+			}
+                   	break;
+
+		case PPP_INTR_DROP_DTR:		/* DTR drop timeout expired  0x40 bit 6 */
+
+			NEX_PRINTK(KERN_INFO "DTR Drop Timeout Interrrupt \n"); 
+			if (card->u.p.ip_mode == WANOPT_PPP_PEER) { 
+				Read_connection_info = 1;
+				remove_route (card);
+			}
+			wanpipe_set_state(card, WAN_DISCONNECTED);
+			show_disc_cause(card, flags->disc_cause);
+			ppp_priv_area->timer_int_enabled |= 
+						TMR_INT_ENABLED_PPP_EVENT;
+			flags->imask |= PPP_INTR_TIMER;
+			break;
+		
+		default:
+			printk(KERN_INFO "%s: Error, Invalid PPP Event\n",card->devname);
 	}
-	dev->tbusy = 0;
-	mark_bh(NET_BH);
 }
 
+
+
+/* TIMER INTERRUPT */
+
+void timer_intr (sdla_t *card)
+{
+
+        struct device* dev = card->wandev.dev;
+        ppp_private_area_t* ppp_priv_area = dev->priv;
+	ppp_flags_t *flags = card->flags;
+
+	/* Update statistics */
+	if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE){
+		ppp_get_err_stats(card);
+                if(!(--ppp_priv_area->update_comms_stats)){
+			ppp_priv_area->timer_int_enabled &= 
+				~TMR_INT_ENABLED_UPDATE;
+		}
+	}
+
+	/* PPIPEMON UDP request */
+
+	if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP){
+		process_udp_mgmt_pkt(card,dev, ppp_priv_area);
+		ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP;
+	}
+
+
+	/* PPP Event */
+	if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_PPP_EVENT){
+
+		if (card->wandev.state == WAN_DISCONNECTED){
+			poll_disconnected(card);
+		}
+
+		/* If the state is CONNECTING, it means that communicatins were
+	 	 * enabled. When the remote side enables its comminication we
+	 	 * should get an interrupt PPP_INTR_OPEN, thus turn off polling 
+		 */
+
+		else if (card->wandev.state == WAN_CONNECTING){
+			/* Turn off the timer interrupt */
+			ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT;
+		}
+
+		/* If state is connected and we are in PEER mode 
+	 	 * poll for an IP address which will be provided by remote end.
+	 	 */
+		else if ((card->wandev.state == WAN_CONNECTED && 
+		  	card->u.p.ip_mode == WANOPT_PPP_PEER) && 
+		  	Read_connection_info){
+
+			card->state_tick = jiffies;
+			if (!read_connection_info (card)){
+				card->poll = &process_route;
+			}
+
+		}else{
+			/* If we are using Static IP,no need to poll for
+			 * an IP address. 
+		 	 */
+			NEX_PRINTK(KERN_INFO "Turning off TIMER \n");
+			ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT;
+		}	
+
+	}/* End of PPP_EVENT */
+
+
+	/* Only disable the timer interrupt if there are no udp, statistic */
+	/* updates or events pending */
+        if(!ppp_priv_area->timer_int_enabled) {
+                flags->imask &= ~PPP_INTR_TIMER;
+        }
+}
+
+
 static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto)
 {
 	int i;
-	if (proto == htons(ETH_P_IPX)) {
-		/* It's an IPX packet */
-		if (!enable_IPX) {
-			/* Return 1 so we don't pass it up the stack. */
+
+	if( proto == htons(ETH_P_IPX) ) {
+		//It's an IPX packet
+		if(!enable_IPX) {
+			//Return 1 so we don't pass it up the stack.
 			return 1;
 		}
 	} else {
-		/* It's not IPX so pass it up the stack. */
+		//It's not IPX so pass it up the stack.
 		return 0;
 	}
-	if (sendpacket[16] == 0x90 &&
-	    sendpacket[17] == 0x04) {
-		/* It's IPXWAN */
-		if (sendpacket[2] == 0x02 &&
-		    sendpacket[34] == 0x00) {
-			/* It's a timer request packet */
-			printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname);
-			/* Go through the routing options and answer no to every */
-			/* option except Unnumbered RIP/SAP */
-			for (i = 41; sendpacket[i] == 0x00; i += 5) {
-				/* 0x02 is the option for Unnumbered RIP/SAP */
-				if (sendpacket[i + 4] != 0x02) {
+
+	if( sendpacket[16] == 0x90 &&
+	    sendpacket[17] == 0x04)
+	{
+		//It's IPXWAN
+
+		if( sendpacket[2] == 0x02 &&
+		    sendpacket[34] == 0x00)
+		{
+			//It's a timer request packet
+			printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname);
+
+			//Go through the routing options and answer no to every
+			//option except Unnumbered RIP/SAP
+			for(i = 41; sendpacket[i] == 0x00; i += 5)
+			{
+				//0x02 is the option for Unnumbered RIP/SAP
+				if( sendpacket[i + 4] != 0x02)
+				{
 					sendpacket[i + 1] = 0;
 				}
 			}
-			/* Skip over the extended Node ID option */
-			if (sendpacket[i] == 0x04) {
+
+			//Skip over the extended Node ID option
+			if( sendpacket[i] == 0x04 )
+			{
 				i += 8;
 			}
-			/* We also want to turn off all header compression opt. */
-			for (; sendpacket[i] == 0x80;) {
+
+			//We also want to turn off all header compression opt.
+			for(; sendpacket[i] == 0x80 ;)
+			{
 				sendpacket[i + 1] = 0;
 				i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
 			}
-			/* Set the packet type to timer response */
+
+			//Set the packet type to timer response
 			sendpacket[34] = 0x01;
-			printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname);
-		} else if (sendpacket[34] == 0x02) {
-			/* This is an information request packet */
-			printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname);
-			/* Set the packet type to information response */
+
+			printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname);
+		}
+		else if( sendpacket[34] == 0x02 )
+		{
+			//This is an information request packet
+			printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname);
+
+			//Set the packet type to information response
 			sendpacket[34] = 0x03;
-			/* Set the router name */
+
+			//Set the router name
 			sendpacket[51] = 'P';
 			sendpacket[52] = 'T';
 			sendpacket[53] = 'P';
@@ -1290,136 +1918,81 @@
 			sendpacket[56] = 'E';
 			sendpacket[57] = '-';
 			sendpacket[58] = CVHexToAscii(network_number >> 28);
-			sendpacket[59] = CVHexToAscii((network_number & 0x0F000000) >> 24);
-			sendpacket[60] = CVHexToAscii((network_number & 0x00F00000) >> 20);
-			sendpacket[61] = CVHexToAscii((network_number & 0x000F0000) >> 16);
-			sendpacket[62] = CVHexToAscii((network_number & 0x0000F000) >> 12);
-			sendpacket[63] = CVHexToAscii((network_number & 0x00000F00) >> 8);
-			sendpacket[64] = CVHexToAscii((network_number & 0x000000F0) >> 4);
+			sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24);
+			sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20);
+			sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16);
+			sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12);
+			sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8);
+			sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4);
 			sendpacket[65] = CVHexToAscii(network_number & 0x0000000F);
-			for (i = 66; i < 99; i += 1)
+			for(i = 66; i < 99; i+= 1)
+			{
 				sendpacket[i] = 0;
-			printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname);
-		} else {
-			printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname);
+			}
+
+			printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname);
+		}
+		else
+		{
+			printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname);
 			return 0;
 		}
-		/* Set the WNodeID to our network address */
-		sendpacket[35] = (unsigned char) (network_number >> 24);
-		sendpacket[36] = (unsigned char) ((network_number & 0x00FF0000) >> 16);
-		sendpacket[37] = (unsigned char) ((network_number & 0x0000FF00) >> 8);
-		sendpacket[38] = (unsigned char) (network_number & 0x000000FF);
+
+		//Set the WNodeID to our network address
+		sendpacket[35] = (unsigned char)(network_number >> 24);
+		sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16);
+		sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8);
+		sendpacket[38] = (unsigned char)(network_number & 0x000000FF);
+
 		return 1;
 	} else {
-		/* If we get here's its an IPX-data packet, so it'll get passed up the stack. */
-		/* switch the network numbers */
-		switch_net_numbers(sendpacket, network_number, 1);
+		//If we get here's its an IPX-data packet, so it'll get passed up the stack.
+
+		//switch the network numbers
+		switch_net_numbers(sendpacket, network_number, 1);	
 		return 0;
 	}
 }
 
 /****** 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!
+/* All polling functions are invoked by the TIMER interrupt in the wpp_isr 
+ * routine.  
  */
 
-static void wpp_poll(sdla_t * card)
+/*============================================================================
+ * Monitor active link phase.
+ */
+static void process_route (sdla_t *card)
 {
+	ppp_flags_t *flags = card->flags;
 	struct device *dev = card->wandev.dev;
-	ppp_flags_t *adptr_flags = card->flags;
-	unsigned long host_cpu_flags;
-	++card->statistics.poll_entry;
-	/* The wpp_poll is called continously by the WANPIPE thread to allow
-	 * for line state housekeeping. However if we are in a connected state
-	 * then we do not need to go through all the checks everytime. When in
-	 * connected state execute wpp_poll once every second.
-	 */
-	if (card->wandev.state == WAN_CONNECTED) {
-		if ((jiffies - card->state_tick) < HZ)
-			return;
-	}
-	disable_irq(card->hw.irq);
-	++card->irq_dis_poll_count;
-	if (test_and_set_bit(0, (void *) &card->wandev.critical)) {
-		++card->statistics.poll_already_critical;
-		printk(KERN_INFO "%s: critical inside wpp_poll\n",
-		       card->devname);
-		save_flags(host_cpu_flags);
-		cli();
-		if ((!card->irq_dis_if_send_count) &&
-		    (!(--card->irq_dis_poll_count)))
-			enable_irq(card->hw.irq);
-		restore_flags(host_cpu_flags);
-		return;
-	}
-	++card->statistics.poll_processed;
-	if (dev && dev->tbusy && !(adptr_flags->imask & 0x02)) {
-		++card->statistics.poll_tbusy_bad_status;
-		printk(KERN_INFO "%s: Wpp_Poll: tbusy = 0x01, imask = 0x%02X\n"
-		       ,card->devname, adptr_flags->imask);
-	}
-	switch (card->wandev.state) {
-	case WAN_CONNECTED:
-		card->state_tick = jiffies;
-		poll_active(card);
-		break;
-	case WAN_CONNECTING:
-		poll_connecting(card);
-		break;
-	case WAN_DISCONNECTED:
-		poll_disconnected(card);
-		break;
-	default:
-		printk(KERN_INFO "%s: Unknown Poll State 0x%02X\n",
-		       card->devname, card->wandev.state);
-		break;
-	}
-	card->wandev.critical = 0;
-	save_flags(host_cpu_flags);
-	cli();
-	if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
-		enable_irq(card->hw.irq);
-	restore_flags(host_cpu_flags);
-}
-
-/*============================================================================
- * Monitor active link phase.
- */
-
-static void poll_active(sdla_t * card)
-{
-	ppp_flags_t *flags = card->flags;
-	/* We check the lcp_state to see if we are in DISCONNECTED state.
-	 * We are considered to be connected for lcp states 0x06, 0x07, 0x08
-	 * and 0x09.
-	 */
-	if ((flags->lcp_state <= 0x05) || (flags->disc_cause & 0x03)) {
-		wanpipe_set_state(card, WAN_DISCONNECTED);
-		show_disc_cause(card, flags->disc_cause);
+	struct in_device *in_dev = dev->ip_ptr;
+	
+	if (in_dev != NULL ) {
+		if ((card->u.p.ip_mode == WANOPT_PPP_PEER) &&
+		    (Read_connection_info && flags->ip_state == 0x09)){ 
+		
+			printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname);
+			if (read_info( card )) {
+   				printk(KERN_INFO 
+					"%s: An error occurred in IP assignment.\n", 
+					card->devname);
+			} else {
+				struct in_ifaddr *ifa = in_dev->ifa_list;
+				printk(KERN_INFO "%s: Assigned Lcl. Addr: %s\n", 
+						card->devname, in_ntoa(ifa->ifa_local));
+				printk(KERN_INFO "%s: Assigned Rmt. Addr: %s\n", 
+						card->devname, in_ntoa(ifa->ifa_address));
+			}
+			Read_connection_info = 0;
+		}
+	}else{
+		printk(KERN_INFO "%s: Error: Null pointer in Poll Active\n",
+				card->devname);
 	}
-}
-
-/*============================================================================
- * Monitor link establishment phase.
- * o if connection timed out, disconnect the link.
- */
+	card->poll = NULL;
 
-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);
-	}
 }
 
 /*============================================================================
@@ -1427,794 +2000,796 @@
  *  o if interface is up and the hold-down timeout has expired, then retry
  *    connection.
  */
-
-static void poll_disconnected(sdla_t * card)
+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);
-		if (ppp_comm_enable(card) == CMD_OK)
-			init_ppp_tx_rx_buff(card);
+		
+		if(ppp_comm_enable(card) == CMD_OK){
+			init_ppp_tx_rx_buff( 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 = 0;	/* changed it from 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.conf_flags |= 0x0E;
-/*
-   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)
+static int config508(ppp_private_area_t *ppp_priv_area, sdla_t *card)
 {
 	ppp508_conf_t cfg;
+	struct device *dev = card->wandev.dev;
+	struct in_device *in_dev = dev->ip_ptr;
+	
 	/* 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.conf_flags |= 0x300;	/*send Configure-Request packets forever */
-	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 = 100;
-	cfg.dtr_drop_tmr = 1;
-	cfg.connect_tmout = 0;	/* changed it from 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;
- */
+		cfg.conf_flags |= INTERFACE_LEVEL_RS232;
+
+        cfg.conf_flags 	|= DONT_TERMINATE_LNK_MAX_CONFIG; /*send Configure-Request packets forever*/
+	cfg.txbuf_percent	= PERCENT_TX_BUFF;	/* % of Tx bufs */
+	cfg.mtu_local		= card->wandev.mtu;
+	cfg.mtu_remote		= card->wandev.mtu;                  /*    Default   */
+	cfg.restart_tmr		= TIME_BETWEEN_CONF_REQ;  	     /*    30 = 3sec */
+	cfg.auth_rsrt_tmr	= TIME_BETWEEN_PAP_CHAP_REQ;         /*    30 = 3sec */
+	cfg.auth_wait_tmr	= WAIT_PAP_CHAP_WITHOUT_REPLY;       /*   300 = 30s  */
+	cfg.mdm_fail_tmr	= WAIT_AFTER_DCD_CTS_LOW;            /*     5 = 0.5s */
+	cfg.dtr_drop_tmr	= TIME_DCD_CTS_LOW_AFTER_LNK_DOWN;   /*    10 = 1s   */
+	cfg.connect_tmout	= WAIT_DCD_HIGH_AFTER_ENABLE_COMM;   /*   900 = 90s  */
+	cfg.conf_retry		= MAX_CONF_REQ_WITHOUT_REPLY;        /*    10 = 1s   */
+	cfg.term_retry		= MAX_TERM_REQ_WITHOUT_REPLY;	     /*     2 times  */
+	cfg.fail_retry		= NUM_CONF_NAK_WITHOUT_REPLY;        /*     5 times  */
+	cfg.auth_retry		= NUM_AUTH_REQ_WITHOUT_REPLY;        /*     10 times */   
+
+
+	if( !card->u.p.authenticator ) {
+		printk(KERN_INFO "%s: Device is not configured as an authenticator\n", 
+				card->devname);
+		cfg.auth_options = NO_AUTHENTICATION;
+	}else{
+		printk(KERN_INFO "%s: Device is configured as an authenticator\n", 
+				card->devname);
+		cfg.auth_options = INBOUND_AUTH;
+	}
+	if( ppp_priv_area->pap == WANOPT_YES){
+		cfg.auth_options |=PAP_AUTH;
+		printk(KERN_INFO "%s: Pap enabled\n", card->devname);
+	}
+	if( ppp_priv_area->chap == WANOPT_YES){
+		cfg.auth_options |= CHAP_AUTH;
+		printk(KERN_INFO "%s: Chap enabled\n", card->devname);
+	}
+
+
+	if (ppp_priv_area->enable_IPX == WANOPT_YES){
+		cfg.ipx_options		= ENABLE_IPX | ROUTING_PROT_DEFAULT;
+	}else{
+		cfg.ipx_options 	= DISABLE_IPX;
+	}
+
+	switch (card->u.p.ip_mode) {
+	
+		case WANOPT_PPP_STATIC:
+
+			cfg.ip_options		= L_AND_R_IP_NO_ASSIG | 
+							    ENABLE_IP;
+			cfg.ip_local		= in_dev->ifa_list->ifa_local;
+			cfg.ip_remote		= in_dev->ifa_list->ifa_address;
+                        NEX_PRINTK(KERN_INFO "Local %s Remote %s Name %s\n",
+					in_ntoa(cfg.ip_local), 
+					in_ntoa(cfg.ip_remote), 
+					dev->name);
+			break;
+	
+		case WANOPT_PPP_PEER:
+			cfg.ip_options		= L_IP_REMOTE_ASSIG | 
+						  R_IP_REMOTE_ASSIG | 
+							  ENABLE_IP;
+			cfg.ip_local		= 0x00;
+			cfg.ip_remote		= 0x00;
+			break;
+	
+	}
 	return ppp_configure(card, &cfg);
 }
 
 /*============================================================================
  * Show disconnection cause.
  */
-
-static void show_disc_cause(sdla_t * card, unsigned 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)
+	if (cause & 0x0802) 
+
+		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)
+	
+	else if (cause & 0x0010) 
+
+		printk(KERN_INFO 
+			"%s: authentication protocol negotiation failed\n", 
+			card->devname);
+
+	else if (cause & 0x0020) 
+		
 		printk(KERN_INFO
-		       "%s: failed to negotiate peer's IPXCP options\n",
-		       card->devname);
-}
+		"%s: peer's request for authentication rejected\n",
+		card->devname);
 
-/*============================================================================
- * Convert line speed in bps to a number used by S502 code.
- */
+	else if (cause & 0x0040) 
+	
+		printk(KERN_INFO "%s: MRU option rejected by peer\n", 
+		card->devname);
 
-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;
-}
+	else if (cause & 0x0080) 
+	
+		printk(KERN_INFO "%s: peer's MRU was too small\n", 
+		card->devname);
 
-/*============================================================================
- * Process UDP call of type DRVSTATS.  
- */
+	else if (cause & 0x0100) 
 
-static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, ppp_private_area_t * ppp_priv_area)
-{
-	unsigned char *sendpacket;
-	unsigned char buf2[5];
-	unsigned char *data;
-	unsigned char *buf;
-	unsigned int len;
-	ppp_mbox_t *mbox = card->mbox;
-	struct sk_buff *new_skb;
-	int err;
-	sendpacket = skb->data;
-	memcpy(&buf2, &card->wandev.udp_port, 2);
-	if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) {
-		printk(KERN_INFO
-		       "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X"
-		       ,card->devname, data[45]);
-		++ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err;
-		return 1;
-	}
-	memcpy(data, sendpacket, skb->len);
-	switch (data[45]) {
-		/* PPIPE_DRIVER_STATISTICS */
-	case 0x26:
-		*(unsigned long *) &data[60] =
-		    ppp_priv_area->if_send_entry;
-		*(unsigned long *) &data[64] =
-		    ppp_priv_area->if_send_skb_null;
-		*(unsigned long *) &data[68] =
-		    ppp_priv_area->if_send_broadcast;
-		*(unsigned long *) &data[72] =
-		    ppp_priv_area->if_send_multicast;
-		*(unsigned long *) &data[76] =
-		    ppp_priv_area->if_send_critical_ISR;
-		*(unsigned long *) &data[80] =
-		    ppp_priv_area->if_send_critical_non_ISR;
-		*(unsigned long *) &data[84] =
-		    ppp_priv_area->if_send_busy;
-		*(unsigned long *) &data[88] =
-		    ppp_priv_area->if_send_busy_timeout;
-		*(unsigned long *) &data[92] =
-		    ppp_priv_area->if_send_DRVSTATS_request;
-		*(unsigned long *) &data[96] =
-		    ppp_priv_area->if_send_PTPIPE_request;
-		*(unsigned long *) &data[100] =
-		    ppp_priv_area->if_send_wan_disconnected;
-		*(unsigned long *) &data[104] =
-		    ppp_priv_area->if_send_adptr_bfrs_full;
-		*(unsigned long *) &data[108] =
-		    ppp_priv_area->if_send_protocol_error;
-		*(unsigned long *) &data[112] =
-		    ppp_priv_area->if_send_tx_int_enabled;
-		*(unsigned long *) &data[116] =
-		    ppp_priv_area->if_send_bfr_passed_to_adptr;
-		*(unsigned long *) &data[118] =
-		    card->irq_dis_if_send_count;
-		mbox->cmd.length = 62;
-		break;
-	case 0x27:
-		*(unsigned long *) &data[60] = card->statistics.isr_entry;
-		*(unsigned long *) &data[64] =
-		    card->statistics.isr_already_critical;
-		*(unsigned long *) &data[68] = card->statistics.isr_rx;
-		*(unsigned long *) &data[72] = card->statistics.isr_tx;
-		*(unsigned long *) &data[76] =
-		    card->statistics.isr_intr_test;
-		*(unsigned long *) &data[80] =
-		    card->statistics.isr_spurious;
-		*(unsigned long *) &data[84] =
-		    card->statistics.isr_enable_tx_int;
-		*(unsigned long *) &data[88] =
-		    card->statistics.rx_intr_corrupt_rx_bfr;
-		*(unsigned long *) &data[92] =
-		    ppp_priv_area->rx_intr_no_socket;
-		*(unsigned long *) &data[96] =
-		    ppp_priv_area->rx_intr_DRVSTATS_request;
-		*(unsigned long *) &data[100] =
-		    ppp_priv_area->rx_intr_PTPIPE_request;
-		*(unsigned long *) &data[104] =
-		    ppp_priv_area->rx_intr_bfr_passed_to_stack;
-		*(unsigned long *) &data[108] =
-		    card->statistics.rx_intr_dev_not_started;
-		*(unsigned long *) &data[112] =
-		    card->statistics.tx_intr_dev_not_started;
-		mbox->cmd.length = 56;
-		break;
-	case 0x28:
-		*(unsigned long *) &data[60] =
-		    ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err;
-		*(unsigned long *) &data[64] =
-		    ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err;
-		*(unsigned long *) &data[68] =
-		    ppp_priv_area->UDP_PTPIPE_mgmt_direction_err;
-		*(unsigned long *) &data[72] =
-		    ppp_priv_area->
-		    UDP_PTPIPE_mgmt_adptr_cmnd_timeout;
-		*(unsigned long *) &data[76] =
-		    ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK;
-		*(unsigned long *) &data[80] =
-		    ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr;
-		*(unsigned long *) &data[84] =
-		    ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack;
-		*(unsigned long *) &data[88] =
-		    ppp_priv_area->UDP_PTPIPE_mgmt_no_socket;
-		*(unsigned long *) &data[92] =
-		    ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err;
-		*(unsigned long *) &data[96] =
-		    ppp_priv_area->
-		    UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
-		*(unsigned long *) &data[100] =
-		    ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
-		*(unsigned long *) &data[104] =
-		    ppp_priv_area->
-		    UDP_DRVSTATS_mgmt_passed_to_adptr;
-		*(unsigned long *) &data[108] =
-		    ppp_priv_area->
-		    UDP_DRVSTATS_mgmt_passed_to_stack;
-		*(unsigned long *) &data[112] =
-		    ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket;
-		*(unsigned long *) &data[116] =
-		    card->statistics.poll_entry;
-		*(unsigned long *) &data[120] =
-		    card->statistics.poll_already_critical;
-		*(unsigned long *) &data[124] =
-		    card->statistics.poll_processed;
-		*(unsigned long *) &data[126] =
-		    card->irq_dis_poll_count;
-		mbox->cmd.length = 70;
-		break;
-	default:
-		/* it's a board command */
-		memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t));
-		if (mbox->cmd.length) {
-			memcpy(&mbox->data, &sendpacket[60],
-			       mbox->cmd.length);
-		}
-		/* run the command on the board */
-		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-		if (err != CMD_OK) {
-			ppp_error(card, err, mbox);
-			++ppp_priv_area->
-			    UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
-			break;
-		}
-		++ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
-		/* copy the result back to our buffer */
-		memcpy(data, sendpacket, skb->len);
-		memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t));
-		if (mbox->cmd.length) {
-			memcpy(&data[60], &mbox->data, mbox->cmd.length);
-		}
-	}
-	/* Fill UDP TTL */
-	data[8] = card->wandev.ttl;
-	len = reply_udp(data, mbox->cmd.length);
-	if (udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-		++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr;
-		ppp_send(card, data, len, skb->protocol);
-	} else {
-		/* Pass it up the stack
-		   Allocate socket buffer */
-		if ((new_skb = dev_alloc_skb(len)) != NULL) {
-			/* copy data into new_skb */
-			buf = skb_put(new_skb, len);
-			memcpy(buf, data, len);
-			++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack;
-			/* Decapsulate packet and pass it up the protocol 
-			   stack */
-			new_skb->protocol = htons(ETH_P_IP);
-			new_skb->dev = dev;
-			new_skb->mac.raw = new_skb->data;
-			netif_rx(new_skb);
-		} else {
-			++ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket;
-			printk(KERN_INFO "no socket buffers available!\n");
-		}
-	}
-	kfree(data);
-	return 0;
+		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);
 }
 
 /*=============================================================================
  * Process UDP call of type PTPIPEAB.
  */
-
-static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card,
-				struct sk_buff *skb, struct device *dev,
-				ppp_private_area_t * ppp_priv_area)
+static void process_udp_mgmt_pkt(sdla_t *card, struct device *dev, 
+				 ppp_private_area_t *ppp_priv_area ) 
 {
-	unsigned char *sendpacket;
 	unsigned char buf2[5];
-	unsigned char *data;
 	unsigned char *buf;
 	unsigned int frames, len;
 	struct sk_buff *new_skb;
-	unsigned short buffer_length, real_len;
+	unsigned short data_length, buffer_length, real_len;
 	unsigned long data_ptr;
 	int udp_mgmt_req_valid = 1;
 	ppp_mbox_t *mbox = card->mbox;
 	struct timeval tv;
 	int err;
-	sendpacket = skb->data;
-	memcpy(&buf2, &card->wandev.udp_port, 2);
-	if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) {
-		printk(KERN_INFO
-		       "%s: Error allocating memory for UDP management cmnd0x%02X"
-		       ,card->devname, data[45]);
-		++ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err;
-		return 1;
-	}
-	memcpy(data, sendpacket, skb->len);
-	switch (data[45]) {
+	ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t*)&ppp_priv_area->udp_pkt_data;
+
+	memcpy(&buf2, &card->wandev.udp_port, 2 );
+
+
+	switch(ppp_udp_pkt->cblock.command) {
+
 		/* FT1 MONITOR STATUS */
-	case 0x80:
-		if (card->hw.fwid != SFID_PPP508) {
-			++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err;
-			udp_mgmt_req_valid = 0;
-			break;
-		}
+		case FT1_MONITOR_STATUS_CTRL:
+		
 		/* PPIPE_ENABLE_TRACING */
-	case 0x20:
+		case PPIPE_ENABLE_TRACING:
+		   
 		/* PPIPE_DISABLE_TRACING */
-	case 0x21:
+		case PPIPE_DISABLE_TRACING:
+		   
 		/* PPIPE_GET_TRACE_INFO */
-	case 0x22:
+		case PPIPE_GET_TRACE_INFO:
+		   
 		/* SET FT1 MODE */
-	case 0x81:
-		if (udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-			++ppp_priv_area->UDP_PTPIPE_mgmt_direction_err;
-			udp_mgmt_req_valid = 0;
-		}
-		break;
-	default:
-		break;
-	}
-	if (!udp_mgmt_req_valid) {
+		case SET_FT1_MODE:
+			if(ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+			
+				++ppp_priv_area->pipe_mgmt_stat.
+						UDP_PIPE_mgmt_direction_err;
+				udp_mgmt_req_valid = 0;
+			}	 
+			break;
+		   
+		default:
+			break;
+	} 
+	
+  	if(!udp_mgmt_req_valid) {
+	    
 		/* set length to 0 */
-		data[46] = data[47] = 0;
-		/* set return code */
-		data[48] = 0xCD;
-	} else {
-		switch (data[45]) {
-			/* PPIPE_ENABLE_TRACING */
-		case 0x20:
-			if (!TracingEnabled) {
+    		ppp_udp_pkt->cblock.length = 0x00;
+
+    		/* set return code */
+    		ppp_udp_pkt->cblock.result = 0xCD; 
+
+   	} else {
+		/* Initialize the trace element */
+		trace_element_t trace_element;		    
+
+		switch (ppp_udp_pkt->cblock.command){
+
+		/* PPIPE_ENABLE_TRACING */
+    		case PPIPE_ENABLE_TRACING:
+			if (!card->TracingEnabled) {
+    			
 				/* OPERATE_DATALINE_MONITOR */
-				mbox->cmd.command = 0x33;
-				mbox->cmd.length = 1;
-				mbox->data[0] = 0x03;
-				err = sdla_exec(mbox) ?
-				    mbox->cmd.result : CMD_TIMEOUT;
-				if (err != CMD_OK) {
+    				mbox->cmd.command = PPP_DATALINE_MONITOR;
+    				mbox->cmd.length = 0x01;
+    				mbox->data[0] = ppp_udp_pkt->data[0];
+	    			err = sdla_exec(mbox) ? 
+					mbox->cmd.result : CMD_TIMEOUT;
+	   
+				if (err != CMD_OK) { 
+	        			
 					ppp_error(card, err, mbox);
-					TracingEnabled = 0;
+	        			card->TracingEnabled = 0;
+	        		
 					/* set the return code */
-					data[48] = mbox->cmd.result;
-					mbox->cmd.length = 0;
-					break;
-				}
-				if (card->hw.fwid == SFID_PPP502) {
-					sdla_peek(&card->hw, 0x9000, &buf2, 2);
-				} else {
-					sdla_peek(&card->hw, 0xC000, &buf2, 2);
-				}
-				curr_trace_addr = 0;
-				memcpy(&curr_trace_addr, &buf2, 2);
-				start_trace_addr = curr_trace_addr;
-				/* MAX_SEND_BUFFER_SIZE -sizeof(UDP_MGMT_PACKET)
-				   - 41 */
-				available_buffer_space = 1926;
-			}
-			data[48] = 0;
-			mbox->cmd.length = 0;
-			TracingEnabled = 1;
-			break;
-			/* PPIPE_DISABLE_TRACING */
-		case 0x21:
-			if (TracingEnabled) {
+
+		        		ppp_udp_pkt->cblock.result = mbox->cmd.result;
+	        			mbox->cmd.length = 0;
+	        			break;
+	    			} 
+
+				sdla_peek(&card->hw, 0xC000, &buf2, 2);
+		    
+				ppp_priv_area->curr_trace_addr = 0;
+		    		memcpy(&ppp_priv_area->curr_trace_addr, &buf2, 2);
+		    		ppp_priv_area->start_trace_addr = 
+						ppp_priv_area->curr_trace_addr;
+				ppp_priv_area->end_trace_addr = 
+					ppp_priv_area->start_trace_addr + END_OFFSET;
+		    	
+				/* MAX_SEND_BUFFER_SIZE - 28 (IP header) 
+				   - 32 (ppipemon CBLOCK) */
+		    		available_buffer_space = MAX_LGTH_UDP_MGNT_PKT - 
+							 sizeof(ip_pkt_t)-
+							 sizeof(udp_pkt_t)-
+							 sizeof(wp_mgmt_t)-
+							 sizeof(cblock_t);
+	       	  	}
+	       	  	ppp_udp_pkt->cblock.result = 0;
+	       	  	mbox->cmd.length = 0;
+	       	  	card->TracingEnabled = 1;
+	       	  	break;
+	   
+		/* PPIPE_DISABLE_TRACING */
+		case PPIPE_DISABLE_TRACING:
+	      		
+			if(card->TracingEnabled) {
+		   	
 				/* OPERATE_DATALINE_MONITOR */
-				mbox->cmd.command = 0x3;
-				mbox->cmd.length = 1;
-				mbox->data[0] = 0x00;
-				err = sdla_exec(mbox) ?
-				    mbox->cmd.result : CMD_TIMEOUT;
-			}
-			/*set return code */
-			data[48] = 0;
+		    		mbox->cmd.command = 0x33;
+		    		mbox->cmd.length = 1;
+		    		mbox->data[0] = 0x00;
+		    		err = sdla_exec(mbox) ? 
+					mbox->cmd.result : CMD_TIMEOUT;
+	       	  
+			} 
+		
+			/*set return code*/
+			ppp_udp_pkt->cblock.result = 0;
 			mbox->cmd.length = 0;
-			TracingEnabled = 0;
+			card->TracingEnabled = 0;
 			break;
-			/* PPIPE_GET_TRACE_INFO */
-		case 0x22:
-			if (TracingEnabled) {
-				buffer_length = 0;
-				/* frames < NUM_TRACE_FRAMES */
-				for (frames = 0; frames < 62; frames += 1) {
-					sdla_peek(&card->hw, curr_trace_addr,
-						  &buf2, 1);
-					/* no data on board so exit */
-					if (buf2[0] == 0x00)
-						break;
-					/*1+sizeof(FRAME_DATA) = 9 */
-					if ((available_buffer_space -
-					     buffer_length) < 9) {
-						/*indicate we have more frames 
-						   on board and exit */
-						data[60] |= 0x02;
+	   
+		/* PPIPE_GET_TRACE_INFO */
+		case PPIPE_GET_TRACE_INFO:
+
+			if(!card->TracingEnabled) {
+				/* set return code */
+	    			ppp_udp_pkt->cblock.result = 1;
+	    			mbox->cmd.length = 0;
+			}		    
+
+			buffer_length = 0;
+			
+			/* frames < 62, where 62 is the number of trace
+			   information elements.  There is in total 496
+			   bytes of space and each trace information
+			   element is 8 bytes. 
+			 */
+			for ( frames=0; frames<62; frames++) {
+	
+				trace_pkt_t *trace_pkt = (trace_pkt_t *)
+					&ppp_udp_pkt->data[buffer_length];
+	
+				/* Read the whole trace packet */
+				sdla_peek(&card->hw, ppp_priv_area->curr_trace_addr, 
+					  &trace_element, sizeof(trace_element_t));
+	
+				/* no data on board so exit */
+				if( trace_element.opp_flag == 0x00 ) 
+					break;
+	      
+				data_ptr = trace_element.trace_data_ptr;
+
+				/* See if there is actual data on the trace buffer */
+				if (data_ptr){
+					data_length = trace_element.trace_length;
+				}else{
+					data_length = 0;
+					ppp_udp_pkt->data[0] |= 0x02;
+				}
+
+				//FIXME: Do we need this check
+				if ((available_buffer_space - buffer_length) 
+				     < (sizeof(trace_element_t)+1)){
+					
+					/*indicate we have more frames 
+					 * on board and exit 
+					 */
+					ppp_udp_pkt->data[0] |= 0x02;
+					break;
+				}
+				
+				trace_pkt->status = trace_element.trace_type;
+				trace_pkt->time_stamp = trace_element.trace_time_stamp;
+				trace_pkt->real_length = trace_element.trace_length;
+
+				real_len = trace_element.trace_length;	
+				
+				if(data_ptr == 0){
+					trace_pkt->data_avail = 0x00;
+				}else{
+					/* we can take it next time */
+					if ((available_buffer_space - buffer_length)<
+						(real_len + sizeof(trace_pkt_t))){
+					
+						ppp_udp_pkt->data[0] |= 0x02;
 						break;
-					}
-					/* get frame status */
-					sdla_peek(&card->hw, curr_trace_addr +
-						  0x01, &data[60 + buffer_length], 1);
-					/* get time stamp */
-					sdla_peek(&card->hw, curr_trace_addr +
-						  0x06, &data[64 + buffer_length], 2);
-					/* get frame length */
-					sdla_peek(&card->hw, curr_trace_addr +
-						  0x02, &data[62 + buffer_length], 2);
-					/* get pointer to real data */
-					sdla_peek(&card->hw, curr_trace_addr +
-						  0x04, &buf2, 2);
-					data_ptr = 0;
-					memcpy(&data_ptr, &buf2, 2);
-					/* see if we can fit the frame into the 
-					   user buffer */
-					memcpy(&real_len,
-					   &data[62 + buffer_length], 2);
-					if ((data_ptr == 0) ||
-					    ((real_len + 8) >
-					     available_buffer_space)) {
-						data[61 + buffer_length] = 0x00;
-					} else {
-						/* we can take it next time */
-						if ((available_buffer_space -
-						     buffer_length) <
-						    (real_len + 8)) {
-							data[60] |= 0x02;
-							break;
-						}
-						/* ok, get the frame */
-						data[61 + buffer_length] = 0x01;
-						/* get the data */
-						sdla_peek(&card->hw, data_ptr,
-						&data[66 + buffer_length],
-							  real_len);
-						/* zero the opp flag to 
-						   show we got the frame */
-						buf2[0] = 0x00;
-						sdla_poke(&card->hw,
-							  curr_trace_addr, &buf2, 1);
-						/* now move onto the next 
-						   frame */
-						curr_trace_addr += 8;
-						/* check if we passed the last 
-						   address */
-						if (curr_trace_addr >=
-						    start_trace_addr + 0x1F0) {
-							curr_trace_addr =
-							    start_trace_addr;
-						}
-						/* update buffer length and make                                                   sure its even */
-						if (data[61 + buffer_length]
-						    == 0x01) {
-							buffer_length +=
-							    real_len - 1;
-						}
-						/* for the header */
-						buffer_length += 8;
-						if (buffer_length & 0x0001)
-							buffer_length += 1;
-					}
+					} 
+					trace_pkt->data_avail = 0x01;
+				
+					/* get the data */
+					sdla_peek(&card->hw, data_ptr, 
+						  &trace_pkt->data,
+						  real_len);
+				}	
+				/* zero the opp flag to 
+				   show we got the frame */
+				buf2[0] = 0x00;
+				sdla_poke(&card->hw, ppp_priv_area->curr_trace_addr,
+					  &buf2, 1);
+
+				/* now move onto the next 
+				   frame */
+				ppp_priv_area->curr_trace_addr += 8;
+
+				/* check if we passed the last address */
+				if ( ppp_priv_area->curr_trace_addr >= 
+					ppp_priv_area->end_trace_addr){
+
+					ppp_priv_area->curr_trace_addr = 
+						ppp_priv_area->start_trace_addr;
 				}
-				/* ok now set the total number of frames passed
-				   in the high 5 bits */
-				data[60] = (frames << 2) | data[60];
-				/* set the data length */
-				mbox->cmd.length = buffer_length;
-				memcpy(&data[46], &buffer_length, 2);
-				/* set return code */
-				data[48] = 0;
-			} else {
-				/* set return code */
-				data[48] = 1;
-				mbox->cmd.length = 0;
+ 
+				/* update buffer length and make sure its even */ 
+
+				if ( trace_pkt->data_avail == 0x01 ) {
+					buffer_length += real_len - 1;
+				}
+ 
+				/* for the header */
+				buffer_length += 8;
+
+				if( buffer_length & 0x0001 )
+					buffer_length += 1;
 			}
-			break;
-			/* PPIPE_GET_IBA_DATA */
-		case 0x23:
+
+			/* ok now set the total number of frames passed
+			   in the high 5 bits */
+			ppp_udp_pkt->data[0] |= (frames << 2);
+	 
+			/* set the data length */
+			mbox->cmd.length = buffer_length;
+			ppp_udp_pkt->cblock.length = buffer_length;
+	 
+			/* set return code */
+			ppp_udp_pkt->cblock.result = 0;
+	      	  	break;
+
+   		/* PPIPE_GET_IBA_DATA */
+		case PPIPE_GET_IBA_DATA:
+	        
 			mbox->cmd.length = 0x09;
-			if (card->hw.fwid == SFID_PPP502) {
-				sdla_peek(&card->hw, 0xA003, &data[60],
-					  mbox->cmd.length);
-			} else {
-				sdla_peek(&card->hw, 0xF003, &data[60],
-					  mbox->cmd.length);
-			}
+		
+			sdla_peek(&card->hw, 0xF003, &ppp_udp_pkt->data, 
+					mbox->cmd.length);
+	        
 			/* set the length of the data */
-			data[46] = 0x09;
+			ppp_udp_pkt->cblock.length = 0x09;
+
 			/* set return code */
-			data[48] = 0x00;
+			ppp_udp_pkt->cblock.result = 0x00;
+
 			break;
-			/* PPIPE_KILL_BOARD */
-		case 0x24:
+
+		/* PPIPE_KILL_BOARD */
+		case PPIPE_KILL_BOARD:
 			break;
-			/* PPIPE_FT1_READ_STATUS */
-		case 0x25:
-			sdla_peek(&card->hw, 0xF020, &data[60], 2);
-			data[46] = 2;
-			data[47] = 0;
-			data[48] = 0;
+
+		/* PPIPE_FT1_READ_STATUS */
+		case PPIPE_FT1_READ_STATUS:
+			sdla_peek(&card->hw, 0xF020, &ppp_udp_pkt->data, 2);
+			ppp_udp_pkt->cblock.length = 2;
+			ppp_udp_pkt->cblock.result = 0;
 			mbox->cmd.length = 2;
 			break;
-		case 0x29:
-			init_ppp_priv_struct(ppp_priv_area);
-			init_global_statistics(card);
+		
+		case PPIPE_FLUSH_DRIVER_STATS:   
+			init_ppp_priv_struct( ppp_priv_area );
+			init_global_statistics( card );
 			mbox->cmd.length = 0;
 			break;
-		case 0x30:
-			do_gettimeofday(&tv);
-			ppp_priv_area->router_up_time = tv.tv_sec -
-			    ppp_priv_area->router_start_time;
-			*(unsigned long *) &data[60] =
-			    ppp_priv_area->router_up_time;
+
+		case PPIPE_ROUTER_UP_TIME:
+
+			do_gettimeofday( &tv );
+			ppp_priv_area->router_up_time = tv.tv_sec - 
+					ppp_priv_area->router_start_time;
+			*(unsigned long *)&ppp_udp_pkt->data = ppp_priv_area->router_up_time;
 			mbox->cmd.length = 4;
 			break;
-			/* FT1 MONITOR STATUS */
-		case 0x80:
+
+		/* FT1 MONITOR STATUS */
+   		case FT1_MONITOR_STATUS_CTRL:
+	
 			/* Enable FT1 MONITOR STATUS */
-			if (data[60] == 1) {
-				if (rCount++ != 0) {
-					data[48] = 0;
-					mbox->cmd.length = 1;
-					break;
-				}
-			}
-			/* Disable FT1 MONITOR STATUS */
-			if (data[60] == 0) {
-				if (--rCount != 0) {
-					data[48] = 0;
-					mbox->cmd.length = 1;
-					break;
-				}
-			}
+	        	if( ppp_udp_pkt->data[0] == 1) {
+			
+				if( rCount++ != 0 ) {
+		        		ppp_udp_pkt->cblock.result = 0;
+	          			mbox->cmd.length = 1;
+		  			break;
+		    		}	
+	      		}
+
+	      		/* Disable FT1 MONITOR STATUS */
+	      		if( ppp_udp_pkt->data[0] == 0) {
+
+	      	   		if( --rCount != 0) {
+		  			ppp_udp_pkt->cblock.result = 0;
+		  			mbox->cmd.length = 1;
+		  			break;
+	   	    		} 
+	      		} 	
+
+		/* PPIPE_DRIVER_STATISTICS */   
+		case PPIPE_DRIVER_STAT_IFSEND:
+			printk(KERN_INFO "Getting IF_SEND Drivers Statistics\n");
+			memcpy(&ppp_udp_pkt->data, &ppp_priv_area->if_send_stat, 
+				sizeof(if_send_stat_t));
+
+
+			ppp_udp_pkt->cblock.result = 0;
+			ppp_udp_pkt->cblock.length = sizeof(if_send_stat_t);
+			mbox->cmd.length = sizeof(if_send_stat_t);	
+			break;
+
+		case PPIPE_DRIVER_STAT_INTR:
+			memcpy(&ppp_udp_pkt->data, &card->statistics, 
+				sizeof(global_stats_t));
+
+			memcpy(&ppp_udp_pkt->data+sizeof(global_stats_t),
+				&ppp_priv_area->rx_intr_stat,
+				sizeof(rx_intr_stat_t));
+
+			ppp_udp_pkt->cblock.result = 0;
+			ppp_udp_pkt->cblock.length = sizeof(global_stats_t)+
+						     sizeof(rx_intr_stat_t);
+			mbox->cmd.length = ppp_udp_pkt->cblock.length;
+			break;
+
+		case PPIPE_DRIVER_STAT_GEN:
+			memcpy( &ppp_udp_pkt->data,
+				&ppp_priv_area->pipe_mgmt_stat,
+				sizeof(pipe_mgmt_stat_t));
+
+			memcpy(&ppp_udp_pkt->data+sizeof(pipe_mgmt_stat_t), 
+			       &card->statistics, sizeof(global_stats_t));
+
+			ppp_udp_pkt->cblock.result = 0;
+			ppp_udp_pkt->cblock.length = sizeof(global_stats_t)+
+						     sizeof(rx_intr_stat_t);
+			mbox->cmd.length = ppp_udp_pkt->cblock.length;
+			break;
+
+	
 		default:
+	        
 			/* it's a board command */
-			memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t));
-			if (mbox->cmd.length) {
-				memcpy(&mbox->data, &sendpacket[60],
+			mbox->cmd.command = ppp_udp_pkt->cblock.command;
+			mbox->cmd.length = ppp_udp_pkt->cblock.length;
+ 
+			if(mbox->cmd.length) {
+				memcpy(&mbox->data,(unsigned char *)ppp_udp_pkt->data,
 				       mbox->cmd.length);
-			}
+	      		} 
+	          
 			/* run the command on the board */
 			err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+		
 			if (err != CMD_OK) {
-				ppp_error(card, err, mbox);
-				++ppp_priv_area->
-				    UDP_PTPIPE_mgmt_adptr_cmnd_timeout;
+		
+		    		ppp_error(card, err, mbox);
+		    		++ppp_priv_area->pipe_mgmt_stat.
+					 UDP_PIPE_mgmt_adptr_cmnd_timeout;
 				break;
 			}
-			++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK;
+	          
+		  	++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK;
+		
 			/* copy the result back to our buffer */
-			memcpy(data, sendpacket, skb->len);
-			memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t));
-			if (mbox->cmd.length) {
-				memcpy(&data[60], &mbox->data, mbox->cmd.length);
-			}
-		}		/* end of switch */
-	}			/* end of else */
-	/* Fill UDP TTL */
-	data[8] = card->wandev.ttl;
-	len = reply_udp(data, mbox->cmd.length);
-	if (udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-		++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr;
-		ppp_send(card, data, len, skb->protocol);
-	} else {
+			memcpy(&ppp_udp_pkt->cblock,mbox, sizeof(cblock_t));
+	          
+			if(mbox->cmd.length) {
+				memcpy(&ppp_udp_pkt->data,&mbox->data,mbox->cmd.length);
+			} 
+
+		} /* end of switch */
+     	} /* end of else */
+
+     	/* Fill UDP TTL */
+     	ppp_udp_pkt->ip_pkt.ttl = card->wandev.ttl; 
+     	len = reply_udp(ppp_priv_area->udp_pkt_data, mbox->cmd.length);
+
+     	if (ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) {
+	
+		++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_adptr;
+		ppp_send(card,ppp_priv_area->udp_pkt_data,len,ppp_priv_area->protocol);
+
+	} else {	
+	
 		/* Pass it up the stack
-		   Allocate socket buffer */
+    		   Allocate socket buffer */
 		if ((new_skb = dev_alloc_skb(len)) != NULL) {
+	    	
 			/* copy data into new_skb */
-			buf = skb_put(new_skb, len);
-			memcpy(buf, data, len);
-			++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack;
-			/* Decapsulate packet and pass it up the protocol 
+
+  	    		buf = skb_put(new_skb, len);
+  	    		memcpy(buf,ppp_priv_area->udp_pkt_data, len);
+
+	    		++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack;
+			
+            		/* Decapsulate packet and pass it up the protocol 
 			   stack */
-			new_skb->protocol = htons(ETH_P_IP);
-			new_skb->dev = dev;
-			new_skb->mac.raw = new_skb->data;
+	    		new_skb->protocol = htons(ETH_P_IP);
+            		new_skb->dev = dev;
+	    		new_skb->mac.raw  = new_skb->data;
 			netif_rx(new_skb);
+		
 		} else {
-			++ppp_priv_area->UDP_PTPIPE_mgmt_no_socket;
+	    	
+			++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket;
 			printk(KERN_INFO "no socket buffers available!\n");
-		}
-	}
-	kfree(data);
-	return 0;
+  		}
+    	}	
+
+	ppp_priv_area->udp_pkt_lgth = 0;
+	
+	return; 
 }
 
 /*=============================================================================
  * Initial the ppp_private_area structure.
  */
-
-static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area)
+static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area )
 {
-	ppp_priv_area->if_send_entry = 0;
-	ppp_priv_area->if_send_skb_null = 0;
-	ppp_priv_area->if_send_broadcast = 0;
-	ppp_priv_area->if_send_multicast = 0;
-	ppp_priv_area->if_send_critical_ISR = 0;
-	ppp_priv_area->if_send_critical_non_ISR = 0;
-	ppp_priv_area->if_send_busy = 0;
-	ppp_priv_area->if_send_busy_timeout = 0;
-	ppp_priv_area->if_send_DRVSTATS_request = 0;
-	ppp_priv_area->if_send_PTPIPE_request = 0;
-	ppp_priv_area->if_send_wan_disconnected = 0;
-	ppp_priv_area->if_send_adptr_bfrs_full = 0;
-	ppp_priv_area->if_send_bfr_passed_to_adptr = 0;
-	ppp_priv_area->rx_intr_no_socket = 0;
-	ppp_priv_area->rx_intr_DRVSTATS_request = 0;
-	ppp_priv_area->rx_intr_PTPIPE_request = 0;
-	ppp_priv_area->rx_intr_bfr_not_passed_to_stack = 0;
-	ppp_priv_area->rx_intr_bfr_passed_to_stack = 0;
-	ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err = 0;
-	ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err = 0;
-	ppp_priv_area->UDP_PTPIPE_mgmt_direction_err = 0;
-	ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_timeout = 0;
-	ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK = 0;
-	ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr = 0;
-	ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack = 0;
-	ppp_priv_area->UDP_PTPIPE_mgmt_no_socket = 0;
-	ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err = 0;
-	ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_type_err = 0;
-	ppp_priv_area->UDP_DRVSTATS_mgmt_direction_err = 0;
-	ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0;
-	ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0;
-	ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr = 0;
-	ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack = 0;
-	ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket = 0;
+
+	memset(&ppp_priv_area->if_send_stat, 0, sizeof(if_send_stat_t));
+	memset(&ppp_priv_area->rx_intr_stat, 0, sizeof(rx_intr_stat_t));
+	memset(&ppp_priv_area->pipe_mgmt_stat, 0, sizeof(pipe_mgmt_stat_t));	
 }
 
 /*============================================================================
  * Initialize Global Statistics
  */
-
-static void init_global_statistics(sdla_t * card)
+static void init_global_statistics( sdla_t *card )
 {
-	card->statistics.isr_entry = 0;
-	card->statistics.isr_already_critical = 0;
-	card->statistics.isr_tx = 0;
-	card->statistics.isr_rx = 0;
-	card->statistics.isr_intr_test = 0;
-	card->statistics.isr_spurious = 0;
-	card->statistics.isr_enable_tx_int = 0;
-	card->statistics.rx_intr_corrupt_rx_bfr = 0;
-	card->statistics.rx_intr_dev_not_started = 0;
-	card->statistics.tx_intr_dev_not_started = 0;
-	card->statistics.poll_entry = 0;
-	card->statistics.poll_already_critical = 0;
-	card->statistics.poll_processed = 0;
-	card->statistics.poll_tbusy_bad_status = 0;
+	memset(&card->statistics, 0, sizeof(global_stats_t));
 }
 
 /*============================================================================
  * Initialize Receive and Transmit Buffers.
  */
-
-static void init_ppp_tx_rx_buff(sdla_t * card)
+static void init_ppp_tx_rx_buff( sdla_t *card )
 {
-	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);
+	ppp508_buf_info_t* info;
+
+	if (card->hw.type == SDLA_S514) {
+		
+		info = (void*)(card->hw.dpmbase + PPP514_BUF_OFFS);
+
+       		card->u.p.txbuf_base = (void*)(card->hw.dpmbase +
+			info->txb_ptr);
+
+                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);
+
+                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;
+		
+		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;
+
+}
+
+/*=============================================================================
+ * Read Connection Information (ie for Remote IP address assginment).
+ * Called when ppp interface connected.
+ */
+static int read_info( sdla_t *card )
+{
+	struct device *dev = card->wandev.dev;
+	ppp_private_area_t *ppp_priv_area = dev->priv;
+	int err;
+	struct ifreq if_info;
+	struct sockaddr_in *if_data1, *if_data2;
+	mm_segment_t fs;
+
+	/* Set Local and remote addresses */
+	memset(&if_info, 0, sizeof(if_info));
+	strcpy(if_info.ifr_name, dev->name);
+
+	fs = get_fs();
+	set_fs(get_ds());     /* get user space block */ 
+
+	
+	/* Change the local and remote ip address of the interface.
+	 * This will also add in the destination route.
+	 */	
+	if_data1 = (struct sockaddr_in *)&if_info.ifr_addr;
+	if_data1->sin_addr.s_addr = ppp_priv_area->ip_local;
+	if_data1->sin_family = AF_INET;
+	err = devinet_ioctl( SIOCSIFADDR, &if_info );
+	if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr;
+	if_data2->sin_addr.s_addr = ppp_priv_area->ip_remote;
+	if_data2->sin_family = AF_INET;
+	err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
+
+	set_fs(fs);           /* restore old block */
+
+
+	if (err) {
+		printk (KERN_INFO "%s: Adding of route failed:\n",
+			card->devname);
+		printk (KERN_INFO "%s:	Local : %s\n",
+			card->devname,in_ntoa(ppp_priv_area->ip_local));
+		printk (KERN_INFO "%s:	Remote: %s\n",
+			card->devname,in_ntoa(ppp_priv_area->ip_remote));
+	}
+	return err;
+}
+
+/*=============================================================================
+ * Remove Dynamic Route.
+ * Called when ppp interface disconnected.
+ */
+
+static int remove_route( sdla_t *card )
+{
+
+	struct device *dev = card->wandev.dev;
+	long ip_addr;
+	int err;
+
+        mm_segment_t fs;
+	struct ifreq if_info;
+	struct sockaddr_in *if_data1;
+        struct in_device *in_dev = dev->ip_ptr;
+        struct in_ifaddr *ifa = in_dev->ifa_list;	
+
+
+	ip_addr = ifa->ifa_local;
+
+	/* Set Local and remote addresses */
+	memset(&if_info, 0, sizeof(if_info));
+	strcpy(if_info.ifr_name, dev->name);
+
+
+	fs = get_fs();
+       	set_fs(get_ds());     /* get user space block */ 
+
+
+	/* Change the local ip address of the interface to 0.
+	 * This will also delete the destination route.
+	 */	
+	if_data1 = (struct sockaddr_in *)&if_info.ifr_addr;
+	if_data1->sin_addr.s_addr = 0;
+	if_data1->sin_family = AF_INET;
+	err = devinet_ioctl( SIOCSIFADDR, &if_info );
+
+        set_fs(fs);           /* restore old block */
+
+	
+	if (err) {
+		printk (KERN_INFO "%s: Deleting dynamic route failed %d!\n",
+			 card->devname, err);
+		return err;
+	}else
+		printk (KERN_INFO "%s: PPP Deleting dynamic route %s successfuly\n",
+			card->devname, in_ntoa(ip_addr));
+
+	
+	return 0;
 }
 
 /*=============================================================================
  * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR
  * _TEST_COUNTER times.
  */
-
-static int intr_test(sdla_t * card)
+static int intr_test( sdla_t *card )
 {
 	ppp_mbox_t *mb = card->mbox;
-	int err, i;
-	/* The critical flag is unset because during initialization (if_open) 
+	int err,i;
+
+	/* The critical flag is unset because during intialization (if_open) 
 	 * we want the interrupts to be enabled so that when the wpp_isr is
 	 * called it does not exit due to critical flag set.
-	 */
+	 */ 
+	 
 	card->wandev.critical = 0;
-	err = ppp_set_intr_mode(card, 0x08);
-	if (err == CMD_OK) {
-		for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) {
+
+	err = ppp_set_intr_mode( card, 0x08 );
+	
+	if (err == CMD_OK) { 
+		
+		for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) {	
 			/* Run command READ_CODE_VERSION */
 			memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
-			mb->cmd.length = 0;
-			mb->cmd.command = 0x10;
+			mb->cmd.length  = 0;
+			mb->cmd.command = PPP_READ_CODE_VERSION;
 			err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-			if (err != CMD_OK)
+			if (err != CMD_OK) 
 				ppp_error(card, err, mb);
 		}
-	} else
-		return err;
-	err = ppp_set_intr_mode(card, 0);
-	if (err != CMD_OK)
+	}
+	else return err;
+
+	err = ppp_set_intr_mode( card, 0 );
+	if (err != CMD_OK) 
 		return err;
+
 	card->wandev.critical = 1;
 	return 0;
 }
@@ -2222,40 +2797,140 @@
 /*==============================================================================
  * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ?
  */
-
-static int udp_pkt_type(struct sk_buff *skb, sdla_t * card)
+static int udp_pkt_type( struct sk_buff *skb, sdla_t *card )
 {
 	unsigned char *sendpacket;
-	unsigned char buf2[5];
+	unsigned char buf2[5]; 
+	//FIXME: Use the structure
+	ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t *)skb->data; 
+	
 	sendpacket = skb->data;
 	memcpy(&buf2, &card->wandev.udp_port, 2);
-	if (sendpacket[0] == 0x45 &&	/* IP packet */
-	    sendpacket[9] == 0x11 &&	/* UDP packet */
-	    sendpacket[22] == buf2[1] &&	/* UDP Port */
-	    sendpacket[23] == buf2[0] &&
-	    sendpacket[36] == 0x01) {
-		if (sendpacket[28] == 0x50 &&	/* PTPIPEAB: Signature */
-		    sendpacket[29] == 0x54 &&
-		    sendpacket[30] == 0x50 &&
-		    sendpacket[31] == 0x49 &&
-		    sendpacket[32] == 0x50 &&
-		    sendpacket[33] == 0x45 &&
-		    sendpacket[34] == 0x41 &&
-		    sendpacket[35] == 0x42) {
+	
+	if( 	ppp_udp_pkt->ip_pkt.ver_inet_hdr_length  == 0x45 &&        /* IP packet */ 
+		sendpacket[9]  == 0x11 &&        /* UDP packet */
+		sendpacket[22] == buf2[1] &&     /* UDP Port */
+		sendpacket[23] == buf2[0] &&
+		sendpacket[36] == 0x01 ) {
+	
+		if (    sendpacket[28] == 0x50 &&    /* PTPIPEAB: Signature */ 
+			sendpacket[29] == 0x54 &&      
+			sendpacket[30] == 0x50 &&      
+			sendpacket[31] == 0x49 &&      
+			sendpacket[32] == 0x50 &&      
+			sendpacket[33] == 0x45 &&      
+			sendpacket[34] == 0x41 &&      
+			sendpacket[35] == 0x42 ){ 
+
 			return UDP_PTPIPE_TYPE;
-		} else if (sendpacket[28] == 0x44 &&	/* DRVSTATS: Signature */
-			   sendpacket[29] == 0x52 &&
-			   sendpacket[30] == 0x56 &&
-			   sendpacket[31] == 0x53 &&
-			   sendpacket[32] == 0x54 &&
-			   sendpacket[33] == 0x41 &&
-			   sendpacket[34] == 0x54 &&
-			   sendpacket[35] == 0x53) {
+	
+		} else if(sendpacket[28] == 0x44 &&  /* DRVSTATS: Signature */
+			sendpacket[29] == 0x52 &&      
+      			sendpacket[30] == 0x56 &&      
+      			sendpacket[31] == 0x53 &&      
+      			sendpacket[32] == 0x54 &&      
+      			sendpacket[33] == 0x41 &&      
+      			sendpacket[34] == 0x54 &&      
+      			sendpacket[35] == 0x53 ){
+	
 			return UDP_DRVSTATS_TYPE;
+
 		} else
 			return UDP_INVALID_TYPE;
+
 	} else
 		return UDP_INVALID_TYPE;
+
+}
+
+/*============================================================================
+ * Check to see if the packet to be transmitted contains a broadcast or
+ * multicast source IP address.
+ */
+
+static int chk_bcast_mcast_addr(sdla_t *card, struct device* dev,
+				struct sk_buff *skb)
+{
+	u32 src_ip_addr;
+        u32 broadcast_ip_addr = 0;
+        struct in_device *in_dev;
+        /* read the IP source address from the outgoing packet */
+        src_ip_addr = *(u32 *)(skb->data + 12);
+
+	/* read the IP broadcast address for the device */
+        in_dev = dev->ip_ptr;
+        if(in_dev != NULL) {
+                struct in_ifaddr *ifa= in_dev->ifa_list;
+                if(ifa != NULL)
+                        broadcast_ip_addr = ifa->ifa_broadcast;
+                else
+                        return 0;
+        }
+ 
+        /* check if the IP Source Address is a Broadcast address */
+        if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) {
+                printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n",
+				card->devname);
+                dev_kfree_skb(skb);
+                ++card->wandev.stats.tx_dropped;
+                return 1;
+        } 
+
+        /* check if the IP Source Address is a Multicast address */
+        if((ntohl(src_ip_addr) >= 0xE0000001) &&
+		(ntohl(src_ip_addr) <= 0xFFFFFFFE)) {
+                printk(KERN_INFO "%s: Multicast Source Address silently discarded\n",
+				card->devname);
+                dev_kfree_skb(skb);
+                ++card->wandev.stats.tx_dropped;
+                return 1;
+        }
+
+        return 0;
+}
+
+void s508_lock (sdla_t *card, unsigned long *smp_flags)
+{
+#ifdef __SMP__
+	spin_lock_irqsave(&card->lock, *smp_flags);
+#else
+	disable_irq(card->hw.irq);
+#endif                                                                     
+}
+
+void s508_unlock (sdla_t *card, unsigned long *smp_flags)
+{
+#ifdef __SMP__
+        spin_unlock_irqrestore(&card->lock, *smp_flags);
+#else
+	enable_irq(card->hw.irq);
+#endif           
+}
+
+static int read_connection_info (sdla_t *card)
+{
+	ppp_mbox_t *mb = card->mbox;
+	struct device *dev = card->wandev.dev;
+	ppp_private_area_t *ppp_priv_area = dev->priv;
+	ppp508_connect_info_t *ppp508_connect_info;
+	int err;
+
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	mb->cmd.length  = 0;
+	mb->cmd.command = PPP_GET_CONNECTION_INFO;
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+
+	if (err != CMD_OK) { 
+		ppp_error(card, err, mb);
+	}
+	else {
+		ppp508_connect_info = (ppp508_connect_info_t *)mb->data;
+
+		ppp_priv_area->ip_remote = ppp508_connect_info->ip_remote;
+		ppp_priv_area->ip_local = ppp508_connect_info->ip_local;
+	}
+
+	return err;
 }
 
 /****** End *****************************************************************/
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdladrv.c linux.14p16/drivers/net/sdladrv.c
--- linux.vanilla/drivers/net/sdladrv.c	Thu Jan  7 17:21:53 1999
+++ linux.14p16/drivers/net/sdladrv.c	Wed Dec 15 16:18:30 1999
@@ -4,15 +4,18 @@
 *		This module is a library of common hardware-specific functions
 *		used by all Sangoma drivers.
 *
-* Author:	Gene Kozin	<genek@compuserve.com>
+* Author:	Gideon Hack	
 *
-* Copyright:	(c) 1995-1996 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-1999 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.
 * ============================================================================
+* Jun 02, 1999  Gideon Hack     Added support for the S514 adapter.
+*				Updates for Linux 2.2.X kernels.	
+* Sep 17, 1998	Jaspreet Singh	Updates for linux 2.2.X kernels
 * 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.
@@ -81,6 +84,7 @@
 
 #if	defined(_LINUX_)	/****** Linux *******************************/
 
+#include <linux/version.h>
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
@@ -89,13 +93,18 @@
 #include <linux/sched.h>	/* for jiffies, HZ, etc. */
 #include <linux/sdladrv.h>	/* API definitions */
 #include <linux/sdlasfm.h>	/* SDLA firmware module definitions */
-#include <linux/init.h>
+#include <linux/sdlapci.h>	/* SDLA PCI hardware definitions */
+#include <linux/pci.h>		/* PCI defines and function prototypes */
 #include <asm/io.h>		/* for inb(), outb(), etc. */
+
 #define _INB(port)		(inb(port))
 #define _OUTB(port, byte)	(outb((byte),(port)))
 #define	SYSTEM_TICK		jiffies
 
+#include <linux/init.h>
+
 #elif	defined(_SCO_UNIX_)	/****** SCO Unix ****************************/
+
 #if	!defined(INKERNEL)
 #error	This code MUST be compiled in kernel mode!
 #endif
@@ -135,6 +144,11 @@
 #define S503_MINMEM	0x8000L
 #define S507_MINMEM	0x20000L
 #define S508_MINMEM	0x20000L
+#define NO_PORT         -1
+
+
+
+
 
 /****** Function Prototypes *************************************************/
 
@@ -158,14 +172,18 @@
 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);
+static int detect_s514  (sdlahw_t* hw);
+static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card);
 
 /* Miscellaneous functions */
+static void peek_by_4 (unsigned long src, void* buf, unsigned len);
+static void poke_by_4 (unsigned long dest, void* buf, unsigned len);
 static int calibrate_delay (int mks);
 static int get_option_index (unsigned* optlist, unsigned optval);
 static unsigned check_memregion (void* ptr, unsigned len);
@@ -179,7 +197,7 @@
 /* private data */
 static char modname[]	= "sdladrv";
 static char fullname[]	= "SDLA Support Module";
-static char copyright[]	= "(c) 1995-1996 Sangoma Technologies Inc.";
+static char copyright[]	= "(c) 1995-1999 Sangoma Technologies Inc.";
 static unsigned	exec_idle;
 
 /* Hardware configuration options.
@@ -324,7 +342,7 @@
  * Return:	0	ok.
  *		< 0	error
  */
- 
+
 EXPORT_SYMBOL(sdla_setup);
 
 int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len)
@@ -332,118 +350,123 @@
 	unsigned* irq_opt	= NULL;	/* IRQ options */
 	unsigned* dpmbase_opt	= NULL;	/* DPM window base options */
 	unsigned* pclk_opt	= NULL;	/* CPU clock rate options */
-	int err;
+	int err=0;
 
-	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
+	if (sdla_detect(hw)) {
+                if(hw->type != SDLA_S514)
+                        printk(KERN_ERR "%s: no SDLA card found at port 0x%X\n",
+                        modname, hw->port);
+		return -EINVAL;
+	}
+
+	if(hw->type != SDLA_S514) {
+                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;
+					modname);
+                                return err;
+                        }
+                }
+                else if (!get_option_index(dpmbase_opt,
+			virt_to_phys(hw->dpmbase))) {
+                        printk(KERN_ERR
+				"%s: memory address 0x%lX is illegal!\n",
+				modname, virt_to_phys(hw->dpmbase));
+                        return -EINVAL;
+                }               
+                else if (sdla_setdpm(hw)) {
+                        printk(KERN_ERR
+			"%s: 8K memory region at 0x%lX is not available!\n",
+				modname, virt_to_phys(hw->dpmbase));
+                        return -EINVAL;
+                } 
+                printk(KERN_INFO
+			"%s: dual-port memory window is set at 0x%lX.\n",
+				modname, virt_to_phys(hw->dpmbase));
+        }
+
+	else {
+		hw->memory = test_memregion((void*)hw->dpmbase, 
+			MAX_SIZEOF_S514_MEMORY);
+		if(hw->memory < (256 * 1024)) {
+			printk(KERN_ERR
+				"%s: error in testing S514 memory (0x%lX)\n",
+				modname, hw->memory);
+			sdla_down(hw);
+			return -EINVAL;
 		}
 	}
-	else if (!get_option_index(dpmbase_opt, virt_to_phys(hw->dpmbase)))
-	{
-		printk(KERN_ERR "%s: memory address 0x%lX is illegal!\n",
-			modname, virt_to_phys(hw->dpmbase))
-		;
-		return -EINVAL;
-	} 
-	else if (sdla_setdpm(hw))
-	{
-		printk(KERN_ERR
-			"%s: 8K memory region at 0x%lX is not available!\n",
-			modname, virt_to_phys(hw->dpmbase));
-		return -EINVAL;
-	} 
-	printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n",
-		modname, virt_to_phys(hw->dpmbase));
-
-	printk(KERN_INFO "%s: found %luK bytes of on-board memory.\n",
+    
+	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;
 } 
 
@@ -457,11 +480,13 @@
 {
 	unsigned port = hw->port;
 	int i;
+        unsigned char CPU_no;
+        u32 int_config, int_status;
 
-	if (!port) return -EFAULT;
+        if(!port && (hw->type != SDLA_S514))
+                return -EFAULT;
 
-	switch (hw->type)
-	{
+	switch (hw->type) {
 	case SDLA_S502A:
 		_OUTB(port, 0x08);		/* halt CPU */
 		_OUTB(port, 0x08);
@@ -486,6 +511,30 @@
 		hw->regs[0] = 0;
 		break;
 
+	case SDLA_S514:
+		/* halt the adapter */
+                *(char *)hw->vector = S514_CPU_HALT;
+        	CPU_no = hw->S514_cpu_no[0];
+
+		/* disable the PCI IRQ and disable memory access */
+                pci_read_config_dword(hw->pci_dev, PCI_INT_CONFIG, &int_config);
+	        int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : 			~PCI_DISABLE_IRQ_CPU_B;
+                pci_write_config_dword(hw->pci_dev, PCI_INT_CONFIG, int_config);
+		read_S514_int_stat(hw, &int_status);
+		S514_intack(hw, int_status);
+		if(CPU_no == S514_CPU_A)
+                        pci_write_config_dword(hw->pci_dev, PCI_MAP0_DWORD,
+				PCI_CPU_A_MEM_DISABLE);
+		else
+                        pci_write_config_dword(hw->pci_dev, PCI_MAP1_DWORD,
+				PCI_CPU_B_MEM_DISABLE);
+
+		/* free up the allocated virtual memory */
+ 		iounmap((void *)hw->dpmbase);
+        	iounmap((void *)hw->vector);
+ 		break;
+
+
 	default:
 		return -EINVAL;
 	}
@@ -503,12 +552,10 @@
 	unsigned port = hw->port;
 	register int tmp;
 
-	switch (hw->type)
-	{
+	switch (hw->type) {
 	case SDLA_S502A:
 	case SDLA_S502E:
-		if (addr < S502_MAXMEM)	/* verify parameter */
-		{
+		if (addr < S502_MAXMEM)	{ /* verify parameter */
 			tmp = addr >> 13;	/* convert to register mask */
 			_OUTB(port + 2, tmp);
 			hw->regs[2] = tmp;
@@ -517,8 +564,7 @@
 		break;
 
 	case SDLA_S503:
-		if (addr < S503_MAXMEM)	/* verify parameter */
-		{
+		if (addr < S503_MAXMEM)	{ /* verify parameter */
 			tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70);
 			_OUTB(port, tmp);
 			hw->regs[0] = tmp;
@@ -527,11 +573,9 @@
 		break;
 
 	case SDLA_S507:
-		if (addr < S507_MAXMEM)
-		{
+		if (addr < S507_MAXMEM) {
 			if (!(_INB(port) & 0x02))
-				return -EIO
-			;
+				return -EIO;
 			tmp = addr >> 13;	/* convert to register mask */
 			_OUTB(port + 2, tmp);
 			hw->regs[2] = tmp;
@@ -540,8 +584,7 @@
 		break;
 
 	case SDLA_S508:
-		if (addr < S508_MAXMEM)
-		{
+		if (addr < S508_MAXMEM) {
 			tmp = addr >> 13;	/* convert to register mask */
 			_OUTB(port + 2, tmp);
 			hw->regs[2] = tmp;
@@ -549,7 +592,10 @@
 		else return -EINVAL;
 		break;
 
-	default:
+	case SDLA_S514:
+		return 0;
+
+ 	default:
 		return -EINVAL;
 	}
 	hw->vector = addr & 0xFFFFE000L;
@@ -559,7 +605,7 @@
 /*============================================================================
  * Enable interrupt generation.
  */
- 
+
 EXPORT_SYMBOL(sdla_inten);
 
 int sdla_inten (sdlahw_t* hw)
@@ -567,14 +613,12 @@
 	unsigned port = hw->port;
 	int tmp, i;
 
-	switch (hw->type)
-	{
+	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)
-		{
+		if (_INB(port) & 0x01) {
 			_OUTB(port, 0x02);	/* bit1 = 1, bit2 = 0 */
 			_OUTB(port, 0x06);	/* bit1 = 1, bit2 = 1 */
 			hw->regs[0] = 0x06;
@@ -588,8 +632,7 @@
 		hw->regs[0] = tmp;		/* update mirror */
 		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
 		if (!(_INB(port) & 0x02))		/* verify */
-			return -EIO
-		;
+			return -EIO;
 		break;
 
 	case SDLA_S508:
@@ -598,14 +641,16 @@
 		hw->regs[0] = tmp;		/* update mirror */
 		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
 		if (!(_INB(port + 1) & 0x10))		/* verify */
-			return -EIO
-		;
+			return -EIO;
 		break;
 
 	case SDLA_S502A:
 	case SDLA_S507:
 		break;
 
+        case SDLA_S514:
+                break;
+
 	default:
 		return -EINVAL;
 
@@ -624,8 +669,7 @@
 	unsigned port = hw->port;
 	int tmp, i;
 
-	switch (hw->type)
-	{
+	switch (hw->type) {
 	case SDLA_S502E:
 		/* Notes:
 		 *  1) interrupt control operations are allowed only if CPU is
@@ -634,8 +678,7 @@
 		 *     causes IRQ line go high, therefore we are going to use
 		 *     0x04 instead: lower it to inhibit interrupts to PC.
 		 */
-		if (_INB(port) & 0x01)
-		{
+		if (_INB(port) & 0x01) {
 			_OUTB(port, hw->regs[0] & ~0x04);
 			hw->regs[0] &= ~0x04;
 		}
@@ -648,8 +691,7 @@
 		hw->regs[0] = tmp;			/* update mirror */
 		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
 		if (_INB(port) & 0x02)			/* verify */
-			return -EIO
-		;
+			return -EIO;
 		break;
 
 	case SDLA_S508:
@@ -658,8 +700,7 @@
 		hw->regs[0] = tmp;			/* update mirror */
 		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
 		if (_INB(port) & 0x10)			/* verify */
-			return -EIO
-		;
+			return -EIO;
 		break;
 
 	case SDLA_S502A:
@@ -683,16 +724,14 @@
 	unsigned port = hw->port;
 	int tmp;
 
-	switch (hw->type)
-	{
+	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)
-		{
+		if (_INB(port) & 0x01) {
 			tmp = hw->regs[0] & ~0x04;
 			_OUTB(port, tmp);
 			tmp |= 0x04;
@@ -703,8 +742,7 @@
 		break;
 
 	case SDLA_S503:
-		if (_INB(port) & 0x04)
-		{
+		if (_INB(port) & 0x04) {
 			tmp = hw->regs[0] & ~0x08;
 			_OUTB(port, tmp);
 			tmp |= 0x08;
@@ -724,6 +762,31 @@
 	return 0;
 }
 
+
+/*============================================================================
+ * Acknowledge S514 hardware interrupt.
+ */
+
+EXPORT_SYMBOL(S514_intack);
+
+void S514_intack (sdlahw_t* hw, u32 int_status)
+{
+        pci_write_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status);
+}
+
+
+/*============================================================================
+ * Read the S514 hardware interrupt status.
+ */
+
+EXPORT_SYMBOL(read_S514_int_stat);
+
+void read_S514_int_stat (sdlahw_t* hw, u32* int_status)
+{
+	pci_read_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status);
+}
+
+
 /*============================================================================
  * Generate an interrupt to adapter's CPU.
  */
@@ -734,11 +797,9 @@
 {
 	unsigned port = hw->port;
 
-	switch (hw->type)
-	{
+	switch (hw->type) {
 	case SDLA_S502A:
-		if (!(_INB(port) & 0x40))
-		{
+		if (!(_INB(port) & 0x40)) {
 			_OUTB(port, 0x10);		/* issue NMI to CPU */
 			hw->regs[0] = 0x10;
 		}
@@ -746,16 +807,14 @@
 		break;
 
 	case SDLA_S507:
-		if ((_INB(port) & 0x06) == 0x06)
-		{
+		if ((_INB(port) & 0x06) == 0x06) {
 			_OUTB(port + 3, 0);
 		}
 		else return -EIO;
 		break;
 
 	case SDLA_S508:
-		if (_INB(port + 1) & 0x02)
-		{
+		if (_INB(port + 1) & 0x02) {
 			_OUTB(port, 0x08);
 		}
 		else return -EIO;
@@ -784,14 +843,19 @@
 	unsigned long tstop;
 	int nloops;
 
-	if (*flag) return 0;	/* ???? */
+	if(readb(flag) != 0x00) {
+		printk(KERN_INFO
+			"WANPIPE: opp flag set on entry to sdla_exec\n");
+		return 0;
+	}
+	
+	writeb(0x01, flag);
 
-	*flag = 1;
 	tstop = SYSTEM_TICK + EXEC_TIMEOUT;
-	for (nloops = 1; *flag; ++nloops)
-	{
+
+	for (nloops = 1; (readb(flag) == 0x01); ++ nloops) {
 		unsigned delay = exec_idle;
-		while (--delay);			/* delay */
+		while (-- delay);			/* delay */
 		if (SYSTEM_TICK > tstop) return 0;	/* time is up! */
 	}
 	return nloops;
@@ -806,39 +870,79 @@
  * This function is not atomic, so caller must disable interrupt if
  * interrupt routines are accessing adapter shared memory.
  */
- 
+
 EXPORT_SYMBOL(sdla_peek);
 
 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(buf, (void *)((u8 *)hw->dpmbase + curpos), curlen);
-		addr       += curlen;
-		(char*)buf += curlen;
-		len        -= curlen;
-	}
+		return -EINVAL;
 
-	/* Restore DPM window position */
-	sdla_mapmem(hw, oldvec);
-	return err;
+        if(hw->type == SDLA_S514) {	/* copy data for the S514 adapter */
+                peek_by_4 ((unsigned long)hw->dpmbase + addr, buf, len);
+                return 0;
+	}
+
+        else {				/* copy data for the S508 adapter */
+	        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;
+
+                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);
+                        peek_by_4 ((unsigned long)hw->dpmbase + curpos, buf,
+				curlen);
+                        addr       += curlen;
+                        (char*)buf += curlen;
+                        len        -= curlen;
+                }
+
+                /* Restore DPM window position */
+                sdla_mapmem(hw, oldvec);
+                return err;
+        }
+}
+
+
+/*============================================================================
+ * Read data from adapter's memory to a data buffer in 4-byte chunks.
+ * Note that we ensure that the SDLA memory address is on a 4-byte boundary
+ * before we begin moving the data in 4-byte chunks.
+*/
+
+static void peek_by_4 (unsigned long src, void* buf, unsigned len)
+{
+
+        /* byte copy data until we get to a 4-byte boundary */
+        while (len && (src & 0x03)) {
+                *(char *)buf ++ = readb(src ++);
+                len --;
+        }
+
+        /* copy data in 4-byte chunks */
+        while (len >= 4) {
+                *(unsigned long *)buf = readl(src);
+                buf += 4;
+                src += 4;
+                len -= 4;
+        }
+
+        /* byte copy any remaining data */
+        while (len) {
+                *(char *)buf ++ = readb(src ++);
+                len --;
+        }
 }
 
+
 /*============================================================================
  * Write Absolute Adapter Memory.
  * Transfer data from data buffer to adapter's memory.
@@ -848,39 +952,79 @@
  * This function is not atomic, so caller must disable interrupt if
  * interrupt routines are accessing adapter shared memory.
  */
- 
+
 EXPORT_SYMBOL(sdla_poke);
  
 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*)((u8 *)hw->dpmbase + curpos), buf, curlen);
-		addr       += curlen;
-		(char*)buf += curlen;
-		len        -= curlen;
-	}
+		return -EINVAL;
+   
+        if(hw->type == SDLA_S514) {	/* copy data for the S514 adapter */
+                poke_by_4 ((unsigned long)hw->dpmbase + addr, buf, len);
+                return 0;
+	}
+	
+	else {				/* copy data for the S508 adapter */
+    		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;
+
+		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);
+                        poke_by_4 ((unsigned long)hw->dpmbase + curpos, buf,
+				curlen);
+	                addr       += curlen;
+                        (char*)buf += curlen;
+                        len        -= curlen;
+                }
+
+                /* Restore DPM window position */
+                sdla_mapmem(hw, oldvec);
+                return err;
+        }
+}
 
-	/* Restore DPM window position */
-	sdla_mapmem(hw, oldvec);
-	return err;
+
+/*============================================================================
+ * Write from a data buffer to adapter's memory in 4-byte chunks.
+ * Note that we ensure that the SDLA memory address is on a 4-byte boundary
+ * before we begin moving the data in 4-byte chunks.
+*/
+
+static void poke_by_4 (unsigned long dest, void* buf, unsigned len)
+{
+
+        /* byte copy data until we get to a 4-byte boundary */
+        while (len && (dest & 0x03)) {
+                writeb (*(char *)buf ++, dest ++);
+                len --;
+        }
+
+        /* copy data in 4-byte chunks */
+        while (len >= 4) {
+                writel (*(unsigned long *)buf, dest);
+                dest += 4;
+                buf += 4;
+                len -= 4;
+        }
+
+        /* byte copy any remaining data */
+        while (len) {
+                writeb (*(char *)buf ++ , dest ++);
+                len --;
+        }
 }
 
+
 #ifdef	DONT_COMPIPLE_THIS
 #endif	/* DONT_COMPIPLE_THIS */
 
@@ -901,11 +1045,10 @@
 	unsigned port = hw->port;
 	int err = 0;
 
-	if (!port)
-		return -EFAULT
-	;
-	switch (hw->type)
-	{
+	if (!port && (hw->type != SDLA_S514))
+		return -EFAULT;
+
+    	switch (hw->type) {
 	case SDLA_S502A:
 		if (!detect_s502a(port)) err = -ENODEV;
 		break;
@@ -926,22 +1069,21 @@
 		if (!detect_s508(port)) err = -ENODEV;
 		break;
 
+	case SDLA_S514:
+                if (!detect_s514(hw)) err = -ENODEV;
+		break;
+
 	default:
 		if (detect_s502a(port))
-			hw->type = SDLA_S502A
-		;
+			hw->type = SDLA_S502A;
 		else if (detect_s502e(port))
-			hw->type = SDLA_S502E
-		;
+			hw->type = SDLA_S502E;
 		else if (detect_s503(port))
-			hw->type = SDLA_S503
-		;
+			hw->type = SDLA_S503;
 		else if (detect_s507(port))
-			hw->type = SDLA_S507
-		;
+			hw->type = SDLA_S507;
 		else if (detect_s508(port))
-			hw->type = SDLA_S508
-		;
+			hw->type = SDLA_S508;
 		else err = -ENODEV;
 	}
 	return err;
@@ -956,8 +1098,7 @@
 	int i, err = -EINVAL;
 	unsigned* opt;
 
-	switch (hw->type)
-	{
+	switch (hw->type) {
 	case SDLA_S502A:
 		opt = s502a_dpmbase_options;
 		break;
@@ -976,8 +1117,7 @@
 		return -EINVAL;
 	}
 
-	for (i = opt[0]; i && err; --i)
-	{
+	for (i = opt[0]; i && err; --i) {
 		hw->dpmbase = phys_to_virt(opt[i]);
 		err = sdla_setdpm(hw);
 	}
@@ -1000,8 +1140,7 @@
 	/* Shut down card and verify memory region */
 	sdla_down(hw);
 	if (check_memregion(hw->dpmbase, hw->dpmsize))
-		return -EINVAL
-	;
+		return -EINVAL;
 
 	/* Initialize adapter and test on-board memory segment by segment.
 	 * If memory size appears to be less than shared memory window size,
@@ -1010,8 +1149,7 @@
 	err = sdla_init(hw);
 	if (err) return err;
 
-	if (sdla_memtest(hw) < hw->dpmsize)	/* less than window size */
-	{
+	if (sdla_memtest(hw) < hw->dpmsize) {	/* less than window size */
 		sdla_down(hw);
 		return -EIO;
 	}
@@ -1026,32 +1164,28 @@
  */
 static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len)
 {
+
 	int i;
 
 	/* Verify firmware signature */
-	if (strcmp(sfm->signature, SFM_SIGNATURE))
-	{
+	if (strcmp(sfm->signature, SFM_SIGNATURE)) {
 		printk(KERN_ERR "%s: not SDLA firmware!\n",
-			modname)
-		;
+			modname);
 		return -EINVAL;
 	}
 
 	/* Verify firmware module format version */
-	if (sfm->version != SFM_VERSION)
-	{
+	if (sfm->version != SFM_VERSION) {
 		printk(KERN_ERR
 			"%s: firmware format %u rejected! Expecting %u.\n",
-			modname, sfm->version, SFM_VERSION)
-		;
+			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))
-	{
+		sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) {
 		printk(KERN_ERR "%s: firmware corrupted!\n", modname);
 		return -EINVAL;
 	}
@@ -1059,8 +1193,11 @@
 	/* Announce */
 	printk(KERN_INFO "%s: loading %s (ID=%u)...\n", modname,
 		(sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware",
-		sfm->info.codeid)
-	;
+		sfm->info.codeid);
+
+	if(hw->type == SDLA_S514)
+		printk(KERN_INFO "%s: loading S514 adapter, CPU %c\n",
+			modname, hw->S514_cpu_no[0]);
 
 	/* Scan through the list of compatible adapters and make sure our
 	 * adapter type is listed.
@@ -1069,49 +1206,41 @@
 	     (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type);
 	     ++i)
 	;
-	if (i == SFM_MAX_SDLA)
-	{
+	if (i == SFM_MAX_SDLA) {
 		printk(KERN_ERR "%s: firmware is not compatible with S%u!\n",
-			modname, hw->type)
+			modname, hw->type);
 		;
 		return -EINVAL;
 	}
 
+
 	/* Make sure there is enough on-board memory */
-	if (hw->memory < sfm->info.memsize)
-	{
+	if (hw->memory < sfm->info.memsize) {
 		printk(KERN_ERR
 			"%s: firmware needs %lu bytes of on-board memory!\n",
-			modname, sfm->info.memsize)
-		;
+			modname, sfm->info.memsize);
 		return -EINVAL;
 	}
 
 	/* Move code onto adapter */
-	if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize))
-	{
+	if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) {
 		printk(KERN_ERR "%s: failed to load code segment!\n",
-			modname)
-		;
+			modname);
 		return -EIO;
 	}
 
 	/* Prepare boot-time configuration data and kick-off CPU */
 	sdla_bootcfg(hw, &sfm->info);
-	if (sdla_start(hw, sfm->info.startoffs))
-	{
+	if (sdla_start(hw, sfm->info.startoffs)) {
 		printk(KERN_ERR "%s: Damn... Adapter won't start!\n",
-			modname)
-		;
+			modname);
 		return -EIO;
 	}
 
 	/* position DPM window over the mailbox and enable interrupts */
-        if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw))
-	{
+        if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) {
 		printk(KERN_ERR "%s: adapter hardware failure!\n",
-			modname)
-		;
+			modname);
 		return -EIO;
 	}
 	hw->fwid = sfm->info.codeid;		/* set firmware ID */
@@ -1126,10 +1255,9 @@
 	int i;
 
 	for (i = 0; i < SDLA_MAXIORANGE; ++i)
-		hw->regs[i] = 0
-	;
-	switch (hw->type)
-	{
+		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);
@@ -1172,23 +1300,28 @@
 	if (!sfminfo->datasize) return 0;	/* nothing to do */
 
 	if (sdla_mapmem(hw, sfminfo->dataoffs) != 0)
-		return -EIO
-	;
-	data = (void*)((u8 *)hw->dpmbase + (sfminfo->dataoffs - hw->vector));
-	memset(data, 0, sfminfo->datasize);
+		return -EIO;
+
+	if(hw->type == SDLA_S514)
+                data = (void*)(hw->dpmbase + sfminfo->dataoffs);
+        else
+                data = (void*)((u8 *)hw->dpmbase +
+                        (sfminfo->dataoffs - hw->vector));
+
+	memset_io (data, 0, sfminfo->datasize);
+
+	writeb (make_config_byte(hw), &data[0x00]);
 
-	data[0x00] = make_config_byte(hw);
-	switch (sfminfo->codeid)
-	{
+	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 */
+                writeb (3, &data[0x01]);        /* T1 timer */
+                writeb (10, &data[0x03]);       /* N2 */
+                writeb (7, &data[0x06]);        /* HDLC window size */
+                writeb (1, &data[0x0B]);        /* DTE */
+                writeb (2, &data[0x0C]);        /* X.25 packet window size */
+                writew (128, &data[0x0D]);	/* default X.25 data size */
+                writew (128, &data[0x0F]);	/* maximum X.25 data size */
 		break;
 	}
 	return 0;
@@ -1201,16 +1334,15 @@
 {
 	unsigned char byte = 0;
 
-	switch (hw->pclk)
-	{
+	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)
-	{
+
+	switch (hw->type) {
 		case SDLA_S502E: byte |= 0x80; break;
 		case SDLA_S503:  byte |= 0x40; break;
 	}
@@ -1230,10 +1362,9 @@
 	unsigned char *bootp;
 	int err, tmp, i;
 
-	if (!port) return -EFAULT;
+	if (!port && (hw->type != SDLA_S514)) return -EFAULT;
 
-	switch (hw->type)
-	{
+ 	switch (hw->type) {
 	case SDLA_S502A:
 		bootp = hw->dpmbase;
 		bootp += 0x66;
@@ -1243,6 +1374,7 @@
 	case SDLA_S503:
 	case SDLA_S507:
 	case SDLA_S508:
+	case SDLA_S514:
 		bootp = hw->dpmbase;
 		break;
 
@@ -1253,12 +1385,11 @@
 	err = sdla_mapmem(hw, 0);
 	if (err) return err;
 
-	*bootp = 0xC3;	 /* Z80: 'jp' opcode */
-	bootp++;
-	*((unsigned short*)(bootp)) = addr;
+      	writeb (0xC3, bootp);   /* Z80: 'jp' opcode */
+	bootp ++;
+	writew (addr, bootp);
 
-	switch (hw->type)
-	{
+	switch (hw->type) {
 	case SDLA_S502A:
 		_OUTB(port, 0x10);		/* issue NMI to CPU */
 		hw->regs[0] = 0x10;
@@ -1268,8 +1399,7 @@
 		_OUTB(port + 3, 0x01);		/* start CPU */
 		hw->regs[3] = 0x01;
 		for (i = 0; i < SDLA_IODELAY; ++i);
-		if (_INB(port) & 0x01)		/* verify */
-		{
+		if (_INB(port) & 0x01) {	/* verify */
 			/*
 			 * Enabling CPU changes functionality of the
 			 * control register, so we have to reset its
@@ -1287,8 +1417,7 @@
 		hw->regs[0] = tmp;		/* update mirror */
 		for (i = 0; i < SDLA_IODELAY; ++i);
 		if (!(_INB(port) & 0x01))	/* verify */
-			return -EIO
-		;
+			return -EIO;
 		break;
 
 	case SDLA_S507:
@@ -1297,8 +1426,7 @@
 		hw->regs[0] = tmp;		/* update mirror */
 		for (i = 0; i < SDLA_IODELAY; ++i);
 		if (!(_INB(port) & 0x04))	/* verify */
-			return -EIO
-		;
+			return -EIO;
 		break;
 
 	case SDLA_S508:
@@ -1307,8 +1435,11 @@
 		hw->regs[0] = tmp;	/* update mirror */
 		for (i = 0; i < SDLA_IODELAY; ++i);
 		if (!(_INB(port + 1) & 0x02))	/* verify */
-			return -EIO
-		;
+			return -EIO;
+		break;
+
+	case SDLA_S514:
+		writeb (S514_CPU_START, hw->vector);
 		break;
 
 	default:
@@ -1326,20 +1457,18 @@
 	int tmp, i;
 
 	if (!detect_s502a(port))
-		return -ENODEV
-	;
+		return -ENODEV;
+
 	hw->regs[0] = 0x08;
 	hw->regs[1] = 0xFF;
 
 	/* Verify configuration options */
 	i = get_option_index(s502a_dpmbase_options, virt_to_phys(hw->dpmbase));
 	if (i == 0)
-		return -EINVAL
-	;
+		return -EINVAL;
 
 	tmp = s502a_hmcr[i - 1];
-	switch (hw->dpmsize)
-	{
+	switch (hw->dpmsize) {
 	case 0x2000:
 		tmp |= 0x01;
 		break;
@@ -1367,18 +1496,15 @@
 	int tmp, i;
 
 	if (!detect_s502e(port))
-		return -ENODEV
-	;
+		return -ENODEV;
 
 	/* Verify configuration options */
 	i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase));
 	if (i == 0)
-		return -EINVAL
-	;
+		return -EINVAL;
 
 	tmp = s502e_hmcr[i - 1];
-	switch (hw->dpmsize)
-	{
+	switch (hw->dpmsize) {
 	case 0x2000:
 		tmp |= 0x01;
 		break;
@@ -1411,18 +1537,15 @@
 	int tmp, i;
 
 	if (!detect_s503(port))
-		return -ENODEV
-	;
+		return -ENODEV;
 
 	/* Verify configuration options */
 	i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase));
 	if (i == 0)
-		return -EINVAL
-	;
+		return -EINVAL;
 
 	tmp = s502e_hmcr[i - 1];
-	switch (hw->dpmsize)
-	{
+	switch (hw->dpmsize) {
 	case 0x2000:
 		tmp |= 0x01;
 		break;
@@ -1453,18 +1576,15 @@
 	int tmp, i;
 
 	if (!detect_s507(port))
-		return -ENODEV
-	;
+		return -ENODEV;
 
 	/* Verify configuration options */
 	i = get_option_index(s507_dpmbase_options, virt_to_phys(hw->dpmbase));
 	if (i == 0)
-		return -EINVAL
-	;
+		return -EINVAL;
 
 	tmp = s507_hmcr[i - 1];
-	switch (hw->dpmsize)
-	{
+	switch (hw->dpmsize) {
 	case 0x2000:
 		tmp |= 0x01;
 		break;
@@ -1481,8 +1601,7 @@
 	hw->regs[0] = 0x01;
 	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
 	if (!(_INB(port) & 0x20))
-		return -EIO
-	;
+		return -EIO;
 
 	/* Setup dual-port memory window */
 	_OUTB(port + 1, tmp);
@@ -1490,8 +1609,7 @@
 
 	/* Enable memory access */
 	tmp = hw->regs[0] | 0x04;
-	if (hw->irq)
-	{
+	if (hw->irq) {
 		i = get_option_index(s508_irq_options, hw->irq);
 		if (i) tmp |= s507_irqmask[i - 1];
 	}
@@ -1510,14 +1628,12 @@
 	int tmp, i;
 
 	if (!detect_s508(port))
-		return -ENODEV
-	;
+		return -ENODEV;
 
 	/* Verify configuration options */
 	i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase));
 	if (i == 0)
-		return -EINVAL
-	;
+		return -EINVAL;
 
 	/* Setup memory configuration */
 	tmp = s508_hmcr[i - 1];
@@ -1550,13 +1666,11 @@
 	int i, j;
 
 	if (!get_option_index(s502_port_options, port))
-		return 0
-	;
-	for (j = 1; j < SDLA_MAXIORANGE; ++j)
-	{
+		return 0;
+	
+	for (j = 1; j < SDLA_MAXIORANGE; ++j) {
 		if (_INB(port + j) != 0xFF)
-			return 0
-		;
+			return 0;
 		for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
 	}
 
@@ -1565,18 +1679,15 @@
 	_OUTB(port, 0x08);
 	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
 	if (_INB(port) != 0x40)
-		return 0
-	;
+		return 0;
 	_OUTB(port, 0x00);
 	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
 	if (_INB(port) != 0x40)
-		return 0
-	;
+		return 0;
 	_OUTB(port, 0x04);
 	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
 	if (_INB(port) != 0x44)
-		return 0
-	;
+		return 0;
 
 	/* Reset adapter */
 	_OUTB(port, 0x08);
@@ -1603,26 +1714,21 @@
 	int i, j;
 
 	if (!get_option_index(s502_port_options, port))
-		return 0
-	;
-	for (j = 1; j < SDLA_MAXIORANGE; ++j)
-	{
+		return 0;
+	for (j = 1; j < SDLA_MAXIORANGE; ++j) {
 		if (_INB(port + j) != 0xFF)
-			return 0
-		;
+			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
-	;
+		return 0;
 	_OUTB(port, 0x04);			/* set bit 2 */
 	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
 	if (_INB(port) != 0xFC)			/* verify */
-		return 0
-	;
+		return 0;
 
 	/* Reset adapter */
 	_OUTB(port, 0);
@@ -1646,26 +1752,21 @@
 	int i, j;
 
 	if (!get_option_index(s503_port_options, port))
-		return 0
-	;
-	for (j = 1; j < SDLA_MAXIORANGE; ++j)
-	{
+		return 0;
+	for (j = 1; j < SDLA_MAXIORANGE; ++j) {
 		if (_INB(port + j) != 0xFF)
-			return 0
-		;
+			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
-	;
+		return 0;
 	_OUTB(port, 0x04);			/* set bit 2 */
 	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
 	if (_INB(port) != 0xF2)			/* verify */
-		return 0
-	;
+		return 0;
 
 	/* Reset adapter */
 	_OUTB(port, 0);
@@ -1689,27 +1790,22 @@
 	int tmp, i, j;
 
 	if (!get_option_index(s508_port_options, port))
-		return 0
-	;
+		return 0;
 	tmp = _INB(port);
-	for (j = 1; j < S507_IORANGE; ++j)
-	{
+	for (j = 1; j < S507_IORANGE; ++j) {
 		if (_INB(port + j) != tmp)
-			return 0
-		;
+			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
-	;
+		return 0;
 	_OUTB(port, 0x01);
 	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
 	if ((_INB(port) & 0x7E) != 0x32)
-		return 0
-	;
+		return 0;
 
 	/* Reset adapter */
 	_OUTB(port, 0x00);
@@ -1732,24 +1828,205 @@
 	int i;
 
 	if (!get_option_index(s508_port_options, port))
-		return 0
-	;
+		return 0;
 	_OUTB(port, 0x00);
 	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
 	if ((_INB(port + 1) & 0x3F) != 0x00)
-		return 0
-	;
+		return 0;
 	_OUTB(port, 0x10);
 	for (i = 0; i < SDLA_IODELAY; ++i);	/* delay */
 	if ((_INB(port + 1) & 0x3F) != 0x10)
-		return 0
-	;
+		return 0;
 
 	/* Reset adapter */
 	_OUTB(port, 0x00);
 	return 1;
 }
 
+/*============================================================================
+ * Detect s514 PCI adapter.
+ *      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_s514 (sdlahw_t* hw)
+{
+	unsigned char CPU_no, slot_no;
+	int number_S514_cards = 0;
+	u32 S514_mem_base_addr = 0;
+	u32 ut_u32;
+
+	struct pci_dev *pci_dev;
+
+
+#ifdef CONFIG_PCI
+        if(!pci_present())
+        {
+                printk(KERN_ERR "%s: PCI BIOS not present!\n", modname);
+                return 0;
+        }
+#else
+        printk(KERN_ERR "%s: Linux not compiled for PCI usage!\n", modname);
+        return 0;
+#endif
+
+	/*
+	The 'setup()' procedure in 'sdlamain.c' passes the CPU number and the
+	slot number defined in 'router.conf' via the 'port' definition.
+	*/
+	CPU_no = hw->S514_cpu_no[0];
+	slot_no = hw->S514_slot_no;
+	
+	printk(KERN_INFO "%s: detecting S514 card, CPU %c, slot #%d\n",
+		modname, CPU_no, slot_no);
+
+	/* check to see that CPU A or B has been selected in 'router.conf' */
+	switch(CPU_no) {
+		case S514_CPU_A:
+		case S514_CPU_B:
+			break;
+	
+		default:
+			printk(KERN_ERR "%s: S514 CPU definition invalid.\n", 
+				modname);
+			printk(KERN_ERR "Must be 'A' or 'B'\n");
+			return 0;
+	}
+
+	number_S514_cards = find_s514_adapter(hw, 0);
+	if(!number_S514_cards)
+		return 0;
+
+	/* we are using a single S514 adapter with a slot of 0 so re-read the */	/* location of this adapter */
+	if((number_S514_cards == 1) && !slot_no) {	
+        	number_S514_cards = find_s514_adapter(hw, 1);
+		if(!number_S514_cards) {
+			printk(KERN_ERR "%s: Error finding PCI card\n",
+				modname);
+			return 0;
+		}
+	}
+
+	pci_dev = hw->pci_dev;
+	/* read the physical memory base address */
+	S514_mem_base_addr = (CPU_no == S514_CPU_A) ? 
+		(pci_dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK) :
+		(pci_dev->base_address[2] & PCI_BASE_ADDRESS_MEM_MASK);
+
+	printk(KERN_INFO "%s: S514 PCI memory at 0x%X\n",
+		modname, S514_mem_base_addr);
+	if(!S514_mem_base_addr) {
+		if(CPU_no == S514_CPU_B)
+			printk(KERN_ERR "%s: CPU #B not present on the card\n", 				modname);
+		else
+			printk(KERN_ERR "%s: No PCI memory allocated to card\n",				modname);
+		return 0;
+	}
+
+	/* enable the PCI memory */
+	pci_read_config_dword(pci_dev, 
+		(CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD,
+		&ut_u32);
+	pci_write_config_dword(pci_dev,
+		(CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD,
+		(ut_u32 | PCI_MEMORY_ENABLE));
+
+	/* check the IRQ allocated and enable IRQ usage */
+	if(!(hw->irq = pci_dev->irq)) {
+		printk(KERN_ERR "%s: IRQ not allocated to S514 adapter\n",
+			modname);
+                return 0;
+	}
+        pci_read_config_dword(pci_dev, PCI_INT_CONFIG, &ut_u32);
+        ut_u32 |= (CPU_no == S514_CPU_A) ?
+                PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B;
+        pci_write_config_dword(pci_dev, PCI_INT_CONFIG, ut_u32);
+
+	printk(KERN_INFO "%s: IRQ %d allocated to the S514 card\n",
+		modname, hw->irq);
+
+	/* map the physical PCI memory to virtual memory */
+	(void *)hw->dpmbase = ioremap((unsigned long)S514_mem_base_addr,
+		(unsigned long)MAX_SIZEOF_S514_MEMORY);
+    	/* map the physical control register memory to virtual memory */
+	(void *)hw->vector = ioremap(
+		(unsigned long)(S514_mem_base_addr + S514_CTRL_REG_BYTE),
+		(unsigned long)16);
+     
+        if(!hw->dpmbase || !hw->vector) {
+		printk(KERN_ERR "%s: PCI virtual memory allocation failed\n",
+			modname);
+                return 0;
+	}
+
+	/* halt the adapter */
+	writeb (S514_CPU_HALT, hw->vector);	
+
+	return 1;
+}
+
+/*============================================================================
+ * Find the S514 PCI adapter in the PCI bus.
+ *      Return the number of S514 adapters found (0 if no adapter found).
+ */
+static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card)
+{
+        unsigned char slot_no;
+        int number_S514_cards = 0;
+	char S514_found_in_slot = 0;
+        u16 PCI_subsys_vendor;
+
+        struct pci_dev *pci_dev = NULL;
+ 
+       slot_no = hw->S514_slot_no;
+  
+	while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev))
+        	!= NULL) {
+                pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD,
+                        &PCI_subsys_vendor);
+                if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
+                	continue;
+        	hw->pci_dev = pci_dev;
+		if(find_first_S514_card)
+			return(1);
+                number_S514_cards ++;
+                printk(KERN_INFO
+			"%s: S514 card found, slot #%d (devfn 0x%X)\n",
+                        modname, ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK),
+			pci_dev->devfn);
+                if(slot_no && (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) ==
+                        slot_no)) {
+                        S514_found_in_slot = 1;
+                        break;
+                }
+        }
+
+	/* if no S514 adapter has been found, then exit */
+        if(!number_S514_cards) {
+                printk(KERN_ERR "%s: no S514 adapters found\n", modname);
+                return 0;
+        }
+        /* if more than one S514 card has been found, then the user must have */        /* defined a slot number so that the correct adapter is used */
+        else if((number_S514_cards > 1) && !slot_no) {
+                printk(KERN_ERR "%s: More than one S514 adapter found\n",
+                        modname);
+                printk(KERN_ERR "Define a PCI slot number for this adapter\n");
+                return 0;
+        }
+        /* if the user has specified a slot number and the S514 adapter has */
+        /* not been found in that slot, then exit */
+        else if (slot_no && !S514_found_in_slot) {
+                printk(KERN_ERR
+			"%s: S514 card not found in specified slot #%d\n",
+                        modname, slot_no);
+                return 0;
+        }
+
+	return (number_S514_cards);
+}
+
+
+
 /******* Miscellaneous ******************************************************/
 
 /*============================================================================
@@ -1775,8 +2052,8 @@
 	int i;
 
 	for (i = 1; i <= optlist[0]; ++i)
-		if ( optlist[i] == optval) return i
-	;
+		if ( optlist[i] == optval)
+			return i;
 	return 0;
 }
 
@@ -1788,15 +2065,14 @@
 {
 	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 */
-		}
-	}
+        for (; len && (readb (p) == 0xFF); --len, ++p) {
+                writeb (0, p);          /* attempt to write 0 */
+                if (readb(p) != 0xFF) { /* still has to read 0xFF */
+                        writeb (0xFF, p);/* restore original value */
+                        break;          /* not good */
+                }
+        }
+
 	return len;
 }
 
@@ -1811,28 +2087,28 @@
 	unsigned len_w = len >> 1;	/* region len in words */
 	unsigned i;
 
+        for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
+                writew (0xAA55, w_ptr);
+        
 	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;
+                if (readw (w_ptr) != 0xAA55) {
+                        len_w = i;
+                        break;
+                }
+
+        for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
+                writew (0x55AA, w_ptr);
+        
+        for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
+                if (readw(w_ptr) != 0x55AA) {
+                        len_w = i;
+                        break;
+                }
+        
+        for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
+		writew (0, w_ptr);
+
+        return len_w << 1;
 }
 
 /*============================================================================
@@ -1843,10 +2119,8 @@
 	unsigned short crc = 0;
 	unsigned mask, flag;
 
-	for (; len; --len, ++buf)
-	{
-		for (mask = 0x80; mask; mask >>= 1)
-		{
+	for (; len; --len, ++buf) {
+		for (mask = 0x80; mask; mask >>= 1) {
 			flag = (crc & 0x8000);
 			crc <<= 1;
 			crc |= ((*buf & mask) ? 1 : 0);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdlamain.c linux.14p16/drivers/net/sdlamain.c
--- linux.vanilla/drivers/net/sdlamain.c	Mon Dec 28 19:05:14 1998
+++ linux.14p16/drivers/net/sdlamain.c	Thu Dec 16 00:22:56 1999
@@ -1,16 +1,21 @@
 /*****************************************************************************
 * sdlamain.c	WANPIPE(tm) Multiprotocol WAN Link Driver.  Main module.
 *
-* Author:	Gene Kozin	<genek@compuserve.com>
-*		Jaspreet Singh	<jaspreet@sangoma.com>
+* Author:	Nenad Corbic	<ncorbic@sangoma.com>
+*		Gideon Hack	
 *
-* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-1999 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.
 * ============================================================================
+* Sep 23, 1999  Nenad Corbic    Added support for SMP
+* Sep 13, 1999  Nenad Corbic	Each port is treated as a separate device.
+* Jun 02, 1999  Gideon Hack     Added support for the S514 adapter.
+*				Updates for Linux 2.2.X kernels.
+* Sep 17, 1998	Jaspreet Singh	Updated for 2.1.121+ kernel
 * Nov 28, 1997	Jaspreet Singh	Changed DRV_RELEASE to 1
 * Nov 10, 1997	Jaspreet Singh	Changed sti() to restore_flags();
 * Nov 06, 1997 	Jaspreet Singh	Changed DRV_VERSION to 4 and DRV_RELEASE to 0
@@ -29,6 +34,7 @@
 * Jan 02, 1997	Gene Kozin	Initial version.
 *****************************************************************************/
 
+#include <linux/version.h>
 #include <linux/config.h>	/* OS configuration options */
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
@@ -42,7 +48,8 @@
 #include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
 #include <asm/uaccess.h>	/* kernel <-> user copy */
 #include <asm/io.h>		/* phys_to_virt() */
-
+#include <linux/pci.h>
+#include <linux/sdlapci.h>
 
 /****** Defines & Macros ****************************************************/
 
@@ -52,8 +59,8 @@
 #define	STATIC		static
 #endif
 
-#define	DRV_VERSION	4		/* version number */
-#define	DRV_RELEASE	1		/* release (minor version) number */
+#define	DRV_VERSION	5		/* version number */
+#define	DRV_RELEASE	0		/* release (minor version) number */
 #define	MAX_CARDS	8		/* max number of adapters */
 
 #ifndef	CONFIG_WANPIPE_CARDS		/* configurable option */
@@ -63,9 +70,11 @@
 #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 *************************************************/
 
+extern void disable_irq(unsigned int);
+extern void enable_irq(unsigned int);
+ 
 /* Module entry points */
 int init_module (void);
 void cleanup_module (void);
@@ -75,13 +84,14 @@
 static int shutdown (wan_device_t* wandev);
 static int ioctl    (wan_device_t* wandev, unsigned cmd, unsigned long arg);
 
-/* IOCTL hanlers */
+/* IOCTL handlers */
 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);
+static void release_hw  (sdla_t *card);
 
 /****** Global Data **********************************************************
  * Note: All data must be explicitly initialized!!!
@@ -90,7 +100,7 @@
 /* private data */
 static char drvname[]	= "wanpipe";
 static char fullname[]	= "WANPIPE(tm) Multiprotocol Driver";
-static char copyright[]	= "(c) 1995-1996 Sangoma Technologies Inc.";
+static char copyright[]	= "(c) 1995-1999 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 */
@@ -104,6 +114,7 @@
 	NULL		/* .data */
 }; 
 
+
 /******* Kernel Loadable Module Entry Points ********************************/
 
 /*============================================================================
@@ -128,24 +139,23 @@
 	int cnt, err = 0;
 
 	printk(KERN_INFO "%s v%u.%u %s\n",
-		fullname, DRV_VERSION, DRV_RELEASE, copyright)
-	;
+		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
-	;
+		return -ENOMEM;
+
 	memset(card_array, 0, sizeof(sdla_t) * ncards);
 
 	/* Register adapters with WAN router */
-	for (cnt = 0; cnt < ncards; ++cnt)
-	{
+	for (cnt = 0; cnt < ncards; ++ cnt) {
 		sdla_t* card = &card_array[cnt];
 		wan_device_t* wandev = &card->wandev;
 
+		card->next = NULL;
 		sprintf(card->devname, "%s%d", drvname, cnt + 1);
 		wandev->magic    = ROUTER_MAGIC;
 		wandev->name     = card->devname;
@@ -155,20 +165,18 @@
 		wandev->shutdown = &shutdown;
 		wandev->ioctl    = &ioctl;
 		err = register_wan_device(wandev);
-		if (err)
-		{
+		if (err) {
 			printk(KERN_ERR
 				"%s: %s registration failed with error %d!\n",
-				drvname, card->devname, err)
-			;
+				drvname, card->devname, err);
 			break;
 		}
 	}
-	if (cnt)
+	if (cnt){
 		ncards = cnt;	/* adjust actual number of cards */
-	else
-	{
+	}else {
 		kfree(card_array);
+		printk(KERN_INFO "IN Init Module: NO Cards registered\n");
 		err = -ENODEV;
 	}
 	return err;
@@ -184,8 +192,7 @@
 {
 	int i;
 
-	for (i = 0; i < ncards; ++i)
-	{
+	for (i = 0; i < ncards; ++i) {
 		sdla_t* card = &card_array[i];
 		unregister_wan_device(card->devname);
 	}
@@ -197,7 +204,7 @@
 /******* WAN Device Driver Entry Points *************************************/
 
 /*============================================================================
- * Setup/confugure WAN link driver.
+ * Setup/configure 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
@@ -217,7 +224,8 @@
 {
 	sdla_t* card;
 	int err = 0;
-	int irq;
+	int irq=0;
+	int i;
 
 	/* Sanity checks */
 	if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL))
@@ -227,80 +235,187 @@
 	if (wandev->state != WAN_UNCONFIGURED)
 		return -EBUSY;		/* already configured */
 
-	if (!conf->data_size || (conf->data == NULL))
-	{
+	printk(KERN_INFO "\nProcessing WAN device %s...\n", wandev->name);
+
+	/* Initialize the counters for each wandev 
+	 * Used for counting number of times new_if and 
+         * del_if get called.
+	 */
+	wandev->del_if_cnt = 0;
+	wandev->new_if_cnt = 0;
+	wandev->config_id  = conf->config_id;
+
+	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
+
+	/* only check I/O port and IRQ if not an S514 adapter */
+	if(!conf->S514_CPU_no[0]) {
+
+                if (conf->ioport <= 0) {
+                        printk(KERN_ERR
 			"%s: can't configure without I/O port address!\n",
 			wandev->name);
-		return -EINVAL;
-	}
+                        return -EINVAL;
+                }
 	
-	if (conf->irq <= 0)
-	{
-		printk(KERN_ERR "%s: can't configure without IRQ!\n",
+                if (conf->irq <= 0) {
+                        printk(KERN_ERR "%s: can't configure without IRQ!\n",
 			wandev->name);
-		return -EINVAL;
-	}
+                        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;
+		/* Check for already loaded card with the same IO port and IRQ 
+		 * If found, copy its hardware configuration and use its
+		 * resources (i.e. piggybacking)
+		 */
+		if (!card->configured){
+			for (i = 0; i < ncards; i ++) {
+				sdla_t *nxt_card = &card_array[i];
+				if (nxt_card->hw.port == conf->ioport && 
+				    nxt_card != card && 
+				    conf->config_id == WANCONFIG_CHDLC &&
+				    nxt_card->wandev.config_id == WANCONFIG_CHDLC){
+					irq = nxt_card->hw.irq;
+					memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t));
+					nxt_card->next = card;
+					card->next = nxt_card;
+					card->wandev.piggyback = WANOPT_YES;
+				}
+			}
+			
+
+			/* Make sure I/O port region is available */
+			if (check_region(conf->ioport, SDLA_MAXIORANGE) && 
+			    !card->wandev.piggyback) {
+				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;
+	/* 
+	For a S514 adapter, check for a possible configuration error in that
+	we are loading an adapter in the same slot as a previously loaded S514
+	card.
+	*/ 
+	else {
+		if (!card->configured){
+			for (i = 0; i < ncards; i ++) {
+				sdla_t* nxt_card = &card_array[i];
+				if(nxt_card == card)
+					continue;
+				if((nxt_card->hw.type == SDLA_S514) &&
+				   (nxt_card->hw.S514_slot_no == conf->PCI_slot_no) &&
+				   (nxt_card->hw.S514_cpu_no[0] == conf->S514_CPU_no[0])&&
+				   (conf->config_id == WANCONFIG_CHDLC)&&
+				   (nxt_card->wandev.config_id == WANCONFIG_CHDLC)){
+
+					irq = nxt_card->hw.irq;
+					memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t));
+					nxt_card->next = card;
+					card->next = nxt_card;
+					card->wandev.piggyback = WANOPT_YES;
+				}
+			}
+		}
 	}
 
-	/* 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;
-	/* Compute the virtual address of the card in kernel space */
-	if(conf->maddr)
-		card->hw.dpmbase = phys_to_virt(conf->maddr);
-	else	/* But 0 means NULL */
-		card->hw.dpmbase = (void *)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;
-	}
+	/* If the current card has already been configured
+         * or its a piggyback card, do not try to allocate
+         * resources.
+	 */
+	if (!card->wandev.piggyback && !card->configured){
+
+		/* Configure hardware, load firmware, etc. */
+		memset(&card->hw, 0, sizeof(sdlahw_t));
+
+		/* for an S514 adapter, pass the CPU number and the slot number read */
+		/* from 'router.conf' to the 'sdla_setup()' function via the 'port' */
+		/* parameter */
+		if (conf->S514_CPU_no[0]){
+
+			card->hw.S514_cpu_no[0] = conf->S514_CPU_no[0];
+			card->hw.S514_slot_no = conf->PCI_slot_no;
+			printk(KERN_INFO "Setting CPU to %c and Slot to %i\n",
+				card->hw.S514_cpu_no[0], card->hw.S514_slot_no);
+
+		}else{
+			/* 508 Card io port and irq initialization */
+			card->hw.port = conf->ioport;
+			card->hw.irq = (conf->irq == 9) ? 2 : conf->irq;
+		}
+
+
+		/* Compute the virtual address of the card in kernel space */
+		if(conf->maddr)
+			card->hw.dpmbase = phys_to_virt(conf->maddr);
+		else	/* But 0 means NULL */
+			card->hw.dpmbase = (void *)conf->maddr;
+
+		card->hw.dpmsize = SDLA_WINDOWSIZE;
+		/* set the adapter type if using an S514 adapter */
+		card->hw.type = (conf->S514_CPU_no[0]) ? SDLA_S514 : conf->hw_opt[0]; 
+		card->hw.pclk = conf->hw_opt[1];
+
+		err = sdla_setup(&card->hw, conf->data, conf->data_size);
+		if (err){
+			return err;
+		}
+
+	        if(card->hw.type != SDLA_S514)
+			irq = (conf->irq == 2) ? 9 : conf->irq; /* IRQ2 -> IRQ9 */
+		else
+			irq = card->hw.irq;
+
+		/* request an interrupt vector - note that interrupts may be shared */
+		/* when using the S514 PCI adapter */
+       		if(request_irq(irq, sdla_isr, 
+		      (card->hw.type == SDLA_S514) ? SA_SHIRQ : 0, wandev->name, card)){
 
-	/* 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;
+			printk(KERN_ERR "%s: Can't reserve IRQ %d!\n", wandev->name, irq);
+			return -EINVAL;
+		}
+
+	}else{
+		printk(KERN_INFO "%s: Card Configured %i or Piggybacking %i!\n",
+			wandev->name,card->configured,card->wandev.piggyback);
+	} 
+
+
+	if (!card->configured){
+
+	#ifdef __SMP__
+		/* Initialize the Spin lock */
+		printk(KERN_INFO "%s: Initializing SMP\n",wandev->name);
+		spin_lock_init(&card->lock);
+	#endif
+		
+		/* Intialize WAN device data space */
+		wandev->irq       = irq;
+		wandev->dma       = 0;
+		if(card->hw.type != SDLA_S514){ 
+			wandev->ioport = card->hw.port;
+		}else{
+			wandev->S514_cpu_no[0] = card->hw.S514_cpu_no[0];
+			wandev->S514_slot_no = card->hw.S514_slot_no;
+		}
+		wandev->maddr     = (unsigned long)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)
-	{
+	switch (card->hw.fwid) {
 #ifdef	CONFIG_WANPIPE_X25
 	case SFID_X25_502:
 	case SFID_X25_508:
@@ -322,22 +437,49 @@
 		break;
 #endif
 
+#ifdef CONFIG_WANPIPE_CHDLC
+	case SFID_CHDLC508:
+	case SFID_CHDLC514:
+//		if (conf->ft1){		
+//			printk(KERN_INFO "%s: Starting FT1 Configurator\n",
+//				card->devname);
+//			err = wpft1_init(card, conf);
+//		}else{
+			err = wpc_init(card, conf);
+//		}
+		break;
+#endif
+
+#ifdef CONFIG_WANPIPE_BSTRM
+	case SFID_BSC502:
+		err = bsc_init(card, conf);
+		break;
+#endif
+
+#ifdef CONFIG_WANPIPE_HDLC
+	case SFID_HDLC508:
+		err = hdlc_init(card, conf);
+		break;
+#endif
+
 	default:
-		printk(KERN_ERR "%s: this firmware is not supported!\n",
-			wandev->name)
-		;
+		printk(KERN_ERR "%s: this firmware is not supported %X %X!\n",
+			wandev->name,card->hw.fwid,SFID_CHDLC508);
 		err = -EINVAL;
 	}
-	if (err)
-	{
-		sdla_down(&card->hw);
-		free_irq(irq, card);
+
+
+	if (err){
+		release_hw(card);
 		return err;
+		
 	}
+
+
   	/* Reserve I/O region and schedule background task */
-/*	printk(KERN_INFO "about to request\n");*/
-	request_region(card->hw.port, card->hw.io_range, wandev->name);
-/*	printk(KERN_INFO "request done\n");*/
+        if(card->hw.type != SDLA_S514 && !card->wandev.piggyback)
+                request_region(card->hw.port, card->hw.io_range, wandev->name);
+
 	if (++active == 1)
 		queue_task(&sdla_tq, &tq_scheduler);
 		
@@ -355,7 +497,7 @@
  */
 static int shutdown (wan_device_t* wandev)
 {
-	sdla_t* card;
+	sdla_t *card;
 
 	/* sanity checks */
 	if ((wandev == NULL) || (wandev->private == NULL))
@@ -364,7 +506,7 @@
 	if (wandev->state == WAN_UNCONFIGURED)
 		return 0;
 		
-	/* If wee are in a critical section we lose */
+	/* If we are in a critical section we lose */
 	if (test_and_set_bit(0, (void*)&wandev->critical))
 		return -EAGAIN;
 		
@@ -373,22 +515,67 @@
 
 	if (--active == 0)
 		schedule();	/* stop background thread */
-	
-/*	printk(KERN_INFO "active now %d\n", active);
 
-	printk(KERN_INFO "About to call sdla_down\n");*/
-	sdla_down(&card->hw);
-/*	printk(KERN_INFO "sdla_down done\n");
-	printk(KERN_INFO "About to call free_irq\n");*/
-	free_irq(wandev->irq, card);
-/*	printk(KERN_INFO "free_irq done\n");
-	printk(KERN_INFO "About to call release_region\n");*/
-	release_region(card->hw.port, card->hw.io_range);
-/*	printk(KERN_INFO "release_region done\n");*/
+	/* Release Resources */
+	release_hw(card);
+
+        /* only free the allocated I/O range if not an S514 adapter */
+	if (wandev->hw_opt[0] != SDLA_S514 && !card->configured){
+              	release_region(card->hw.port, card->hw.io_range);
+	}
+
+	if (!card->configured){
+		memset(&card->hw, 0, sizeof(sdlahw_t));
+	      	if (card->next){
+			memset(&card->next->hw, 0, sizeof(sdlahw_t));
+		}
+	}
+
 	wandev->critical = 0;
 	return 0;
 }
 
+static void release_hw (sdla_t *card)
+{
+	sdla_t *nxt_card;
+
+	/* Check if next device exists */
+	if (card->next){
+		nxt_card = card->next;
+		/* If next device is down then release resources */
+		if (nxt_card->wandev.state == WAN_UNCONFIGURED){
+			if (card->wandev.piggyback){
+				/* If this device is piggyback then use
+                                 * information of the master device 
+				 */
+				printk(KERN_INFO "%s: Piggyback shutting down\n",card->devname);
+				sdla_down(&card->next->hw);
+       				free_irq(card->wandev.irq, card->next);
+				card->configured = 0;
+				card->next->configured = 0;
+				card->wandev.piggyback = 0;
+			}else{
+				/* Master device shutting down */
+				printk(KERN_INFO "%s: Master shutting down\n",card->devname);
+				sdla_down(&card->hw);
+				free_irq(card->wandev.irq, card);
+				card->configured = 0;
+				card->next->configured = 0;
+			}
+		}else{
+			printk(KERN_INFO "%s: Device still running\n",
+				nxt_card->devname);
+			card->configured = 1;
+		}
+	}else{
+		printk(KERN_INFO "%s: Master shutting down\n",card->devname);
+		sdla_down(&card->hw);
+       		free_irq(card->wandev.irq, card);
+		card->configured = 0;
+	}
+}
+
+
 /*============================================================================
  * Driver I/O control. 
  * o verify arguments
@@ -399,20 +586,29 @@
  */
 static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg)
 {
+	sdla_t* card;
 	int err;
 
 	/* sanity checks */
 	if ((wandev == NULL) || (wandev->private == NULL))
-		return -EFAULT
-	;
+		return -EFAULT;
 	if (wandev->state == WAN_UNCONFIGURED)
-		return -ENODEV
-	;
-	if (test_and_set_bit(0, (void*)&wandev->critical))
-		return -EAGAIN
-	;
-	switch (cmd)
-	{
+		return -ENODEV;
+
+	card = wandev->private;
+
+	if(card->hw.type != SDLA_S514){
+		disable_irq(card->hw.irq);
+	}
+
+	if (test_and_set_bit(0, (void*)&wandev->critical)) {
+		if(card->hw.type != SDLA_S514){
+			enable_irq(card->hw.irq);
+		}
+		return -EAGAIN;
+	}
+	
+	switch (cmd) {
 	case WANPIPE_DUMP:
 		err = ioctl_dump(wandev->private, (void*)arg);
 		break;
@@ -424,11 +620,16 @@
 	default:
 		err = -EINVAL;
 	}
-	wandev->critical = 0;
+ 
+	clear_bit(0, (void*)&wandev->critical);
+        if(card->hw.type != SDLA_S514){
+		enable_irq(card->hw.irq);
+	}
+ 
 	return err;
 }
 
-/****** Driver IOCTL Hanlers ************************************************/
+/****** Driver IOCTL Handlers ***********************************************/
 
 /*============================================================================
  * Dump adapter memory to user buffer.
@@ -455,34 +656,47 @@
 	if ((dump.magic != WANPIPE_MAGIC) ||
 	    (dump.offset + dump.length > card->hw.memory))
 		return -EINVAL;
-		
+	
 	winsize = card->hw.dpmsize;
 	save_flags(flags);
         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;
-		}
+
+	if(card->hw.type != SDLA_S514) {
+                oldvec = card->hw.vector;
+                while (dump.length) {
+			/* current offset */				
+                        unsigned pos = dump.offset % winsize;
+			/* current vector */
+                        unsigned long vec = dump.offset - pos;
+                        unsigned len = (dump.length > (winsize - pos)) ?
+                        	(winsize - pos) : dump.length;
+			/* relocate window */
+                        if (sdla_mapmem(&card->hw, vec) != 0) {
+                                err = -EIO;
+                                break;
+                        }
+                        /* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */
+                        sti();  /* Not ideal but tough we have to do this */
+                        if(copy_to_user((void *)dump.ptr,
+                                (u8 *)card->hw.dpmbase + pos, len)) 
+                                return -EFAULT;
+                        cli();
+                        dump.length     -= len;
+                        dump.offset     += len;
+                        (char*)dump.ptr += len;
+                }
+                sdla_mapmem(&card->hw, oldvec);/* restore DPM window position */
+        }
+	
+	else {
 		/* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */
-		sti();	/* Not ideal but tough we have to do this */
-		if(copy_to_user((void *)dump.ptr,
-			(u8 *)card->hw.dpmbase + pos, len))	
-			return -EFAULT;
-		cli();
-		dump.length     -= len;
-		dump.offset     += len;
-		(char*)dump.ptr += len;
+                sti();  /* Not ideal but tough we have to do this */
+               if(copy_to_user((void *)dump.ptr,
+	                (u8 *)card->hw.dpmbase + dump.offset, dump.length))
+                	return -EFAULT;
+               cli();
 	}
-	sdla_mapmem(&card->hw, oldvec);	/* restore DPM window position */
+
 	restore_flags(flags);		/* >>> critical section end <<< */
 	return err;
 }
@@ -499,9 +713,10 @@
 
 	if (card->exec == NULL)
 		return -ENODEV;
-		
+	
 	if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t)))
 		return -EFAULT;
+
 	if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL))
 		return -EINVAL;
 	return card->exec(card, exec.cmd, exec.data);
@@ -518,21 +733,110 @@
 {
 #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;
+	if(card->hw.type == SDLA_S514) {	/* handle interrrupt on S514 */
+                u32 int_status;
+                unsigned char CPU_no = card->hw.S514_cpu_no[0];
+                unsigned char card_found_for_IRQ;
+		u8 IRQ_count = 0;
+
+		for(;;) {
+
+			read_S514_int_stat(&card->hw, &int_status);
+
+			/* check if the interrupt is for this device */
+ 			if(!((unsigned char)int_status &
+				(IRQ_CPU_A | IRQ_CPU_B)))
+                	        return;
+
+			/* if the IRQ is for both CPUs on the same adapter, */
+			/* then alter the interrupt status so as to handle */
+			/* one CPU at a time */
+			if(((unsigned char)int_status & (IRQ_CPU_A | IRQ_CPU_B))
+				== (IRQ_CPU_A | IRQ_CPU_B)) {
+				int_status &= (CPU_no == S514_CPU_A) ?
+					~IRQ_CPU_B : ~IRQ_CPU_A;
+			}
+ 
+			card_found_for_IRQ = 0;
+
+	             	/* check to see that the CPU number for this device */
+			/* corresponds to the interrupt status read */
+                	switch (CPU_no) {
+                        	case S514_CPU_A:
+                                	if((unsigned char)int_status &
+						IRQ_CPU_A)
+                                        card_found_for_IRQ = 1;
+                                break;
+
+	                        case S514_CPU_B:
+        	                        if((unsigned char)int_status &
+						IRQ_CPU_B)
+                                        card_found_for_IRQ = 1;
+                                break;
+                	}
+
+			/* exit if the interrupt is for another CPU on the */
+			/* same IRQ */
+			if(!card_found_for_IRQ)
+				return;
+
+       	 		if (!card || 
+			   (card->wandev.state == WAN_UNCONFIGURED && !card->configured)){
+					printk(KERN_INFO
+						"Received IRQ %d for CPU #%c\n",
+						irq, CPU_no);
+					printk(KERN_INFO
+						"IRQ for unconfigured adapter\n");
+					S514_intack(&card->hw, int_status);
+					return;
+       			}
+
+	        	if (card->in_isr) {
+        	       		printk(KERN_INFO
+					"%s: interrupt re-entrancy on IRQ %d\n",
+                       			card->devname, card->wandev.irq);
+				S514_intack(&card->hw, int_status);
+ 				return;
+       			}
+
+	               	S514_intack(&card->hw, int_status);
+ 
+       			if (card->isr)
+				card->isr(card);
+
+			/* handle a maximum of two interrupts (one for each */
+			/* CPU on the adapter) before returning */  
+			if((++ IRQ_count) == 2)
+				return;
+		}
 	}
 
-	sdla_intack(&card->hw);
-	if (card->isr) 
-		card->isr(card);
+	else {			/* handle interrupt on S508 adapter */
+
+		if (!card || ((card->wandev.state == WAN_UNCONFIGURED) && !card->configured))
+			return;
 
+		if (card->in_isr) {
+			printk(KERN_INFO
+				"%s: interrupt re-entrancy on IRQ %d!\n",
+				card->devname, card->wandev.irq);
+			return;
+		}
+
+		/* Use spin lock only for S508 */
+
+#ifdef __SMP__
+		spin_lock(&card->lock);
+#endif
+		sdla_intack(&card->hw);
+		if (card->isr)
+			card->isr(card);
+#ifdef __SMP__
+		spin_unlock(&card->lock);
+#endif
+
+	}
+                
 #undef	card
 }
 
@@ -547,13 +851,11 @@
 {
 	int i;
 
-	for (i = 0; i < ncards; ++i)
-	{
+	for (i = 0; i < ncards; ++i) {
 		sdla_t* card = &card_array[i];
 
 		if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll &&
-		    !card->wandev.critical)
-		{
+			!card->wandev.critical) {
 			card->poll(card);
 		}
 	}
@@ -594,26 +896,21 @@
 
 	save_flags(flags);
 	cli();
-	if (card->wandev.state != state)
-	{
-		switch (state)
-		{
+	if (card->wandev.state != state) {
+		switch (state) {
 		case WAN_CONNECTED:
 			printk (KERN_INFO "%s: link connected!\n",
-				card->devname)
-			;
+				card->devname);
 			break;
 
 		case WAN_CONNECTING:
 			printk (KERN_INFO "%s: link connecting...\n",
-				card->devname)
-			;
+				card->devname);
 			break;
 
 		case WAN_DISCONNECTED:
 			printk (KERN_INFO "%s: link disconnected!\n",
-				card->devname)
-			;
+				card->devname);
 			break;
 		}
 		card->wandev.state = state;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/shaper.c linux.14p16/drivers/net/shaper.c
--- linux.vanilla/drivers/net/shaper.c	Sat Aug 14 02:27:29 1999
+++ linux.14p16/drivers/net/shaper.c	Thu Dec  9 15:33:30 1999
@@ -557,6 +557,13 @@
 {
 	struct shaperconf *ss= (struct shaperconf *)&ifr->ifr_data;
 	struct shaper *sh=dev->priv;
+	
+	if(ss->ss_cmd == SHAPER_SET_DEV || ss->ss_cmd == SHAPER_SET_SPEED)
+	{
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+	}
+	
 	switch(ss->ss_cmd)
 	{
 		case SHAPER_SET_DEV:
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sis900.c linux.14p16/drivers/net/sis900.c
--- linux.vanilla/drivers/net/sis900.c	Wed Oct 20 01:12:39 1999
+++ linux.14p16/drivers/net/sis900.c	Thu Dec  9 15:33:32 1999
@@ -1,58 +1,29 @@
-/*****************************************************************************/
-/*      sis900.c: A SiS 900 PCI Fast Ethernet driver for Linux.              */
-/*                                                                           */
-/*                Silicon Integrated System Corporation                      */ 
-/*                Revision:	1.05	Aug 7 1999                           */
-/*                                                                           */
-/*****************************************************************************/
-
-/*                                                                            
-      Modified from the driver which is originally written by Donald Becker. 
-
-      This software may be used and distributed according to the terms
-      of the GNU Public License (GPL), incorporated herein by reference.
-      Drivers based on this skeleton fall under the GPL and must retain
-      the authorship (implicit copyright) notice.
-
-      The author may be reached as becker@tidalwave.net, or
-      Donald Becker
-      312 Severn Ave. #W302
-      Annapolis MD 21403
-
-      Support and updates [to the original skeleton] available at
-      http://www.tidalwave.net/~becker/pci-skeleton.html
+/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
+   Silicon Integrated System Corporation 
+   Revision:	1.05	Aug 7 1999
+   
+   Modified from the driver which is originally written by Donald Becker. 
+   
+   This software may be used and distributed according to the terms
+   of the GNU Public License (GPL), incorporated herein by reference.
+   Drivers based on this skeleton fall under the GPL and must retain
+   the authorship (implicit copyright) notice.
+   
+   References:
+   SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
+   preliminary Rev. 1.0 Jan. 14, 1998
+   SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support,
+   preliminary Rev. 1.0 Nov. 10, 1998
+   SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
+   preliminary Rev. 1.0 Jan. 18, 1998
+   http://www.sis.com.tw/support/databook.htm
+   
+   Rev 1.06 Nov. 4 1999 Ollie Lho (ollie@sis.com.tw) Second release
+   Rev 1.05.05 Oct. 29 1999 Ollie Lho (ollie@sis.com.tw) Single buffer Tx/Rx  
+   Chin-Shan Li (lcs@sis.com.tw) Added AMD Am79c901 HomePNA PHY support
+   Rev 1.05 Aug. 7 1999 Jim Huang (cmhuang@sis.com.tw) Initial release
 */
 
-static const char *version =
-"sis900.c:v1.05  8/07/99\n";
-
-static int max_interrupt_work = 20;
-#define sis900_debug debug
-static int sis900_debug = 0;
-
-static int multicast_filter_limit = 128;
-
-#define MAX_UNITS 8             /* More are supported, limit only on options */
-static int speeds[MAX_UNITS] = {100, 100, 100, 100, 100, 100, 100, 100};
-static int full_duplex[MAX_UNITS] = {1, 1, 1, 1, 1, 1, 1, 1};
-
-#define TX_BUF_SIZE     1536
-#define RX_BUF_SIZE     1536
-
-#define TX_DMA_BURST    0
-#define RX_DMA_BURST    0
-#define TX_FIFO_THRESH  16
-#define TxDRNT_100      (1536>>5)
-#define TxDRNT_10       16 
-#define RxDRNT_100      8
-#define RxDRNT_10       8 
-#define TRUE            1
-#define FALSE           0
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (4*HZ)
-
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/kernel.h>
@@ -65,680 +36,320 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/netdevice.h>
+
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <asm/processor.h>      /* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
-
-#define RUN_AT(x) (jiffies + (x))
-
 #include <linux/delay.h>
 
-#if LINUX_VERSION_CODE < 0x20123
-#define test_and_set_bit(val, addr) set_bit(val, addr)
-#endif
-#if LINUX_VERSION_CODE <= 0x20139
-#define net_device_stats enet_statistics
-#else
-#define NETSTATS_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20155  ||  defined(CARDBUS)
-/* Grrrr, the PCI code changed, but did not consider CardBus... */
-#include <linux/bios32.h>
-#define PCI_SUPPORT_VER1
-#else
-#define PCI_SUPPORT_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20159
-#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
-#else
-#define dev_free_skb(skb) dev_kfree_skb(skb);
-#endif
+#include "sis900.h"
 
-/* The I/O extent. */
-#define SIS900_TOTAL_SIZE 0x100
+static const char *version =
+"sis900.c: v1.06  11/04/99\n";
 
-/* This table drives the PCI probe routines.  It's mostly boilerplate in all
-   of the drivers, and will likely be provided by some future kernel.
-   Note the matching code -- the first table entry matchs all 56** cards but
-   second only the 1234 card.
-*/
+static int max_interrupt_work = 20;
+#define sis900_debug debug
+static int sis900_debug = 0;
 
-enum pci_flags_bit {
-        PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-};
+static int multicast_filter_limit = 128;
 
-struct pci_id_info {
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (4*HZ)
+
+struct mac_chip_info {
         const char *name;
-        u16     vendor_id, device_id, device_id_mask, flags;
-        int io_size;
-        struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev,
-                         long ioaddr, int irq, int chip_idx, int fnd_cnt);
+        u16 	vendor_id, device_id, flags;
+        int 	io_size;
+        struct device *(*probe) (struct mac_chip_info *mac, struct pci_dev * pci_dev, 
+				 struct device * net_dev);
 };
+static struct device * sis900_mac_probe (struct mac_chip_info * mac, struct pci_dev * pci_dev,
+					 struct device * net_dev);
 
-static struct device * sis900_probe1(int pci_bus, int pci_devfn,
-                                  struct device *dev, long ioaddr,
-                                  int irq, int chp_idx, int fnd_cnt);
-
-static struct pci_id_info pci_tbl[] =
-{{ "SiS 900 PCI Fast Ethernet",
-   0x1039, 0x0900, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x100, sis900_probe1},
-  { "SiS 7016 PCI Fast Ethernet",
-   0x1039, 0x7016, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x100, sis900_probe1},
- {0,},                                          /* 0 terminated list. */
+static struct mac_chip_info  mac_chip_table[] = {
+	{ "SiS 900 PCI Fast Ethernet", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_900,
+	  PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE, sis900_mac_probe},
+	{ "SiS 7016 PCI Fast Ethernet",PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016,
+	  PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE, sis900_mac_probe},
+	{0,},                                          /* 0 terminated list. */
 };
 
-/* The capability table matches the chip table above. */
-enum {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02, HAS_LNK_CHNG=0x04};
-static int sis_cap_tbl[] = {
-        HAS_MII_XCVR|HAS_CHIP_XCVR|HAS_LNK_CHNG,
-        HAS_MII_XCVR|HAS_CHIP_XCVR|HAS_LNK_CHNG,
+static void sis900_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex);
+static void amd79c901_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex);
+
+static struct mii_chip_info {
+	const char * name;
+	u16 phy_id0;
+	u16 phy_id1;
+	void (*read_mode) (struct device *net_dev, int phy_addr, int *speed, int *duplex);
+} mii_chip_table[] = {
+	{"SiS 900 Internal MII PHY", 0x001d, 0x8000, sis900_read_mode},
+	{"SiS 7014 Physical Layer Solution", 0x0016, 0xf830,sis900_read_mode},
+	{"AMD 79C901 10BASE-T PHY",  0x0000, 0x35b9, amd79c901_read_mode},
+	{"AMD 79C901 HomePNA PHY",   0x0000, 0x35c8, amd79c901_read_mode},
+	{0,},
 };
 
-/* The rest of these values should never change. */
-#define NUM_TX_DESC     16      /* Number of Tx descriptor registers. */
-#define NUM_RX_DESC     8       /* Number of Rx descriptor registers. */
-
-/* Symbolic offsets to registers. */
-enum SIS900_registers {
-        cr=0x0,                 //Command Register
-        cfg=0x4,                //Configuration Register
-        mear=0x8,               //EEPROM Access Register
-        ptscr=0xc,              //PCI Test Control Register
-        isr=0x10,               //Interrupt Status Register
-        imr=0x14,               //Interrupt Mask Register
-        ier=0x18,               //Interrupt Enable Register
-        epar=0x18,              //Enhanced PHY Access Register
-        txdp=0x20,              //Transmit Descriptor Pointer Register
-        txcfg=0x24,             //Transmit Configuration Register
-        rxdp=0x30,              //Receive Descriptor Pointer Register
-        rxcfg=0x34,             //Receive Configuration Register
-        flctrl=0x38,            //Flow Control Register
-        rxlen=0x3c,             //Receive Packet Length Register
-        rfcr=0x48,              //Receive Filter Control Register
-        rfdr=0x4C,              //Receive Filter Data Register
-        pmctrl=0xB0,            //Power Management Control Register
-        pmer=0xB4               //Power Management Wake-up Event Register
+struct mii_phy {
+	struct mii_phy * next;
+	struct mii_chip_info * chip_info;
+	int phy_addr;
+	u16 status;
 };
 
-#define RESET           0x00000100
-#define SWI             0x00000080
-#define RxRESET         0x00000020
-#define TxRESET         0x00000010
-#define RxDIS           0x00000008
-#define RxENA           0x00000004
-#define TxDIS           0x00000002
-#define TxENA           0x00000001
-
-#define BISE            0x80000000
-#define EUPHCOM         0x00000100
-#define REQALG          0x00000080
-#define SB              0x00000040
-#define POW             0x00000020
-#define EXD             0x00000010
-#define PESEL           0x00000008
-#define LPM             0x00000004
-#define BEM             0x00000001
-
-/* Interrupt register bits, using my own meaningful names. */
-#define WKEVT           0x10000000
-#define TxPAUSEEND      0x08000000
-#define TxPAUSE         0x04000000
-#define TxRCMP          0x02000000
-#define RxRCMP          0x01000000
-#define DPERR           0x00800000
-#define SSERR           0x00400000
-#define RMABT           0x00200000
-#define RTABT           0x00100000
-#define RxSOVR          0x00010000
-#define HIBERR          0x00008000
-#define SWINT           0x00001000
-#define MIBINT          0x00000800
-#define TxURN           0x00000400
-#define TxIDLE          0x00000200
-#define TxERR           0x00000100
-#define TxDESC          0x00000080
-#define TxOK            0x00000040
-#define RxORN           0x00000020
-#define RxIDLE          0x00000010
-#define RxEARLY         0x00000008
-#define RxERR           0x00000004
-#define RxDESC          0x00000002
-#define RxOK            0x00000001
-
-#define IE              0x00000001
-
-#define TxCSI           0x80000000
-#define TxHBI           0x40000000
-#define TxMLB           0x20000000
-#define TxATP           0x10000000
-#define TxIFG           0x0C000000
-#define TxMXF           0x03800000
-#define TxMXF_shift     0x23
-#define TxMXDMA         0x00700000
-#define TxMXDMA_shift   20
-#define TxRTCNT         0x000F0000
-#define TxRTCNT_shift   16
-#define TxFILLT         0x00007F00
-#define TxFILLT_shift   8
-#define TxDRNT          0x0000007F
-
-#define RxAEP           0x80000000
-#define RxARP           0x40000000
-#define RxATP           0x10000000
-#define RxAJAB          0x08000000
-#define RxMXF           0x03800000
-#define RxMXF_shift     23
-#define RxMXDMA         0x00700000
-#define RxMXDMA_shift   20
-#define RxDRNT          0x0000007F
-
-#define RFEN            0x80000000
-#define RFAAB           0x40000000
-#define RFAAM           0x20000000
-#define RFAAP           0x10000000
-#define RFPromiscuous   (RFAAB|RFAAM|RFAAP)
-#define RFAA_shift      28
-#define RFEP            0x00070000
-#define RFEP_shift      16
-
-#define RFDAT           0x0000FFFF
-
-#define OWN             0x80000000
-#define MORE            0x40000000
-#define INTR            0x20000000
-#define OK              0x08000000
-#define DSIZE           0x00000FFF
-
-#define SUPCRC          0x10000000
-#define ABORT           0x04000000
-#define UNDERRUN        0x02000000
-#define NOCARRIER       0x01000000
-#define DEFERD          0x00800000
-#define EXCDEFER        0x00400000
-#define OWCOLL          0x00200000
-#define EXCCOLL         0x00100000
-#define COLCNT          0x000F0000
-
-#define INCCRC          0x10000000
-//      ABORT           0x04000000
-#define OVERRUN         0x02000000
-#define DEST            0x01800000
-#define BCAST           0x01800000
-#define MCAST           0x01000000
-#define UNIMATCH        0x00800000
-#define TOOLONG         0x00400000
-#define RUNT            0x00200000
-#define RXISERR         0x00100000
-#define CRCERR          0x00080000
-#define FAERR           0x00040000
-#define LOOPBK          0x00020000
-#define RXCOL           0x00010000
-
-#define EuphLiteEEMACAddr               0x08
-#define EuphLiteEEVendorID              0x02
-#define EuphLiteEEDeviceID              0x03
-#define EuphLiteEECardTypeRev           0x0b
-#define EuphLiteEEPlexusRev             0x0c
-#define EuphLiteEEChecksum              0x0f
-
-#define RXSTS_shift     18
-#define OWN             0x80000000
-#define MORE            0x40000000
-#define INTR            0x20000000
-#define OK              0x08000000
-#define DSIZE           0x00000FFF
-/* MII register offsets */
-#define MII_CONTROL             0x0000
-#define MII_STATUS              0x0001
-#define MII_PHY_ID0             0x0002
-#define MII_PHY_ID1             0x0003
-#define MII_ANAR                0x0004
-#define MII_ANLPAR              0x0005
-#define MII_ANER                0x0006
-/* MII Control register bit definitions. */
-#define MIICNTL_FDX             0x0100
-#define MIICNTL_RST_AUTO        0x0200
-#define MIICNTL_ISOLATE         0x0400
-#define MIICNTL_PWRDWN          0x0800
-#define MIICNTL_AUTO            0x1000
-#define MIICNTL_SPEED           0x2000
-#define MIICNTL_LPBK            0x4000
-#define MIICNTL_RESET           0x8000
-/* MII Status register bit significance. */
-#define MIISTAT_EXT             0x0001
-#define MIISTAT_JAB             0x0002
-#define MIISTAT_LINK            0x0004
-#define MIISTAT_CAN_AUTO        0x0008
-#define MIISTAT_FAULT           0x0010
-#define MIISTAT_AUTO_DONE       0x0020
-#define MIISTAT_CAN_T           0x0800
-#define MIISTAT_CAN_T_FDX       0x1000
-#define MIISTAT_CAN_TX          0x2000
-#define MIISTAT_CAN_TX_FDX      0x4000
-#define MIISTAT_CAN_T4          0x8000
-/* MII NWAY Register Bits ...
-** valid for the ANAR (Auto-Negotiation Advertisement) and
-** ANLPAR (Auto-Negotiation Link Partner) registers */
-#define MII_NWAY_NODE_SEL       0x001f
-#define MII_NWAY_CSMA_CD        0x0001
-#define MII_NWAY_T              0x0020
-#define MII_NWAY_T_FDX          0x0040
-#define MII_NWAY_TX             0x0080
-#define MII_NWAY_TX_FDX         0x0100
-#define MII_NWAY_T4             0x0200
-#define MII_NWAY_RF             0x2000
-#define MII_NWAY_ACK            0x4000
-#define MII_NWAY_NP             0x8000
-
-/* MII Auto-Negotiation Expansion Register Bits */
-#define MII_ANER_PDF            0x0010
-#define MII_ANER_LP_NP_ABLE     0x0008
-#define MII_ANER_NP_ABLE        0x0004
-#define MII_ANER_RX_PAGE        0x0002
-#define MII_ANER_LP_AN_ABLE     0x0001
-#define HALF_DUPLEX                     1
-#define FDX_CAPABLE_DUPLEX_UNKNOWN      2
-#define FDX_CAPABLE_HALF_SELECTED       3
-#define FDX_CAPABLE_FULL_SELECTED       4
-#define HW_SPEED_UNCONFIG       0
-#define HW_SPEED_10_MBPS        10
-#define HW_SPEED_100_MBPS       100
-#define HW_SPEED_DEFAULT        (HW_SPEED_10_MBPS)
-
-#define ACCEPT_ALL_PHYS         0x01
-#define ACCEPT_ALL_MCASTS       0x02
-#define ACCEPT_ALL_BCASTS       0x04
-#define ACCEPT_ALL_ERRORS       0x08
-#define ACCEPT_CAM_QUALIFIED    0x10
-#define MAC_LOOPBACK            0x20
-//#define FDX_CAPABLE_FULL_SELECTED     4
-#define CRC_SIZE                4
-#define MAC_HEADER_SIZE         14
-
-typedef struct _EuphLiteDesc {
-        u32     llink;
-        unsigned char*  buf;
-        u32     physAddr;
-        /* Hardware sees the physical address of descriptor */
-        u32     plink;
+typedef struct _BufferDesc {
+        u32     link;
         u32     cmdsts;
-        u32     bufPhys;
-} EuphLiteDesc;
+        u32     bufptr;
+} BufferDesc;
 
 struct sis900_private {
-        char devname[8];                /* Used only for kernel debugging. */
-        const char *product_name;
         struct device *next_module;
-        int chip_id;
-        int chip_revision;
-        unsigned char pci_bus, pci_devfn;
-#if LINUX_VERSION_CODE > 0x20139
         struct net_device_stats stats;
-#else
-        struct enet_statistics stats;
-#endif
-        struct timer_list timer;        /* Media selection timer. */
-        unsigned int cur_rx;    /* Index into the Rx buffer of next Rx pkt. */
-        unsigned int cur_tx, dirty_tx, tx_flag;
-
-        /* The saved address of a sent-in-place packet/buffer, for skfree(). */
-        struct sk_buff* tx_skbuff[NUM_TX_DESC];
-        EuphLiteDesc tx_buf[NUM_TX_DESC];       /* Tx bounce buffers */
-        EuphLiteDesc rx_buf[NUM_RX_DESC];
-        unsigned char *rx_bufs;
-        unsigned char *tx_bufs;                 /* Tx bounce buffer region. */
-        char phys[4];                           /* MII device addresses.    */
-        int phy_idx;                            /* Support Max 4 PHY        */
-        u16 pmd_status;
-        unsigned int tx_full;                   /* The Tx queue is full.    */
-	int MediaSpeed;                         /* user force speed         */
-	int MediaDuplex;                        /* user force duplex        */
-        int full_duplex;                        /* Full/Half-duplex.        */
-        int speeds;                             /* 100/10 Mbps.             */
-        u16 LinkOn;
-        u16 LinkChange;
+	struct pci_dev * pci_dev;
+
+	struct mac_chip_info * mac;
+	struct mii_phy * mii;
+	unsigned int cur_phy;
+
+        struct timer_list timer;        		/* Link status detection timer. */
+        unsigned int cur_rx, dirty_rx;		
+        unsigned int cur_tx, dirty_tx;
+
+        /* The saved address of a sent/receive-in-place packet buffer */
+        struct sk_buff *tx_skbuff[NUM_TX_DESC];
+	struct sk_buff *rx_skbuff[NUM_RX_DESC];
+	BufferDesc tx_ring[NUM_TX_DESC];	
+        BufferDesc rx_ring[NUM_RX_DESC];
+        unsigned int tx_full;			/* The Tx queue is full.    */
+
+        int LinkOn;
 };
 
 #ifdef MODULE
 #if LINUX_VERSION_CODE > 0x20115
 MODULE_AUTHOR("Jim Huang <cmhuang@sis.com.tw>");
 MODULE_DESCRIPTION("SiS 900 PCI Fast Ethernet driver");
-MODULE_PARM(speeds, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(multicast_filter_limit, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(debug, "i");
 #endif
 #endif
 
-static int sis900_open(struct device *dev);
+static int sis900_open(struct device *net_dev);
+static int sis900_mii_probe (struct device * net_dev);
+static void sis900_init_rxfilter (struct device * net_dev);
 static u16 read_eeprom(long ioaddr, int location);
-static int mdio_read(struct device *dev, int phy_id, int location);
-static void mdio_write(struct device *dev, int phy_id, int location, int val);
+static u16 mdio_read(struct device *net_dev, int phy_id, int location);
+static void mdio_write(struct device *net_dev, int phy_id, int location, int val);
 static void sis900_timer(unsigned long data);
-static void sis900_tx_timeout(struct device *dev);
-static void sis900_init_ring(struct device *dev);
-static int sis900_start_xmit(struct sk_buff *skb, struct device *dev);
-static int sis900_rx(struct device *dev);
+static void sis900_check_mode (struct device *net_dev, struct mii_phy *mii_phy);
+static void sis900_tx_timeout(struct device *net_dev);
+static void sis900_init_tx_ring(struct device *net_dev);
+static void sis900_init_rx_ring(struct device *net_dev);
+static int sis900_start_xmit(struct sk_buff *skb, struct device *net_dev);
+static int sis900_rx(struct device *net_dev);
+static void sis900_finish_xmit (struct device *net_dev);
 static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-static int sis900_close(struct device *dev);
-static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd);
-static struct enet_statistics *sis900_get_stats(struct device *dev);
-static void set_rx_mode(struct device *dev);
-static void sis900_reset(struct device *dev);
-static u16 elAutoNegotiate(struct device *dev, int phy_id, int *duplex, int *speed);
-static void elSetCapability(struct device *dev, int phy_id, int duplex, int speed);
-static u16 elPMDreadMode(struct device *dev, int phy_id, int *speed, int *duplex);
-static u16 elMIIpollBit(struct device *dev, int phy_id, int location, u16 mask, u16 polarity, u16 *value);
-static void elSetMediaType(struct device *dev, int speed, int duplex);
+static int sis900_close(struct device *net_dev);
+static int mii_ioctl(struct device *net_dev, struct ifreq *rq, int cmd);
+static struct enet_statistics *sis900_get_stats(struct device *net_dev);
+static u16 sis900_compute_hashtable_index(u8 *addr);
+static void set_rx_mode(struct device *net_dev);
+static void sis900_reset(struct device *net_dev);
 
 /* A list of all installed SiS900 devices, for removing the driver module. */
 static struct device *root_sis900_dev = NULL;
 
-/* Ideally we would detect all network cards in slot order.  That would
-   be best done a central PCI probe dispatch, which wouldn't work
-   well when dynamically adding drivers.  So instead we detect just the
-   SiS 900 cards in slot order. */
-
-int sis900_probe(struct device *dev)
-{
-        int cards_found = 0;
-        int pci_index = 0;
-        unsigned char pci_bus, pci_device_fn;
-
-        if ( ! pcibios_present())
-                return -ENODEV;
-
-        for (;pci_index < 0xff; pci_index++) {
-                u16 vendor, device, pci_command, new_command;
-                int chip_idx, irq;
-                long ioaddr;
-
-                if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
-                                                pci_index,
-                                                &pci_bus, &pci_device_fn)
-                                != PCIBIOS_SUCCESSFUL) {
-                        break;
-                }
-                pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID,
-                                                        &vendor);
-                pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID,
-                                                        &device);
-
-                for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-                        if (vendor == pci_tbl[chip_idx].vendor_id &&
-                                (device & pci_tbl[chip_idx].device_id_mask) ==
-                                pci_tbl[chip_idx].device_id)
-                                break;
-                if (pci_tbl[chip_idx].vendor_id == 0)   /* Compiled out! */
-                        continue;
-
-        {
-#if defined(PCI_SUPPORT_VER2)
-                struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-                ioaddr = pdev->base_address[0] & ~3;
-                irq = pdev->irq;
-#else
-                u32 pci_ioaddr;
-                u8 pci_irq_line;
-                pcibios_read_config_byte(pci_bus, pci_device_fn,
-                                         PCI_INTERRUPT_LINE, &pci_irq_line);
-                pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                         PCI_BASE_ADDRESS_0, &pci_ioaddr);
-                ioaddr = pci_ioaddr & ~3;
-                irq = pci_irq_line;
-#endif
-        }
+/* walk through every ethernet PCI devices to see if some of them are matched with our card list*/
+int sis900_probe (struct device * net_dev)
+{
+	int found = 0;
+	struct pci_dev * pci_dev = NULL;
+		
+	if (!pci_present())
+		return -ENODEV;
+		
+	while ((pci_dev = pci_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_dev)) != NULL) {
+		/* pci_dev contains all ethernet devices */
+		u32 pci_io_base;
+		struct mac_chip_info * mac;
+
+		for (mac = mac_chip_table; mac->vendor_id; mac++) {
+			/* try to match our card list */
+			if (pci_dev->vendor == mac->vendor_id &&
+			    pci_dev->device == mac->device_id)
+				break;
+		}
+		
+		if (mac->vendor_id == 0)
+			/* pci_dev does not match any of our cards */
+			continue;
+		
+		/* now, pci_dev should be either 900 or 7016 */
+		pci_io_base = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+		if ((mac->flags & PCI_COMMAND_IO ) && 
+		    check_region(pci_io_base, mac->io_size))
+			continue;
+		
+		/* setup various bits in PCI command register */
+		pci_set_master(pci_dev);
+
+		/* do the real low level jobs */
+		net_dev = mac->probe(mac, pci_dev, net_dev);
+		
+		if (net_dev != NULL) {
+			found++;
+		}
+		net_dev = NULL;
+	}
+	return found ? 0 : -ENODEV;
+}
 
-                if ((pci_tbl[chip_idx].flags & PCI_USES_IO) &&
-                        check_region(ioaddr, pci_tbl[chip_idx].io_size))
-                        continue;
-
-                /* Activate the card: fix for brain-damaged Win98 BIOSes. */
-                pcibios_read_config_word(pci_bus, pci_device_fn,
-                                         PCI_COMMAND, &pci_command);
-                new_command = pci_command | (pci_tbl[chip_idx].flags & 7);
-                if (pci_command != new_command) {
-                        printk(KERN_INFO "  The PCI BIOS has not enabled the"
-                                   " device at %d/%d!"
-                                   "Updating PCI command %4.4x->%4.4x.\n",
-                                        pci_bus, pci_device_fn,
-                                        pci_command, new_command);
+static struct device * sis900_mac_probe (struct mac_chip_info * mac, struct pci_dev * pci_dev, 
+					 struct device * net_dev)
+{
+	struct sis900_private *sis_priv;
+	long ioaddr = pci_dev->base_address[0] & ~3;
+	int irq = pci_dev->irq;
+	static int did_version = 0;
+	u16 signature;
+	int i;
+
+	if (did_version++ == 0)
+		printk(KERN_INFO "%s", version);
+
+	/* check to see if we have sane EEPROM */
+	signature = (u16) read_eeprom(ioaddr, EEPROMSignature);    
+	if (signature == 0xffff || signature == 0x0000) {
+		printk (KERN_INFO "%s: Error EERPOM read %x\n", 
+			net_dev->name, signature);
+		return NULL;
+	}
 
-                        pcibios_write_config_word(pci_bus, pci_device_fn,
-                                                  PCI_COMMAND, new_command);
-                }
+	if ((net_dev = init_etherdev(net_dev, 0)) == NULL)
+		return NULL;
 
-                dev = pci_tbl[chip_idx].probe1(pci_bus,
-                                                pci_device_fn,
-                                                dev,
-                                                ioaddr,
-                                                irq,
-                                                chip_idx,
-                                                cards_found);
-
-                if (dev  && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) {
-                        u8 pci_latency;
-
-                        pcibios_read_config_byte(pci_bus, pci_device_fn,
-                                        PCI_LATENCY_TIMER, &pci_latency);
-
-                        if (pci_latency < 32) {
-                           printk(KERN_NOTICE "  PCI latency timer (CFLT) is "
-                           "unreasonably low at %d.  Setting to 64 clocks.\n",
-                                           pci_latency);
-                           pcibios_write_config_byte(pci_bus, pci_device_fn,
-                                          PCI_LATENCY_TIMER, 64);
-                        }
-                }
-                dev = 0;
-                cards_found++;
-        }
-        return cards_found ? 0 : -ENODEV;
-}
+	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, mac->name,
+	       ioaddr, irq);
 
-static struct device * sis900_probe1(   int pci_bus,
-                                        int pci_devfn,
-                                        struct device *dev,
-                                        long ioaddr,
-                                        int irq,
-                                        int chip_idx,
-                                        int found_cnt)
-{
-        static int did_version = 0;     /* Already printed version info. */
-        struct sis900_private *tp;
-	u16    status;
-        int    duplex = found_cnt < MAX_UNITS ? full_duplex[found_cnt] : 0 ;
-        int    speed  = found_cnt < MAX_UNITS ? speeds[found_cnt] : 0 ;
-        int    phy=0, phy_idx=0, i;
-
-        if (did_version++ == 0)
-                printk(KERN_INFO "%s", version);
-
-        dev = init_etherdev(dev, 0);
-        
-        if(dev==NULL)
-        	return NULL;
-
-        printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
-                   dev->name, pci_tbl[chip_idx].name, ioaddr, irq);
-
-        if ((u16)read_eeprom(ioaddr, EuphLiteEEVendorID) != 0xffff) {
-                for (i = 0; i < 3; i++)
-                        ((u16 *)(dev->dev_addr))[i] =
-                                        read_eeprom(ioaddr,i+EuphLiteEEMACAddr);
-                for (i = 0; i < 5; i++)
-                        printk("%2.2x:", (u8)dev->dev_addr[i]);
-                printk("%2.2x.\n", dev->dev_addr[i]);
-        } else
-                printk(KERN_INFO "Error EEPROM read\n");
-
-        /* We do a request_region() to register /proc/ioports info. */
-        request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);
-
-        dev->base_addr = ioaddr;
-        dev->irq = irq;
-
-        /* Some data structures must be quadword aligned. */
-        tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA);
-        if(tp==NULL)
-        {
-        	release_region(ioaddr, pci_tbl[chip_idx].io_size);
-        	return NULL;
-        }
-        memset(tp, 0, sizeof(*tp));
-        dev->priv = tp;
+	/* get MAC address from EEPROM */
+	for (i = 0; i < 3; i++)
+		((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr);
+	for (i = 0; i < 5; i++)
+		printk("%2.2x:", (u8)net_dev->dev_addr[i]);
+	printk("%2.2x.\n", net_dev->dev_addr[i]);
+
+	if ((net_dev->priv = kmalloc(sizeof(struct sis900_private), GFP_KERNEL)) == NULL) {
+		unregister_netdevice(net_dev);
+		return NULL;
+	}
 
-        tp->next_module = root_sis900_dev;
-        root_sis900_dev = dev;
+	sis_priv = net_dev->priv;
+	memset(sis_priv, 0, sizeof(struct sis900_private));
 
-        tp->chip_id = chip_idx;
-        tp->pci_bus = pci_bus;
-        tp->pci_devfn = pci_devfn;
-
-        /* Find the connected MII xcvrs.
-           Doing this in open() would allow detecting external xcvrs later, but
-           takes too much time. */
-        if (sis_cap_tbl[chip_idx] & HAS_MII_XCVR) {
-                for (phy = 0, phy_idx = 0;
-                        phy < 32 && phy_idx < sizeof(tp->phys); phy++)
-                {
-                        int mii_status ;
-			mii_status = mdio_read(dev, phy, MII_STATUS);
-
-                        if (mii_status != 0xffff && mii_status != 0x0000) {
-                                tp->phy_idx = phy_idx;
-                                tp->phys[phy_idx++] = phy;
-                                tp->pmd_status=mdio_read(dev, phy, MII_STATUS);
-                                printk(KERN_INFO "%s: MII transceiver found "
-                                                 "at address %d.\n",
-                                                 dev->name, phy);
-                                break;
-                        }
-                }
+	/* We do a request_region() to register /proc/ioports info. */
+	request_region(ioaddr, mac->io_size, net_dev->name);
+	net_dev->base_addr = ioaddr;
+	net_dev->irq = irq;
+	sis_priv->pci_dev = pci_dev;
+	sis_priv->mac = mac;
+
+	/* probe for mii transciver */
+	if (sis900_mii_probe(net_dev) == 0) {
+		unregister_netdev(net_dev);
+		kfree(sis_priv);
+		release_region(ioaddr, mac->io_size);
+		return NULL;
+	}
 
-                if (phy_idx == 0) {
-                        printk(KERN_INFO "%s: No MII transceivers found!\n",
-                                        dev->name);
-                        tp->phys[0] = -1;
-			tp->pmd_status = 0;
-                }
-        } else {
-                        tp->phys[0] = -1;
-			tp->pmd_status = 0;
-        }
+	sis_priv->next_module = root_sis900_dev;
+	root_sis900_dev = net_dev;
 
-        if ((tp->pmd_status > 0) && (phy_idx > 0)) {
-		if (sis900_debug > 1) {
-			printk(KERN_INFO "duplex=%d, speed=%d\n",
-						duplex, speed);
-		}
-		if (!duplex && !speed) {  
-			// auto-config media type
-			// Set full capability
-			if (sis900_debug > 1) {
-				printk(KERN_INFO "Auto Config ...\n");
-			}
-			elSetCapability(dev, tp->phys[tp->phy_idx], 1, 100);
-            		tp->pmd_status=elAutoNegotiate(dev,
-               	    				       tp->phys[tp->phy_idx],
-			                  	       &tp->full_duplex,
-						       &tp->speeds);
-		} else {
-			tp->MediaSpeed = speed;
-			tp->MediaDuplex = duplex;
-			elSetCapability(dev, tp->phys[tp->phy_idx],
-					duplex, speed);
-            		elAutoNegotiate(dev, tp->phys[tp->phy_idx],
-			                &tp->full_duplex,
-					&tp->speeds);
-			status = mdio_read(dev, phy, MII_ANLPAR);
-			if ( !(status & (MII_NWAY_T  | MII_NWAY_T_FDX |
-					 MII_NWAY_TX | MII_NWAY_TX_FDX )))
-			{
-				u16 cmd=0;
-				cmd |= ( speed == 100 ?
-					 MIICNTL_SPEED : 0 );
-				cmd |= ( duplex ? MIICNTL_FDX : 0 );
-        			mdio_write(dev, phy, MII_CONTROL, cmd);
-				elSetMediaType(dev, speed==100 ? 
-						    HW_SPEED_100_MBPS :
-						    HW_SPEED_10_MBPS,
-						    duplex ?
-						    FDX_CAPABLE_FULL_SELECTED:
-						    FDX_CAPABLE_HALF_SELECTED);
-        			elMIIpollBit(dev, phy, MII_STATUS,
-						MIISTAT_LINK, TRUE, &status);
-			} else {
-				status = mdio_read(dev, phy, MII_STATUS);
-			}
-		}
+	/* The SiS900-specific entries in the device structure. */
+	net_dev->open = &sis900_open;
+	net_dev->hard_start_xmit = &sis900_start_xmit;
+	net_dev->stop = &sis900_close;
+	net_dev->get_stats = &sis900_get_stats;
+	net_dev->set_multicast_list = &set_rx_mode;
+	net_dev->do_ioctl = &mii_ioctl;
 
-                if (tp->pmd_status & MIISTAT_LINK) 
-               	        tp->LinkOn = TRUE;
-	        else
-                        tp->LinkOn = FALSE;
+	return net_dev;
+}
 
-		tp->LinkChange = FALSE;
+static int sis900_mii_probe (struct device * net_dev)
+{
+	struct sis900_private * sis_priv = (struct sis900_private *)net_dev->priv;
+	int phy_addr;
 	
-        }
+	sis_priv->mii = NULL;
+	
+	/* search for total of 32 possible mii phy addresses */
+	for (phy_addr = 0; phy_addr < 32; phy_addr++) {
+		u16 mii_status;
+		u16 phy_id0, phy_id1;
+		int i;
+		
+		mii_status = mdio_read(net_dev, phy_addr, MII_STATUS);
+		if (mii_status == 0xffff || mii_status == 0x0000)
+			/* the mii is not accessable, try next one */
+			continue;
+		
+		phy_id0 = mdio_read(net_dev, phy_addr, MII_PHY_ID0);
+		phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1);
+		
+		/* search our mii table for the current mii */ 
+		for (i = 0; mii_chip_table[i].phy_id1; i++)
+			if (phy_id0 == mii_chip_table[i].phy_id0) {
+				struct mii_phy * mii_phy;
+				
+				printk(KERN_INFO 
+				       "%s: %s transceiver found at address %d.\n",
+				       net_dev->name, mii_chip_table[i].name, 
+				       phy_addr);;
+				if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) != NULL) {
+					mii_phy->chip_info = mii_chip_table+i;
+					mii_phy->phy_addr = phy_addr;
+					mii_phy->status = mdio_read(net_dev, phy_addr, 
+								    MII_STATUS);
+					mii_phy->next = sis_priv->mii;
+					sis_priv->mii = mii_phy;
+				}
+				/* the current mii is on our mii_info_table, 
+				   try next address */
+				break;
+			}
+	}
+	
+	if (sis_priv->mii == NULL) {
+		printk(KERN_INFO "%s: No MII transceivers found!\n", 
+		       net_dev->name);
+		return 0;
+	}
 
-	if (sis900_debug > 1) {
-        	if (tp->full_duplex == FDX_CAPABLE_FULL_SELECTED) {
-                	printk(KERN_INFO "%s: Media type is Full Duplex.\n",
-						dev->name);
-        	} else {
-                	printk(KERN_INFO "%s: Media type is Half Duplex.\n",
-						dev->name);
-        	}
-        	if (tp->speeds == HW_SPEED_100_MBPS) {
-                	printk(KERN_INFO "%s: Speed is 100mbps.\n", dev->name);
-        	} else {
-                	printk(KERN_INFO "%s: Speed is 10mbps.\n", dev->name);
-        	}
-	}
-
-        /* The SiS900-specific entries in the device structure. */
-        dev->open = &sis900_open;
-        dev->hard_start_xmit = &sis900_start_xmit;
-        dev->stop = &sis900_close;
-        dev->get_stats = &sis900_get_stats;
-        dev->set_multicast_list = &set_rx_mode;
-        dev->do_ioctl = &mii_ioctl;
-
-        return dev;
-}
-
-/* Serial EEPROM section. */
-
-/*  EEPROM_Ctrl bits. */
-#define EECLK           0x00000004      /* EEPROM shift clock. */
-#define EECS            0x00000008      /* EEPROM chip select. */
-#define EEDO            0x00000002      /* EEPROM chip data out. */
-#define EEDI            0x00000001      /* EEPROM chip data in. */
+	/* arbitrary choose that last PHY and current PHY */
+	sis_priv->cur_phy = sis_priv->mii->phy_addr;
+	printk(KERN_INFO "%s: Using %s as default\n", net_dev->name,
+	       sis_priv->mii->chip_info->name);
 
-/* Delay between EEPROM clock transitions.
-   No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
- */
+	if (sis_priv->mii->status & MII_STAT_LINK) 
+		sis_priv->LinkOn = TRUE;
+	else
+		sis_priv->LinkOn = FALSE;
 
-#define eeprom_delay()  inl(ee_addr)
+	return 1;
+}
 
-/* The EEPROM commands include the alway-set leading bit. */
-#define EEread          0x0180
-#define EEwrite         0x0140
-#define EEerase         0x01C0
-#define EEwriteEnable   0x0130
-#define EEwriteDisable  0x0100
-#define EEeraseAll      0x0120
-#define EEwriteAll      0x0110
-#define EEaddrMask      0x013F
-#define EEcmdShift      16
+/* Delay between EEPROM clock transitions. */
+#define eeprom_delay()  inl(ee_addr)
 
+/* Read Serial EEPROM through EEPROM Access Register, Note that location is 
+   in word (16 bits) unit */
 static u16 read_eeprom(long ioaddr, int location)
 {
-        int i;
+	int i;
         u16 retval = 0;
         long ee_addr = ioaddr + mear;
         u32 read_cmd = location | EEread;
@@ -748,7 +359,7 @@
         outl(EECLK, ee_addr);
         eeprom_delay();
 
-        /* Shift the read command bits out. */
+        /* Shift the read command (9) bits out. */
         for (i = 8; i >= 0; i--) {
                 u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS;
                 outl(dataval, ee_addr);
@@ -759,6 +370,7 @@
         outb(EECS, ee_addr);
         eeprom_delay();
 
+	/* read the 16-bits data in */
         for (i = 16; i > 0; i--) {
                 outl(EECS, ee_addr);
                 eeprom_delay();
@@ -767,39 +379,20 @@
                 retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0);
                 eeprom_delay();
         }
-
+		
         /* Terminate the EEPROM access. */
         outl(0, ee_addr);
         eeprom_delay();
         outl(EECLK, ee_addr);
+
         return (retval);
 }
 
-/* MII serial management: mostly bogus for now. */
 /* Read and write the MII management registers using software-generated
-   serial MDIO protocol.
-   The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
-   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
-   "overclocking" issues. */
-
+   serial MDIO protocol. Note that the command bits and data bits are
+   send out seperately */
 #define mdio_delay()    inl(mdio_addr)
 
-#define MIIread         0x6000
-#define MIIwrite        0x6002
-#define MIIpmdMask      0x0F80
-#define MIIpmdShift     7
-#define MIIregMask      0x007C
-#define MIIregShift     2
-#define MIIturnaroundBits       2
-#define MIIcmdLen       16
-#define MIIcmdShift     16
-#define MIIreset        0xFFFFFFFF
-#define MIIwrLen        32
-
-#define MDC             0x00000040
-#define MDDIR           0x00000020
-#define MDIO            0x00000010
-
 static void mdio_idle(long mdio_addr)
 {
         outl(MDIO | MDDIR, mdio_addr);
@@ -821,11 +414,11 @@
         return;
 }
 
-static int mdio_read(struct device *dev, int phy_id, int location)
+static u16 mdio_read(struct device *net_dev, int phy_id, int location)
 {
-        long mdio_addr = dev->base_addr + mear;
+        long mdio_addr = net_dev->base_addr + mear;
         int mii_cmd = MIIread|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
-        int retval = 0;
+        u16 retval = 0;
         int i;
 
         mdio_reset(mdio_addr);
@@ -834,13 +427,15 @@
         for (i = 15; i >= 0; i--) {
                 int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
                 outl(dataval, mdio_addr);
+		mdio_delay();
                 outl(dataval | MDC, mdio_addr);
+		mdio_delay();
         }
 
-        /* Read the two transition, 16 data, and wire-idle bits. */
+        /* Read the 16 data bits. */
         for (i = 16; i > 0; i--) {
                 outl(0, mdio_addr);
-                //mdio_delay();
+                mdio_delay();
                 retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0);
                 outl(MDC, mdio_addr);
                 mdio_delay();
@@ -848,9 +443,9 @@
         return retval;
 }
 
-static void mdio_write(struct device *dev, int phy_id, int location, int value)
+static void mdio_write(struct device *net_dev, int phy_id, int location, int value)
 {
-        long mdio_addr = dev->base_addr + mear;
+        long mdio_addr = net_dev->base_addr + mear;
         int mii_cmd = MIIwrite|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
         int i;
 
@@ -858,7 +453,7 @@
         mdio_idle(mdio_addr);
 
         /* Shift the command bits out. */
-        for (i = 31; i >= 0; i--) {
+        for (i = 15; i >= 0; i--) {
                 int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
                 outb(dataval, mdio_addr);
                 mdio_delay();
@@ -866,6 +461,17 @@
                 mdio_delay();
         }
         mdio_delay();
+
+	/* Shift the value bits out. */
+	for (i = 15; i >= 0; i--) {
+		int dataval = (value & (1 << i)) ? MDDIR | MDIO : MDDIR;
+	        outl(dataval, mdio_addr);
+	        mdio_delay();
+	        outl(dataval | MDC, mdio_addr);
+	       	mdio_delay();
+	}
+	mdio_delay();
+	
         /* Clear out extra bits. */
         for (i = 2; i > 0; i--) {
                 outb(0, mdio_addr);
@@ -877,354 +483,366 @@
 }
 
 static int
-sis900_open(struct device *dev)
+sis900_open(struct device *net_dev)
 {
-        struct sis900_private *tp = (struct sis900_private *)dev->priv;
-        long ioaddr = dev->base_addr;
-
-        if (sis900_debug > 0)
-                printk(KERN_INFO "%s sis900_open, IO Addr=%x, Irq=%x\n",
-                                dev->name, (unsigned int)ioaddr, dev->irq);
+        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+        long ioaddr = net_dev->base_addr;
 
         /* Soft reset the chip. */
-        outl(0, ioaddr + imr);
-        outl(0, ioaddr + ier);
-        outl(0, ioaddr + rfcr);
-        outl(RESET | RxRESET | TxRESET, ioaddr + cr);
+	sis900_reset(net_dev);
 
-        if (request_irq(dev->irq, &sis900_interrupt, SA_SHIRQ, dev->name, dev))
-        {
+        if (request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev)) {
                 return -EAGAIN;
         }
 
-        MOD_INC_USE_COUNT;      
+        MOD_INC_USE_COUNT;
 
-        tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL);
-        tp->rx_bufs = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL);
-        if (tp->tx_bufs == NULL || tp->rx_bufs == NULL) {
-                if (tp->tx_bufs)
-                        kfree(tp->tx_bufs);
-                if (tp->rx_bufs)
-                        kfree(tp->rx_bufs);
-		if (!tp->tx_bufs) {
-	              printk(KERN_ERR "%s: Can't allocate a %d byte TX Bufs.\n",
-                                   dev->name, TX_BUF_SIZE * NUM_TX_DESC);
-		}
-		if (!tp->rx_bufs) {
-	              printk(KERN_ERR "%s: Can't allocate a %d byte RX Bufs.\n",
-                                   dev->name, RX_BUF_SIZE * NUM_RX_DESC);
-		}
-                return -ENOMEM;
-        }
-
-        {
-                u32 rfcrSave;
-                u32 w;
-                u32 i;
-
-                rfcrSave = inl(rfcr);
-                outl(rfcrSave & ~RFEN, rfcr);
-                for (i=0 ; i<3 ; i++) {
-                        w = (u16)*((u16*)(dev->dev_addr)+i);
-                        outl((((u32) i) << RFEP_shift), ioaddr + rfcr);
-                        outl((u32)w, ioaddr + rfdr);
-                        if (sis900_debug > 4) {
-                                printk(KERN_INFO "Filter Addr[%d]=%x\n",
-                                        i, inl(ioaddr + rfdr));
-                        }
-                }
-                outl(rfcrSave, rfcr);
-        }
-
-        sis900_init_ring(dev);
-        outl((u32)tp->tx_buf[0].physAddr, ioaddr + txdp);
-        outl((u32)tp->rx_buf[0].physAddr, ioaddr + rxdp);
-
-        if (sis900_debug > 4)
-                printk(KERN_INFO "txdp:%8.8x\n", inl(ioaddr + txdp));
-
-        /* Check that the chip has finished the reset. */
-        {
-                u32 status;
-                int j=0;
-                status = TxRCMP | RxRCMP;
-                while (status && (j++ < 30000)) {
-                        status ^= (inl(isr) & status);
-                }
-        }
+	sis900_init_rxfilter(net_dev);
 
-        outl(PESEL, ioaddr + cfg);
+	sis900_init_tx_ring(net_dev);
+	sis900_init_rx_ring(net_dev);
 
-        /* Must enable Tx/Rx before setting transfer thresholds! */
-        /*
-         *      #define TX_DMA_BURST    0
-         *      #define RX_DMA_BURST    0
-         *      #define TX_FIFO_THRESH  16
-         *      #define TxDRNT_100      (1536>>5)
-         *      #define TxDRNT_10       (1536>>5)
-         *      #define RxDRNT_100      (1536>>5)
-         *      #define RxDRNT_10       (1536>>5)
-         */
-        outl((RX_DMA_BURST<<20) | (RxDRNT_10 << 1), ioaddr+rxcfg);
-        outl(TxATP | (TX_DMA_BURST << 20) | (TX_FIFO_THRESH<<8) | TxDRNT_10,
-                                                ioaddr + txcfg);
-        if (sis900_debug > 1)
-        {
-        	if (tp->LinkOn) {
-        		printk(KERN_INFO"%s: Media Type %s%s-duplex.\n",
-                                dev->name,
-                                tp->speeds==HW_SPEED_100_MBPS ?
-					"100mbps " : "10mbps ",
-                                tp->full_duplex== FDX_CAPABLE_FULL_SELECTED ?
-					"full" : "half");
-		}
-		else
-		{
-			printk(KERN_INFO"%s: Media Link Off\n", dev->name);
-		}
-	}
-        set_rx_mode(dev);
+        set_rx_mode(net_dev);
 
-        dev->tbusy = 0;
-        dev->interrupt = 0;
-        dev->start = 1;
+        net_dev->tbusy = 0;
+        net_dev->interrupt = 0;
+        net_dev->start = 1;
 
         /* Enable all known interrupts by setting the interrupt mask. */
-        outl((RxOK|RxERR|RxORN|RxSOVR|TxOK|TxERR|TxURN), ioaddr + imr);
+	outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxOK), ioaddr + imr);
         outl(RxENA, ioaddr + cr);
         outl(IE, ioaddr + ier);
 
-        if (sis900_debug > 3)
-                printk(KERN_INFO "%s: sis900_open() ioaddr %#lx IRQ %d \n",
-                           dev->name, ioaddr, dev->irq);
+	sis900_check_mode(net_dev, sis_priv->mii);
 
         /* Set the timer to switch to check for link beat and perhaps switch
            to an alternate media type. */
-        init_timer(&tp->timer);
-        tp->timer.expires = RUN_AT((24*HZ)/10);         /* 2.4 sec. */
-        tp->timer.data = (unsigned long)dev;
-        tp->timer.function = &sis900_timer;             /* timer handler */
-        add_timer(&tp->timer);
+        init_timer(&sis_priv->timer);
+        sis_priv->timer.expires = jiffies + HZ;
+        sis_priv->timer.data = (unsigned long)net_dev;
+        sis_priv->timer.function = &sis900_timer;
+        add_timer(&sis_priv->timer);
 
         return 0;
 }
 
-static void sis900_timer(unsigned long data)
+/* set receive filter address to our MAC address */
+static void
+sis900_init_rxfilter (struct device * net_dev)
 {
-        struct device *dev = (struct device *)data;
-        struct sis900_private *tp = (struct sis900_private *)dev->priv;
-        int next_tick = 0;
-        u16 status;
+	long ioaddr = net_dev->base_addr;
+	u32 rfcrSave;
+	u32 i;
+	
+	rfcrSave = inl(rfcr + ioaddr);
 
-        if (!tp->LinkOn) {
-                status = mdio_read(dev, tp->phys[tp->phy_idx], MII_STATUS);
-		if (status & MIISTAT_LINK) {
-                	elPMDreadMode(dev, tp->phys[tp->phy_idx],
-                                        &tp->speeds, &tp->full_duplex);
-			tp->LinkOn = TRUE;
-                        printk(KERN_INFO "%s: Media Link On %s%s-duplex ",
-                                   dev->name,
-                                   tp->speeds == HW_SPEED_100_MBPS ?
-						"100mbps " : "10mbps ",
-                                   tp->full_duplex==FDX_CAPABLE_FULL_SELECTED ?
-						"full" : "half");
-		}
-        } else { // previous link on
-                status = mdio_read(dev, tp->phys[tp->phy_idx], MII_STATUS);
-		if (!(status & MIISTAT_LINK)) {
-			tp->LinkOn = FALSE;
-                        printk(KERN_INFO "%s: Media Link Off\n", dev->name);
+	/* disable packet filtering before setting filter */
+	outl(rfcrSave & ~RFEN, rfcr);
+
+	/* load MAC addr to filter data register */
+	for (i = 0 ; i < 3 ; i++) {
+		u32 w;
+
+		w = (u32) *((u16 *)(net_dev->dev_addr)+i);
+		outl((i << RFADDR_shift), ioaddr + rfcr);
+		outl(w, ioaddr + rfdr);
+
+		if (sis900_debug > 2) {
+			printk(KERN_INFO "%s: Receive Filter Addrss[%d]=%x\n",
+			       net_dev->name, i, inl(ioaddr + rfdr));
 		}
-        }
-        next_tick = 2*HZ;
+	}
 
-        if (next_tick) {
-                tp->timer.expires = RUN_AT(next_tick);
-                add_timer(&tp->timer);
-        }
+	/* enable packet filitering */
+	outl(rfcrSave | RFEN, rfcr + ioaddr);
 }
 
-static void sis900_tx_timeout(struct device *dev)
+/* Initialize the Tx ring. */
+static void
+sis900_init_tx_ring(struct device *net_dev)
 {
-        struct sis900_private *tp = (struct sis900_private *)dev->priv;
-        long ioaddr = dev->base_addr;
+        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+        long ioaddr = net_dev->base_addr; 
         int i;
+	
+        sis_priv->tx_full = 0;
+        sis_priv->dirty_tx = sis_priv->cur_tx = 0;
+	
+        for (i = 0; i < NUM_TX_DESC; i++) {
+		sis_priv->tx_skbuff[i] = NULL;
 
-        if (sis900_debug > 0)
-                printk(KERN_INFO "%s: Transmit timeout, status %2.2x %4.4x \n",
-                           dev->name, inl(ioaddr + cr), inl(ioaddr + isr));
-
-        /* Disable interrupts by clearing the interrupt mask. */
-        outl(0x0000, ioaddr + imr);
+		sis_priv->tx_ring[i].link = (u32) virt_to_bus(&sis_priv->tx_ring[i+1]);
+                sis_priv->tx_ring[i].cmdsts = 0;
+		sis_priv->tx_ring[i].bufptr = 0;
+        }
+	sis_priv->tx_ring[i-1].link = (u32) virt_to_bus(&sis_priv->tx_ring[0]);
+
+	/* load Transmit Descriptor Register */
+        outl(virt_to_bus(&sis_priv->tx_ring[0]), ioaddr + txdp); 
+	if (sis900_debug > 2)
+                printk(KERN_INFO "%s: TX descriptor register loaded with: %8.8x\n", 
+		       net_dev->name, inl(ioaddr + txdp));
+}
+
+/* Initialize the Rx descriptor ring, pre-allocate recevie buffers */ 
+static void 
+sis900_init_rx_ring(struct device *net_dev) 
+{ 
+        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; 
+        long ioaddr = net_dev->base_addr; 
+        int i;
+ 
+        sis_priv->cur_rx = 0; 
+	sis_priv->dirty_rx = 0;
+
+	/* init RX descriptor */
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		sis_priv->rx_skbuff[i] = NULL;
+
+		sis_priv->rx_ring[i].link = (u32) virt_to_bus(&sis_priv->rx_ring[i+1]);
+		sis_priv->rx_ring[i].cmdsts = 0;
+		sis_priv->rx_ring[i].bufptr = 0;
+	}
+	sis_priv->rx_ring[i-1].link = (u32) virt_to_bus(&sis_priv->rx_ring[0]);
 
-        /* Emit info to figure out what went wrong. */
-	if (sis900_debug > 1) {
-	        printk(KERN_INFO "%s:Tx queue start entry %d dirty entry %d.\n",
-                		   dev->name, tp->cur_tx, tp->dirty_tx);
-        	for (i = 0; i < NUM_TX_DESC; i++) 
-                	printk(KERN_INFO "%s:  Tx descriptor %d is %8.8x.%s\n",
-                        	dev->name, i, (unsigned int)&tp->tx_buf[i],
-                     		i == tp->dirty_tx % NUM_TX_DESC ?
-                      		" (queue head)" : "");
+        /* allocate sock buffers */
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		struct sk_buff *skb;
+
+		if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
+			/* not enough memory for skbuff, this makes a "hole"
+			   on the buffer ring, it is not clear how the 
+			   hardware will react to this kind of degenerated 
+			   buffer */
+			break;
+		}
+		skb->dev = net_dev;
+		sis_priv->rx_skbuff[i] = skb;
+		sis_priv->rx_ring[i].cmdsts = RX_BUF_SIZE;
+		sis_priv->rx_ring[i].bufptr = virt_to_bus(skb->tail);
 	}
+	sis_priv->dirty_rx = (unsigned int) (i - NUM_RX_DESC);
 
-        /* Soft reset the chip. */
-        //outb(RESET, ioaddr + cr);
-        /* Check that the chip has finished the reset. */
-        /*
-        for (i = 1000; i > 0; i--)
-                if ((inb(ioaddr + cr) & RESET) == 0)
-                        break;
-        */
+	/* load Receive Descriptor Register */
+        outl(virt_to_bus(&sis_priv->rx_ring[0]), ioaddr + rxdp);
+	if (sis900_debug > 2)
+                printk(KERN_INFO "%s: RX descriptor register loaded with: %8.8x\n", 
+		       net_dev->name, inl(ioaddr + rxdp));
+}
+/* on each timer ticks we check two things, Link Status (ON/OFF) and 
+   Link Mode (10/100/Full/Half)
+ */
+static void sis900_timer(unsigned long data)
+{
+        struct device *net_dev = (struct device *)data;
+        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+	struct mii_phy *mii_phy = sis_priv->mii;
+        static int next_tick = 5*HZ;
+        u16 status;
 
-        tp->cur_rx = 0; 
-        /* Must enable Tx/Rx before setting transfer thresholds! */
-        /*
-        set_rx_mode(dev);
-        */
-        {       /* Save the unsent Tx packets. */
-                struct sk_buff *saved_skb[NUM_TX_DESC], *skb;
-                int j;
-                for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++)
-                        saved_skb[j]=tp->tx_skbuff[tp->dirty_tx % NUM_TX_DESC];
-                tp->dirty_tx = tp->cur_tx = 0;
-
-                for (i = 0; i < j; i++) {
-                        skb = tp->tx_skbuff[i] = saved_skb[i];
-                        /* Always alignment */
-                        memcpy((unsigned char*)(tp->tx_buf[i].buf),
-                                                skb->data, skb->len);
-                        tp->tx_buf[i].cmdsts = OWN | skb->len;
-                        /* Note: the chip doesn't have auto-pad! */
-                        /*
-                        outl(tp->tx_flag|(skb->len>=ETH_ZLEN?skb->len:ETH_ZLEN),
-                                 ioaddr + TxStatus0 + i*4);
-                        */
-                }
-                outl(TxENA, ioaddr + cr);
-                tp->cur_tx = i;
-                while (i < NUM_TX_DESC)
-                        tp->tx_skbuff[i++] = 0;
-                if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
-                        dev->tbusy = 0;
-                        tp->tx_full = 0;
-                } else {
-                        tp->tx_full = 1;
-                }
-        }
+	status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);
 
-        dev->trans_start = jiffies;
-        tp->stats.tx_errors++;
-        /* Enable all known interrupts by setting the interrupt mask. */
-        outl((RxOK|RxERR|RxORN|RxSOVR|TxOK|TxERR|TxURN), ioaddr + imr);
-        return;
-}
+	/* current mii phy is failed to link, try another one */
+	while (!(status & MII_STAT_LINK)) {		
+		if (mii_phy->next == NULL) { 
+			if (sis_priv->LinkOn) {
+				/* link stat change from ON to OFF */
+				next_tick = HZ;
+				sis_priv->LinkOn = FALSE;
+				printk(KERN_INFO "%s: Media Link Off\n",
+				       net_dev->name);
+			}
+			sis_priv->timer.expires = jiffies + next_tick;
+			add_timer(&sis_priv->timer);
+			return;
+		}
+		mii_phy = mii_phy->next;
+		status = mdio_read(net_dev, mii_phy->phy_addr, MII_STATUS);
+	}
 
+	if (!sis_priv->LinkOn) {
+		/* link stat change forn OFF to ON, read and report link mode */
+		sis_priv->LinkOn = TRUE;
+		next_tick = 5*HZ;
+		/* change what cur_phy means */
+		if (mii_phy->phy_addr != sis_priv->cur_phy) {
+			printk(KERN_INFO "%s: Changing transceiver to %s\n", net_dev->name,
+			       mii_phy->chip_info->name);
+			status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);
+			mdio_write(net_dev, sis_priv->cur_phy, 
+				   MII_CONTROL, status | MII_CNTL_ISOLATE);
+			status = mdio_read(net_dev, mii_phy->phy_addr, MII_CONTROL);
+			mdio_write(net_dev, mii_phy->phy_addr, 
+				   MII_CONTROL, status & ~MII_CNTL_ISOLATE);
+			sis_priv->cur_phy = mii_phy->phy_addr;
+		}
+		sis900_check_mode(net_dev, mii_phy);
+	}
 
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void
-sis900_init_ring(struct device *dev)
+	sis_priv->timer.expires = jiffies + next_tick;
+	add_timer(&sis_priv->timer);
+}
+static void sis900_check_mode (struct device *net_dev, struct mii_phy *mii_phy)
 {
-        struct sis900_private *tp = (struct sis900_private *)dev->priv;
-        int i;
+	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+        long ioaddr = net_dev->base_addr;
+	int speed, duplex;
+	u32 tx_flags = 0, rx_flags = 0;
 
-        tp->tx_full = 0;
-        tp->cur_rx = 0;
-        tp->dirty_tx = tp->cur_tx = 0;
+	mii_phy->chip_info->read_mode(net_dev, sis_priv->cur_phy, &speed, &duplex);
 
-        /* Tx Buffer */
-        for (i = 0; i < NUM_TX_DESC; i++) {
-                tp->tx_skbuff[i] = 0;
-                tp->tx_buf[i].buf = &tp->tx_bufs[i*TX_BUF_SIZE];
-                tp->tx_buf[i].bufPhys =
-                                virt_to_bus(&tp->tx_bufs[i*TX_BUF_SIZE]);
-        }
+	tx_flags = TxATP | (TX_DMA_BURST << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);
+	rx_flags = RX_DMA_BURST << RxMXDMA_shift;
 
-        /* Tx Descriptor */
-        for (i = 0; i< NUM_TX_DESC; i++) {
-                tp->tx_buf[i].llink = (u32)
-                        &(tp->tx_buf[((i+1) < NUM_TX_DESC) ? (i+1) : 0]);
-                tp->tx_buf[i].plink = (u32)
-                        virt_to_bus(&(tp->tx_buf[((i+1) < NUM_TX_DESC) ?
-                                (i+1) : 0].plink));
-                tp->tx_buf[i].physAddr=
-                                virt_to_bus(&(tp->tx_buf[i].plink));
-                tp->tx_buf[i].cmdsts=0;
-        }
+	if (speed == HW_SPEED_HOME || speed == HW_SPEED_10_MBPS ) {
+		rx_flags |= (RxDRNT_10 << RxDRNT_shift);
+		tx_flags |= (TxDRNT_10 << TxDRNT_shift);
+	}
+	else {
+		rx_flags |= (RxDRNT_100 << RxDRNT_shift);
+		tx_flags |= (TxDRNT_100 << TxDRNT_shift);
+	}
 
-        /* Rx Buffer */
-        for (i = 0; i < NUM_RX_DESC; i++) {
-                tp->rx_buf[i].buf = &tp->rx_bufs[i*RX_BUF_SIZE];
-                tp->rx_buf[i].bufPhys =
-                                virt_to_bus(&tp->rx_bufs[i*RX_BUF_SIZE]);
-        }
+	if (duplex == FDX_CAPABLE_FULL_SELECTED) {
+		tx_flags |= (TxCSI | TxHBI);
+		rx_flags |= RxATX;
+	}
 
-        /* Rx Descriptor */
-        for (i = 0; i< NUM_RX_DESC; i++) {
-                tp->rx_buf[i].llink = (u32)
-                        &(tp->rx_buf[((i+1) < NUM_RX_DESC) ? (i+1) : 0]);
-                tp->rx_buf[i].plink = (u32)
-                        virt_to_bus(&(tp->rx_buf[((i+1) < NUM_RX_DESC) ?
-                                (i+1) : 0].plink));
-                tp->rx_buf[i].physAddr=
-                                virt_to_bus(&(tp->rx_buf[i].plink));
-                tp->rx_buf[i].cmdsts=RX_BUF_SIZE;
-        }
+	outl (tx_flags, ioaddr + txcfg);
+	outl (rx_flags, ioaddr + rxcfg);
 }
+static void sis900_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex)
+{
+	int i = 0;
+	u32 status;
+	
+	/* STSOUT register is Latched on Transition, read operation updates it */
+	while (i++ < 2)
+		status = mdio_read(net_dev, phy_addr, MII_STSOUT);
+
+	if (status & MII_STSOUT_SPD)
+		*speed = HW_SPEED_100_MBPS;
+	else
+		*speed = HW_SPEED_10_MBPS;
+
+	if (status & MII_STSOUT_DPLX)
+		*duplex = FDX_CAPABLE_FULL_SELECTED;
+	else
+		*duplex = FDX_CAPABLE_HALF_SELECTED;
+
+	if (status & MII_STSOUT_LINK_FAIL)
+		printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
+	else
+		printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", 
+		       net_dev->name,
+		       *speed == HW_SPEED_100_MBPS ? 
+		       "100mbps" : "10mbps",
+		       *duplex == FDX_CAPABLE_FULL_SELECTED ?
+		       "full" : "half");
+}
+static void amd79c901_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex)
+{
+	int i;
+	u16 status;
+	
+	for (i = 0; i < 2; i++)
+		status = mdio_read(net_dev, phy_addr, MII_STATUS);
 
-static int
-sis900_start_xmit(struct sk_buff *skb, struct device *dev)
+	if (status & MII_STAT_CAN_AUTO) {
+		/* 10BASE-T PHY */
+		for (i = 0; i < 2; i++)
+			status = mdio_read(net_dev, phy_addr, MII_STATUS_SUMMARY);
+		if (status & MII_STSSUM_SPD)
+			*speed = HW_SPEED_100_MBPS;
+		else
+			*speed = HW_SPEED_10_MBPS;
+		if (status & MII_STSSUM_DPLX)
+			*duplex = FDX_CAPABLE_FULL_SELECTED;
+		else
+			*duplex = FDX_CAPABLE_HALF_SELECTED;
+
+		if (status & MII_STSSUM_LINK)
+			printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", 
+			       net_dev->name,
+			       *speed == HW_SPEED_100_MBPS ? 
+			       "100mbps" : "10mbps",
+			       *duplex == FDX_CAPABLE_FULL_SELECTED ?
+			       "full" : "half");
+		else
+			printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
+			
+	}
+	else {
+		/* HomePNA */
+		*speed = HW_SPEED_HOME;
+		*duplex = FDX_CAPABLE_HALF_SELECTED;
+		if (status & MII_STAT_LINK)
+			printk(KERN_INFO "%s: Media Link On 1mbps half-duplex \n", 
+			       net_dev->name);
+		else
+			printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
+	}
+}
+static void sis900_tx_timeout(struct device *net_dev)
 {
-        struct sis900_private *tp = (struct sis900_private *)dev->priv;
-        long ioaddr = dev->base_addr;
-        int entry;
-
-        /* Block a timer-based transmit from overlapping.  This could better be
-           done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-        if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-                if (jiffies - dev->trans_start < TX_TIMEOUT)
-                        return 1;
-                sis900_tx_timeout(dev);
-                return 1;
-        }
+        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+        long ioaddr = net_dev->base_addr;
 
-        /* Calculate the next Tx descriptor entry. ????? */
-        entry = tp->cur_tx % NUM_TX_DESC;
+	printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x \n",
+	       net_dev->name, inl(ioaddr + cr), inl(ioaddr + isr));
+	
+        /* Disable interrupts by clearing the interrupt mask. */
+        outl(0x0000, ioaddr + imr);
 
-        tp->tx_skbuff[entry] = skb;
+        sis_priv->cur_rx = 0;
+        net_dev->trans_start = jiffies;
+        sis_priv->stats.tx_errors++;
 
-        if (sis900_debug > 5) {
-                int i;
-                printk(KERN_INFO "%s: SKB Tx Frame contents:(len=%d)",
-                                                dev->name,skb->len);
-
-                for (i = 0; i < skb->len; i++) {
-                        printk("%2.2x ",
-                        (u8)skb->data[i]);
-                }
-                printk(".\n");
-        }
+	/* FIXME: Should we restart the transmission thread here  ?? */
 
-        memcpy(tp->tx_buf[entry].buf,
-                                skb->data, skb->len);
+        /* Enable all known interrupts by setting the interrupt mask. */
+        outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxOK), ioaddr + imr);
+        return;
+}
 
-        tp->tx_buf[entry].cmdsts=(OWN | skb->len);
+static int
+sis900_start_xmit(struct sk_buff *skb, struct device *net_dev)
+{
+        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+        long ioaddr = net_dev->base_addr;
+        unsigned int  entry;
+
+	/* test tbusy to see if we have timeout situation then set it */
+        if (test_and_set_bit(0, (void*)&net_dev->tbusy) != 0) {
+                if (jiffies - net_dev->trans_start > TX_TIMEOUT)
+			sis900_tx_timeout(net_dev);
+                return 1;
+        }
 
-        //tp->tx_buf[entry].plink = 0;
+        /* Calculate the next Tx descriptor entry. */
+        entry = sis_priv->cur_tx % NUM_TX_DESC;
+        sis_priv->tx_skbuff[entry] = skb;
+
+	/* set the transmit buffer descriptor and enable Transmit State Machine */
+	sis_priv->tx_ring[entry].bufptr = virt_to_bus(skb->data);
+        sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len);
         outl(TxENA, ioaddr + cr);
-        if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
-                clear_bit(0, (void*)&dev->tbusy);
+
+        if (++sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC) {
+		/* Typical path, clear tbusy to indicate more 
+		   transmission is possible */
+                clear_bit(0, (void*)&net_dev->tbusy);
         } else {
-                tp->tx_full = 1;
+		/* no more transmit descriptor avaiable, tbusy remain set */
+                sis_priv->tx_full = 1;
         }
 
-        /* Note: the chip doesn't have auto-pad! */
+        net_dev->trans_start = jiffies;
 
-        dev->trans_start = jiffies;
-        if (sis900_debug > 4)
-                printk(KERN_INFO "%s: Queued Tx packet at "
-                                "%p size %d to slot %d.\n",
-                           dev->name, skb->data, (int)skb->len, entry);
+        if (sis900_debug > 3)
+                printk(KERN_INFO "%s: Queued Tx packet at %p size %d "
+		       "to slot %d.\n",
+		       net_dev->name, skb->data, (int)skb->len, entry);
 
         return 0;
 }
@@ -1233,340 +851,264 @@
    after the Tx thread. */
 static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 {
-        struct device *dev = (struct device *)dev_instance;
-        struct sis900_private *tp = (struct sis900_private *)dev->priv;
+        struct device *net_dev = (struct device *)dev_instance;
         int boguscnt = max_interrupt_work;
-        int status;
-        long ioaddr = dev->base_addr;
+	long ioaddr = net_dev->base_addr;
+	u32 status;
 
 #if defined(__i386__)
         /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
-        if (test_and_set_bit(0, (void*)&dev->interrupt)) {
+        if (test_and_set_bit(0, (void*)&net_dev->interrupt)) {
                 printk(KERN_INFO "%s: SMP simultaneous entry of "
-                                "an interrupt handler.\n", dev->name);
-                dev->interrupt = 0;     /* Avoid halting machine. */
+		       "an interrupt handler.\n", net_dev->name);
+                net_dev->interrupt = 0;     /* Avoid halting machine. */
                 return;
         }
 #else
-        if (dev->interrupt) {
-                printk(KERN_INFO "%s: Re-entering the "
-                                "interrupt handler.\n", dev->name);
+        if (net_dev->interrupt) {
+                printk(KERN_INFO "%s: Re-entering the interrupt handler.\n", 
+		       net_dev->name);
                 return;
         }
-        dev->interrupt = 1;
+        net_dev->interrupt = 1;
 #endif
 
         do {
                 status = inl(ioaddr + isr);
-                /* Acknowledge all of the current interrupt sources ASAP. */
-                outl(status, ioaddr + isr); // ?????
-
-                if (sis900_debug > 4)
-                        printk(KERN_INFO "%s: interrupt  status=%#4.4x "
-                                "new intstat=%#4.4x.\n",
-                                dev->name, status, inl(ioaddr + isr));
+		
+                if (sis900_debug > 3)
+			printk(KERN_INFO "%s: entering interrupt, "
+			       "original status = %#8.8x, "
+			       "new status = %#8.8x.\n",
+			       net_dev->name, status, inl(ioaddr + isr));
 
-                if ((status & (TxURN|TxERR|TxOK | RxORN|RxERR|RxOK)) == 0) {
+                if ((status & (HIBERR|TxURN|TxERR|TxOK|RxORN|RxERR|RxOK)) == 0)
+			/* nothing intresting happened */
                         break;
-                }
-
-                if (status & (RxOK|RxORN|RxERR)) /* Rx interrupt */
-                        sis900_rx(dev);
 
-                if (status & (TxOK | TxERR)) {
-                        unsigned int dirty_tx;
-
-                        if (sis900_debug > 5) {
-                                printk(KERN_INFO "TxOK:tp->cur_tx:%d,"
-                                                "tp->dirty_tx:%x\n",
-                                        tp->cur_tx, tp->dirty_tx);
-                        }
-                        for (dirty_tx = tp->dirty_tx; dirty_tx < tp->cur_tx;
-                                dirty_tx++)
-                        {
-                                int i;
-                                int entry = dirty_tx % NUM_TX_DESC;
-                                int txstatus = tp->tx_buf[entry].cmdsts;
-
-                                if (sis900_debug > 4) {
-                                        printk(KERN_INFO "%s:     Tx Frame contents:"
-                                                "(len=%d)",
-                                                dev->name, (txstatus & DSIZE));
-
-                                        for (i = 0; i < (txstatus & DSIZE) ;
-                                                                        i++) {
-                                                printk("%2.2x ",
-                                                (u8)(tp->tx_buf[entry].buf[i]));
-                                        }
-                                        printk(".\n");
-                                }
-                                if ( ! (txstatus & (OK | UNDERRUN)))
-                                {
-                                        if (sis900_debug > 1)
-                                                printk(KERN_INFO "Tx NOT (OK,"
-                                                        "UnderRun)\n");
-                                        break;  /* It still hasn't been Txed */
-                                }
-
-                                /* Note: TxCarrierLost is always asserted
-                                                at 100mbps.                 */
-                                if (txstatus & (OWCOLL | ABORT)) {
-                                        /* There was an major error, log it. */
-                                        if (sis900_debug > 1)
-                                                printk(KERN_INFO "Tx Out of "
-                                                        " Window,Abort\n");
-#ifndef final_version
-                                        if (sis900_debug > 1)
-                                                printk(KERN_INFO "%s: Transmit "
-                                                    "error, Tx status %8.8x.\n",
-                                                           dev->name, txstatus);
-#endif
-                                        tp->stats.tx_errors++;
-                                        if (txstatus & ABORT) {
-                                                tp->stats.tx_aborted_errors++;
-                                        }
-                                        if (txstatus & NOCARRIER)
-                                                tp->stats.tx_carrier_errors++;
-                                        if (txstatus & OWCOLL)
-                                                tp->stats.tx_window_errors++;
-#ifdef ETHER_STATS
-                                        if ((txstatus & COLCNT)==COLCNT)
-                                                tp->stats.collisions16++;
-#endif
-                                } else {
-#ifdef ETHER_STATS
-                                        /* No count for tp->stats.tx_deferred */
-#endif
-                                        if (txstatus & UNDERRUN) {
-                                           if (sis900_debug > 2)
-                                             printk(KERN_INFO "Tx UnderRun\n");
-                                        }
-                                        tp->stats.collisions +=
-                                                        (txstatus >> 16) & 0xF;
-#if LINUX_VERSION_CODE > 0x20119
-                                        tp->stats.tx_bytes += txstatus & DSIZE;
-#endif
-                                        if (sis900_debug > 2)
-                                           printk(KERN_INFO "Tx Transmit OK\n");
-                                        tp->stats.tx_packets++;
-                                }
-
-                                /* Free the original skb. */
-                                if (sis900_debug > 2)
-                                        printk(KERN_INFO "Free original skb\n");
-                                dev_free_skb(tp->tx_skbuff[entry]);
-                                tp->tx_skbuff[entry] = 0;
-                        } // for dirty
-
-#ifndef final_version
-                        if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
-                                printk(KERN_INFO"%s: Out-of-sync dirty pointer,"
-                                                " %d vs. %d, full=%d.\n",
-                                                dev->name, dirty_tx,
-                                                tp->cur_tx, tp->tx_full);
-                                dirty_tx += NUM_TX_DESC;
-                        }
-#endif
-
-                        if (tp->tx_full && dirty_tx > tp->cur_tx-NUM_TX_DESC) {
-                                /* The ring is no longer full, clear tbusy. */
-				if (sis900_debug > 3)
-                                   printk(KERN_INFO "Tx Ring NO LONGER Full\n");
-                                tp->tx_full = 0;
-                                dev->tbusy = 0;
-                                mark_bh(NET_BH);
-                        }
-
-                        tp->dirty_tx = dirty_tx;
-                        if (sis900_debug > 2)
-                           printk(KERN_INFO "TxOK,tp->cur_tx:%d,tp->dirty:%d\n",
-                                                tp->cur_tx, tp->dirty_tx);
-                } // if (TxOK | TxERR)
-
-                /* Check uncommon events with one test. */
-                if (status & (RxORN | TxERR | RxERR)) {
-                        if (sis900_debug > 2)
-                                printk(KERN_INFO "%s: Abnormal interrupt,"
-                                        "status %8.8x.\n", dev->name, status);
-
-                        if (status == 0xffffffff)
-                                break;
-                        if (status & (RxORN | RxERR))
-                                tp->stats.rx_errors++;
-
-
-                        if (status & RxORN) {
-                                tp->stats.rx_over_errors++;
-                        }
-                }
+		/* why dow't we break after Tx/Rx case ?? keyword: full-duplex */
+                if (status & (RxORN | RxERR | RxOK))
+			/* Rx interrupt */
+                        sis900_rx(net_dev);
+
+                if (status & (TxURN | TxERR | TxOK))
+			/* Tx interrupt */
+			sis900_finish_xmit(net_dev);
+
+                /* something strange happened !!! */
+                if (status & HIBERR) {
+			printk(KERN_INFO "%s: Abnormal interrupt,"
+			       "status %#8.8x.\n", net_dev->name, status);
+			break;
+		}
                 if (--boguscnt < 0) {
                         printk(KERN_INFO "%s: Too much work at interrupt, "
-                                   "IntrStatus=0x%4.4x.\n",
-                                   dev->name, status);
+			       "interrupt status = %#8.8x.\n",
+			       net_dev->name, status);
                         break;
                 }
         } while (1);
-
+	
         if (sis900_debug > 3)
-                printk(KERN_INFO "%s: exiting interrupt, intr_status=%#4.4x.\n",
-                           dev->name, inl(ioaddr + isr));
-
+                printk(KERN_INFO "%s: exiting interrupt, "
+		       "interrupt status = 0x%#8.8x.\n",
+		       net_dev->name, inl(ioaddr + isr));
+	
 #if defined(__i386__)
-        clear_bit(0, (void*)&dev->interrupt);
+        clear_bit(0, (void*)&net_dev->interrupt);
 #else
-        dev->interrupt = 0;
+        net_dev->interrupt = 0;
 #endif
         return;
 }
 
-/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
-   field alignments and semantics. */
-static int sis900_rx(struct device *dev)
-{
-        struct sis900_private *tp = (struct sis900_private *)dev->priv;
-        long ioaddr = dev->base_addr;
-        u16 cur_rx = tp->cur_rx % NUM_RX_DESC;
-        int rx_status=tp->rx_buf[cur_rx].cmdsts;
-
-        if (sis900_debug > 4)
-                printk(KERN_INFO "%s: sis900_rx, current %4.4x,"
-                                " rx status=%8.8x\n",
-                                dev->name, cur_rx,
-                                rx_status);
-
+/* Process receive interrupt events, put buffer to higher layer and refill buffer pool 
+   Note: This fucntion is called by interrupt handler, don't do "too much" work here */
+static int sis900_rx(struct device *net_dev)
+{
+        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+        long ioaddr = net_dev->base_addr;
+	unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC;
+        u32 rx_status = sis_priv->rx_ring[entry].cmdsts;
+	
+        if (sis900_debug > 3)
+                printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d "
+		       "status:0x%8.8x\n",
+		       sis_priv->cur_rx, sis_priv->dirty_rx,rx_status);
+	
         while (rx_status & OWN) {
-                int rx_size = rx_status & DSIZE;
-                rx_size -= CRC_SIZE;
-
-                if (sis900_debug > 4) {
-                        int i;
-                        printk(KERN_INFO "%s:  sis900_rx, rx status %8.8x,"
-                                        " size %4.4x, cur %4.4x.\n",
-                                   dev->name, rx_status, rx_size, cur_rx);
-                        printk(KERN_INFO "%s: Rx Frame contents:", dev->name);
-
-                        for (i = 0; i < rx_size; i++) {
-                                printk("%2.2x ",
-                                (u8)(tp->rx_buf[cur_rx].buf[i]));
-                        }
-
-                        printk(".\n");
-                }
-                if (rx_status & TOOLONG) {
-                        if (sis900_debug > 1)
-                                printk(KERN_INFO "%s: Oversized Ethernet frame,"
-                                                " status %4.4x!\n",
-                                           dev->name, rx_status);
-                        tp->stats.rx_length_errors++;
-                } else if (rx_status & (RXISERR | RUNT | CRCERR | FAERR)) {
-                        if (sis900_debug > 1)
-                                printk(KERN_INFO"%s: Ethernet frame had errors,"
-                                        " status %4.4x.\n",
-                                        dev->name, rx_status);
-                        tp->stats.rx_errors++;
+                unsigned int rx_size;
+		
+		rx_size = (rx_status & DSIZE) - CRC_SIZE;
+		
+		if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) {
+			/* corrupted packet received */
+                        if (sis900_debug > 3)
+                                printk(KERN_INFO "%s: Corrupted packet "
+				       "received, buffer status = 0x%8.8x.\n",
+				       net_dev->name, rx_status);
+                        sis_priv->stats.rx_errors++;
+			if (rx_status & OVERRUN)
+				sis_priv->stats.rx_over_errors++;
+			if (rx_status & (TOOLONG|RUNT))
+                                sis_priv->stats.rx_length_errors++;
                         if (rx_status & (RXISERR | FAERR))
-                                tp->stats.rx_frame_errors++;
-                        if (rx_status & (RUNT | TOOLONG))
-                                tp->stats.rx_length_errors++;
-                        if (rx_status & CRCERR) tp->stats.rx_crc_errors++;
+                                sis_priv->stats.rx_frame_errors++;
+			if (rx_status & CRCERR) 
+				sis_priv->stats.rx_crc_errors++;
+			/* reset buffer descriptor state */
+			sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
                 } else {
-                        /* Malloc up new buffer, compatible with net-2e. */
-                        /* Omit the four octet CRC from the length. */
-                        struct sk_buff *skb;
-
-                        skb = dev_alloc_skb(rx_size + 2);
-                        if (skb == NULL) {
-                                printk(KERN_INFO "%s: Memory squeeze,"
-                                                "deferring packet.\n",
-                                                dev->name);
-                                /* We should check that some rx space is free.
-                                   If not,
-                                   free one and mark stats->rx_dropped++. */
-                                tp->stats.rx_dropped++;
-                                tp->rx_buf[cur_rx].cmdsts = RX_BUF_SIZE;
-                                break;
-                        }
-                        skb->dev = dev;
-                        skb_reserve(skb, 2); /* 16 byte align the IP fields. */
-                        if (rx_size+CRC_SIZE > RX_BUF_SIZE) {
-                                /*
-                                int semi_count = RX_BUF_LEN - ring_offset - 4;
-                                memcpy(skb_put(skb, semi_count),
-                                        &rx_bufs[ring_offset + 4], semi_count);
-                                memcpy(skb_put(skb, rx_size-semi_count),
-                                        rx_bufs, rx_size - semi_count);
-                                if (sis900_debug > 4) {
-                                        int i;
-                                        printk(KERN_DEBUG"%s:  Frame wrap @%d",
-                                                   dev->name, semi_count);
-                                        for (i = 0; i < 16; i++)
-                                                printk(" %2.2x", rx_bufs[i]);
-                                        printk(".\n");
-                                        memset(rx_bufs, 0xcc, 16);
-                                }
-                                */
-                        } else {
-#if 0  /* USE_IP_COPYSUM */
-                                eth_copy_and_sum(skb,
-                                   tp->rx_buf[cur_rx].buf, rx_size, 0);
-                                skb_put(skb, rx_size);
-#else
-                                memcpy(skb_put(skb, rx_size),
-                                        tp->rx_buf[cur_rx].buf, rx_size);
-#endif
-                        }
-                        skb->protocol = eth_type_trans(skb, dev);
+			struct sk_buff * skb;
+			
+			if (sis_priv->rx_skbuff[entry] == NULL) {
+				printk(KERN_INFO "%s: NULL pointer " 
+				       "encountered in Rx ring, skipping\n",
+				       net_dev->name);
+				break;			
+			}
+			skb = sis_priv->rx_skbuff[entry];
+			sis_priv->rx_skbuff[entry] = NULL;
+			/* reset buffer descriptor state */
+			sis_priv->rx_ring[entry].cmdsts = 0;
+			sis_priv->rx_ring[entry].bufptr = 0;
+			
+			skb_put(skb, rx_size);
+                        skb->protocol = eth_type_trans(skb, net_dev);
                         netif_rx(skb);
-#if LINUX_VERSION_CODE > 0x20119
-                        tp->stats.rx_bytes += rx_size;
-#endif
-                        tp->stats.rx_packets++;
+			
+			if ((rx_status & BCAST) == MCAST)
+				sis_priv->stats.multicast++;
+			net_dev->last_rx = jiffies;
+                        sis_priv->stats.rx_bytes += rx_size;
+                        sis_priv->stats.rx_packets++;
                 }
-                tp->rx_buf[cur_rx].cmdsts = RX_BUF_SIZE;
-
-                cur_rx = ((cur_rx+1) % NUM_RX_DESC);
-                rx_status = tp->rx_buf[cur_rx].cmdsts;
+                sis_priv->cur_rx++;
+		entry = sis_priv->cur_rx % NUM_RX_DESC;
+                rx_status = sis_priv->rx_ring[entry].cmdsts;
         } // while
-        if (sis900_debug > 4)
-                printk(KERN_INFO "%s: Done sis900_rx(), current %4.4x "
-                                "Cmd %2.2x.\n",
-                           dev->name, cur_rx,
-                           inb(ioaddr + cr));
-        tp->cur_rx = cur_rx;
+	
+	/* refill the Rx buffer, what if the rate of refilling is slower than 
+	   consuming ?? */
+	for (;sis_priv->cur_rx - sis_priv->dirty_rx > 0; sis_priv->dirty_rx++) {
+		struct sk_buff *skb;
+		
+		entry = sis_priv->dirty_rx % NUM_RX_DESC;
+		
+		if (sis_priv->rx_skbuff[entry] == NULL) {
+			if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
+				/* not enough memory for skbuff, this makes a "hole"
+				   on the buffer ring, it is not clear how the 
+				   hardware will react to this kind of degenerated 
+				   buffer */
+				printk(KERN_INFO "%s: Memory squeeze,"
+				       "deferring packet.\n",
+				       net_dev->name);
+				sis_priv->stats.rx_dropped++;
+				break;
+			}
+			skb->dev = net_dev;
+			sis_priv->rx_skbuff[entry] = skb;
+			sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
+			sis_priv->rx_ring[entry].bufptr = virt_to_bus(skb->tail);
+		}
+	}
+	/* re-enable the potentially idle receive state matchine */
+	outl(RxENA , ioaddr + cr );
+	
         return 0;
 }
 
+/* finish up transmission of packets, check for error condition and free skbuff etc.
+   Note: This fucntion is called by interrupt handler, don't do "too much" work here */
+static void sis900_finish_xmit (struct device *net_dev)
+{
+	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+	
+	for (; sis_priv->dirty_tx < sis_priv->cur_tx; sis_priv->dirty_tx++) {
+		unsigned int entry;
+		u32 tx_status;
+		
+		entry = sis_priv->dirty_tx % NUM_TX_DESC;
+	        tx_status = sis_priv->tx_ring[entry].cmdsts;
+		
+		if (tx_status & OWN) {
+			/* The packet is not transmited yet (owned by hardware) ! */
+			break;
+		}
+		
+		if (tx_status & (ABORT | UNDERRUN | OWCOLL)) {
+			/* packet unsuccessfully transmited */
+			if (sis900_debug > 3)
+				printk(KERN_INFO "%s: Transmit "
+				       "error, Tx status %8.8x.\n",
+				       net_dev->name, tx_status);
+			sis_priv->stats.tx_errors++;
+			if (tx_status & UNDERRUN)
+				sis_priv->stats.tx_fifo_errors++;
+			if (tx_status & ABORT)
+				sis_priv->stats.tx_aborted_errors++;
+			if (tx_status & NOCARRIER)
+				sis_priv->stats.tx_carrier_errors++;
+			if (tx_status & OWCOLL)
+				sis_priv->stats.tx_window_errors++;
+		} else {
+			/* packet successfully transmited */
+			if (sis900_debug > 3)
+				printk(KERN_INFO "Tx Transmit OK\n");
+			sis_priv->stats.collisions += (tx_status & COLCNT) >> 16;
+			sis_priv->stats.tx_bytes += tx_status & DSIZE;
+			sis_priv->stats.tx_packets++;
+		}
+		/* Free the original skb. */
+		dev_kfree_skb(sis_priv->tx_skbuff[entry]);
+		sis_priv->tx_skbuff[entry] = NULL;
+		sis_priv->tx_ring[entry].bufptr = 0;
+		sis_priv->tx_ring[entry].cmdsts = 0;
+	}
+	
+	if (sis_priv->tx_full && net_dev->tbusy && 
+	    sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) {
+		/* The ring is no longer full, clear tbusy, tx_full and schedule 
+		   more transmission by marking NET_BH */
+		sis_priv->tx_full = 0;
+		clear_bit(0, (void *)&net_dev->tbusy);
+		mark_bh(NET_BH);
+	}
+}
+
 static int
-sis900_close(struct device *dev)
+sis900_close(struct device *net_dev)
 {
-        long ioaddr = dev->base_addr;
-        struct sis900_private *tp = (struct sis900_private *)dev->priv;
+        long ioaddr = net_dev->base_addr;
+        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
         int i;
-
-        dev->start = 0;
-        dev->tbusy = 1;
-
-        if (sis900_debug > 1)
-                printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n",
-                           dev->name, inl(ioaddr + isr));
+	
+        net_dev->start = 0;
+        net_dev->tbusy = 1;
 
         /* Disable interrupts by clearing the interrupt mask. */
         outl(0x0000, ioaddr + imr);
+	outl(0x0000, ioaddr + ier);
 
-        /* Stop the chip's Tx and Rx DMA processes. */
-        outl(0x00, ioaddr + cr);
+        /* Stop the chip's Tx and Rx Status Machine */
+        outl(RxDIS | TxDIS, ioaddr + cr);
 
-        del_timer(&tp->timer);
+        del_timer(&sis_priv->timer);
 
-        free_irq(dev->irq, dev);
+        free_irq(net_dev->irq, net_dev);
 
+	/* Free Tx and RX skbuff */
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		if (sis_priv->rx_skbuff[i] != NULL)
+			dev_kfree_skb(sis_priv->rx_skbuff[i]);
+		sis_priv->rx_skbuff[i] = 0;
+	}
         for (i = 0; i < NUM_TX_DESC; i++) {
-                if (tp->tx_skbuff[i])
-                        dev_free_skb(tp->tx_skbuff[i]);
-                tp->tx_skbuff[i] = 0;
+                if (sis_priv->tx_skbuff[i] != NULL)
+                        dev_kfree_skb(sis_priv->tx_skbuff[i]);
+                sis_priv->tx_skbuff[i] = 0;
         }
-        kfree(tp->rx_bufs);
-        kfree(tp->tx_bufs);
 
         /* Green! Put the chip in low-power mode. */
 
@@ -1575,22 +1117,22 @@
         return 0;
 }
 
-static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+static int mii_ioctl(struct device *net_dev, struct ifreq *rq, int cmd)
 {
-        struct sis900_private *tp = (struct sis900_private *)dev->priv;
+        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
         u16 *data = (u16 *)&rq->ifr_data;
 
         switch(cmd) {
-        case SIOCDEVPRIVATE:            /* Get the address of the PHY in use. */
-                data[0] = tp->phys[tp->phy_idx];
+        case SIOCDEVPRIVATE:            	/* Get the address of the PHY in use. */
+                data[0] = sis_priv->mii->phy_addr;
                 /* Fall Through */
-        case SIOCDEVPRIVATE+1:          /* Read the specified MII register. */
-                data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
+        case SIOCDEVPRIVATE+1:          	/* Read the specified MII register. */
+                data[3] = mdio_read(net_dev, data[0] & 0x1f, data[1] & 0x1f);
                 return 0;
-        case SIOCDEVPRIVATE+2:          /* Write the specified MII register */
+        case SIOCDEVPRIVATE+2:          	/* Write the specified MII register */
                 if (!suser())
                         return -EPERM;
-                mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+                mdio_write(net_dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
                 return 0;
         default:
                 return -EOPNOTSUPP;
@@ -1598,326 +1140,140 @@
 }
 
 static struct enet_statistics *
-sis900_get_stats(struct device *dev)
-{
-        struct sis900_private *tp = (struct sis900_private *)dev->priv;
-
-        return &tp->stats;
-}
-
-/* Set or clear the multicast filter for this adaptor.
-   This routine is not state sensitive and need not be SMP locked. */
-
-static u16 elComputeHashTableIndex(u8 *addr)
-{
-#define POLYNOMIAL 0x04C11DB6L
-    u32      crc = 0xffffffff, msb;
-    int      i, j;
-    u8       byte;
-
-    for( i=0; i<6; i++ ) {
-        byte = *addr++;
-        for( j=0; j<8; j++ ) {
-            msb = crc >> 31;
-            crc <<= 1;
-            if( msb ^ ( byte & 1 )) {
-                crc ^= POLYNOMIAL;
-                crc |= 1;
-            }
-            byte >>= 1;
-        }
-    }
-    // 7 bit crc for 128 bit hash table
-    return( (int)(crc >> 25) );
-}
-
-static u16 elMIIpollBit(struct device *dev,
-                         int phy_id,
-                         int location,
-                         u16 mask,
-                         u16 polarity,
-                         u16 *value)
-{
-        u32 i;
-        i=0;
-        while (1) {
-                *value = mdio_read(dev, phy_id, location);
-                if (polarity) {
-                        if (mask & *value) return(TRUE);
-                } else {
-                        if (mask & ~(*value)) return(TRUE);
-                }
-                if (++i == 1200) break;
-        }
-        return(FALSE);
-}
-
-static u16 elPMDreadMode(struct device *dev,
-                         int phy_id,
-                         int *speed,
-                         int *duplex)
-{
-        u16 status, OurCap;
-
-        *speed = HW_SPEED_10_MBPS;
-        *duplex = FDX_CAPABLE_HALF_SELECTED;
-
-        status = mdio_read(dev, phy_id, MII_ANLPAR);
-        OurCap = mdio_read(dev, phy_id, MII_ANAR);
-	if (sis900_debug > 1) {
-		printk(KERN_INFO "Link Part Status %4X\n", status);
-		printk(KERN_INFO "Our Status %4X\n", OurCap);
-		printk(KERN_INFO "Status Reg %4X\n",
-					mdio_read(dev, phy_id, MII_STATUS));
-	}
-	status &= OurCap;
-
-        if ( !( status &
-                (MII_NWAY_T|MII_NWAY_T_FDX | MII_NWAY_TX | MII_NWAY_TX_FDX ))) {
-		if (sis900_debug > 1) {
-			printk(KERN_INFO "The other end NOT support NWAY...\n");
-		}
-                while (( status = mdio_read(dev, phy_id, 18)) & 0x4000) ;
-                while (( status = mdio_read(dev, phy_id, 18)) & 0x0020) ;
-                if (status & 0x80)
-                        *speed = HW_SPEED_100_MBPS;
-                if (status & 0x40)
-                        *duplex = FDX_CAPABLE_FULL_SELECTED;
-                if (sis900_debug > 3) {
-                        printk(KERN_INFO"%s: Setting %s%s-duplex.\n",
-                                dev->name,
-                                *speed == HW_SPEED_100_MBPS ?
-                                        "100mbps " : "10mbps ",
-                                *duplex == FDX_CAPABLE_FULL_SELECTED ?
-                                        "full" : "half");
-                }
-        } else {
-		if (sis900_debug > 1) {
-			printk(KERN_INFO "The other end support NWAY...\n");
-		}
-
-                if (status & (MII_NWAY_TX_FDX | MII_NWAY_T_FDX)) {
-                        *duplex = FDX_CAPABLE_FULL_SELECTED;
-                }
-                if (status & (MII_NWAY_TX_FDX | MII_NWAY_TX)) {
-                        *speed = HW_SPEED_100_MBPS;
-                }
-                if (sis900_debug > 3) {
-                        printk(KERN_INFO"%s: Setting %s%s-duplex based on"
-                                " auto-negotiated partner ability.\n",
-                                dev->name,
-                                *speed == HW_SPEED_100_MBPS ?
-                                        "100mbps " : "10mbps ",
-                                *duplex == FDX_CAPABLE_FULL_SELECTED ?
-                                        "full" : "half");
-                }
-        }
-        return (status);
-}
-
-static u16 elAutoNegotiate(struct device *dev, int phy_id, int *duplex, int *speed)
+sis900_get_stats(struct device *net_dev)
 {
-        u16 status, retnVal;
+        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
 
-	if (sis900_debug > 1) {
-		printk(KERN_INFO "AutoNegotiate...\n");
-	}
-        mdio_write(dev, phy_id, MII_CONTROL, 0);
-        mdio_write(dev, phy_id, MII_CONTROL, MIICNTL_AUTO | MIICNTL_RST_AUTO);
-        retnVal = elMIIpollBit(dev, phy_id, MII_CONTROL, MIICNTL_RST_AUTO,
-				FALSE,&status);
-	if (!retnVal) {
-		printk(KERN_INFO "Not wait for Reset Complete\n");
-	}
-        retnVal = elMIIpollBit(dev, phy_id, MII_STATUS, MIISTAT_AUTO_DONE,
-				TRUE, &status);
-	if (!retnVal) {
-		printk(KERN_INFO "Not wait for AutoNego Complete\n");
-	}
-        retnVal = elMIIpollBit(dev, phy_id, MII_STATUS, MIISTAT_LINK,
-				TRUE, &status);
-	if (!retnVal) {
-		printk(KERN_INFO "Not wait for Link Complete\n");
-	}
-        if (status & MIISTAT_LINK) {
-                elPMDreadMode(dev, phy_id, speed, duplex);
-                elSetMediaType(dev, *speed, *duplex);
-        }
-        return(status);
+        return &sis_priv->stats;
 }
 
-static void elSetCapability(struct device *dev, int phy_id,
-			    int duplex, int speed)
+/* SiS 900 uses the most sigificant 7 bits to index a 128 bits multicast hash table, which makes
+   this function a little bit different from other drivers */
+static u16 sis900_compute_hashtable_index(u8 *addr)
 {
-        u16 cap = ( MII_NWAY_T  | MII_NWAY_T_FDX  |
-		    MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_CSMA_CD );
 
-	if (speed != 100) {
-		cap &= ~( MII_NWAY_TX | MII_NWAY_TX_FDX );
-		if (sis900_debug > 1) {
-			printk(KERN_INFO "UNSET 100Mbps\n");
-		}
-	}
-
-	if (!duplex) {
-		cap &= ~( MII_NWAY_T_FDX | MII_NWAY_TX_FDX );
-		if (sis900_debug > 1) {
-			printk(KERN_INFO "UNSET full-duplex\n");
+/* what is the correct value of the POLYNOMIAL ??
+   Donald Becker use 0x04C11DB7U */
+#define POLYNOMIAL 0x04C11DB6L
+	u32 crc = 0xffffffff, msb;
+	int  i, j;
+	u8  byte;
+
+	for (i = 0; i < 6; i++) {
+		byte = *addr++;
+		for (j = 0; j < 8; j++) {
+			msb = crc >> 31;
+			crc <<= 1;
+			if (msb ^ (byte & 1)) {
+				crc ^= POLYNOMIAL;
+				crc |= 1;
+			}
+			byte >>= 1;
 		}
 	}
-
-        mdio_write(dev, phy_id, MII_ANAR, cap);
+	/* leave 7 most siginifant bits */ 
+	return ((int)(crc >> 25));
 }
 
-static void elSetMediaType(struct device *dev, int speed, int duplex)
+static void set_rx_mode(struct device *net_dev)
 {
-        long ioaddr = dev->base_addr;
-        u32     txCfgOn = 0, txCfgOff = TxDRNT;
-        u32     rxCfgOn = 0, rxCfgOff = 0;
-
-        if (speed == HW_SPEED_100_MBPS) {
-                txCfgOn |= (TxDRNT_100 | TxHBI);
-        } else {
-                txCfgOn |= TxDRNT_10;
-        }
-
-        if (duplex == FDX_CAPABLE_FULL_SELECTED) {
-                txCfgOn |= (TxCSI | TxHBI);
-                rxCfgOn |= RxATP;
-        } else {
-                txCfgOff |= (TxCSI | TxHBI);
-                rxCfgOff |= RxATP;
-        }
-        outl( (inl(ioaddr + txcfg) & ~txCfgOff) | txCfgOn, ioaddr + txcfg);
-        outl( (inl(ioaddr + rxcfg) & ~rxCfgOff) | rxCfgOn, ioaddr + rxcfg);
-}
-
-static void set_rx_mode(struct device *dev)
-{
-        long ioaddr = dev->base_addr;
-        u16 mc_filter[8];
+        long ioaddr = net_dev->base_addr;
+        u16 mc_filter[8];			/* 128 bits multicast hash table */
         int i;
-        int rx_mode;
-        u32 rxCfgOn = 0, rxCfgOff = 0;
-        u32 txCfgOn = 0, txCfgOff = 0;
+        u32 rx_mode;
 
-        if (sis900_debug > 3)
-                printk(KERN_INFO "%s: set_rx_mode (%4.4x) done--"
-                                "RxCfg %8.8x.\n",
-                                dev->name, dev->flags, inl(ioaddr + rxcfg));
-
-        /* Note: do not reorder, GCC is clever about common statements. */
-        if (dev->flags & IFF_PROMISC) {
-                printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name);
-                rx_mode = ACCEPT_ALL_BCASTS | ACCEPT_ALL_MCASTS |
-                                ACCEPT_CAM_QUALIFIED | ACCEPT_ALL_PHYS;
-                for (i=0 ; i<8 ; i++)
-                        mc_filter[i]=0xffff;
-        } else if ((dev->mc_count > multicast_filter_limit)
-                           ||  (dev->flags & IFF_ALLMULTI)) {
-                rx_mode = ACCEPT_ALL_BCASTS | ACCEPT_ALL_MCASTS |
-                                ACCEPT_CAM_QUALIFIED;
-                for (i=0 ; i<8 ; i++)
-                        mc_filter[i]=0xffff;
+        if (net_dev->flags & IFF_PROMISC) {
+		/* Accept any kinds of packets */
+		rx_mode = RFPromiscuous;
+                for (i = 0; i < 8; i++)
+                        mc_filter[i] = 0xffff;
+        } else if ((net_dev->mc_count > multicast_filter_limit) ||
+		   (net_dev->flags & IFF_ALLMULTI)) {
+		/* too many multicast addresses or accept all multicast packet */
+                rx_mode = RFAAB | RFAAM;
+                for (i = 0; i < 8; i++)
+                        mc_filter[i] = 0xffff;
         } else {
+		/* Accept Broadcast packet, destination address matchs our MAC address,
+		   use Receive Filter to reject unwanted MCAST packet */
                 struct dev_mc_list *mclist;
-                rx_mode = ACCEPT_ALL_BCASTS | ACCEPT_ALL_MCASTS |
-                                ACCEPT_CAM_QUALIFIED;
-                for (i=0 ; i<8 ; i++)
+                rx_mode = RFAAB;
+                for (i = 0; i < 8; i++)
                         mc_filter[i]=0;
-                for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-                         i++, mclist = mclist->next)
-                        set_bit(elComputeHashTableIndex(mclist->dmi_addr),
-                                                mc_filter);
+                for (i = 0, mclist = net_dev->mc_list; mclist && i < net_dev->mc_count;
+		     i++, mclist = mclist->next)
+                        set_bit(sis900_compute_hashtable_index(mclist->dmi_addr),
+				mc_filter);
         }
 
-        for (i=0 ; i<8 ; i++) {
-                outl((u32)(0x00000004+i) << 16, ioaddr + rfcr);
+	/* update Multicast Hash Table in Receive Filter */
+        for (i = 0; i < 8; i++) {
+		/* why plus 0x04 ??, I don't know, UNDOCUMENT FEATURE ?? */
+                outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr);
                 outl(mc_filter[i], ioaddr + rfdr);
         }
-        /* We can safely update without stopping the chip. */
-        //rx_mode = ACCEPT_CAM_QUALIFIED | ACCEPT_ALL_BCASTS | ACCEPT_ALL_PHYS;
-        //rx_mode = ACCEPT_CAM_QUALIFIED | ACCEPT_ALL_BCASTS;
-        outl(RFEN | ((rx_mode & (ACCEPT_ALL_MCASTS | ACCEPT_ALL_BCASTS |
-                          ACCEPT_ALL_PHYS)) << RFAA_shift), ioaddr + rfcr);
-
-        if (rx_mode & ACCEPT_ALL_ERRORS) {
-                rxCfgOn = RxAEP | RxARP | RxAJAB;
-        } else {
-                rxCfgOff = RxAEP | RxARP | RxAJAB;
-        }
-        if (rx_mode & MAC_LOOPBACK) {
-                rxCfgOn |= RxATP;
-                txCfgOn |= TxMLB;
-        } else {
-                if (!(( (struct sis900_private *)(dev->priv) )->full_duplex))
-                        rxCfgOff |= RxATP;
-                txCfgOff |= TxMLB;
-        }
 
-        if (sis900_debug > 2) {
-                printk(KERN_INFO "Before Set TxCfg=%8.8x\n",inl(ioaddr+txcfg));
-                printk(KERN_INFO "Before Set RxCfg=%8.8x\n",inl(ioaddr+rxcfg));
-        }
+        outl(RFEN | rx_mode, ioaddr + rfcr);
 
-        outl((inl(ioaddr + rxcfg) | rxCfgOn) & ~rxCfgOff, ioaddr + rxcfg);
-        outl((inl(ioaddr + txcfg) | txCfgOn) & ~txCfgOff, ioaddr + txcfg);
+	/* sis900 is capatable of looping back packet at MAC level for debugging purpose */
+	if (net_dev->flags & IFF_LOOPBACK) {
+		u32 cr_saved;
+		/* We must disable Tx/Rx before setting loopback mode */
+		cr_saved = inl(ioaddr + cr);
+		outl(cr_saved | TxDIS | RxDIS, ioaddr + cr);
+		/* enable loopback */
+		outl(inl(ioaddr + txcfg) | TxMLB, ioaddr + txcfg);
+		outl(inl(ioaddr + rxcfg) | RxATX, ioaddr + rxcfg);
+		/* restore cr */
+		outl(cr_saved, ioaddr + cr);
+	}		
 
-        if (sis900_debug > 2) {
-                printk(KERN_INFO "After Set TxCfg=%8.8x\n",inl(ioaddr+txcfg));
-                printk(KERN_INFO "After Set RxCfg=%8.8x\n",inl(ioaddr+rxcfg));
-                printk(KERN_INFO "Receive Filter Register:%8.8x\n",
-                                                        inl(ioaddr + rfcr));
-        }
         return;
 }
 
-static void sis900_reset(struct device *dev)
+static void sis900_reset(struct device *net_dev)
 {
-        long ioaddr = dev->base_addr;
+        long ioaddr = net_dev->base_addr;
+	int i = 0;
+	u32 status = TxRCMP | RxRCMP;
 
         outl(0, ioaddr + ier);
         outl(0, ioaddr + imr);
         outl(0, ioaddr + rfcr);
 
         outl(RxRESET | TxRESET | RESET, ioaddr + cr);
-        outl(PESEL, ioaddr + cfg);
+	
+	/* Check that the chip has finished the reset. */
+	while (status && (i++ < 1000)) {
+		status ^= (inl(isr + ioaddr) & status);
+        }
 
-        set_rx_mode(dev);
+        outl(PESEL, ioaddr + cfg);
 }
 
 #ifdef MODULE
 int init_module(void)
 {
-        return sis900_probe(0);
+        return sis900_probe(NULL);
 }
 
 void
 cleanup_module(void)
 {
-        struct device *next_dev;
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_sis900_dev) {
+		struct sis900_private *sis_priv =
+			(struct sis900_private *)root_sis900_dev->priv;
+		struct device *next_dev = sis_priv->next_module;
+		
+		unregister_netdev(root_sis900_dev);
+		release_region(root_sis900_dev->base_addr,
+			       sis_priv->mac->io_size);
+		kfree(sis_priv);
+		kfree(root_sis900_dev);
 
-        /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-        while (root_sis900_dev) {
-                struct sis900_private *tp =
-                        (struct sis900_private *)root_sis900_dev->priv;
-                next_dev = tp->next_module;
-                unregister_netdev(root_sis900_dev);
-                release_region(root_sis900_dev->base_addr,
-                                           pci_tbl[tp->chip_id].io_size);
-                kfree(tp);
-                kfree(root_sis900_dev);
-                root_sis900_dev = next_dev;
+		root_sis900_dev = next_dev;
         }
 }
 
 #endif  /* MODULE */
-/*
- * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c sis900.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c sis900.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sis900.h linux.14p16/drivers/net/sis900.h
--- linux.vanilla/drivers/net/sis900.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sis900.h	Thu Dec  9 15:33:33 1999
@@ -0,0 +1,248 @@
+/* sis900.h Definitions for SiS ethernet controllers including 7014/7016 and 900 
+ * Copyright 1999 Silicon Integrated System Corporation
+ * References:
+ *   SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
+ *	preliminary Rev. 1.0 Jan. 14, 1998
+ *   SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support,
+ *	preliminary Rev. 1.0 Nov. 10, 1998
+ *   SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
+ *	preliminary Rev. 1.0 Jan. 18, 1998
+ *   http://www.sis.com.tw/support/databook.htm
+ */
+
+/* MAC operationl registers of SiS 7016 and SiS 900 ehternet controller */
+/* The I/O extent, SiS 900 needs 256 bytes of io address */
+#define SIS900_TOTAL_SIZE 0x100
+
+/* Symbolic offsets to registers. */
+enum sis900_registers {
+	cr=0x0,                 //Command Register
+	cfg=0x4,                //Configuration Register
+	mear=0x8,               //EEPROM Access Register
+	ptscr=0xc,              //PCI Test Control Register
+	isr=0x10,               //Interrupt Status Register
+	imr=0x14,               //Interrupt Mask Register
+	ier=0x18,               //Interrupt Enable Register
+	epar=0x18,              //Enhanced PHY Access Register
+	txdp=0x20,              //Transmit Descriptor Pointer Register
+        txcfg=0x24,             //Transmit Configuration Register
+        rxdp=0x30,              //Receive Descriptor Pointer Register
+        rxcfg=0x34,             //Receive Configuration Register
+        flctrl=0x38,            //Flow Control Register
+        rxlen=0x3c,             //Receive Packet Length Register
+        rfcr=0x48,              //Receive Filter Control Register
+        rfdr=0x4C,              //Receive Filter Data Register
+        pmctrl=0xB0,            //Power Management Control Register
+        pmer=0xB4               //Power Management Wake-up Event Register
+};
+
+/* Symbolic names for bits in various registers */
+enum sis900_command_register_bits {
+	RESET   = 0x00000100, SWI = 0x00000080, RxRESET = 0x00000020,
+	TxRESET = 0x00000010, RxDIS = 0x00000008, RxENA = 0x00000004,
+	TxDIS   = 0x00000002, TxENA = 0x00000001
+};
+
+enum sis900_configuration_register_bits {
+	DESCRFMT = 0x00000100 /* 7016 specific */, REQALG = 0x00000080,
+	SB    = 0x00000040, POW = 0x00000020, EXD = 0x00000010, 
+	PESEL = 0x00000008, LPM = 0x00000004, BEM = 0x00000001
+};
+
+enum sis900_eeprom_access_reigster_bits {
+	MDC  = 0x00000040, MDDIR = 0x00000020, MDIO = 0x00000010, /* 7016 specific */ 
+	EECS = 0x00000008, EECLK = 0x00000004, EEDO = 0x00000002,
+	EEDI = 0x00000001
+};
+
+enum sis900_interrupt_register_bits {
+	WKEVT  = 0x10000000, TxPAUSEEND = 0x08000000, TxPAUSE = 0x04000000,
+	TxRCMP = 0x02000000, RxRCMP = 0x01000000, DPERR = 0x00800000,
+	SSERR  = 0x00400000, RMABT  = 0x00200000, RTABT = 0x00100000,
+	RxSOVR = 0x00010000, HIBERR = 0x00008000, SWINT = 0x00001000,
+	MIBINT = 0x00000800, TxURN  = 0x00000400, TxIDLE  = 0x00000200,
+	TxERR  = 0x00000100, TxDESC = 0x00000080, TxOK  = 0x00000040,
+	RxORN  = 0x00000020, RxIDLE = 0x00000010, RxEARLY = 0x00000008,
+	RxERR  = 0x00000004, RxDESC = 0x00000002, RxOK  = 0x00000001
+};
+
+enum sis900_interrupt_enable_reigster_bits {
+	IE = 0x00000001
+};
+
+/* maximum dma burst fro transmission and receive*/
+#define MAX_DMA_RANGE	7	/* actually 0 means MAXIMUM !! */
+#define TxMXDMA_shift   	20
+#define RxMXDMA_shift    20
+#define TX_DMA_BURST    	0
+#define RX_DMA_BURST    	0
+
+/* transmit FIFO threshholds */
+#define TX_FILL_THRESH   16	/* 1/4 FIFO size */
+#define TxFILLT_shift   	8
+#define TxDRNT_shift    	0
+#define TxDRNT_100      	48	/* 3/4 FIFO size */
+#define TxDRNT_10		16 	/* 1/2 FIFO size */
+
+enum sis900_transmit_config_register_bits {
+	TxCSI = 0x80000000, TxHBI = 0x40000000, TxMLB = 0x20000000,
+	TxATP = 0x10000000, TxIFG = 0x0C000000, TxFILLT = 0x00003F00,
+	TxDRNT = 0x0000003F
+};
+
+/* recevie FIFO thresholds */
+#define RxDRNT_shift     1
+#define RxDRNT_100	24	/* 3/4 FIFO size */
+#define RxDRNT_10		16 	/* 1/2 FIFO size */
+
+enum sis900_reveive_config_register_bits {
+	RxAEP  = 0x80000000, RxARP = 0x40000000, RxATX = 0x10000000,
+	RxAJAB = 0x08000000, RxDRNT = 0x0000007F
+};
+
+#define RFAA_shift      28
+#define RFADDR_shift    16
+
+enum sis900_receive_filter_control_register_bits {
+	RFEN  = 0x80000000, RFAAB = 0x40000000, RFAAM = 0x20000000,
+	RFAAP = 0x10000000, RFPromiscuous = (RFAAB|RFAAM|RFAAP)
+};
+
+enum sis900_reveive_filter_data_mask {
+	RFDAT =  0x0000FFFF
+};
+
+/* EEPROM Addresses */
+enum sis900_eeprom_address {
+	EEPROMSignature = 0x00, EEPROMVendorID = 0x02, EEPROMDeviceID = 0x03,
+	EEPROMMACAddr   = 0x08, EEPROMChecksum = 0x0b
+};
+
+/* The EEPROM commands include the alway-set leading bit. Refer to NM93Cxx datasheet */
+enum sis900_eeprom_command {
+	EEread     = 0x0180, EEwrite    = 0x0140, EEerase = 0x01C0, 
+	EEwriteEnable = 0x0130, EEwriteDisable = 0x0100,
+	EEeraseAll = 0x0120, EEwriteAll = 0x0110, 
+	EEaddrMask = 0x013F, EEcmdShift = 16
+};
+
+/* Manamgement Data I/O (mdio) frame */
+#define MIIread         0x6000
+#define MIIwrite        0x5002
+#define MIIpmdShift     7
+#define MIIregShift     2
+#define MIIcmdLen       16
+#define MIIcmdShift     16
+
+/* Buffer Descriptor Status*/
+enum sis900_buffer_status {
+	OWN    = 0x80000000, MORE   = 0x40000000, INTR = 0x20000000,
+	SUPCRC = 0x10000000, INCCRC = 0x10000000,
+	OK     = 0x08000000, DSIZE  = 0x00000FFF
+};
+/* Status for TX Buffers */
+enum sis900_tx_buffer_status {
+	ABORT   = 0x04000000, UNDERRUN = 0x02000000, NOCARRIER = 0x01000000,
+	DEFERD  = 0x00800000, EXCDEFER = 0x00400000, OWCOLL    = 0x00200000,
+	EXCCOLL = 0x00100000, COLCNT   = 0x000F0000
+};
+
+enum sis900_rx_bufer_status {
+	OVERRUN = 0x02000000, DEST = 0x00800000,     BCAST = 0x01800000,
+	MCAST   = 0x01000000, UNIMATCH = 0x00800000, TOOLONG = 0x00400000,
+	RUNT    = 0x00200000, RXISERR  = 0x00100000, CRCERR  = 0x00080000,
+	FAERR   = 0x00040000, LOOPBK   = 0x00020000, RXCOL   = 0x00010000
+};
+
+/* MII register offsets */
+enum mii_registers {
+	MII_CONTROL = 0x0000, MII_STATUS = 0x0001, MII_PHY_ID0 = 0x0002,
+	MII_PHY_ID1 = 0x0003, MII_ANADV  = 0x0004, MII_ANLPAR  = 0x0005,
+	MII_ANEXT   = 0x0006
+};
+
+/* mii registers specific to SiS 900 */
+enum sis_mii_registers {
+	MII_CONFIG1 = 0x0010, MII_CONFIG2 = 0x0011, MII_STSOUT = 0x0012,
+	MII_MASK    = 0x0013
+};
+
+/* mii registers specific to AMD 79C901 */
+enum amd_mii_registers {
+	MII_STATUS_SUMMARY = 0x0018
+};
+
+/* MII Control register bit definitions. */
+enum mii_control_register_bits {
+	MII_CNTL_FDX     = 0x0100, MII_CNTL_RST_AUTO = 0x0200, 
+	MII_CNTL_ISOLATE = 0x0400, MII_CNTL_PWRDWN   = 0x0800,
+	MII_CNTL_AUTO    = 0x1000, MII_CNTL_SPEED    = 0x2000,
+	MII_CNTL_LPBK    = 0x4000, MII_CNTL_RESET    = 0x8000
+};
+
+/* MII Status register bit  */
+enum mii_status_register_bits {
+	MII_STAT_EXT    = 0x0001, MII_STAT_JAB        = 0x0002, 
+	MII_STAT_LINK   = 0x0004, MII_STAT_CAN_AUTO   = 0x0008, 
+	MII_STAT_FAULT  = 0x0010, MII_STAT_AUTO_DONE  = 0x0020,
+	MII_STAT_CAN_T  = 0x0800, MII_STAT_CAN_T_FDX  = 0x1000,
+	MII_STAT_CAN_TX = 0x2000, MII_STAT_CAN_TX_FDX = 0x4000,
+	MII_STAT_CAN_T4 = 0x8000
+};
+
+#define		MII_ID1_OUI_LO		0xFC00	/* low bits of OUI mask */
+#define		MII_ID1_MODEL		0x03F0	/* model number */
+#define		MII_ID1_REV		0x000F	/* model number */
+
+/* MII NWAY Register Bits ...
+   valid for the ANAR (Auto-Negotiation Advertisement) and
+   ANLPAR (Auto-Negotiation Link Partner) registers */
+enum mii_nway_register_bits {
+	MII_NWAY_NODE_SEL = 0x001f, MII_NWAY_CSMA_CD = 0x0001,
+	MII_NWAY_T	  = 0x0020, MII_NWAY_T_FDX   = 0x0040,
+	MII_NWAY_TX       = 0x0080, MII_NWAY_TX_FDX  = 0x0100,
+	MII_NWAY_T4       = 0x0200, MII_NWAY_PAUSE   = 0x0400,
+	MII_NWAY_RF       = 0x2000, MII_NWAY_ACK     = 0x4000,
+	MII_NWAY_NP       = 0x8000
+};
+
+enum mii_stsout_register_bits {
+	MII_STSOUT_LINK_FAIL = 0x4000,
+	MII_STSOUT_SPD       = 0x0080, MII_STSOUT_DPLX = 0x0040
+};
+
+enum mii_stssum_register_bits {
+	MII_STSSUM_LINK = 0x0008, MII_STSSUM_DPLX = 0x0004,
+	MII_STSSUM_AUTO = 0x0002, MII_STSSUM_SPD  = 0x0001
+};
+
+#define FDX_CAPABLE_DUPLEX_UNKNOWN      0
+#define FDX_CAPABLE_HALF_SELECTED       1
+#define FDX_CAPABLE_FULL_SELECTED       2
+
+#define HW_SPEED_UNCONFIG		0
+#define HW_SPEED_HOME		1
+#define HW_SPEED_10_MBPS        	10
+#define HW_SPEED_100_MBPS       	100
+#define HW_SPEED_DEFAULT        	(HW_SPEED_100_MBPS)
+
+#define CRC_SIZE                4
+#define MAC_HEADER_SIZE         14
+
+#define TX_BUF_SIZE     1536
+#define RX_BUF_SIZE     1536
+
+#define NUM_TX_DESC     16      	/* Number of Tx descriptor registers. */
+#define NUM_RX_DESC     16       	/* Number of Rx descriptor registers. */
+
+#define TRUE            1
+#define FALSE           0
+
+/* PCI stuff, should be move to pic.h */
+#define PCI_DEVICE_ID_SI_900	0x900   
+#define PCI_DEVICE_ID_SI_7016	0x7016  
+
+/* ioctl for accessing MII transveiver */
+#define SIOCGMIIPHY (SIOCDEVPRIVATE)		/* Get the PHY in use. */
+#define SIOCGMIIREG (SIOCDEVPRIVATE+1)		/* Read a PHY register. */
+#define SIOCSMIIREG (SIOCDEVPRIVATE+2)		/* Write a PHY register */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/Makefile linux.14p16/drivers/net/sk98lin/Makefile
--- linux.vanilla/drivers/net/sk98lin/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/Makefile	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,80 @@
+# File: drivers/sk98lin/Makefile
+#
+# Makefile for the SysKonnect SK-98xx device driver.
+#
+
+ifeq ($(CONFIG_SK98LIN),y)
+    O_TARGET := sk98lin.o
+    O_OBJS = skge.o skaddr.o skgehwt.o skgeinit.o skgepnmi.o skgesirq.o \
+             ski2c.o sklm80.o skqueue.o skrlmt.o sktimer.o skvpd.o \
+             skxmac2.o skcsum.o
+else
+  ifeq ($(CONFIG_SK98LIN),m)
+    MOD_LIST_NAME := SK98LIN_MODULES
+    M_OBJS := sk98lin.o
+    O_TARGET := sk98lin.o
+    O_OBJS = skge.o skaddr.o skgehwt.o skgeinit.o skgepnmi.o skgesirq.o \
+             ski2c.o sklm80.o skqueue.o skrlmt.o sktimer.o skvpd.o \
+             skxmac2.o skcsum.o
+  endif
+endif
+
+# DBGDEF =  \
+# -DDEBUG
+
+ifdef DEBUG
+DBGDEF +=  \
+-DSK_DEBUG_CHKMOD=0x00000000L \
+-DSK_DEBUG_CHKCAT=0x00000000L
+endif
+
+
+# **** possible debug modules for SK_DEBUG_CHKMOD *****************
+# SK_DBGMOD_MERR        0x00000001L     /* general module error indication */
+# SK_DBGMOD_HWM         0x00000002L     /* Hardware init module */
+# SK_DBGMOD_RLMT        0x00000004L     /* RLMT module */
+# SK_DBGMOD_VPD         0x00000008L     /* VPD module */
+# SK_DBGMOD_I2C         0x00000010L     /* I2C module */
+# SK_DBGMOD_PNMI        0x00000020L     /* PNMI module */
+# SK_DBGMOD_CSUM        0x00000040L     /* CSUM module */
+# SK_DBGMOD_ADDR        0x00000080L     /* ADDR module */
+# SK_DBGMOD_DRV         0x00010000L     /* DRV module */
+
+# **** possible debug categories for SK_DEBUG_CHKCAT **************
+# *** common modules ***
+# SK_DBGCAT_INIT        0x00000001L     module/driver initialization
+# SK_DBGCAT_CTRL        0x00000002L     controlling: add/rmv MCA/MAC and other controls (IOCTL)
+# SK_DBGCAT_ERR         0x00000004L     error handling paths
+# SK_DBGCAT_TX          0x00000008L     transmit path
+# SK_DBGCAT_RX          0x00000010L     receive path
+# SK_DBGCAT_IRQ         0x00000020L     general IRQ handling
+# SK_DBGCAT_QUEUE       0x00000040L     any queue management
+# SK_DBGCAT_DUMP        0x00000080L     large data output e.g. hex dump
+# SK_DBGCAT_FATAL       0x00000100L     large data output e.g. hex dump
+
+# *** driver (file skge.c) ***
+# SK_DBGCAT_DRV_ENTRY           0x00010000      entry points
+# SK_DBGCAT_DRV_???             0x00020000      not used
+# SK_DBGCAT_DRV_MCA             0x00040000      multicast
+# SK_DBGCAT_DRV_TX_PROGRESS     0x00080000      tx path
+# SK_DBGCAT_DRV_RX_PROGRESS     0x00100000      rx path
+# SK_DBGCAT_DRV_PROGRESS        0x00200000      general runtime
+# SK_DBGCAT_DRV_???             0x00400000      not used
+# SK_DBGCAT_DRV_PROM            0x00800000      promiscuous mode
+# SK_DBGCAT_DRV_TX_FRAME        0x01000000      display tx frames
+# SK_DBGCAT_DRV_ERROR           0x02000000      error conditions
+# SK_DBGCAT_DRV_INT_SRC         0x04000000      interrupts sources
+# SK_DBGCAT_DRV_EVENT           0x08000000      driver events
+
+EXTRA_CFLAGS += -I. -DSK_USE_CSUM $(DBGDEF)
+
+include $(TOPDIR)/Rules.make
+
+clean:
+	rm -f core *.o *.a *.s
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/lm80.h linux.14p16/drivers/net/sk98lin/h/lm80.h
--- linux.vanilla/drivers/net/sk98lin/h/lm80.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/lm80.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,192 @@
+/******************************************************************************
+ *
+ * Name:	lm80.h	
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.2 $
+ * Date:	$Date: 1999/03/12 13:26:51 $
+ * Purpose:	Contains all defines for the LM80 Chip
+ *		(National Semiconductor).
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *	$Log: lm80.h,v $
+ *	Revision 1.2  1999/03/12 13:26:51  malthoff
+ *	remove __STDC__.
+ *	
+ *	Revision 1.1  1998/06/19 09:28:31  malthoff
+ *	created.
+ *	
+ *
+ ******************************************************************************/
+
+#ifndef __INC_LM80_H
+#define __INC_LM80_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* __cplusplus */
+
+/* defines ********************************************************************/
+
+/*
+ * LM80 register definition
+ *
+ * All registers are 8 bit wide
+ */
+#define	LM80_CFG		0x00	/* Configuration Register */
+#define	LM80_ISRC_1		0x01	/* Interrupt Status Register 1 */
+#define LM80_ISRC_2		0x02	/* Interrupt Status Register 2 */
+#define LM80_IMSK_1		0x03	/* Interrupt Mask Register 1 */
+#define LM80_IMSK_2		0x04	/* Interrupt Mask Register 2 */
+#define LM80_FAN_CTRL		0x05	/* Fan Devisor/RST#/OS# Register */
+#define LM80_TEMP_CTRL		0x06	/* OS# Config, Temp Res. Reg */
+	/* 0x07 - 0x1f reserved	*/
+	/* current values */
+#define LM80_VT0_IN		0x20	/* current Voltage 0 value */
+#define LM80_VT1_IN		0x21	/* current Voltage 1 value */
+#define LM80_VT2_IN		0x22	/* current Voltage 2 value */
+#define LM80_VT3_IN		0x23	/* current Voltage 3 value */
+#define LM80_VT4_IN		0x24	/* current Voltage 4 value */
+#define LM80_VT5_IN		0x25	/* current Voltage 5 value */
+#define LM80_VT6_IN		0x26	/* current Voltage 6 value */
+#define LM80_TEMP_IN		0x27	/* current temperature value */
+#define LM80_FAN1_IN		0x28	/* current Fan 1 count */
+#define LM80_FAN2_IN		0x29	/* current Fan 2 count */
+	/* limit values */
+#define LM80_VT0_HIGH_LIM	0x2a	/* high limit val for Voltage 0 */
+#define LM80_VT0_LOW_LIM	0x2b	/* low limit val for Voltage 0 */
+#define LM80_VT1_HIGH_LIM	0x2c	/* high limit val for Voltage 1 */
+#define LM80_VT1_LOW_LIM	0x2d	/* low limit val for Voltage 1 */
+#define LM80_VT2_HIGH_LIM	0x2e	/* high limit val for Voltage 2 */
+#define LM80_VT2_LOW_LIM	0x2f	/* low limit val for Voltage 2 */
+#define LM80_VT3_HIGH_LIM	0x30	/* high limit val for Voltage 3 */
+#define LM80_VT3_LOW_LIM	0x31	/* low limit val for Voltage 3 */
+#define LM80_VT4_HIGH_LIM	0x32	/* high limit val for Voltage 4 */
+#define LM80_VT4_LOW_LIM	0x33	/* low limit val for Voltage 4 */
+#define LM80_VT5_HIGH_LIM	0x34	/* high limit val for Voltage 5 */
+#define LM80_VT5_LOW_LIM	0x35	/* low limit val for Voltage 5 */
+#define LM80_VT6_HIGH_LIM	0x36	/* high limit val for Voltage 6 */
+#define LM80_VT6_LOW_LIM	0x37	/* low limit val for Voltage 6 */
+#define LM80_THOT_LIM_UP	0x38	/* hot temperature limit (high) */
+#define LM80_THOT_LIM_LO	0x39	/* hot temperature limit (low) */
+#define LM80_TOS_LIM_UP		0x3a	/* OS temperature limit (high) */
+#define LM80_TOS_LIM_LO		0x3b	/* OS temperature limit (low) */
+#define	LM80_FAN1_COUNT_LIM	0x3c	/* Fan 1 count limit (high) */
+#define	LM80_FAN2_COUNT_LIM	0x3d	/* Fan 2 count limit (low) */
+	/* 0x3e - 0x3f reserved	*/
+
+/*
+ * LM80 bit definitions
+ */
+
+/*	LM80_CFG		Configuration Register */
+#define LM80_CFG_START		(1<<0)	/* start monitoring operation */
+#define LM80_CFG_INT_ENA	(1<<1)	/* enables the INT# Interrupt output */
+#define LM80_CFG_INT_POL	(1<<2)	/* INT# pol: 0 act low, 1 act high */
+#define LM80_CFG_INT_CLR	(1<<3)	/* disables INT#/RST_OUT#/OS# outputs */
+#define LM80_CFG_RESET		(1<<4)	/* signals a reset */
+#define LM80_CFG_CHASS_CLR	(1<<5)	/* clears Chassis Intrusion (CI) pin */
+#define LM80_CFG_GPO		(1<<6)	/* drives the GPO# pin */
+#define LM80_CFG_INIT		(1<<7)	/* restore power on defaults */
+
+/*	LM80_ISRC_1		Interrupt Status Register 1 */
+/*	LM80_IMSK_1		Interrupt Mask Register 1 */
+#define LM80_IS_VT0		(1<<0)	/* limit exceeded for Voltage 0 */
+#define LM80_IS_VT1		(1<<1)	/* limit exceeded for Voltage 1 */
+#define LM80_IS_VT2		(1<<2)	/* limit exceeded for Voltage 2 */
+#define LM80_IS_VT3		(1<<3)	/* limit exceeded for Voltage 3 */
+#define LM80_IS_VT4		(1<<4)	/* limit exceeded for Voltage 4 */
+#define LM80_IS_VT5		(1<<5)	/* limit exceeded for Voltage 5 */
+#define LM80_IS_VT6		(1<<6)	/* limit exceeded for Voltage 6 */
+#define LM80_IS_INT_IN		(1<<7)	/* state of INT_IN# */
+
+/*	LM80_ISRC_2		Interrupt Status Register 2 */
+/*	LM80_IMSK_2		Interrupt Mask Register 2 */
+#define	LM80_IS_TEMP		(1<<0)	/* HOT temperature limit exceeded */
+#define LM80_IS_BTI		(1<<1)	/* state of BTI# pin */
+#define LM80_IS_FAN1		(1<<2)	/* count limit exceeded for Fan 1 */
+#define LM80_IS_FAN2		(1<<3)	/* count limit exceeded for Fan 2 */
+#define LM80_IS_CI		(1<<4)	/* Chassis Intrusion occured */
+#define LM80_IS_OS		(1<<5)	/* OS temperature limit exceeded */
+	/* bit 6 and 7 are reserved in LM80_ISRC_2 */
+#define LM80_IS_HT_IRQ_MD	(1<<6)	/* Hot temperature interrupt mode */
+#define LM80_IS_OT_IRQ_MD	(1<<7)	/* OS temperature interrupt mode */
+
+/*	LM80_FAN_CTRL		Fan Devisor/RST#/OS# Register */
+#define LM80_FAN1_MD_SEL	(1<<0)	/* Fan 1 mode select */
+#define LM80_FAN2_MD_SEL	(1<<1)	/* Fan 2 mode select */
+#define LM80_FAN1_PRM_CTL	(3<<2)	/* Fan 1 speed control */
+#define LM80_FAN2_PRM_CTL	(3<<4)	/* Fan 2 speed control */
+#define LM80_FAN_OS_ENA		(1<<6)	/* enable OS mode on RST_OUT#/OS# pins*/
+#define LM80_FAN_RST_ENA	(1<<7)	/* sets RST_OUT#/OS# pins in RST mode */
+
+/*	LM80_TEMP_CTRL		OS# Config, Temp Res. Reg */
+#define	LM80_TEMP_OS_STAT	(1<<0)	/* mirrors the state of RST_OUT#/OS# */
+#define LM80_TEMP_OS_POL	(1<<1)	/* select OS# polarity */
+#define LM80_TEMP_OS_MODE	(1<<2)	/* selects Interrupt mode */
+#define LM80_TEMP_RES		(1<<3)	/* selects 9 or 11 bit temp resulution*/
+#define LM80_TEMP_LSB		(0xf<<4)/* 4 LSBs of 11 bit temp data */
+#define LM80_TEMP_LSB_9		(1<<7)	/* LSB of 9 bit temperature data */
+
+	/* 0x07 - 0x1f reserved	*/
+/*	LM80_VT0_IN		current Voltage 0 value */
+/*	LM80_VT1_IN		current Voltage 1 value */
+/*	LM80_VT2_IN		current Voltage 2 value */
+/*	LM80_VT3_IN		current Voltage 3 value */
+/*	LM80_VT4_IN		current Voltage 4 value */
+/*	LM80_VT5_IN		current Voltage 5 value */
+/*	LM80_VT6_IN		current Voltage 6 value */
+/*	LM80_TEMP_IN		current temperature value */
+/*	LM80_FAN1_IN		current Fan 1 count */
+/*	LM80_FAN2_IN		current Fan 2 count */
+/*	LM80_VT0_HIGH_LIM	high limit val for Voltage 0 */
+/*	LM80_VT0_LOW_LIM	low limit val for Voltage 0 */
+/*	LM80_VT1_HIGH_LIM	high limit val for Voltage 1 */
+/*	LM80_VT1_LOW_LIM	low limit val for Voltage 1 */
+/*	LM80_VT2_HIGH_LIM	high limit val for Voltage 2 */
+/*	LM80_VT2_LOW_LIM	low limit val for Voltage 2 */
+/*	LM80_VT3_HIGH_LIM	high limit val for Voltage 3 */
+/*	LM80_VT3_LOW_LIM	low limit val for Voltage 3 */
+/*	LM80_VT4_HIGH_LIM	high limit val for Voltage 4 */
+/*	LM80_VT4_LOW_LIM	low limit val for Voltage 4 */
+/*	LM80_VT5_HIGH_LIM	high limit val for Voltage 5 */
+/*	LM80_VT5_LOW_LIM	low limit val for Voltage 5 */
+/*	LM80_VT6_HIGH_LIM	high limit val for Voltage 6 */
+/*	LM80_VT6_LOW_LIM	low limit val for Voltage 6 */
+/*	LM80_THOT_LIM_UP	hot temperature limit (high) */
+/*	LM80_THOT_LIM_LO	hot temperature limit (low) */
+/*	LM80_TOS_LIM_UP		OS temperature limit (high) */
+/*	LM80_TOS_LIM_LO		OS temperature limit (low) */
+/*	LM80_FAN1_COUNT_LIM	Fan 1 count limit (high) */
+/*	LM80_FAN2_COUNT_LIM	Fan 2 count limit (low) */
+	/* 0x3e - 0x3f reserved	*/
+
+#define LM80_ADDR	0x28	/* LM80 default addr */
+
+/* typedefs *******************************************************************/
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_LM80_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skaddr.h linux.14p16/drivers/net/sk98lin/h/skaddr.h
--- linux.vanilla/drivers/net/sk98lin/h/skaddr.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skaddr.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,309 @@
+/******************************************************************************
+ *
+ * Name:	skaddr.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.19 $
+ * Date:	$Date: 1999/05/28 10:56:07 $
+ * Purpose:	Header file for Address Management (MC, UC, Prom)
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skaddr.h,v $
+ *	Revision 1.19  1999/05/28 10:56:07  rassmann
+ *	Editorial changes.
+ *	
+ *	Revision 1.18  1999/04/06 17:22:04  rassmann
+ *	Added private "ActivePort".
+ *	
+ *	Revision 1.17  1999/01/14 16:18:19  rassmann
+ *	Corrected multicast initialization.
+ *	
+ *	Revision 1.16  1999/01/04 10:30:36  rassmann
+ *	SkAddrOverride only possible after SK_INIT_IO phase.
+ *	
+ *	Revision 1.15  1998/12/29 13:13:11  rassmann
+ *	An address override is now preserved in the SK_INIT_IO phase.
+ *	All functions return an int now.
+ *	Extended parameter checking.
+ *	
+ *	Revision 1.14  1998/11/24 12:39:45  rassmann
+ *	Reserved multicast entry for BPDU address.
+ *	13 multicast entries left for protocol.
+ *	
+ *	Revision 1.13  1998/11/13 17:24:32  rassmann
+ *	Changed return value of SkAddrOverride to int.
+ *	
+ *	Revision 1.12  1998/11/13 16:56:19  rassmann
+ *	Added macro SK_ADDR_COMPARE.
+ *	Changed return type of SkAddrOverride to SK_BOOL.
+ *	
+ *	Revision 1.11  1998/10/28 18:16:35  rassmann
+ *	Avoiding I/Os before SK_INIT_RUN level.
+ *	Aligning InexactFilter.
+ *	
+ *	Revision 1.10  1998/10/22 11:39:10  rassmann
+ *	Corrected signed/unsigned mismatches.
+ *	
+ *	Revision 1.9  1998/10/15 15:15:49  rassmann
+ *	Changed Flags Parameters from SK_U8 to int.
+ *	Checked with lint.
+ *	
+ *	Revision 1.8  1998/09/24 19:15:12  rassmann
+ *	Code cleanup.
+ *	
+ *	Revision 1.7  1998/09/18 20:22:13  rassmann
+ *	Added HW access.
+ *	
+ *	Revision 1.6  1998/09/04 19:40:20  rassmann
+ *	Interface enhancements.
+ *	
+ *	Revision 1.5  1998/09/04 12:40:57  rassmann
+ *	Interface cleanup.
+ *	
+ *	Revision 1.4  1998/09/04 12:14:13  rassmann
+ *	Interface cleanup.
+ *	
+ *	Revision 1.3  1998/09/02 16:56:40  rassmann
+ *	Updated interface.
+ *	
+ *	Revision 1.2  1998/08/27 14:26:09  rassmann
+ *	Updated interface.
+ *	
+ *	Revision 1.1  1998/08/21 08:31:08  rassmann
+ *	First public version.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module is intended to manage multicast addresses and promiscuous mode
+ * on GEnesis adapters.
+ *
+ * Include File Hierarchy:
+ *
+ *	"skdrv1st.h"
+ *	...
+ *	"sktypes.h"
+ *	"skqueue.h"
+ *	"skaddr.h"
+ *	...
+ *	"skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKADDR_H
+#define __INC_SKADDR_H
+
+#ifdef __cplusplus
+xxxx	/* not supported yet - force error */
+extern "C" {
+#endif	/* cplusplus */
+
+/* defines ********************************************************************/
+
+#define SK_MAC_ADDR_LEN		6	/* Length of MAC address. */
+#define	SK_MAX_ADDRS		14	/* #Addrs for exact match. */
+
+/* ----- Common return values ----- */
+
+#define SK_ADDR_SUCCESS		0	/* Function returned successfully. */
+#define SK_ADDR_ILLEGAL_PORT	100	/* Port number too high. */
+#define SK_ADDR_TOO_EARLY	101	/* Function called too early. */
+
+/* ----- Clear/Add flag bits ----- */
+
+#define SK_ADDR_PERMANENT	1	/* RLMT Address */
+
+/* ----- Additional Clear flag bits ----- */
+
+#define SK_MC_SW_ONLY		2	/* Do not update HW when clearing. */
+
+/* ----- Override flag bits ----- */
+
+#define SK_ADDR_VIRTUAL_ADDRESS		0
+#define SK_ADDR_PHYSICAL_ADDRESS	1
+
+/* ----- Override return values ----- */
+
+#define SK_ADDR_OVERRIDE_SUCCESS	(SK_ADDR_SUCCESS)
+#define SK_ADDR_DUPLICATE_ADDRESS	1
+#define SK_ADDR_MULTICAST_ADDRESS	2
+
+/* ----- Partitioning of excact match table ----- */
+
+#define SK_ADDR_EXACT_MATCHES	16	/* #Exact match entries. */
+
+#define SK_ADDR_FIRST_MATCH_RLMT	1
+#define SK_ADDR_LAST_MATCH_RLMT		2
+#define SK_ADDR_FIRST_MATCH_DRV		3
+#define SK_ADDR_LAST_MATCH_DRV		(SK_ADDR_EXACT_MATCHES - 1)
+
+/* ----- SkAddrMcAdd/SkAddrMcUpdate return values ----- */
+
+#define SK_MC_FILTERING_EXACT	0	/* Exact filtering. */
+#define SK_MC_FILTERING_INEXACT	1	/* Inexact filtering. */
+
+/* ----- Additional SkAddrMcAdd return values ----- */
+
+#define SK_MC_ILLEGAL_ADDRESS	2	/* Illegal address. */
+#define SK_MC_ILLEGAL_PORT	3	/* Illegal port (not the active one). */
+#define SK_MC_RLMT_OVERFLOW	4	/* Too many RLMT mc addresses. */
+
+/* Promiscuous mode bits ----- */
+
+#define SK_PROM_MODE_NONE	0	/* Normal receive. */
+#define SK_PROM_MODE_LLC	1	/* Receive all LLC frames. */
+#define SK_PROM_MODE_ALL_MC	2	/* Receive all multicast frames. */
+/* #define SK_PROM_MODE_NON_LLC	4 */	/* Receive all non-LLC frames. */
+
+/* Macros */
+
+#ifndef SK_ADDR_EQUAL
+#ifndef SK_ADDR_DWORD_COMPARE
+#define SK_ADDR_EQUAL(A1,A2)	( \
+	((SK_U8 *)(A1))[5] == ((SK_U8 *)(A2))[5] && \
+	((SK_U8 *)(A1))[4] == ((SK_U8 *)(A2))[4] && \
+	((SK_U8 *)(A1))[3] == ((SK_U8 *)(A2))[3] && \
+	((SK_U8 *)(A1))[2] == ((SK_U8 *)(A2))[2] && \
+	((SK_U8 *)(A1))[1] == ((SK_U8 *)(A2))[1] && \
+	((SK_U8 *)(A1))[0] == ((SK_U8 *)(A2))[0])
+#else	/* SK_ADDR_DWORD_COMPARE */
+#define SK_ADDR_EQUAL(A1,A2)	( \
+	*(SK_U32 *)&(((SK_U8 *)(A1))[2]) == *(SK_U32 *)&(((SK_U8 *)(A2))[2]) && \
+	*(SK_U32 *)&(((SK_U8 *)(A1))[0]) == *(SK_U32 *)&(((SK_U8 *)(A2))[0]))
+#endif	/* SK_ADDR_DWORD_COMPARE */
+#endif /* SK_ADDR_EQUAL */
+
+/* typedefs *******************************************************************/
+
+typedef struct s_MacAddr {
+	SK_U8	a[SK_MAC_ADDR_LEN];
+} SK_MAC_ADDR;
+
+/* SK_FILTER is used to ensure alignment of the filter. */
+typedef union s_InexactFilter {
+	SK_U8	Bytes[8];
+	SK_U64	Val;		/* Dummy entry for alignment only. */
+} SK_FILTER64;
+
+typedef struct s_AddrPort {
+
+/* ----- Public part (read-only) ----- */
+
+	SK_MAC_ADDR	PermanentMacAddress;	/* Physical MAC Address. */
+	SK_MAC_ADDR	CurrentMacAddress;	/* Physical MAC Address. */
+	int		PromMode;		/* Promiscuous Mode. */
+
+/* ----- Private part ----- */
+
+	SK_BOOL		CurrentMacAddressSet;	/* CurrentMacAddress is set. */
+	SK_MAC_ADDR	PreviousMacAddress;	/* Prev. phys. MAC Address. */
+	SK_U32		FirstExactMatchRlmt;
+	SK_U32		NextExactMatchRlmt;
+	SK_U32		FirstExactMatchDrv;
+	SK_U32		NextExactMatchDrv;
+	SK_MAC_ADDR	Exact[SK_ADDR_EXACT_MATCHES];
+	SK_FILTER64	InexactFilter;		/* For 64-bit hash register. */
+} SK_ADDR_PORT;
+
+typedef struct s_Addr {
+
+/* ----- Public part (read-only) ----- */
+
+	SK_ADDR_PORT	Port[SK_MAX_MACS];
+	SK_MAC_ADDR	PermanentMacAddress;	/* Logical MAC Address. */
+	SK_MAC_ADDR	CurrentMacAddress;	/* Logical MAC Address. */
+
+/* ----- Private part ----- */
+
+#if 0
+	SK_BOOL		Initialized;	/* Flag: Addr module is initialized. */
+#endif	/* 0 */
+	SK_BOOL		CurrentMacAddressSet;	/* CurrentMacAddress is set. */
+	SK_U32		ActivePort;		/* Vie of module ADDR. */
+} SK_ADDR;
+
+/* function prototypes ********************************************************/
+
+#ifndef SK_KR_PROTO
+
+/* Functions provided by SkRlmt */
+
+/* ANSI/C++ compliant function prototypes */
+
+extern	int	SkAddrInit(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int	Level);
+
+extern	int	SkAddrMcClear(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortIdx,
+	int	Flags);
+
+extern	int	SkAddrMcAdd(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	SK_U32		PortIdx,
+	SK_MAC_ADDR	*pMc,
+	int		Flags);
+
+extern	int	SkAddrMcUpdate(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortIdx);
+
+extern	int	SkAddrOverride(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	SK_U32		PortIdx,
+	SK_MAC_ADDR	*pNewAddr,
+	int		Flags);
+
+extern	int	SkAddrPromiscuousChange(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortIdx,
+	int	NewPromMode);
+
+extern	int	SkAddrSwap(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	FromPortIdx,
+	SK_U32	ToPortIdx);
+
+#else	/* defined(SK_KR_PROTO)) */
+
+/* Non-ANSI/C++ compliant function prototypes */
+
+xxxx	/* not supported yet - force error */
+
+#endif	/* defined(SK_KR_PROTO)) */
+
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_SKADDR_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skcsum.h linux.14p16/drivers/net/sk98lin/h/skcsum.h
--- linux.vanilla/drivers/net/sk98lin/h/skcsum.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skcsum.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,223 @@
+/******************************************************************************
+ *
+ * Name:	skcsum.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.2 $
+ * Date:	$Date: 1998/09/04 12:16:34 $
+ * Purpose:	Store/verify Internet checksum in send/receive packets.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skcsum.h,v $
+ *	Revision 1.2  1998/09/04 12:16:34  mhaveman
+ *	Checked in for Stephan to allow compilation.
+ *	-Added definition SK_CSUM_EVENT_CLEAR_PROTO_STATS to clear statistic
+ *	-Added prototype for SkCsEvent()
+ *	
+ *	Revision 1.1  1998/09/01 15:36:53  swolf
+ *	initial revision
+ *
+ *	01-Sep-1998 sw	Created.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * Public header file for the "GEnesis" common module "CSUM".
+ *
+ * "GEnesis" is an abbreviation of "Gigabit Ethernet Network System in Silicon"
+ * and is the code name of this SysKonnect project.
+ *
+ * Compilation Options:
+ *
+ *	SK_USE_CSUM - Define if CSUM is to be used. Otherwise, CSUM will be an
+ *	empty module.
+ *
+ *	SKCS_OVERWRITE_PROTO - Define to overwrite the default protocol id
+ *	definitions. In this case, all SKCS_PROTO_xxx definitions must be made
+ *	external.
+ *
+ *	SKCS_OVERWRITE_STATUS - Define to overwrite the default return status
+ *	definitions. In this case, all SKCS_STATUS_xxx definitions must be made
+ *	external.
+ *
+ * Include File Hierarchy:
+ *
+ *	"h/skcsum.h"
+ *	 "h/sktypes.h"
+ *	 "h/skqueue.h"
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKCSUM_H
+#define __INC_SKCSUM_H
+
+#include "h/sktypes.h"
+#include "h/skqueue.h"
+
+/* defines ********************************************************************/
+
+/*
+ * Define the default bit flags for 'SKCS_PACKET_INFO.ProtocolFlags'  if no user
+ * overwrite.
+ */
+#ifndef SKCS_OVERWRITE_PROTO	/* User overwrite? */
+#define SKCS_PROTO_IP	0x1	/* IP (Internet Protocol version 4) */
+#define SKCS_PROTO_TCP	0x2	/* TCP (Transmission Control Protocol) */
+#define SKCS_PROTO_UDP	0x4	/* UDP (User Datagram Protocol) */
+
+/* Indices for protocol statistics. */
+#define SKCS_PROTO_STATS_IP	0
+#define SKCS_PROTO_STATS_UDP	1
+#define SKCS_PROTO_STATS_TCP	2
+#define SKCS_NUM_PROTOCOLS	3	/* Number of supported protocols. */
+#endif	/* !SKCS_OVERWRITE_PROTO */
+
+/*
+ * Define the default SKCS_STATUS type and values if no user overwrite.
+ *
+ *	SKCS_STATUS_UNKNOWN_IP_VERSION - Not an IP v4 frame.
+ *	SKCS_STATUS_IP_CSUM_ERROR - IP checksum error.
+ *	SKCS_STATUS_IP_FRAGMENT - IP fragment (IP checksum ok).
+ *	SKCS_STATUS_IP_CSUM_OK - IP checksum ok (not a TCP or UDP frame).
+ *	SKCS_STATUS_TCP_CSUM_ERROR - TCP checksum error (IP checksum ok).
+ *	SKCS_STATUS_UDP_CSUM_ERROR - UDP checksum error (IP checksum ok).
+ *	SKCS_STATUS_TCP_CSUM_OK - IP and TCP checksum ok.
+ *	SKCS_STATUS_UDP_CSUM_OK - IP and UDP checksum ok.
+ */
+#ifndef SKCS_OVERWRITE_STATUS	/* User overwrite? */
+#define SKCS_STATUS	int	/* Define status type. */
+
+#define SKCS_STATUS_UNKNOWN_IP_VERSION	1
+#define SKCS_STATUS_IP_CSUM_ERROR	2
+#define SKCS_STATUS_IP_FRAGMENT		3
+#define SKCS_STATUS_IP_CSUM_OK		4
+#define SKCS_STATUS_TCP_CSUM_ERROR	5
+#define SKCS_STATUS_UDP_CSUM_ERROR	6
+#define SKCS_STATUS_TCP_CSUM_OK		7
+#define SKCS_STATUS_UDP_CSUM_OK		8
+#endif	/* !SKCS_OVERWRITE_STATUS */
+
+/* Clear protocol statistics event. */
+#define SK_CSUM_EVENT_CLEAR_PROTO_STATS	1
+
+/*
+ * Add two values in one's complement.
+ *
+ * Note: One of the two input values may be "longer" than 16-bit, but then the
+ * resulting sum may be 17 bits long. In this case, add zero to the result using
+ * SKCS_OC_ADD() again.
+ *
+ *	Result = Value1 + Value2
+ */
+#define SKCS_OC_ADD(Result, Value1, Value2) {				\
+	unsigned long Sum;						\
+									\
+	Sum = (unsigned long) (Value1) + (unsigned long) (Value2);	\
+	/* Add-in any carry. */						\
+	(Result) = (Sum & 0xffff) + (Sum >> 16);			\
+}
+
+/*
+ * Subtract two values in one's complement.
+ *
+ *	Result = Value1 - Value2
+ */
+#define SKCS_OC_SUB(Result, Value1, Value2)	\
+	SKCS_OC_ADD((Result), (Value1), ~(Value2) & 0xffff)
+
+/* typedefs *******************************************************************/
+
+/*
+ * SKCS_PROTO_STATS - The CSUM protocol statistics structure.
+ *
+ * There is one instance of this structure for each protocol supported.
+ */
+typedef struct s_CsProtocolStatistics {
+	SK_U64 RxOkCts;		/* Receive checksum ok. */
+	SK_U64 RxUnableCts;	/* Unable to verify receive checksum. */
+	SK_U64 RxErrCts;	/* Receive checksum error. */
+	SK_U64 TxOkCts;		/* Transmit checksum ok. */
+	SK_U64 TxUnableCts;	/* Unable to verify transmit checksum. */
+} SKCS_PROTO_STATS;
+
+/*
+ * s_Csum - The CSUM module context structure.
+ */
+typedef struct s_Csum {
+	/* Enabled receive SK_PROTO_XXX bit flags. */
+	unsigned ReceiveFlags;
+
+	/* The protocol statistics structure; one per supported protocol. */
+	SKCS_PROTO_STATS ProtoStats[SKCS_NUM_PROTOCOLS];
+} SK_CSUM;
+
+/*
+ * SKCS_PACKET_INFO - The packet information structure.
+ */
+typedef struct s_CsPacketInfo {
+	/* Bit field specifiying the desired/found protocols. */
+	unsigned ProtocolFlags;
+
+	/* Length of complete IP header, including any option fields. */
+	unsigned IpHeaderLength;
+
+	/* IP header checksum. */
+	unsigned IpHeaderChecksum;
+
+	/* TCP/UDP pseudo header checksum. */
+	unsigned PseudoHeaderChecksum;
+} SKCS_PACKET_INFO;
+
+/* function prototypes ********************************************************/
+
+#ifndef SkCsCalculateChecksum
+extern unsigned SkCsCalculateChecksum(
+	void		*pData,
+	unsigned	Length);
+#endif
+
+extern int SkCsEvent(
+	SK_AC		*pAc,
+	SK_IOC		Ioc,
+	SK_U32		Event,
+	SK_EVPARA	Param);
+
+extern SKCS_STATUS SkCsGetReceiveInfo(
+	SK_AC		*pAc,
+	void		*pIpHeader,
+	unsigned	Checksum1,
+	unsigned	Checksum2);
+
+extern void SkCsGetSendInfo(
+	SK_AC			*pAc,
+	void			*pIpHeader,
+	SKCS_PACKET_INFO	*pPacketInfo);
+
+extern void SkCsSetReceiveFlags(
+	SK_AC		*pAc,
+	unsigned	ReceiveFlags,
+	unsigned	*pChecksum1Offset,
+	unsigned	*pChecksum2Offset);
+
+#endif	/* __INC_SKCSUM_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skdebug.h linux.14p16/drivers/net/sk98lin/h/skdebug.h
--- linux.vanilla/drivers/net/sk98lin/h/skdebug.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skdebug.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,111 @@
+/******************************************************************************
+ *
+ * Name:	skdebug.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.9 $
+ * Date:	$Date: 1999/09/14 14:02:43 $
+ * Purpose:	SK specific DEBUG support
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *	$Log: skdebug.h,v $
+ *	Revision 1.9  1999/09/14 14:02:43  rwahl
+ *	Added SK_DBGMOD_PECP.
+ *	
+ *	Revision 1.8  1998/11/25 08:31:54  gklug
+ *	fix: no C++ comments allowed in common sources
+ *	
+ *	Revision 1.7  1998/11/24 16:47:24  swolf
+ *	Driver may now define its own SK_DBG_MSG() (eg. in "h/skdrv1st.h").
+ *	
+ *	Revision 1.6  1998/10/28 10:23:55  rassmann
+ *	ADDED SK_DBGMOD_ADDR.
+ *	
+ *	Revision 1.5  1998/10/22 09:43:55  gklug
+ *	add: CSUM module
+ *	
+ *	Revision 1.4  1998/10/01 07:54:44  gklug
+ *	add: PNMI debug module
+ *	
+ *	Revision 1.3  1998/09/18 08:32:34  afischer
+ *	Macros changed according ssr-spec.:
+ *		SK_DBG_MODCHK -> SK_DBG_CHKMOD
+ *		SK_DBG_CATCHK -> SK_DBG_CHKCAT
+ *	
+ *	Revision 1.2  1998/07/03 14:38:25  malthoff
+ *	Add category SK_DBGCAT_FATAL.
+ *	
+ *	Revision 1.1  1998/06/19 13:39:01  malthoff
+ *	created.
+ *	
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDEBUG_H
+#define __INC_SKDEBUG_H
+
+#ifdef	DEBUG
+#ifndef SK_DBG_MSG
+#define SK_DBG_MSG(pAC,comp,cat,arg) \
+		if ( ((comp) & SK_DBG_CHKMOD(pAC)) && 	\
+		      ((cat) & SK_DBG_CHKCAT(pAC)) ) { 	\
+			SK_DBG_PRINTF arg ;		\
+		}
+#endif
+#else
+#define SK_DBG_MSG(pAC,comp,lev,arg)
+#endif
+
+/* PLS NOTE:
+ * =========
+ * Due to any restrictions of kernel printf routines do not use other
+ * format identifiers as: %x %d %c %s .
+ * Never use any combined format identifiers such as: %lx %ld in your
+ * printf - argument (arg) because some OS specific kernel printfs may
+ * only support some basic identifiers.
+ */
+
+/* Debug modules */
+
+#define SK_DBGMOD_MERR	0x00000001L	/* general module error indication */
+#define SK_DBGMOD_HWM	0x00000002L	/* Hardware init module */
+#define	SK_DBGMOD_RLMT	0x00000004L	/* RLMT module */
+#define	SK_DBGMOD_VPD	0x00000008L	/* VPD module */
+#define	SK_DBGMOD_I2C	0x00000010L	/* I2C module */
+#define	SK_DBGMOD_PNMI	0x00000020L	/* PNMI module */
+#define	SK_DBGMOD_CSUM	0x00000040L	/* CSUM module */
+#define	SK_DBGMOD_ADDR	0x00000080L	/* ADDR module */
+#define SK_DBGMOD_PECP	0x00000100L	/* PECP module */
+
+/* Debug events */
+
+#define	SK_DBGCAT_INIT	0x00000001L	/* module/driver initialization */
+#define	SK_DBGCAT_CTRL	0x00000002L	/* controlling: add/rmv MCA/MAC
+					 * and other controls (IOCTL)
+					 */
+#define	SK_DBGCAT_ERR	0x00000004L	/* error handling paths */
+#define	SK_DBGCAT_TX	0x00000008L	/* transmit path */
+#define	SK_DBGCAT_RX	0x00000010L	/* receive path */
+#define	SK_DBGCAT_IRQ	0x00000020L	/* general IRQ handling */
+#define	SK_DBGCAT_QUEUE	0x00000040L	/* any queue management */
+#define	SK_DBGCAT_DUMP	0x00000080L	/* large data output e.g. hex dump */
+#define	SK_DBGCAT_FATAL	0x00000100L	/* large data output e.g. hex dump */
+
+#endif	/* __INC_SKDEBUG_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skdrv1st.h linux.14p16/drivers/net/sk98lin/h/skdrv1st.h
--- linux.vanilla/drivers/net/sk98lin/h/skdrv1st.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skdrv1st.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,213 @@
+/******************************************************************************
+ *
+ * Name:	skdrv1st.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.6 $
+ * Date:	$Date: 1999/07/27 08:03:33 $
+ * Purpose:	First header file for driver and all other modules
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skdrv1st.h,v $
+ *	Revision 1.6  1999/07/27 08:03:33  cgoos
+ *	Changed SK_IN/OUT macros to readX/writeX instead of memory
+ *	accesses (necessary for ALPHA).
+ *	
+ *	Revision 1.5  1999/07/23 12:10:21  cgoos
+ *	Removed SK_RLMT_SLOW_LOOKAHEAD define.
+ *	
+ *	Revision 1.4  1999/07/14 12:31:13  cgoos
+ *	Added SK_RLMT_SLOW_LOOKAHEAD define.
+ *	
+ *	Revision 1.3  1999/04/07 10:12:54  cgoos
+ *	Added check for KERNEL and OPTIMIZATION defines.
+ *	
+ *	Revision 1.2  1999/03/01 08:51:47  cgoos
+ *	Fixed pcibios_read/write definitions.
+ *	
+ *	Revision 1.1  1999/02/16 07:40:49  cgoos
+ *	First version.
+ *	
+ *	
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the first include file of the driver, which includes all
+ * neccessary system header files and some of the GEnesis header files.
+ * It also defines some basic items.
+ *
+ * Include File Hierarchy:
+ *
+ *	see skge.c
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDRV1ST_H
+#define __INC_SKDRV1ST_H
+
+
+typedef struct s_AC	SK_AC;
+
+/* override some default functions with optimized linux functions */
+
+#define SK_PNMI_STORE_U16(p,v)		memcpy((char*)(p),(char*)&(v),2)
+#define SK_PNMI_STORE_U32(p,v)		memcpy((char*)(p),(char*)&(v),4)
+#define SK_PNMI_STORE_U64(p,v)		memcpy((char*)(p),(char*)&(v),8)
+#define SK_PNMI_READ_U16(p,v)		memcpy((char*)&(v),(char*)(p),2)
+#define SK_PNMI_READ_U32(p,v)		memcpy((char*)&(v),(char*)(p),2)
+#define SK_PNMI_READ_U64(p,v)		memcpy((char*)&(v),(char*)(p),2)
+
+#define SkCsCalculateChecksum(p,l)	((~ip_compute_csum(p, l)) & 0xffff)
+
+#define SK_ADDR_EQUAL(a1,a2)		(!memcmp(a1,a2,6))
+
+
+#if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <asm/byteorder.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <net/checksum.h>
+
+#include	"h/sktypes.h"
+#include	"h/skerror.h"
+#include	"h/skdebug.h"
+#include	"h/lm80.h"
+#include	"h/xmac_ii.h"
+
+#ifdef __LITTLE_ENDIAN
+#define SK_LITTLE_ENDIAN
+#else
+#define SK_BIG_ENDIAN
+#endif
+
+
+/* we use gethrtime(), return unit: nanoseconds */
+#define SK_TICKS_PER_SEC	HZ
+
+#define	SK_MEM_MAPPED_IO
+
+// #define SK_RLMT_SLOW_LOOKAHEAD
+
+#define SK_MAX_MACS		2
+
+#define SK_IOC			char*
+
+typedef struct s_DrvRlmtMbuf SK_MBUF;
+
+#define	SK_CONST64	INT64_C
+#define	SK_CONSTU64	UINT64_C
+
+#define SK_MEMCPY(dest,src,size)	memcpy(dest,src,size)
+#define SK_MEMCMP(s1,s2,size)		memcmp(s1,s2,size)
+#define SK_MEMSET(dest,val,size)	memset(dest,val,size)
+#define SK_STRLEN(pStr)			strlen((char*)pStr)
+#define SK_STRNCPY(pDest,pSrc,size)	strncpy((char*)pDest,(char*)pSrc,size)
+#define SK_STRCMP(pStr1,pStr2)		strcmp((char*)pStr1,(char*)pStr2)
+
+/* macros to access the adapter */
+#define SK_OUT8(b,a,v)		writeb(v, (b+a))	
+#define SK_OUT16(b,a,v)		writew(v, (b+a))	
+#define SK_OUT32(b,a,v)		writel(v, (b+a))	
+#define SK_IN8(b,a,pv)		(*(pv) = readb(b+a))
+#define SK_IN16(b,a,pv)		(*(pv) = readw(b+a))
+#define SK_IN32(b,a,pv)		(*(pv) = readl(b+a))
+
+#define int8_t		char
+#define int16_t		short
+#define int32_t		long
+#define int64_t		long long
+#define uint8_t		u_char
+#define uint16_t	u_short
+#define uint32_t	u_long
+#define uint64_t	unsigned long long
+#define t_scalar_t	int
+#define t_uscalar_t	unsigned int
+#define uintptr_t	unsigned long
+
+#define __CONCAT__(A,B) A##B
+
+#define INT32_C(a)		__CONCAT__(a,L)
+#define INT64_C(a)		__CONCAT__(a,LL)
+#define UINT32_C(a)		__CONCAT__(a,UL)
+#define UINT64_C(a)		__CONCAT__(a,ULL)
+
+#ifdef DEBUG
+#define SK_DBG_PRINTF		printk
+#ifndef SK_DEBUG_CHKMOD
+#define SK_DEBUG_CHKMOD		0
+#endif
+#ifndef SK_DEBUG_CHKCAT
+#define SK_DEBUG_CHKCAT		0
+#endif
+/* those come from the makefile */
+#define SK_DBG_CHKMOD(pAC)	(SK_DEBUG_CHKMOD)
+#define SK_DBG_CHKCAT(pAC)	(SK_DEBUG_CHKCAT)
+
+extern void SkDbgPrintf(const char *format,...);
+
+#define SK_DBGMOD_DRV			0x00010000
+
+/**** possible driver debug categories ********************************/
+#define SK_DBGCAT_DRV_ENTRY		0x00010000
+#define SK_DBGCAT_DRV_SAP		0x00020000
+#define SK_DBGCAT_DRV_MCA		0x00040000
+#define SK_DBGCAT_DRV_TX_PROGRESS	0x00080000
+#define SK_DBGCAT_DRV_RX_PROGRESS	0x00100000
+#define SK_DBGCAT_DRV_PROGRESS		0x00200000
+#define SK_DBGCAT_DRV_MSG		0x00400000
+#define SK_DBGCAT_DRV_PROM		0x00800000
+#define SK_DBGCAT_DRV_TX_FRAME		0x01000000
+#define SK_DBGCAT_DRV_ERROR		0x02000000
+#define SK_DBGCAT_DRV_INT_SRC		0x04000000
+#define SK_DBGCAT_DRV_EVENT		0x08000000
+
+#endif /* DEBUG */
+
+#define SK_ERR_LOG		SkErrorLog
+
+extern void SkErrorLog(SK_AC*, int, int, char*);
+
+#endif /* __INC_SKDRV1ST_H */
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skdrv2nd.h linux.14p16/drivers/net/sk98lin/h/skdrv2nd.h
--- linux.vanilla/drivers/net/sk98lin/h/skdrv2nd.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skdrv2nd.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,445 @@
+/******************************************************************************
+ *
+ * Name:	skdrv2nd.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.7 $
+ * Date:	$Date: 1999/09/28 12:38:21 $
+ * Purpose:	Second header file for driver and all other modules
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skdrv2nd.h,v $
+ *	Revision 1.7  1999/09/28 12:38:21  cgoos
+ *	Added CheckQueue to SK_AC.
+ *	
+ *	Revision 1.6  1999/07/27 08:04:05  cgoos
+ *	Added checksumming variables to SK_AC.
+ *	
+ *	Revision 1.5  1999/03/29 12:33:26  cgoos
+ *	Rreversed to fine lock granularity.
+ *	
+ *	Revision 1.4  1999/03/15 12:14:02  cgoos
+ *	Added DriverLock to SK_AC.
+ *	Removed other locks.
+ *	
+ *	Revision 1.3  1999/03/01 08:52:27  cgoos
+ *	Changed pAC->PciDev declaration.
+ *	
+ *	Revision 1.2  1999/02/18 10:57:14  cgoos
+ *	Removed SkDrvTimeStamp prototype.
+ *	Fixed SkGeOsGetTime prototype.
+ *	
+ *	Revision 1.1  1999/02/16 07:41:01  cgoos
+ *	First version.
+ *	
+ *	
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the second include file of the driver, which includes all other
+ * neccessary files and defines all structures and constants used by the
+ * driver and the common modules.
+ *
+ * Include File Hierarchy:
+ *
+ *	see skge.c
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDRV2ND_H
+#define __INC_SKDRV2ND_H
+
+#include "h/skqueue.h"
+#include "h/skgehwt.h"
+#include "h/sktimer.h"
+#include "h/ski2c.h"
+#include "h/skgepnmi.h"
+#include "h/skvpd.h"
+#include "h/skgehw.h"
+#include "h/skgeinit.h"
+#include "h/skaddr.h"
+#include "h/skgesirq.h"
+#include "h/skcsum.h"
+#include "h/skrlmt.h"
+#include "h/skgedrv.h"
+
+/* global function prototypes ******************************************/
+extern SK_MBUF		*SkDrvAllocRlmtMbuf(SK_AC*, SK_IOC, unsigned);
+extern void		SkDrvFreeRlmtMbuf(SK_AC*, SK_IOC, SK_MBUF*);
+extern SK_U64		SkOsGetTime(SK_AC*);
+extern int		SkPciReadCfgDWord(SK_AC*, int, SK_U32*);
+extern int		SkPciReadCfgWord(SK_AC*, int, SK_U16*);
+extern int		SkPciReadCfgByte(SK_AC*, int, SK_U8*);
+extern int		SkPciWriteCfgDWord(SK_AC*, int, SK_U32);
+extern int		SkPciWriteCfgWord(SK_AC*, int, SK_U16);
+extern int		SkPciWriteCfgByte(SK_AC*, int, SK_U8);
+extern int		SkDrvEvent(SK_AC*, SK_IOC IoC, SK_U32, SK_EVPARA);
+
+struct s_DrvRlmtMbuf {
+	SK_MBUF		*pNext;		/* Pointer to next RLMT Mbuf. */
+	SK_U8		*pData;		/* Data buffer (virtually contig.). */
+	unsigned	Size;		/* Data buffer size. */
+	unsigned	Length;		/* Length of packet (<= Size). */
+	SK_U32		PortIdx;	/* Receiving/transmitting port. */
+#ifdef SK_RLMT_MBUF_PRIVATE
+	SK_RLMT_MBUF	Rlmt;		/* Private part for RLMT. */
+#endif  /* SK_RLMT_MBUF_PRIVATE */
+	struct sk_buff	*pOs;		/* Pointer to message block */
+};
+
+
+
+/*
+ * ioctl definitions
+ */
+#define		SK_IOCTL_BASE		(SIOCDEVPRIVATE)
+#define		SK_IOCTL_GETMIB		(SK_IOCTL_BASE + 0)
+#define		SK_IOCTL_SETMIB		(SK_IOCTL_BASE + 1)
+#define		SK_IOCTL_PRESETMIB	(SK_IOCTL_BASE + 2)
+
+typedef struct s_IOCTL	SK_GE_IOCTL;
+
+struct s_IOCTL {
+	char*		pData;
+	unsigned int	Len;
+};
+
+
+/*
+ * define sizes of descriptor rings in bytes
+ */
+
+#define		TX_RING_SIZE	(8*1024)
+#define		RX_RING_SIZE	(24*1024)
+
+/*
+ * Buffer size for ethernet packets
+ */
+#define	ETH_BUF_SIZE	1540
+#define	ETH_MAX_MTU	1514
+#define ETH_MIN_MTU	60
+#define ETH_MULTICAST_BIT	0x01
+#define SK_JUMBO_MTU	9000
+
+/*
+ * transmit priority selects the queue: LOW=asynchron, HIGH=synchron
+ */
+#define TX_PRIO_LOW	0
+#define TX_PRIO_HIGH	1
+
+/*
+ * alignment of rx/tx descriptors
+ */
+#define DESCR_ALIGN	8
+
+/*
+ * definitions for pnmi. TODO
+ */
+#define SK_DRIVER_RESET(pAC, IoC)	0
+#define SK_DRIVER_SENDEVENT(pAC, IoC)	0
+#define SK_DRIVER_SELFTEST(pAC, IoC)	0
+
+/* TX and RX descriptors *****************************************************/
+
+typedef struct s_RxD RXD; /* the receive descriptor */
+
+struct s_RxD {
+	volatile SK_U32	RBControl;	/* Receive Buffer Control */
+	SK_U32		VNextRxd;	/* Next receive descriptor,low dword */
+	SK_U32		VDataLow;	/* Receive buffer Addr, low dword */
+	SK_U32		VDataHigh;	/* Receive buffer Addr, high dword */
+	SK_U32		FrameStat;	/* Receive Frame Status word */
+	SK_U32		TimeStamp;	/* Time stamp from XMAX */
+	SK_U32		TcpSums;	/* TCP Sum 2 / TCP Sum 1 */
+	SK_U32		TcpSumStarts;	/* TCP Sum Start 2 / TCP Sum Start 1 */
+	RXD		*pNextRxd;	/* Pointer to next Rxd */
+	struct sk_buff	*pMBuf;		/* Pointer to Linux' socket buffer */
+};
+
+typedef struct s_TxD TXD; /* the transmit descriptor */
+
+struct s_TxD {
+	volatile SK_U32	TBControl;	/* Transmit Buffer Control */
+	SK_U32		VNextTxd;	/* Next transmit descriptor,low dword */
+	SK_U32		VDataLow;	/* Transmit Buffer Addr, low dword */
+	SK_U32		VDataHigh;	/* Transmit Buffer Addr, high dword */
+	SK_U32		FrameStat;	/* Transmit Frame Status Word */
+	SK_U32		TcpSumOfs;	/* Reserved / TCP Sum Offset */
+	SK_U32		TcpSumStWr;	/* TCP Sum Start / TCP Sum Write */
+	SK_U32		TcpReserved;	/* not used */
+	TXD		*pNextTxd;	/* Pointer to next Txd */
+	struct sk_buff	*pMBuf;		/* Pointer to Linux' socket buffer */
+};
+
+
+/* definition of flags in descriptor control field */
+#define	RX_CTRL_OWN_BMU 	UINT32_C(0x80000000)
+#define	RX_CTRL_STF		UINT32_C(0x40000000)
+#define	RX_CTRL_EOF		UINT32_C(0x20000000)
+#define	RX_CTRL_EOB_IRQ		UINT32_C(0x10000000)
+#define	RX_CTRL_EOF_IRQ		UINT32_C(0x08000000)
+#define RX_CTRL_DEV_NULL	UINT32_C(0x04000000)
+#define RX_CTRL_STAT_VALID	UINT32_C(0x02000000)
+#define RX_CTRL_TIME_VALID	UINT32_C(0x01000000)
+#define RX_CTRL_CHECK_DEFAULT	UINT32_C(0x00550000)
+#define RX_CTRL_CHECK_CSUM	UINT32_C(0x00560000)
+#define	RX_CTRL_LEN_MASK	UINT32_C(0x0000FFFF)
+
+#define	TX_CTRL_OWN_BMU 	UINT32_C(0x80000000)
+#define	TX_CTRL_STF		UINT32_C(0x40000000)
+#define	TX_CTRL_EOF		UINT32_C(0x20000000)
+#define	TX_CTRL_EOB_IRQ		UINT32_C(0x10000000)
+#define	TX_CTRL_EOF_IRQ		UINT32_C(0x08000000)
+#define TX_CTRL_ST_FWD		UINT32_C(0x04000000)
+#define TX_CTRL_DISAB_CRC	UINT32_C(0x02000000)
+#define TX_CTRL_SOFTWARE	UINT32_C(0x01000000)
+#define TX_CTRL_CHECK_DEFAULT	UINT32_C(0x00550000)
+#define TX_CTRL_CHECK_CSUM	UINT32_C(0x00560000)
+#define	TX_CTRL_LEN_MASK	UINT32_C(0x0000FFFF)
+
+
+
+/* The offsets of registers in the TX and RX queue control io area ***********/
+
+#define RX_Q_BUF_CTRL_CNT	0x00
+#define RX_Q_NEXT_DESCR_LOW	0x04
+#define RX_Q_BUF_ADDR_LOW	0x08
+#define RX_Q_BUF_ADDR_HIGH	0x0c
+#define RX_Q_FRAME_STAT		0x10
+#define RX_Q_TIME_STAMP		0x14
+#define RX_Q_CSUM_1_2		0x18
+#define RX_Q_CSUM_START_1_2	0x1c
+#define RX_Q_CUR_DESCR_LOW	0x20
+#define RX_Q_DESCR_HIGH		0x24
+#define RX_Q_CUR_ADDR_LOW	0x28
+#define RX_Q_CUR_ADDR_HIGH	0x2c
+#define RX_Q_CUR_BYTE_CNT	0x30
+#define RX_Q_CTRL		0x34
+#define RX_Q_FLAG		0x38
+#define RX_Q_TEST1		0x3c
+#define RX_Q_TEST2		0x40
+#define RX_Q_TEST3		0x44
+
+#define TX_Q_BUF_CTRL_CNT	0x00
+#define TX_Q_NEXT_DESCR_LOW	0x04
+#define TX_Q_BUF_ADDR_LOW	0x08
+#define TX_Q_BUF_ADDR_HIGH	0x0c
+#define TX_Q_FRAME_STAT		0x10
+#define TX_Q_CSUM_START		0x14
+#define TX_Q_CSUM_START_POS	0x18
+#define TX_Q_RESERVED		0x1c
+#define TX_Q_CUR_DESCR_LOW	0x20
+#define TX_Q_DESCR_HIGH		0x24
+#define TX_Q_CUR_ADDR_LOW	0x28
+#define TX_Q_CUR_ADDR_HIGH	0x2c
+#define TX_Q_CUR_BYTE_CNT	0x30
+#define TX_Q_CTRL		0x34
+#define TX_Q_FLAG		0x38
+#define TX_Q_TEST1		0x3c
+#define TX_Q_TEST2		0x40
+#define TX_Q_TEST3		0x44
+
+/* definition of flags in the queue control field */
+#define RX_Q_CTRL_POLL_ON	0x00000080
+#define RX_Q_CTRL_POLL_OFF	0x00000040
+#define RX_Q_CTRL_STOP		0x00000020
+#define RX_Q_CTRL_START		0x00000010
+#define RX_Q_CTRL_CLR_I_PAR	0x00000008
+#define RX_Q_CTRL_CLR_I_EOB	0x00000004
+#define RX_Q_CTRL_CLR_I_EOF	0x00000002
+#define RX_Q_CTRL_CLR_I_ERR	0x00000001
+
+#define TX_Q_CTRL_POLL_ON	0x00000080
+#define TX_Q_CTRL_POLL_OFF	0x00000040
+#define TX_Q_CTRL_STOP		0x00000020
+#define TX_Q_CTRL_START		0x00000010
+#define TX_Q_CTRL_CLR_I_EOB	0x00000004
+#define TX_Q_CTRL_CLR_I_EOF	0x00000002
+#define TX_Q_CTRL_CLR_I_ERR	0x00000001
+
+
+/* Interrupt bits in the interrupts source register **************************/
+#define IRQ_HW_ERROR		0x80000000
+#define IRQ_RESERVED		0x40000000
+#define IRQ_PKT_TOUT_RX1	0x20000000
+#define IRQ_PKT_TOUT_RX2	0x10000000
+#define IRQ_PKT_TOUT_TX1	0x08000000
+#define IRQ_PKT_TOUT_TX2	0x04000000
+#define IRQ_I2C_READY		0x02000000
+#define IRQ_SW			0x01000000
+#define IRQ_EXTERNAL_REG	0x00800000
+#define IRQ_TIMER		0x00400000
+#define IRQ_MAC1		0x00200000
+#define IRQ_LINK_SYNC_C_M1	0x00100000
+#define IRQ_MAC2		0x00080000
+#define IRQ_LINK_SYNC_C_M2	0x00040000
+#define IRQ_EOB_RX1		0x00020000
+#define IRQ_EOF_RX1		0x00010000
+#define IRQ_CHK_RX1		0x00008000
+#define IRQ_EOB_RX2		0x00004000
+#define IRQ_EOF_RX2		0x00002000
+#define IRQ_CHK_RX2		0x00001000
+#define IRQ_EOB_SY_TX1		0x00000800
+#define IRQ_EOF_SY_TX1		0x00000400
+#define IRQ_CHK_SY_TX1		0x00000200
+#define IRQ_EOB_AS_TX1		0x00000100
+#define IRQ_EOF_AS_TX1		0x00000080
+#define IRQ_CHK_AS_TX1		0x00000040
+#define IRQ_EOB_SY_TX2		0x00000020
+#define IRQ_EOF_SY_TX2		0x00000010
+#define IRQ_CHK_SY_TX2		0x00000008
+#define IRQ_EOB_AS_TX2		0x00000004
+#define IRQ_EOF_AS_TX2		0x00000002
+#define IRQ_CHK_AS_TX2		0x00000001
+
+#define DRIVER_IRQS	(IRQ_SW | IRQ_EOF_RX1 | IRQ_EOF_RX2 | \
+			IRQ_EOF_SY_TX1 | IRQ_EOF_AS_TX1 | \
+			IRQ_EOF_SY_TX2 | IRQ_EOF_AS_TX2)
+
+#define SPECIAL_IRQS	(IRQ_HW_ERROR | IRQ_PKT_TOUT_RX1 | IRQ_PKT_TOUT_RX2 | \
+			IRQ_PKT_TOUT_TX1 | IRQ_PKT_TOUT_TX2 | \
+			IRQ_I2C_READY | IRQ_EXTERNAL_REG | IRQ_TIMER | \
+			IRQ_MAC1 | IRQ_LINK_SYNC_C_M1 | \
+			IRQ_MAC2 | IRQ_LINK_SYNC_C_M2 | \
+			IRQ_CHK_RX1 | IRQ_CHK_RX2 | \
+			IRQ_CHK_SY_TX1 | IRQ_CHK_AS_TX1 | \
+			IRQ_CHK_SY_TX2 | IRQ_CHK_AS_TX2)
+
+#define IRQ_MASK	(IRQ_SW | IRQ_EOB_RX1 | IRQ_EOF_RX1 | \
+			IRQ_EOB_RX2 | IRQ_EOF_RX2 | \
+			IRQ_EOB_SY_TX1 | IRQ_EOF_SY_TX1 | \
+			IRQ_EOB_AS_TX1 | IRQ_EOF_AS_TX1 | \
+			IRQ_EOB_SY_TX2 | IRQ_EOF_SY_TX2 | \
+			IRQ_EOB_AS_TX2 | IRQ_EOF_AS_TX2 | \
+			IRQ_HW_ERROR | IRQ_PKT_TOUT_RX1 | IRQ_PKT_TOUT_RX2 | \
+			IRQ_PKT_TOUT_TX1 | IRQ_PKT_TOUT_TX2 | \
+			IRQ_I2C_READY | IRQ_EXTERNAL_REG | IRQ_TIMER | \
+			IRQ_MAC1 | \
+			IRQ_MAC2 | \
+			IRQ_CHK_RX1 | IRQ_CHK_RX2 | \
+			IRQ_CHK_SY_TX1 | IRQ_CHK_AS_TX1 | \
+			IRQ_CHK_SY_TX2 | IRQ_CHK_AS_TX2)
+
+#define IRQ_HWE_MASK	0x00000FFF /* enable all HW irqs */
+
+typedef struct s_TxPort		TX_PORT;
+
+struct s_TxPort {
+	/* the transmit descriptor rings */
+	caddr_t		pTxDescrRing;	/* descriptor area memory */
+	SK_U64		VTxDescrRing;	/* descr. area bus virt. addr. */
+	TXD		*pTxdRingHead;	/* Head of Tx rings */
+	TXD		*pTxdRingTail;	/* Tail of Tx rings */
+	TXD		*pTxdRingPrev;	/* descriptor sent previously */
+	int		TxdRingFree;	/* # of free entrys */
+	spinlock_t	TxDesRingLock;	/* serialize descriptor accesses */
+	caddr_t		HwAddr;		/* bmu registers address */
+	int		PortIndex;	/* index number of port (0 or 1) */
+};
+
+typedef struct s_RxPort		RX_PORT;
+
+struct s_RxPort {
+	/* the receive descriptor rings */
+	caddr_t		pRxDescrRing;	/* descriptor area memory */
+	SK_U64		VRxDescrRing;   /* descr. area bus virt. addr. */
+	RXD		*pRxdRingHead;	/* Head of Rx rings */
+	RXD		*pRxdRingTail;	/* Tail of Rx rings */
+	RXD		*pRxdRingPrev;	/* descriptor given to BMU previously */
+	int		RxdRingFree;	/* # of free entrys */
+	spinlock_t	RxDesRingLock;	/* serialize descriptor accesses */
+	int		RxFillLimit;	/* limit for buffers in ring */
+	caddr_t		HwAddr;		/* bmu registers address */
+	int		PortIndex;	/* index number of port (0 or 1) */
+};
+
+typedef struct s_PerStrm	PER_STRM;
+
+#define SK_ALLOC_IRQ	0x00000001
+
+/****************************************************************************
+ * Per board structure / Adapter Context structure:
+ *	Allocated within attach(9e) and freed within detach(9e).
+ *	Contains all 'per device' necessary handles, flags, locks etc.:
+ */
+struct s_AC  {
+	SK_GEINIT	GIni;		/* GE init struct */
+	SK_PNMI		Pnmi;		/* PNMI data struct */
+	SK_VPD		vpd;		/* vpd data struct */
+	SK_QUEUE	Event;		/* Event queue */
+	SK_HWT		Hwt;		/* Hardware Timer control struct */
+	SK_TIMCTRL	Tim;		/* Software Timer control struct */
+	SK_I2C		I2c;		/* I2C relevant data structure */
+	SK_ADDR		Addr;		/* for Address module */
+	SK_CSUM		Csum;		/* for checksum module */
+	SK_RLMT		Rlmt;		/* for rlmt module */
+	spinlock_t	SlowPathLock;	/* Normal IRQ lock */
+	SK_PNMI_STRUCT_DATA PnmiStruct;	/* structure to get all Pnmi-Data */
+	int		RlmtMode;	/* link check mode to set */
+	
+	SK_IOC		IoBase;		/* register set of adapter */
+	int		BoardLevel;	/* level of active hw init (0-2) */
+	char		DeviceStr[80];	/* adapter string from vpd */
+	SK_U32		AllocFlag;	/* flag allocation of resources */
+	struct pci_dev	PciDev;		/* for access to pci config space */
+	SK_U32		PciDevId;	/* pci device id */
+	struct device	*dev;		/* pointer to device struct */
+	char		Name[30];	/* driver name */
+	struct device	*Next;		/* link all devices (for clearing) */
+	int		RxBufSize;	/* length of receive buffers */
+        struct net_device_stats stats;	/* linux 'netstat -i' statistics */
+	int		Index;		/* internal board index number */
+
+	/* adapter RAM sizes for queues of active port */
+	int		RxQueueSize;	/* memory used for receive queue */
+	int		TxSQueueSize;	/* memory used for sync. tx queue */
+	int		TxAQueueSize;	/* memory used for async. tx queue */
+
+	int		PromiscCount;	/* promiscuous mode counter  */
+	int		AllMultiCount;  /* allmulticast mode counter */
+	int		MulticCount;	/* number of different MC    */
+					/*  addresses for this board */
+					/*  (may be more than HW can)*/
+
+	int		ActivePort;	/* the active XMAC port */
+	int		TxDescrPerRing;	/* # of descriptors per tx ring */
+	int		RxDescrPerRing;	/* # of descriptors per rx ring */
+
+	
+	caddr_t		pDescrMem;	/* Pointer to the descriptor area */
+	/* the port structures with descriptor rings */
+	TX_PORT		TxPort[SK_MAX_MACS][2];
+	RX_PORT		RxPort[SK_MAX_MACS];
+
+	unsigned int	CsOfs1;		/* for checksum calculation */
+	unsigned int	CsOfs2;		/* for checksum calculation */
+	SK_U32		CsOfs;		/* for checksum calculation */
+
+	SK_BOOL		CheckQueue;	/* check event queue soon */
+};
+
+
+#endif /* __INC_SKDRV2ND_H */
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skerror.h linux.14p16/drivers/net/sk98lin/h/skerror.h
--- linux.vanilla/drivers/net/sk98lin/h/skerror.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skerror.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ * Name:	skerror.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.3 $
+ * Date:	$Date: 1999/09/14 14:04:42 $
+ * Purpose:	SK specific Error log support
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *	$Log: skerror.h,v $
+ *	Revision 1.3  1999/09/14 14:04:42  rwahl
+ *	Added error base SK_ERRBASE_PECP.
+ *	Changed error base for driver.
+ *	
+ *	Revision 1.2  1998/08/11 11:15:41  gklug
+ *	chg: comments
+ *	
+ *	Revision 1.1  1998/08/11 11:09:38  gklug
+ *	add: error bases
+ *	add: error Classes
+ *	first version
+ *	
+ *	
+ *
+ ******************************************************************************/
+
+#ifndef _INC_SKERROR_H_
+#define _INC_SKERROR_H_
+
+/*
+ * Define the Error Classes
+ */
+#define	SK_ERRCL_OTHER		(0)	/* Other error */
+#define	SK_ERRCL_CONFIG		(1L<<0)	/* Configuration error */
+#define	SK_ERRCL_INIT		(1L<<1)	/* Initialization error */
+#define	SK_ERRCL_NORES		(1L<<2)	/* Out of resources error */
+#define	SK_ERRCL_SW		(1L<<3)	/* internal Software error */
+#define	SK_ERRCL_HW		(1L<<4)	/* Hardware failure */
+#define	SK_ERRCL_COMM		(1L<<5)	/* Communication error */
+
+
+/*
+ * Define Error code bases
+ */
+#define	SK_ERRBASE_RLMT		100	/* Base Error number for RLMT */
+#define	SK_ERRBASE_HWINIT	200	/* Base Error number for HWInit */
+#define	SK_ERRBASE_VPD		300	/* Base Error number for VPD */
+#define	SK_ERRBASE_PNMI		400	/* Base Error number for PNMI */
+#define	SK_ERRBASE_CSUM		500	/* Base Error number for Checksum */
+#define	SK_ERRBASE_SIRQ		600	/* Base Error number for Special IRQ */
+#define	SK_ERRBASE_I2C		700	/* Base Error number for i2C module */
+#define	SK_ERRBASE_QUEUE	800	/* Base Error number for Scheduler */
+#define	SK_ERRBASE_ADDR		900	/* Base Error number for Address mod. */
+#define SK_ERRBASE_PECP		1000    /* Base Error number for PECP */
+#define	SK_ERRBASE_DRV		1100	/* Base Error number for Driver */
+
+#endif	/* _INC_SKERROR_H_ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skgedrv.h linux.14p16/drivers/net/sk98lin/h/skgedrv.h
--- linux.vanilla/drivers/net/sk98lin/h/skgedrv.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skgedrv.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,62 @@
+/******************************************************************************
+ *
+ * Name:	skgedrv.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.3 $
+ * Date:	$Date: 1998/12/01 13:31:39 $
+ * Purpose:	Interface with the driver
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgedrv.h,v $
+ *	Revision 1.3  1998/12/01 13:31:39  cgoos
+ *	SWITCH INTERN Event added.
+ *	
+ *	Revision 1.2  1998/11/25 08:28:38  gklug
+ *	rmv: PORT SWITCH Event
+ *	
+ *	Revision 1.1  1998/09/29 06:14:07  gklug
+ *	add: driver events (initial version)
+ *	
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKGEDRV_H_
+#define __INC_SKGEDRV_H_
+
+/* defines ********************************************************************/
+
+/*
+ * Define the driver events.
+ * Usually the events are defined by the destination module. In case of the
+ * driver we put the definition of the events here.
+ */
+#define SK_DRV_PORT_RESET	1	/* The port needs to be reset */
+#define SK_DRV_NET_UP   	2	/* The net is now operational */
+#define SK_DRV_NET_DOWN		3	/* The net is now down */
+#define	SK_DRV_SWITCH_SOFT	4	/* Ports switch with both links conn */
+#define	SK_DRV_SWITCH_HARD	5	/* Port switch due to link failure */
+#define	SK_DRV_RLMT_SEND	6	/* Send a RLMT packet */
+#define	SK_DRV_ADAP_FAIL	7	/* The whole adapter fails */
+#define	SK_DRV_PORT_FAIL	8	/* One port fails */
+#define	SK_DRV_SWITCH_INTERN	9	/* Port switch from driver to itself */
+
+#endif	/* __INC_SKGEDRV_H_ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skgehw.h linux.14p16/drivers/net/sk98lin/h/skgehw.h
--- linux.vanilla/drivers/net/sk98lin/h/skgehw.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skgehw.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,1715 @@
+/******************************************************************************
+ *
+ * Name:	skgehw.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.33 $
+ * Date:	$Date: 1999/08/27 11:17:10 $
+ * Purpose:	Defines and Macros for the Gigabit Ethernet Adapter Product
+ *		Family
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ * $Log: skgehw.h,v $
+ * Revision 1.33  1999/08/27 11:17:10  malthoff
+ * It's more savely to put bracket around marco parameters.
+ * Brackets added for PHY_READ and PHY_WRITE.
+ *
+ * Revision 1.32  1999/05/19 07:31:01  cgoos
+ * Changes for 1000Base-T.
+ * Added HWAC_LINK_LED macro.
+ *
+ * Revision 1.31  1999/03/12 13:27:40  malthoff
+ * Remove __STDC__.
+ *
+ * Revision 1.30  1999/02/09 09:28:20  malthoff
+ * Add PCI_ERRBITS.
+ *
+ * Revision 1.29  1999/01/26 08:55:48  malthoff
+ * Bugfix: The 16 bit field releations inside the descriptor are
+ * 	endianess dependend if the descriptor reversal feature
+ * 	(PCI_REV_DESC bit in PCI_OUR_REG_2) is enabled.
+ * 	Drivers which use this feature has to set the define
+ * 	SK_USE_REV_DESC.
+ *
+ * Revision 1.28  1998/12/10 11:10:22  malthoff
+ * bug fix: IS_IRQ_STAT and IS_IRQ_MST_ERR has been twisted.
+ *
+ * Revision 1.27  1998/11/13 14:19:21  malthoff
+ * Bug Fix: The bit definition of B3_PA_CTRL has completely
+ * changed from HW Spec v1.3 to v1.5.
+ *
+ * Revision 1.26  1998/11/04 08:31:48  cgoos
+ * Fixed byte ordering in XM_OUTADDR/XM_OUTHASH macros.
+ *
+ * Revision 1.25  1998/11/04 07:16:25  cgoos
+ * Changed byte ordering in XM_INADDR/XM_INHASH again.
+ *
+ * Revision 1.24  1998/11/02 11:08:43  malthoff
+ * RxCtrl and TxCtrl must be volatile.
+ *
+ * Revision 1.23  1998/10/28 13:50:45  malthoff
+ * Fix: Endian support missing in XM_IN/OUT-ADDR/HASH macros.
+ *
+ * Revision 1.22  1998/10/26 08:01:36  malthoff
+ * RX_MFF_CTRL1 is split up into RX_MFF_CTRL1,
+ * RX_MFF_STAT_TO, and RX_MFF_TIST_TO.
+ * TX_MFF_CTRL1 is split up TX_MFF_CTRL1 and TX_MFF_WAF.
+ *
+ * Revision 1.21  1998/10/20 07:43:10  malthoff
+ * Fix: XM_IN/OUT/ADDR/HASH macros:
+ * The pointer must be casted.
+ *
+ * Revision 1.20  1998/10/19 15:53:59  malthoff
+ * Remove ML proto definitions.
+ *
+ * Revision 1.19  1998/10/16 14:40:17  gklug
+ * fix: typo B0_XM_IMSK regs
+ *
+ * Revision 1.18  1998/10/16 09:46:54  malthoff
+ * Remove temp defines for ML diag prototyp.
+ * Fix register definition for B0_XM1_PHY_DATA, B0_XM1_PHY_DATA
+ * B0_XM2_PHY_DATA, B0_XM2_PHY_ADDR, B0_XA1_CSR, B0_XS1_CSR,
+ * B0_XS2_CSR, and B0_XA2_CSR.
+ *
+ * Revision 1.17  1998/10/14 06:03:14  cgoos
+ * Changed shifted constant to ULONG.
+ *
+ * Revision 1.16  1998/10/09 07:05:41  malthoff
+ * Rename ALL_PA_ENA_TO to PA_ENA_TO_ALL.
+ *
+ * Revision 1.15  1998/10/05 07:54:23  malthoff
+ * Split up RB_CTRL and it's bit definition into
+ * RB_CTRL, RB_TST1, and RB_TST2.
+ * Rename RB_RX_HTPP to RB_RX_LTPP.
+ * Add ALL_PA_ENA_TO. Modify F_WATER_MARK
+ * according to HW Spec. v1.5.
+ * Add MFF_TX_CTRL_DEF.
+ *
+ * Revision 1.14  1998/09/28 13:31:16  malthoff
+ * bug fix: B2_MAC_3 is 0x110 not 0x114
+ *
+ * Revision 1.13  1998/09/24 14:42:56  malthoff
+ * Split the RX_MFF_TST into RX_MFF_CTRL2,
+ * RX_MFF_TST1, and RX_MFF_TST2.
+ * Rename RX_MFF_CTRL to RX_MFF_CTRL1.
+ * Add BMU bit CSR_SV_IDLE.
+ * Add macros PHY_READ() and PHY_WRITE().
+ * Rename macro SK_ADDR() to SK_HW_ADDR()
+ * because of conflicts with the Address Module.
+ *
+ * Revision 1.12  1998/09/16 07:25:33  malthoff
+ * Change the parameter order in the XM_INxx and XM_OUTxx macros,
+ * to have the IoC as first parameter.
+ *
+ * Revision 1.11  1998/09/03 09:58:41  malthoff
+ * Rework the XM_xxx macros. Use {} instead of () to
+ * be compatible with SK_xxx macros which are defined
+ * with {}.
+ *
+ * Revision 1.10  1998/09/02 11:16:39  malthoff
+ * Temporary modify B2_I2C_SW to make tests with
+ * the GE/ML prototyp.
+ *
+ * Revision 1.9  1998/08/19 09:11:49  gklug
+ * fix: struct are removed from c-source (see CCC)
+ * add: typedefs for all structs
+ *
+ * Revision 1.8  1998/08/18 08:27:27  malthoff
+ * Add some temporary workarounds to test GE
+ * sources with the ML.
+ *
+ * Revision 1.7  1998/07/03 14:42:26  malthoff
+ * bug fix: Correct macro XMA().
+ * Add temporary workaround to access the PCI config space over IO
+ *
+ * Revision 1.6  1998/06/23 11:30:36  malthoff
+ * Remove ';' with ',' in macors.
+ *
+ * Revision 1.5  1998/06/22 14:20:57  malthoff
+ * Add macro SK_ADDR(Base,Addr).
+ *
+ * Revision 1.4  1998/06/19 13:35:43  malthoff
+ * change 'pGec' with 'pAC'
+ *
+ * Revision 1.3  1998/06/17 14:58:16  cvs
+ * Lost keywords reinserted.
+ *
+ * Revision 1.1  1998/06/17 14:16:36  cvs
+ * created
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKGEHW_H
+#define __INC_SKGEHW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* __cplusplus */
+
+/* defines ********************************************************************/
+
+/*
+ * Configuration Space header
+ * Since this module is used for different OS', those may be
+ * duplicate on some of them (e.g. Linux). But to keep the
+ * common source, we have to live with this...
+ */
+#define	PCI_VENDOR_ID	0x00	/* 16 bit	Vendor ID */
+#define	PCI_DEVICE_ID	0x02	/* 16 bit	Device ID */
+#define	PCI_COMMAND	0x04	/* 16 bit	Command */
+#define	PCI_STATUS	0x06	/* 16 bit	Status */
+#define	PCI_REV_ID	0x08	/*  8 bit	Revision ID */
+#define	PCI_CLASS_CODE	0x09	/* 24 bit	Class Code */
+#define	PCI_CACHE_LSZ	0x0c	/*  8 bit	Cache Line Size */
+#define	PCI_LAT_TIM	0x0d	/*  8 bit	Latency Timer */
+#define	PCI_HEADER_T	0x0e	/*  8 bit	Header Type */
+#define	PCI_BIST	0x0f	/*  8 bit	Built-in selftest */
+#define	PCI_BASE_1ST	0x10	/* 32 bit	1st Base address */
+#define	PCI_BASE_2ND	0x14	/* 32 bit	2nd Base address */
+	/* Byte 18..2b:	reserved */
+#define	PCI_SUB_VID	0x2c	/* 16 bit	Subsystem Vendor ID */
+#define	PCI_SUB_ID	0x2e	/* 16 bit	Subsystem ID */
+#define	PCI_BASE_ROM	0x30	/* 32 bit	Expansion ROM Base Address */
+	/* Byte 34..33:	reserved */
+#define PCI_CAP_PTR	0x34	/*  8 bit 	Capabilities Ptr */
+	/* Byte 35..3b:	reserved */
+#define	PCI_IRQ_LINE	0x3c	/*  8 bit	Interrupt Line */
+#define	PCI_IRQ_PIN	0x3d	/*  8 bit	Interrupt Pin */
+#define	PCI_MIN_GNT	0x3e	/*  8 bit	Min_Gnt */
+#define	PCI_MAX_LAT	0x3f	/*  8 bit	Max_Lat */
+	/* Device Dependent Region */
+#define	PCI_OUR_REG_1	0x40	/* 32 bit 	Our Register 1 */
+#define	PCI_OUR_REG_2	0x44	/* 32 bit 	Our Register 2 */
+	/* Power Management Region */
+#define PCI_PM_CAP_ID	0x48	/*  8 bit 	Power Management Cap. ID */
+#define PCI_PM_NITEM	0x49	/*  8 bit 	Next Item Ptr */
+#define PCI_PM_CAP_REG	0x4a	/* 16 bit 	Power Management Capabilities */
+#define PCI_PM_CTL_STS	0x4c	/* 16 bit 	Power Manag. Control/Status */
+	/* Byte 0x4e:	reserved */
+#define PCI_PM_DAT_REG	0x4f	/*  8 bit 	Power Manag. Data Register */
+	/* VPD Region */
+#define	PCI_VPD_CAP_ID	0x50	/*  8 bit 	VPD Cap. ID */
+#define PCI_VPD_NITEM	0x51	/*  8 bit 	Next Item Ptr */
+#define PCI_VPD_ADR_REG	0x52	/* 16 bit 	VPD Address Register */
+#define PCI_VPD_DAT_REG	0x54	/* 32 bit 	VPD Data Register */
+	/* Byte 58..ff:	reserved */
+
+/*
+ * I2C Address (PCI Config)
+ *
+ * Note: The temperature and voltage sensors are relocated on a different
+ *	 I2C bus.
+ */
+#define I2C_ADDR_VPD	0xA0	/* I2C address for the VPD EEPROM */
+
+/*
+ * Define Bits and Values of the registers
+ */
+/*	PCI_VENDOR_ID	16 bit	Vendor ID */
+/*	PCI_DEVICE_ID	16 bit	Device ID */
+/* Values for Vendor ID and Device ID shall be patched into the code */
+/*	PCI_COMMAND	16 bit	Command */
+				/* Bit 15..10:	reserved */
+#define	PCI_FBTEN	(1<<9)	/* Bit 9:	Fast Back-To-Back enable */
+#define	PCI_SERREN	(1<<8)	/* Bit 8:	SERR enable */
+#define	PCI_ADSTEP	(1<<7)	/* Bit 7:	Address Stepping */
+#define	PCI_PERREN	(1<<6)	/* Bit 6:	Parity Report Response enable */
+#define	PCI_VGA_SNOOP	(1<<5)	/* Bit 5:	VGA palette snoop */
+#define	PCI_MWIEN	(1<<4)	/* Bit 4:	Memory write an inv cycl ena */
+#define	PCI_SCYCEN	(1<<3)	/* Bit 3:	Special Cycle enable */
+#define	PCI_BMEN	(1<<2)	/* Bit 2:	Bus Master enable */
+#define	PCI_MEMEN	(1<<1)	/* Bit 1:	Memory Space Access enable */
+#define	PCI_IOEN	(1<<0)	/* Bit 0:	IO Space Access enable */
+
+/*	PCI_STATUS	16 bit	Status */
+#define	PCI_PERR	(1<<15)	/* Bit 15:	Parity Error */
+#define	PCI_SERR	(1<<14)	/* Bit 14:	Signaled SERR */
+#define	PCI_RMABORT	(1<<13)	/* Bit 13:	Received Master Abort */
+#define	PCI_RTABORT	(1<<12)	/* Bit 12:	Received Target Abort */
+				/* Bit 11:	reserved */
+#define	PCI_DEVSEL	(3<<9)	/* Bit 10..9:	DEVSEL Timing */
+#define	PCI_DEV_FAST	(0<<9)	/*		fast */
+#define	PCI_DEV_MEDIUM	(1<<9)	/*		medium */
+#define	PCI_DEV_SLOW	(2<<9)	/*		slow */
+#define	PCI_DATAPERR	(1<<8)	/* Bit 8:	DATA Parity error detected */
+#define	PCI_FB2BCAP	(1<<7)	/* Bit 7:	Fast Back-to-Back Capability */
+#define	PCI_UDF		(1<<6)	/* Bit 6:	User Defined Features */
+#define PCI_66MHZCAP	(1<<5)	/* Bit 5:	66 MHz PCI bus clock capable */
+#define PCI_NEWCAP	(1<<4)	/* Bit 4:	New cap. list implemented */
+				/* Bit 3..0:	reserved */
+
+#define PCI_ERRBITS	(PCI_PERR | PCI_SERR | PCI_RMABORT | PCI_RTABORT |\
+			PCI_DATAPERR)
+
+/*	PCI_CLASS_CODE	24 bit	Class Code */
+/*	Byte 2:		Base Class		(02) */
+/*	Byte 1:		SubClass		(00) */
+/*	Byte 0:		Programming Interface	(00) */
+
+/*	PCI_CACHE_LSZ	8 bit	Cache Line Size */
+/*	Possible values: 0,2,4,8,16,32,64,128	*/
+
+/*	PCI_HEADER_T	8 bit	Header Type */
+#define	PCI_HD_MF_DEV	(1<<7)	/* Bit 7:	0= single, 1= multi-func dev */
+#define	PCI_HD_TYPE	0x7f	/* Bit 6..0:	Header Layout 0= normal */
+
+/*	PCI_BIST	8 bit	Built-in selftest */
+/*	Built-in Self test not supported (optional) */
+
+/*	PCI_BASE_1ST	32 bit	1st Base address */
+#define	PCI_MEMSIZE	0x4000L		/* use 16 kB Memory Base */
+#define	PCI_MEMBASE_MSK 0xffffc000L	/* Bit 31..14:	Memory Base Address */
+#define	PCI_MEMSIZE_MSK 0x00003ff0L	/* Bit 13.. 4:	Memory Size Req. */
+#define	PCI_PREFEN	(1L<<3)		/* Bit	3:	Prefetchable */
+#define	PCI_MEM_TYP	(3L<<2)		/* Bit	2.. 1:	Memory Type */
+#define	PCI_MEM32BIT	(0L<<1)		/* Base addr anywhere in 32 Bit range */
+#define	PCI_MEM1M	(1L<<1)		/* Base addr below 1 MegaByte */
+#define	PCI_MEM64BIT	(2L<<1)		/* Base addr anywhere in 64 Bit range */
+#define	PCI_MEMSPACE	(1L<<0)		/* Bit	0:	Memory Space Indic. */
+
+/*	PCI_BASE_2ND	32 bit	2nd Base address */
+#define	PCI_IOBASE	0xffffff00L	/* Bit 31..8:	I/O Base address */
+#define	PCI_IOSIZE	0x000000fcL	/* Bit	7..2:	I/O Size Requirements */
+					/* Bit	1:	reserved */
+#define	PCI_IOSPACE	(1L<<0)		/* Bit	0:	I/O Space Indicator */
+
+/*	PCI_BASE_ROM	32 bit	Expansion ROM Base Address */
+#define	PCI_ROMBASE	(0xfffeL<<17)	/* Bit 31..17:	ROM BASE address (1st)*/
+#define	PCI_ROMBASZ	(0x1cL<<14)	/* Bit 16..14:	Treat as BASE or SIZE */
+#define	PCI_ROMSIZE	(0x38L<<11)	/* Bit 13..11:	ROM Size Requirements */
+					/* Bit 10.. 1:	reserved */
+#define	PCI_ROMEN	(0x1L<<0)	/* Bit 0:	Address Decode enable */
+
+/* Device Dependent Region */
+/*	PCI_OUR_REG_1		32 bit	Our Register 1 */
+					/* Bit 31..26:	reserved */
+#define PCI_VIO		(1L<<25)	/* Bit 25:	PCI IO Voltage, */
+					/*		0 = 3.3V / 1 = 5V */
+#define	PCI_EN_BOOT	(1L<<24)	/* Bit 24:	Enable BOOT via ROM */
+					/*		1 = Don't boot wth ROM*/
+					/*		0 = Boot with ROM */
+#define	PCI_EN_IO	(1L<<23)	/* Bit 23:	Mapping to IO space */
+#define	PCI_EN_FPROM	(1L<<22)	/* Bit 22:	FLASH mapped to mem? */
+					/*		1 = Map Flash to Mem */
+					/*		0 = Disable addr. dec*/
+#define	PCI_PAGESIZE	(3L<<20)	/* Bit 21..20:	FLASH Page Size	*/
+#define	PCI_PAGE_16	(0L<<20)	/*		16 k pages	*/
+#define	PCI_PAGE_32K	(1L<<20)	/*		32 k pages	*/
+#define	PCI_PAGE_64K	(2L<<20)	/*		64 k pages	*/
+#define	PCI_PAGE_128K	(3L<<20)	/*		128 k pages	*/
+					/* Bit 19:	reserved	*/
+#define	PCI_PAGEREG	(7L<<16)	/* Bit 18..16:	Page Register	*/
+#define PCI_NOTAR	(1L<<15)	/* Bit 15:	No turnaround cycle */
+#define	PCI_FORCE_BE	(1L<<14)	/* Bit 14:	Assert all BEs on MR */
+#define	PCI_DIS_MRL	(1L<<13)	/* Bit 13:	Disable Mem R Line */
+#define	PCI_DIS_MRM	(1L<<12)	/* Bit 12:	Disable Mem R multip */
+#define	PCI_DIS_MWI	(1L<<11)	/* Bit 11:	Disable Mem W & inv */
+#define	PCI_DISC_CLS	(1L<<10)	/* Bit 10:	Disc: cacheLsz bound */
+#define	PCI_BURST_DIS	(1L<<9)		/* Bit	9:	Burst Disable */
+#define	PCI_DIS_PCI_CLK	(1L<<8)		/* Bit	8:	Disable PCI clock driv*/
+#define	PCI_SKEW_DAS	(0xfL<<4)	/* Bit	7..4:	Skew Ctrl, DAS Ext */
+#define	PCI_SKEW_BASE	(0xfL<<0)	/* Bit	3..0:	Skew Ctrl, Base	*/
+
+
+/*	PCI_OUR_REG_2		32 bit	Our Register 2 */
+#define PCI_VPD_WR_THR	(0xffL<<24)	/* Bit 31..24:	VPD Write Threshold */
+#define	PCI_DEV_SEL	(0x7fL<<17)	/* Bit 23..17:	EEPROM Device Select */
+#define	PCI_VPD_ROM_SZ	(7L<<14)	/* Bit 16..14:	VPD ROM Size	*/
+					/* Bit 13..12:	reserved	*/
+#define	PCI_PATCH_DIR	(0xfL<<8)	/* Bit 11.. 8:	Ext Patchs dir 3..0 */
+#define	PCI_PATCH_DIR_0	(1L<<8)
+#define	PCI_PATCH_DIR_1	(1L<<9)
+#define	PCI_PATCH_DIR_2	(1L<<10)
+#define	PCI_PATCH_DIR_3	(1L<<11)
+#define PCI_EXT_PATCHS	(0xfL<<4)	/* Bit	7..4:	Extended Patches 3..0 */
+#define	PCI_EXT_PATCH_0	(1L<<4)
+#define	PCI_EXT_PATCH_1	(1L<<5)
+#define	PCI_EXT_PATCH_2	(1L<<6)
+#define	PCI_EXT_PATCH_3	(1L<<7)
+#define	PCI_EN_DUMMY_RD	(1L<<3)		/* Bit	3:	Enable Dummy Read */
+#define PCI_REV_DESC	(1L<<2)		/* Bit	2:	Reverse Desc. Bytes */
+					/* Bit	1:	reserved */
+#define PCI_USEDATA64	(1L<<0)		/* Bit	0:	Use 64Bit Data bus ext*/
+
+
+/* Power Management Region */
+/*	PCI_PM_CAP_REG		16 bit	Power Management Capabilities */
+#define	PCI_PME_SUP	(0x1f<<11)	/* Bit 15..11:	PM Manag. Event Sup */
+#define PCI_PM_D2_SUB	(1<<10)		/* Bit 10:	D2 Support Bit */
+#define PCI_PM_D1_SUB	(1<<9)		/* Bit	9:	D1 Support Bit */
+					/* Bit	8..6:	reserved */
+#define PCI_PM_DSI	(1<<5)		/* Bit	5:	Device Specific Init.*/
+#define PCI_PM_APS	(1<<4)		/* Bit	4:	Auxialiary Power Src */
+#define PCI_PME_CLOCK	(1<<3)		/* Bit	3:	PM Event Clock */
+#define PCI_PM_VER	(7<<0)		/* Bit	2..0:	PM PCI Spec. version */
+
+/*	PCI_PM_CTL_STS		16 bit	Power Manag. Control/Status */
+#define	PCI_PME_STATUS	(1<<15)		/* Bit 15: 	PGA doesn't sup. PME# */
+#define PCI_PM_DAT_SCL	(3<<13)		/* Bit 14..13:	dat reg Scaling factor*/
+#define PCI_PM_DAT_SEL	(0xf<<9)	/* Bit 12.. 9:	PM data selector field*/
+#define PCI_PME_EN	(1<<8)		/* Bit	8:	PGA doesn't sup. PME# */
+					/* Bit	7.. 2:	reserved */
+#define PCI_PM_STATE	(3<<0)		/* Bit	1.. 0:	Power Management State*/
+#define PCI_PM_STATE_D0	(0<<0)		/* D0:	Operational (default) */
+#define	PCI_PM_STATE_D1	(1<<0)		/* D1:	not supported */
+#define PCI_PM_STATE_D2	(2<<0)		/* D2:	not supported */
+#define PCI_PM_STATE_D3 (3<<0)		/* D3:	HOT, Power Down and Reset */
+
+/* VPD Region */
+/*	PCI_VPD_ADR_REG		16 bit	VPD Address Register */
+#define	PCI_VPD_FLAG	(1L<<15)	/* Bit 15:	starts VPD rd/wd cycle*/
+#define PCI_VPD_ADDR	(0x3fffL<<0)	/* Bit 14..0:	VPD address */
+
+/*
+ *	Control Register File:
+ *	Bank 0
+ */
+#define	B0_RAP		0x0000	/*  8 bit	Register Address Port */
+	/* 0x0001 - 0x0003:	reserved */
+#define	B0_CTST		0x0004	/* 16 bit	Control/Status register */
+#define	B0_LED		0x0006	/*  8 Bit	LED register */
+	/* 0x0007:		reserved */
+#define	B0_ISRC		0x0008	/* 32 bit	Interrupt Source Register */
+#define	B0_IMSK		0x000c	/* 32 bit	Interrupt Mask Register */
+#define B0_HWE_ISRC	0x0010	/* 32 bit	HW Error Interrupt Src Reg */
+#define B0_HWE_IMSK	0x0014	/* 32 bit	HW Error Interrupt Mask Reg */
+#define B0_SP_ISRC	0x0018	/* 32 bit	Special Interrupt Source Reg */
+	/* 0x001c:		reserved */
+
+/* B0 XMAC 1 registers */
+#define	B0_XM1_IMSK	0x0020	/* 16 bit r/w	XMAC 1 Interrupt Mask Register*/
+	/* 0x0022 - 0x0027	reserved */
+#define B0_XM1_ISRC	0x0028	/* 16 bit ro	XMAC 1 Interrupt Status Reg */
+	/* 0x002a - 0x002f	reserved */
+#define B0_XM1_PHY_ADDR 0x0030	/* 16 bit r/w	XMAC 1 PHY Address Register */
+	/* 0x0032 - 0x0033	reserved */
+#define B0_XM1_PHY_DATA 0x0034	/* 16 bit r/w	XMAC 1 PHY Data Register */
+	/* 0x0036 - 0x003f	reserved */
+
+/* B0 XMAC 2 registers */
+#define	B0_XM2_IMSK	0x0040	/* 16 bit r/w	XMAC 2 Interrupt Mask Register*/
+	/* 0x0042 - 0x0047	reserved */
+#define B0_XM2_ISRC	0x0048	/* 16 bit ro	XMAC 2 Interrupt Status Reg */
+	/* 0x004a - 0x004f	reserved */
+#define B0_XM2_PHY_ADDR 0x0050	/* 16 bit r/w	XMAC 2 PHY Address Register */
+	/* 0x0052 - 0x0053	reserved */
+#define B0_XM2_PHY_DATA 0x0054	/* 16 bit r/w	XMAC 2 PHY Data Register */
+				/* 0x0056 - 0x005f	reserved */
+
+/* BMU Control Status Registers */
+#define	B0_R1_CSR	0x0060	/* 32 bit	BMU Ctrl/Stat Rx Queue 1 */
+#define	B0_R2_CSR	0x0064	/* 32 bit	BMU Ctrl/Stat Rx Queue 2 */
+#define	B0_XS1_CSR	0x0068	/* 32 bit	BMU Ctrl/Stat Sync Tx Queue 1 */
+#define	B0_XA1_CSR	0x006c	/* 32 bit	BMU Ctrl/Stat Async Tx Queue 1*/
+#define	B0_XS2_CSR	0x0070	/* 32 bit	BMU Ctrl/Stat Sync Tx Queue 2 */
+#define	B0_XA2_CSR	0x0074	/* 32 bit	BMU Ctrl/Stat Async Tx Queue 2*/
+	/* x0078 - 0x007f	reserved */
+
+/*
+ *	Bank 1
+ *	- completely empty (this is the RAP Block window)
+ *	Note: if RAP = 1 this page is reserved
+ */
+
+/*
+ *	Bank 2
+ */
+/* NA reg = 48 bit Network Address Register, 3x16 or 8x8 bit readable */
+
+#define	B2_MAC_1	0x0100	/* NA reg	 MAC Address 1 */
+	/* 0x0106 - 0x0107	reserved */
+#define	B2_MAC_2	0x0108	/* NA reg	 MAC Address 2 */
+	/* 0x010e - 0x010f	reserved */
+#define	B2_MAC_3	0x0110	/* NA reg	 MAC Address 3 */
+	/* 0x0116 - 0x0117	reserved */
+#define B2_CONN_TYP	0x0118	/*  8 bit	Connector type */
+#define B2_PMD_TYP	0x0119	/*  8 bit	PMD type */
+#define B2_MAC_CFG	0x011a	/*  8 bit	MAC Configuration */
+#define B2_CHIP_REV	0x011b	/*  8 bit 	Queen Chip Revision Number */
+	/* Eprom registers are currently of no use */
+#define B2_E_0		0x011c	/*  8 bit	EPROM Byte 0 */
+#define B2_E_1		0x011d	/*  8 bit	EPROM Byte 1 */
+#define B2_E_2		0x011e	/*  8 bit	EPROM Byte 2 */
+#define B2_E_3		0x011f	/*  8 bit	EPROM Byte 3 */
+#define B2_FAR		0x0120	/* 32 bit	Flash-Prom Addr Reg/Cnt */
+#define B2_FDP		0x0124	/*  8 bit	Flash-Prom Data Port */
+	/* 0x0125 - 0x0127:	reserved */
+#define B2_LD_CRTL	0x0128	/*  8 bit	EPROM loader control register */
+#define B2_LD_TEST	0x0129	/*  8 bit	EPROM loader test register */
+	/* 0x012a - 0x012f:	reserved */
+#define B2_TI_INI	0x0130	/* 32 bit	Timer init value */
+#define B2_TI_VAL	0x0134	/* 32 bit	Timer value */
+#define B2_TI_CRTL	0x0138	/*  8 bit	Timer control */
+#define B2_TI_TEST	0x0139	/*  8 Bit	Timer Test */
+	/* 0x013a - 0x013f:	reserved */
+#define B2_IRQM_INI	0x0140	/* 32 bit	IRQ Moderation Timer Init Reg.*/
+#define B2_IRQM_VAL	0x0144	/* 32 bit	IRQ Moderation Timer Value */
+#define B2_IRQM_CTRL	0x0148	/*  8 bit	IRQ Moderation Timer Control */
+#define B2_IRQM_TEST	0x0149	/*  8 bit	IRQ Moderation Timer Test */
+#define B2_IRQM_MSK 	0x014c	/* 32 bit	IRQ Moderation Mask */
+#define B2_IRQM_HWE_MSK 0x0150	/* 32 bit	IRQ Moderation HW Error Mask */
+	/* 0x0154 - 0x0157:	reserved */
+#define	B2_TST_CTRL1	0x0158	/*  8 bit	Test Control Register 1 */
+#define B2_TST_CTRL2	0x0159	/*  8 bit	Test Control Register 2 */
+	/* 0x015a - 0x015b:	reserved */
+#define B2_GP_IO	0x015c	/* 32 bit	General Purpose IO Register */
+#define B2_I2C_CTRL	0x0160	/* 32 bit	I2C HW Control Register */
+#define B2_I2C_DATA	0x0164	/* 32 bit	I2C HW Data Register */
+#define B2_I2C_IRQ	0x0168	/* 32 bit	I2C HW IRQ Register */
+#define B2_I2C_SW	0x016c	/* 32 bit	I2C SW Port Register */
+#define B2_BSC_INI	0x0170	/* 32 bit	Blink Source Counter Init Val */
+#define B2_BSC_VAL	0x0174	/* 32 bit	Blink Source Counter Value */
+#define B2_BSC_CTRL	0x0178	/*  8 bit	Blink Source Counter Control */
+#define B2_BSC_STAT	0x0179	/*  8 bit	Blink Source Counter Status */
+#define B2_BSC_TST	0x017a	/* 16 bit	Blink Source Counter Test Reg */
+	/* 0x017c - 0x017f:	reserved */
+
+/*
+ *	Bank 3
+ */
+#define B3_RAM_ADDR	0x0180	/* 32 bit	RAM Address, to read or write */
+#define B3_RAM_DATA_LO	0x0184	/* 32 bit	RAM Data Word (low dWord) */
+#define B3_RAM_DATA_HI	0x0188	/* 32 bit	RAM Data Word (high dWord) */
+	/* 0x018c - 0x018f:	reserved */
+/* RAM Interface Registers */
+/*
+ * The HW-Spec. call this registers Timeout Value 0..11. But this names are
+ * not usable in SW. Please notice these are NOT real timeouts, these are
+ * the number of qWords transfered continously.
+ */
+#define B3_RI_WTO_R1	0x0190	/* 8 bit RAM Iface WR Timeout Queue R1	(TO0) */
+#define B3_RI_WTO_XA1	0x0191	/* 8 bit RAM Iface WR Timeout Queue XA1	(TO1) */
+#define B3_RI_WTO_XS1	0x0192	/* 8 bit RAM Iface WR Timeout Queue XS1 (TO2) */
+#define B3_RI_RTO_R1	0x0193	/* 8 bit RAM Iface RD Timeout Queue R1	(TO3) */
+#define B3_RI_RTO_XA1	0x0194	/* 8 bit RAM Iface RD Timeout Queue XA1	(TO4) */
+#define B3_RI_RTO_XS1	0x0195	/* 8 bit RAM Iface RD Timeout Queue XS1	(TO5) */
+#define B3_RI_WTO_R2	0x0196	/* 8 bit RAM Iface WR Timeout Queue R2	(TO6) */
+#define B3_RI_WTO_XA2	0x0197	/* 8 bit RAM Iface WR Timeout Queue XA2	(TO7) */
+#define B3_RI_WTO_XS2	0x0198	/* 8 bit RAM Iface WR Timeout Queue XS2	(TO8) */
+#define B3_RI_RTO_R2	0x0199	/* 8 bit RAM Iface RD Timeout Queue R2	(TO9) */
+#define B3_RI_RTO_XA2	0x019a	/* 8 bit RAM Iface RD Timeout Queue XA2	(TO10)*/
+#define B3_RI_RTO_XS2	0x019b	/* 8 bit RAM Iface RD Timeout Queue XS2	(TO11)*/
+#define B3_RI_TO_VAL	0x019c	/* 8 bit RAM Iface Current Timeout Count Val */
+	/* 0x019d - 0x019f	reserved */
+#define B3_RI_CTRL	0x01a0	/* 16 bit	RAM Iface Control Register */
+#define B3_RI_TEST	0x01a2	/*  8 bit	RAM Iface Test Register */
+	/* 0x01a3 - 0x01af	reserved */
+/* MAC Arbiter Registers */
+/* Please notice these are the number of qWord tranfered continously and */
+/* NOT real timeouts */
+#define B3_MA_TOINI_RX1	0x01b0	/* 8 bit Timeout Init Value Rx Path MAC 1 */
+#define B3_MA_TOINI_RX2	0x01b1	/* 8 bit Timeout Init Value Rx Path MAC 2 */
+#define B3_MA_TOINI_TX1	0x01b2	/* 8 bit Timeout Init Value Tx Path MAC 1 */
+#define B3_MA_TOINI_TX2	0x01b3	/* 8 bit Timeout Init Value Tx Path MAC 2 */
+#define B3_MA_TOVAL_RX1	0x01b4	/* 8 bit Timeout Value Rx Path MAC 1 */
+#define B3_MA_TOVAL_RX2	0x01b5	/* 8 bit Timeout Value Rx Path MAC 1 */
+#define B3_MA_TOVAL_TX1	0x01b6	/* 8 bit Timeout Value Tx Path MAC 2 */
+#define B3_MA_TOVAL_TX2	0x01b7	/* 8 bit Timeout Value Tx Path MAC 2 */
+#define B3_MA_TO_CTRL	0x01b8	/* 16 bit	MAC Arbiter Timeout Ctrl Reg */
+#define B3_MA_TO_TEST	0x01ba	/* 16 bit	MAC Arbiter Timeout Test Reg */
+	/* 0x01bc - 0x01bf	reserved */
+#define B3_MA_RCINI_RX1	0x01c0	/* 8 bit Recovery Init Value Rx Path MAC 1 */
+#define B3_MA_RCINI_RX2	0x01c1	/* 8 bit Recovery Init Value Rx Path MAC 2 */
+#define B3_MA_RCINI_TX1	0x01c2	/* 8 bit Recovery Init Value Tx Path MAC 1 */
+#define B3_MA_RCINI_TX2	0x01c3	/* 8 bit Recovery Init Value Tx Path MAC 2 */
+#define B3_MA_RCVAL_RX1	0x01c4	/* 8 bit Recovery Value Rx Path MAC 1 */
+#define B3_MA_RCVAL_RX2	0x01c5	/* 8 bit Recovery Value Rx Path MAC 1 */
+#define B3_MA_RCVAL_TX1	0x01c6	/* 8 bit Recovery Value Tx Path MAC 2 */
+#define B3_MA_RCVAL_TX2	0x01c7	/* 8 bit Recovery Value Tx Path MAC 2 */
+#define B3_MA_RC_CTRL	0x01c8	/* 16 bit	MAC Arbiter Recovery Ctrl Reg */
+#define B3_MA_RC_TEST	0x01ca	/* 16 bit	MAC Arbiter Recovery Test Reg */
+	/* 0x01cc - 0x01cf	reserved */
+/* Packet Arbiter Registers, This are real timeouts */
+#define B3_PA_TOINI_RX1	0x01d0	/* 16 bit	Timeout Init Val Rx Path MAC 1*/
+	/* 0x01d2 - 0x01d3:	reserved */
+#define B3_PA_TOINI_RX2	0x01d4	/* 16 bit	Timeout Init Val Rx Path MAC 2*/
+	/* 0x01d6 - 0x01d7:	reserved */
+#define B3_PA_TOINI_TX1	0x01d8	/* 16 bit	Timeout Init Val Tx Path MAC 1*/
+	/* 0x01da - 0x01db:	reserved */
+#define B3_PA_TOINI_TX2	0x01dc	/* 16 bit	Timeout Init Val Tx Path MAC 2*/
+	/* 0x01de - 0x01df:	reserved */
+#define B3_PA_TOVAL_RX1	0x01e0	/* 16 bit	Timeout Val Rx Path MAC 1 */
+	/* 0x01e2 - 0x01e3:	reserved */
+#define B3_PA_TOVAL_RX2	0x01e4	/* 16 bit	Timeout Val Rx Path MAC 2 */
+	/* 0x01e6 - 0x01e7:	reserved */
+#define B3_PA_TOVAL_TX1	0x01e8	/* 16 bit	Timeout Val Tx Path MAC 1 */
+	/* 0x01ea - 0x01eb:	reserved */
+#define B3_PA_TOVAL_TX2	0x01ec	/* 16 bit	Timeout Val Tx Path MAC 2 */
+	/* 0x01ee - 0x01ef:	reserved */
+#define B3_PA_CTRL	0x01f0	/* 16 bit	Packet Arbiter Ctrl Register */
+#define B3_PA_TEST	0x01f2	/* 16 bit	Packet Arbiter Test Register */
+	/* 0x01f4 - 0x01ff:	reserved */
+
+/*
+ *	Bank 4 - 5
+ */
+
+/* Transmit Arbiter Registers MAC 1 and 2, user MR_ADDR() to address */
+#define TXA_ITI_INI	0x0200	/* 32 bit	Tx Arb Interval Timer Init Val*/
+#define TXA_ITI_VAL	0x0204	/* 32 bit	Tx Arb Interval Timer Value */
+#define TXA_LIM_INI	0x0208	/* 32 bit	Tx Arb Limit Counter Init Val */
+#define TXA_LIM_VAL	0x020c	/* 32 bit	Tx Arb Limit Counter Value */
+#define TXA_CTRL	0x0210	/*  8 bit	Tx Arbiter Control Register */
+#define TXA_TEST	0x0211	/*  8 bit	Tx Arbiter Test Register */
+#define TXA_STAT	0x0212	/*  8 bit	Tx Arbiter Status Register */
+	/* 0x0213 - 0x027f:	reserved */
+
+/*
+ *	Bank 6
+ */
+/* External registers */
+#define B6_EXT_REG	0x0300
+
+/*
+ *	Bank 7
+ */
+/* This is a copy of the Configuration register file (lower half) */
+#define B7_CFG_SPC	0x0380
+
+/*
+ *	Bank 8 - 15
+ */
+/* Receive and Transmit Queue Registers, use Q_ADDR() to access */
+#define	B8_Q_REGS	0x0400
+
+/* Queue Register Offsets, use Q_ADDR() to access */
+#define Q_D	0x00	/* 8*32	bit	Current Descriptor */
+#define Q_DA_L	0x20	/* 32 bit	Current Descriptor Address Low dWord */
+#define Q_DA_H	0x24	/* 32 bit	Current Descriptor Address High dWord */
+#define Q_AC_L	0x28	/* 32 bit	Current Address Counter Low dWord */
+#define Q_AC_H	0x2c	/* 32 bit	Current Address Counter High dWord */
+#define Q_BC	0x30	/* 32 bit	Current Byte Counter */
+#define Q_CSR	0x34	/* 32 bit	BMU Control/Status Register */
+#define Q_F	0x38	/* 32 bit	Flag Register */
+#define Q_T1	0x3c	/* 32 bit	Test Register 1 */
+#define Q_T1_TR	0x3c	/*  8 bit	Test Register 1 Transfer SM */
+#define Q_T1_WR	0x3d	/*  8 bit	Test Register 1 Write Descriptor SM */
+#define Q_T1_RD	0x3e	/*  8 bit	Test Register 1 Read Descriptor SM */
+#define Q_T1_SV	0x3f	/*  8 bit	Test Register 1 Supervisor SM */
+#define Q_T2	0x40	/* 32 bit	Test Register 2	*/
+#define Q_T3	0x44	/* 32 bit	Test Register 3	*/
+	/* 0x48 - 0x7f:	reserved */
+
+/*
+ *	Bank 16 - 23
+ */
+/* RAM Buffer Registers */
+#define	B16_RAM_REGS	0x0800
+
+/* RAM Buffer Register Offsets */
+/* use RB_ADDR(Queue,Offs) to address */
+#define RB_START	0x00	/* 32 bit	RAM Buffer Start Address */
+#define RB_END		0x04	/* 32 bit	RAM Buffer End Address */
+#define RB_WP		0x08	/* 32 bit	RAM Buffer Write Pointer */
+#define RB_RP		0x0c	/* 32 bit	RAM Buffer Read Pointer */
+#define RB_RX_UTPP	0x10	/* 32 bit	Rx Upper Threshold, Pause Pack*/
+#define RB_RX_LTPP	0x14	/* 32 bit	Rx Lower Threshold, Pause Pack*/
+#define RB_RX_UTHP	0x18	/* 32 bit	Rx Upper Threshold, High Prio */
+#define RB_RX_LTHP	0x1c	/* 32 bit	Rx Lower Threshold, High Prio */
+	/* 0x10 - 0x1f:		reserved for Tx RAM Buffer Registers */
+#define RB_PC		0x20	/* 32 bit	RAM Buffer Packet Counter */
+#define RB_LEV		0x24	/* 32 bit	RAM Buffer Level Register */
+#define RB_CTRL		0x28	/*  8 bit	RAM Buffer Control Register */
+#define RB_TST1		0x29	/*  8 bit	RAM Buffer Test Register 1 */
+#define RB_TST2		0x2A	/*  8 bit	RAM Buffer Test Register 2 */
+	/* 0x2c - 0x7f:		reserved */
+
+/*
+ *	Bank 24 - 25
+ */
+/* Receive MAC FIFO, Receive LED, and Link Sync regs, use MR_ADDR() to address*/
+#define RX_MFF_EA	0x0c00	/* 32 bit	Receive MAC FIFO End Address */
+#define RX_MFF_WP	0x0c04	/* 32 bit 	Receive MAC FIFO Write Pointer*/
+	/* 0x0c08 - 0x0c0b	reserved */
+#define RX_MFF_RP	0x0c0c	/* 32 bit	Receive MAC FIFO Read Pointer */
+#define RX_MFF_PC	0x0c10	/* 32 bit	Receive MAC FIFO Packet Cnt */
+#define RX_MFF_LEV	0x0c14	/* 32 bit	Receive MAC FIFO Level */
+#define RX_MFF_CTRL1	0x0c18	/* 16 bit	Receive MAC FIFO Control Reg 1*/
+#define RX_MFF_STAT_TO	0x0c1a	/*  8 bit	Receive MAC Status Timeout */
+#define RX_MFF_TIST_TO	0x0c1b	/*  8 bit	Receive MAC Timestamp Timeout */
+#define RX_MFF_CTRL2	0x0c1c	/*  8 bit	Receive MAC FIFO Control Reg 2*/
+#define RX_MFF_TST1	0x0c1d	/*  8 bit	Receive MAC FIFO Test Reg 1 */
+#define RX_MFF_TST2	0x0c1e	/*  8 bit	Receive MAC FIFO Test Reg 2 */
+	/* 0x0c1f		reserved */
+#define RX_LED_INI	0x0c20	/* 32 bit	Receive LED Cnt Init Value */
+#define RX_LED_VAL	0x0c24	/* 32 bit	Receive LED Cnt Current Value */
+#define RX_LED_CTRL	0x0c28	/*  8 bit	Receive LED Cnt Control Reg */
+#define RX_LED_TST	0x0c29	/*  8 bit	Receive LED Cnt Test Register */
+	/* 0x0c2a - 0x0c2f	reserved */
+#define LNK_SYNC_INI	0x0c30	/* 32 bit	Link Sync Cnt Init Value */
+#define LNK_SYNC_VAL	0x0c34	/* 32 bit	Link Sync Cnt Current Value */
+#define LNK_SYNC_CTRL	0x0c38	/*  8 bit	Link Sync Cnt Control Register*/
+#define LNK_SYNC_TST	0x0c39	/*  8 bit	Link Sync Cnt Test Register */
+	/* 0x0c3a - 0x0c3b	reserved */
+#define LNK_LED_REG	0x0c3c	/*  8 bit	Link LED Register */
+	/* 0x0c3d - 0x0c7f	reserved */
+
+/*
+ *	Bank 26 - 27
+ */
+/* Transmit MAC FIFO and Transmit LED Registers, use MR_ADDR() to address */
+#define TX_MFF_EA	0x0d00	/* 32 bit	Transmit MAC FIFO End Address */
+#define TX_MFF_WP	0x0d04	/* 32 bit 	Transmit MAC FIFO WR Pointer */
+#define TX_MFF_WSP	0x0d08	/* 32 bit	Transmit MAC FIFO WR Shadow Pt*/
+#define TX_MFF_RP	0x0d0c	/* 32 bit	Transmit MAC FIFO RD Pointer */
+#define TX_MFF_PC	0x0d10	/* 32 bit	Transmit MAC FIFO Packet Cnt */
+#define TX_MFF_LEV	0x0d14	/* 32 bit	Transmit MAC FIFO Level */
+#define TX_MFF_CTRL1	0x0d18	/* 16 bit	Transmit MAC FIFO Ctrl Reg 1 */
+#define TX_MFF_WAF	0x0d1a	/*  8 bit	Transmit MAC Wait after flush*/
+	/* 0x0c1b		reserved */
+#define TX_MFF_CTRL2	0x0d1c	/*  8 bit	Transmit MAC FIFO Ctrl Reg 2 */
+#define TX_MFF_TST1	0x0d1d	/*  8 bit	Transmit MAC FIFO Test Reg 1 */
+#define TX_MFF_TST2	0x0d1e	/*  8 bit	Transmit MAC FIFO Test Reg 2 */
+	/* 0x0d1f		reserved */
+#define TX_LED_INI	0x0d20	/* 32 bit	Transmit LED Cnt Init Value */
+#define TX_LED_VAL	0x0d24	/* 32 bit	Transmit LED Cnt Current Val */
+#define TX_LED_CTRL	0x0d28	/*  8 bit	Transmit LED Cnt Control Reg */
+#define TX_LED_TST	0x0d29	/*  8 bit	Transmit LED Cnt Test Register*/
+	/* 0x0d2a - 0x0d7f	reserved */
+
+/*
+ *	Bank 28
+ */
+/* Descriptor Poll Timer Registers */
+#define B28_DPT_INI	0x0e00	/* 32 bit	Descriptor Poll Timer Init Val*/
+#define B28_DPT_VAL	0x0e04	/* 32 bit	Descriptor Poll Timer Curr Val*/
+#define B28_DPT_CTRL	0x0e08	/*  8 bit	Descriptor Poll Timer Ctrl Reg*/
+	/* 0x0e09:		reserved */
+#define B28_DPT_TST	0x0e0a	/*  8 bit	Descriptor Poll Timer Test Reg*/
+	/* 0x0e0b - 0x0e8f:	reserved */
+
+/*
+ *	Bank 29 - 31
+ */
+/* 0x0e90 - 0x0fff:	reserved */
+
+/*
+ *	Bank 0x20 - 0x3f
+ */
+/* 0x1000 - 0x1fff:	reserved */
+
+/*
+ *	Bank 0x40 - 0x4f
+ */
+/* XMAC 1 registers */
+#define B40_XMAC1	0x2000
+
+/*
+ *	Bank 0x50 - 0x5f
+ */
+/* 0x2800 - 0x2fff:	reserved */
+
+/*
+ *	Bank 0x60 - 0x6f
+ */
+/* XMAC 2 registers */
+#define B40_XMAC2	0x3000
+
+/*
+ *	Bank 0x70 - 0x7f
+ */
+/* 0x3800 - 0x3fff:	reserved */
+
+/*
+ *	Control Register Bit Definitions:
+ */
+/*	B0_RAP		8 bit	Register Address Port */
+				/* Bit 7:	reserved */
+#define	RAP_RAP		0x3f	/* Bit 6..0:	0 = block 0, .., 6f = block 6f*/
+
+/*	B0_CTST		16 bit	Control/Status register */
+				/* Bit 15..10:	reserved */
+#define CS_BUS_CLOCK	(1<<9)	/* Bit	9:	Bus Clock 0/1 = 33/66MHz */
+#define CS_BUS_SLOT_SZ	(1<<8)	/* Bit	8:	Slot Size 0/1 = 32/64 bit slot*/
+#define CS_ST_SW_IRQ	(1<<7)	/* Bit	7:	Set IRQ SW Request	*/
+#define CS_CL_SW_IRQ	(1<<6)	/* Bit	6:	Clear IRQ SW Request	*/
+#define CS_STOP_DONE	(1<<5)	/* Bit	5:	Stop Master is finished */
+#define	CS_STOP_MAST	(1<<4)	/* Bit	4:	Command Bit to stop the master*/
+#define	CS_MRST_CLR	(1<<3)	/* Bit	3:	Clear Master reset	*/
+#define	CS_MRST_SET	(1<<2)	/* Bit	2:	Set Master reset	*/
+#define	CS_RST_CLR	(1<<1)	/* Bit	1:	Clear Software reset	*/
+#define	CS_RST_SET	(1<<0)	/* Bit	0:	Set Software reset	*/
+
+/*	B0_LED		 8 Bit	LED register */
+				/* Bit 7..2:	reserved */
+#define LED_STAT_ON	(1<<1)	/* Bit 1:	Status LED on	*/
+#define LED_STAT_OFF	(1<<0)	/* Bit 0:	Status LED off	*/
+
+/*	B0_ISRC		32 bit	Interrupt Source Register */
+/*	B0_IMSK		32 bit	Interrupt Mask Register */
+/*	B0_SP_ISRC	32 bit	Special Interrupt Source Reg */
+/*	B2_IRQM_MSK 	32 bit	IRQ Moderation Mask */
+#define IS_ALL_MSK	0xbfffffffL	/* 		All Interrupt bits */
+#define IS_HW_ERR	(1UL<<31)	/* Bit 31:	Interrupt HW Error */
+					/* Bit 30:	reserved */
+#define IS_PA_TO_RX1	(1L<<29)	/* Bit 29:	Packet Arb Timeout Rx1*/
+#define IS_PA_TO_RX2	(1L<<28)	/* Bit 28:	Packet Arb Timeout Rx2*/
+#define IS_PA_TO_TX1	(1L<<27)	/* Bit 27:	Packet Arb Timeout Tx1*/
+#define IS_PA_TO_TX2	(1L<<26)	/* Bit 26:	Packet Arb Timeout Tx2*/
+#define IS_I2C_READY	(1L<<25)	/* Bit 25:	IRQ on end of I2C tx */
+#define IS_IRQ_SW	(1L<<24)	/* Bit 24:	SW forced IRQ	*/
+#define IS_EXT_REG	(1L<<23)	/* Bit 23:	IRQ from external reg */
+#define	IS_TIMINT	(1L<<22)	/* Bit 22:	IRQ from Timer	*/
+#define IS_MAC1		(1L<<21)	/* Bit 21:	IRQ from MAC 1	*/
+#define IS_LNK_SYNC_M1	(1L<<20)	/* Bit 20:	Link Sync Cnt wrap M1 */
+#define IS_MAC2		(1L<<19)	/* Bit 19:	IRQ from MAC 2	*/
+#define IS_LNK_SYNC_M2	(1L<<18)	/* Bit 18:	Link Sync Cnt wrap M2 */
+/* Receive Queue 1 */
+#define	IS_R1_B		(1L<<17)	/* Bit 17:	Q_R1 End of Buffer */
+#define	IS_R1_F		(1L<<16)	/* Bit 16:	Q_R1 End of Frame */
+#define	IS_R1_C		(1L<<15)	/* Bit 15:	Q_R1 Encoding Error */
+/* Receive Queue 2 */
+#define	IS_R2_B		(1L<<14)	/* Bit 14:	Q_R2 End of Buffer */
+#define	IS_R2_F		(1L<<13)	/* Bit 13:	Q_R2 End of Frame */
+#define	IS_R2_C		(1L<<12)	/* Bit 12:	Q_R2 Encoding Error */
+/* Synchronous Transmit Queue 1 */
+#define	IS_XS1_B	(1L<<11)	/* Bit 11:	Q_XS1 End of Buffer */
+#define	IS_XS1_F	(1L<<10)	/* Bit 10:	Q_XS1 End of Frame */
+#define	IS_XS1_C	(1L<<9)		/* Bit	9:	Q_XS1 Encoding Error */
+/* Asynchronous Transmit Queue 1 */
+#define	IS_XA1_B	(1L<<8)		/* Bit	8:	Q_XA1 End of Buffer */
+#define	IS_XA1_F	(1L<<7)		/* Bit	7:	Q_XA1 End of Frame */
+#define	IS_XA1_C	(1L<<6)		/* Bit	6:	Q_XA1 Encoding Error */
+/* Synchronous Transmit Queue 2 */
+#define	IS_XS2_B	(1L<<5)		/* Bit	5:	Q_XS2 End of Buffer */
+#define	IS_XS2_F	(1L<<4)		/* Bit	4:	Q_XS2 End of Frame */
+#define	IS_XS2_C	(1L<<3)		/* Bit	3:	Q_XS2 Encoding Error */
+/* Asynchronous Transmit Queue 2 */
+#define	IS_XA2_B	(1L<<2)		/* Bit	2:	Q_XA2 End of Buffer */
+#define	IS_XA2_F	(1L<<1)		/* Bit	1:	Q_XA2 End of Frame */
+#define	IS_XA2_C	(1L<<0)		/* Bit	0:	Q_XA2 Encoding Error */
+
+
+/*	B0_HWE_ISRC	32 bit	HW Error Interrupt Src Reg */
+/*	B0_HWE_IMSK	32 bit	HW Error Interrupt Mask Reg */
+/*	B2_IRQM_HWE_MSK 32 bit	IRQ Moderation HW Error Mask */
+#define IS_ERR_MSK	0x00000fffL	/* 		All Error bits */
+					/* Bit 31..12:	reserved */
+#define	IS_IRQ_MST_ERR	(1L<<11)	/* Bit 11:	IRQ master error */
+					/*	PERR,RMABORT,RTABORT,DATAPERR */
+#define	IS_IRQ_STAT	(1L<<10)	/* Bit 10:	IRQ status execption */
+					/*	RMABORT, RTABORT, DATAPERR */
+#define IS_NO_STAT_M1	(1L<<9)		/* Bit	9:	No Rx Status from MAC1*/
+#define IS_NO_STAT_M2	(1L<<8)		/* Bit	8:	No Rx Status from MAC2*/
+#define IS_NO_TIST_M1	(1L<<7)		/* Bit	7:	No Timestamp from MAC1*/
+#define IS_NO_TIST_M2	(1L<<6)		/* Bit	6:	No Timestamp from MAC2*/
+#define IS_RAM_RD_PAR	(1L<<5)		/* Bit	5:	RAM Read Parity Error */
+#define IS_RAM_WR_PAR	(1L<<4)		/* Bit	4:	RAM Write Parity Error*/
+#define IS_M1_PAR_ERR	(1L<<3)		/* Bit	3:	MAC 1 Parity Error */
+#define IS_M2_PAR_ERR	(1L<<2)		/* Bit	2:	MAC 2 Parity Error */
+#define IS_R1_PAR_ERR	(1L<<1)		/* Bit	1:	Queue R1 Parity Error */
+#define IS_R2_PAR_ERR	(1L<<0)		/* Bit	0:	Queue R2 Parity Error */
+
+/*	B2_CONN_TYP	 8 bit	Connector type */
+/*	B2_PMD_TYP	 8 bit	PMD type */
+/*	Values of connector and PMD type comply to SysKonnect internal std */
+
+/*	B2_MAC_CFG	 8 bit	MAC Configuration */
+				/* Bit 7..2:	reserved */
+#define	CFG_DIS_M2_CLK	(1<<1)	/* Bit 1:	Disable Clock for 2nd MAC */
+#define CFG_SNG_MAC	(1<<0)	/* Bit 0:	MAC Config: 1=2 MACs / 0=1 MAC*/
+
+/*	B2_CHIP_REV	 8 bit 	Queen Chip Revision Number */
+#define FIRST_CHIP_REV	0x0a	/* Initial Revision Value */
+
+/*	B2_FAR		32 bit	Flash-Prom Addr Reg/Cnt */
+#define	FAR_ADDR	0x1ffffL	/* Bit 16..0:	FPROM Address mask */
+
+/*	B2_LD_CRTL	 8 bit	EPROM loader control register */
+/*	Bits are currently reserved */
+
+/*	B2_LD_TEST	 8 bit	EPROM loader test register */
+				/* Bit 7..4:	reserved */
+#define	LD_T_ON		(1<<3)	/* Bit 3:	Loader Testmode on */
+#define	LD_T_OFF	(1<<2)	/* Bit 2:	Loader Testmode off */
+#define	LD_T_STEP	(1<<1)	/* Bit 1:	Decrement FPROM addr. Counter */
+#define	LD_START	(1<<0)	/* Bit 0:	Start loading FPROM */
+
+/*
+ *	Timer Section
+ */
+/*	B2_TI_CRTL	 8 bit	Timer control */
+/*	B2_IRQM_CTRL	 8 bit	IRQ Moderation Timer Control */
+				/* Bit 7..3:	reserved */
+#define TIM_START	(1<<2)	/* Bit 2:	Start Timer */
+#define TIM_STOP	(1<<1)	/* Bit 1:	Stop Timer */
+#define TIM_CLR_IRQ	(1<<0)	/* Bit 0:	Clear Timer IRQ, (!IRQM) */
+
+/*	B2_TI_TEST	 8 Bit	Timer Test */
+/*	B2_IRQM_TEST	 8 bit	IRQ Moderation Timer Test */
+/*	B28_DPT_TST	 8 bit	Descriptor Poll Timer Test Reg */
+				/* Bit 7..3:	reserved */
+#define	TIM_T_ON	(1<<2)	/* Bit 2:	Test mode on */
+#define	TIM_T_OFF	(1<<1)	/* Bit 1:	Test mode off */
+#define	TIM_T_STEP	(1<<0)	/* Bit 0:	Test step */
+
+/*	B28_DPT_INI	32 bit	Descriptor Poll Timer Init Val */
+/*	B28_DPT_VAL	32 bit	Descriptor Poll Timer Curr Val */
+				/* Bit 31..24:	reserved */
+#define DPT_MSK	0x00ffffffL	/* Bit 23.. 0:	Desc Poll Timer Bits */
+
+/*	B28_DPT_CTRL	 8 bit	Descriptor Poll Timer Ctrl Reg */
+				/* Bit 7..2:	reserved */
+#define DPT_START	(1<<1)	/* Bit 1:	Start Desciptor Poll Timer */
+#define DPT_STOP	(1<<0)	/* Bit 0:	Stop Desciptor Poll Timer */
+
+
+/*	B2_TST_CTRL1	 8 bit	Test Control Register 1 */
+#define	TST_FRC_DPERR_MR	(1<<7)	/* Bit 7: force DATAPERR on MST RD */
+#define	TST_FRC_DPERR_MW	(1<<6)	/* Bit 6: force DATAPERR on MST WR */
+#define	TST_FRC_DPERR_TR	(1<<5)	/* Bit 5: force DATAPERR on TRG RD */
+#define	TST_FRC_DPERR_TW	(1<<4)	/* Bit 4: force DATAPERR on TRG WR */
+#define	TST_FRC_APERR_M		(1<<3)	/* Bit 3: force ADDRPERR on MST */
+#define	TST_FRC_APERR_T		(1<<2)	/* Bit 2: force ADDRPERR on TRG */
+#define	TST_CFG_WRITE_ON	(1<<1)	/* Bit 1: Enable Config Reg WR */
+#define	TST_CFG_WRITE_OFF	(1<<0)	/* Bit 0: Disable Config Reg WR */
+
+/*	B2_TST_CTRL2	 8 bit	Test Control Register 2 */
+					/* Bit 7..4:	reserved */
+					/* force the following error on */
+					/* the next master read/write	*/
+#define TST_FRC_DPERR_MR64	(1<<3)	/* Bit 3:	DataPERR RD 64	*/
+#define TST_FRC_DPERR_MW64	(1<<2)	/* Bit 2:	DataPERR WR 64	*/
+#define TST_FRC_APERR_1M64	(1<<1)	/* Bit 1:	AddrPERR on 1. phase */
+#define TST_FRC_APERR_2M64	(1<<0)	/* Bit 0:	AddrPERR on 2. phase */
+
+/*	B2_GP_IO	32 bit	General Purpose IO Register */
+					/* Bit 31..26:	reserved */
+#define	GP_DIR_9	(1L<<25)	/* Bit 25:	IO_9 direct, 0=I/1=O */
+#define	GP_DIR_8	(1L<<24)	/* Bit 24:	IO_8 direct, 0=I/1=O */
+#define	GP_DIR_7	(1L<<23)	/* Bit 23:	IO_7 direct, 0=I/1=O */
+#define	GP_DIR_6	(1L<<22)	/* Bit 22:	IO_6 direct, 0=I/1=O */
+#define	GP_DIR_5	(1L<<21)	/* Bit 21:	IO_5 direct, 0=I/1=O */
+#define	GP_DIR_4	(1L<<20)	/* Bit 20:	IO_4 direct, 0=I/1=O */
+#define	GP_DIR_3	(1L<<19)	/* Bit 19:	IO_3 direct, 0=I/1=O */
+#define	GP_DIR_2	(1L<<18)	/* Bit 18:	IO_2 direct, 0=I/1=O */
+#define	GP_DIR_1	(1L<<17)	/* Bit 17:	IO_1 direct, 0=I/1=O */
+#define	GP_DIR_0	(1L<<16)	/* Bit 16:	IO_0 direct, 0=I/1=O */
+					/* Bit 15..10:	reserved */
+#define	GP_IO_9		(1L<<9)		/* Bit	9:	IO_9 pin */
+#define	GP_IO_8		(1L<<8)		/* Bit	8:	IO_8 pin */
+#define	GP_IO_7		(1L<<7)		/* Bit	7:	IO_7 pin */
+#define	GP_IO_6		(1L<<6)		/* Bit	6:	IO_6 pin */
+#define	GP_IO_5		(1L<<5)		/* Bit	5:	IO_5 pin */
+#define	GP_IO_4		(1L<<4)		/* Bit	4:	IO_4 pin */
+#define	GP_IO_3		(1L<<3)		/* Bit	3:	IO_3 pin */
+#define	GP_IO_2		(1L<<2)		/* Bit	2:	IO_2 pin */
+#define	GP_IO_1		(1L<<1)		/* Bit	1:	IO_1 pin */
+#define	GP_IO_0		(1L<<0)		/* Bit	0:	IO_0 pin */
+
+/*	B2_I2C_CTRL	32 bit	I2C HW Control Register */
+#define	I2C_FLAG	(1UL<<31)	/* Bit 31:	Start read/write if WR*/
+#define I2C_ADDR	(0x7fffL<<16)	/* Bit 30..16:	Addr to be RD/WR */
+#define	I2C_DEV_SEL	(0x7fL<<9)	/* Bit 15.. 9:	I2C Device Select */
+					/* Bit	8.. 5:	reserved	*/
+#define I2C_BURST_LEN	(1L<<4)		/* Bit	4:	Burst Len, 1/4 bytes */
+#define I2C_DEV_SIZE	(7L<<1)		/* Bit	3.. 1:	I2C Device Size	*/
+#define I2C_025K_DEV	(0L<<1)		/*		0: 256 Bytes or smal. */
+#define I2C_05K_DEV	(1L<<1)		/* 		1: 512	Bytes	*/
+#define	I2C_1K_DEV	(2L<<1)		/*		2: 1024 Bytes	*/
+#define I2C_2K_DEV	(3L<<1)		/*		3: 2048	Bytes	*/
+#define	I2C_4K_DEV	(4L<<1)		/*		4: 4096 Bytes	*/
+#define	I2C_8K_DEV	(5L<<1)		/*		5: 8192 Bytes	*/
+#define	I2C_16K_DEV	(6L<<1)		/*		6: 16384 Bytes	*/
+#define	I2C_32K_DEV	(7L<<1)		/*		7: 32768 Bytes	*/
+#define I2C_STOP	(1L<<0)		/* Bit	0:	Interrupt I2C transfer*/
+
+/*	B2_I2C_IRQ	32 bit	I2C HW IRQ Register */
+				/* Bit 31..1	reserved */
+#define I2C_CLR_IRQ	(1<<0)	/* Bit 0:	Clear I2C IRQ */
+
+/*	B2_I2C_SW	32 bit	I2C HW SW Port Register */
+				/* Bit 7..3:	reserved */
+#define	I2C_DATA_DIR	(1<<2)	/* Bit 2:	direction of I2C_DATA */
+#define I2C_DATA	(1<<1)	/* Bit 1:	I2C Data Port	*/
+#define	I2C_CLK		(1<<0)	/* Bit 0:	I2C Clock Port	*/
+
+/*
+ * I2C Address
+ */
+#define	I2C_SENS_ADDR	LM80_ADDR	/* I2C Sensor Address, (Volt and Temp)*/
+
+
+/*	B2_BSC_CTRL	 8 bit	Blink Source Counter Control */
+				/* Bit 7..2:	reserved */
+#define BSC_START	(1<<1)	/* Bit 1:	Start Blink Source Counter */
+#define BSC_STOP	(1<<0)	/* Bit 0:	Stop Blink Source Counter */
+
+/*	B2_BSC_STAT	 8 bit	Blink Source Counter Status */
+				/* Bit 7..1:	reserved */
+#define BSC_SRC		(1<<0)	/* Bit 0:	Blink Source, 0=Off / 1=On */
+
+/*	B2_BSC_TST	16 bit	Blink Source Counter Test Reg */
+#define	BSC_T_ON	(1<<2)	/* Bit 2:	Test mode on */
+#define	BSC_T_OFF	(1<<1)	/* Bit 1:	Test mode off */
+#define	BSC_T_STEP	(1<<0)	/* Bit 0:	Test step */
+
+
+/*	B3_RAM_ADDR	32 bit	RAM Address, to read or write */
+					/* Bit 31..19:	reserved */
+#define RAM_ADR_RAN	0x0007ffffL	/* Bit 18.. 0:	RAM Address Range */
+
+/* RAM Interface Registers */
+/*	B3_RI_CTRL	16 bit	RAM Iface Control Register */
+				/* Bit 15..10:	reserved */
+#define RI_CLR_RD_PERR	(1<<9)	/* Bit	9:	Clear IRQ RAM Read Parity Err */
+#define RI_CLR_WR_PERR	(1<<8)	/* Bit	8:	Clear IRQ RAM Write Parity Err*/
+				/* Bit	7..2:	reserved */
+#define RI_RST_CLR	(1<<1)	/* Bit	1:	Clear RAM Interface Reset */
+#define RI_RST_SET	(1<<0)	/* Bit	0:	Set RAM Interface Reset */
+
+/*	B3_RI_TEST	 8 bit	RAM Iface Test Register */
+				/* Bit 15..4:	reserved */
+#define RI_T_EV		(1<<3)	/* Bit	3:	Timeout Event occured */
+#define RI_T_ON		(1<<2)	/* Bit	2:	Timeout Timer Test On */
+#define RI_T_OFF	(1<<1)	/* Bit	1:	Timeout Timer Test Off */
+#define RI_T_STEP	(1<<0)	/* Bit	0:	Timeout Timer Step */
+
+/* MAC Arbiter Registers */
+/*	B3_MA_TO_CTRL	16 bit	MAC Arbiter Timeout Ctrl Reg */
+				/* Bit 15..4:	reserved */
+#define MA_FOE_ON	(1<<3)	/* Bit	3:	XMAC Fast Output Enable ON */
+#define MA_FOE_OFF	(1<<2)	/* Bit	2:	XMAC Fast Output Enable OFF */
+#define MA_RST_CLR	(1<<1)	/* Bit	1:	Clear MAC Arbiter Reset */
+#define MA_RST_SET	(1<<0)	/* Bit	0:	Set MAC Arbiter Reset */
+
+/*	B3_MA_RC_CTRL	16 bit	MAC Arbiter Recovery Ctrl Reg */
+				/* Bit 15..8:	reserved */
+#define MA_ENA_REC_TX2	(1<<7)	/* Bit	7:	Enable Recovery Timer TX2 */
+#define MA_DIS_REC_TX2	(1<<6)	/* Bit	6:	Disable Recovery Timer TX2 */
+#define MA_ENA_REC_TX1	(1<<5)	/* Bit	5:	Enable Recovery Timer TX1 */
+#define MA_DIS_REC_TX1	(1<<4)	/* Bit	4:	Disable Recovery Timer TX1 */
+#define MA_ENA_REC_RX2	(1<<3)	/* Bit	3:	Enable Recovery Timer RX2 */
+#define MA_DIS_REC_RX2	(1<<2)	/* Bit	2:	Disable Recovery Timer RX2 */
+#define MA_ENA_REC_RX1	(1<<1)	/* Bit	1:	Enable Recovery Timer RX1 */
+#define MA_DIS_REC_RX1	(1<<0)	/* Bit	0:	Disable Recovery Timer RX1 */
+
+/* Packet Arbiter Registers */
+/*	B3_PA_CTRL	16 bit	Packet Arbiter Ctrl Register */
+				/* Bit 15..14:	reserved */
+#define PA_CLR_TO_TX2	(1<<13)	/* Bit 13:	Clear IRQ Packet Timeout TX2 */
+#define PA_CLR_TO_TX1	(1<<12)	/* Bit 12:	Clear IRQ Packet Timeout TX1 */
+#define PA_CLR_TO_RX2	(1<<11)	/* Bit 11:	Clear IRQ Packet Timeout RX2 */
+#define PA_CLR_TO_RX1	(1<<10)	/* Bit 10:	Clear IRQ Packet Timeout RX1 */
+#define PA_ENA_TO_TX2	(1<<9)	/* Bit	9:	Enable Timeout Timer TX2 */
+#define PA_DIS_TO_TX2	(1<<8)	/* Bit	8:	Disable Timeout Timer TX2 */
+#define PA_ENA_TO_TX1	(1<<7)	/* Bit	7:	Enable Timeout Timer TX1 */
+#define PA_DIS_TO_TX1	(1<<6)	/* Bit	6:	Disable Timeout Timer TX1 */
+#define PA_ENA_TO_RX2	(1<<5)	/* Bit	5:	Enable Timeout Timer RX2 */
+#define PA_DIS_TO_RX2	(1<<4)	/* Bit	4:	Disable Timeout Timer RX2 */
+#define PA_ENA_TO_RX1	(1<<3)	/* Bit	3:	Enable Timeout Timer RX1 */
+#define PA_DIS_TO_RX1	(1<<2)	/* Bit	2:	Disable Timeout Timer RX1 */
+#define PA_RST_CLR	(1<<1)	/* Bit	1:	Clear MAC Arbiter Reset */
+#define PA_RST_SET	(1<<0)	/* Bit	0:	Set MAC Arbiter Reset */
+
+#define PA_ENA_TO_ALL	(PA_ENA_TO_RX1 | PA_ENA_TO_RX2 |\
+			 PA_ENA_TO_TX1 | PA_ENA_TO_TX2)
+
+/* Rx/Tx Path related Arbiter Test Registers */
+/*	B3_MA_TO_TEST	16 bit	MAC Arbiter Timeout Test Reg */
+/*	B3_MA_RC_TEST	16 bit	MAC Arbiter Recovery Test Reg */
+/*	B3_PA_TEST	16 bit	Packet Arbiter Test Register */
+/*			Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */
+#define TX2_T_EV	(1<<15)	/* Bit 15: 	TX2 Timeout/Recv Event occured*/
+#define TX2_T_ON	(1<<14)	/* Bit 14:	TX2 Timeout/Recv Timer Test On*/
+#define TX2_T_OFF	(1<<13)	/* Bit 13:	TX2 Timeout/Recv Timer Tst Off*/
+#define TX2_T_STEP	(1<<12)	/* Bit 12:	TX2 Timeout/Recv Timer Step */
+#define TX1_T_EV	(1<<11)	/* Bit 11:	TX1 Timeout/Recv Event occured*/
+#define TX1_T_ON	(1<<10)	/* Bit 10:	TX1 Timeout/Recv Timer Test On*/
+#define TX1_T_OFF	(1<<9)	/* Bit	9:	TX1 Timeout/Recv Timer Tst Off*/
+#define TX1_T_STEP	(1<<8)	/* Bit	8:	TX1 Timeout/Recv Timer Step */
+#define RX2_T_EV	(1<<7)	/* Bit	7:	RX2 Timeout/Recv Event occured*/
+#define RX2_T_ON	(1<<6)	/* Bit	6:	RX2 Timeout/Recv Timer Test On*/
+#define RX2_T_OFF	(1<<5)	/* Bit	5:	RX2 Timeout/Recv Timer Tst Off*/
+#define RX2_T_STEP	(1<<4)	/* Bit	4:	RX2 Timeout/Recv Timer Step */
+#define RX1_T_EV	(1<<3)	/* Bit	3:	RX1 Timeout/Recv Event occured*/
+#define RX1_T_ON	(1<<2)	/* Bit	2:	RX1 Timeout/Recv Timer Test On*/
+#define RX1_T_OFF	(1<<1)	/* Bit	1:	RX1 Timeout/Recv Timer Tst Off*/
+#define RX1_T_STEP	(1<<0)	/* Bit	0:	RX1 Timeout/Recv Timer Step */
+
+
+/* Transmit Arbiter Registers MAC 1 and 2, user MR_ADDR() to address */
+/*	TXA_ITI_INI	32 bit	Tx Arb Interval Timer Init Val */
+/*	TXA_ITI_VAL	32 bit	Tx Arb Interval Timer Value */
+/*	TXA_LIM_INI	32 bit	Tx Arb Limit Counter Init Val */
+/*	TXA_LIM_VAL	32 bit	Tx Arb Limit Counter Value */
+					/* Bit 31..24:	reserved */
+#define	TXA_MAX_VAL	0x00ffffffL	/* Bit 23.. 0:	Max TXA Timer/Cnt Val */
+
+/*	TXA_CTRL	 8 bit	Tx Arbiter Control Register */
+#define TXA_ENA_FSYNC	(1<<7)	/* Bit 7:	Enable force of sync tx queue */
+#define TXA_DIS_FSYNC	(1<<6)	/* Bit 6:	Disable force of sync tx queue*/
+#define TXA_ENA_ALLOC	(1<<5)	/* Bit 5:	Enable alloc of free bandwidth*/
+#define TXA_DIS_ALLOC	(1<<4)	/* Bit 4:	Disabl alloc of free bandwidth*/
+#define TXA_START_RC	(1<<3)	/* Bit 3:	Start sync Rate Control */
+#define TXA_STOP_RC	(1<<2)	/* Bit 2:	Stop sync Rate Control */
+#define TXA_ENA_ARB	(1<<1)	/* Bit 1:	Enable Tx Arbiter */
+#define TXA_DIS_ARB	(1<<0)	/* Bit 0:	Disable Tx Arbiter */
+
+/*	TXA_TEST	 8 bit	Tx Arbiter Test Register */
+				/* Bit 7..6:	reserved */
+#define TXA_INT_T_ON	(1<<5)	/* Bit 5:	Tx Arb Interval Timer Test On */
+#define TXA_INT_T_OFF	(1<<4)	/* Bit 4:	Tx Arb Interval Timer Test Off*/
+#define TXA_INT_T_STEP	(1<<3)	/* Bit 3:	Tx Arb Interval Timer Step */
+#define TXA_LIM_T_ON	(1<<2)	/* Bit 2:	Tx Arb Limit Timer Test On */
+#define TXA_LIM_T_OFF	(1<<1)	/* Bit 1:	Tx Arb Limit Timer Test Off */
+#define TXA_LIM_T_STEP	(1<<0)	/* Bit 0:	Tx Arb Limit Timer Step */
+
+/*	TXA_STAT	 8 bit	Tx Arbiter Status Register */
+				/* Bit 7..1:	reserved */
+#define	TXA_PRIO_XS	(1<<0)	/* Bit 0:	sync queue has prio to send */
+
+/*	Q_BC	32 bit	Current Byte Counter */
+				/* Bit 31..16:	reserved */
+#define BC_MAX		0xffff	/* Bit 15.. 0:	Byte counter */
+
+/* BMU Control Status Registers */
+/*	B0_R1_CSR	32 bit	BMU Ctrl/Stat Rx Queue 1 */
+/*	B0_R2_CSR	32 bit	BMU Ctrl/Stat Rx Queue 2 */
+/*	B0_XA1_CSR	32 bit	BMU Ctrl/Stat Sync Tx Queue 1 */
+/*	B0_XS1_CSR	32 bit	BMU Ctrl/Stat Async Tx Queue 1 */
+/*	B0_XA2_CSR	32 bit	BMU Ctrl/Stat Sync Tx Queue 2 */
+/*	B0_XS2_CSR	32 bit	BMU Ctrl/Stat Async Tx Queue 2 */
+/*	Q_CSR	32 bit	BMU Control/Status Register */
+					/* Bit 31..25:	reserved */
+#define CSR_SV_IDLE	(1L<<24)	/* Bit 24: 	BMU SM Idle */
+					/* Bit 23..22:	reserved */
+#define	CSR_DESC_CLR	(1L<<21)	/* Bit 21:	Clear Reset for Descr */
+#define	CSR_DESC_SET	(1L<<20)	/* Bit 20:	Set Reset for Descr */
+#define	CSR_FIFO_CLR	(1L<<19)	/* Bit 19:	Clear Reset for FIFO */
+#define	CSR_FIFO_SET	(1L<<18)	/* Bit 18:	Set Reset for FIFO */
+#define	CSR_HPI_RUN	(1L<<17)	/* Bit 17:	Release HPI SM */
+#define	CSR_HPI_RST	(1L<<16)	/* Bit 16:	Reset HPI SM to Idle */
+#define	CSR_SV_RUN	(1L<<15)	/* Bit 15:	Release Supervisor SM */
+#define	CSR_SV_RST	(1L<<14)	/* Bit 14:	Reset Supervisor SM */
+#define	CSR_DREAD_RUN	(1L<<13)	/* Bit 13:	Release Descr Read SM */
+#define	CSR_DREAD_RST	(1L<<12)	/* Bit 12:	Reset Descr Read SM */
+#define	CSR_DWRITE_RUN	(1L<<11)	/* Bit 11:	Rel. Descr Write SM */
+#define	CSR_DWRITE_RST	(1L<<10)	/* Bit 10:	Reset Descr Write SM */
+#define	CSR_TRANS_RUN	(1L<<9)		/* Bit	9:	Release Transfer SM */
+#define	CSR_TRANS_RST	(1L<<8)		/* Bit	8:	Reset Transfer SM */
+#define CSR_ENA_POL	(1L<<7)		/* Bit	7:	Enable Descr Polling */
+#define CSR_DIS_POL	(1L<<6)		/* Bit	6:	Disable Descr Polling */
+#define CSR_STOP	(1L<<5)		/* Bit	5:	Stop Rx/Tx Queue */
+#define	CSR_START	(1L<<4)		/* Bit	4:	Start Rx/Tx Queue */
+#define	CSR_IRQ_CL_P	(1L<<3)		/* Bit	3: (Rx)	Clear Parity IRQ */
+#define	CSR_IRQ_CL_B	(1L<<2)		/* Bit	2:	Clear EOB IRQ */
+#define	CSR_IRQ_CL_F	(1L<<1)		/* Bit	1:	Clear EOF IRQ */
+#define	CSR_IRQ_CL_C	(1L<<0)		/* Bit	0:	Clear ERR IRQ */
+
+#define CSR_SET_RESET	(CSR_DESC_SET|CSR_FIFO_SET|CSR_HPI_RST|CSR_SV_RST|\
+			CSR_DREAD_RST|CSR_DWRITE_RST|CSR_TRANS_RST)
+#define CSR_CLR_RESET	(CSR_DESC_CLR|CSR_FIFO_CLR|CSR_HPI_RUN|CSR_SV_RUN|\
+			CSR_DREAD_RUN|CSR_DWRITE_RUN|CSR_TRANS_RUN)
+
+
+/*	Q_F	32 bit	Flag Register */
+					/* Bit 28..31:	reserved */
+#define F_ALM_FULL	(1L<<27) (Rx)	/* Bit 27: (Rx)	FIFO almost full */
+#define F_EMPTY		(1L<<27) (Tx)	/* Bit 27: (Tx)	FIFO empty flag */
+#define F_FIFO_EOF	(1L<<26)	/* Bit 26: 	Fag bit in FIFO */
+#define F_WM_REACHED	(1L<<25)	/* Bit 25: 	Watermark reached */
+					/* Bit 24:	reserved */
+#define F_FIFO_LEVEL	(0x1fL<<16)	/* Bit 23..16:	# of Qwords in FIFO */
+					/* Bit 15..11: 	reserved */
+#define F_WATER_MARK	0x0007ffL	/* Bit 10.. 0:	Watermark */
+
+/*	Q_T1	32 bit	Test Register 1 */
+/*		Holds four State Machine control Bytes */
+#define	SM_CRTL_SV	(0xffL<<24)	/* Bit 31..24:	Control Supervisor SM */
+#define	SM_CRTL_RD	(0xffL<<16)	/* Bit 23..16:	Control Read Desc SM */
+#define	SM_CRTL_WR	(0xffL<<8)	/* Bit 15.. 8:	Control Write Desc SM */
+#define	SM_CRTL_TR	(0xffL<<0)	/* Bit	7.. 0:	Control Transfer SM */
+
+/*	Q_T1_TR	 8 bit	Test Register 1 Transfer SM */
+/*	Q_T1_WR	 8 bit	Test Register 1 Write Descriptor SM */
+/*	Q_T1_RD	 8 bit	Test Register 1 Read Descriptor SM */
+/*	Q_T1_SV	 8 bit	Test Register 1 Supervisor SM */
+/* The control status byte of each machine looks like ... */
+#define	SM_STATE	0xf0	/* Bit 7..4:	State which shall be loaded */
+#define	SM_LOAD		(1<<3)	/* Bit 3:	Load the SM with SM_STATE */
+#define	SM_TEST_ON	(1<<2)	/* Bit 2:	Switch on SM Test Mode */
+#define	SM_TEST_OFF	(1<<1)	/* Bit 1:	Go off the Test Mode */
+#define	SM_STEP		(1<<0)	/* Bit 0:	Step the State Machine */
+/* The encoding of the states is not supported by the Diagnostics Tool */
+
+/*	Q_T2	32 bit	Test Register 2	*/
+				/* Bit 31..8:	reserved */
+#define	T2_AC_T_ON	(1<<7)	/* Bit 7:	Address Counter Test Mode on */
+#define	T2_AC_T_OFF	(1<<6)	/* Bit 6:	Address Counter Test Mode off*/
+#define	T2_BC_T_ON	(1<<5)	/* Bit 5:	Byte Counter Test Mode on */
+#define	T2_BC_T_OFF	(1<<4)	/* Bit 4:	Byte Counter Test Mode off */
+#define	T2_STEP04	(1<<3)	/* Bit 3:	Inc AC/Dec BC by 4 */
+#define	T2_STEP03	(1<<2)	/* Bit 2:	Inc AC/Dec BC by 3 */
+#define	T2_STEP02	(1<<1)	/* Bit 1:	Inc AC/Dec BC by 2 */
+#define	T2_STEP01	(1<<0)	/* Bit 0:	Inc AC/Dec BC by 1 */
+
+/*	Q_T3	32 bit	Test Register 3	*/
+				/* Bit 31..7:	reserved */
+#define	T3_MUX		(7<<4)	/* Bit 6.. 4:	Mux Position */
+				/* Bit 3:	reserved */
+#define	T3_VRAM		(7<<0)	/* Bit 2.. 0:	Virtual RAM Buffer Address */
+
+/* RAM Buffer Register Offsets */
+/* use RB_ADDR(Queue,Offs) to address */
+/*	RB_START	32 bit	RAM Buffer Start Address */
+/*	RB_END		32 bit	RAM Buffer End Address */
+/*	RB_WP		32 bit	RAM Buffer Write Pointer */
+/*	RB_RP		32 bit	RAM Buffer Read Pointer */
+/*	RB_RX_UTPP	32 bit	Rx Upper Threshold, Pause Pack */
+/*	RB_RX_LTPP	32 bit	Rx Lower Threshold, Pasue Pack */
+/*	RB_RX_UTHP	32 bit	Rx Upper Threshold, High Prio */
+/*	RB_RX_LTHP	32 bit	Rx Lower Threshold, High Prio */
+/*	RB_PC		32 bit	RAM Buffer Packet Counter */
+/*	RB_LEV		32 bit	RAM Buffer Level Register */
+				/* Bit 31..19:	reserved */
+#define RB_MSK	0x0007ffff	/* Bit 18.. 0:	RAM Buffer Pointer Bits */
+
+/*	RB_TST2		8 bit	RAM Buffer Test Register 2 */
+				/* Bit 4..7:	reserved */
+#define	RB_PC_DEC	(1<<3)	/* Bit 3:	Packet Counter Decrem */
+#define RB_PC_T_ON	(1<<2)	/* Bit 2:	Packet Counter Test On */
+#define RB_PC_T_OFF	(1<<1)	/* Bit 1:	Packet Counter Tst Off */
+#define RB_PC_INC	(1<<0)	/* Bit 0:	Packet Counter Increm */
+
+/*	RB_TST1		8 bit	RAM Buffer Test Register 1 */
+				/* Bit 7:	reserved */
+#define RB_WP_T_ON	(1<<6)	/* Bit 6:	Write Pointer Test On */
+#define RB_WP_T_OFF	(1<<5)	/* Bit 5:	Write Pointer Test Off */
+#define RB_WP_INC	(1<<4)	/* Bit 4:	Write Pointer Increm */
+				/* Bit 3:	reserved */
+#define RB_RP_T_ON	(1<<2)	/* Bit 2:	Read Pointer Test On */
+#define RB_RP_T_OFF	(1<<1)	/* Bit 1:	Read Pointer Test Off */
+#define RB_RP_DEC	(1<<0)	/* Bit 0:	Read Pointer Decrement */
+
+/*	RB_CTRL		8 bit	RAM Buffer Control Register */
+				/* Bit	7..6:	reserved */
+#define RB_ENA_STFWD	(1<<5)	/* Bit	5:	Enable Store & Forward */
+#define RB_DIS_STFWD	(1<<4)	/* Bit	4:	Disab. Store & Forward */
+#define RB_ENA_OP_MD	(1<<3)	/* Bit	3:	Enable Operation Mode */
+#define RB_DIS_OP_MD	(1<<2)	/* Bit	2:	Disab. Operation Mode */
+#define RB_RST_CLR	(1<<1)	/* Bit	1:	Clr RAM Buf STM Reset */
+#define RB_RST_SET	(1<<0)	/* Bit	0:	Set RAM Buf STM Reset */
+
+
+/* Receive and Transmit MAC FIFO Registers, use MR_ADDR() to address */
+/*	RX_MFF_EA	32 bit	Receive MAC FIFO End Address */
+/*	RX_MFF_WP	32 bit 	Receive MAC FIFO Write Pointer */
+/*	RX_MFF_RP	32 bit	Receive MAC FIFO Read Pointer */
+/*	RX_MFF_PC	32 bit	Receive MAC FIFO Packet Counter*/
+/*	RX_MFF_LEV	32 bit	Receive MAC FIFO Level */
+/*	TX_MFF_EA	32 bit	Transmit MAC FIFO End Address */
+/*	TX_MFF_WP	32 bit 	Transmit MAC FIFO Write Pointer*/
+/*	TX_MFF_WSP	32 bit	Transmit MAC FIFO WR Shadow Pt*/
+/*	TX_MFF_RP	32 bit	Transmit MAC FIFO Read Pointer */
+/*	TX_MFF_PC	32 bit	Transmit MAC FIFO Packet Cnt */
+/*	TX_MFF_LEV	32 bit	Transmit MAC FIFO Level */
+				/* Bit 31..6:	reserved */
+#define MFF_MSK		0x007fL	/* Bit	5..0:	MAC FIFO Address/Pointer Bits */
+
+/*	RX_MFF_CTRL1	16 bit	Receive MAC FIFO Control Reg 1 */
+					/* Bit 15..14:	reserved */
+#define MFF_ENA_RDY_PAT	(1<<13)		/* Bit 13:	Enable Ready Patch */
+#define MFF_DIS_RDY_PAT	(1<<12)		/* Bit 12:	Disable Ready Patch */
+#define MFF_ENA_TIM_PAT	(1<<11)		/* Bit 11:	Enable Timing Patch */
+#define MFF_DIS_TIM_PAT	(1<<10)		/* Bit 10:	Disable Timing Patch */
+#define MFF_ENA_ALM_FUL	(1<<9)		/* Bit	9:	Enable AlmostFull Sign*/
+#define MFF_DIS_ALM_FUL	(1<<8)		/* Bit	8:	Disab. AlmostFull Sign*/
+#define MFF_ENA_PAUSE	(1<<7)		/* Bit	7:	Enable Pause Signaling*/
+#define MFF_DIS_PAUSE	(1<<6)		/* Bit	6:	Disab. Pause Signaling*/
+#define MFF_ENA_FLUSH	(1<<5)		/* Bit	5:	Enable Frame Flushing */
+#define MFF_DIS_FLUSH	(1<<4)		/* Bit	4:	Disab. Frame Flushing */
+#define MFF_ENA_TIST	(1<<3)		/* Bit	3:	Enable Timestamp Gener*/
+#define MFF_DIS_TIST	(1<<2)		/* Bit	2:	Disab. Timestamp Gener*/
+#define MFF_CLR_INTIST	(1<<1)		/* Bit	1:	Clear IRQ No Timestamp*/
+#define MFF_CLR_INSTAT	(1<<0)		/* Bit	0:	Clear IRQ No Status */
+
+#define MFF_RX_CTRL_DEF MFF_ENA_TIM_PAT
+
+/*	TX_MFF_CTRL1	16 bit	Transmit MAC FIFO Control Reg 1 */
+#define MFF_CLR_PERR	(1<<15)		/* Bit 15:	Clear Parity Error IRQ*/
+					/* Bit 14:	reserved */
+#define MFF_ENA_PKT_REC	(1<<13)		/* Bit 13:	Enable Packet Recovery*/
+#define MFF_DIS_PKT_REC (1<<12)		/* Bit 12:	Disable Packet Recov. */
+/*	MFF_ENA_TIM_PAT	 (see RX_MFF_CTRL1)Bit 11:	Enable Timing Patch */
+/*	MFF_DIS_TIM_PAT	 (see RX_MFF_CTRL1)Bit 10:	Disable Timing Patch */
+/*	MFF_ENA_ALM_FUL	 (see RX_MFF_CTRL1)Bit	9:	Enable AlmostFull Sign*/
+/*	MFF_DIS_ALM_FUL	 (see RX_MFF_CTRL1)Bit	8:	Disab. AlmostFull Sign*/
+#define	MFF_ENA_W4E	(1<<7)		/* Bit	7:	Enable Wait for Empty */
+#define MFF_DIS_W4E	(1<<6)		/* Bit	6:	Disab. Wait for Empty */
+/*	MFF_ENA_FLUSH	 (see RX_MFF_CTRL1)Bit	5:	Enable Frame Flushing */
+/*	MFF_DIS_FLUSH	 (see RX_MFF_CTRL1)Bit	4:	Disab. Frame Flushing */
+#define MFF_ENA_LOOPB	(1<<3)		/* Bit	3:	Enable Loopback */
+#define MFF_DIS_LOOPB	(1<<2)		/* Bit	2:	Disable Loopback */
+#define MFF_CLR_MAC_RST	(1<<1)		/* Bit	1:	Clear XMAC Reset */
+#define MFF_SET_MAC_RST	(1<<0)		/* Bit	0:	Set XMAC Reset */
+
+#define MFF_TX_CTRL_DEF	(MFF_ENA_PKT_REC | MFF_ENA_TIM_PAT | MFF_ENA_FLUSH)
+
+/*	RX_MFF_TST2	 8 bit	Receive MAC FIFO Test Register 2 */
+/*	TX_MFF_TST2	 8 bit	Transmit MAC FIFO Test Register 2 */
+				/* Bit 7:	reserved */
+#define MFF_WSP_T_ON	(1<<6)	/* Bit 6: (Tx)	Write Shadow Pt TestOn */
+#define MFF_WSP_T_OFF	(1<<5)	/* Bit 5: (Tx)	Write Shadow Pt TstOff */
+#define MFF_WSP_INC	(1<<4)	/* Bit 4: (Tx)	Write Shadow Pt Increm */
+#define	MFF_PC_DEC	(1<<3)	/* Bit 3:	Packet Counter Decrem  */
+#define MFF_PC_T_ON	(1<<2)	/* Bit 2:	Packet Counter Test On */
+#define MFF_PC_T_OFF	(1<<1)	/* Bit 1:	Packet Counter Tst Off */
+#define MFF_PC_INC	(1<<0)	/* Bit 0:	Packet Counter Increm  */
+
+/*	RX_MFF_TST1	 8 bit	Receive MAC FIFO Test Register 1 */
+/*	TX_MFF_TST1	 8 bit	Transmit MAC FIFO Test Register 1 */
+				/* Bit 7:	reserved */
+#define MFF_WP_T_ON	(1<<6)	/* Bit 6:	Write Pointer Test On */
+#define MFF_WP_T_OFF	(1<<5)	/* Bit 5:	Write Pointer Test Off */
+#define MFF_WP_INC	(1<<4)	/* Bit 4:	Write Pointer Increm */
+				/* Bit 3:	reserved */
+#define MFF_RP_T_ON	(1<<2)	/* Bit 2:	Read Pointer Test On */
+#define MFF_RP_T_OFF	(1<<1)	/* Bit 1:	Read Pointer Test Off */
+#define MFF_RP_DEC	(1<<0)	/* Bit 0:	Read Pointer Decrement */
+
+/*	RX_MFF_CTRL2	 8 bit	Receive MAC FIFO Control Reg 2 */
+/*	TX_MFF_CTRL2	 8 bit	Transmit MAC FIFO Control Reg 2 */
+				/* Bit 7..4:	reserved */
+#define MFF_ENA_OP_MD	(1<<3)	/* Bit 3:	Enable Operation Mode */
+#define MFF_DIS_OP_MD	(1<<2)	/* Bit 2:	Disab. Operation Mode */
+#define MFF_RST_CLR	(1<<1)	/* Bit 1:	Clear MAC FIFO Reset */
+#define MFF_RST_SET	(1<<0)	/* Bit 0:	Set MAC FIFO Reset */
+
+
+/* Receive, Transmit, and Link LED Counter Registers */
+/*	RX_LED_CTRL	 8 bit	Receive LED Cnt Control Reg */
+/*	TX_LED_CTRL	 8 bit	Transmit LED Cnt Control Reg */
+/*	LNK_SYNC_CTRL	 8 bit	Link Sync Cnt Control Register */
+				/* Bit 7..3:	reserved */
+#define LED_START	(1<<2)	/* Bit 2:	Start Timer */
+#define LED_STOP	(1<<1)	/* Bit 1:	Stop Timer */
+#define LED_STATE	(1<<0)	/* Bit 0:(Rx/Tx)LED State, 1=LED on */
+#define LED_CLR_IRQ	(1<<0)	/* Bit 0:(Lnk) 	Clear Link IRQ */
+
+/*	RX_LED_TST	 8 bit	Receive LED Cnt Test Register */
+/*	TX_LED_TST	 8 bit	Transmit LED Cnt Test Register */
+/*	LNK_SYNC_TST	 8 bit	Link Sync Cnt Test Register */
+				/* Bit 7..3:	reserved */
+#define LED_T_ON	(1<<2)	/* Bit 2:	LED Counter Testmode On */
+#define LED_T_OFF	(1<<1)	/* Bit 1:	LED Counter Testmode Off */
+#define LED_T_STEP	(1<<0)	/* Bit 0:	LED Counter Step */
+
+/*	LNK_LED_REG	 8 bit	Link LED Register */
+				/* Bit 7..6:	reserved */
+#define LED_BLK_ON	(1<<5)	/* Bit 5:	Link LED Blinking On */
+#define LED_BLK_OFF	(1<<4)	/* Bit 4:	Link LED Blinking Off */
+#define LED_SYNC_ON	(1<<3)	/* Bit 3:	Use Sync Wire to switch LED */
+#define LED_SYNC_OFF	(1<<2)	/* Bit 2:	Disable Sync Wire Input */
+#define LED_ON		(1<<1)	/* Bit 1:	switch LED on */
+#define LED_OFF		(1<<0)	/* Bit 0:	switch LED off */
+
+
+/* Receive and Transmit Descriptors ******************************************/
+
+/* Transmit Descriptor struct */
+typedef	struct s_HwTxd {
+	SK_U32 volatile	TxCtrl;	/* Transmit Buffer Control Field */
+	SK_U32	TxNext ;	/* Physical Address Pointer to the next TxD */
+	SK_U32	TxAdrLo ;	/* Physical Tx Buffer Address lower dword */
+	SK_U32	TxAdrHi ;	/* Physical Tx Buffer Address upper dword */
+	SK_U32	TxStat ;	/* Transmit Frame Status Word */
+#ifndef	SK_USE_REV_DESC
+	SK_U16	TxTcpOffs ;	/* TCP Checksum Calculation Start Value */
+	SK_U16	TxRes1 ;	/* 16 bit reserved field */
+	SK_U16	TxTcpWp ;	/* TCP Checksum Write Position */
+	SK_U16	TxTcpSp ;	/* TCP Checksum Calculation Start Position */
+#else	/* SK_USE_REV_DESC */
+	SK_U16	TxRes1 ;	/* 16 bit reserved field */
+	SK_U16	TxTcpOffs ;	/* TCP Checksum Calculation Start Value */
+	SK_U16	TxTcpSp ;	/* TCP Checksum Calculation Start Position */
+	SK_U16	TxTcpWp ;	/* TCP Checksum Write Position */
+#endif	/* SK_USE_REV_DESC */
+	SK_U32  TxRes2;		/* 32 bit reserved field */
+} SK_HWTXD;
+
+/* Receive Descriptor struct */
+typedef	struct s_HwRxd {
+	SK_U32 volatile RxCtrl;	/* Receive Buffer Control Field */
+	SK_U32	RxNext ;	/* Physical Address Pointer to the next TxD */
+	SK_U32	RxAdrLo ;	/* Physical Receive Buffer Address lower dword*/
+	SK_U32	RxAdrHi ;	/* Physical Receive Buffer Address upper dword*/
+	SK_U32	RxStat ;	/* Receive Frame Status Word */
+	SK_U32	RxTiSt ;	/* Receive Timestamp provided by the XMAC */
+#ifndef	SK_USE_REV_DESC	
+	SK_U16	RxTcpSum1 ;	/* TCP Checksum 1 */
+	SK_U16	RxTcpSum2 ;	/* TCP Checksum 2 */
+	SK_U16	RxTcpSp1 ;	/* TCP Checksum Calculation Start Position 1 */
+	SK_U16	RxTcpSp2 ;	/* TCP Checksum Calculation Start Position 2 */
+#else	/* SK_USE_REV_DESC */
+	SK_U16	RxTcpSum2 ;	/* TCP Checksum 2 */
+	SK_U16	RxTcpSum1 ;	/* TCP Checksum 1 */
+	SK_U16	RxTcpSp2 ;	/* TCP Checksum Calculation Start Position 2 */
+	SK_U16	RxTcpSp1 ;	/* TCP Checksum Calculation Start Position 1 */
+#endif	/* SK_USE_REV_DESC */
+} SK_HWRXD;
+
+/*
+ * Drivers which use the reverse descriptor feature (PCI_OUR_REG_2)
+ * should set the define SK_USE_REV_DESC.
+ * Structures are 'normaly' not endianess dependent. But in 
+ * this case the SK_U16 fields are bound to bit positions inside the
+ * descriptor. RxTcpSum1 e.g. must start at bit 0 within the 6.th DWord.
+ * The bit positions inside a DWord are of course endianess dependent and
+ * swaps if the DWord is swaped by the hardware.
+ */
+
+
+/* Descriptor Bit Definition */
+/*	TxCtrl		Transmit Buffer Control Field */
+/*	RxCtrl		Receive Buffer Control Field */
+#define	BMU_OWN		(1UL<<31)	/* Bit 31:	OWN bit: 0=host/1=BMU */
+#define	BMU_STF		(1L<<30)	/* Bit 30:	Start of Frame ? */
+#define	BMU_EOF		(1L<<29)	/* Bit 29:	End of Frame ?	*/
+#define	BMU_IRQ_EOB	(1L<<28)	/* Bit 28:	Req "End of Buff" IRQ */
+#define	BMU_IRQ_EOF	(1L<<27)	/* Bit 27:	Req "End of Frame" IRQ*/
+/* TxCtrl specific bits */
+#define BMU_STFWD	(1L<<26)	/* Bit 26: (Tx)	Store&Forward Frame */
+#define BMU_NO_FCS	(1L<<25)	/* Bit 25: (Tx) disable XMAC FCS gener*/
+#define BMU_SW		(1L<<24)	/* Bit 24: (Tx)	1 bit res. for SW use */
+/* RxCtrl specific bits */
+#define	BMU_DEV_0	(1L<<26)	/* Bit 26: (Rx)	transfer data to Dev0 */
+#define BMU_STAT_VAL	(1L<<25)	/* Bit 25: (Rx)	RxStat Valid */
+#define BMU_TIST_VAL	(1L<<24)	/* Bit 24: (Rx)	RxTiSt Valid */
+					/* Bit 23..16:	BMU Check Opcodes */
+#define	BMU_CHECK	0x00550000L	/* 		Default BMU check */
+#define	BMU_TCP_CHECK	0x00560000L	/* 		Descr with TCP ext */
+#define	BMU_BBC		0x0000FFFFL	/* Bit 15..0:	Buffer Byte Counter */
+
+/*	TxStat		Transmit Frame Status Word */
+/*	RxStat		Receive Frame Status Word */
+/*
+ *Note: TxStat is reserved for ASIC loopback mode only
+ *
+ *	The Bits of the Status words are defined in xmac_ii.h
+ *	(see XMR_FS bits)
+ */
+
+/* other defines *************************************************************/
+
+/*
+ * FlashProm specification
+ */
+#define	MAX_PAGES	0x20000L	/* Every byte has a single page */
+#define	MAX_FADDR	1		/* 1 byte per page */
+#define	SKFDDI_PSZ	8		/* address PROM size */
+
+/* macros ********************************************************************/
+
+/*
+ * Receive and Transmit Queues
+ */
+#define Q_R1	0x0000		/* Receive Queue 1 */
+#define Q_R2	0x0080		/* Receive Queue 2 */
+#define Q_XS1	0x0200		/* Synchronous Transmit Queue 1 */
+#define Q_XA1	0x0280		/* Asynchronous Transmit Queue 1 */
+#define Q_XS2	0x0300		/* Synchronous Transmit Queue 2 */
+#define Q_XA2	0x0380		/* Asynchronous Transmit Queue 2 */
+
+/*
+ *	Macro Q_ADDR()
+ *
+ *	Use this macro to address the Receive and Transmit Queue Registers.
+ *
+ * para	Queue	Queue to address.
+ *			Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2
+ *	Offs	Queue register offset.
+ *			Values: Q_D, Q_DA_L ... Q_T2, Q_T3
+ *
+ * usage	SK_IN32(pAC,Q_ADDR(Q_R2,Q_BC),pVal)
+ */
+#define Q_ADDR(Queue,Offs)	(B8_Q_REGS + (Queue) + (Offs))
+
+/*
+ *	Macro RB_ADDR()
+ *
+ *	Use this macro to address the RAM Buffer Registers.
+ *
+ * para	Queue	Queue to address.
+ *			Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2
+ *	Offs	Queue register offset.
+ *			Values: RB_START, RB_END ... RB_LEV, RB_CTRL
+ *
+ * usage	SK_IN32(pAC,RB_ADDR(Q_R2,RB_RP),pVal)
+ */
+#define RB_ADDR(Queue,Offs)	(B16_RAM_REGS + (Queue) + (Offs))
+
+
+/*
+ * MAC Related Registers
+ */
+#define	MAC_1		0	/* belongs to the port near the slot */
+#define MAC_2		1	/* belongs to the port far away from the slot */
+
+/*
+ *	Macro MR_ADDR()
+ *
+ *	Use this macro to address a MAC Related Registers in side the ASIC.
+ *
+ * para	Queue	Queue to address.
+ *			Values:	TXA_ITI_INI	...	TXA_TEST,
+ *				RX_MFF_EA	...	RX_LED_TST,
+ *				LNK_SYNC_INI	...	LNK_LED_REG, and
+ *				TX_MFF_EA	...	TX_LED_TST
+ *	Mac	MAC to address.
+ *			Values: MAC_1, MAC_2
+ *
+ * usage	SK_IN32(pAC,MR_ADDR(MAC_1,TX_MFF_EA),pVal)
+ */
+#define MR_ADDR(Mac,Offs)	(((Mac) << 7) + (Offs))
+
+
+
+/*
+ * macros to access the XMAC
+ *
+ * XM_IN16(),		to read a 16 bit register (e.g. XM_MMU_CMD)
+ * XM_OUT16(),		to write a 16 bit register (e.g. XM_MMU_CMD)
+ * XM_IN32(),		to read a 32 bit register (e.g. XM_TX_EV_CNT)
+ * XM_OUT32(),		to write a 32 bit register (e.g. XM_TX_EV_CNT)
+ * XM_INADDR(),		to read a network address register (e.g. XM_SRC_CHK)
+ * XM_OUTADDR(),	to write a network address register (e.g. XM_SRC_CHK)
+ * XM_INHASH(),		to read the XM_HSM_CHK register
+ * XM_OUTHASH()		to write the XM_HSM_CHK register
+ *
+ * para:	Mac	XMAC to address		values: MAC_1 or MAC_2
+ *		IoC	I/O context needed for SK IO macros
+ *		Reg	XMAC Register to read or write
+ *		(p)Val	Value or pointer to the value which should be read or
+ *			written.
+ *
+ * usage:	XM_OUT16(IoC, MAC_1, XM_MMU_CMD, Value) ;
+ */
+
+#ifdef	SK_LITTLE_ENDIAN
+#define	XM_WORD_LO	0
+#define XM_WORD_HI	1
+#else	/* !SK_LITTLE_ENDIAN */
+#define	XM_WORD_LO	1
+#define XM_WORD_HI	0
+#endif	/* !SK_LITTLE_ENDIAN */
+
+#define	XMA(Mac,Reg)	(((0x1000 << (Mac)) + 0x1000) | ((Reg) << 1))
+
+#define XM_IN16(IoC,Mac,Reg,pVal)	SK_IN16((IoC),XMA((Mac),(Reg)),(pVal))
+#define XM_OUT16(IoC,Mac,Reg,Val)	SK_OUT16((IoC),XMA((Mac),(Reg)),(Val))
+
+#define XM_IN32(IoC,Mac,Reg,pVal) {					\
+	SK_IN16((IoC),XMA((Mac),(Reg)),					\
+		(SK_U16 *)&((SK_U16 *)(pVal))[XM_WORD_LO]);		\
+	SK_IN16((IoC),XMA((Mac),(Reg+2)),				\
+		(SK_U16 *)&((SK_U16 *)(pVal))[XM_WORD_HI]);		\
+}
+
+#define XM_OUT32(IoC,Mac,Reg,Val) {					\
+	SK_OUT16((IoC),XMA((Mac),(Reg)), (SK_U16)((Val) & 0x0000ffffL));\
+	SK_OUT16((IoC),XMA((Mac),(Reg+2)),(SK_U16)(((Val)>>16) & 0x0000ffffL));\
+}
+
+/*
+ * Remember: we are always writing to / reading from LITTLE ENDIAN memory
+ */
+
+#define XM_INADDR(IoC, Mac, Reg, pVal) {				\
+	SK_U16	Word;							\
+	SK_U8	*pByte;							\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_IN16((IoC), XMA((Mac), (Reg)), &Word);			\
+	pByte[0] = (SK_U8) (Word  & 0x00ff);				\
+	pByte[1] = (SK_U8) ((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word);			\
+	pByte[2] = (SK_U8) (Word  & 0x00ff);				\
+	pByte[3] = (SK_U8) ((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word);			\
+	pByte[4] = (SK_U8) (Word  & 0x00ff);				\
+	pByte[5] = (SK_U8) ((Word >> 8) & 0x00ff);			\
+}
+
+#define XM_OUTADDR(IoC, Mac, Reg, pVal) {				\
+	SK_U8	*pByte;							\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)			\
+		 (((SK_U16)(pByte[0]) & 0x00ff)|			\
+		 (((SK_U16)(pByte[1]) << 8) & 0xff00)));		\
+	SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)			\
+		 (((SK_U16)(pByte[2]) & 0x00ff)|			\
+		 (((SK_U16)(pByte[3]) << 8) & 0xff00)));		\
+	SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16)			\
+		 (((SK_U16)(pByte[4]) & 0x00ff)|			\
+		 (((SK_U16)(pByte[5]) << 8) & 0xff00)));		\
+}
+
+#define XM_INHASH(IoC, Mac, Reg, pVal) {				\
+	SK_U16	Word;							\
+	SK_U8	*pByte;							\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_IN16((IoC), XMA((Mac), (Reg)), &Word);			\
+	pByte[0] = (SK_U8) (Word  & 0x00ff);				\
+	pByte[1] = (SK_U8) ((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word);			\
+	pByte[2] = (SK_U8) (Word  & 0x00ff);				\
+	pByte[3] = (SK_U8) ((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word);			\
+	pByte[4] = (SK_U8) (Word  & 0x00ff);				\
+	pByte[5] = (SK_U8) ((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), XMA((Mac), (Reg+6)), &Word);			\
+	pByte[6] = (SK_U8) (Word  & 0x00ff);				\
+	pByte[7] = (SK_U8) ((Word >> 8) & 0x00ff);			\
+}
+
+#define XM_OUTHASH(IoC, Mac, Reg, pVal) {				\
+	SK_U8	*pByte;							\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)			\
+		 (((SK_U16)(pByte[0]) & 0x00ff)|			\
+		 (((SK_U16)(pByte[1]) << 8) & 0xff00)));		\
+	SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)			\
+		 (((SK_U16)(pByte[2]) & 0x00ff)|			\
+		 (((SK_U16)(pByte[3]) << 8) & 0xff00)));		\
+	SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16)			\
+		 (((SK_U16)(pByte[4]) & 0x00ff)|			\
+		 (((SK_U16)(pByte[5]) << 8) & 0xff00)));		\
+	SK_OUT16((IoC), XMA((Mac), (Reg+6)), (SK_U16)			\
+		 (((SK_U16)(pByte[6]) & 0x00ff)|			\
+		 (((SK_U16)(pByte[7]) << 8) & 0xff00)));		\
+}
+
+/*
+ * Different PHY Types
+ */
+#define SK_PHY_XMAC	0	/* integrated in Xmac II*/
+#define SK_PHY_BCOM	1	/* Broadcom BCM5400 */
+#define SK_PHY_LONE	2	/* Level One LXT1000 */
+#define SK_PHY_NAT	3	/* National DP83891 */ 
+
+/*
+ * PHY addresses (bits 8..12 of PHY address reg)
+ */
+#define PHY_ADDR_XMAC	(0<<8)
+#define PHY_ADDR_BCOM	(1<<8)
+#define PHY_ADDR_LONE	(3<<8)
+#define PHY_ADDR_NAT	(0<<8)
+
+/*
+ * macros to access the PHY
+ *
+ * PHY_READ()		read a 16 bit value from the PHY
+ * PHY_WIRTE()		write a 16 bit value to the PHY
+ *
+ * para:	IoC	I/O context needed for SK IO macros
+ *		pPort	Pointer to port struct for PhyAddr
+ * 		Mac	XMAC to address		values: MAC_1 or MAC_2
+ *		PhyReg	PHY Register to read or write
+ *		(p)Val	Value or pointer to the value which should be read or
+ *			written.
+ *
+ * usage:	PHY_READ(IoC, pPort, MAC_1, PHY_CTRL, Value);
+ */
+#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) {			\
+	SK_U16 Mmu;  							\
+									\
+	XM_OUT16((IoC),(Mac), XM_PHY_ADDR, (PhyReg)|(pPort)->PhyAddr);	\
+	XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));			\
+	if ((pPort)->PhyType != SK_PHY_XMAC) {				\
+		do {  							\
+			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);	\
+		} while ((Mmu & XM_MMU_PHY_RDY) == 0);			\
+		XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));		\
+	}  								\
+}
+
+#define PHY_WRITE(IoC, pPort, Mac, PhyReg, Val) {			\
+	SK_U16 Mmu;							\
+									\
+	if ((pPort)->PhyType != SK_PHY_XMAC) {				\
+		do {  							\
+			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);	\
+		} while ((Mmu & XM_MMU_PHY_BUSY) != 0);			\
+	}  								\
+	XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg)|(pPort)->PhyAddr);	\
+	XM_OUT16((IoC), (Mac), XM_PHY_DATA, (Val));			\
+	if ((pPort)->PhyType != SK_PHY_XMAC) {				\
+		do {  							\
+			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);	\
+		} while ((Mmu & XM_MMU_PHY_BUSY) != 0);			\
+	}  								\
+}
+
+/*
+ *	Macro PCI_C()
+ *
+ *	Use this macro to address PCI config register from the IO space.
+ *
+ * para	Addr	PCI configuration register to address.
+ *			Values:	PCI_VENDOR_ID	...	PCI_VPD_ADDR,
+ *
+ * usage	SK_IN16(pAC,PCI_C(PCI_VENDOR_ID),pVal);
+ */
+#define PCI_C(Addr)	(B7_CFG_SPC + (Addr))	/* PCI Config Space */
+
+/*
+ *	Macro SK_ADDR(Base,Addr)
+ *
+ *	Calculates the effective HW address
+ *
+ * para Base	IO- or memory base address
+ *	Addr	Address offset
+ *
+ * usage:	May be used in SK_INxx and SK_OUTxx macros
+ *		#define SK_IN8(pAC,Addr,pVal) ...\
+ *			*pVal = (SK_U8) inp(SK_ADDR(pAC->Hw.Iop,Addr)))
+ */
+#ifdef	SK_MEM_MAPPED_IO
+#define	SK_HW_ADDR(Base,Addr)	((Base)+(Addr))
+#else	/* SK_MEM_MAPPED_IO */
+#define SK_HW_ADDR(Base,Addr)	((Base)+(((Addr)&0x7F)|((Addr)>>7 ? 0x80:0)))
+#endif	/* SK_MEM_MAPPED_IO */
+
+#define	SZ_LONG	(sizeof(SK_U32))
+
+/*
+ *	Macro SK_HWAC_LINK_LED()
+ *
+ *	Use this macro to set the link LED mode.
+ * para pAC	Pointer to adapter context struct
+ *	IoC	I/O context needed for SK IO macros
+ *     	Port	Port number
+ *	Mode	Mode to set for this LED
+ */
+#define SK_HWAC_LINK_LED(pAC, IoC, Port, Mode) \
+SK_OUT8(IoC, MR_ADDR(Port,LNK_LED_REG), Mode); 
+
+ 
+/* typedefs *******************************************************************/
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_SKGEHW_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skgehwt.h linux.14p16/drivers/net/sk98lin/h/skgehwt.h
--- linux.vanilla/drivers/net/sk98lin/h/skgehwt.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skgehwt.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,71 @@
+/******************************************************************************
+ *
+ * Name:	skhwt.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.4 $
+ * Date:	$Date: 1998/08/19 09:50:58 $
+ * Purpose:	Defines for the hardware timer functions
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgehwt.h,v $
+ *	Revision 1.4  1998/08/19 09:50:58  gklug
+ *	fix: remove struct keyword from c-code (see CCC) add typedefs
+ *	
+ *	Revision 1.3  1998/08/14 07:09:29  gklug
+ *	fix: chg pAc -> pAC
+ *	
+ *	Revision 1.2  1998/08/07 12:54:21  gklug
+ *	fix: first compiled version
+ *	
+ *	Revision 1.1  1998/08/07 09:32:58  gklug
+ *	first version
+ *	
+ *	
+ *	
+ *	
+ *
+ ******************************************************************************/
+
+/*
+ * SKGEHWT.H	contains all defines and types for the timer functions
+ */
+
+#ifndef	_SKGEHWT_H_
+#define _SKGEHWT_H_
+
+/*
+ * SK Hardware Timer
+ * - needed wherever the HWT module is used
+ * - use in Adapters context name pAC->Hwt
+ */
+typedef	struct s_Hwt {
+	SK_U32		TStart ;	/* HWT start */
+	SK_U32		TStop ;		/* HWT stop */
+	int		TActive ;	/* HWT: flag : active/inactive */
+} SK_HWT;
+
+extern void SkHwtInit(SK_AC *pAC, SK_IOC Ioc);
+extern void SkHwtStart(SK_AC *pAC, SK_IOC Ioc, SK_U32 Time);
+extern void SkHwtStop(SK_AC *pAC, SK_IOC Ioc);
+extern SK_U32 SkHwtRead(SK_AC *pAC,SK_IOC Ioc);
+extern void SkHwtIsr(SK_AC *pAC, SK_IOC Ioc);
+#endif	/* _SKGEHWT_H_ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skgei2c.h linux.14p16/drivers/net/sk98lin/h/skgei2c.h
--- linux.vanilla/drivers/net/sk98lin/h/skgei2c.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skgei2c.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,245 @@
+/******************************************************************************
+ *
+ * Name:	skgei2c.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.16 $
+ * Date:	$Date: 1999/11/12 08:24:10 $
+ * Purpose:	Special genesis defines for I2C
+ *		(taken from Monalisa (taken from Concentrator))
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgei2c.h,v $
+ *	Revision 1.16  1999/11/12 08:24:10  malthoff
+ *	Change voltage warning and error limits
+ *	(warning +-5%, error +-10%).
+ *	
+ *	Revision 1.15  1999/09/14 14:14:43  malthoff
+ *	The 1000BT Dual Link adapter has got only one Fan.
+ *	The second Fan has been removed.
+ *	
+ *	Revision 1.14  1999/05/27 13:40:50  malthoff
+ *	Fan Divisor = 1. Assuming fan with 6500 rpm.
+ *	
+ *	Revision 1.13  1999/05/20 14:56:55  malthoff
+ *	Bug Fix: Missing brace in SK_LM80_FAN_FAKTOR.
+ *	
+ *	Revision 1.12  1999/05/20 09:22:00  cgoos
+ *	Changes for 1000Base-T (Fan sensors).
+ *	
+ *	Revision 1.11  1998/10/14 05:57:22  cgoos
+ *	Fixed compilation warnings.
+ *	
+ *	Revision 1.10  1998/09/04 08:37:00  malthoff
+ *	bugfix: correct the SK_I2C_GET_CTL() macro.
+ *	
+ *	Revision 1.9  1998/08/25 06:10:03  gklug
+ *	add: thresholds for all sensors
+ *
+ *	Revision 1.8  1998/08/20 11:37:42  gklug
+ *	chg: change Ioc to IoC
+ *	
+ *	Revision 1.7  1998/08/20 08:53:11  gklug
+ *	fix: compiler errors
+ *	add: Threshold values
+ *	
+ *	Revision 1.6  1998/08/17 11:37:09  malthoff
+ *	Bugfix in SK_I2C_CTL macro. The parameter 'dev'
+ *	has to be shifted 9 bits.
+ *	
+ *	Revision 1.5  1998/08/17 06:52:21  malthoff
+ *	Remove unrequired macros.
+ *	Add macros for accessing I2C SW register.
+ *	
+ *	Revision 1.4  1998/08/13 08:30:18  gklug
+ *	add: conversion factors for read values
+ *	add: new state SEN_VALEXT to read extension value of temperature sensor
+ *
+ *	Revision 1.3  1998/08/12 13:37:56  gklug
+ *	rmv: error numbers and messages
+ *
+ *	Revision 1.2  1998/08/11 07:54:38  gklug
+ *	add: sensor states for GE sensors
+ *	add: Macro to access I2c hardware register
+ *	chg: Error messages for I2c errors
+ *
+ *	Revision 1.1  1998/07/17 11:27:56  gklug
+ *	Created.
+ *
+ *
+ *
+ ******************************************************************************/
+
+/*
+ * SKGEI2C.H	contains all SK-98xx specific defines for the I2C handling
+ */
+
+#ifndef _INC_SKGEI2C_H_
+#define _INC_SKGEI2C_H_
+
+/*
+ * Macros to access the B2_I2C_CTRL
+ */
+#define SK_I2C_CTL(IoC,flag,dev,reg,burst) \
+	SK_OUT32(IoC,B2_I2C_CTRL,\
+		(flag ? 0x80000000UL : 0x0L ) | \
+		(((SK_U32) reg << 16) & I2C_ADDR) | \
+		(((SK_U32) dev << 9) & I2C_DEV_SEL) | \
+		(( burst << 4) & I2C_BURST_LEN) )
+
+#define SK_I2C_STOP(IoC) {				\
+	SK_U32	I2cCtrl;				\
+	SK_IN32(IoC, B2_I2C_CTRL, &I2cCtrl);		\
+	SK_OUT32(IoC, B2_I2C_CTRL, I2cCtrl | I2C_STOP);	\
+}
+
+#define SK_I2C_GET_CTL(Ioc,pI2cCtrl)	SK_IN32(Ioc,B2_I2C_CTRL,pI2cCtrl)
+
+/*
+ * Macros to access the I2C SW Registers
+ */
+#define SK_I2C_SET_BIT(IoC, SetBits) {			\
+	SK_U8	OrgBits;				\
+	SK_IN8(IoC, B2_I2C_SW, &OrgBits);		\
+	SK_OUT8(IoC, B2_I2C_SW, OrgBits | (SetBits));	\
+}
+
+#define SK_I2C_CLR_BIT(IoC,ClrBits) {			\
+	SK_U8	OrgBits;				\
+	SK_IN8(IoC, B2_I2C_SW, &OrgBits);		\
+	SK_OUT8(IoC, B2_I2C_SW, OrgBits & ~(ClrBits));	\
+}
+
+#define SK_I2C_GET_SW(IoC,pI2cSw)	SK_IN8(IoC,B2_I2C_SW,pI2cSw)
+
+/*
+ * define the possible sensor states
+ */
+#define	SK_SEN_IDLE	0	/* Idle: sensor not read */
+#define	SK_SEN_VALUE	1	/* Value Read cycle */
+#define	SK_SEN_VALEXT	2	/* Extended Value Read cycle */
+
+/*
+ * Conversion factor to convert read Voltage sensor to milli Volt
+ * Conversion factor to convert read Temperature sensor to 10th degree Celsius
+ */
+#define	SK_LM80_VT_LSB		22	/* 22mV LSB resolution */
+#define	SK_LM80_TEMP_LSB	10	/* 1 degree LSB resolution */
+#define	SK_LM80_TEMPEXT_LSB	5	/* 0.5 degree LSB resolution for the
+					 * extension value 
+					 */
+#define SK_LM80_FAN_FAKTOR	((22500L*60)/(1*2))
+/* formula: counter = (22500*60)/(rpm * divisor * pulses/2)
+ * assuming: 6500rpm, 4 pulses, divisor 1
+ */
+
+/*
+ * Define sensor management data
+ * Maximum is reached on copperfield with dual Broadcom.
+ * Board specific maximum is in pAC->I2c.MaxSens
+ */
+#define	SK_MAX_SENSORS	8	/* maximal no. of installed sensors */
+#define	SK_MIN_SENSORS	5	/* minimal no. of installed sensors */
+
+/*
+ * Defines for the individual Thresholds
+ */
+
+/* Temperature sensor */
+#define	SK_SEN_ERRHIGH0		800	/* Temperature High Err Threshold */
+#define	SK_SEN_WARNHIGH0	700	/* Temperature High Warn Threshold */
+#define	SK_SEN_WARNLOW0		100	/* Temperature Low Err Threshold */
+#define	SK_SEN_ERRLOW0		0	/* Temperature Low Warn Threshold */
+
+/* VCC which should be 5 V */
+#define	SK_SEN_ERRHIGH1		5588	/* Voltage PCI High Err Threshold */
+#define	SK_SEN_WARNHIGH1	5346	/* Voltage PCI High Warn Threshold */
+#define	SK_SEN_WARNLOW1		4664	/* Voltage PCI Low Err Threshold */
+#define	SK_SEN_ERRLOW1		4422	/* Voltage PCI Low Warn Threshold */
+
+/*
+ * VIO may be 5 V or 3.3 V. Initialization takes two parts:
+ * 1. Initialize lowest lower limit and highest higher limit.
+ * 2. After the first value is read correct the upper or the lower limit to
+ *    the appropriate C constant.
+ *
+ * Warning limits are +-5% of the exepected voltage.
+ * Error limits are +-10% of the expected voltage.
+ */
+#define	SK_SEN_ERRHIGH2		5588	/* Voltage PCI-IO High Err Threshold */
+#define	SK_SEN_WARNHIGH2	5346	/* Voltage PCI-IO High Warn Threshold */
+#define	SK_SEN_WARNLOW2		3146	/* Voltage PCI-IO Low Err Threshold */
+#define	SK_SEN_ERRLOW2		2970	/* Voltage PCI-IO Low Warn Threshold */
+
+/* correction values for the second pass */
+#define	SK_SEN_ERRHIGH2C	3630	/* Voltage PCI-IO High Err Threshold */
+#define	SK_SEN_WARNHIGH2C	3476	/* Voltage PCI-IO High Warn Threshold */
+#define	SK_SEN_WARNLOW2C	4664	/* Voltage PCI-IO Low Err Threshold */
+#define	SK_SEN_ERRLOW2C		4422	/* Voltage PCI-IO Low Warn Threshold */
+
+/*
+ * VDD voltage
+ */
+#define	SK_SEN_ERRHIGH3		3630	/* Voltage ASIC High Err Threshold */
+#define	SK_SEN_WARNHIGH3	3476	/* Voltage ASIC High Warn Threshold */
+#define	SK_SEN_WARNLOW3		3146	/* Voltage ASIC Low Err Threshold */
+#define	SK_SEN_ERRLOW3		2970	/* Voltage ASIC Low Warn Threshold */
+
+/*
+ * PLC_3V3 voltage
+ * PHY_PLL_A_3V3 voltage
+ */
+#define	SK_SEN_ERRHIGH4		3630	/* Voltage PMA High Err Threshold */
+#define	SK_SEN_WARNHIGH4	3476	/* Voltage PMA High Warn Threshold */
+#define	SK_SEN_WARNLOW4		3146	/* Voltage PMA Low Err Threshold */
+#define	SK_SEN_ERRLOW4		2970	/* Voltage PMA Low Warn Threshold */
+
+/*
+ * PHY_2V5 voltage
+ */
+#define	SK_SEN_ERRHIGH5		2750	/* Voltage PHY High Err Threshold */
+#define	SK_SEN_WARNHIGH5	2640	/* Voltage PHY High Warn Threshold */
+#define	SK_SEN_WARNLOW5		2376	/* Voltage PHY Low Err Threshold */
+#define	SK_SEN_ERRLOW5		2222	/* Voltage PHY Low Warn Threshold */
+
+/*
+ * PHY_PLL_B_3V3 voltage
+ */
+#define	SK_SEN_ERRHIGH6		3630	/* Voltage PMA High Err Threshold */
+#define	SK_SEN_WARNHIGH6	3476	/* Voltage PMA High Warn Threshold */
+#define	SK_SEN_WARNLOW6		3146	/* Voltage PMA Low Err Threshold */
+#define	SK_SEN_ERRLOW6		2970	/* Voltage PMA Low Warn Threshold */
+
+/*
+ * FAN 1 speed
+ */
+/* assuming: 6500rpm +-15%, 4 pulses,
+ * warning at:	80 %
+ * error at:	70 %
+ * no upper limit
+ */
+#define	SK_SEN_ERRHIGH		20000	/* FAN Speed High Err Threshold */
+#define	SK_SEN_WARNHIGH		20000	/* FAN Speed High Warn Threshold */
+#define	SK_SEN_WARNLOW		5200	/* FAN Speed Low Err Threshold */
+#define	SK_SEN_ERRLOW		4550	/* FAN Speed Low Warn Threshold */
+
+extern	int SkLm80ReadSensor(SK_AC *pAC, SK_IOC IoC, SK_SENSOR *pSen);
+#endif	/* n_INC_SKGEI2C_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skgeinit.h linux.14p16/drivers/net/sk98lin/h/skgeinit.h
--- linux.vanilla/drivers/net/sk98lin/h/skgeinit.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skgeinit.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,733 @@
+/******************************************************************************
+ *
+ * Name:	skgeinit.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.44 $
+ * Date:	$Date: 1999/10/26 07:34:15 $
+ * Purpose:	Structures and prototypes for the GE Init Module
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgeinit.h,v $
+ *	Revision 1.44  1999/10/26 07:34:15  malthoff
+ *	The define SK_LNK_ON has been lost in v1.41.
+ *	
+ *	Revision 1.43  1999/10/06 09:30:16  cgoos
+ *	Changed SK_XM_THR_JUMBO.
+ *	
+ *	Revision 1.42  1999/09/16 12:58:26  cgoos
+ *	Changed SK_LED_STANDY macro to be independent of HW link sync.
+ *	
+ *	Revision 1.41  1999/07/30 06:56:14  malthoff
+ *	Correct comment for SK_MS_STAT_UNSET.
+ *	
+ *	Revision 1.40  1999/05/27 13:38:46  cgoos
+ *	Added SK_BMU_TX_WM.
+ *	Made SK_BMU_TX_WM and SK_BMU_RX_WM user-definable.
+ *	Changed XMAC Tx treshold to max. values.
+ *	
+ *	Revision 1.39  1999/05/20 14:35:26  malthoff
+ *	Remove prototypes for SkGeLinkLED().
+ *	
+ *	Revision 1.38  1999/05/19 11:59:12  cgoos
+ *	Added SK_MS_CAP_INDETERMINATED define.
+ *	
+ *	Revision 1.37  1999/05/19 07:32:33  cgoos
+ *	Changes for 1000Base-T.
+ *	LED-defines for HWAC_LINK_LED macro.
+ *	
+ *	Revision 1.36  1999/04/08 14:00:24  gklug
+ *	add:Port struct field PLinkResCt
+ *	
+ *	Revision 1.35  1999/03/25 07:43:07  malthoff
+ *	Add error string for SKERR_HWI_E018MSG.
+ *	
+ *	Revision 1.34  1999/03/12 16:25:57  malthoff
+ *	Remove PPollRxD and PPollTxD.
+ *	Add SKERR_HWI_E017MSG. and SK_DPOLL_MAX.
+ *	
+ *	Revision 1.33  1999/03/12 13:34:41  malthoff
+ *	Add Autonegotiation error codes.
+ *	Change defines for parameter Mode in SkXmSetRxCmd().
+ *	Replace __STDC__ by SK_KR_PROTO.
+ *	
+ *	Revision 1.32  1999/01/25 14:40:20  mhaveman
+ *	Added new return states for the virtual management port if multiple
+ *	ports are active but differently configured.
+ *	
+ *	Revision 1.31  1998/12/11 15:17:02  gklug
+ *	add: Link partnet autoneg states : Unknown Manual and Autonegotiation
+ *	
+ *	Revision 1.30  1998/12/07 12:17:04  gklug
+ *	add: Link Partner autonegotiation flag
+ *	
+ *	Revision 1.29  1998/12/01 10:54:42  gklug
+ *	add: variables for XMAC Errata
+ *	
+ *	Revision 1.28  1998/12/01 10:14:15  gklug
+ *	add: PIsave saves the Interrupt status word
+ *	
+ *	Revision 1.27  1998/11/26 15:24:52  mhaveman
+ *	Added link status states SK_LMODE_STAT_AUTOHALF and
+ *	SK_LMODE_STAT_AUTOFULL which are used by PNMI.
+ *	
+ *	Revision 1.26  1998/11/26 14:53:01  gklug
+ *	add:autoNeg Timeout variable
+ *	
+ *	Revision 1.25  1998/11/26 08:58:50  gklug
+ *	add: Link Mode configuration (AUTO Sense mode)
+ *	
+ *	Revision 1.24  1998/11/24 13:30:27  gklug
+ *	add: PCheckPar to port struct
+ *	
+ *	Revision 1.23  1998/11/18 13:23:26  malthoff
+ *	Add SK_PKT_TO_MAX.
+ *	
+ *	Revision 1.22  1998/11/18 13:19:54  gklug
+ *	add: PPrevShorts and PLinkBroken to port struct for WA XMAC Errata #C1
+ *
+ *	Revision 1.21  1998/10/26 08:02:57  malthoff
+ *	Add GIRamOffs.
+ *	
+ *	Revision 1.20  1998/10/19 07:28:37  malthoff
+ *	Add prototyp for SkGeInitRamIface().
+ *	
+ *	Revision 1.19  1998/10/14 14:47:48  malthoff
+ *	SK_TIMER should not be defined for Diagnostics.
+ *	Add SKERR_HWI_E015MSG and SKERR_HWI_E016MSG.
+ *	
+ *	Revision 1.18  1998/10/14 14:00:03  gklug
+ *	add: timer to port struct for workaround of Errata #2
+ *	
+ *	Revision 1.17  1998/10/14 11:23:09  malthoff
+ *	Add prototype for SkXmAutoNegDone().
+ *	Fix SkXmSetRxCmd() prototype statement.
+ *
+ *	Revision 1.16  1998/10/14 05:42:29  gklug
+ *	add: HWLinkUp flag to Port struct
+ *	
+ *	Revision 1.15  1998/10/09 08:26:33  malthoff
+ *	Rename SK_RB_ULPP_B to SK_RB_LLPP_B.
+ *	
+ *	Revision 1.14  1998/10/09 07:11:13  malthoff
+ *	bug fix: SK_FACT_53 is 85 not 117.
+ *	Rework time out init values.
+ *	Add GIPortUsage and corresponding defines.
+ *	Add some error log messages.
+ *	
+ *	Revision 1.13  1998/10/06 14:13:14  malthoff
+ *	Add prototyp for SkGeLoadLnkSyncCnt().
+ *
+ *	Revision 1.12  1998/10/05 11:29:53  malthoff
+ *	bug fix: A comment was not closed.
+ *
+ *	Revision 1.11  1998/10/05 08:01:59  malthoff
+ *	Add default Timeout- Threshold- and
+ *	Watermark constants. Add QRam start and end
+ *	variables. Also add vars to store the polling
+ *	mode and receive command. Add new Error Log
+ *	Messages and function prototypes.
+ *
+ *	Revision 1.10  1998/09/28 13:34:48  malthoff
+ *	Add mode bits for LED functions.
+ *	Move Autoneg and Flow Ctrl bits from shgesirq.h
+ *	Add the required Error Log Entries
+ *	and Function Prototypes.
+ *
+ *	Revision 1.9  1998/09/16 14:38:41  malthoff
+ *	Rework the SK_LNK_xxx defines.
+ *	Add error log message defines.
+ *	Add prototypes for skxmac2.c
+ *
+ *	Revision 1.8  1998/09/11 05:29:18  gklug
+ *	add: init state of a port
+ *
+ *	Revision 1.7  1998/09/08 08:35:52  gklug
+ *	add: defines of the Init Levels
+ *
+ *	Revision 1.6  1998/09/03 13:48:42  gklug
+ *	add: Link strati, capabilities to Port struct
+ *
+ *	Revision 1.5  1998/09/03 13:30:59  malthoff
+ *	Add SK_LNK_BLINK and SK_LNK_PERM.
+ *
+ *	Revision 1.4  1998/09/03 09:55:31  malthoff
+ *	Add constants for parameters Dir and RstMode
+ *	when calling SkGeStopPort().
+ *	Rework the prototyp section.
+ *	Add Queue Address offsets PRxQOff, PXsQOff, and PXaQOff.
+ *	Remove Ioc with IoC.
+ *
+ *	Revision 1.3  1998/08/19 09:11:54  gklug
+ *	fix: struct are removed from c-source (see CCC)
+ *	add: typedefs for all structs
+ *
+ *	Revision 1.2  1998/07/28 12:38:26  malthoff
+ *	The prototypes got the parameter 'IoC'.
+ *
+ *	Revision 1.1  1998/07/23 09:50:24  malthoff
+ *	Created.
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKGEINIT_H_
+#define __INC_SKGEINIT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* __cplusplus */
+
+/* defines ********************************************************************/
+
+/*
+ * defines for modifying Link LED behaviour (has been used with SkGeLinkLED())
+ */
+#define SK_LNK_OFF	LED_OFF
+#define SK_LNK_ON	(LED_ON | LED_BLK_OFF| LED_SYNC_OFF)	
+#define SK_LNK_BLINK	(LED_ON | LED_BLK_ON | LED_SYNC_ON)
+#define SK_LNK_PERM	(LED_ON | LED_BLK_OFF| LED_SYNC_ON)
+#define SK_LNK_TST	(LED_ON | LED_BLK_ON | LED_SYNC_OFF)
+
+/*
+ * defines for parameter 'Mode' when calling SK_HWAC_LINK_LED()
+ */
+#define SK_LED_OFF	LED_OFF
+#define SK_LED_ACTIVE	(LED_ON | LED_BLK_OFF| LED_SYNC_OFF)
+#define SK_LED_STANDBY	(LED_ON | LED_BLK_ON| LED_SYNC_OFF)
+
+/*
+ * defines for parameter 'Mode' when calling SkGeXmitLED()
+ */
+#define SK_LED_DIS	0
+#define SK_LED_ENA	1
+#define SK_LED_TST	2
+
+/*
+ * Counter and Timer constants, for a host clock of 62.5 MHz
+ */
+#define SK_XMIT_DUR	0x002faf08L		/*  50 ms */
+#define SK_BLK_DUR	0x01dcd650L		/* 500 ms */
+
+#define SK_DPOLL_DEF	0x00EE6B28L		/* 250 ms */
+#define SK_DPOLL_MAX	0x00FFFFFFL		/* ca. 268ms */
+
+#define SK_FACT_62	100			/* is given in percent */
+#define SK_FACT_53	 85
+
+/*
+ * Timeout values
+ */
+#define SK_MAC_TO_53	72		/* MAC arbiter timeout */
+#define SK_PKT_TO_53	0x2000		/* Packet arbiter timeout */
+#define SK_PKT_TO_MAX	0xffff		/* Maximum value */
+#define SK_RI_TO_53	36		/* RAM interface timeout */
+
+/*
+ * RAM Buffer High Pause Threshold values
+ */
+#define SK_RB_ULPP	( 8 * 1024)	/* Upper Level in kB/8 */
+#define SK_RB_LLPP_S	(10 * 1024)	/* Lower Level for small Queues */
+#define SK_RB_LLPP_B	(16 * 1024)	/* Lower Level for big Queues */
+
+#ifndef SK_BMU_RX_WM
+#define SK_BMU_RX_WM	0x600		/* BMU Rx Watermark */
+#endif
+#ifndef SK_BMU_TX_WM
+#define SK_BMU_TX_WM	0x600		/* BMU Rx Watermark */
+#endif
+
+/* XMAC II Tx Threshold */
+#define SK_XM_THR_REDL	0x01fb		/* .. for redundant link usage */
+#define SK_XM_THR_SL	0x01fb		/* .. for single link adapters */
+#define SK_XM_THR_MULL	0x01fb		/* .. for multiple link usage */
+#define SK_XM_THR_JUMBO	0x03fc		/* .. for jumbo frame usage */
+
+/* values for GIPortUsage */
+#define SK_RED_LINK	1		/* redundant link usage */
+#define SK_MUL_LINK	2		/* multiple link usage */
+#define SK_JUMBO_LINK	3		/* driver uses jumbo frames */
+
+/* Minimum RAM Buffer Receive Queue Size */
+#define SK_MIN_RXQ_SIZE	16	/* 16 kB */
+/*
+ * defines for parameter 'Dir' when calling SkGeStopPort()
+ */
+#define	SK_STOP_TX	1	/* Stops the transmit path, resets the XMAC */
+#define SK_STOP_RX	2	/* Stops the receive path */
+#define SK_STOP_ALL	3	/* Stops rx and tx path, resets the XMAC */
+
+/*
+ * defines for parameter 'RstMode' when calling SkGeStopPort()
+ */
+#define SK_SOFT_RST	1	/* perform a software reset */
+#define SK_HARD_RST	2	/* perform a hardware reset */
+
+/*
+ * Define Init Levels
+ */
+#define	SK_INIT_DATA	0	/* Init level 0: init data structures */
+#define	SK_INIT_IO	1	/* Init level 1: init with IOs */
+#define	SK_INIT_RUN	2	/* Init level 2: init for run time */
+
+/*
+ * Set Link Mode Parameter
+ */
+#define	SK_LMODE_HALF		1	/* Half Duplex Mode */
+#define	SK_LMODE_FULL		2	/* Full Duplex Mode */
+#define	SK_LMODE_AUTOHALF	3	/* AutoHalf Duplex Mode */
+#define	SK_LMODE_AUTOFULL	4	/* AutoFull Duplex Mode */
+#define	SK_LMODE_AUTOBOTH	5	/* AutoBoth Duplex Mode */
+#define	SK_LMODE_AUTOSENSE	6	/* configured mode auto sensing */
+#define SK_LMODE_INDETERMINATED	7	/* Return value for virtual port if
+					 * multiple ports are differently
+					 * configured.
+					 */
+
+/*
+ * Autonegotiation timeout in 100ms granularity.
+ */
+#define	SK_AND_MAX_TO		6	/* Wait 600 msec before link comes up */
+
+/*
+ * Define Autonegotiation error codes here
+ */
+#define	SK_AND_OK		0	/* no error */
+#define	SK_AND_OTHER		1	/* other error than below */
+#define	SK_AND_DUP_CAP		2	/* Duplex capabilities error */
+
+/*
+ * Link Capability value
+ */
+#define	SK_LMODE_CAP_HALF	(1<<0)	/* Half Duplex Mode */
+#define	SK_LMODE_CAP_FULL	(1<<1)	/* Full Duplex Mode */
+#define	SK_LMODE_CAP_AUTOHALF	(1<<2)	/* AutoHalf Duplex Mode */
+#define	SK_LMODE_CAP_AUTOFULL	(1<<3)	/* AutoFull Duplex Mode */
+#define SK_LMODE_CAP_INDETERMINATED (1<<4) /* Return value for virtual port if
+					 * multiple ports are differently
+					 * configured.
+					 */
+
+/*
+ * Link mode current state
+ */
+#define	SK_LMODE_STAT_UNKNOWN	1	/* Unknown Duplex Mode */
+#define	SK_LMODE_STAT_HALF	2	/* Half Duplex Mode */
+#define	SK_LMODE_STAT_FULL	3	/* Full Duplex Mode */
+#define SK_LMODE_STAT_AUTOHALF	4	/* Half Duplex Mode obtained by AutoNeg */
+#define SK_LMODE_STAT_AUTOFULL	5	/* Half Duplex Mode obtained by AutoNeg */
+#define SK_LMODE_STAT_INDETERMINATED 6	/* Return value for virtual port if
+					 * multiple ports are differently
+					 * configured.
+					 */
+/*
+ * Set Flow Control Mode Parameter (and capabilities)
+ */
+#define	SK_FLOW_MODE_NONE	1	/* No Flow Control */
+#define	SK_FLOW_MODE_LOC_SEND	2	/* Local station sends PAUSE */
+#define	SK_FLOW_MODE_SYMMETRIC	3	/* Both station may send PAUSE */
+#define	SK_FLOW_MODE_SYM_OR_REM	4	/* Both station may send PAUSE or
+					 * just the remote station may send
+					 * PAUSE
+					 */
+#define SK_FLOW_MODE_INDETERMINATED 5	/* Return value for virtual port if
+					 * multiple ports are differently
+					 * configured.
+					 */
+
+/*
+ * Flow Control Status Parameter
+ */
+#define	SK_FLOW_STAT_NONE	1	/* No Flow Control */
+#define	SK_FLOW_STAT_REM_SEND	2	/* Remote Station sends PAUSE */
+#define	SK_FLOW_STAT_LOC_SEND	3	/* Local station sends PAUSE */
+#define	SK_FLOW_STAT_SYMMETRIC	4	/* Both station may send PAUSE */
+#define SK_FLOW_STAT_INDETERMINATED 5	/* Return value for virtual port if
+					 * multiple ports are differently
+					 * configured.
+					 */
+/*
+ * Master/Slave Mode capabilities
+ */
+#define	SK_MS_CAP_AUTO		(1<<0)	/* Automatic resolution */
+#define	SK_MS_CAP_MASTER	(1<<1)	/* This station is master */
+#define	SK_MS_CAP_SLAVE		(1<<2)	/* This station is slave */
+#define	SK_MS_CAP_INDETERMINATED (1<<3)	/* Return value for virtual port if
+					 * multiple ports are differently
+					 * configured.
+					 */
+
+/*
+ * Set Master/Slave Mode Parameter (and capabilities)
+ */
+#define	SK_MS_MODE_AUTO		1	/* Automatic resolution */
+#define	SK_MS_MODE_MASTER	2	/* This station is master */
+#define	SK_MS_MODE_SLAVE	3	/* This station is slave */
+#define SK_MS_MODE_INDETERMINATED 4	/* Return value for virtual port if 
+					 * multiple ports are differently
+					 */
+
+/*
+ * Master/Slave Status Parameter
+ */
+#define	SK_MS_STAT_UNSET	1	/* The MS status is never been determ*/
+#define	SK_MS_STAT_MASTER	2	/* This station is master */
+#define	SK_MS_STAT_SLAVE	3	/* This station is slave */
+#define	SK_MS_STAT_FAULT	4	/* MS resolution failed */
+#define SK_MS_STAT_INDETERMINATED 5	/* Return value for virtual port if
+					 * multiple ports are differently
+					 */
+
+/*
+ * defines for parameter 'Mode' when calling SkXmSetRxCmd()
+ */
+#define SK_STRIP_FCS_ON		(1<<0)	/* Enable FCS stripping of rx frames */
+#define SK_STRIP_FCS_OFF	(1<<1)	/* Disable FCS stripping of rx frames */
+#define SK_STRIP_PAD_ON		(1<<2)	/* Enable pad byte stripping of rx f */
+#define SK_STRIP_PAD_OFF	(1<<3)	/* Disable pad byte stripping of rx f */
+#define SK_LENERR_OK_ON		(1<<4)	/* Don't chk fr for in range len error*/
+#define SK_LENERR_OK_OFF	(1<<5)	/* Check frames for in range len error*/
+#define SK_BIG_PK_OK_ON		(1<<6)	/* Don't set rcvError bit for big fr */
+#define SK_BIG_PK_OK_OFF	(1<<7)	/* Set rcvError bit for big frames */	
+
+/*
+ * States of PState
+ */
+#define SK_PRT_RESET	0	/* the port is reset */
+#define SK_PRT_STOP	1	/* the port is stopped (similar to sw reset) */
+#define SK_PRT_INIT	2	/* the port is initialized */
+#define SK_PRT_RUN	3	/* the port has an active link */
+
+/*
+ * Default receive frame limit for Workaround of XMAC Errata
+ */
+#define	SK_DEF_RX_WA_LIM	SK_CONSTU64(100)
+
+/*
+ * Define link partner Status
+ */
+#define	SK_LIPA_UNKNOWN	0	/* Link partner is in unknown state */
+#define	SK_LIPA_MANUAL	1	/* Link partner is in detected manual state */
+#define	SK_LIPA_AUTO	2	/* Link partner is in autonegotiation state */
+
+/*
+ * Define Maximum Restarts before restart is ignored (3com WA)
+ */
+#define	SK_MAX_LRESTART	3	/* Max. 3 times the link is restarted */
+
+/* structures *****************************************************************/
+
+/*
+ * Port Structure
+ */
+typedef	struct s_GePort {
+#ifndef SK_DIAG
+	SK_TIMER	PWaTimer;	/* Workaround Timer */
+#endif
+	SK_U64	PPrevShorts;	/* Previous short Counter checking */
+	SK_U64	PPrevRx;	/* Previous RxOk Counter checking */
+	SK_U64	PPrevFcs;	/* Previous FCS Error Counter checking */
+	SK_U64	PRxLim;		/* Previous RxOk Counter checking */
+	int	PLinkResCt;	/* Link Restart Counter */
+	int	PAutoNegTimeOut;/* AutoNegotiation timeout current value */
+	int	PRxQSize;	/* Port Rx Queue Size in kB */
+	int	PXSQSize;	/* Port Synchronous Transmit Queue Size in kB */
+	int	PXAQSize;	/* Port Asynchronous Transmit Queue Size in kB*/
+	SK_U32	PRxQRamStart;	/* Receive Queue RAM Buffer Start Address */
+	SK_U32	PRxQRamEnd;	/* Receive Queue RAM Buffer End Address */
+	SK_U32	PXsQRamStart;	/* Sync Tx Queue RAM Buffer Start Address */
+	SK_U32	PXsQRamEnd;	/* Sync Tx Queue RAM Buffer End Address */
+	SK_U32	PXaQRamStart;	/* Async Tx Queue RAM Buffer Start Address */
+	SK_U32	PXaQRamEnd;	/* Async Tx Queue RAM Buffer End Address */
+	int	PRxQOff;	/* Rx Queue Address Offset */
+	int	PXsQOff;	/* Synchronous Tx Queue Address Offset */
+	int	PXaQOff;	/* Asynchronous Tx Queue Address Offset */
+	SK_U16	PRxCmd;		/* Port Receive Command Configuration Value */
+	SK_U16	PIsave;		/* Saved Interrupt status word */
+	SK_U16	PSsave;		/* Saved PHY status word */
+	SK_BOOL	PHWLinkUp;	/* The hardware Link is up (wireing) */
+	SK_BOOL	PState;		/* Is port initialized ? */
+	SK_BOOL	PLinkBroken;	/* Is Link broken ? */
+	SK_BOOL	PCheckPar;	/* Do we check for parity errors ? */
+	SK_U8	PLinkCap;	/* Link Capabilities */
+	SK_U8	PLinkModeConf;	/* Link Mode configured */
+	SK_U8	PLinkMode;	/* Link Mode currently used */
+	SK_U8	PLinkModeStatus;	/* Link Mode Status */
+	SK_U8	PFlowCtrlCap;	/* Flow Control Capabilities */
+	SK_U8	PFlowCtrlMode;	/* Flow Control Mode */
+	SK_U8	PFlowCtrlStatus;	/* Flow Control Status */
+	SK_U8	PMSCap;		/* Master/Slave Capabilities */
+	SK_U8	PMSMode;	/* Master/Slave Mode */
+	SK_U8	PMSStatus;	/* Master/Slave Status */
+	SK_U8	PAutoNegFail;	/* Autonegotiation fail flag */
+	SK_U8	PLipaAutoNeg;	/* Autonegotiation possible with Link Partner */
+	int	PhyType;	/* PHY used on this port */
+	SK_U16	PhyAddr;	/* MDIO/MDC PHY address */
+} SK_GEPORT;
+
+/*
+ * Gigabit Ethernet Initalization Struct
+ * (has to be included in the adapter context
+ */
+typedef	struct s_GeInit {
+	int	GIMacsFound;	/* Number of MACs found on this adapter */
+	int	GIPciHwRev;	/* PCI HW Revision Number */
+	SK_U32	GIRamOffs;	/* RAM Address Offset for addr calculation */
+	int	GIRamSize;	/* The RAM size of the adapter in kB */
+	int	GIHstClkFact;	/* Host Clock Factor (62.5 / HstClk * 100) */
+	int	GIPortUsage;	/* driver port usage: SK_RED_LINK/SK_MUL_LINK */
+	SK_U32	GIPollTimerVal;	/* Descriptor Poll Timer Init Val in clk ticks*/
+	int	GILevel;	/* Initialization Level Completed */
+	SK_BOOL	GIAnyPortAct;	/* Is True if one or more port is initialized */
+	SK_GEPORT	GP[SK_MAX_MACS];	/* Port Dependent Information */
+} SK_GEINIT;
+
+/*
+ * Define the error numbers and messages for xmac_ii.c and skgeinit.c
+ */
+#define	SKERR_HWI_E001		(SK_ERRBASE_HWINIT)
+#define	SKERR_HWI_E001MSG	"SkXmClrExactAddr() has got illegal parameters"
+#define	SKERR_HWI_E002		(SKERR_HWI_E001+1)
+#define	SKERR_HWI_E002MSG	"SkGeInit() Level 1 call missing"
+#define	SKERR_HWI_E003		(SKERR_HWI_E002+1)
+#define	SKERR_HWI_E003MSG	"SkGeInit() called with illegal init Level"
+#define	SKERR_HWI_E004		(SKERR_HWI_E003+1)
+#define	SKERR_HWI_E004MSG	"SkGeInitPort() Queue size illegal configured"
+#define	SKERR_HWI_E005		(SKERR_HWI_E004+1)
+#define	SKERR_HWI_E005MSG	"SkGeInitPort() cannot init running ports"
+#define	SKERR_HWI_E006		(SKERR_HWI_E005+1)
+#define	SKERR_HWI_E006MSG	"SkGeXmInit(): PState does not match HW state"
+#define	SKERR_HWI_E007		(SKERR_HWI_E006+1)
+#define	SKERR_HWI_E007MSG	"SkXmInitDupMd() called with invalid Dup Mode"
+#define	SKERR_HWI_E008		(SKERR_HWI_E007+1)
+#define	SKERR_HWI_E008MSG	"SkXmSetRxCmd() called with invalid Mode"
+#define	SKERR_HWI_E009		(SKERR_HWI_E008+1)
+#define	SKERR_HWI_E009MSG	"SkGeCfgSync() called although PXSQSize zero"
+#define	SKERR_HWI_E010		(SKERR_HWI_E009+1)
+#define	SKERR_HWI_E010MSG	"SkGeCfgSync() called with invalid parameters"
+#define	SKERR_HWI_E011		(SKERR_HWI_E010+1)
+#define	SKERR_HWI_E011MSG	"SkGeInitPort() Receive Queue Size to small"
+#define	SKERR_HWI_E012		(SKERR_HWI_E011+1)
+#define	SKERR_HWI_E012MSG	"SkGeInitPort() invalid Queue Size specified"
+#define	SKERR_HWI_E013		(SKERR_HWI_E012+1)
+#define	SKERR_HWI_E013MSG	"SkGeInitPort() cfg changed for running queue"
+#define	SKERR_HWI_E014		(SKERR_HWI_E013+1)
+#define	SKERR_HWI_E014MSG	"SkGeInitPort() unknown GIPortUsage specified"
+#define	SKERR_HWI_E015		(SKERR_HWI_E014+1)
+#define	SKERR_HWI_E015MSG	"Illegal Link mode parameter"
+#define	SKERR_HWI_E016		(SKERR_HWI_E015+1)
+#define	SKERR_HWI_E016MSG	"Illegal Flow control mode parameter"
+#define	SKERR_HWI_E017		(SKERR_HWI_E016+1)
+#define	SKERR_HWI_E017MSG	"Illegal value specified for GIPollTimerVal"
+#define	SKERR_HWI_E018		(SKERR_HWI_E017+1)
+#define	SKERR_HWI_E018MSG	"FATAL: SkGeStopPort() does not terminate"
+#define	SKERR_HWI_E019		(SKERR_HWI_E018+1)
+#define	SKERR_HWI_E019MSG	""
+
+/* function prototypes ********************************************************/
+
+#ifndef	SK_KR_PROTO
+
+/*
+ * public functions in skgeinit.c
+ */
+extern void	SkGePollRxD(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port,
+	SK_BOOL		PollRxD);
+
+extern void	SkGePollTxD(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port,
+	SK_BOOL 	PollTxD);
+
+extern void	SkGeYellowLED(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		State);
+
+extern int	SkGeCfgSync(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port,
+	SK_U32		IntTime,
+	SK_U32		LimCount,
+	int		SyncMode);
+
+extern void	SkGeLoadLnkSyncCnt(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port,
+	SK_U32		CntVal);
+
+extern void	SkGeStopPort(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port,
+	int		Dir,
+	int		RstMode);
+
+extern int	SkGeInit(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Level);
+
+extern void	SkGeDeInit(
+	SK_AC		*pAC,
+	SK_IOC		IoC);
+
+extern int	SkGeInitPort(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port);
+
+extern void	SkGeXmitLED(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Led,
+	int		Mode);
+
+extern void	SkGeInitRamIface(
+	SK_AC		*pAC,
+	SK_IOC		IoC);
+
+/*
+ * public functions in skxmac2.c
+ */
+extern void	SkXmSetRxCmd(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port,
+	int		Mode);
+
+extern void	SkXmClrExactAddr(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port,
+	int		StartNum,
+	int		StopNum);
+
+extern void	SkXmFlushTxFifo(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port);
+
+extern void	SkXmFlushRxFifo(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port);
+
+extern void	SkXmSoftRst(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port);
+
+extern void	SkXmHardRst(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port);
+
+extern void	SkXmInitMac(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port);
+
+extern void	SkXmInitDupMd(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port);
+
+extern void	SkXmInitPauseMd(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port);
+
+extern int	SkXmAutoNegDone(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port);
+
+extern void	SkXmAutoNegLipaXmac(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port,
+	SK_U16		IStatus);
+
+extern void	SkXmAutoNegLipaBcom(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port,
+	SK_U16		IStatus);
+
+extern void	SkXmAutoNegLipaLone(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port,
+	SK_U16		IStatus);
+
+extern void	SkXmIrq(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		Port,
+	SK_U16		IStatus);
+
+#else	/* SK_KR_PROTO */
+
+/*
+ * public functions in skgeinit.c
+ */
+extern void	SkGePollRxD();
+extern void	SkGePollTxD();
+extern void	SkGeYellowLED();
+extern int	SkGeCfgSync();
+extern void	SkGeLoadLnkSyncCnt();
+extern void	SkGeStopPort();
+extern int	SkGeInit();
+extern void	SkGeDeInit();
+extern int	SkGeInitPort();
+extern void	SkGeXmitLED();
+extern void	SkGeInitRamIface();
+
+/*
+ * public functions in skxmac2.c
+ */
+extern void	SkXmSetRxCmd();
+extern void	SkXmClrExactAddr();
+extern void	SkXmFlushTxFifo();
+extern void	SkXmFlushRxFifo();
+extern void	SkXmSoftRst();
+extern void	SkXmHardRst();
+extern void	SkXmInitMac();
+extern void	SkXmInitDupMd();
+extern void	SkXmInitPauseMd();
+extern int	SkXmAutoNegDone();
+extern void	SkXmAutoNegLipa();
+extern void	SkXmIrq();
+
+#endif	/* SK_KR_PROTO */
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_SKGEINIT_H_ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skgepnm2.h linux.14p16/drivers/net/sk98lin/h/skgepnm2.h
--- linux.vanilla/drivers/net/sk98lin/h/skgepnm2.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skgepnm2.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,417 @@
+/*****************************************************************************
+ *
+ * Name:	skgepnm2.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.24 $
+ * Date:	$Date: 1999/04/13 15:11:11 $
+ * Purpose:	Defines for Private Network Management Interface
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgepnm2.h,v $
+ *	Revision 1.24  1999/04/13 15:11:11  mhaveman
+ *	Changed copyright.
+ *	
+ *	Revision 1.23  1999/01/28 15:07:12  mhaveman
+ *	Changed default threshold for port switches per hour from 10
+ *	to 240 which means 4 switches per minute. This fits better
+ *	the granularity of 32 for the port switch estimate
+ *	counter.
+ *	
+ *	Revision 1.22  1999/01/05 12:52:30  mhaveman
+ *	Removed macro SK_PNMI_MICRO_SEC.
+ *	
+ *	Revision 1.21  1999/01/05 12:50:34  mhaveman
+ *	Enlarged macro definition SK_PNMI_HUNDREDS_SEC() so that no 64-bit
+ *	arithmetic is necessary if SK_TICKS_PER_SEC is 100.
+ *	
+ *	Revision 1.20  1998/12/09 14:02:53  mhaveman
+ *	Defined macro SK_PNMI_DEF_RLMT_CHG_THRES for default port switch
+ *	threshold.
+ *	
+ *	Revision 1.19  1998/12/03 11:28:41  mhaveman
+ *	Removed SK_PNMI_CHECKPTR macro.
+ *	
+ *	Revision 1.18  1998/12/03 11:21:00  mhaveman
+ *	-Added pointer check macro SK_PNMI_CHECKPTR
+ *	-Added macros SK_PNMI_VPD_ARR_SIZE and SK_PNMI_VPD_STR_SIZE for
+ *	 VPD key evaluation.
+ *	
+ *	Revision 1.17  1998/11/20 13:20:33  mhaveman
+ *	Fixed bug in SK_PNMI_SET_STAT macro. ErrorStatus was not correctly set.
+ *	
+ *	Revision 1.16  1998/11/20 08:08:49  mhaveman
+ *	Macro SK_PNMI_CHECKFLAGS has got a if clause.
+ *	
+ *	Revision 1.15  1998/11/03 13:53:40  mhaveman
+ *	Fixed alignment problem in macor SK_PNMI_SET_STAT macro.
+ *	
+ *	Revision 1.14  1998/10/30 15:50:13  mhaveman
+ *	Added macro SK_PNMI_MICRO_SEC()
+ *	
+ *	Revision 1.13  1998/10/30 12:32:20  mhaveman
+ *	Added forgotten cast in SK_PNMI_READ_U32 macro.
+ *
+ *	Revision 1.12  1998/10/29 15:40:26  mhaveman
+ *	-Changed SK_PNMI_TRAP_SENSOR_LEN because SensorDescr has now
+ *	 variable string length.
+ *	-Defined SK_PNMI_CHECKFLAGS macro
+ *	
+ *	Revision 1.11  1998/10/29 08:53:34  mhaveman
+ *	Removed SK_PNMI_RLM_XXX table indexed because these counters need
+ *	not been saved over XMAC resets.
+ *	
+ *	Revision 1.10  1998/10/28 08:48:20  mhaveman
+ *	-Added macros for storage according to alignment
+ *	-Changed type of Instance to SK_U32 because of VPD
+ *	-Removed trap structures. Not needed because of alignment problem
+ *	-Changed type of Action form SK_U8 to int
+ *	
+ *	Revision 1.9  1998/10/21 13:34:45  mhaveman
+ *	Shit, mismatched calculation of SK_PNMI_HUNDREDS_SEC. Corrected.
+ *	
+ *	Revision 1.8  1998/10/21 13:24:58  mhaveman
+ *	Changed calculation of hundreds of seconds.
+ *	
+ *	Revision 1.7  1998/10/20 07:31:41  mhaveman
+ *	Made type changes to unsigned int where possible.
+ *	
+ *	Revision 1.6  1998/09/04 17:04:05  mhaveman
+ *	Added Sync counters to offset storage to provided settled values on
+ *	port switch.
+ *	
+ *	Revision 1.5  1998/09/04 12:45:35  mhaveman
+ *	Removed dummies for SK_DRIVER_ macros. They should be added by driver
+ *	writer in skdrv2nd.h.
+ *	
+ *	Revision 1.4  1998/09/04 11:59:50  mhaveman
+ *	Everything compiles now. Driver Macros for counting still missing.
+ *	
+ *	Revision 1.3  1998/08/24 12:01:35  mhaveman
+ *	Intermediate state.
+ *	
+ *	Revision 1.2  1998/08/17 07:51:40  mhaveman
+ *	Intermediate state.
+ *	
+ *	Revision 1.1  1998/08/11 09:08:40  mhaveman
+ *	Intermediate state.
+ *	
+ ****************************************************************************/
+
+#ifndef _SKGEPNM2_H_
+#define _SKGEPNM2_H_
+
+#ifndef FALSE
+#define FALSE			0
+#endif
+
+#ifndef TRUE
+#define	TRUE			!(FALSE)
+#endif
+
+/*
+ * General definitions
+ */
+#define SK_PNMI_CHIPSET		1	/* XMAC11800FP */
+
+#define	SK_PNMI_BUS_PCI		1	/* PCI bus*/
+
+/*
+ * Actions
+ */
+#define SK_PNMI_ACT_IDLE	1
+#define SK_PNMI_ACT_RESET	2
+#define SK_PNMI_ACT_SELFTEST	3
+#define SK_PNMI_ACT_RESETCNT	4
+
+/*
+ * VPD releated defines
+ */
+#define SK_PNMI_VPD_ARR_SIZE	40
+#define SK_PNMI_VPD_STR_SIZE	5
+
+#define SK_PNMI_VPD_RW		1
+#define SK_PNMI_VPD_RO		2
+
+#define SK_PNMI_VPD_OK		0
+#define SK_PNMI_VPD_NOTFOUND	1
+#define SK_PNMI_VPD_CUT		2
+#define SK_PNMI_VPD_TIMEOUT	3
+#define SK_PNMI_VPD_FULL	4
+#define SK_PNMI_VPD_NOWRITE	5
+#define SK_PNMI_VPD_FATAL	6
+
+#define SK_PNMI_VPD_IGNORE	0
+#define SK_PNMI_VPD_CREATE	1
+#define SK_PNMI_VPD_DELETE	2
+
+
+/*
+ * RLMT related defines
+ */
+#define SK_PNMI_DEF_RLMT_CHG_THRES	240	/* 4 changes per minute */
+
+/*
+ * Internal table definitions
+ */
+#define SK_PNMI_GET		0
+#define SK_PNMI_PRESET		1
+#define SK_PNMI_SET		2
+
+#define SK_PNMI_RO		0
+#define SK_PNMI_RW		1
+
+typedef struct s_OidTabEntry {
+	SK_U32		Id;
+	SK_U32		InstanceNo;
+	unsigned int	StructSize;
+	unsigned int	Offset;
+	int		Access;
+	int		(* Func)(SK_AC *pAc, SK_IOC pIo, int action,
+				SK_U32 Id, char* pBuf, unsigned int* pLen,
+				SK_U32 Instance, unsigned int TableIndex);
+	SK_U16		Param;
+} SK_PNMI_TAB_ENTRY;
+
+
+/*
+ * Trap lengths
+ */
+#define SK_PNMI_TRAP_SIMPLE_LEN		17
+#define SK_PNMI_TRAP_SENSOR_LEN_BASE	46
+#define SK_PNMI_TRAP_RLMT_CHANGE_LEN	23
+#define SK_PNMI_TRAP_RLMT_PORT_LEN	23
+
+
+/*
+ * MAC statistic data structures
+ */
+#define SK_PNMI_HTX			0
+#define SK_PNMI_HTX_OCTET		1
+#define SK_PNMI_HTX_OCTETHIGH		1
+#define SK_PNMI_HTX_OCTETLOW		2
+#define SK_PNMI_HTX_BROADCAST		3
+#define SK_PNMI_HTX_MULTICAST		4
+#define SK_PNMI_HTX_UNICAST		5
+#define SK_PNMI_HTX_LONGFRAMES		6
+#define SK_PNMI_HTX_BURST		7
+#define SK_PNMI_HTX_PMACC		8
+#define SK_PNMI_HTX_MACC		9
+#define SK_PNMI_HTX_SINGLE_COL		10
+#define SK_PNMI_HTX_MULTI_COL		11
+#define SK_PNMI_HTX_EXCESS_COL		12
+#define SK_PNMI_HTX_LATE_COL		13
+#define SK_PNMI_HTX_DEFFERAL		14
+#define SK_PNMI_HTX_EXCESS_DEF		15
+#define SK_PNMI_HTX_UNDERRUN		16
+#define SK_PNMI_HTX_CARRIER		17
+#define SK_PNMI_HTX_UTILUNDER		18
+#define SK_PNMI_HTX_UTILOVER		19
+#define SK_PNMI_HTX_64			20
+#define SK_PNMI_HTX_127			21
+#define SK_PNMI_HTX_255			22
+#define SK_PNMI_HTX_511			23
+#define SK_PNMI_HTX_1023		24
+#define SK_PNMI_HTX_MAX			25
+#define SK_PNMI_HTX_RESERVED26		26
+#define SK_PNMI_HTX_RESERVED27		27
+#define SK_PNMI_HTX_RESERVED28		28
+#define SK_PNMI_HTX_RESERVED29		29
+#define SK_PNMI_HTX_RESERVED30		30
+#define SK_PNMI_HTX_RESERVED31		31
+#define SK_PNMI_HRX			(32 + 0)
+#define SK_PNMI_HRX_OCTET		(32 + 1)
+#define SK_PNMI_HRX_OCTETHIGH		(32 + 1)
+#define SK_PNMI_HRX_OCTETLOW		(32 + 2)
+#define SK_PNMI_HRX_BROADCAST		(32 + 3)
+#define SK_PNMI_HRX_MULTICAST		(32 + 4)
+#define SK_PNMI_HRX_UNICAST		(32 + 5)
+#define SK_PNMI_HRX_PMACC		(32 + 6)
+#define SK_PNMI_HRX_MACC		(32 + 7)
+#define SK_PNMI_HRX_PMACC_ERR		(32 + 8)
+#define SK_PNMI_HRX_MACC_UNKWN		(32 + 9)
+#define SK_PNMI_HRX_BURST		(32 + 10)
+#define SK_PNMI_HRX_MISSED		(32 + 11)
+#define SK_PNMI_HRX_FRAMING		(32 + 12)
+#define SK_PNMI_HRX_OVERFLOW		(32 + 13)
+#define SK_PNMI_HRX_JABBER		(32 + 14)
+#define SK_PNMI_HRX_CARRIER		(32 + 15)
+#define SK_PNMI_HRX_IRLENGTH		(32 + 16)
+#define SK_PNMI_HRX_SYMBOL		(32 + 17)
+#define SK_PNMI_HRX_SHORTS		(32 + 18)
+#define SK_PNMI_HRX_RUNT		(32 + 19)
+#define SK_PNMI_HRX_TOO_LONG		(32 + 20)
+#define SK_PNMI_HRX_FCS			(32 + 21)
+#define SK_PNMI_HRX_RESERVED22		(32 + 22)
+#define SK_PNMI_HRX_CEXT		(32 + 23)
+#define SK_PNMI_HRX_UTILUNDER		(32 + 24)
+#define SK_PNMI_HRX_UTILOVER		(32 + 25)
+#define SK_PNMI_HRX_64			(32 + 26)
+#define SK_PNMI_HRX_127			(32 + 27)
+#define SK_PNMI_HRX_255			(32 + 28)
+#define SK_PNMI_HRX_511			(32 + 29)
+#define SK_PNMI_HRX_1023		(32 + 30)
+#define SK_PNMI_HRX_MAX			(32 + 31)
+
+#define SK_PNMI_HTX_SYNC		64
+#define SK_PNMI_HTX_SYNC_OCTET		65
+
+#define SK_PNMI_MAX_IDX			(SK_PNMI_CNT_NO)
+
+/*
+ * MAC specific data
+ */
+typedef struct s_PnmiStatAddr {
+	SK_BOOL		GetOffset;	/* TRUE: Call GetStatVal function */
+	SK_U16		Param;		/* XMAC register containing value */
+} SK_PNMI_STATADDR;
+
+
+/*
+ * SK_PNMI_STRUCT_DATA copy offset evaluation macros
+ */
+#define SK_PNMI_OFF(e)		((SK_U32)&(((SK_PNMI_STRUCT_DATA *)0)->e))
+#define SK_PNMI_MAI_OFF(e)	((SK_U32)&(((SK_PNMI_STRUCT_DATA *)0)->e))
+#define SK_PNMI_VPD_OFF(e)	((SK_U32)&(((SK_PNMI_VPD *)0)->e))
+#define SK_PNMI_SEN_OFF(e)	((SK_U32)&(((SK_PNMI_SENSOR *)0)->e))
+#define SK_PNMI_CHK_OFF(e)	((SK_U32)&(((SK_PNMI_CHECKSUM *)0)->e))
+#define SK_PNMI_STA_OFF(e)	((SK_U32)&(((SK_PNMI_STAT *)0)->e))
+#define SK_PNMI_CNF_OFF(e)	((SK_U32)&(((SK_PNMI_CONF *)0)->e))
+#define SK_PNMI_RLM_OFF(e)	((SK_U32)&(((SK_PNMI_RLMT *)0)->e))
+#define SK_PNMI_MON_OFF(e)	((SK_U32)&(((SK_PNMI_RLMT_MONITOR *)0)->e))
+#define SK_PNMI_TRP_OFF(e)	((SK_U32)&(((SK_PNMI_TRAP *)0)->e))
+
+#define SK_PNMI_SET_STAT(b,s,o)	{SK_U32	Val32; char *pVal; \
+					Val32 = (s); \
+					pVal = (char *)(b) + ((SK_U32) \
+						&(((SK_PNMI_STRUCT_DATA *)0)-> \
+						ReturnStatus.ErrorStatus)); \
+					SK_PNMI_STORE_U32(pVal, Val32); \
+					Val32 = (o); \
+					pVal = (char *)(b) + ((SK_U32) \
+						&(((SK_PNMI_STRUCT_DATA *)0)-> \
+						ReturnStatus.ErrorOffset)); \
+					SK_PNMI_STORE_U32(pVal, Val32);}
+
+/*
+ * Time macros
+ */
+#if SK_TICKS_PER_SEC == 100
+#define SK_PNMI_HUNDREDS_SEC(t)	(t)
+#else
+#define SK_PNMI_HUNDREDS_SEC(t)	(((t) * 100) / (SK_TICKS_PER_SEC))
+#endif
+
+/*
+ * Macros to work around alignment problems
+ */
+#ifndef SK_PNMI_STORE_U16
+#define SK_PNMI_STORE_U16(p,v)	{*(char *)(p) = *((char *)&(v)); \
+					*((char *)(p) + 1) = \
+						*(((char *)&(v)) + 1);}
+#endif
+
+#ifndef SK_PNMI_STORE_U32
+#define SK_PNMI_STORE_U32(p,v)	{*(char *)(p) = *((char *)&(v)); \
+					*((char *)(p) + 1) = \
+						*(((char *)&(v)) + 1); \
+					*((char *)(p) + 2) = \
+						*(((char *)&(v)) + 2); \
+					*((char *)(p) + 3) = \
+						*(((char *)&(v)) + 3);}
+#endif
+
+#ifndef SK_PNMI_STORE_U64
+#define SK_PNMI_STORE_U64(p,v)	{*(char *)(p) = *((char *)&(v)); \
+					*((char *)(p) + 1) = \
+						*(((char *)&(v)) + 1); \
+					*((char *)(p) + 2) = \
+						*(((char *)&(v)) + 2); \
+					*((char *)(p) + 3) = \
+						*(((char *)&(v)) + 3); \
+					*((char *)(p) + 4) = \
+						*(((char *)&(v)) + 4); \
+					*((char *)(p) + 5) = \
+						*(((char *)&(v)) + 5); \
+					*((char *)(p) + 6) = \
+						*(((char *)&(v)) + 6); \
+					*((char *)(p) + 7) = \
+						*(((char *)&(v)) + 7);}
+#endif
+
+#ifndef SK_PNMI_READ_U16
+#define SK_PNMI_READ_U16(p,v)	{*((char *)&(v)) = *(char *)(p); \
+					*(((char *)&(v)) + 1) = \
+						*((char *)(p) + 1);}
+#endif
+
+#ifndef SK_PNMI_READ_U32
+#define SK_PNMI_READ_U32(p,v)	{*((char *)&(v)) = *(char *)(p); \
+					*(((char *)&(v)) + 1) = \
+						*((char *)(p) + 1); \
+					*(((char *)&(v)) + 2) = \
+						*((char *)(p) + 2); \
+					*(((char *)&(v)) + 3) = \
+						*((char *)(p) + 3);}
+#endif
+
+#ifndef SK_PNMI_READ_U64
+#define SK_PNMI_READ_U64(p,v)	{*((char *)&(v)) = *(char *)(p); \
+					*(((char *)&(v)) + 1) = \
+						*((char *)(p) + 1); \
+					*(((char *)&(v)) + 2) = \
+						*((char *)(p) + 2); \
+					*(((char *)&(v)) + 3) = \
+						*((char *)(p) + 3); \
+					*(((char *)&(v)) + 4) = \
+						*((char *)(p) + 4); \
+					*(((char *)&(v)) + 5) = \
+						*((char *)(p) + 5); \
+					*(((char *)&(v)) + 6) = \
+						*((char *)(p) + 6); \
+					*(((char *)&(v)) + 7) = \
+						*((char *)(p) + 7);}
+#endif
+
+/*
+ * Macros for Debug
+ */
+#ifdef DEBUG
+
+#define SK_PNMI_CHECKFLAGS(vSt)	{if (pAC->Pnmi.MacUpdatedFlag > 0 || \
+					pAC->Pnmi.RlmtUpdatedFlag > 0 || \
+					pAC->Pnmi.SirqUpdatedFlag > 0) { \
+						SK_DBG_MSG(pAC, \
+						SK_DBGMOD_PNMI, \
+						SK_DBGCAT_CTRL,	\
+						("PNMI: ERR: %s MacUFlag=%d, RlmtUFlag=%d, SirqUFlag=%d\n", \
+						vSt, \
+						pAC->Pnmi.MacUpdatedFlag, \
+						pAC->Pnmi.RlmtUpdatedFlag, \
+						pAC->Pnmi.SirqUpdatedFlag))}}
+
+#else	/* !DEBUG */
+
+#define SK_PNMI_CHECKFLAGS(vSt)	/* Nothing */
+
+#endif	/* !DEBUG */
+
+#endif	/* _SKGEPNM2_H_ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skgepnmi.h linux.14p16/drivers/net/sk98lin/h/skgepnmi.h
--- linux.vanilla/drivers/net/sk98lin/h/skgepnmi.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skgepnmi.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,914 @@
+/*****************************************************************************
+ *
+ * Name:	skgepnmi.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.37 $
+ * Date:	$Date: 1999/09/14 14:25:32 $
+ * Purpose:	Defines for Private Network Management Interface
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgepnmi.h,v $
+ *	Revision 1.37  1999/09/14 14:25:32  rwahl
+ *	Set MDB version for 1000Base-T (sensors, Master/Slave) changes.
+ *	
+ *	Revision 1.36  1999/05/20 09:24:56  cgoos
+ *	Changes for 1000Base-T (sensors, Master/Slave).
+ *	
+ *	Revision 1.35  1999/04/13 15:10:51  mhaveman
+ *	Replaced RLMT macros SK_RLMT_CHECK_xxx again by those of PNMI to
+ *	grant unified interface. But PNMI macros will store the same
+ *	value as RLMT macros.
+ *	
+ *	Revision 1.34  1999/04/13 15:03:49  mhaveman
+ *	-Changed copyright
+ *	-Removed SK_PNMI_RLMT_MODE_CHK_xxx macros. Those of RLMT should be
+ *	 used.
+ *	
+ *	Revision 1.33  1999/03/23 10:41:02  mhaveman
+ *	Changed comments.
+ *	
+ *	Revision 1.32  1999/01/25 15:01:33  mhaveman
+ *	Added support for multiple simultaniously active ports.
+ *	
+ *	Revision 1.31  1999/01/19 10:06:26  mhaveman
+ *	Added new error log message.
+ *	
+ *	Revision 1.30  1999/01/05 10:34:49  mhaveman
+ *	Fixed little error in RlmtChangeEstimate calculation.
+ *	
+ *	Revision 1.29  1999/01/05 09:59:41  mhaveman
+ *	Redesigned port switch average calculation to avoid 64bit
+ *	arithmetic.
+ *	
+ *	Revision 1.28  1998/12/08 10:05:48  mhaveman
+ *	Defined macro SK_PNMI_MIN_STRUCT_SIZE.
+ *	
+ *	Revision 1.27  1998/12/03 14:39:35  mhaveman
+ *	Fixed problem that LSTAT was enumerated wrong.
+ *	
+ *	Revision 1.26  1998/12/03 11:19:51  mhaveman
+ *	Changed contents of errlog message SK_PNMI_ERR016MSG
+ *	
+ *	Revision 1.25  1998/12/01 10:40:04  mhaveman
+ *	Changed size of SensorNumber, ChecksumNumber and RlmtPortNumber in
+ *	SK_PNMI_STRUCT_DATA to be conform with OID definition.
+ *	
+ *	Revision 1.24  1998/11/20 08:09:27  mhaveman
+ *	Added macros to convert between logical, physical port indexes and
+ *	instances.
+ *	
+ *	Revision 1.23  1998/11/10 13:41:13  mhaveman
+ *	Needed to change interface, because NT driver needs a return value
+ *	of needed buffer space on TOO_SHORT errors. Therefore all
+ *	SkPnmiGet/Preset/Set functions now have a pointer to the length
+ *	parameter, where the needed space on error is returned.
+ *	
+ *	Revision 1.22  1998/11/03 12:05:51  mhaveman
+ *	Added pAC parameter to counter macors.
+ *	
+ *	Revision 1.21  1998/11/02 10:47:36  mhaveman
+ *	Added syslog messages for internal errors.
+ *	
+ *	Revision 1.20  1998/10/30 15:49:36  mhaveman
+ *	-Removed unused SK_PNMI_UTILIZATION_BASE and EstOldCnt.
+ *	-Redefined SK_PNMI_CHG_EST_BASE to hundreds of seconds.
+ *	
+ *	Revision 1.19  1998/10/29 15:38:44  mhaveman
+ *	Changed string lengths of PNMI_STRUCT_DATA structure because
+ *	string OIDs are now encoded with leading length ocetet.
+ *	
+ *	Revision 1.18  1998/10/29 08:52:27  mhaveman
+ *	-Added byte to strings in PNMI_STRUCT_DATA structure.
+ *	-Shortened SK_PNMI_RLMT structure to SK_MAX_MACS elements.
+ *	
+ *	Revision 1.17  1998/10/28 08:49:50  mhaveman
+ *	-Changed type of Instance back to SK_U32 because of VPD
+ *	-Changed type from SK_U8 to char of PciBusSpeed, PciBusWidth, PMD,
+ *	 and Connector.
+ *	
+ *	Revision 1.16  1998/10/22 10:42:31  mhaveman
+ *	-Removed (SK_U32) casts for OIDs
+ *	-excluded NDIS OIDs when they are already defined with ifndef _NDIS_
+ *	
+ *	Revision 1.15  1998/10/20 13:56:28  mhaveman
+ *	Headerfile includes now directly other header files to comile correctly.
+ *	
+ *	Revision 1.14  1998/10/20 07:31:09  mhaveman
+ *	Made type changes to unsigned int where possible.
+ *	
+ *	Revision 1.13  1998/10/19 10:53:13  mhaveman
+ *	-Casted OID definitions to SK_U32
+ *	-Renamed RlmtMAC... to RlmtPort...
+ *	-Changed wrong type of VpdEntriesList from SK_U32 to char *
+ *	
+ *	Revision 1.12  1998/10/13 07:42:27  mhaveman
+ *	-Added OIDs OID_SKGE_TRAP_NUMBER and OID_SKGE_ALL_DATA
+ *	-Removed old cvs history entries
+ *	-Renamed MacNumber to PortNumber
+ *	
+ *	Revision 1.11  1998/10/07 10:55:24  mhaveman
+ *	-Added OID_MDB_VERSION. Therefore was a renumbering of the VPD OIDs
+ *	 necessary.
+ *	-Added OID_GEN_ Ids to support the windows driver.
+ *	
+ *	Revision 1.10  1998/09/30 13:41:10  mhaveman
+ *	Renamed some OIDs to reduce usage of 'MAC' which is replaced by 'PORT'.
+ *	
+ *	Revision 1.9  1998/09/04 17:06:17  mhaveman
+ *	-Added SyncCounter as macro.
+ *	-Renamed OID_SKGE_.._NO_DESCR_CTS to OID_SKGE_.._NO_BUF_CTS.
+ *	-Added macros for driver description and version strings.
+ *	
+ *	Revision 1.8  1998/09/04 14:36:52  mhaveman
+ *	Added OIDs and Structure to access value of macro counters which are
+ *	counted by the driver.
+ *	
+ *	Revision 1.7  1998/09/04 11:59:36  mhaveman
+ *	Everything compiles now. Driver Macros for counting still missing.
+ *	
+ ****************************************************************************/
+
+#ifndef _SKGEPNMI_H_
+#define _SKGEPNMI_H_
+
+/*
+ * Include dependencies
+ */
+#include "h/sktypes.h"
+#include "h/skerror.h"
+#include "h/sktimer.h"
+#include "h/ski2c.h"
+#include "h/skaddr.h"
+#include "h/skrlmt.h"
+
+
+/*
+ * Management Database Version
+ */
+#define SK_PNMI_MDB_VERSION		0x00030000	/* 3.0 */
+
+
+/*
+ * Event definitions
+ */
+#define SK_PNMI_EVT_SIRQ_OVERFLOW	1	/* Counter overflow */
+#define SK_PNMI_EVT_SEN_WAR_LOW		2	/* Lower war thres exceeded */
+#define SK_PNMI_EVT_SEN_WAR_UPP		3	/* Upper war thres exceeded */
+#define SK_PNMI_EVT_SEN_ERR_LOW		4	/* Lower err thres exceeded */
+#define SK_PNMI_EVT_SEN_ERR_UPP		5	/* Upper err thres exceeded */
+#define SK_PNMI_EVT_CHG_EST_TIMER	6	/* Timer event for RLMT Chg */
+#define SK_PNMI_EVT_UTILIZATION_TIMER	7	/* Timer event for Utiliza. */
+#define SK_PNMI_EVT_CLEAR_COUNTER	8	/* Clear statistic counters */
+#define SK_PNMI_EVT_XMAC_RESET		9	/* XMAC will be reset */
+
+#define SK_PNMI_EVT_RLMT_PORT_UP	10	/* Port came logically up */
+#define SK_PNMI_EVT_RLMT_PORT_DOWN	11	/* Port went logically down */
+#define SK_PNMI_EVT_RLMT_PORT_SWITCH	12	/* Switched active port */
+#define SK_PNMI_EVT_RLMT_SEGMENTATION	13	/* Two SP root bridges found */
+#define SK_PNMI_EVT_RLMT_ACTIVE_DOWN	14	/* Port went logically down */
+#define SK_PNMI_EVT_RLMT_ACTIVE_UP	15	/* Port came logically up */
+
+/*
+ * Return values
+ */
+#define SK_PNMI_ERR_OK			0
+#define SK_PNMI_ERR_GENERAL		1
+#define SK_PNMI_ERR_TOO_SHORT		2
+#define SK_PNMI_ERR_BAD_VALUE		3
+#define SK_PNMI_ERR_READ_ONLY		4
+#define SK_PNMI_ERR_UNKNOWN_OID		5
+#define SK_PNMI_ERR_UNKNOWN_INST	6
+
+
+/*
+ * Return values of driver reset function SK_DRIVER_RESET() and
+ * driver event function SK_DRIVER_EVENT()
+ */
+#define SK_PNMI_ERR_OK			0
+#define SK_PNMI_ERR_FAIL		1
+
+
+/*
+ * Return values of driver test function SK_DRIVER_SELFTEST()
+ */
+#define SK_PNMI_TST_UNKNOWN		(1 << 0)
+#define SK_PNMI_TST_TRANCEIVER		(1 << 1)
+#define SK_PNMI_TST_ASIC		(1 << 2)
+#define SK_PNMI_TST_SENSOR		(1 << 3)
+#define SK_PNMI_TST_POWERMGMT		(1 << 4)
+#define SK_PNMI_TST_PCI			(1 << 5)
+#define SK_PNMI_TST_MAC			(1 << 6)
+
+
+/*
+ * RLMT specific definitions
+ */
+#define SK_PNMI_RLMT_STATUS_STANDBY	1
+#define SK_PNMI_RLMT_STATUS_ACTIVE	2
+#define SK_PNMI_RLMT_STATUS_ERROR	3
+
+#define SK_PNMI_RLMT_LSTAT_PHY_DOWN	1
+#define SK_PNMI_RLMT_LSTAT_AUTONEG	2
+#define SK_PNMI_RLMT_LSTAT_LOG_DOWN	3
+#define SK_PNMI_RLMT_LSTAT_LOG_UP	4
+#define SK_PNMI_RLMT_LSTAT_INDETERMINATED 5
+
+#define SK_PNMI_RLMT_MODE_CHK_LINK	(SK_RLMT_CHECK_LINK)
+#define SK_PNMI_RLMT_MODE_CHK_RX	(SK_RLMT_CHECK_LOC_LINK)
+#define SK_PNMI_RLMT_MODE_CHK_SPT	(SK_RLMT_CHECK_SEG)
+/* #define SK_PNMI_RLMT_MODE_CHK_EX */
+
+/*
+ * OID definition
+ */
+#ifndef _NDIS_	/* Check, whether NDIS already included OIDs */
+
+#define OID_GEN_XMIT_OK			0x00020101
+#define OID_GEN_RCV_OK			0x00020102
+#define OID_GEN_XMIT_ERROR		0x00020103
+#define OID_GEN_RCV_ERROR		0x00020104
+#define OID_GEN_RCV_NO_BUFFER		0x00020105
+
+/* #define OID_GEN_DIRECTED_BYTES_XMIT	0x00020201 */
+#define OID_GEN_DIRECTED_FRAMES_XMIT	0x00020202
+/* #define OID_GEN_MULTICAST_BYTES_XMIT	0x00020203 */
+#define OID_GEN_MULTICAST_FRAMES_XMIT	0x00020204
+/* #define OID_GEN_BROADCAST_BYTES_XMIT	0x00020205 */
+#define OID_GEN_BROADCAST_FRAMES_XMIT	0x00020206
+/* #define OID_GEN_DIRECTED_BYTES_RCV	0x00020207 */
+#define OID_GEN_DIRECTED_FRAMES_RCV	0x00020208
+/* #define OID_GEN_MULTICAST_BYTES_RCV	0x00020209 */
+#define OID_GEN_MULTICAST_FRAMES_RCV	0x0002020A
+/* #define OID_GEN_BROADCAST_BYTES_RCV	0x0002020B */
+#define OID_GEN_BROADCAST_FRAMES_RCV	0x0002020C
+#define OID_GEN_RCV_CRC_ERROR		0x0002020D
+#define OID_GEN_TRANSMIT_QUEUE_LENGTH	0x0002020E
+
+#define OID_802_3_PERMANENT_ADDRESS	0x01010101
+#define OID_802_3_CURRENT_ADDRESS	0x01010102
+/* #define OID_802_3_MULTICAST_LIST	0x01010103 */
+/* #define OID_802_3_MAXIMUM_LIST_SIZE	0x01010104 */
+/* #define OID_802_3_MAC_OPTIONS	0x01010105 */
+			
+#define OID_802_3_RCV_ERROR_ALIGNMENT	0x01020101
+#define OID_802_3_XMIT_ONE_COLLISION	0x01020102
+#define OID_802_3_XMIT_MORE_COLLISIONS	0x01020103
+#define OID_802_3_XMIT_DEFERRED		0x01020201
+#define OID_802_3_XMIT_MAX_COLLISIONS	0x01020202
+#define OID_802_3_RCV_OVERRUN		0x01020203
+#define OID_802_3_XMIT_UNDERRUN		0x01020204
+#define OID_802_3_XMIT_TIMES_CRS_LOST	0x01020206
+#define OID_802_3_XMIT_LATE_COLLISIONS	0x01020207
+
+#endif /* _NDIS_ */
+
+#define OID_SKGE_MDB_VERSION		0xFF010100
+#define OID_SKGE_SUPPORTED_LIST		0xFF010101
+#define OID_SKGE_VPD_FREE_BYTES		0xFF010102
+#define OID_SKGE_VPD_ENTRIES_LIST	0xFF010103
+#define OID_SKGE_VPD_ENTRIES_NUMBER	0xFF010104
+#define OID_SKGE_VPD_KEY		0xFF010105
+#define OID_SKGE_VPD_VALUE		0xFF010106
+#define OID_SKGE_VPD_ACCESS		0xFF010107
+#define OID_SKGE_VPD_ACTION		0xFF010108
+			
+#define OID_SKGE_PORT_NUMBER		0xFF010110
+#define OID_SKGE_DEVICE_TYPE		0xFF010111
+#define OID_SKGE_DRIVER_DESCR		0xFF010112
+#define OID_SKGE_DRIVER_VERSION		0xFF010113
+#define OID_SKGE_HW_DESCR		0xFF010114
+#define OID_SKGE_HW_VERSION		0xFF010115
+#define OID_SKGE_CHIPSET		0xFF010116
+#define OID_SKGE_ACTION			0xFF010117
+#define OID_SKGE_RESULT			0xFF010118
+#define OID_SKGE_BUS_TYPE		0xFF010119
+#define OID_SKGE_BUS_SPEED		0xFF01011A
+#define OID_SKGE_BUS_WIDTH		0xFF01011B
+
+/*#define OID_SKGE_MULTICAST_LIST		0xFF01011C*/
+
+#define OID_SKGE_SENSOR_NUMBER		0xFF020100			
+#define OID_SKGE_SENSOR_INDEX		0xFF020101
+#define OID_SKGE_SENSOR_DESCR		0xFF020102
+#define OID_SKGE_SENSOR_TYPE		0xFF020103
+#define OID_SKGE_SENSOR_VALUE		0xFF020104
+#define OID_SKGE_SENSOR_WAR_THRES_LOW	0xFF020105
+#define OID_SKGE_SENSOR_WAR_THRES_UPP	0xFF020106
+#define OID_SKGE_SENSOR_ERR_THRES_LOW	0xFF020107
+#define OID_SKGE_SENSOR_ERR_THRES_UPP	0xFF020108
+#define OID_SKGE_SENSOR_STATUS		0xFF020109
+#define OID_SKGE_SENSOR_WAR_CTS		0xFF02010A
+#define OID_SKGE_SENSOR_ERR_CTS		0xFF02010B
+#define OID_SKGE_SENSOR_WAR_TIME	0xFF02010C
+#define OID_SKGE_SENSOR_ERR_TIME	0xFF02010D
+
+#define OID_SKGE_CHKSM_NUMBER		0xFF020110
+#define OID_SKGE_CHKSM_RX_OK_CTS	0xFF020111
+#define OID_SKGE_CHKSM_RX_UNABLE_CTS	0xFF020112
+#define OID_SKGE_CHKSM_RX_ERR_CTS	0xFF020113
+#define OID_SKGE_CHKSM_TX_OK_CTS	0xFF020114
+#define OID_SKGE_CHKSM_TX_UNABLE_CTS	0xFF020115
+			
+#define OID_SKGE_STAT_TX		0xFF020120
+#define OID_SKGE_STAT_TX_OCTETS		0xFF020121
+#define OID_SKGE_STAT_TX_BROADCAST	0xFF020122
+#define OID_SKGE_STAT_TX_MULTICAST	0xFF020123
+#define OID_SKGE_STAT_TX_UNICAST	0xFF020124
+#define OID_SKGE_STAT_TX_LONGFRAMES	0xFF020125
+#define OID_SKGE_STAT_TX_BURST		0xFF020126
+#define OID_SKGE_STAT_TX_PFLOWC		0xFF020127
+#define OID_SKGE_STAT_TX_FLOWC		0xFF020128
+#define OID_SKGE_STAT_TX_SINGLE_COL	0xFF020129
+#define OID_SKGE_STAT_TX_MULTI_COL	0xFF02012A
+#define OID_SKGE_STAT_TX_EXCESS_COL	0xFF02012B
+#define OID_SKGE_STAT_TX_LATE_COL	0xFF02012C
+#define OID_SKGE_STAT_TX_DEFFERAL	0xFF02012D
+#define OID_SKGE_STAT_TX_EXCESS_DEF	0xFF02012E
+#define OID_SKGE_STAT_TX_UNDERRUN	0xFF02012F
+#define OID_SKGE_STAT_TX_CARRIER	0xFF020130
+/* #define OID_SKGE_STAT_TX_UTIL		0xFF020131 */
+#define OID_SKGE_STAT_TX_64		0xFF020132
+#define OID_SKGE_STAT_TX_127		0xFF020133
+#define OID_SKGE_STAT_TX_255		0xFF020134
+#define OID_SKGE_STAT_TX_511		0xFF020135
+#define OID_SKGE_STAT_TX_1023		0xFF020136
+#define OID_SKGE_STAT_TX_MAX		0xFF020137
+#define OID_SKGE_STAT_TX_SYNC		0xFF020138
+#define OID_SKGE_STAT_TX_SYNC_OCTETS	0xFF020139
+#define OID_SKGE_STAT_RX		0xFF02013A
+#define OID_SKGE_STAT_RX_OCTETS		0xFF02013B
+#define OID_SKGE_STAT_RX_BROADCAST	0xFF02013C
+#define OID_SKGE_STAT_RX_MULTICAST	0xFF02013D
+#define OID_SKGE_STAT_RX_UNICAST	0xFF02013E
+#define OID_SKGE_STAT_RX_PFLOWC		0xFF02013F
+#define OID_SKGE_STAT_RX_FLOWC		0xFF020140
+#define OID_SKGE_STAT_RX_PFLOWC_ERR	0xFF020141
+#define OID_SKGE_STAT_RX_FLOWC_UNKWN	0xFF020142
+#define OID_SKGE_STAT_RX_BURST		0xFF020143
+#define OID_SKGE_STAT_RX_MISSED		0xFF020144
+#define OID_SKGE_STAT_RX_FRAMING	0xFF020145
+#define OID_SKGE_STAT_RX_OVERFLOW	0xFF020146
+#define OID_SKGE_STAT_RX_JABBER		0xFF020147
+#define OID_SKGE_STAT_RX_CARRIER	0xFF020148
+#define OID_SKGE_STAT_RX_IR_LENGTH	0xFF020149
+#define OID_SKGE_STAT_RX_SYMBOL		0xFF02014A
+#define OID_SKGE_STAT_RX_SHORTS		0xFF02014B
+#define OID_SKGE_STAT_RX_RUNT		0xFF02014C
+#define OID_SKGE_STAT_RX_CEXT		0xFF02014D
+#define OID_SKGE_STAT_RX_TOO_LONG	0xFF02014E
+#define OID_SKGE_STAT_RX_FCS		0xFF02014F
+/* #define OID_SKGE_STAT_RX_UTIL		0xFF020150 */
+#define OID_SKGE_STAT_RX_64		0xFF020151
+#define OID_SKGE_STAT_RX_127		0xFF020152
+#define OID_SKGE_STAT_RX_255		0xFF020153
+#define OID_SKGE_STAT_RX_511		0xFF020154
+#define OID_SKGE_STAT_RX_1023		0xFF020155
+#define OID_SKGE_STAT_RX_MAX		0xFF020156
+			
+#define OID_SKGE_PHYS_CUR_ADDR		0xFF010120
+#define OID_SKGE_PHYS_FAC_ADDR		0xFF010121
+#define OID_SKGE_PMD			0xFF010122
+#define OID_SKGE_CONNECTOR		0xFF010123
+#define OID_SKGE_LINK_CAP		0xFF010124
+#define OID_SKGE_LINK_MODE		0xFF010125
+#define OID_SKGE_LINK_MODE_STATUS	0xFF010126
+#define OID_SKGE_LINK_STATUS		0xFF010127
+#define OID_SKGE_FLOWCTRL_CAP		0xFF010128
+#define OID_SKGE_FLOWCTRL_MODE		0xFF010129
+#define OID_SKGE_FLOWCTRL_STATUS	0xFF01012A
+#define OID_SKGE_PHY_OPERATION_CAP	0xFF01012B
+#define OID_SKGE_PHY_OPERATION_MODE	0xFF01012C
+#define OID_SKGE_PHY_OPERATION_STATUS	0xFF01012D
+			
+#define OID_SKGE_TRAP			0xFF010130
+#define OID_SKGE_TRAP_NUMBER		0xFF010131
+
+#define OID_SKGE_RLMT_MODE		0xFF010140
+#define OID_SKGE_RLMT_PORT_NUMBER	0xFF010141
+#define OID_SKGE_RLMT_PORT_ACTIVE	0xFF010142
+#define OID_SKGE_RLMT_PORT_PREFERED	0xFF010143
+#define OID_SKGE_RLMT_CHANGE_CTS	0xFF020160
+#define OID_SKGE_RLMT_CHANGE_TIME	0xFF020161
+#define OID_SKGE_RLMT_CHANGE_ESTIM	0xFF020162
+#define OID_SKGE_RLMT_CHANGE_THRES	0xFF020163
+			
+#define OID_SKGE_RLMT_PORT_INDEX	0xFF020164
+#define OID_SKGE_RLMT_STATUS		0xFF020165
+#define OID_SKGE_RLMT_TX_HELLO_CTS	0xFF020166
+#define OID_SKGE_RLMT_RX_HELLO_CTS	0xFF020167
+#define OID_SKGE_RLMT_TX_SP_REQ_CTS	0xFF020168
+#define OID_SKGE_RLMT_RX_SP_CTS		0xFF020169
+
+#define OID_SKGE_RLMT_MONITOR_NUMBER	0xFF010150			
+#define OID_SKGE_RLMT_MONITOR_INDEX	0xFF010151
+#define OID_SKGE_RLMT_MONITOR_ADDR	0xFF010152
+#define OID_SKGE_RLMT_MONITOR_ERRS	0xFF010153
+#define OID_SKGE_RLMT_MONITOR_TIMESTAMP	0xFF010154
+#define OID_SKGE_RLMT_MONITOR_ADMIN	0xFF010155
+
+#define OID_SKGE_TX_SW_QUEUE_LEN	0xFF020170
+#define OID_SKGE_TX_SW_QUEUE_MAX	0xFF020171
+#define OID_SKGE_TX_RETRY		0xFF020172
+#define OID_SKGE_RX_INTR_CTS		0xFF020173
+#define OID_SKGE_TX_INTR_CTS		0xFF020174
+#define OID_SKGE_RX_NO_BUF_CTS		0xFF020175
+#define OID_SKGE_TX_NO_BUF_CTS		0xFF020176
+#define OID_SKGE_TX_USED_DESCR_NO	0xFF020177
+#define OID_SKGE_RX_DELIVERED_CTS	0xFF020178
+#define OID_SKGE_RX_OCTETS_DELIV_CTS	0xFF020179
+#define OID_SKGE_RX_HW_ERROR_CTS	0xFF02017A
+#define OID_SKGE_TX_HW_ERROR_CTS	0xFF02017B
+#define OID_SKGE_IN_ERRORS_CTS		0xFF02017C
+#define OID_SKGE_OUT_ERROR_CTS		0xFF02017D
+#define OID_SKGE_ERR_RECOVERY_CTS	0xFF02017E
+#define OID_SKGE_SYSUPTIME		0xFF02017F
+
+#define OID_SKGE_ALL_DATA		0xFF020190			
+
+
+#define	OID_SKGE_TRAP_SEN_WAR_LOW	500
+#define OID_SKGE_TRAP_SEN_WAR_UPP	501
+#define	OID_SKGE_TRAP_SEN_ERR_LOW	502
+#define OID_SKGE_TRAP_SEN_ERR_UPP	503
+#define OID_SKGE_TRAP_RLMT_CHANGE_THRES	520
+#define OID_SKGE_TRAP_RLMT_CHANGE_PORT	521
+#define OID_SKGE_TRAP_RLMT_PORT_DOWN	522
+#define OID_SKGE_TRAP_RLMT_PORT_UP	523
+#define OID_SKGE_TRAP_RLMT_SEGMENTATION	524
+
+
+/*
+ * Define error numbers and messages for syslog
+ */
+#define SK_PNMI_ERR001		(SK_ERRBASE_PNMI + 1)
+#define SK_PNMI_ERR001MSG	"SkPnmiGetStruct: Unknown OID"
+#define SK_PNMI_ERR002		(SK_ERRBASE_PNMI + 2)
+#define SK_PNMI_ERR002MSG	"SkPnmiGetStruct: Cannot read VPD keys"
+#define SK_PNMI_ERR003		(SK_ERRBASE_PNMI + 3)
+#define SK_PNMI_ERR003MSG	"OidStruct: Called with wrong OID"
+#define SK_PNMI_ERR004		(SK_ERRBASE_PNMI + 4)
+#define SK_PNMI_ERR004MSG	"OidStruct: Called with wrong action"
+#define SK_PNMI_ERR005		(SK_ERRBASE_PNMI + 5)
+#define SK_PNMI_ERR005MSG	"Perform: Cannot reset driver"
+#define SK_PNMI_ERR006		(SK_ERRBASE_PNMI + 6)
+#define SK_PNMI_ERR006MSG	"Perform: Unknown OID action command"
+#define SK_PNMI_ERR007		(SK_ERRBASE_PNMI + 7)
+#define SK_PNMI_ERR007MSG	"General: Driver description not initialized"
+#define SK_PNMI_ERR008		(SK_ERRBASE_PNMI + 8)
+#define SK_PNMI_ERR008MSG	"Addr: Tried to get unknown OID"
+#define SK_PNMI_ERR009		(SK_ERRBASE_PNMI + 9)
+#define SK_PNMI_ERR009MSG	"Addr: Unknown OID"
+#define SK_PNMI_ERR010		(SK_ERRBASE_PNMI + 10)
+#define SK_PNMI_ERR010MSG	"CsumStat: Unknown OID"
+#define SK_PNMI_ERR011		(SK_ERRBASE_PNMI + 11)
+#define SK_PNMI_ERR011MSG	"SensorStat: Sensor descr string too long"
+#define SK_PNMI_ERR012		(SK_ERRBASE_PNMI + 12)
+#define SK_PNMI_ERR012MSG	"SensorStat: Unknown OID"
+#define SK_PNMI_ERR013		(SK_ERRBASE_PNMI + 13)
+#define SK_PNMI_ERR013MSG	"SensorStat: Unknown OID should be errored before"
+#define SK_PNMI_ERR014		(SK_ERRBASE_PNMI + 14)
+#define SK_PNMI_ERR014MSG	"Vpd: Cannot read VPD keys"
+#define SK_PNMI_ERR015		(SK_ERRBASE_PNMI + 15)
+#define SK_PNMI_ERR015MSG	"Vpd: Internal array for VPD keys to small"
+#define SK_PNMI_ERR016		(SK_ERRBASE_PNMI + 16)
+#define SK_PNMI_ERR016MSG	"Vpd: Key string too long"
+#define SK_PNMI_ERR017		(SK_ERRBASE_PNMI + 17)
+#define SK_PNMI_ERR017MSG	"Vpd: Invalid VPD status pointer"
+#define SK_PNMI_ERR018		(SK_ERRBASE_PNMI + 18)
+#define SK_PNMI_ERR018MSG	"Vpd: VPD data not valid"
+#define SK_PNMI_ERR019		(SK_ERRBASE_PNMI + 19)
+#define SK_PNMI_ERR019MSG	"Vpd: VPD entries list string too long"
+#define SK_PNMI_ERR021		(SK_ERRBASE_PNMI + 21)
+#define SK_PNMI_ERR021MSG	"Vpd: VPD data string too long"
+#define SK_PNMI_ERR022		(SK_ERRBASE_PNMI + 22)
+#define SK_PNMI_ERR022MSG	"Vpd: VPD data string too long should be errored before"
+#define SK_PNMI_ERR023		(SK_ERRBASE_PNMI + 23)
+#define SK_PNMI_ERR023MSG	"Vpd: Unknown OID in get action"
+#define SK_PNMI_ERR024		(SK_ERRBASE_PNMI + 24)
+#define SK_PNMI_ERR024MSG	"Vpd: Unknown OID in preset/set action"
+#define SK_PNMI_ERR025		(SK_ERRBASE_PNMI + 25)
+#define SK_PNMI_ERR025MSG	"Vpd: Cannot write VPD after modify entry"
+#define SK_PNMI_ERR026		(SK_ERRBASE_PNMI + 26)
+#define SK_PNMI_ERR026MSG	"Vpd: Cannot update VPD"
+#define SK_PNMI_ERR027		(SK_ERRBASE_PNMI + 27)
+#define SK_PNMI_ERR027MSG	"Vpd: Cannot delete VPD entry"
+#define SK_PNMI_ERR028		(SK_ERRBASE_PNMI + 28)
+#define SK_PNMI_ERR028MSG	"Vpd: Cannot update VPD after delete entry"
+#define SK_PNMI_ERR029		(SK_ERRBASE_PNMI + 29)
+#define SK_PNMI_ERR029MSG	"General: Driver description string too long"
+#define SK_PNMI_ERR030		(SK_ERRBASE_PNMI + 30)
+#define SK_PNMI_ERR030MSG	"General: Driver version not initialized"
+#define SK_PNMI_ERR031		(SK_ERRBASE_PNMI + 31)
+#define SK_PNMI_ERR031MSG	"General: Driver version string too long"
+#define SK_PNMI_ERR032		(SK_ERRBASE_PNMI + 32)
+#define SK_PNMI_ERR032MSG	"General: Cannot read VPD Name for HW descr"
+#define SK_PNMI_ERR033		(SK_ERRBASE_PNMI + 33)
+#define SK_PNMI_ERR033MSG	"General: HW description string too long"
+#define SK_PNMI_ERR034		(SK_ERRBASE_PNMI + 34)
+#define SK_PNMI_ERR034MSG	"General: Unknown OID"
+#define SK_PNMI_ERR035		(SK_ERRBASE_PNMI + 35)
+#define SK_PNMI_ERR035MSG	"Rlmt: Unknown OID"
+#define SK_PNMI_ERR036		(SK_ERRBASE_PNMI + 36)
+#define SK_PNMI_ERR036MSG	"Rlmt: Unknown OID should be errored before"
+#define SK_PNMI_ERR037		(SK_ERRBASE_PNMI + 37)
+#define SK_PNMI_ERR037MSG	"Rlmt: SK_RLMT_MODE_CHANGE event return not 0"
+#define SK_PNMI_ERR038		(SK_ERRBASE_PNMI + 38)
+#define SK_PNMI_ERR038MSG	"Rlmt: SK_RLMT_PREFPORT_CHANGE event return not 0"
+#define SK_PNMI_ERR039		(SK_ERRBASE_PNMI + 39)
+#define SK_PNMI_ERR039MSG	"RlmtStat: Unknown OID"
+#define SK_PNMI_ERR040		(SK_ERRBASE_PNMI + 40)
+#define SK_PNMI_ERR040MSG	"RlmtStat: Unknown OID should be errored before"
+#define SK_PNMI_ERR041		(SK_ERRBASE_PNMI + 41)
+#define SK_PNMI_ERR041MSG	"MacPrivateConf: Unknown OID"
+#define SK_PNMI_ERR042		(SK_ERRBASE_PNMI + 42)
+#define SK_PNMI_ERR042MSG	"MacPrivateConf: Unknown OID should be errored before"
+#define SK_PNMI_ERR043		(SK_ERRBASE_PNMI + 43)
+#define SK_PNMI_ERR043MSG	"MacPrivateConf: SK_HWEV_SET_LMODE returned not 0"
+#define SK_PNMI_ERR044		(SK_ERRBASE_PNMI + 44)
+#define SK_PNMI_ERR044MSG	"MacPrivateConf: SK_HWEV_SET_FLOWMODE returned not 0"
+#define SK_PNMI_ERR045		(SK_ERRBASE_PNMI + 45)
+#define SK_PNMI_ERR045MSG	"MacPrivateConf: Unknown OID in set action"
+#define SK_PNMI_ERR046		(SK_ERRBASE_PNMI + 46)
+#define SK_PNMI_ERR046MSG	"Monitor: Unknown OID"
+#define SK_PNMI_ERR047		(SK_ERRBASE_PNMI + 47)
+#define SK_PNMI_ERR047MSG	"SirqUpdate: Event function returns not 0"
+#define SK_PNMI_ERR048		(SK_ERRBASE_PNMI + 48)
+#define SK_PNMI_ERR048MSG	"RlmtUpdate: Event function returns not 0"
+#define SK_PNMI_ERR049		(SK_ERRBASE_PNMI + 49)
+#define SK_PNMI_ERR049MSG	""
+#define SK_PNMI_ERR050		(SK_ERRBASE_PNMI + 50)
+#define SK_PNMI_ERR050MSG	"MacUpdate: Cannot update statistic counter"
+#define SK_PNMI_ERR051		(SK_ERRBASE_PNMI + 51)
+#define SK_PNMI_ERR051MSG	"SkPnmiEvent: Port switch suspicious"
+
+/*
+ * Management counter macros called by the driver
+ */
+#define SK_PNMI_SET_DRIVER_DESCR(pAC,v)	((pAC)->Pnmi.pDriverDescription = \
+	(char *)(v))
+
+#define SK_PNMI_SET_DRIVER_VER(pAC,v)	((pAC)->Pnmi.pDriverVersion = \
+	(char *)(v))
+
+#define SK_PNMI_CNT_TX_QUEUE_LEN(pAC,v) \
+	{ \
+		(pAC)->Pnmi.TxSwQueueLen = (SK_U64)(v); \
+		if ((pAC)->Pnmi.TxSwQueueLen > (pAC)->Pnmi.TxSwQueueMax) { \
+			(pAC)->Pnmi.TxSwQueueMax = (pAC)->Pnmi.TxSwQueueLen; \
+		} \
+	}
+#define SK_PNMI_CNT_TX_RETRY(pAC)	(((pAC)->Pnmi.TxRetryCts)++)
+#define SK_PNMI_CNT_RX_INTR(pAC)	(((pAC)->Pnmi.RxIntrCts)++)
+#define SK_PNMI_CNT_TX_INTR(pAC)	(((pAC)->Pnmi.TxIntrCts)++)
+#define SK_PNMI_CNT_NO_RX_BUF(pAC)	(((pAC)->Pnmi.RxNoBufCts)++)
+#define SK_PNMI_CNT_NO_TX_BUF(pAC)	(((pAC)->Pnmi.TxNoBufCts)++)
+#define SK_PNMI_CNT_USED_TX_DESCR(pAC,v) \
+	((pAC)->Pnmi.TxUsedDescrNo=(SK_U64)(v));
+#define SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,v) \
+	{ \
+		((pAC)->Pnmi.RxDeliveredCts)++; \
+		(pAC)->Pnmi.RxOctetsDeliveredCts += (SK_U64)(v); \
+	}
+#define SK_PNMI_CNT_ERR_RECOVERY(pAC)	(((pAC)->Pnmi.ErrRecoveryCts)++);
+
+#define SK_PNMI_CNT_SYNC_OCTETS(pAC,p,v) \
+	{ \
+		if (((p) >= 0) && ((p) < SK_MAX_MACS)) { \
+			((pAC)->Pnmi.StatSyncCts[p])++; \
+			(pAC)->Pnmi.StatSyncOctetsCts[p] += (SK_U64)(v); \
+		} \
+	}
+
+/*
+ * Conversion Macros
+ */
+#define SK_PNMI_PORT_INST2LOG(i)	((unsigned int)(i) - 1)
+#define SK_PNMI_PORT_LOG2INST(l)	((unsigned int)(l) + 1)
+#define SK_PNMI_PORT_PHYS2LOG(p)	((unsigned int)(p) + 1)
+#define SK_PNMI_PORT_LOG2PHYS(pAC,l)	((unsigned int)(l) - 1)
+#define SK_PNMI_PORT_PHYS2INST(p)	((unsigned int)(p) + 2)
+#define SK_PNMI_PORT_INST2PHYS(pAC,i)	((unsigned int)(i) - 2)
+
+/*
+ * Structure definition for SkPnmiGetStruct and SkPnmiSetStruct
+ */
+#define SK_PNMI_VPD_ENTRIES		20
+#define SK_PNMI_VPD_DATALEN		128
+#define SK_PNMI_MULTICAST_LISTLEN	64
+#define SK_PNMI_SENSOR_ENTRIES		(SK_MAX_SENSORS)
+#define SK_PNMI_CHECKSUM_ENTRIES	3
+#define SK_PNMI_MAC_ENTRIES		(SK_MAX_MACS + 1)
+#define SK_PNMI_MONITOR_ENTRIES		20
+#define SK_PNMI_TRAP_ENTRIES		10
+#define SK_PNMI_TRAPLEN			128
+#define SK_PNMI_STRINGLEN1		80
+#define SK_PNMI_STRINGLEN2		25
+#define SK_PNMI_TRAP_QUEUE_LEN		512
+
+typedef struct s_PnmiVpd {
+	char			VpdKey[5];
+	char			VpdValue[SK_PNMI_VPD_DATALEN];
+	SK_U8			VpdAccess;
+	SK_U8			VpdAction;
+} SK_PNMI_VPD;
+
+typedef struct s_PnmiSensor {
+	SK_U8			SensorIndex;
+	char			SensorDescr[SK_PNMI_STRINGLEN2];
+	SK_U8			SensorType;
+	SK_U32			SensorValue;
+	SK_U32			SensorWarningThresholdLow;
+	SK_U32			SensorWarningThresholdHigh;
+	SK_U32			SensorErrorThresholdLow;
+	SK_U32			SensorErrorThresholdHigh;
+	SK_U8			SensorStatus;
+	SK_U64			SensorWarningCts;
+	SK_U64			SensorErrorCts;
+	SK_U64			SensorWarningTimestamp;
+	SK_U64			SensorErrorTimestamp;
+} SK_PNMI_SENSOR;
+
+typedef struct s_PnmiChecksum {
+	SK_U64			ChecksumRxOkCts;
+	SK_U64			ChecksumRxUnableCts;
+	SK_U64			ChecksumRxErrCts;
+	SK_U64			ChecksumTxOkCts;
+	SK_U64			ChecksumTxUnableCts;
+} SK_PNMI_CHECKSUM;
+
+typedef struct s_PnmiStat {
+	SK_U64			StatTxOkCts;
+	SK_U64			StatTxOctetsOkCts;
+	SK_U64			StatTxBroadcastOkCts;
+	SK_U64			StatTxMulticastOkCts;
+	SK_U64			StatTxUnicastOkCts;
+	SK_U64			StatTxLongFramesCts;
+	SK_U64			StatTxBurstCts;
+	SK_U64			StatTxPauseMacCtrlCts;
+	SK_U64			StatTxMacCtrlCts;
+	SK_U64			StatTxSingleCollisionCts;
+	SK_U64			StatTxMultipleCollisionCts;
+	SK_U64			StatTxExcessiveCollisionCts;
+	SK_U64			StatTxLateCollisionCts;
+	SK_U64			StatTxDeferralCts;
+	SK_U64			StatTxExcessiveDeferralCts;
+	SK_U64			StatTxFifoUnderrunCts;
+	SK_U64			StatTxCarrierCts;
+	SK_U64			Dummy1; /* StatTxUtilization */
+	SK_U64			StatTx64Cts;
+	SK_U64			StatTx127Cts;
+	SK_U64			StatTx255Cts;
+	SK_U64			StatTx511Cts;
+	SK_U64			StatTx1023Cts;
+	SK_U64			StatTxMaxCts;
+	SK_U64			StatTxSyncCts;
+	SK_U64			StatTxSyncOctetsCts;
+	SK_U64			StatRxOkCts;
+	SK_U64			StatRxOctetsOkCts;
+	SK_U64			StatRxBroadcastOkCts;
+	SK_U64			StatRxMulticastOkCts;
+	SK_U64			StatRxUnicastOkCts;
+	SK_U64			StatRxPauseMacCtrlCts;
+	SK_U64			StatRxMacCtrlCts;
+	SK_U64			StatRxPauseMacCtrlErrorCts;
+	SK_U64			StatRxMacCtrlUnknownCts;
+	SK_U64			StatRxBurstCts;
+	SK_U64			StatRxMissedCts;
+	SK_U64			StatRxFramingCts;
+	SK_U64			StatRxFifoOverflowCts;
+	SK_U64			StatRxJabberCts;
+	SK_U64			StatRxCarrierCts;
+	SK_U64			StatRxIRLengthCts;
+	SK_U64			StatRxSymbolCts;
+	SK_U64			StatRxShortsCts;
+	SK_U64			StatRxRuntCts;
+	SK_U64			StatRxCextCts;
+	SK_U64			StatRxTooLongCts;
+	SK_U64			StatRxFcsCts;
+	SK_U64			Dummy2; /* StatRxUtilization */
+	SK_U64			StatRx64Cts;
+	SK_U64			StatRx127Cts;
+	SK_U64			StatRx255Cts;
+	SK_U64			StatRx511Cts;
+	SK_U64			StatRx1023Cts;
+	SK_U64			StatRxMaxCts;
+} SK_PNMI_STAT;
+
+typedef struct s_PnmiConf {
+	char			ConfMacCurrentAddr[6];
+	char			ConfMacFactoryAddr[6];
+	SK_U8			ConfPMD;
+	SK_U8			ConfConnector;
+	SK_U8			ConfLinkCapability;
+	SK_U8			ConfLinkMode;
+	SK_U8			ConfLinkModeStatus;
+	SK_U8			ConfLinkStatus;
+	SK_U8			ConfFlowCtrlCapability;
+	SK_U8			ConfFlowCtrlMode;
+	SK_U8			ConfFlowCtrlStatus;
+	SK_U8			ConfPhyOperationCapability;
+	SK_U8			ConfPhyOperationMode;
+	SK_U8			ConfPhyOperationStatus;
+} SK_PNMI_CONF;
+
+typedef struct s_PnmiRlmt {
+	SK_U32			RlmtIndex;
+	SK_U32			RlmtStatus;
+	SK_U64			RlmtTxHelloCts;
+	SK_U64			RlmtRxHelloCts;
+	SK_U64			RlmtTxSpHelloReqCts;
+	SK_U64			RlmtRxSpHelloCts;
+} SK_PNMI_RLMT;
+
+typedef struct s_PnmiRlmtMonitor {
+	SK_U32			RlmtMonitorIndex;
+	char			RlmtMonitorAddr[6];
+	SK_U64			RlmtMonitorErrorCts;
+	SK_U64			RlmtMonitorTimestamp;
+	SK_U8			RlmtMonitorAdmin;
+} SK_PNMI_RLMT_MONITOR;
+
+typedef struct s_PnmiRequestStatus {
+	SK_U32			ErrorStatus;
+	SK_U32			ErrorOffset;
+} SK_PNMI_REQUEST_STATUS;
+
+typedef struct s_PnmiStrucData {
+	SK_U32			MgmtDBVersion;
+	SK_PNMI_REQUEST_STATUS	ReturnStatus;
+	SK_U32			VpdFreeBytes;
+	char			VpdEntriesList[SK_PNMI_VPD_DATALEN];
+	SK_U32			VpdEntriesNumber;
+	SK_PNMI_VPD		Vpd[SK_PNMI_VPD_ENTRIES];
+	SK_U32			PortNumber;
+	SK_U32			DeviceType;
+	char			DriverDescr[SK_PNMI_STRINGLEN1];
+	char			DriverVersion[SK_PNMI_STRINGLEN2];
+	char			HwDescr[SK_PNMI_STRINGLEN1];
+	char			HwVersion[SK_PNMI_STRINGLEN2];
+	SK_U16			Chipset;
+	SK_U32			Action;
+	SK_U32			TestResult;
+	SK_U8			BusType;
+	SK_U8			BusSpeed;
+	SK_U8			BusWidth;
+	SK_U8			SensorNumber;
+	SK_PNMI_SENSOR		Sensor[SK_PNMI_SENSOR_ENTRIES];
+	SK_U8			ChecksumNumber;
+	SK_PNMI_CHECKSUM	Checksum[SK_PNMI_CHECKSUM_ENTRIES];
+	SK_PNMI_STAT		Stat[SK_PNMI_MAC_ENTRIES];
+	SK_PNMI_CONF		Conf[SK_PNMI_MAC_ENTRIES];
+	SK_U8			RlmtMode;
+	SK_U32			RlmtPortNumber;
+	SK_U8			RlmtPortActive;
+	SK_U8			RlmtPortPreferred;
+	SK_U64			RlmtChangeCts;
+	SK_U64			RlmtChangeTime;
+	SK_U64			RlmtChangeEstimate;
+	SK_U64			RlmtChangeThreshold;
+	SK_PNMI_RLMT		Rlmt[SK_MAX_MACS];
+	SK_U32			RlmtMonitorNumber;
+	SK_PNMI_RLMT_MONITOR	RlmtMonitor[SK_PNMI_MONITOR_ENTRIES];
+	SK_U32			TrapNumber;
+	SK_U8			Trap[SK_PNMI_TRAP_QUEUE_LEN];
+	SK_U64			TxSwQueueLen;
+	SK_U64			TxSwQueueMax;
+	SK_U64			TxRetryCts;
+	SK_U64			RxIntrCts;
+	SK_U64			TxIntrCts;
+	SK_U64			RxNoBufCts;
+	SK_U64			TxNoBufCts;
+	SK_U64			TxUsedDescrNo;
+	SK_U64			RxDeliveredCts;
+	SK_U64			RxOctetsDeliveredCts;
+	SK_U64			RxHwErrorsCts;
+	SK_U64			TxHwErrorsCts;
+	SK_U64			InErrorsCts;
+	SK_U64			OutErrorsCts;
+	SK_U64			ErrRecoveryCts;
+	SK_U64			SysUpTime;
+} SK_PNMI_STRUCT_DATA;
+
+#define SK_PNMI_STRUCT_SIZE	(sizeof(SK_PNMI_STRUCT_DATA))
+#define SK_PNMI_MIN_STRUCT_SIZE	((unsigned int)&(((SK_PNMI_STRUCT_DATA *)0)->\
+					VpdFreeBytes))	/*
+							 * ReturnStatus field
+							 * must be located
+							 * before VpdFreeBytes
+							 */
+
+/*
+ * Various definitions
+ */
+#define SK_PNMI_MAX_PROTOS		3
+
+#define SK_PNMI_SCNT_NOT		64
+#define SK_PNMI_CNT_NO			66
+
+/*
+ * Estimate data structure
+ */
+typedef struct s_PnmiEstimate {
+	unsigned int		EstValueIndex;
+	SK_U64			EstValue[7];
+	SK_U64			Estimate;
+	SK_TIMER		EstTimer;
+} SK_PNMI_ESTIMATE;
+
+
+/*
+ * PNMI specific adatper context structure
+ */
+typedef struct s_PnmiPort {
+	SK_U32			CounterHigh[SK_PNMI_SCNT_NOT];
+	SK_U64			CounterOffset[SK_PNMI_CNT_NO];
+	SK_U64			StatSyncCts;
+	SK_U64			StatSyncOctetsCts;
+	SK_BOOL			ActiveFlag;
+} SK_PNMI_PORT;
+
+typedef struct s_PnmiData {
+	SK_PNMI_PORT		Port[SK_MAX_MACS];
+	SK_U64			VirtualCounterOffset[SK_PNMI_CNT_NO];
+	SK_U32			TestResult;
+	char			HwVersion[10];
+
+	char			*pDriverDescription;
+	char			*pDriverVersion;
+
+	char			TrapBuf[SK_PNMI_TRAP_QUEUE_LEN];
+	unsigned int		TrapBufFree;
+	unsigned int		TrapQueueBeg;
+	unsigned int		TrapQueueEnd;
+	unsigned int		TrapBufPad;
+	unsigned int		TrapUnique;
+
+	int			MacUpdatedFlag;
+	int			RlmtUpdatedFlag;
+	int			SirqUpdatedFlag;
+
+	SK_U64			RlmtChangeCts;
+	SK_U64			RlmtChangeTime;
+	SK_PNMI_ESTIMATE	RlmtChangeEstimate;
+	SK_U64			RlmtChangeThreshold;
+
+	SK_U32			DeviceType;
+	char			PciBusSpeed;
+	char			PciBusWidth;
+	char			PMD;
+	char			Connector;
+
+	SK_U64			TxSwQueueLen;
+	SK_U64			TxSwQueueMax;
+	SK_U64			TxRetryCts;
+	SK_U64			RxIntrCts;
+	SK_U64			TxIntrCts;
+	SK_U64			RxNoBufCts;
+	SK_U64			TxNoBufCts;
+	SK_U64			TxUsedDescrNo;
+	SK_U64			RxDeliveredCts;
+	SK_U64			RxOctetsDeliveredCts;
+	SK_U64			ErrRecoveryCts;
+	SK_U64			StartUpTime;
+} SK_PNMI;
+
+
+/*
+ * Function prototypes
+ */
+extern int SkPnmiInit(SK_AC *pAc, SK_IOC IoC, int level);
+extern int SkPnmiGetVar(SK_AC *pAc, SK_IOC IoC, SK_U32 Id, void* pBuf,
+	unsigned int* pLen, SK_U32 Instance);
+extern int SkPnmiPreSetVar(SK_AC *pAc, SK_IOC IoC, SK_U32 Id,
+	void* pBuf, unsigned int *pLen, SK_U32 Instance);
+extern int SkPnmiSetVar(SK_AC *pAc, SK_IOC IoC, SK_U32 Id, void* pBuf,
+	unsigned int *pLen, SK_U32 Instance);
+extern int SkPnmiGetStruct(SK_AC *pAc, SK_IOC IoC, void* pBuf,
+	unsigned int *pLen);
+extern int SkPnmiPreSetStruct(SK_AC *pAc, SK_IOC IoC, void* pBuf,
+	unsigned int *pLen);
+extern int SkPnmiSetStruct(SK_AC *pAc, SK_IOC IoC, void* pBuf,
+	unsigned int *pLen);
+extern int SkPnmiEvent(SK_AC *pAc, SK_IOC IoC, SK_U32 Event,
+	SK_EVPARA Param);
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skgesirq.h linux.14p16/drivers/net/sk98lin/h/skgesirq.h
--- linux.vanilla/drivers/net/sk98lin/h/skgesirq.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skgesirq.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,161 @@
+/******************************************************************************
+ *
+ * Name:	skgesirq.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.18 $
+ * Date:	$Date: 1999/05/19 07:32:59 $
+ * Purpose:	SK specific Gigabit Ethernet special IRQ functions
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *	$Log: skgesirq.h,v $
+ *	Revision 1.18  1999/05/19 07:32:59  cgoos
+ *	Changes for 1000Base-T.
+ *	
+ *	Revision 1.17  1999/03/12 13:29:31  malthoff
+ *	Move Autonegotiation Error Codes to skgeinit.h.
+ *	
+ *	Revision 1.16  1999/03/08 10:11:28  gklug
+ *	add: AutoNegDone return codes
+ *	
+ *	Revision 1.15  1998/11/18 13:20:53  gklug
+ *	add: different timeouts for active and non-active links
+ *	
+ *	Revision 1.14  1998/11/04 07:18:14  cgoos
+ *	Added prototype for SkXmRxTxEnable.
+ *	
+ *	Revision 1.13  1998/10/21 05:52:23  gklug
+ *	add: parameter DoLoop to InitPhy function
+ *	
+ *	Revision 1.12  1998/10/19 06:45:03  cgoos
+ *	Added prototype for SkXmInitPhy.
+ *	
+ *	Revision 1.11  1998/10/15 14:34:10  gklug
+ *	add: WA_TIME is 500 msec
+ *	
+ *	Revision 1.10  1998/10/14 14:49:41  malthoff
+ *	Remove err log defines E021 and E022. They are
+ *	defined in skgeinit.h now.
+ *
+ *	Revision 1.9  1998/10/14 14:00:39  gklug
+ *	add: eroor logs for init phys
+ *	
+ *	Revision 1.8  1998/10/14 05:44:05  gklug
+ *	add: E020
+ *	
+ *	Revision 1.7  1998/10/02 06:24:58  gklug
+ *	add: error messages
+ *	
+ *	Revision 1.6  1998/10/01 07:54:45  gklug
+ *	add: PNMI debug module
+ *	
+ *	Revision 1.5  1998/09/28 13:36:31  malthoff
+ *	Move the bit definitions for Autonegotiation
+ *	and Flow Control to skgeinit.h.
+ *	
+ *	Revision 1.4  1998/09/15 12:29:34  gklug
+ *	add: error logs
+ *	
+ *	Revision 1.3  1998/09/03 13:54:02  gklug
+ *	add: function prototypes
+ *	
+ *	Revision 1.2  1998/09/03 10:24:36  gklug
+ *	add: Events send by PNMI
+ *	add: parameter definition for Flow Control etc.
+ *	
+ *	Revision 1.1  1998/08/27 11:50:27  gklug
+ *	initial revision
+ *	
+ *
+ ******************************************************************************/
+
+#ifndef _INC_SKGESIRQ_H_
+#define _INC_SKGESIRQ_H_
+
+/*
+ * Define the Event the special IRQ/INI module can handle
+ */
+#define SK_HWEV_WATIM		1	/* Timeout for WA errata #2 XMAC */
+#define SK_HWEV_PORT_START	2	/* Port Start Event by RLMT */
+#define SK_HWEV_PORT_STOP	3	/* Port Stop Event by RLMT */
+#define SK_HWEV_CLEAR_STAT	4	/* Clear Statistics by PNMI */
+#define SK_HWEV_UPDATE_STAT	5	/* Update Statistics by PNMI */
+#define SK_HWEV_SET_LMODE	6	/* Set Link Mode by PNMI */
+#define SK_HWEV_SET_FLOWMODE	7	/* Set Flow Control Mode by PNMI */
+
+#define	SK_WA_ACT_TIME		(5000000L)	/* 5 sec */
+#define	SK_WA_INA_TIME		(100000L)	/* 100 msec */
+
+/*
+ * Define the error numbers and messages
+ */
+#define	SKERR_SIRQ_E001		(SK_ERRBASE_SIRQ+0)
+#define	SKERR_SIRQ_E001MSG	"Unknown event"
+#define	SKERR_SIRQ_E002		(SKERR_SIRQ_E001+1)
+#define	SKERR_SIRQ_E002MSG	"Packet timeout RX1"
+#define	SKERR_SIRQ_E003		(SKERR_SIRQ_E002+1)
+#define	SKERR_SIRQ_E003MSG	"Packet timeout RX2"
+#define	SKERR_SIRQ_E004		(SKERR_SIRQ_E003+1)
+#define	SKERR_SIRQ_E004MSG	"XMAC 1 not correctly initialized"
+#define	SKERR_SIRQ_E005		(SKERR_SIRQ_E004+1)
+#define	SKERR_SIRQ_E005MSG	"XMAC 2 not correctly initialized"
+#define	SKERR_SIRQ_E006		(SKERR_SIRQ_E005+1)
+#define	SKERR_SIRQ_E006MSG	"CHECK failure R1"
+#define	SKERR_SIRQ_E007		(SKERR_SIRQ_E006+1)
+#define	SKERR_SIRQ_E007MSG	"CHECK failure R2"
+#define	SKERR_SIRQ_E008		(SKERR_SIRQ_E007+1)
+#define	SKERR_SIRQ_E008MSG	"CHECK failure XS1"
+#define	SKERR_SIRQ_E009		(SKERR_SIRQ_E008+1)
+#define	SKERR_SIRQ_E009MSG	"CHECK failure XA1"
+#define	SKERR_SIRQ_E010		(SKERR_SIRQ_E009+1)
+#define	SKERR_SIRQ_E010MSG	"CHECK failure XS2"
+#define	SKERR_SIRQ_E011		(SKERR_SIRQ_E010+1)
+#define	SKERR_SIRQ_E011MSG	"CHECK failure XA2"
+#define	SKERR_SIRQ_E012		(SKERR_SIRQ_E011+1)
+#define	SKERR_SIRQ_E012MSG	"unexpected IRQ Master error"
+#define	SKERR_SIRQ_E013		(SKERR_SIRQ_E012+1)
+#define	SKERR_SIRQ_E013MSG	"unexpected IRQ Status error"
+#define	SKERR_SIRQ_E014		(SKERR_SIRQ_E013+1)
+#define	SKERR_SIRQ_E014MSG	"Parity error on RAM (read)"
+#define	SKERR_SIRQ_E015		(SKERR_SIRQ_E014+1)
+#define	SKERR_SIRQ_E015MSG	"Parity error on RAM (write)"
+#define	SKERR_SIRQ_E016		(SKERR_SIRQ_E015+1)
+#define	SKERR_SIRQ_E016MSG	"Parity error MAC 1"
+#define	SKERR_SIRQ_E017		(SKERR_SIRQ_E016+1)
+#define	SKERR_SIRQ_E017MSG	"Parity error MAC 2"
+#define	SKERR_SIRQ_E018		(SKERR_SIRQ_E017+1)
+#define	SKERR_SIRQ_E018MSG	"Parity error RX 1"
+#define	SKERR_SIRQ_E019		(SKERR_SIRQ_E018+1)
+#define	SKERR_SIRQ_E019MSG	"Parity error RX 2"
+#define	SKERR_SIRQ_E020		(SKERR_SIRQ_E019+1)
+#define	SKERR_SIRQ_E020MSG	"XMAC transmit FIFO underrun"
+#define	SKERR_SIRQ_E021		(SKERR_SIRQ_E020+1)
+#define	SKERR_SIRQ_E021MSG	"Spurious I2C interrupt"
+#define	SKERR_SIRQ_E022		(SKERR_SIRQ_E020+1)
+#define	SKERR_SIRQ_E022MSG	"Cable pair swap error"
+
+extern void SkGeSirqIsr(SK_AC *pAC, SK_IOC IoC, SK_U32 Istatus);
+extern int  SkGeSirqEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para);
+extern void SkXmInitPhy( SK_AC *pAC, SK_IOC IoC, int Port, SK_BOOL DoLoop);
+extern int  SkXmRxTxEnable(SK_AC *pAC, SK_IOC IoC, int Port);
+extern void SkHWLinkUp(SK_AC *pAC, SK_IOC IoC, int Port);
+extern void SkHWLinkDown(SK_AC *pAC, SK_IOC IoC, int Port);
+
+#endif	/* _INC_SKGESIRQ_H_ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/ski2c.h linux.14p16/drivers/net/sk98lin/h/ski2c.h
--- linux.vanilla/drivers/net/sk98lin/h/ski2c.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/ski2c.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,263 @@
+/******************************************************************************
+ *
+ * Name:	ski2c.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.27 $
+ * Date:	$Date: 1999/05/20 09:23:10 $
+ * Purpose:	Defines to access Voltage and Temperature Sensor
+ *		(taken from Monalisa (taken from Concentrator))
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: ski2c.h,v $
+ *	Revision 1.27  1999/05/20 09:23:10  cgoos
+ *	Changes for 1000Base-T (Fan sensors).
+ *	
+ *	Revision 1.26  1998/12/01 13:45:47  gklug
+ *	add: InitLevel to I2c struct
+ *	
+ *	Revision 1.25  1998/11/03 06:55:16  gklug
+ *	add: Dummy Reads to I2c struct
+ *	
+ *	Revision 1.24  1998/10/02 14:28:59  cgoos
+ *	Added prototype for SkI2cIsr.
+ *	
+ *	Revision 1.23  1998/09/08 12:20:11  gklug
+ *	add: prototypes for init and read functions
+ *	
+ *	Revision 1.22  1998/09/08 07:37:56  gklug
+ *	add: log error if PCI_IO voltage sensor could not be initialized
+ *	
+ *	Revision 1.21  1998/09/04 08:38:05  malthoff
+ *	Change the values for I2C_READ and I2C_WRITE
+ *	
+ *	Revision 1.20  1998/08/25 07:52:22  gklug
+ *	chg: Timestamps (last) added for logging
+ *
+ *	Revision 1.19  1998/08/25 06:09:00  gklug
+ *	rmv: warning and error levels of the individual sensors.
+ *	add: timing definitions for sending traps and logging errors
+ *	
+ *	Revision 1.18  1998/08/20 11:41:15  gklug
+ *	chg: omit STRCPY macro by using char * as Sensor Description
+ *	
+ *	Revision 1.17  1998/08/20 11:37:43  gklug
+ *	chg: change Ioc to IoC
+ *	
+ *	Revision 1.16  1998/08/20 11:30:38  gklug
+ *	fix: SenRead declaration
+ *	
+ *	Revision 1.15  1998/08/20 11:27:53  gklug
+ *	fix: Compile bugs with new awrning constants
+ *	
+ *	Revision 1.14  1998/08/20 08:53:12  gklug
+ *	fix: compiler errors
+ *	add: Threshold values
+ *	
+ *	Revision 1.13  1998/08/19 12:21:16  gklug
+ *	fix: remove struct from C files (see CCC)
+ *	add: typedefs for all structs
+ *	
+ *	Revision 1.12  1998/08/19 10:57:41  gklug
+ *	add: Warning levels
+ *	
+ *	Revision 1.11  1998/08/18 08:37:02  malthoff
+ *	Prototypes not required for SK_DIAG.
+ *	
+ *	Revision 1.10  1998/08/17 13:54:00  gklug
+ *	fix: declaration of event function
+ *	
+ *	Revision 1.9  1998/08/17 06:48:39  malthoff
+ *	Remove some unrequired macros.
+ *	Fix the compiler errors.
+ *	
+ *	Revision 1.8  1998/08/14 06:47:19  gklug
+ *	fix: Values are intergers
+ *
+ *	Revision 1.7  1998/08/14 06:26:05  gklug
+ *	add: Init error message
+ *
+ *	Revision 1.6  1998/08/13 08:31:08  gklug
+ *	add: Error message
+ *
+ *	Revision 1.5  1998/08/12 14:32:04  gklug
+ *	add: new error code/message
+ *
+ *	Revision 1.4  1998/08/12 13:39:08  gklug
+ *	chg: names of error messages
+ *	add: defines for Sensor type and thresholds
+ *
+ *	Revision 1.3  1998/08/11 07:57:16  gklug
+ *	add: sensor struct
+ *	add: Timeout defines
+ *	add: I2C control struct for pAC
+ *
+ *	Revision 1.2  1998/07/17 11:29:02  gklug
+ *	rmv: Microwire and SMTPANIC
+ *
+ *	Revision 1.1  1998/06/19 14:30:10  malthoff
+ *	Created. Sources taken from ML Project.
+ *
+ *
+ ******************************************************************************/
+
+/*
+ * SKI2C.H	contains all I2C specific defines
+ */
+
+#ifndef _SKI2C_H_
+#define _SKI2C_H_
+
+typedef struct  s_Sensor SK_SENSOR;
+
+#include "h/skgei2c.h"
+
+/*
+ * Define the I2c events.
+ */
+#define SK_I2CEV_IRQ	1	/* IRQ happened Event */
+#define SK_I2CEV_TIM	2	/* Timeout event */
+#define SK_I2CEV_CLEAR	3	/* Clear Mib Values */
+
+/*
+ * Define READ and WRITE Constants.
+ */
+#define	I2C_READ	0
+#define	I2C_WRITE	1
+#define I2C_BURST	1
+#define I2C_SIGLE	0
+
+#define	SKERR_I2C_E001		(SK_ERRBASE_I2C+0)
+#define	SKERR_I2C_E001MSG	"Sensor index unknown"
+#define	SKERR_I2C_E002		(SKERR_I2C_E001+1)
+#define	SKERR_I2C_E002MSG	"I2C: transfer does not complete.\n"
+#define	SKERR_I2C_E003		(SKERR_I2C_E002+1)
+#define	SKERR_I2C_E003MSG	"lm80: NAK on device send.\n"
+#define	SKERR_I2C_E004		(SKERR_I2C_E003+1)
+#define	SKERR_I2C_E004MSG	"lm80: NAK on register send.\n"
+#define	SKERR_I2C_E005		(SKERR_I2C_E004+1)
+#define	SKERR_I2C_E005MSG	"lm80: NAK on device (2) send.\n"
+#define	SKERR_I2C_E006		(SKERR_I2C_E005+1)
+#define	SKERR_I2C_E006MSG	"Unknown event"
+#define	SKERR_I2C_E007		(SKERR_I2C_E006+1)
+#define	SKERR_I2C_E007MSG	"LM80 read out of state"
+#define	SKERR_I2C_E008		(SKERR_I2C_E007+1)
+#define	SKERR_I2C_E008MSG	"unexpected sensor read completed"
+#define	SKERR_I2C_E009		(SKERR_I2C_E008+1)
+#define	SKERR_I2C_E009MSG	"WARNING: temperature sensor out of range"
+#define	SKERR_I2C_E010		(SKERR_I2C_E009+1)
+#define	SKERR_I2C_E010MSG	"WARNING: voltage sensor out of range"
+#define	SKERR_I2C_E011		(SKERR_I2C_E010+1)
+#define	SKERR_I2C_E011MSG	"ERROR: temperature sensor out of range"
+#define	SKERR_I2C_E012		(SKERR_I2C_E011+1)
+#define	SKERR_I2C_E012MSG	"ERROR: voltage sensor out of range"
+#define	SKERR_I2C_E013		(SKERR_I2C_E012+1)
+#define	SKERR_I2C_E013MSG	"ERROR: couldn't init sensor"
+#define	SKERR_I2C_E014		(SKERR_I2C_E013+1)
+#define	SKERR_I2C_E014MSG	"WARNING: fan sensor out of range"
+#define	SKERR_I2C_E015		(SKERR_I2C_E014+1)
+#define	SKERR_I2C_E015MSG	"ERROR: fan sensor out of range"
+
+/*
+ * Define Timeout values
+ */
+#define	SK_I2C_TIM_LONG		2000000L	/* 2 second */
+#define	SK_I2C_TIM_SHORT	100000L		/* 100 milli second */
+
+/*
+ * Define trap and error log hold times
+ */
+#ifndef	SK_SEN_ERR_TR_HOLD
+#define	SK_SEN_ERR_TR_HOLD	(4*SK_TICKS_PER_SEC)
+#endif
+#ifndef	SK_SEN_ERR_LOG_HOLD
+#define	SK_SEN_ERR_LOG_HOLD	(60*SK_TICKS_PER_SEC)
+#endif
+#ifndef	SK_SEN_WARN_TR_HOLD
+#define	SK_SEN_WARN_TR_HOLD	(15*SK_TICKS_PER_SEC)
+#endif
+#ifndef	SK_SEN_WARN_LOG_HOLD
+#define	SK_SEN_WARN_LOG_HOLD	(15*60*SK_TICKS_PER_SEC)
+#endif
+
+/*
+ * Defines for SenType
+ */
+#define	SK_SEN_TEMP	1
+#define	SK_SEN_VOLT	2
+#define	SK_SEN_FAN	3
+
+/*
+ * Define for the ErrorFlag
+ */
+#define	SK_SEN_ERR_OK	1	/* Error Flag: O.K. */
+#define	SK_SEN_ERR_WARN	2	/* Error Flag: Warning */
+#define	SK_SEN_ERR_ERR	3	/* Error Flag: Error */
+
+/*
+ * Define the Sensor struct
+ */
+struct	s_Sensor {
+	char	*SenDesc;	/* Description */
+	int	SenType;	/* Voltage or Temperature */
+	SK_I32	SenValue;	/* Current value of the sensor */
+	SK_I32	SenThreErrHigh;	/* High error Threshhold of this sensor */
+	SK_I32	SenThreWarnHigh;/* High warning Threshhold of this sensor */
+	SK_I32	SenThreErrLow;	/* Lower error Threshold of the sensor */
+	SK_I32	SenThreWarnLow;	/* Lower warning Threshold of the sensor */
+	int	SenErrFlag;	/* Sensor indicated an error */
+	SK_BOOL	SenInit;	/* Is sensor initialized? */
+	SK_U64	SenErrCts;	/* Error  trap counter */
+	SK_U64	SenWarnCts;	/* Warning trap  counter */
+	SK_U64	SenBegErrTS;	/* Begin error timestamp */
+	SK_U64	SenBegWarnTS;	/* Begin warning timestamp */
+	SK_U64	SenLastErrTrapTS;	/* Last error trap timestamp */
+	SK_U64	SenLastErrLogTS;	/* Last error log timestamp */
+	SK_U64	SenLastWarnTrapTS;	/* Last warning trap timestamp */
+	SK_U64	SenLastWarnLogTS;	/* Last warning log timestamp */
+	int	SenState;	/* Sensor State (see HW specific include) */
+	int	(*SenRead)(SK_AC *pAC, SK_IOC IoC,struct s_Sensor *pSen) ;
+				/* Sensors read function */
+	SK_U16	SenReg;		/* Register Address for this sensor */
+	SK_U8	SenDev;		/* DeviceSelection for this sensor */
+} ;
+
+
+typedef	struct	s_I2c {
+	SK_SENSOR	SenTable[SK_MAX_SENSORS];	/* Sensor Table */
+	int		CurrSens;	/* Which sensor is currently queried */
+	int		MaxSens;	/* Max. number of sensors */
+	int		InitLevel;	/* Initialized Level */
+#ifndef SK_DIAG
+	int		DummyReads;	/* Number of non-checked dummy reads */
+	SK_TIMER	SenTimer;	/* Sensors timer */
+#endif	/* !SK_DIAG */
+} SK_I2C;
+
+extern int SkI2cReadSensor(SK_AC *pAC, SK_IOC IoC, SK_SENSOR *pSen);
+#ifndef SK_DIAG
+extern int SkI2cEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event,
+	SK_EVPARA Para);
+extern int SkI2cInit(SK_AC *pAC, SK_IOC IoC, int Level);
+extern void SkI2cIsr(SK_AC *pAC, SK_IOC IoC);
+
+#endif
+#endif	/* n_SKI2C_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skqueue.h linux.14p16/drivers/net/sk98lin/h/skqueue.h
--- linux.vanilla/drivers/net/sk98lin/h/skqueue.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skqueue.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,136 @@
+/******************************************************************************
+ *
+ * Name:	skqueue.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.12 $
+ * Date:	$Date: 1998/09/08 08:48:01 $
+ * Purpose:	Defines for the Event queue
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skqueue.h,v $
+ *	Revision 1.12  1998/09/08 08:48:01  gklug
+ *	add: init level handling
+ *	
+ *	Revision 1.11  1998/09/03 14:15:11  gklug
+ *	add: CSUM and HWAC Eventclass and function.
+ *	fix: pParaPtr according to CCC
+ *	
+ *	Revision 1.10  1998/08/20 12:43:03  gklug
+ *	add: typedef SK_QUEUE
+ *	
+ *	Revision 1.9  1998/08/19 09:50:59  gklug
+ *	fix: remove struct keyword from c-code (see CCC) add typedefs
+ *	
+ *	Revision 1.8  1998/08/18 07:00:01  gklug
+ *	fix: SK_PTR not defined use void * instead.
+ *	
+ *	Revision 1.7  1998/08/17 13:43:19  gklug
+ *	chg: Parameter will be union of 64bit para, 2 times SK_U32 or SK_PTR
+ *	
+ *	Revision 1.6  1998/08/14 07:09:30  gklug
+ *	fix: chg pAc -> pAC
+ *	
+ *	Revision 1.5  1998/08/11 14:26:44  gklug
+ *	chg: Event Dispatcher returns now int.
+ *	
+ *	Revision 1.4  1998/08/11 12:15:21  gklug
+ *	add: Error numbers of skqueue module
+ *	
+ *	Revision 1.3  1998/08/07 12:54:23  gklug
+ *	fix: first compiled version
+ *	
+ *	Revision 1.2  1998/08/07 09:34:00  gklug
+ *	adapt structure defs to CCC
+ *	add: prototypes for functions
+ *	
+ *	Revision 1.1  1998/07/30 14:52:12  gklug
+ *	Initial version.
+ *	Defines Event Classes, Event structs and queue management variables.
+ *	
+ *	
+ *
+ ******************************************************************************/
+
+/*
+ * SKQUEUE.H	contains all defines and types for the event queue
+ */
+
+#ifndef _SKQUEUE_H_
+#define _SKQUEUE_H_
+
+
+/*
+ * define the event classes to be served
+ */
+#define	SKGE_DRV	1	/* Driver Event Class */
+#define	SKGE_RLMT	2	/* RLMT Event Class */
+#define	SKGE_I2C	3	/* i2C Event Class */
+#define	SKGE_PNMI	4	/* PNMI Event Class */
+#define	SKGE_CSUM	5	/* Checksum Event Class */
+#define	SKGE_HWAC	6	/* Hardware Access Event Class */
+
+/*
+ * define event queue as circular buffer
+ */
+#define SK_MAX_EVENT	64
+
+/*
+ * Parameter union for the Para stuff
+ */
+typedef	union u_EvPara {
+	void	*pParaPtr;	/* Parameter Pointer */
+	SK_U64	Para64;		/* Parameter 64bit version */
+	SK_U32	Para32[2];	/* Parameter Array of 32bit parameters */
+} SK_EVPARA;
+
+/*
+ * Event Queue
+ *	skqueue.c
+ * events are class/value pairs
+ *	class	is addressee, e.g. RMT, PCM etc.
+ *	value	is command, e.g. line state change, ring op change etc.
+ */
+typedef	struct s_EventElem {
+	SK_U32		Class ;			/* Event class */
+	SK_U32		Event ;			/* Event value */
+	SK_EVPARA	Para ;			/* Event parameter */
+} SK_EVENTELEM;
+
+typedef	struct s_Queue {
+	SK_EVENTELEM	EvQueue[SK_MAX_EVENT];
+	SK_EVENTELEM	*EvPut ;
+	SK_EVENTELEM	*EvGet ;
+} SK_QUEUE;
+
+extern	void SkEventInit(SK_AC *pAC, SK_IOC Ioc, int Level);
+extern	void SkEventQueue(SK_AC *pAC, SK_U32 Class, SK_U32 Event,
+	SK_EVPARA Para);
+extern	int SkEventDispatcher(SK_AC *pAC,SK_IOC Ioc);
+
+
+/* Define Error Numbers and messages */
+#define	SKERR_Q_E001	(SK_ERRBASE_QUEUE+0)
+#define	SKERR_Q_E001MSG	"Event queue overflow"
+#define	SKERR_Q_E002	(SKERR_Q_E001+1)
+#define	SKERR_Q_E002MSG	"Undefined event class"
+#endif	/* _SKQUEUE_H_ */
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skrlmt.h linux.14p16/drivers/net/sk98lin/h/skrlmt.h
--- linux.vanilla/drivers/net/sk98lin/h/skrlmt.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skrlmt.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,494 @@
+/******************************************************************************
+ *
+ * Name:	skrlmt.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.26 $
+ * Date:	$Date: 1999/10/04 14:01:19 $
+ * Purpose:	Header file for Redundant Link ManagemenT.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skrlmt.h,v $
+ *	Revision 1.26  1999/10/04 14:01:19  rassmann
+ *	Corrected reaction to reception of BPDU frames.
+ *	Added parameter descriptions to "For Readme" section skrlmt.txt.
+ *	Clarified usage of lookahead result *pForRlmt.
+ *	Requested driver to present RLMT packets as soon as poosible.
+ *	
+ *	Revision 1.25  1999/07/20 12:53:39  rassmann
+ *	Fixed documentation errors for lookahead macros.
+ *	
+ *	Revision 1.24  1999/05/28 11:15:56  rassmann
+ *	Changed behaviour to reflect Design Spec v1.2.
+ *	Controlling Link LED(s).
+ *	Introduced RLMT Packet Version field in RLMT Packet.
+ *	Newstyle lookahead macros (checking meta-information before looking at
+ *	  the packet).
+ *	
+ *	Revision 1.23  1999/01/28 12:50:42  rassmann
+ *	Not using broadcast time stamps in CheckLinkState mode.
+ *	
+ *	Revision 1.22  1999/01/27 14:13:04  rassmann
+ *	Monitoring broadcast traffic.
+ *	Switching more reliably and not too early if switch is
+ *	 configured for spanning tree.
+ *	
+ *	Revision 1.21  1998/12/08 13:11:25  rassmann
+ *	Stopping SegTimer at RlmtStop.
+ *	
+ *	Revision 1.20  1998/11/24 12:37:33  rassmann
+ *	Implemented segmentation check.
+ *	
+ *	Revision 1.19  1998/11/17 13:43:06  rassmann
+ *	Handling (logical) tx failure.
+ *	Sending packet on logical address after PORT_SWITCH.
+ *	
+ *	Revision 1.18  1998/11/13 16:56:56  rassmann
+ *	Added macro version of SkRlmtLookaheadPacket.
+ *	
+ *	Revision 1.17  1998/11/06 18:06:05  rassmann
+ *	Corrected timing when RLMT checks fail.
+ *	Clearing tx counter earlier in periodical checks.
+ *	
+ *	Revision 1.16  1998/11/03 13:53:50  rassmann
+ *	RLMT should switch now (at least in mode 3).
+ *	
+ *	Revision 1.15  1998/10/22 11:39:52  rassmann
+ *	Corrected signed/unsigned mismatches.
+ *	Corrected receive list handling and address recognition.
+ *	
+ *	Revision 1.14  1998/10/15 15:16:36  rassmann
+ *	Finished Spanning Tree checking.
+ *	Checked with lint.
+ *	
+ *	Revision 1.13  1998/09/24 19:16:08  rassmann
+ *	Code cleanup.
+ *	Introduced Timer for PORT_DOWN due to no RX.
+ *	
+ *	Revision 1.12  1998/09/16 11:09:52  rassmann
+ *	Syntax corrections.
+ *	
+ *	Revision 1.11  1998/09/15 11:28:50  rassmann
+ *	Syntax corrections.
+ *	
+ *	Revision 1.10  1998/09/14 17:07:38  rassmann
+ *	Added code for port checking via LAN.
+ *	Changed Mbuf definition.
+ *	
+ *	Revision 1.9  1998/09/07 11:14:15  rassmann
+ *	Syntax corrections.
+ *	
+ *	Revision 1.8  1998/09/07 09:06:08  rassmann
+ *	Syntax corrections.
+ *	
+ *	Revision 1.7  1998/09/04 19:41:34  rassmann
+ *	Syntax corrections.
+ *	Started entering code for checking local links.
+ *	
+ *	Revision 1.6  1998/09/04 12:14:28  rassmann
+ *	Interface cleanup.
+ *	
+ *	Revision 1.5  1998/09/02 16:55:29  rassmann
+ *	Updated to reflect new DRV/HWAC/RLMT interface.
+ *	
+ *	Revision 1.4  1998/09/02 07:26:02  afischer
+ *	typedef for SK_RLMT_PORT
+ *
+ *	Revision 1.3  1998/08/27 14:29:03  rassmann
+ *	Code cleanup.
+ *	
+ *	Revision 1.2  1998/08/27 14:26:25  rassmann
+ *	Updated interface.
+ *	
+ *	Revision 1.1  1998/08/21 08:29:10  rassmann
+ *	First public version.
+ *	
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the header file for Redundant Link ManagemenT.
+ *
+ * Include File Hierarchy:
+ *
+ *	"skdrv1st.h"
+ *	...
+ *	"sktypes.h"
+ *	"skqueue.h"
+ *	"skaddr.h"
+ *	"skrlmt.h"
+ *	...
+ *	"skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKRLMT_H
+#define __INC_SKRLMT_H
+
+#ifdef __cplusplus
+xxxx	/* not supported yet - force error */
+extern "C" {
+#endif	/* cplusplus */
+
+/* defines ********************************************************************/
+
+#define	SK_RLMT_NET_DOWN_TEMP	1	/* NET_DOWN due to last port down. */
+#define	SK_RLMT_NET_DOWN_FINAL	2	/* NET_DOWN due to RLMT_STOP. */
+
+/* ----- Default queue sizes - must be multiples of 8 KB ----- */
+
+/* Less than 8 KB free in RX queue => pause frames. */
+#define SK_RLMT_STANDBY_QRXSIZE	128	/* Size of rx standby queue in KB. */
+#define SK_RLMT_STANDBY_QXASIZE	32	/* Size of async standby queue in KB. */
+#define SK_RLMT_STANDBY_QXSSIZE	0	/* Size of sync standby queue in KB. */
+
+#define SK_RLMT_MAX_TX_BUF_SIZE	60	/* Maximum RLMT transmit size. */
+
+/* ----- PORT states ----- */
+
+#define SK_RLMT_PS_INIT		0	/* Port state: Init. */
+#define SK_RLMT_PS_LINK_DOWN	1	/* Port state: Link down. */
+#define SK_RLMT_PS_DOWN		2	/* Port state: Port down. */
+#define SK_RLMT_PS_GOING_UP	3	/* Port state: Going up. */
+#define SK_RLMT_PS_UP		4	/* Port state: Up. */
+
+/* ----- RLMT states ----- */
+
+#define SK_RLMT_RS_INIT		0	/* RLMT state: Init. */
+#define SK_RLMT_RS_NET_DOWN	1	/* RLMT state: Net down. */
+#define SK_RLMT_RS_NET_UP	2	/* RLMT state: Net up. */
+
+/* ----- PORT events ----- */
+
+#define SK_RLMT_LINK_UP		1001	/* Link came up. */
+#define SK_RLMT_LINK_DOWN	1002	/* Link went down. */
+#define SK_RLMT_PORT_ADDR	1003	/* Port address changed. */
+
+/* ----- RLMT events ----- */
+
+#define SK_RLMT_START		2001	/* Start RLMT. */
+#define SK_RLMT_STOP		2002	/* Stop RLMT. */
+#define SK_RLMT_PACKET_RECEIVED	2003	/* Packet was received for RLMT. */
+#define SK_RLMT_STATS_CLEAR	2004	/* Clear statistics. */
+#define SK_RLMT_STATS_UPDATE	2005	/* Update statistics. */
+#define SK_RLMT_PREFPORT_CHANGE	2006	/* Change preferred port. */
+#define SK_RLMT_MODE_CHANGE	2007	/* New RlmtMode. */
+
+/* ----- RLMT mode bits ----- */
+
+#define SK_RLMT_CHECK_LINK	1	/* Check Link. */
+#define SK_RLMT_CHECK_LOC_LINK	2	/* Check other link on same adapter. */
+#define SK_RLMT_CHECK_SEG	4	/* Check segmentation. */
+
+#ifndef RLMT_CHECK_REMOTE
+#define SK_RLMT_CHECK_OTHERS	SK_RLMT_CHECK_LOC_LINK
+#else	/* RLMT_CHECK_REMOTE */
+#define SK_RLMT_CHECK_REM_LINK	8	/* Check link(s) on other adapter(s). */
+#define SK_RLMT_MAX_REMOTE_PORTS_CHECKED	3
+#define SK_RLMT_CHECK_OTHERS	(SK_RLMT_CHECK_LOC_LINK | \
+				 SK_RLMT_CHECK_REM_LINK)
+#endif	/* RLMT_CHECK_REMOTE */
+
+/* ----- RLMT modes ----- */
+
+/* Check Link State. */
+#define SK_RLMT_MODE_CLS	(SK_RLMT_CHECK_LINK)
+
+/* Check Local Ports: check other links on the same adapter. */
+#define SK_RLMT_MODE_CLP	(SK_RLMT_CHECK_LINK | \
+				 SK_RLMT_CHECK_LOC_LINK)
+
+/* Check Local Ports and Segmentation Status. */
+#define SK_RLMT_MODE_CLPSS	(SK_RLMT_CHECK_LINK | \
+				 SK_RLMT_CHECK_LOC_LINK | \
+				 SK_RLMT_CHECK_SEG)
+
+#ifdef RLMT_CHECK_REMOTE
+/* Check Local and Remote Ports: check links (local or remote). */
+	Name of define TBD!
+#define SK_RLMT_MODE_CRP	(SK_RLMT_CHECK_LINK | \
+				 SK_RLMT_CHECK_LOC_LINK | \
+				 SK_RLMT_CHECK_REM_LINK)
+
+/* Check Local and Remote Ports and Segmentation Status. */
+	Name of define TBD!
+#define SK_RLMT_MODE_CRPSS	(SK_RLMT_CHECK_LINK | \
+				 SK_RLMT_CHECK_LOC_LINK | \
+				 SK_RLMT_CHECK_REM_LINK | \
+				 SK_RLMT_CHECK_SEG)
+#endif	/* RLMT_CHECK_REMOTE */
+
+/* ----- RLMT lookahead result bits ----- */
+
+#define SK_RLMT_RX_RLMT		1	/* Give packet to RLMT. */
+#define SK_RLMT_RX_PROTOCOL	2	/* Give packet to protocol. */
+
+/* Macros */
+
+#if 0
+SK_AC		*pAC		/* adapter context */
+SK_U32		PortIdx		/* receiving port */
+unsigned	PacketLength	/* received packet's length */
+SK_BOOL		IsBc		/* Flag: broadcast received */
+unsigned	*pOffset	/* Result: offset of bytes to present
+				   to SK_RLMT_LOOKAHEAD */
+unsigned	*pNumBytes	/* Result: #Bytes to present
+				   to SK_RLMT_LOOKAHEAD */
+#endif	/* 0 */
+
+
+#define SK_RLMT_PRE_LOOKAHEAD(pAC,PortIdx,PacketLength,IsBc,pOffset,pNumBytes) { \
+	SK_AC	*_pAC; \
+	SK_U32	_PortIdx; \
+	_pAC = (pAC); \
+	_PortIdx = (SK_U32)(PortIdx); \
+	_pAC->Rlmt.Port[_PortIdx].PacketsRx++; \
+	_pAC->Rlmt.Port[_PortIdx].PacketsPerTimeSlot++; \
+	if ((IsBc) && _pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS) { \
+		*(pOffset) = 6; \
+		*(pNumBytes) = 6; \
+	} \
+	else { \
+		*(pOffset) = 0; \
+		if ((PacketLength) > SK_RLMT_MAX_TX_BUF_SIZE) { \
+			_pAC->Rlmt.Port[_PortIdx].DataPacketsPerTimeSlot++; \
+			*(pNumBytes) = 0; \
+		} \
+		else { \
+			*(pNumBytes) = 6; \
+		} \
+	} \
+}
+
+#if 0
+SK_AC		*pAC		/* adapter context */
+SK_U32		PortIdx		/* receiving port */
+SK_U8		*pLaPacket,	/* received packet's data (points to pOffset) */
+SK_BOOL		IsBc		/* Flag: broadcast received */
+SK_BOOL		IsMc		/* Flag: multicast received */
+unsigned	*pForRlmt	/* Result: bits SK_RLMT_RX_RLMT,
+				   SK_RLMT_RX_PROTOCOL */
+SK_RLMT_LOOKAHEAD() expects *pNumBytes from
+packet offset *pOffset (s.a.) at *pLaPacket.
+
+If you use SK_RLMT_LOOKAHEAD in a path where you already know if the packet is
+BC, MC, or UC, you should use constants for IsBc and IsMc, so that your compiler
+can trash unneeded parts of the if construction.
+#endif	/* 0 */
+#define SK_RLMT_LOOKAHEAD(pAC,PortIdx,pLaPacket,IsBc,IsMc,pForRlmt) { \
+	SK_AC	*_pAC; \
+	SK_U32	_PortIdx; \
+	SK_U8	*_pLaPacket; \
+	_pAC = (pAC); \
+	_PortIdx = (SK_U32)(PortIdx); \
+	_pLaPacket = (SK_U8 *)(pLaPacket); \
+	if (IsBc) {\
+		if (!SK_ADDR_EQUAL( \
+			_pLaPacket, \
+			_pAC->Addr.CurrentMacAddress.a)) { \
+			_pAC->Rlmt.Port[_PortIdx].BcTimeStamp = \
+				SkOsGetTime(_pAC); \
+		} \
+		_pAC->Rlmt.Port[_PortIdx].DataPacketsPerTimeSlot++; \
+		*(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+	} \
+	else if (IsMc) { \
+		if (SK_ADDR_EQUAL(_pLaPacket, BridgeMcAddr.a)) { \
+			_pAC->Rlmt.Port[_PortIdx].BpduPacketsPerTimeSlot++; \
+			if (_pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) { \
+				*(pForRlmt) = SK_RLMT_RX_RLMT | \
+					SK_RLMT_RX_PROTOCOL; \
+			} \
+			else { \
+				*(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+			} \
+		} \
+		else if (SK_ADDR_EQUAL(_pLaPacket, SkRlmtMcAddr.a)) { \
+			*(pForRlmt) = SK_RLMT_RX_RLMT; \
+		} \
+		else { \
+			_pAC->Rlmt.Port[_PortIdx].DataPacketsPerTimeSlot++; \
+			*(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+		} \
+	} \
+	else { \
+		if (SK_ADDR_EQUAL( \
+			_pLaPacket, \
+			_pAC->Addr.Port[_PortIdx].CurrentMacAddress.a)) { \
+			*(pForRlmt) = SK_RLMT_RX_RLMT; \
+		} \
+		else { \
+			_pAC->Rlmt.Port[_PortIdx].DataPacketsPerTimeSlot++; \
+			*(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+		} \
+	} \
+}
+
+#ifdef SK_RLMT_FAST_LOOKAHEAD
+Error: SK_RLMT_FAST_LOOKAHEAD no longer used. Use new macros for lookahead.
+#endif	/* SK_RLMT_FAST_LOOKAHEAD */
+
+/* typedefs *******************************************************************/
+
+typedef struct s_RootId {
+	SK_U8		Id[8];		/* Root Bridge Id. */
+} SK_RLMT_ROOT_ID;
+
+typedef struct s_port {
+	SK_MAC_ADDR	CheckAddr;
+	SK_BOOL		SuspectTx;
+} SK_PORT_CHECK;
+
+typedef struct s_RlmtPort {
+
+/* ----- Public part (read-only) ----- */
+
+	SK_U8		PortState;	/* Current state of this port. */
+
+	/* For PNMI */
+
+	SK_BOOL		LinkDown;
+	SK_BOOL		PortDown;
+
+	SK_U64		TxHelloCts;
+	SK_U64		RxHelloCts;
+	SK_U64		TxSpHelloReqCts;
+	SK_U64		RxSpHelloCts;
+
+/* ----- Private part ----- */
+
+	SK_BOOL		PortStarted;		/* Port is started. */
+	SK_BOOL		PortNoRx;		/* NoRx for >= 1 time slot. */
+	SK_U32		CheckingState;		/* Checking State. */
+
+	SK_U64		PacketsRx;		/* Total packets received. */
+	SK_U32		PacketsPerTimeSlot;	/* Packets rxed between TOs. */
+	SK_U32		DataPacketsPerTimeSlot;	/* Data packets ... */
+#if 0
+	SK_U32		RlmtAcksPerTimeSlot;	/* RLMT Acks rxed in TS. */
+	SK_U32		RlmtChksPerTimeSlot;	/* RLMT Chks rxed in TS. */
+#endif	/* 0 */
+	SK_U32		BpduPacketsPerTimeSlot;	/* BPDU packets rxed in TS. */
+	SK_U64		BcTimeStamp;		/* Time of last BC receive. */
+	SK_U64		GuTimeStamp;		/* Time of entering GOING_UP. */
+
+	SK_TIMER	UpTimer;		/* Timer struct Link/Port up. */
+	SK_TIMER	DownRxTimer;		/* Timer struct down rx. */
+	SK_TIMER	DownTxTimer;		/* Timer struct down tx. */
+
+	SK_U8		Random[4];		/* Random value. */
+	unsigned	PortsChecked;		/* #ports checked. */
+	unsigned	PortsSuspect;		/* #ports checked that are s. */
+	SK_PORT_CHECK	PortCheck[1];
+/*	SK_PORT_CHECK	PortCheck[SK_MAX_MACS - 1]; */
+
+	SK_BOOL		RootIdSet;
+	SK_RLMT_ROOT_ID	Root;			/* Root Bridge Id. */
+} SK_RLMT_PORT;
+
+#ifdef SK_RLMT_MBUF_PRIVATE
+typedef struct s_RlmtMbuf {
+	some content
+} SK_RLMT_MBUF;
+#endif	/* SK_RLMT_MBUF_PRIVATE */
+
+#ifdef SK_LA_INFO
+typedef struct s_Rlmt_PacketInfo {
+	unsigned	PacketLength;	/* Length of packet. */
+	unsigned	PacketType;	/* Directed/Multicast/Broadcast. */
+} SK_RLMT_PINFO;
+#endif	/* SK_LA_INFO */
+
+typedef struct s_Rlmt {
+
+/* ----- Public part (read-only) ----- */
+
+	SK_U8		RlmtState;		/* Current RLMT state. */
+	SK_RLMT_PORT	Port[SK_MAX_MACS];	/* Array of available ports. */
+	SK_U32		PrefPort;		/* Preferred port. */
+
+	/* For PNMI */
+
+	SK_U32		RlmtMode;		/* Check ... */
+	SK_U32		MacActive;		/* Active port. */
+	SK_U32		MacPreferred;		/* 0xFFFFFFFF: Automatic. */
+
+/* ----- Private part ----- */
+
+	int		LinksUp;		/* #Links up. */
+	int		PortsUp;		/* #Ports up. */
+	SK_U32		TimeoutValue;		/* RLMT timeout value. */
+	SK_TIMER	LocTimer;		/* Timer struct. */
+
+	SK_U32		CheckingState;		/* Checking State. */
+	SK_BOOL		RootIdSet;
+	SK_RLMT_ROOT_ID	Root;			/* Root Bridge Id. */
+	SK_TIMER	SegTimer;		/* Timer struct. */
+} SK_RLMT;
+
+extern	SK_MAC_ADDR	BridgeMcAddr;
+extern	SK_MAC_ADDR     SkRlmtMcAddr;
+
+/* function prototypes ********************************************************/
+
+
+#ifndef SK_KR_PROTO
+
+/* Functions provided by SkRlmt */
+
+/* ANSI/C++ compliant function prototypes */
+
+extern	void	SkRlmtInit(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int	Level);
+
+#ifdef SK_RLMT_SLOW_LOOKAHEAD
+extern	SK_BOOL	SkRlmtLookaheadPacket(
+	SK_AC		*pAC,
+	SK_U32		PortIdx,
+	SK_U8		*pLaPacket,
+	unsigned	PacketLength,
+	unsigned	LaLength);
+#endif	/* SK_RLMT_SLOW_LOOKAHEAD */
+
+extern	int	SkRlmtEvent(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	SK_U32		Event,
+	SK_EVPARA	Para);
+
+#else	/* defined(SK_KR_PROTO)) */
+
+/* Non-ANSI/C++ compliant function prototypes */
+
+xxxx	/* not supported yet - force error */
+
+#endif	/* defined(SK_KR_PROTO)) */
+
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_SKRLMT_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/sktimer.h linux.14p16/drivers/net/sk98lin/h/sktimer.h
--- linux.vanilla/drivers/net/sk98lin/h/sktimer.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/sktimer.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,96 @@
+/******************************************************************************
+ *
+ * Name:	sktimer.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.8 $
+ * Date:	$Date: 1998/09/08 08:48:02 $
+ * Purpose:	Defines for the timer functions
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: sktimer.h,v $
+ *	Revision 1.8  1998/09/08 08:48:02  gklug
+ *	add: init level handling
+ *	
+ *	Revision 1.7  1998/08/20 12:31:29  gklug
+ *	fix: SK_TIMCTRL needs to be defined
+ *	
+ *	Revision 1.6  1998/08/19 09:51:00  gklug
+ *	fix: remove struct keyword from c-code (see CCC) add typedefs
+ *	
+ *	Revision 1.5  1998/08/17 13:43:21  gklug
+ *	chg: Parameter will be union of 64bit para, 2 times SK_U32 or SK_PTR
+ *	
+ *	Revision 1.4  1998/08/14 07:09:31  gklug
+ *	fix: chg pAc -> pAC
+ *	
+ *	Revision 1.3  1998/08/07 12:54:24  gklug
+ *	fix: first compiled version
+ *	
+ *	Revision 1.2  1998/08/07 09:35:29  gklug
+ *	add: Timer control struct for Adapters context
+ *	add: function prototypes
+ *	
+ *	Revision 1.1  1998/08/05 11:27:01  gklug
+ *	First version: adapted from SMT
+ *	
+ *
+ ******************************************************************************/
+
+/*
+ * SKTIMER.H	contains all defines and types for the timer functions
+ */
+
+#ifndef	_SKTIMER_H_
+#define _SKTIMER_H_
+
+#include "h/skqueue.h"
+
+/*
+ * SK timer
+ * - needed wherever a timer is used. Put this in your data structure
+ *   wherever you want.
+ */
+typedef	struct s_Timer SK_TIMER;
+
+struct s_Timer {
+	SK_TIMER	*TmNext ;	/* linked list */
+	SK_U32		TmClass ;	/* Timer Event class */
+	SK_U32		TmEvent ;	/* Timer Event value */
+	SK_EVPARA	TmPara ;	/* Timer Event parameter */
+	SK_U32		TmDelta ;	/* delta time */
+	int		TmActive ;	/* flag : active/inactive */
+} ;
+
+/*
+ * Timer control struct.
+ * - use in Adapters context name pAC->Tim
+ */
+typedef	struct s_TimCtrl {
+	SK_TIMER	*StQueue ;	/* Head of Timer queue */
+} SK_TIMCTRL ;
+
+extern void SkTimerInit(SK_AC *pAC,SK_IOC Ioc, int Level);
+extern void SkTimerStop(SK_AC *pAC,SK_IOC Ioc,SK_TIMER *pTimer);
+extern void SkTimerStart(SK_AC *pAC,SK_IOC Ioc,SK_TIMER *pTimer,
+	SK_U32 Time,SK_U32 Class,SK_U32 Event,SK_EVPARA Para);
+extern void SkTimerDone(SK_AC *pAC,SK_IOC Ioc);
+#endif	/* _SKTIMER_H_ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/sktypes.h linux.14p16/drivers/net/sk98lin/h/sktypes.h
--- linux.vanilla/drivers/net/sk98lin/h/sktypes.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/sktypes.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,81 @@
+/******************************************************************************
+ *
+ * Name:	sktypes.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.1 $
+ * Date:	$Date: 1999/02/16 07:41:40 $
+ * Purpose:	Define data types for Linux
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+ 
+ /*****************************************************************************
+ *
+ * History:
+ *
+ *	$Log: sktypes.h,v $
+ *	Revision 1.1  1999/02/16 07:41:40  cgoos
+ *	First version.
+ *	
+ *	
+ *
+ *****************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * In this file, all data types that are needed by the common modules
+ * are mapped to Linux data types.
+ * 
+ *
+ * Include File Hierarchy:
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKTYPES_H
+#define __INC_SKTYPES_H
+
+
+/* defines *******************************************************************/
+
+/*
+ * Data types with a specific size. 'I' = signed, 'U' = unsigned.
+ */
+#define SK_I8	s8
+#define SK_U8	u8
+#define SK_I16	s16
+#define SK_U16	u16
+#define SK_I32	s32
+#define SK_U32	u32
+#define SK_I64	s64
+#define SK_U64	u64
+
+#define SK_UPTR	ulong		/* casting pointer <-> integral */
+
+/*
+* Boolean type.
+*/
+#define SK_BOOL		SK_U8
+#define SK_FALSE	0
+#define SK_TRUE		(!SK_FALSE)
+
+/* typedefs *******************************************************************/
+
+/* function prototypes ********************************************************/
+
+#endif	/* __INC_SKTYPES_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/skvpd.h linux.14p16/drivers/net/sk98lin/h/skvpd.h
--- linux.vanilla/drivers/net/sk98lin/h/skvpd.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/skvpd.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,295 @@
+/******************************************************************************
+ *
+ * Name:	skvpd.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.8 $
+ * Date:	$Date: 1999/03/11 14:26:40 $
+ * Purpose:	Defines and Macros for VPD handling
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skvpd.h,v $
+ *	Revision 1.8  1999/03/11 14:26:40  malthoff
+ *	Replace __STDC__ with SK_KR_PROTO.
+ *	
+ *	Revision 1.7  1998/10/28 07:27:17  gklug
+ *	rmv: SWAP macros
+ *	add: VPD_IN/OUT8 macros
+ *	chg: interface definition
+ *	
+ *	Revision 1.6  1998/10/22 10:03:44  gklug
+ *	fix: use SK_OUT16 instead of SK_OUTW
+ *	
+ *	Revision 1.5  1998/10/14 07:05:31  cgoos
+ *	Changed constants in SK_SWAP_32 to UL.
+ *	
+ *	Revision 1.4  1998/08/19 08:14:09  gklug
+ *	fix: remove struct keyword as much as possible from the c-code (see CCC)
+ *	
+ *	Revision 1.3  1998/08/18 08:18:56  malthoff
+ *	Modify VPD in and out macros for SK_DIAG
+ *	
+ *	Revision 1.2  1998/07/03 14:49:08  malthoff
+ *	Add VPD_INxx() and VPD_OUTxx() macros for the Diagnostics tool.
+ *	
+ *	Revision 1.1  1998/06/19 14:08:03  malthoff
+ *	Created.
+ *	
+ *
+ ******************************************************************************/
+
+/*
+ * skvpd.h	contains Diagnostic specific defines for VPD handling
+ */
+
+#ifndef __INC_SKVPD_H_
+#define __INC_SKVPD_H_
+
+/*
+ * Define Resource Type Identifiers and VPD keywords
+ */
+#define	RES_ID		0x82	/* Resource Type ID String (Product Name) */
+#define RES_VPD_R	0x90	/* start of VPD read only area */
+#define RES_VPD_W	0x91	/* start of VPD read/write area */
+#define RES_END		0x78	/* Resource Type End Tag */
+
+#ifndef VPD_NAME
+#define VPD_NAME	"Name"	/* Product Name, VPD name of RES_ID */
+#endif	/* VPD_NAME */
+#define VPD_PN		"PN"	/* Adapter Part Number */
+#define	VPD_EC		"EC"	/* Adapter Engineering Level */
+#define VPD_MN		"MN"	/* Manufacture ID */
+#define VPD_SN		"SN"	/* Serial Number */
+#define VPD_CP		"CP"	/* Extended Capability */
+#define VPD_RV		"RV"	/* Checksum and Reserved */
+#define	VPD_YA		"YA"	/* Asset Tag Identifier */
+#define VPD_VL		"VL"	/* First Error Log Message (SK specific) */
+#define VPD_VF		"VF"	/* Second Error Log Message (SK specific) */
+#define VPD_RW		"RW"	/* Remaining Read / Write Area */
+
+/* 'type' values for vpd_setup_para() */
+#define VPD_RO_KEY	1	/* RO keys are "PN", "EC", "MN", "SN", "RV" */
+#define VPD_RW_KEY	2	/* RW keys are "Yx", "Vx", and "RW" */
+
+/* 'op' values for vpd_setup_para() */
+#define	ADD_KEY		1	/* add the key at the pos "RV" or "RW" */
+#define OWR_KEY		2	/* overwrite key if already exists */
+
+/*
+ * Define READ and WRITE Constants.
+ */
+#define	VPD_SIZE	512
+#define VPD_READ	0x0000
+#define VPD_WRITE	0x8000
+
+#define VPD_STOP(pAC,IoC)	VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG,VPD_WRITE)
+
+#define VPD_GET_RES_LEN(p)	((unsigned int) \
+					(* (SK_U8 *)&(p)[1]) |\
+					((* (SK_U8 *)&(p)[2]) << 8))
+#define VPD_GET_VPD_LEN(p)	((unsigned int)(* (SK_U8 *)&(p)[2]))
+#define VPD_GET_VAL(p)		((char *)&(p)[3])
+
+#define VPD_MAX_LEN	50
+
+/* VPD status */
+	/* bit 7..1 reserved */
+#define VPD_VALID	(1<<0)		/* VPD data buffer, vpd_free_ro, */
+					/* and vpd_free_rw valid	 */
+
+/*
+ * VPD structs
+ */
+typedef	struct s_vpd_status {
+	unsigned short	vpd_status ;	/* VPD status, description see above */
+	int		vpd_free_ro ;	/* unused bytes in read only area */
+	int		vpd_free_rw ;	/* bytes available in read/write area */
+} SK_VPD_STATUS;
+
+typedef	struct s_vpd {
+	SK_VPD_STATUS	v ;			/* VPD status structure */
+	char		vpd_buf[VPD_SIZE] ;	/* VPD buffer */
+} SK_VPD;
+
+typedef	struct s_vpd_para {
+	unsigned int	p_len ;		/* parameter length */
+	char		*p_val ;	/* points to the value */
+} SK_VPD_PARA;
+
+/*
+ * structure of Large Resource Type Identifiers
+ */
+/* was removed, because of alignment problems */
+
+/*
+ * sturcture of VPD keywords
+ */
+typedef	struct s_vpd_key {
+	char		p_key[2] ;	/* 2 bytes ID string */
+	unsigned char	p_len ;		/* 1 byte length */
+	char		p_val ;		/* start of the value string */
+} SK_VPD_KEY;
+
+
+/*
+ * System specific VPD macros
+ */
+#ifndef SKDIAG
+#ifndef VPD_DO_IO
+#define VPD_OUT8(pAC,IoC,Addr,Val)	(void)SkPciWriteCfgByte(pAC,Addr,Val)
+#define VPD_OUT16(pAC,IoC,Addr,Val)	(void)SkPciWriteCfgWord(pAC,Addr,Val)
+#define VPD_OUT32(pAC,IoC,Addr,Val)	(void)SkPciWriteCfgDWord(pAC,Addr,Val)
+#define VPD_IN8(pAC,IoC,Addr,pVal)	(void)SkPciReadCfgByte(pAC,Addr,pVal)
+#define VPD_IN16(pAC,IoC,Addr,pVal)	(void)SkPciReadCfgWord(pAC,Addr,pVal)
+#define VPD_IN32(pAC,IoC,Addr,pVal)	(void)SkPciReadCfgDWord(pAC,Addr,pVal)
+#else	/* VPD_DO_IO */
+#define VPD_OUT8(pAC,IoC,Addr,Val)	SK_OUT8(IoC,PCI_C(Addr),Val)
+#define VPD_OUT16(pAC,IoC,Addr,Val)	SK_OUT16(IoC,PCI_C(Addr),Val)
+#define VPD_OUT32(pAC,IoC,Addr,Val)	SK_OUT32(IoC,PCI_C(Addr),Val)
+#define VPD_IN8(pAC,IoC,Addr,pVal)	SK_IN8(IoC,PCI_C(Addr),pVal)
+#define VPD_IN16(pAC,IoC,Addr,pVal)	SK_IN16(IoC,PCI_C(Addr),pVal)
+#define VPD_IN32(pAC,IoC,Addr,pVal)	SK_IN32(IoC,PCI_C(Addr),pVal)
+#endif	/* VPD_DO_IO */
+#else	/* SKDIAG */
+#define VPD_OUT8(pAC,Ioc,Addr,Val) {				\
+		if ((pAC)->DgT.DgUseCfgCycle)			\
+			SkPciWriteCfgByte(pAC,Addr,Val) ;	\
+		else						\
+			SK_OUT8(pAC,PCI_C(Addr),Val);		\
+		}
+#define VPD_OUT16(pAC,Ioc,Addr,Val) {				\
+		if ((pAC)->DgT.DgUseCfgCycle)			\
+			SkPciWriteCfgWord(pAC,Addr,Val) ;	\
+		else						\
+			SK_OUT16(pAC,PCI_C(Addr),Val);		\
+		}
+#define VPD_OUT32(pAC,Ioc,Addr,Val) {				\
+		if ((pAC)->DgT.DgUseCfgCycle)			\
+			SkPciWriteCfgDWord(pAC,Addr,Val) ;	\
+		else						\
+			SK_OUT32(pAC,PCI_C(Addr),Val); 		\
+		}
+#define VPD_IN8(pAC,Ioc,Addr,pVal) {				\
+		if ((pAC)->DgT.DgUseCfgCycle) 			\
+			SkPciReadCfgByte(pAC,Addr,pVal) ;	\
+		else						\
+			SK_IN8(pAC,PCI_C(Addr),pVal); 		\
+		}
+#define VPD_IN16(pAC,Ioc,Addr,pVal) {				\
+		if ((pAC)->DgT.DgUseCfgCycle) 			\
+			SkPciReadCfgWord(pAC,Addr,pVal) ;	\
+		else						\
+			SK_IN16(pAC,PCI_C(Addr),pVal); 		\
+		}
+#define VPD_IN32(pAC,Ioc,Addr,pVal) {				\
+		if ((pAC)->DgT.DgUseCfgCycle)			\
+			SkPciReadCfgDWord(pAC,Addr,pVal) ;	\
+		else						\
+			SK_IN32(pAC,PCI_C(Addr),pVal);		\
+		}
+#endif	/* nSKDIAG */
+
+/* function prototypes ********************************************************/
+
+#ifndef	SK_KR_PROTO
+extern SK_U32	VpdReadDWord(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int		addr) ;
+
+extern int	VpdSetupPara(
+	SK_AC		*pAC,
+	char		*key,
+	char		*buf,
+	int		len,
+	int		type,
+	int		op) ;
+
+extern SK_VPD_STATUS	*VpdStat(
+	SK_AC		*pAC,
+	SK_IOC		IoC) ;
+
+extern int	VpdKeys(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	char		*buf,
+	int		*len,
+	int		*elements) ;
+
+extern int	VpdRead(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	char		*key,
+	char		*buf,
+	int		*len) ;
+
+extern	SK_BOOL	VpdMayWrite(
+	char		*key) ;
+
+extern int	VpdWrite(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	char		*key,
+	char		*buf) ;
+
+extern int	VpdDelete(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	char		*key) ;
+
+extern int	VpdUpdate(
+	SK_AC		*pAC,
+	SK_IOC		IoC);
+
+extern void	VpdErrLog(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	char		*msg) ;
+
+#ifdef	SKDIAG
+extern int	VpdReadBlock(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	char		*buf,
+	int		addr,
+	int		len) ;
+
+extern int	VpdWriteBlock(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	char		*buf,
+	int		addr,
+	int		len) ;
+#endif	/* SKDIAG */
+#else	/* SK_KR_PROTO */
+extern SK_U32	VpdReadDWord() ;
+extern int	VpdSetupPara() ;
+extern SK_VPD_STATUS	*VpdStat() ;
+extern int	VpdKeys() ;
+extern int	VpdRead() ;
+extern SK_BOOL	VpdMayWrite() ;
+extern int	VpdWrite() ;
+extern int	VpdDelete() ;
+extern int	VpdUpdate() ;
+extern void	VpdErrLog() ;
+#endif	/* SK_KR_PROTO */
+
+#endif	/* __INC_SKVPD_H_ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/h/xmac_ii.h linux.14p16/drivers/net/sk98lin/h/xmac_ii.h
--- linux.vanilla/drivers/net/sk98lin/h/xmac_ii.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/h/xmac_ii.h	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,1155 @@
+/******************************************************************************
+ *
+ * Name:	xmac_ii.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.25 $
+ * Date:	$Date: 1999/08/12 19:19:38 $
+ * Purpose:	Defines and Macros for XaQti's Gigabit Ethernet Controller
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: xmac_ii.h,v $
+ *	Revision 1.25  1999/08/12 19:19:38  malthoff
+ *	Add PHY_B_AC_TX_TST bit according to BCOM A1 errata sheet.
+ *	
+ *	Revision 1.24  1999/07/30 11:27:21  cgoos
+ *	Fixed a missing end-of-comment.
+ *	
+ *	Revision 1.23  1999/07/30 07:03:31  malthoff
+ *	Cut some long comments.
+ *	Correct the XMAC PHY ID definitions.
+ *	
+ *	Revision 1.22  1999/05/19 07:33:18  cgoos
+ *	Changes for 1000Base-T.
+ *	
+ *	Revision 1.21  1999/03/25 07:46:11  malthoff
+ *	Add XM_HW_CFG, XM_TS_READ, and XM_TS_LOAD registers.
+ *	
+ *	Revision 1.20  1999/03/12 13:36:09  malthoff
+ *	Remove __STDC__.
+ *
+ *	Revision 1.19  1998/12/10 12:22:54  gklug
+ *	fix: RX_PAGE must be in interrupt mask
+ *
+ *	Revision 1.18  1998/12/10 10:36:36  gklug
+ *	fix: swap of pause bits
+ *
+ *	Revision 1.17  1998/11/18 13:21:45  gklug
+ *	fix: Default interrupt mask
+ *
+ *	Revision 1.16  1998/10/29 15:53:21  gklug
+ *	fix: Default mask uses ASS (GP0) signal
+ *
+ *	Revision 1.15  1998/10/28 13:52:52  malthoff
+ *	Add new bits in RX_CMD register.
+ *
+ *	Revision 1.14  1998/10/19 15:34:53  gklug
+ *	fix: typos
+ *
+ *	Revision 1.13  1998/10/14 07:19:03  malthoff
+ *	bug fix: Every define which describes bit 31
+ *	must be declared as unsigned long 'UL'.
+ *	fix bit definitions of PHY_AN_RFB and PHY_AN_PAUSE.
+ *	Remove ANP defines. Rework the RFB defines.
+ *
+ *	Revision 1.12  1998/10/14 06:22:44  cgoos
+ *	Changed shifted constant to ULONG.
+ *
+ *	Revision 1.11  1998/10/14 05:43:26  gklug
+ *	add: shift pause codeing
+ *	fix: PAUSE bits definition
+ *
+ *	Revision 1.10  1998/10/13 09:19:21  malthoff
+ *	Again change XMR_FS_ANY_ERR because of new info from XaQti.
+ *
+ *	Revision 1.9  1998/10/09 07:58:30  malthoff
+ *	Add XMR_FS_FCS_ERR to XMR_FS_ANY_ERR.
+ *
+ *	Revision 1.8  1998/10/09 07:18:17  malthoff
+ *	bug fix of a bug fix: XM_PAUSE_MODE and XM_DEF_MODE
+ *	are not inverted! Bug XM_DEF_MSK is inverted.
+ *
+ *	Revision 1.7  1998/10/05 08:04:32  malthoff
+ *	bug fix: XM_PAUSE_MODE and XM_DEF_MODE
+ *	must be inverted declarations.
+ *
+ *	Revision 1.6  1998/09/28 13:38:18  malthoff
+ *	Add default modes and masks XM_DEF_MSK,
+ *	XM_PAUSE_MODE and XM_DEF_MODE
+ *
+ *	Revision 1.5  1998/09/16 14:42:04  malthoff
+ *	Bug Fix: XM_GP_PORT is a 32 bit (not a 16 bit) register.
+ *
+ *	Revision 1.4  1998/08/20 14:59:47  malthoff
+ *	Rework this file after reading the XaQti data sheet
+ *	"Differences between Rev. B2 & Rev. C XMAC II".
+ *	This file is now 100% XMAC II Rev. C complained.
+ *
+ *	Revision 1.3  1998/06/29 12:18:23  malthoff
+ *	Correct XMR_FS_ANY_ERR definition.
+ *
+ *	Revision 1.2  1998/06/29 12:10:56  malthoff
+ *	Add define XMR_FS_ANY_ERR.
+ *
+ *	Revision 1.1  1998/06/19 13:37:17  malthoff
+ *	created.
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __INC_XMAC_H
+#define __INC_XMAC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* __cplusplus */
+
+/* defines ********************************************************************/
+
+/*
+ * XMAC II registers
+ *
+ * The XMAC registers are 16 or 32 bits wide. The XMACs host processor
+ * interface is set to 16 bit mode, therefore ALL registers will be
+ * addressed with 16 bit accesses.
+ *
+ * The following macros are provided to access the XMAC registers
+ * XM_IN16(), XM_OUT16, XM_IN32(), MX_OUT32(), XM_INADR(), XM_OUTADR(),
+ * XM_INHASH(), and XM_OUTHASH().
+ * The macros are defined in SkGeHw.h.
+ *
+ * Note:	NA reg	= Network Address e.g DA, SA etc.
+ *
+ */
+#define XM_MMU_CMD	0x0000	/* 16 bit r/w	MMU Command Register */
+	/* 0x0004:		reserved */
+#define XM_POFF		0x0008	/* 32 bit r/w	Packet Offset Register */
+#define XM_BURST	0x000c	/* 32 bit r/w	Burst Register for half duplex*/
+#define XM_1L_VLAN_TAG	0x0010	/* 16 bit r/w	One Level VLAN Tag ID */
+#define XM_2L_VLAN_TAG	0x0014	/* 16 bit r/w	Two Level VLAN Tag ID */
+	/* 0x0018 - 0x001e:	reserved */
+#define XM_TX_CMD	0x0020	/* 16 bit r/w	Transmit Command Register */
+#define	XM_TX_RT_LIM	0x0024	/* 16 bit r/w	Transmit Retry Limit Register */
+#define XM_TX_STIME	0x0028	/* 16 bit r/w	Transmit Slottime Register */
+#define XM_TX_IPG	0x002c	/* 16 bit r/w	Transmit Inter Packet Gap */
+#define XM_RX_CMD	0x0030	/* 16 bit r/w	Receive Command Register */
+#define XM_PHY_ADDR	0x0034	/* 16 bit r/w	PHY Address Register */
+#define	XM_PHY_DATA	0x0038	/* 16 bit r/w	PHY Data Register */
+	/* 0x003c: 		reserved */
+#define XM_GP_PORT	0x0040	/* 32 bit r/w	General Purpose Port Register */
+#define XM_IMSK		0x0044	/* 16 bit r/w	Interrupt Mask Register */
+#define XM_ISRC		0x0048	/* 16 bit ro	Interrupt Status Register */
+#define XM_HW_CFG	0x004c	/* 16 bit r/w	Hardware Config Register */
+	/* 0x0050 - 0x005e:	reserved */
+#define XM_TX_LO_WM	0x0060	/* 16 bit r/w	Tx FIFO Low Water Mark */
+#define XM_TX_HI_WM	0x0062	/* 16 bit r/w	Tx FIFO High Water Mark */
+#define XM_TX_THR	0x0064	/* 16 bit r/w	Tx Request Threshold */
+#define	XM_HT_THR	0x0066	/* 16 bit r/w	Host Request Threshold */
+#define	XM_PAUSE_DA	0x0068	/* NA reg r/w	Pause Destination Address */
+	/* 0x006e: 		reserved */
+#define XM_CTL_PARA	0x0070	/* 32 bit r/w	Control Parameter Register */
+#define XM_MAC_OPCODE	0x0074	/* 16 bit r/w	Opcode for MAC control frames */
+#define XM_MAC_PTIME	0x0076	/* 16 bit r/w	Pause time for MAC ctrl frames*/
+#define XM_TX_STAT	0x0078	/* 32 bit ro	Tx Status LIFO Register */
+
+	/* 0x0080 - 0x00fc:	16 NA reg r/w	Exakt Match Address Registers */
+	/* 				use the XM_EMX() macro to address */
+#define XM_EXM_START	0x0080		/* r/w	Start Address of the EXM Regs */
+
+	/*
+	 * XM_EXM(Reg)
+	 *
+	 * returns the XMAC address offset off specified Exakt Match Addr Reg
+	 *
+	 * para:	Reg	EXM register to addr	(0 .. 15)
+	 *
+	 * usage:	XM_INADDR(XMAC_1,pAC,XM_EXM(i),&val[i]) ;
+	 */
+#define XM_EXM(Reg)	(XM_EXM_START + ((Reg) << 3))
+
+#define XM_SRC_CHK	0x0100	/* NA reg r/w	Source Check Address Register */
+#define XM_SA		0x0108	/* NA reg r/w	Station Address Register */
+#define XM_HSM		0x0110	/* 64 bit r/w	Hash Match Address Registers */
+#define XM_RX_LO_WM	0x0118	/* 16 bit r/w	Receive Low Water Mark */
+#define XM_RX_HI_WM	0x011a	/* 16 bit r/w	Receive High Water Mark */
+#define XM_RX_THR	0x011c	/* 32 bit r/w	Receive Request Threshold */
+#define XM_DEV_ID	0x0120	/* 32 bit ro	Device ID Register */
+#define XM_MODE		0x0124	/* 32 bit r/w	Mode Register */
+#define XM_LSA		0x0128	/* NA reg ro	Last Source Register */
+	/* 0x012e:		reserved */
+#define XM_TS_READ	0x0130	/* 32 bit ro	TimeStamp Read Regeister */
+#define XM_TS_LOAD	0x0134	/* 32 bit ro	TimeStamp Load Value */
+	/* 0x0138 - 0x01fe:	reserved */
+#define XM_STAT_CMD	0x0200	/* 16 bit r/w	Statistics Command Register */
+#define	XM_RX_CNT_EV	0x0204	/* 32 bit ro	Rx Counter Event Register */
+#define XM_TX_CNT_EV	0x0208	/* 32 bit ro	Tx Counter Event Register */
+#define XM_RX_EV_MSK	0x020c	/* 32 bit r/w	Rx Counter Event Mask */
+#define XM_TX_EV_MSK	0x0210	/* 32 bit r/w	Tx Counter Event Mask */
+	/* 0x0204 - 0x027e:	reserved */
+#define XM_TXF_OK	0x0280	/* 32 bit ro	Frames Transmitted OK Conuter */
+#define XM_TXO_OK_HI	0x0284	/* 32 bit ro	Octets Transmitted OK High Cnt*/
+#define XM_TXO_OK_LO	0x0288	/* 32 bit ro	Octets Transmitted OK Low Cnt */
+#define XM_TXF_BC_OK	0x028c	/* 32 bit ro	Broadcast Frames Xmitted OK */
+#define XM_TXF_MC_OK	0x0290	/* 32 bit ro	Multicast Frames Xmitted OK */
+#define XM_TXF_UC_OK	0x0294	/* 32 bit ro	Unicast Frames Xmitted OK */
+#define XM_TXF_LONG	0x0298	/* 32 bit ro	Tx Long Frame Counter */
+#define XM_TXE_BURST	0x029c	/* 32 bit ro	Tx Burst Event Counter */
+#define XM_TXF_MPAUSE	0x02a0	/* 32 bit ro	Tx Pause MAC Ctrl Frame Cnt */
+#define XM_TXF_MCTRL	0x02a4	/* 32 bit ro	Tx MAC Ctrl Frame Counter */
+#define XM_TXF_SNG_COL	0x02a8	/* 32 bit ro	Tx Single Colliosion Counter */
+#define XM_TXF_MUL_COL	0x02ac	/* 32 bit ro	Tx Multiple Collision Counter */
+#define XM_TXF_ABO_COL	0x02b0	/* 32 bit ro	Tx aborted due to Exessive Col*/
+#define XM_TXF_LAT_COL	0x02b4	/* 32 bit ro	Tx Late Collision Counter */
+#define XM_TXF_DEF	0x02b8	/* 32 bit ro	Tx Deferred Frame Counter */
+#define XM_TXF_EX_DEF	0x02bc	/* 32 bit ro	Tx Excessive Deferall Counter */
+#define XM_TXE_FIFO_UR	0x02c0	/* 32 bit ro	Tx FIFO Underrun Event Cnt */
+#define XM_TXE_CS_ERR	0x02c4	/* 32 bit ro	Tx Carrier Sence Error Cnt */
+#define XM_TXP_UTIL	0x02c8	/* 32 bit ro	Tx Utilization in % */
+	/* 0x02cc - 0x02ce:	reserved */
+#define XM_TXF_64B	0x02d0	/* 32 bit ro	64 Byte Tx Frame Counter */
+#define XM_TXF_127B	0x02d4	/* 32 bit ro	65-127 Byte Tx Frame Counter */
+#define XM_TXF_255B	0x02d8	/* 32 bit ro	128-255 Byte Tx Frame Counter */
+#define XM_TXF_511B	0x02dc	/* 32 bit ro	256-511 Byte Tx Frame Counter */
+#define XM_TXF_1023B	0x02e0	/* 32 bit ro	512-1023 Byte Tx Frame Counter*/
+#define XM_TXF_MAX_SZ	0x02e4	/* 32 bit ro	1024-MaxSize Byte Tx Frame Cnt*/
+	/* 0x02e8 - 0x02fe:	reserved */
+#define XM_RXF_OK	0x0300	/* 32 bit ro	Frames Received OK */
+#define XM_RXO_OK_HI	0x0304	/* 32 bit ro	Octets Received OK High Cnt */
+#define XM_RXO_OK_LO	0x0308	/* 32 bit ro	Octets Received OK Low Counter*/
+#define XM_RXF_BC_OK	0x030c	/* 32 bit ro	Broadcast Frames Received OK */
+#define XM_RXF_MC_OK	0x0310	/* 32 bit ro	Multicast Frames Received OK */
+#define XM_RXF_UC_OK	0x0314	/* 32 bit ro	Unicast Frames Received OK */
+#define XM_RXF_MPAUSE	0x0318	/* 32 bit ro	Rx Pause MAC Ctrl Frame Cnt */
+#define XM_RXF_MCTRL	0x031c	/* 32 bit ro	Rx MAC Ctrl Frame Counter */
+#define XM_RXF_INV_MP	0x0320	/* 32 bit ro	Rx invalid Pause Frame Cnt */
+#define XM_RXF_INV_MOC	0x0324	/* 32 bit ro	Rx Frames with inv. MAC Opcode*/
+#define XM_RXE_BURST	0x0328	/* 32 bit ro	Rx Burst Event Counter */
+#define XM_RXE_FMISS	0x032c	/* 32 bit ro	Rx Missed Frames Event Cnt */
+#define XM_RXF_FRA_ERR	0x0330	/* 32 bit ro	Rx Framing Error Counter */
+#define XM_RXE_FIFO_OV	0x0334	/* 32 bit ro	Rx FIFO overflow Event Cnt */
+#define XM_RXF_JAB_PKT	0x0338	/* 32 bit ro	Rx Jabber Packet Frame Cnt */
+#define XM_RXE_CAR_ERR	0x033c	/* 32 bit ro	Rx Carrier Event Error Cnt */
+#define XM_RXF_LEN_ERR	0x0340	/* 32 bit ro	Rx in Range Length Error */
+#define XM_RXE_SYM_ERR	0x0344	/* 32 bit ro	Rx Symbol Error Counter */
+#define XM_RXE_SHT_ERR	0x0348	/* 32 bit ro	Rx Short Event Error Cnt */
+#define XM_RXE_RUNT	0x034c	/* 32 bit ro	Rx Runt Event Counter */
+#define XM_RXF_LNG_ERR	0x0350	/* 32 bit ro	Rx Frame too Long Error Cnt */
+#define XM_RXF_FCS_ERR	0x0354	/* 32 bit ro	Rx Frame Check Seq. Error Cnt */
+	/* 0x0358 - 0x035a:	reserved */
+#define XM_RXF_CEX_ERR	0x035c	/* 32 bit ro	Rx Carrier Ext Error Frame Cnt*/
+#define XM_RXP_UTIL	0x0360	/* 32 bit ro	Rx Utilization in % */
+	/* 0x0364 - 0x0366:	reserved */
+#define XM_RXF_64B	0x0368	/* 32 bit ro	64 Byte Rx Frame Counter */
+#define XM_RXF_127B	0x036c	/* 32 bit ro	65-127 Byte Rx Frame Counter */
+#define XM_RXF_255B	0x0370	/* 32 bit ro	128-255 Byte Rx Frame Counter */
+#define XM_RXF_511B	0x0374	/* 32 bit ro	256-511 Byte Rx Frame Counter */
+#define XM_RXF_1023B	0x0378	/* 32 bit ro	512-1023 Byte Rx Frame Counter*/
+#define XM_RXF_MAX_SZ	0x037c	/* 32 bit ro	1024-MaxSize Byte Rx Frame Cnt*/
+	/* 0x02e8 - 0x02fe:	reserved */
+
+
+/*----------------------------------------------------------------------------*/
+/*
+ * XMAC Bit Definitions
+ *
+ * If the bit access behaviour differs from the register access behaviour
+ * (r/w, ro) this is docomented after the bit number. The following bit
+ * access behaviours are used:
+ *	(sc)	self clearing
+ *	(ro)	read only
+ */
+
+/*	XM_MMU_CMD	16 bit r/w	MMU Comamnd Register */
+				/* Bit 15..13:	reserved */
+#define XM_MMU_PHY_RDY	(1<<12)	/* Bit 12:	PHY Read Ready */
+#define XM_MMU_PHY_BUSY	(1<<11)	/* Bit 11:	PHY Busy */
+#define XM_MMU_IGN_PF	(1<<10)	/* Bit 10:	Ignore Pause Frame */
+#define XM_MMU_MAC_LB	(1<<9)	/* Bit	9:	Enable MAC Loopback */
+				/* Bit	8:	reserved */
+#define XM_MMU_FRC_COL	(1<<7)	/* Bit	7:	Force Collision */
+#define XM_MMU_SIM_COL	(1<<6)	/* Bit	6:	Simulate Collision */
+#define XM_MMU_NO_PRE	(1<<5)	/* Bit	5:	No MDIO Preamble */
+#define XM_MMU_GMII_FD	(1<<4)	/* Bit	4:	GMII uses Full Duplex */
+#define XM_MMU_RAT_CTRL	(1<<3)	/* Bit	3:	Enable Rate Control */
+#define XM_MMU_GMII_LOOP (1<<2)	/* Bit	2:	PHY is in Lookback Mode */
+#define XM_MMU_ENA_RX	(1<<1)	/* Bit	1:	Enable Receiver */
+#define XM_MMU_ENA_TX	(1<<0)	/* Bit	0:	Enable Transmitter */
+
+
+/*	XM_TX_CMD	16 bit r/w	Transmit Command Register */
+				/* Bit 15..7:	reserved */
+#define XM_TX_BK2BK	(1<<6)	/* Bit	6:	Ignor Carrier Sense (tx Bk2Bk)*/
+#define XM_TX_ENC_BYP	(1<<5)	/* Bit	5:	Set Encoder in Bypass Mode */
+#define XM_TX_SAM_LINE	(1<<4)	/* Bit	4: (sc)	Start utilization calculation */
+#define XM_TX_NO_GIG_MD	(1<<3)	/* Bit	3:	Disable Carrier Extension */
+#define XM_TX_NO_PRE	(1<<2)	/* Bit	2:	Disable Preamble Generation */
+#define XM_TX_NO_CRC	(1<<1)	/* Bit	1:	Disable CRC Generation */
+#define XM_TX_AUTO_PAD	(1<<0)	/* Bit	0:	Enable Automatic Padding */
+
+
+/*	XM_TX_RT_LIM	16 bit r/w	Transmit Retry Limit Register */
+				/* Bit 15..5:	reserved */
+#define	XM_RT_LIM_MSK	0x1f	/* Bit	4..0:	Tx Retry Limit */
+
+
+/*	XM_TX_STIME	16 bit r/w	Transmit Slottime Register */
+				/* Bit 15..7:	reserved */
+#define XM_STIME_MSK	0x7f	/* Bit	6..0:	Tx Slottime bits */
+
+
+/*	XM_TX_IPG	16 bit r/w	Transmit Inter Packet Gap */
+				/* Bit 15..8:	reserved */
+#define XM_IPG_MSK	0xff	/* Bit	7..0:	IPG value bits */
+
+
+/*	XM_RX_CMD	16 bit r/w	Receive Command Register */
+				/* Bit 15..9:	reserved */
+#define XM_RX_LENERR_OK (1<<8)	/* Bit	8	don't set Rx Err bit for */
+				/*		inrange error packets */
+#define XM_RX_BIG_PK_OK	(1<<7)	/* Bit	7	don't set Rx Err bit for */
+				/*		jumbo packets */
+#define XM_RX_IPG_CAP	(1<<6)	/* Bit	6	repl. type field with IPG */
+#define XM_RX_TP_MD	(1<<5)	/* Bit	5:	Enable transparent Mode */
+#define XM_RX_STRIP_FCS	(1<<4)	/* Bit	4:	Enable FCS Stripping */
+#define XM_RX_SELF_RX	(1<<3)	/* Bit	3: 	Enable Rx of own packets */
+#define XM_RX_SAM_LINE	(1<<2)	/* Bit	2: (sc)	Start utilization calculation */
+#define XM_RX_STRIP_PAD	(1<<1)	/* Bit	1:	Strip pad bytes of rx frames */
+#define XM_RX_DIS_CEXT	(1<<0)	/* Bit	0:	Disable carrier ext. check */
+
+
+/*	XM_PHY_ADDR	16 bit r/w	PHY Address Register */
+				/* Bit 15..5:	reserved */
+#define	XM_PHY_ADDR_SZ	0x1f	/* Bit	4..0:	PHY Address bits */
+
+
+/*	XM_GP_PORT	32 bit r/w	General Purpose Port Register */
+				/* Bit 31..7:	reserved */
+#define	XM_GP_ANIP	(1L<<6)	/* Bit	6: (ro)	Auto Negotiation in Progress */
+#define XM_GP_FRC_INT	(1L<<5)	/* Bit	5: (sc)	Force Interrupt */
+				/* Bit	4:	reserved */
+#define XM_GP_RES_MAC	(1L<<3)	/* Bit	3: (sc)	Reset MAC and FIFOs */
+#define XM_GP_RES_STAT	(1L<<2)	/* Bit	2: (sc)	Reset the statistics module */
+				/* Bit	1:	reserved */
+#define XM_GP_INP_ASS	(1L<<0)	/* Bit	0: (ro) GP Input Pin asserted */
+
+
+/*	XM_IMSK		16 bit r/w	Interrupt Mask Register */
+/*	XM_ISRC		16 bit ro	Interrupt Status Register */
+				/* Bit 15:	reserved */
+#define XM_IS_LNK_AE	(1<<14) /* Bit 14:	Link Asynchronous Event */
+#define XM_IS_TX_ABORT	(1<<13) /* Bit 13:	Transmit Abort, late Col. etc */
+#define XM_IS_FRC_INT	(1<<12) /* Bit 12:	Force INT bit set in GP */
+#define XM_IS_INP_ASS	(1<<11)	/* Bit 11:	Input Asserted, GP bit 0 set */
+#define XM_IS_LIPA_RC	(1<<10)	/* Bit 10:	Link Partner requests config */
+#define XM_IS_RX_PAGE	(1<<9)	/* Bit	9:	Page Received */
+#define XM_IS_TX_PAGE	(1<<8)	/* Bit	8:	Next Page Loaded for Transmit */
+#define XM_IS_AND	(1<<7)	/* Bit	7:	Auto Negotiation Done */
+#define XM_IS_TSC_OV	(1<<6)	/* Bit	6:	Time Stamp Counter Overflow */
+#define XM_IS_RXC_OV	(1<<5)	/* Bit	5:	Rx Counter Event Overflow */
+#define XM_IS_TXC_OV	(1<<4)	/* Bit	4:	Tx Counter Event Overflow */
+#define XM_IS_RXF_OV	(1<<3)	/* Bit	3:	Receive FIFO Overflow */
+#define XM_IS_TXF_UR	(1<<2)	/* Bit	2:	Transmit FIFO Underrun */
+#define XM_IS_TX_COMP	(1<<1)	/* Bit	1:	Frame Tx Complete */
+#define XM_IS_RX_COMP	(1<<0)	/* Bit	0:	Frame Rx Complete */
+
+#define XM_DEF_MSK	(~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE |\
+			XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV |\
+			XM_IS_TXF_UR))
+
+
+/*	XM_HW_CFG	16 bit r/w	Hardware Config Register */
+				/* Bit 15.. 4:	reserved */
+#define	XM_HW_GEN_EOP	(1<<3)	/* Bit	3:	generate End of Packet pulse */
+#define XM_HW_COM4SIG	(1<<2)	/* Bit	2:	use Comma Detect for Sig. Det.*/
+				/* Bit	1:	reserved */
+#define XM_HW_GMII_MD	(1<<0)	/* Bit	0:	GMII Interface selected */
+
+
+/*	XM_TX_LO_WM	16 bit r/w	Tx FIFO Low Water Mark */
+/*	XM_TX_HI_WM	16 bit r/w	Tx FIFO High Water Mark */
+				/* Bit 15..10	reserved */
+#define	XM_TX_WM_MSK	0x01ff	/* Bit	9.. 0	Tx FIFO Watermark bits */
+
+/*	XM_TX_THR	16 bit r/w	Tx Request Threshold */
+/*	XM_HT_THR	16 bit r/w	Host Request Threshold */
+/*	XM_RX_THR	16 bit r/w	Receive Request Threshold */
+				/* Bit 15..11	reserved */
+#define	XM_THR_MSK	0x03ff	/* Bit 10.. 0	Tx FIFO Watermark bits */
+
+
+/*	XM_TX_STAT	32 bit ro	Tx Status LIFO Register */
+#define XM_ST_VALID	(1UL<<31)	/* Bit 31:	Status Valid */
+#define XM_ST_BYTE_CNT	(0x3fffL<<17)	/* Bit 30..17:	Tx frame Length */
+#define XM_ST_RETRY_CNT	(0x1fL<<12)	/* Bit 16..12:	Retry Count */
+#define XM_ST_EX_COL	(1L<<11)	/* Bit 11:	Excessive Collisions */
+#define XM_ST_EX_DEF	(1L<<10)	/* Bit 10:	Excessive Deferral */
+#define XM_ST_BURST	(1L<<9)		/* Bit	9:	p. xmitted in burst md*/
+#define XM_ST_DEFER	(1L<<8)		/* Bit	8:	packet was defered */
+#define XM_ST_BC	(1L<<7)		/* Bit	7:	Broadcast packet */
+#define XM_ST_MC	(1L<<6)		/* Bit	6:	Multicast packet */
+#define XM_ST_UC	(1L<<5)		/* Bit	5:	Unicast packet */
+#define XM_ST_TX_UR	(1L<<4)		/* Bit	4:	FIFO Underrun occured */
+#define XM_ST_CS_ERR	(1L<<3)		/* Bit	3:	Carrier Sense Error */
+#define XM_ST_LAT_COL	(1L<<2)		/* Bit	2:	Late Collision Error */
+#define XM_ST_MUL_COL	(1L<<1)		/* Bit	1:	Multiple Collisions */
+#define XM_ST_SGN_COL	(1L<<0)		/* Bit	0:	Single Collision */
+
+/*	XM_RX_LO_WM	16 bit r/w	Receive Low Water Mark */
+/*	XM_RX_HI_WM	16 bit r/w	Receive High Water Mark */
+				/* Bit 15..11:	reserved */
+#define	XM_RX_WM_MSK	0x03ff	/* Bit 11.. 0:	Rx FIFO Watermark bits */
+
+
+/*	XM_DEV_ID	32 bit ro	Device ID Register */
+#define	XM_DEV_OUI	(0x00ffffffUL<<8)	/* Bit 31..8:	Device OUI */
+#define XM_DEV_REV	(0x07L << 5)		/* Bit	7..5:	Chip Rev Num */
+
+
+/*	XM_MODE		32 bit r/w	Mode Register */
+					/* Bit 31..27:	reserved */
+#define XM_MD_ENA_REJ	(1L<<26)	/* Bit 26:	Enable Frame Reject */
+#define XM_MD_SPOE_E	(1L<<25)	/* Bit 25:	Send Pause on Edge */
+					/* 		extern generated */
+#define XM_MD_TX_REP	(1L<<24)	/* Bit 24:	Transmit Repeater Mode*/
+#define XM_MD_SPOFF_I	(1L<<23)	/* Bit 23:	Send Pause on FIFOfull*/
+					/*		intern generated */
+#define XM_MD_LE_STW	(1L<<22)	/* Bit 22:	Rx Stat Word in Lit En*/
+#define XM_MD_TX_CONT	(1L<<21)	/* Bit 21:	Send Continuous */
+#define XM_MD_TX_PAUSE	(1L<<20)	/* Bit 20: (sc)	Send Pause Frame */
+#define XM_MD_ATS	(1L<<19)	/* Bit 19:	Append Time Stamp */
+#define XM_MD_SPOL_I	(1L<<18)	/* Bit 18:	Send Pause on Low */
+					/*		intern generated */
+#define XM_MD_SPOH_I	(1L<<17)	/* Bit 17:	Send Pause on High */
+					/*		intern generated */
+#define XM_MD_CAP	(1L<<16)	/* Bit 16:	Check Address Pair */
+#define XM_MD_ENA_HSH	(1L<<15)	/* Bit 15:	Enable Hashing */
+#define XM_MD_CSA	(1L<<14)	/* Bit 14:	Check Station Address */
+#define XM_MD_CAA	(1L<<13)	/* Bit 13:	Check Address Array */
+#define XM_MD_RX_MCTRL	(1L<<12)	/* Bit 12:	Rx MAC Control Frames */
+#define XM_MD_RX_RUNT	(1L<<11)	/* Bit 11:	Rx Runt Frames */
+#define XM_MD_RX_IRLE	(1L<<10)	/* Bit 10:	Rx in Range Len Err F */
+#define XM_MD_RX_LONG	(1L<<9)		/* Bit	9:	Rx Long Frames */
+#define XM_MD_RX_CRCE	(1L<<8)		/* Bit	8:	Rx CRC Error Frames */
+#define XM_MD_RX_ERR	(1L<<7)		/* Bit	7:	Rx Error Frames */
+#define XM_MD_DIS_UC	(1L<<6)		/* Bit	6:	Disable Rx Unicast */
+#define XM_MD_DIS_MC	(1L<<5)		/* Bit	5:	Disable Rx Multicast */
+#define XM_MD_DIS_BC	(1L<<4)		/* Bit	4:	Disable Rx Boradcast */
+#define XM_MD_ENA_PROM	(1L<<3)		/* Bit	3:	Enable Promiscuous */
+#define XM_MD_ENA_BE	(1L<<2)		/* Bit	2:	Enable Big Endian */
+#define XM_MD_FTF	(1L<<1)		/* Bit	1: (sc)	Flush Tx FIFO */
+#define XM_MD_FRF	(1L<<0)		/* Bit	0: (sc)	Flush Rx FIFO */
+
+#define	XM_PAUSE_MODE	(XM_MD_SPOE_E | XM_MD_SPOL_I | XM_MD_SPOH_I)
+#define XM_DEF_MODE	(XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\
+			 XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA |\
+			 XM_MD_CAA)
+
+/*	XM_STAT_CMD	16 bit r/w	Statistics Command Register */
+				/* Bit 16..6:	reserved */
+#define XM_SC_SNP_RXC	(1<<5)	/* Bit	5: (sc)	Snap Rx Counters */
+#define XM_SC_SNP_TXC	(1<<4)	/* Bit	4: (sc)	Snap Tx Counters */
+#define XM_SC_CP_RXC	(1<<3)	/* Bit	3: 	Copy Rx Counters Continuously */
+#define XM_SC_CP_TXC	(1<<2)	/* Bit	2:	Copy Tx Counters Continuously */
+#define XM_SC_CLR_RXC	(1<<1)	/* Bit	1: (sc)	Clear Rx Counters */
+#define XM_SC_CLR_TXC	(1<<0)	/* Bit	0: (sc) Clear Tx Counters */
+
+
+/*	XM_RX_CNT_EV	32 bit ro	Rx Counter Event Register */
+/*	XM_RX_EV_MSK	32 bit r/w	Rx Counter Event Mask */
+#define	XMR_MAX_SZ_OV	(1UL<<31)	/* Bit 31:	1024-MaxSize Rx Cnt Ov*/
+#define XMR_1023B_OV	(1L<<30)	/* Bit 30:	512-1023Byte Rx Cnt Ov*/
+#define XMR_511B_OV	(1L<<29)	/* Bit 29:	256-511 Byte Rx Cnt Ov*/
+#define XMR_255B_OV	(1L<<28)	/* Bit 28:	128-255 Byte Rx Cnt Ov*/
+#define XMR_127B_OV	(1L<<27)	/* Bit 27:	65-127 Byte Rx Cnt Ov */
+#define XMR_64B_OV	(1L<<26)	/* Bit 26:	64 Byte Rx Cnt Ov */
+#define XMR_UTIL_OV	(1L<<25)	/* Bit 25:	Rx Util Cnt Overflow */
+#define XMR_UTIL_UR	(1L<<24)	/* Bit 24:	Rx Util Cnt Underrun */
+#define XMR_CEX_ERR_OV	(1L<<23)	/* Bit 23:	CEXT Err Cnt Ov */
+					/* Bit 22:	reserved */
+#define XMR_FCS_ERR_OV	(1L<<21)	/* Bit 21:	Rx FCS Error Cnt Ov */
+#define XMR_LNG_ERR_OV	(1L<<20)	/* Bit 20:	Rx too Long Err Cnt Ov*/
+#define XMR_RUNT_OV	(1L<<19)	/* Bit 19:	Runt Event Cnt Ov */
+#define XMR_SHT_ERR_OV	(1L<<18)	/* Bit 18:	Rx Short Ev Err Cnt Ov*/
+#define XMR_SYM_ERR_OV	(1L<<17)	/* Bit 17:	Rx Sym Err Cnt Ov */
+					/* Bit 16:	reserved */
+#define XMR_CAR_ERR_OV	(1L<<15)	/* Bit 15:	Rx Carr Ev Err Cnt Ov */
+#define XMR_JAB_PKT_OV	(1L<<14)	/* Bit 14:	Rx Jabb Packet Cnt Ov */
+#define XMR_FIFO_OV	(1L<<13)	/* Bit 13:	Rx FIFO Ov Ev Cnt Ov */
+#define XMR_FRA_ERR_OV	(1L<<12)	/* Bit 12:	Rx Framing Err Cnt Ov */
+#define XMR_FMISS_OV	(1L<<11)	/* Bit 11:	Rx Missed Ev Cnt Ov */
+#define XMR_BURST	(1L<<10)	/* Bit 10:	Rx Burst Event Cnt Ov */
+#define XMR_INV_MOC	(1L<<9)		/* Bit	9:	Rx with inv. MAC OC Ov*/
+#define XMR_INV_MP	(1L<<8)		/* Bit	8:	Rx inv Pause Frame Ov */
+#define XMR_MCTRL_OV	(1L<<7)		/* Bit	7:	Rx MAC Ctrl-F Cnt Ov */
+#define XMR_MPAUSE_OV	(1L<<6)		/* Bit	6:	Rx Pause MAC Ctrl-F Ov*/
+#define XMR_UC_OK_OV	(1L<<5)		/* Bit	5:	Rx Unicast Frame CntOv*/
+#define XMR_MC_OK_OV	(1L<<4)		/* Bit	4:	Rx Multicast Cnt Ov */
+#define XMR_BC_OK_OV	(1L<<3)		/* Bit	3:	Rx Broadcast Cnt Ov */
+#define XMR_OK_LO_OV	(1L<<2)		/* Bit	2:	Octets Rx OK Low CntOv*/
+#define XMR_OK_HI_OV	(1L<<1)		/* Bit	1:	Octets Rx OK Hi Cnt Ov*/
+#define XMR_OK_OV	(1L<<0)		/* Bit	0:	Frames Received Ok Ov */
+
+#define XMR_DEF_MSK	0x00000006L	/* all bits excepting 1 and 2 */
+
+/*	XM_TX_CNT_EV	32 bit ro	Tx Counter Event Register */
+/*	XM_TX_EV_MSK	32 bit r/w	Tx Counter Event Mask */
+					/* Bit 31..26:	reserved */
+#define XMT_MAX_SZ_OV	(1L<<25)	/* Bit 25:	1024-MaxSize Tx Cnt Ov*/
+#define XMT_1023B_OV	(1L<<24)	/* Bit 24:	512-1023Byte Tx Cnt Ov*/
+#define XMT_511B_OV	(1L<<23)	/* Bit 23:	256-511 Byte Tx Cnt Ov*/
+#define XMT_255B_OV	(1L<<22)	/* Bit 22:	128-255 Byte Tx Cnt Ov*/
+#define XMT_127B_OV	(1L<<21)	/* Bit 21:	65-127 Byte Tx Cnt Ov */
+#define XMT_64B_OV	(1L<<20)	/* Bit 20:	64 Byte Tx Cnt Ov */
+#define XMT_UTIL_OV	(1L<<19)	/* Bit 19:	Tx Util Cnt Overflow */
+#define XMT_UTIL_UR	(1L<<18)	/* Bit 18:	Tx Util Cnt Underrun */
+#define XMT_CS_ERR_OV	(1L<<17)	/* Bit 17:	Tx Carr Sen Err Cnt Ov*/
+#define XMT_FIFO_UR_OV	(1L<<16)	/* Bit 16:	Tx FIFO Ur Ev Cnt Ov */
+#define XMT_EX_DEF_OV	(1L<<15)	/* Bit 15:	Tx Ex Deferall Cnt Ov */
+#define XMT_DEF		(1L<<14)	/* Bit 14:	Tx Deferred Cnt Ov */
+#define XMT_LAT_COL_OV	(1L<<13)	/* Bit 13:	Tx Late Col Cnt Ov */
+#define XMT_ABO_COL_OV	(1L<<12)	/* Bit 12:	Tx abo dueto Ex Col Ov*/
+#define XMT_MUL_COL_OV	(1L<<11)	/* Bit 11:	Tx Mult Col Cnt Ov */
+#define XMT_SNG_COL	(1L<<10)	/* Bit 10:	Tx Single Col Cnt Ov */
+#define XMT_MCTRL_OV	(1L<<9)		/* Bit	9:	Tx MAC Ctrl Counter Ov*/
+#define XMT_MPAUSE	(1L<<8)		/* Bit	8:	Tx Pause MAC Ctrl-F Ov*/
+#define XMT_BURST	(1L<<7)		/* Bit	7:	Tx Burst Event Cnt Ov */
+#define XMT_LONG	(1L<<6)		/* Bit	6:	Tx Long Frame Cnt Ov */
+#define XMT_UC_OK_OV	(1L<<5)		/* Bit	5:	Tx Unicast Cnt Ov */
+#define XMT_MC_OK_OV	(1L<<4)		/* Bit	4:	Tx Multicast Cnt Ov */
+#define XMT_BC_OK_OV	(1L<<3)		/* Bit	3:	Tx Broadcast Cnt Ov */
+#define XMT_OK_LO_OV	(1L<<2)		/* Bit	2:	Octets Tx OK Low CntOv*/
+#define XMT_OK_HI_OV	(1L<<1)		/* Bit	1:	Octets Tx OK Hi Cnt Ov*/
+#define XMT_OK_OV	(1L<<0)		/* Bit	0:	Frames Tx Ok Ov */
+
+#define XMT_DEF_MSK	0x00000006L	/* all bits excepting 1 and 2 */
+
+/*
+ * Receive Frame Status Encoding
+ */
+#define XMR_FS_LEN	(0x3fffUL<<18)	/* Bit 31..18:	Rx Frame Length */
+#define XMR_FS_2L_VLAN	(1L<<17)	/* Bit 17:	tagged wh 2Lev VLAN ID*/
+#define XMR_FS_1L_VLAN	(1L<<16)	/* Bit 16:	tagged wh 1Lev VLAN ID*/
+#define XMR_FS_BC	(1L<<15)	/* Bit 15:	Broadcast Frame */
+#define XMR_FS_MC	(1L<<14)	/* Bit 14:	Multicast Frame */
+#define XMR_FS_UC	(1L<<13)	/* Bit 13:	Unicast Frame */
+					/* Bit 12:	reserved */
+#define XMR_FS_BURST	(1L<<11)	/* Bit 11:	Burst Mode */
+#define XMR_FS_CEX_ERR	(1L<<10)	/* Bit 10:	Carrier Ext. Error */
+#define XMR_FS_802_3	(1L<<9)		/* Bit	9:	802.3 Frame */
+#define XMR_FS_COL_ERR	(1L<<8)		/* Bit	8:	Collision Error */
+#define XMR_FS_CAR_ERR	(1L<<7)		/* Bit	7:	Carrier Event Error */
+#define XMR_FS_LEN_ERR	(1L<<6)		/* Bit	6:	In-Range Length Error */
+#define XMR_FS_FRA_ERR	(1L<<5)		/* Bit	5:	Framing Error */
+#define XMR_FS_RUNT	(1L<<4)		/* Bit	4:	Runt Error */
+#define XMR_FS_LNG_ERR	(1L<<3)		/* Bit	3:	Gaint Error */
+#define XMR_FS_FCS_ERR	(1L<<2)		/* Bit	2:	Frame Check Sequ Err */
+#define XMR_FS_ERR	(1L<<1)		/* Bit	1:	Frame Error */
+#define XMR_FS_MCTRL	(1L<<0)		/* Bit	0:	MAC Control Packet */
+
+/*
+ * XMR_FS_ERR will be set if
+ *	XMR_FS_FCS_ERR, XMR_FS_LNG_ERR, XMR_FS_RUNT,
+ *	XMR_FS_FRA_ERR, XMR_FS_LEN_ERR, or XMR_FS_CEX_ERR
+ * is set. XMR_FS_LNG_ERR and XMR_FS_LEN_ERR will issue
+ * XMR_FS_ERR unless the corresponding bit in the Receive Command
+ * Register is set.
+ */
+#define XMR_FS_ANY_ERR	XMR_FS_ERR
+
+/*----------------------------------------------------------------------------*/
+/*
+ * XMAC-PHY Registers, indirect addressed over the XMAC
+ */
+#define	PHY_XMAC_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define	PHY_XMAC_STAT		0x01	/* 16 bit r/w	PHY Status Register */
+#define	PHY_XMAC_ID0		0x02	/* 16 bit ro	PHY ID0 Register */
+#define	PHY_XMAC_ID1		0x03	/* 16 bit ro	PHY ID1 Register */
+#define	PHY_XMAC_AUNE_ADV	0x04	/* 16 bit r/w	Autoneg Advertisement */
+#define	PHY_XMAC_AUNE_LP	0x05	/* 16 bit ro	Link Partner Abi Reg */
+#define	PHY_XMAC_AUNE_EXP	0x06	/* 16 bit ro	Autoneg Expansion Reg */
+#define	PHY_XMAC_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define	PHY_XMAC_NEPG_LP	0x08	/* 16 bit ro	Next Page Link P Reg */
+	/* 0x09 - 0x0e:		reserved */
+#define	PHY_XMAC_EXT_STAT	0x0f	/* 16 bit ro	Ext Status Register */
+#define	PHY_XMAC_RES_ABI	0x10	/* 16 bit ro	PHY Resolved Ability */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Broadcom-PHY Registers, indirect addressed over XMAC
+ */
+#define	PHY_BCOM_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define	PHY_BCOM_STAT		0x01	/* 16 bit ro	PHY Status Register */
+#define	PHY_BCOM_ID0		0x02	/* 16 bit ro	PHY ID0 Register */
+#define	PHY_BCOM_ID1		0x03	/* 16 bit ro	PHY ID1 Register */
+#define	PHY_BCOM_AUNE_ADV	0x04	/* 16 bit r/w	Autoneg Advertisement */
+#define	PHY_BCOM_AUNE_LP	0x05	/* 16 bit ro	Link Part Ability Reg */
+#define	PHY_BCOM_AUNE_EXP	0x06	/* 16 bit ro	Autoneg Expansion Reg */
+#define	PHY_BCOM_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define	PHY_BCOM_NEPG_LP	0x08	/* 16 bit ro	Next Page Link P Reg */
+	/* Broadcom-specific registers */
+#define	PHY_BCOM_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Ctrl Reg */
+#define	PHY_BCOM_1000T_STAT	0x0a	/* 16 bit ro	1000Base-T Status Reg */
+	/* 0x0b - 0x0e:		reserved */
+#define	PHY_BCOM_EXT_STAT	0x0f	/* 16 bit ro	Extended Status Reg */
+#define	PHY_BCOM_P_EXT_CTRL	0x10	/* 16 bit r/w	PHY Extended Ctrl Reg */
+#define	PHY_BCOM_P_EXT_STAT	0x11	/* 16 bit ro	PHY Extended Stat Reg */
+#define	PHY_BCOM_RE_CTR		0x12	/* 16 bit r/w	Receive Error Counter */
+#define	PHY_BCOM_FC_CTR		0x13	/* 16 bit r/w	False Carr Sense Cnt */
+#define	PHY_BCOM_RNO_CTR	0x14	/* 16 bit r/w	Receiver NOT_OK Cnt */
+	/* 0x15 - 0x17:		reserved */
+#define	PHY_BCOM_AUX_CTRL	0x18	/* 16 bit r/w	Auxiliary Control Reg */
+#define	PHY_BCOM_AUX_STAT	0x19	/* 16 bit ro	Auxiliary Stat Summary*/
+#define	PHY_BCOM_INT_STAT	0x1a	/* 16 bit ro	Interrupt Status Reg */
+#define	PHY_BCOM_INT_MASK	0x1b	/* 16 bit r/w	Interrupt Mask Reg */
+	/* 0x1c:		reserved */
+	/* 0x1d - 0x1f:		test registers */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Level One-PHY Registers, indirect addressed over XMAC
+ */
+#define	PHY_LONE_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define	PHY_LONE_STAT		0x01	/* 16 bit ro	PHY Status Register */
+#define	PHY_LONE_ID0		0x02	/* 16 bit ro	PHY ID0 Register */
+#define	PHY_LONE_ID1		0x03	/* 16 bit ro	PHY ID1 Register */
+#define	PHY_LONE_AUNE_ADV	0x04	/* 16 bit r/w	Autoneg Advertisement */
+#define	PHY_LONE_AUNE_LP	0x05	/* 16 bit ro	Link Part Ability Reg */
+#define	PHY_LONE_AUNE_EXP	0x06	/* 16 bit ro	Autoneg Expansion Reg */
+#define	PHY_LONE_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define	PHY_LONE_NEPG_LP	0x08	/* 16 bit ro	Next Page Link Partner*/
+	/* Level One-specific registers */
+#define	PHY_LONE_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Control Reg*/
+#define	PHY_LONE_1000T_STAT	0x0a	/* 16 bit ro	1000Base-T Status Reg */
+	/* 0x0b -0x0e:		reserved */
+#define	PHY_LONE_EXT_STAT	0x0f	/* 16 bit ro	Extended Status Reg */
+#define	PHY_LONE_PORT_CFG	0x10	/* 16 bit r/w	Port Configuration Reg*/
+#define	PHY_LONE_Q_STAT		0x11	/* 16 bit ro	Quick Status Reg */
+#define	PHY_LONE_INT_ENAB	0x12	/* 16 bit r/w	Interrupt Enable Reg */
+#define	PHY_LONE_INT_STAT	0x13	/* 16 bit ro	Interrupt Status Reg */
+#define	PHY_LONE_LED_CFG	0x14	/* 16 bit r/w	LED Configuration Reg */
+#define	PHY_LONE_PORT_CTRL	0x15	/* 16 bit r/w	Port Control Reg */
+#define	PHY_LONE_CIM		0x16	/* 16 bit ro	CIM Reg */
+	/* 0x17 -0x1c:		reserved */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * National-PHY Registers, indirect addressed over XMAC
+ */
+#define	PHY_NAT_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define	PHY_NAT_STAT		0x01	/* 16 bit r/w	PHY Status Register */
+#define	PHY_NAT_ID0		0x02	/* 16 bit ro	PHY ID0 Register */
+#define	PHY_NAT_ID1		0x03	/* 16 bit ro	PHY ID1 Register */
+#define	PHY_NAT_AUNE_ADV	0x04	/* 16 bit r/w	Autonegotiation Advertisement */
+#define	PHY_NAT_AUNE_LP		0x05	/* 16 bit ro	Link Partner Ability Reg */
+#define	PHY_NAT_AUNE_EXP	0x06	/* 16 bit ro	Autonegotiation Expansion Reg */
+#define	PHY_NAT_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define	PHY_NAT_NEPG_LP		0x08	/* 16 bit ro	Next Page Link Partner Reg */
+	/* National-specific registers */
+#define	PHY_NAT_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Control Reg */
+#define	PHY_NAT_1000T_STAT	0x0a	/* 16 bit ro	1000Base-T Status Reg */
+	/* 0x0b -0x0e:		reserved */
+#define	PHY_NAT_EXT_STAT	0x0f	/* 16 bit ro	Extended Status Register */
+#define	PHY_NAT_EXT_CTRL1	0x10	/* 16 bit ro	Extended Control Reg1 */
+#define	PHY_NAT_Q_STAT1		0x11	/* 16 bit ro	Quick Status Reg1 */
+#define	PHY_NAT_10B_OP		0x12	/* 16 bit ro	10Base-T Operations Reg */
+#define	PHY_NAT_EXT_CTRL2	0x13	/* 16 bit ro	Extended Control Reg1 */
+#define	PHY_NAT_Q_STAT2		0x14	/* 16 bit ro	Quick Status Reg2 */
+	/* 0x15 -0x18:		reserved */
+#define	PHY_NAT_PHY_ADDR	0x19	/* 16 bit ro	PHY Address Register */
+
+
+/*----------------------------------------------------------------------------*/
+
+/*
+ * PHY bit definitions
+ * Bits defined as PHY_X_..., PHY_B_..., PHY_L_... or PHY_N_... are
+ * Xmac/Broadcom/LevelOne/National-specific.
+ * All other are general.
+ */
+
+/*****	PHY_XMAC_CTRL	16 bit r/w	PHY Control Register *****/
+/*****	PHY_BCOM_CTRL	16 bit r/w	PHY Control Register *****/
+/*****	PHY_LONE_CTRL	16 bit r/w	PHY Control Register *****/
+#define	PHY_CT_RESET	(1<<15)	/* Bit 15: (sc)	clear all PHY releated regs */
+#define PHY_CT_LOOP	(1<<14)	/* Bit 14:	enable Loopback over PHY */
+#define PHY_CT_SPS_LSB	(1<<13) /* Bit 13: (BC,L1) Speed select, lower bit */
+#define PHY_CT_ANE	(1<<12)	/* Bit 12:	Autonegotiation Enabled */
+#define PHY_CT_PDOWN	(1<<11)	/* Bit 11: (BC,L1) Power Down Mode */
+#define PHY_CT_ISOL	(1<<10)	/* Bit 10: (BC,L1) Isolate Mode */
+#define PHY_CT_RE_CFG	(1<<9)	/* Bit	9: (sc) Restart Autonegotiation */
+#define PHY_CT_DUP_MD	(1<<8)	/* Bit	8:	Duplex Mode */
+#define PHY_CT_COL_TST	(1<<7)	/* Bit	7: (BC,L1) Collsion Test enabled */
+#define PHY_CT_SPS_MSB	(1<<6)	/* Bit	6: (BC,L1) Speed select, upper bit */
+				/* Bit	5..0:	reserved */
+
+#define PHY_B_CT_SP1000	(1<<6)	/* Bit  6:	enable speed of 1000 MBit/s */
+#define PHY_B_CT_SP100	(1<<13)	/* Bit 13:	enable speed of  100 MBit/s */
+#define PHY_B_CT_SP10	(0)	/* Bit 6/13 not set,	speed of  10 MBit/s */
+
+#define PHY_L_CT_SP1000	(1<<6)	/* Bit  6:      enable speed of 1000 MBit/s */
+#define PHY_L_CT_SP100	(1<<13)	/* Bit 13:      enable speed of  100 MBit/s */
+#define PHY_L_CT_SP10	(0)	/* Bit 6/13 not set,    speed of  10 MBit/s */
+
+
+/*****	PHY_XMAC_STAT	16 bit r/w	PHY Status Register *****/
+/*****	PHY_BCOM_STAT	16 bit r/w	PHY Status Register *****/
+/*****	PHY_LONE_STAT	16 bit r/w	PHY Status Register *****/
+				/* Bit 15..9:	reserved */
+				/*	(BC/L1) 100/10 MBit/s cap bits ignored*/
+#define PHY_ST_EXT_ST	(1<<8)	/* Bit	8:	Extended Status Present */
+				/* Bit	7:	reserved */
+#define PHY_ST_PRE_SUB	(1<<6)	/* Bit	6: (BC/L1) preamble suppression */
+#define PHY_ST_AN_OVER	(1<<5)	/* Bit	5:	Autonegotiation Over */
+#define PHY_ST_REM_FLT	(1<<4)	/* Bit	4:	Remode Fault Condition Occured*/
+#define PHY_ST_AN_CAP	(1<<3)	/* Bit	3:	Autonegotiation Capability */
+#define PHY_ST_LSYNC	(1<<2)	/* Bit	2:	Link Synchronized */
+#define PHY_ST_JAP_DET	(1<<1)	/* Bit	1: (BC/L1) Japper Detected */
+#define PHY_ST_EXT_REG	(1<<0)	/* Bit	0:	Extended Register available */
+
+
+/*	PHY_XMAC_ID1		16 bit ro	PHY ID1 Register */
+/*	PHY_BCOM_ID1		16 bit ro	PHY ID1 Register */
+/*	PHY_LONE_ID1		16 bit ro	PHY ID1 Register */
+#define	PHY_I1_OUI	(0x3f<<10)	/* Bit 15..10:	Organiz. Unique ID */
+#define PHY_I1_MOD_NUM	(0x3f<<4)	/* Bit	9.. 4:	Model Number */
+#define PHY_I1_REV	(0x0f<<0)	/* Bit	3.. 0:	Revision Number */
+
+
+/*****	PHY_XMAC_AUNE_ADV	16 bit r/w	Autoneg Advertisement *****/
+/*****	PHY_XMAC_AUNE_LP	16 bit ro	Link Partner Ability Reg *****/
+#define PHY_AN_NXT_PG	(1<<15)	/* Bit 15:	Request Next Page */
+#define PHY_X_AN_ACK	(1<<14)	/* Bit 14: (ro)	Acknowledge Received */
+#define PHY_X_AN_RFB	(3<<12)	/* Bit 13..12:	Remode Fault Bits */
+				/* Bit 11.. 9:	reserved */
+#define PHY_X_AN_PAUSE	(3<<7)	/* Bit	8.. 7:	Pause Bits */
+#define PHY_X_AN_HD	(1<<6)	/* Bit	6:	Half Duplex */
+#define PHY_X_AN_FD	(1<<5)	/* Bit	5:	Full Duplex */
+				/* Bit	4.. 0:	reserved */
+
+/*****	PHY_BCOM_AUNE_ADV	16 bit r/w	Autoneg Advertisement *****/
+/*****	PHY_BCOM_AUNE_LP	16 bit ro	Link Partner Ability Reg *****/
+/*	PHY_AN_NXT_PG	(see XMAC) Bit 15:	Request Next Page */
+				/* Bit 14:	reserved */
+#define PHY_B_AN_RF	(1<<13)	/* Bit 13:	Remote Fault */
+				/* Bit 12:	reserved */
+#define PHY_B_AN_ASP	(1<<11)	/* Bit 11:	Asymetric Pause */
+#define PHY_B_AN_PC	(1<<10)	/* Bit 10:	Pause Capable */
+				/* Bit	9..5:	100/10 BT cap bits ingnored */
+#define PHY_B_AN_SEL	(0x1f<<0)/* Bit 4..0:	Selector Field, 00001=Ethernet*/
+
+/*****	PHY_LONE_AUNE_ADV	16 bit r/w	Autoneg Advertisement *****/
+/*****	PHY_LONE_AUNE_LP	16 bit ro	Link Partner Ability Reg *****/
+/*	PHY_AN_NXT_PG	(see XMAC) Bit 15:	Request Next Page */
+				/* Bit 14:	reserved */
+#define PHY_L_AN_RF	(1<<13)	/* Bit 13:	Remote Fault */
+				/* Bit 12:	reserved */
+#define PHY_L_AN_ASP	(1<<11)	/* Bit 11:	Asymetric Pause */
+#define PHY_L_AN_PC	(1<<10)	/* Bit 10:	Pause Capable */
+				/* Bit	9..5:	100/10 BT cap bits ingnored */
+#define PHY_L_AN_SEL	(0x1f<<0)/* Bit 4..0:	Selector Field, 00001=Ethernet*/
+
+/*****	PHY_NAT_AUNE_ADV	16 bit r/w	Autoneg Advertisement *****/
+/*****	PHY_NAT_AUNE_LP	16 bit ro	Link Partner Ability Reg *****/
+/*	PHY_AN_NXT_PG	(see XMAC) Bit 15:	Request Next Page */
+				/* Bit 14:	reserved */
+#define PHY_N_AN_RF	(1<<13)	/* Bit 13:	Remote Fault */
+				/* Bit 12:	reserved */
+#define PHY_N_AN_100F	(1<<11)	/* Bit 11:	100Base-T2 FD Support */
+#define PHY_N_AN_100H	(1<<10)	/* Bit 10:	100Base-T2 HD Support */
+				/* Bit	9..5:	100/10 BT cap bits ingnored */
+#define PHY_N_AN_SEL	(0x1f<<0)/* Bit 4..0:	Selector Field, 00001=Ethernet*/
+
+/* field type definition for PHY_x_AN_SEL */
+#define PHY_SEL_TYPE	0x01	/* 00001 = Ethernet */
+
+/*****	PHY_XMAC_AUNE_EXP	16 bit ro	Autoneg Expansion Reg *****/
+				/* Bit 15..4:	reserved */
+#define PHY_AN_LP_NP	(1<<3)	/* Bit	3:	Link Partner can Next Page */
+#define PHY_AN_LOC_NP	(1<<2)	/* Bit	2:	Local PHY can Next Page */
+#define PHY_AN_RX_PG	(1<<1)	/* Bit	1:	Page Received */
+				/* Bit	0:	reserved */
+
+/*****	PHY_BCOM_AUNE_EXP	16 bit ro	Autoneg Expansion Reg *****/
+				/* Bit 15..5:	reserved */
+#define PHY_B_AN_PDF	(1<<4)	/* Bit	4:	Parallel Detection Fault */
+/*	PHY_AN_LP_NP	(see XMAC) Bit	3:	Link Partner can Next Page */
+/*	PHY_AN_LOC_NP	(see XMAC) Bit	2:	Local PHY can Next Page */
+/*	PHY_AN_RX_PG	(see XMAC) Bit	1:	Page Received */
+#define PHY_B_AN_LP_CAP	(1<<0)	/* Bit	0:	Link Partner Autoneg Cap. */ 	
+
+/*****	PHY_LONE_AUNE_EXP	16 bit ro	Autoneg Expansion Reg *****/
+#define PHY_L_AN_BP	(1<<5)	/* Bit	5:	Base Page Indication */
+#define PHY_L_AN_PDF	(1<<4)	/* Bit	4:	Parallel Detection Fault */
+/*	PHY_AN_LP_NP	(see XMAC) Bit	3:	Link Partner can Next Page */
+/*	PHY_AN_LOC_NP	(see XMAC) Bit	2:	Local PHY can Next Page */
+/*	PHY_AN_RX_PG	(see XMAC) Bit	1:	Page Received */
+#define PHY_B_AN_LP_CAP	(1<<0)	/* Bit	0:	Link Partner Autoneg Cap. */ 	
+
+
+/*****	PHY_XMAC_NEPG		16 bit r/w	Next Page Register *****/
+/*****	PHY_BCOM_NEPG		16 bit r/w	Next Page Register *****/
+/*****	PHY_LONE_NEPG		16 bit r/w	Next Page Register *****/
+/*****	PHY_XMAC_NEPG_LP	16 bit ro	Next Page Link Partner *****/
+/*****	PHY_BCOM_NEPG_LP	16 bit ro	Next Page Link Partner *****/
+/*****	PHY_LONE_NEPG_LP	16 bit ro	Next Page Link Partner *****/
+#define PHY_NP_MORE	(1<<15)	/* Bit 15:	More, Next Pages to follow */
+#define PHY_NP_ACK1	(1<<14)	/* Bit 14: (ro)	Ack 1, for receiving a message*/
+#define PHY_NP_MSG_VAL	(1<<13)	/* Bit 13:	Message Page valid */
+#define PHY_NP_ACK2	(1<<12)	/* Bit 12:	Ack 2, comply with msg content*/
+#define PHY_NP_TOG	(1<<11)	/* Bit 11:	Toggle Bit, ensure sync */
+#define PHY_NP_MSG	0x07ff	/* Bit 10..0:	Message from/to Link Partner */
+
+/*
+ * XMAC-Specific
+ */
+/*****	PHY_XMAC_EXT_STAT	16 bit r/w	Extended Status Register *****/
+#define PHY_X_EX_FD	(1<<15)	/* Bit 15:	Device Supports Full Duplex */
+#define PHY_X_EX_HD	(1<<14)	/* Bit 14:	Device Supports Half Duplex */
+				/* Bit 13..0:	reserved */
+
+/*****	PHY_XMAC_RES_ABI	16 bit ro	PHY Resolved Ability *****/
+				/* Bit 15..9:	reserved */
+#define PHY_X_RS_PAUSE	(3<<7)	/* Bit	8..7:	selected Pause Mode */
+#define PHY_X_RS_HD	(1<<6)	/* Bit	6:	Half Duplex Mode selected */
+#define PHY_X_RS_FD	(1<<5)	/* Bit	5:	Full Duplex Mode selected */
+#define PHY_X_RS_ABLMIS (1<<4)	/* Bit	4:	duplex or pause cap mismatch */
+#define PHY_X_RS_PAUMIS (1<<3)	/* Bit	3:	pause capability missmatch */
+				/* Bit	2..0:	reserved */
+/*
+ * Remote Fault Bits (PHY_X_AN_RFB) encoding
+ */
+#define X_RFB_OK	(0<<12)	/* Bit 12..13	No errors, Link OK */
+#define X_RFB_LF	(1<<12)	/* Bit 12..13	Link Failure */
+#define X_RFB_OFF	(2<<12)	/* Bit 12..13	Offline */
+#define X_RFB_AN_ERR	(3<<12)	/* Bit 12..13	Autonegotiation Error */
+
+/*
+ * Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding
+ */
+#define PHY_X_P_NO_PAUSE	(0<<7)	/* Bit	8..7:	no Pause Mode */
+#define PHY_X_P_SYM_MD		(1<<7)	/* Bit	8..7:	symmetric Pause Mode */
+#define PHY_X_P_ASYM_MD		(2<<7)	/* Bit	8..7:	asymmetric Pause Mode */
+#define PHY_X_P_BOTH_MD		(3<<7)	/* Bit	8..7:	both Pause Mode */
+
+
+/*
+ * Broadcom-Specific
+ */
+/***** PHY_BCOM_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+#define PHY_B_1000C_TEST	(7<<13)	/* Bit	15..13:	Test Modes */
+#define PHY_B_1000C_MSE		(1<<12)	/* Bit	12:	Master/Slave Enable */
+#define PHY_B_1000C_MSC		(1<<11)	/* Bit	11:	M/S Configuration */
+#define PHY_B_1000C_RD		(1<<10)	/* Bit	10:	Repeater/DTE */
+#define PHY_B_1000C_AFD		(1<<9)	/* Bit	9:	Advertise Full Duplex */
+#define PHY_B_1000C_AHD		(1<<8)	/* Bit	8:	Advertise Half Duplex */
+					/* Bit	7..0:	reserved */
+
+/***** PHY_BCOM_1000T_STAT	16 bit ro	1000Base-T Status Reg *****/
+#define PHY_B_1000S_MSF		(1<<15)	/* Bit	15:	Master/Slave Fault */
+#define PHY_B_1000S_MSR		(1<<14)	/* Bit	14:	Master/Slave Result */
+#define PHY_B_1000S_LRS		(1<<13)	/* Bit	13:	Local Receiver Status */
+#define PHY_B_1000S_RRS		(1<<12)	/* Bit	12:	Remote Receiver Status */
+#define PHY_B_1000S_LP_FD	(1<<11)	/* Bit	11:	Link Partner can FD */
+#define PHY_B_1000S_LP_HD	(1<<10)	/* Bit	10:	Link Partner can HD */
+					/* Bit	9..8:	reserved */
+#define PHY_B_1000S_IEC		(255<<0)/* Bit	7..0:	Idle Error Count */
+
+/*****	PHY_BCOM_EXT_STAT	16 bit ro	Extended Status Register *****/
+#define PHY_B_ES_X_FD_CAP	(1<<15)	/* Bit 15:	1000Base-X FD capable */
+#define PHY_B_ES_X_HD_CAP	(1<<14)	/* Bit 14:	1000Base-X HD capable */
+#define PHY_B_ES_T_FD_CAP	(1<<13)	/* Bit 13:	1000Base-T FD capable */
+#define PHY_B_ES_T_HD_CAP	(1<<12)	/* Bit 12:	1000Base-T HD capable */
+					/* Bit 11..0:	reserved */
+
+/*****	PHY_BCOM_P_EXT_CTRL	16 bit r/w	PHY Extended Control Reg *****/
+#define PHY_B_PEC_MAC_PHY	(1<<15)	/* Bit 15:	10BIT/GMI-Interface */
+#define PHY_B_PEC_DIS_CROSS	(1<<14)	/* Bit 14:	Disable MDI Crossover */
+#define PHY_B_PEC_TX_DIS	(1<<13)	/* Bit 13:	Tx output Disabled */
+#define PHY_B_PEC_INT_DIS	(1<<12)	/* Bit 12:	Interrupts Disabled */
+#define PHY_B_PEC_F_INT		(1<<11)	/* Bit 11:	Force Interrupt */
+#define PHY_B_PEC_BY_45		(1<<10)	/* Bit 10:	Bypass 4B5B-Decoder */
+#define PHY_B_PEC_BY_SCR	(1<<9)	/* Bit 9:	Bypass Scrambler */
+#define PHY_B_PEC_BY_MLT3	(1<<8)	/* Bit 8:	Bypass MLT3 Encoder */
+#define PHY_B_PEC_BY_RXA	(1<<7)	/* Bit 7:	Bypass Rx Alignm. */
+#define PHY_B_PEC_RES_SCR	(1<<6)	/* Bit 6:	Reset Scrambler */
+#define PHY_B_PEC_EN_LTR	(1<<5)	/* Bit 5:	Ena LED Traffic Mode */
+#define PHY_B_PEC_LED_ON	(1<<4)	/* Bit 4:	Force LED's on */
+#define PHY_B_PEC_LED_OFF	(1<<3)	/* Bit 3:	Force LED's off */
+#define PHY_B_PEC_EX_IPG	(1<<2)	/* Bit 2:	Extend Tx IPG Mode */
+#define PHY_B_PEC_3_LED		(1<<1)	/* Bit 1:	Three Link LED mode */
+#define PHY_B_PEC_HIGH_LA	(1<<0)	/* Bit 0:	GMII Fifo Elasticy */
+
+/*****	PHY_BCOM_P_EXT_STAT	16 bit ro	PHY Extended Status Reg *****/
+					/* Bit 15..14:	reserved */
+#define PHY_B_PES_CROSS_STAT	(1<<13)	/* Bit 13:	MDI Crossover Status */
+#define PHY_B_PES_INT_STAT	(1<<12)	/* Bit 12:	Interrupt Status */
+#define PHY_B_PES_RRS		(1<<11)	/* Bit 11:	Remote Receiver Stat. */
+#define PHY_B_PES_LRS		(1<<10)	/* Bit 10:	Local Receiver Stat. */
+#define PHY_B_PES_LOCKED	(1<<9)	/* Bit 9:	Locked */
+#define PHY_B_PES_LS		(1<<8)	/* Bit 8:	Link Status */
+#define PHY_B_PES_RF		(1<<7)	/* Bit 7:	Remote Fault */
+#define PHY_B_PES_CE_ER		(1<<6)	/* Bit 6:	Carrier Ext Error */
+#define PHY_B_PES_BAD_SSD	(1<<5)	/* Bit 5:	Bad SSD */
+#define PHY_B_PES_BAD_ESD	(1<<4)	/* Bit 4:	Bad ESD */
+#define PHY_B_PES_RX_ER		(1<<3)	/* Bit 3:	Receive Error */
+#define PHY_B_PES_TX_ER		(1<<2)	/* Bit 2:	Transmit Error */
+#define PHY_B_PES_LOCK_ER	(1<<1)	/* Bit 1:	Lock Error */
+#define PHY_B_PES_MLT3_ER	(1<<0)	/* Bit 0:	MLT3 code Error */
+
+/*****	PHY_BCOM_FC_CTR		16 bit r/w	False Carrier Counter *****/
+					/* Bit 15..8:	reserved */
+#define PHY_B_FC_CTR		(255<<0)/* Bit 7..0:	False Carrier Counter */
+
+/*****	PHY_BCOM_RNO_CTR	16 bit r/w	Receive NOT_OK Counter *****/
+#define PHY_B_RC_LOC		(255<<8)/* Bit 15..8:	Local Rx NOT_OK cnt */
+#define PHY_B_RC_REM		(255<<0)/* Bit  7..0:	Remote Rx NOT_OK cnt */
+
+/*****	PHY_BCOM_AUX_CTRL	16 bit r/w	Auxiliary Control Reg *****/
+#define PHY_B_AC_L_SQE		(1<<15)	/* Bit 15:	Low Squelch */
+#define PHY_B_AC_LONG_PACK	(1<<14)	/* Bit 14:	Rx Long Packets */
+#define PHY_B_AC_ER_CTRL	(3<<12)	/* Bit 13..12:	Edgerate Control */
+					/* Bit 11:	reserved */
+#define PHY_B_AC_TX_TST		(1<<10) /* Bit 10:	tx test bit, always 1 */
+					/* Bit  9.. 8:	reserved */
+#define PHY_B_AC_DIS_PRF	(1<<7)	/* Bit  7:	dis part resp filter */
+					/* Bit  6.. 4:	reserved */
+#define PHY_B_AC_DIAG		(1<<3)	/* Bit  3:	Diagnostic Mode */
+					/* Bit  2.. 0:	reserved */
+
+/*****	PHY_BCOM_AUX_STAT	16 bit ro	Auxiliary Status Reg *****/
+#define PHY_B_AS_AN_C		(1<<15)	/* Bit 15:	AutoNeg complete */
+#define PHY_B_AS_AN_CA		(1<<14)	/* Bit 14:	AN Complete Ack */
+#define PHY_B_AS_ANACK_D	(1<<13)	/* Bit 13:	AN Ack Detect */
+#define PHY_B_AS_ANAB_D		(1<<12)	/* Bit 12:	AN Ability Detect */
+#define PHY_B_AS_NPW		(1<<11)	/* Bit 11:	AN Next Page Wait */
+#define PHY_B_AS_AN_RES		(7<<8)	/* Bit 10..8:	AN HDC */
+#define PHY_B_AS_PDF		(1<<7)	/* Bit 7:	Parallel Detect. Fault*/
+#define PHY_B_AS_RF		(1<<6)	/* Bit 6:	Remote Fault */
+#define PHY_B_AS_ANP_R		(1<<5)	/* Bit 5:	AN Page Received */
+#define PHY_B_AS_LP_ANAB	(1<<4)	/* Bit 4:	LP AN Ability */
+#define PHY_B_AS_LP_NPAB	(1<<3)	/* Bit 3:	LP Next Page Ability */
+#define PHY_B_AS_LS		(1<<2)	/* Bit 2:	Link Status */
+#define PHY_B_AS_PRR		(1<<1)	/* Bit 1:	Pause Resolution-Rx */
+#define PHY_B_AS_PRT		(1<<0)	/* Bit 0:	Pause Resolution-Tx */
+
+/*****	PHY_BCOM_INT_STAT	16 bit ro	Interrupt Status Reg *****/
+/*****	PHY_BCOM_INT_MASK	16 bit r/w	Interrupt Mask Reg *****/
+					/* Bit 15:	reserved */
+#define PHY_B_IS_PSE		(1<<14)	/* Bit 14:	Pair Swap Error */
+#define PHY_B_IS_MDXI_SC	(1<<13)	/* Bit 13:	MDIX Status Change */
+#define PHY_B_IS_HCT		(1<<12)	/* Bit 12:	counter above 32k */
+#define PHY_B_IS_LCT		(1<<11)	/* Bit 11:	all counter below 128 */
+#define PHY_B_IS_AN_PR		(1<<10)	/* Bit 10:	Page Received */
+#define PHY_B_IS_NO_HDCL	(1<<9)	/* Bit 9:	No HCD Link */
+#define PHY_B_IS_NO_HDC		(1<<8)	/* Bit 8:	No HCD */
+#define PHY_B_IS_NEG_USHDC	(1<<7)	/* Bit 7:	Negotiated Unsup. HCD */
+#define PHY_B_IS_SCR_S_ER	(1<<6)	/* Bit 6:	Scrambler Sync Error */
+#define PHY_B_IS_RRS_CHANGE	(1<<5)	/* Bit 5:	Remote Rx Stat Change */
+#define PHY_B_IS_LRS_CHANGE	(1<<4)	/* Bit 4:	Local Rx Stat Change */
+#define PHY_B_IS_DUP_CHANGE	(1<<3)	/* Bit 3:	Duplex Mode Change */
+#define PHY_B_IS_LSP_CHANGE	(1<<2)	/* Bit 2:	Link Speed Change */
+#define PHY_B_IS_LST_CHANGE	(1<<1)	/* Bit 1:	Link Status Changed */
+#define PHY_B_IS_CRC_ER		(1<<0)	/* Bit 0:	CRC Error */
+
+#define PHY_B_DEF_MSK	(~(PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE))
+
+
+/*
+ * Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding
+ */
+#define PHY_B_P_NO_PAUSE	(0<<10)	/* Bit	11..10:	no Pause Mode */
+#define PHY_B_P_SYM_MD		(1<<10)	/* Bit	11..10:	symmetric Pause Mode */
+#define PHY_B_P_ASYM_MD		(2<<10)	/* Bit	11..10:	asymmetric Pause Mode */
+#define PHY_B_P_BOTH_MD		(3<<10)	/* Bit	11..10:	both Pause Mode */
+
+/*
+ * Resolved Duplex mode and Capabilities (Aux Status Summary Reg)
+ */
+#define	PHY_B_RES_1000FD	(7<<8)	/* Bit	10..8:	1000Base-T Full Dup. */
+#define	PHY_B_RES_1000HD	(6<<8)	/* Bit	10..8:	1000Base-T Half Dup. */
+/* others: 100/10: invalid for us */
+
+/*
+ * Level One-Specific
+ */
+/*****	PHY_LONE_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+#define PHY_L_1000C_TEST	(7<<13)	/* Bit	15..13:	Test Modes */
+#define PHY_L_1000C_MSE		(1<<12)	/* Bit	12:	Master/Slave Enable */
+#define PHY_L_1000C_MSC		(1<<11)	/* Bit	11:	M/S Configuration */
+#define PHY_L_1000C_RD		(1<<10)	/* Bit	10:	Repeater/DTE */
+#define PHY_L_1000C_AFD		(1<<9)	/* Bit	9:	Advertise Full Duplex */
+#define PHY_L_1000C_AHD		(1<<8)	/* Bit	8:	Advertise Half Duplex */
+					/* Bit	7..0:	reserved */
+
+/*****	PHY_LONE_1000T_STAT	16 bit ro	1000Base-T Status Reg *****/
+#define PHY_L_1000S_MSF		(1<<15)	/* Bit	15:	Master/Slave Fault */
+#define PHY_L_1000S_MSR		(1<<14)	/* Bit	14:	Master/Slave Result */
+#define PHY_L_1000S_LRS		(1<<13)	/* Bit	13:	Local Receiver Status */
+#define PHY_L_1000S_RRS		(1<<12)	/* Bit	12:	Remote Receiver Status*/
+#define PHY_L_1000S_LP_FD	(1<<11)	/* Bit	11:	Link Partner can FD */
+#define PHY_L_1000S_LP_HD	(1<<10)	/* Bit	10:	Link Partner can HD */
+					/* Bit	9..8:	reserved */
+#define PHY_B_1000S_IEC		(255<<0)/* Bit	7..0:	Idle Error Count */
+
+/*****	PHY_LONE_EXT_STAT	16 bit ro	Extended Status Register *****/
+#define PHY_L_ES_X_FD_CAP	(1<<15)	/* Bit 15:	1000Base-X FD capable */
+#define PHY_L_ES_X_HD_CAP	(1<<14)	/* Bit 14:	1000Base-X HD capable */
+#define PHY_L_ES_T_FD_CAP	(1<<13)	/* Bit 13:	1000Base-T FD capable */
+#define PHY_L_ES_T_HD_CAP	(1<<12)	/* Bit 12:	1000Base-T HD capable */
+					/* Bit 11..0:	reserved */
+
+/*****	PHY_LONE_PORT_CFG	16 bit r/w	Port Configuration Reg *****/
+#define PHY_L_PC_REP_MODE	(1<<15)	/* Bit 15:	Repeater Mode */
+					/* Bit 14:	reserved */
+#define PHY_L_PC_TX_DIS		(1<<13)	/* Bit 13:	Tx output Disabled */
+#define PHY_L_PC_BY_SCR		(1<<12)	/* Bit 12:	Bypass Scrambler */
+#define PHY_L_PC_BY_45		(1<<11)	/* Bit 11:	Bypass 4B5B-Decoder */
+#define PHY_L_PC_JAB_DIS	(1<<10)	/* Bit 10:	Jabber Disabled */
+#define PHY_L_PC_SQE		(1<<9)	/* Bit 9:	Enable Heartbeat */
+#define PHY_L_PC_TP_LOOP	(1<<8)	/* Bit 8:	TP Loopback */
+#define PHY_L_PC_SSS		(1<<7)	/* Bit 7:	Smart Speed Selection */
+#define PHY_L_PC_FIFO_SIZE	(1<<6)	/* Bit 6:	FIFO Size */
+#define PHY_L_PC_PRE_EN		(1<<5)	/* Bit 5:	Preamble Enable */
+#define PHY_L_PC_CIM		(1<<4)	/* Bit 4:	Carrier Integrity Mon */
+#define PHY_L_PC_10_SER		(1<<3)	/* Bit 3:	Use Serial Output */
+#define PHY_L_PC_ANISOL		(1<<2)	/* Bit 2:	Unisolate Port */
+#define PHY_L_PC_TEN_BIT	(1<<1)	/* Bit 1:	10bit iface mode on */
+#define PHY_L_PC_ALTCLOCK	(1<<0)	/* Bit 0: (ro)	ALTCLOCK Mode on */
+
+/*****	PHY_LONE_Q_STAT		16 bit ro	Quick Status Reg *****/
+#define PHY_L_QS_D_RATE		(3<<14)	/* Bit 15..14:	Data Rate */
+#define PHY_L_QS_TX_STAT	(1<<13)	/* Bit 13:	Transmitting */
+#define PHY_L_QS_RX_STAT	(1<<12)	/* Bit 12:	Receiving */
+#define PHY_L_QS_COL_STAT	(1<<11)	/* Bit 11:	Collision */
+#define PHY_L_QS_L_STAT		(1<<10)	/* Bit 10:	Link is up */
+#define PHY_L_QS_DUP_MOD	(1<<9)	/* Bit 9:	Full/Half Duplex */
+#define PHY_L_QS_AN		(1<<8)	/* Bit 8:	AutoNeg is On */
+#define PHY_L_QS_AN_C		(1<<7)	/* Bit 7:	AN is Complete */
+#define PHY_L_QS_LLE		(7<<4)	/* Bit 6:	Line Length Estim. */
+#define PHY_L_QS_PAUSE		(1<<3)	/* Bit 3:	LP advertised Pause */
+#define PHY_L_QS_AS_PAUSE	(1<<2)	/* Bit 2:	LP adv. asym. Pause */
+#define PHY_L_QS_ISOLATE	(1<<1)	/* Bit 1:	CIM Isolated */
+#define PHY_L_QS_EVENT		(1<<0)	/* Bit 0:	Event has occurred */
+
+/*****	PHY_LONE_INT_ENAB	16 bit r/w	Interrupt Enable Reg *****/
+/*****	PHY_LONE_INT_STAT	16 bit ro	Interrupt Status Reg *****/
+					/* Bit 15..14:	reserved */
+#define PHY_L_IS_AN_F		(1<<13)	/* Bit 13:	Autoneg fault */
+					/* Bit 12:	not described */
+#define PHY_L_IS_CROSS		(1<<11)	/* Bit 11:	Crossover used */
+#define PHY_L_IS_POL		(1<<10)	/* Bit 10:	Polarity correct. used*/
+#define PHY_L_IS_SS		(1<<9)	/* Bit 9:	Smart Speed Downgrade*/
+#define PHY_L_IS_CFULL		(1<<8)	/* Bit 8:	Counter Full */
+#define PHY_L_IS_AN_C		(1<<7)	/* Bit 7:	AutoNeg Complete */
+#define PHY_L_IS_SPEED		(1<<6)	/* Bit 6:	Speed Changed */
+#define PHY_L_IS_DUP		(1<<5)	/* Bit 5:	Duplex Changed */
+#define PHY_L_IS_LS		(1<<4)	/* Bit 4:	Link Status Changed */
+#define PHY_L_IS_ISOL		(1<<3)	/* Bit 3:	Isolate Occured */
+#define PHY_L_IS_MDINT		(1<<2)	/* Bit 2: (ro)	STAT: MII Int Pending */
+#define PHY_L_IS_INTEN		(1<<1)	/* Bit 1:	ENAB: Enable IRQs */
+#define PHY_L_IS_FORCE		(1<<0)	/* Bit 0:	ENAB: Force Interrupt */
+
+#define PHY_L_DEF_MSK		(PHY_L_IS_LS | PHY_L_IS_ISOL | \
+				PHY_L_IS_INTEN)	/* int. mask */
+
+/*****	PHY_LONE_LED_CFG	16 bit r/w	LED Configuration Reg *****/
+#define PHY_L_LC_LEDC		(3<<14)	/* Bit 15..14:	Col/Blink/On/Off */
+#define PHY_L_LC_LEDR		(3<<12)	/* Bit 13..12:	Rx/Blink/On/Off */
+#define PHY_L_LC_LEDT		(3<<10)	/* Bit 11..10:	Tx/Blink/On/Off */
+#define PHY_L_LC_LEDG		(3<<8)	/* Bit 9..8:	Giga/Blink/On/Off */
+#define PHY_L_LC_LEDS		(3<<6)	/* Bit 7..6:	10-100/Blink/On/Off */
+#define PHY_L_LC_LEDL		(3<<4)	/* Bit 5..4:	Link/Blink/On/Off */
+#define PHY_L_LC_LEDF		(3<<2)	/* Bit 3..2:	Duplex/Blink/On/Off */
+#define PHY_L_LC_PSTRECH	(1<<1)	/* Bit 1:	Strech LED Pulses */
+#define PHY_L_LC_FREQ		(1<<0)	/* Bit 0:	30/100 ms */
+
+/*****	PHY_LONE_PORT_CTRL	16 bit r/w	Port Control Reg *****/
+#define PHY_L_PC_TX_TCLK	(1<<15)	/* Bit 15:	Enable TX_TCLK */
+					/* Bit 14:	reserved */
+#define PHY_L_PC_ALT_NP		(1<<13)	/* Bit 14:	Alternate Next Page */
+#define PHY_L_PC_GMII_ALT	(1<<12)	/* Bit 13:	Alternate GMII driver */
+					/* Bit 11:	reserved */
+#define PHY_L_PC_TEN_CRS	(1<<10)	/* Bit 10:	Extend CRS*/
+					/* Bit 9..0:	not described */
+
+/*****	PHY_LONE_CIM		16 bit ro	CIM Reg *****/
+#define PHY_L_CIM_ISOL		(255<<8)/* Bit 15..8:	Isolate Count */
+#define PHY_L_CIM_FALSE_CAR	(255<<0)/* Bit  7..0:	False Carrier Count */
+
+
+/*
+ * Pause Bits (PHY_L_AN_ASP and PHY_L_AN_PC) encoding
+ */
+#define PHY_L_P_NO_PAUSE	(0<<10)	/* Bit	11..10:	no Pause Mode */
+#define PHY_L_P_SYM_MD		(1<<10)	/* Bit	11..10:	symmetric Pause Mode */
+#define PHY_L_P_ASYM_MD		(2<<10)	/* Bit	11..10:	asymmetric Pause Mode */
+#define PHY_L_P_BOTH_MD		(3<<10)	/* Bit	11..10:	both Pause Mode */
+
+
+/*
+ * National-Specific
+ */
+/***** PHY_NAT_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+#define PHY_N_1000C_TEST	(7<<13)	/* Bit	15..13:	Test Modes */
+#define PHY_N_1000C_MSE		(1<<12)	/* Bit	12:	Master/Slave Enable */
+#define PHY_N_1000C_MSC		(1<<11)	/* Bit	11:	M/S Configuration */
+#define PHY_N_1000C_RD		(1<<10)	/* Bit	10:	Repeater/DTE */
+#define PHY_N_1000C_AFD		(1<<9)	/* Bit	9:	Advertise Full Duplex */
+#define PHY_N_1000C_AHD		(1<<8)	/* Bit	8:	Advertise Half Duplex */
+#define PHY_N_1000C_APC		(1<<7)	/* Bit	7:	Asymetric Pause Cap. */
+					/* Bit	6..0:	reserved */
+
+/***** PHY_NAT_1000T_STAT	16 bit ro	1000Base-T Status Reg *****/
+#define PHY_N_1000S_MSF		(1<<15)	/* Bit	15:	Master/Slave Fault */
+#define PHY_N_1000S_MSR		(1<<14)	/* Bit	14:	Master/Slave Result */
+#define PHY_N_1000S_LRS		(1<<13)	/* Bit	13:	Local Receiver Status */
+#define PHY_N_1000S_RRS		(1<<12)	/* Bit	12:	Remote Receiver Status*/
+#define PHY_N_1000S_LP_FD	(1<<11)	/* Bit	11:	Link Partner can FD */
+#define PHY_N_1000S_LP_HD	(1<<10)	/* Bit	10:	Link Partner can HD */
+#define PHY_N_1000C_LP_APC	(1<<9)	/* Bit	9:	LP Asym. Pause Cap. */
+					/* Bit	8:	reserved */
+#define PHY_N_1000S_IEC		(255<<0)/* Bit	7..0:	Idle Error Count */
+
+/*****	PHY_NAT_EXT_STAT	16 bit ro	Extended Status Register *****/
+#define PHY_N_ES_X_FD_CAP	(1<<15)	/* Bit 15:	1000Base-X FD capable */
+#define PHY_N_ES_X_HD_CAP	(1<<14)	/* Bit 14:	1000Base-X HD capable */
+#define PHY_N_ES_T_FD_CAP	(1<<13)	/* Bit 13:	1000Base-T FD capable */
+#define PHY_N_ES_T_HD_CAP	(1<<12)	/* Bit 12:	1000Base-T HD capable */
+					/* Bit 11..0:	reserved */
+
+/* todo: those are still missing */
+/*****	PHY_NAT_EXT_CTRL1	16 bit ro	Extended Control Reg1 *****/
+/*****	PHY_NAT_Q_STAT1		16 bit ro	Quick Status Reg1 *****/
+/*****	PHY_NAT_10B_OP		16 bit ro	10Base-T Operations Reg *****/
+/*****	PHY_NAT_EXT_CTRL2	16 bit ro	Extended Control Reg1 *****/
+/*****	PHY_NAT_Q_STAT2		16 bit ro	Quick Status Reg2 *****/
+/*****	PHY_NAT_PHY_ADDR	16 bit ro	PHY Address Register *****/
+
+/* typedefs *******************************************************************/
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_XMAC_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/skaddr.c linux.14p16/drivers/net/sk98lin/skaddr.c
--- linux.vanilla/drivers/net/sk98lin/skaddr.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/skaddr.c	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,1300 @@
+/******************************************************************************
+ *
+ * Name:	skaddr.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.33 $
+ * Date:	$Date: 1999/05/28 10:56:06 $
+ * Purpose:	Manage Addresses (Multicast and Unicast) and Promiscuous Mode
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skge.c" for further 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 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skaddr.c,v $
+ *	Revision 1.33  1999/05/28 10:56:06  rassmann
+ *	Editorial changes.
+ *	
+ *	Revision 1.32  1999/03/31 10:59:20  rassmann
+ *	Returning Success instead of DupAddr if address shall be overridden
+ *	with same value.
+ *	
+ *	Revision 1.31  1999/01/14 16:18:17  rassmann
+ *	Corrected multicast initialization.
+ *	
+ *	Revision 1.30  1999/01/04 10:30:35  rassmann
+ *	SkAddrOverride only possible after SK_INIT_IO phase.
+ *	
+ *	Revision 1.29  1998/12/29 13:13:10  rassmann
+ *	An address override is now preserved in the SK_INIT_IO phase.
+ *	All functions return an int now.
+ *	Extended parameter checking.
+ *	
+ *	Revision 1.28  1998/12/01 11:45:53  rassmann
+ *	Code cleanup.
+ *	
+ *	Revision 1.27  1998/12/01 09:22:49  rassmann
+ *	SkAddrMcAdd and SkAddrMcUpdate returned SK_MC_FILTERING_INEXACT
+ *	too often.
+ *	
+ *	Revision 1.26  1998/11/24 12:39:44  rassmann
+ *	Reserved multicast entry for BPDU address.
+ *	13 multicast entries left for protocol.
+ *	
+ *	Revision 1.25  1998/11/17 16:54:23  rassmann
+ *	Using exact match for up to 14 multicast addresses.
+ *	Still receiving all multicasts if more addresses are added.
+ *	
+ *	Revision 1.24  1998/11/13 17:24:31  rassmann
+ *	Changed return value of SkAddrOverride to int.
+ *	
+ *	Revision 1.23  1998/11/13 16:56:18  rassmann
+ *	Added macro SK_ADDR_COMPARE.
+ *	Changed return type of SkAddrOverride to SK_BOOL.
+ *	
+ *	Revision 1.22  1998/11/04 17:06:17  rassmann
+ *	Corrected McUpdate and PromiscuousChange functions.
+ *	
+ *	Revision 1.21  1998/10/29 14:34:04  rassmann
+ *	Clearing SK_ADDR struct at startup.
+ *	
+ *	Revision 1.20  1998/10/28 18:16:34  rassmann
+ *	Avoiding I/Os before SK_INIT_RUN level.
+ *	Aligning InexactFilter.
+ *	
+ *	Revision 1.19  1998/10/28 11:29:28  rassmann
+ *	Programming physical address in SkAddrMcUpdate.
+ *	Corrected programming of exact match entries.
+ *	
+ *	Revision 1.18  1998/10/28 10:34:48  rassmann
+ *	Corrected reading of physical addresses.
+ *	
+ *	Revision 1.17  1998/10/28 10:26:13  rassmann
+ *	Getting ports' current MAC addresses from EPROM now.
+ *	Added debug output.
+ *	
+ *	Revision 1.16  1998/10/27 16:20:12  rassmann
+ *	Reading MAC address byte by byte.
+ *	
+ *	Revision 1.15  1998/10/22 11:39:09  rassmann
+ *	Corrected signed/unsigned mismatches.
+ *	
+ *	Revision 1.14  1998/10/19 17:12:35  rassmann
+ *	Syntax corrections.
+ *	
+ *	Revision 1.13  1998/10/19 17:02:19  rassmann
+ *	Now reading permanent MAC addresses from CRF.
+ *	
+ *	Revision 1.12  1998/10/15 15:15:48  rassmann
+ *	Changed Flags Parameters from SK_U8 to int.
+ *	Checked with lint.
+ *	
+ *	Revision 1.11  1998/09/24 19:15:12  rassmann
+ *	Code cleanup.
+ *	
+ *	Revision 1.10  1998/09/18 20:18:54  rassmann
+ *	Added HW access.
+ *	Implemented swapping.
+ *	
+ *	Revision 1.9  1998/09/16 11:32:00  rassmann
+ *	Including skdrv1st.h again. :(
+ *	
+ *	Revision 1.8  1998/09/16 11:09:34  rassmann
+ *	Syntax corrections.
+ *	
+ *	Revision 1.7  1998/09/14 17:06:34  rassmann
+ *	Minor changes.
+ *	
+ *	Revision 1.6  1998/09/07 08:45:41  rassmann
+ *	Syntax corrections.
+ *	
+ *	Revision 1.5  1998/09/04 19:40:19  rassmann
+ *	Interface enhancements.
+ *	
+ *	Revision 1.4  1998/09/04 12:14:12  rassmann
+ *	Interface cleanup.
+ *	
+ *	Revision 1.3  1998/09/02 16:56:40  rassmann
+ *	Updated interface.
+ *	
+ *	Revision 1.2  1998/08/27 14:26:09  rassmann
+ *	Updated interface.
+ *	
+ *	Revision 1.1  1998/08/21 08:30:22  rassmann
+ *	First public version.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module is intended to manage multicast addresses, address override,
+ * and promiscuous mode on GEnesis adapters.
+ *
+ * Address Layout:
+ *	port address:		physical MAC address
+ *	1st exact match:	logical MAC address
+ *	2nd exact match:	RLMT multicast
+ *	exact match 3-13:	OS-specific multicasts
+ *
+ * Include File Hierarchy:
+ *
+ *	"skdrv1st.h"
+ *	"skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef	lint
+static const char SysKonnectFileId[] =
+	"@(#) $Id: skaddr.c,v 1.33 1999/05/28 10:56:06 rassmann Exp $ (C) SysKonnect.";
+#endif	/* !defined(lint) */
+
+#define __SKADDR_C
+
+#ifdef __cplusplus
+xxxx	/* not supported yet - force error */
+extern "C" {
+#endif	/* cplusplus */
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* defines ********************************************************************/
+
+#define SK_ADDR_CHEAT		YES	/* Cheat. */
+
+/*
+ * G32:
+ * POLY	equ		04C11DB6h	; CRC polynominal term
+ * bit-reversed:	6DB88320
+ */
+
+#define CRC32_POLY	0xEDB88320UL	/* CRC32-Poly - XMAC: Little Endian */
+#if 0
+#define CRC32_POLY	0x6DB88320UL	/* CRC32-Poly - XMAC: Little Endian */
+#endif	/* 0 */
+#define HASH_BITS	6		/* #bits in hash */
+#define	SK_MC_BIT	0x01
+
+/* Error numbers and messages. */
+
+#define SKERR_ADDR_E001		(SK_ERRBASE_ADDR + 0)
+#define SKERR_ADDR_E001MSG	"Bad Flags."
+#define SKERR_ADDR_E002		(SKERR_ADDR_E001 + 1)
+#define SKERR_ADDR_E002MSG	"New Error."
+
+/* typedefs *******************************************************************/
+
+/* None. */
+
+/* global variables ***********************************************************/
+
+/* 64-bit hash values with all bits set. */
+
+SK_U16	OnesHash[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
+
+/* local variables ************************************************************/
+
+#ifdef DEBUG
+static int	Next0[SK_MAX_MACS] = {0, 0};
+#endif	/* DEBUG */
+
+/* functions ******************************************************************/
+
+#if 0
+void	SkAddrDummy(void)
+{
+	SkAddrInit(NULL, NULL, 0);
+}	/* SkAddrDummy */
+#endif	/* 0 */
+
+/******************************************************************************
+ *
+ *	SkAddrInit - initialize data, set state to init
+ *
+ * Description:
+ *
+ *	SK_INIT_DATA
+ *	============
+ *
+ *	This routine clears the multicast tables and resets promiscuous mode.
+ *	Some entries are reserved for the "logical board address", the
+ *	SK-RLMT multicast address, and the BPDU multicast address.
+ *
+ *
+ *	SK_INIT_IO
+ *	==========
+ *
+ *	All permanent MAC addresses are read from EPROM.
+ *	If the current MAC addresses are not already set in software,
+ *	they are set to the values of the permanent addresses.
+ *	The current addresses are written to the corresponding XMAC.
+ *
+ *
+ *	SK_INIT_RUN
+ *	===========
+ *
+ *	Nothing.
+ *
+ * Context:
+ *	init, pageable
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ */
+int	SkAddrInit(
+SK_AC	*pAC,	/* the adapter context */
+SK_IOC	IoC,	/* I/O context */
+int	Level)	/* initialization level */
+{
+	int		j;
+	SK_U32		i;
+	SK_U8		*InAddr;
+	SK_U16		*OutAddr;
+	SK_ADDR_PORT	*pAPort;
+
+	switch (Level) {
+	case SK_INIT_DATA:
+		SK_MEMSET((char *)&pAC->Addr, 0, sizeof(SK_ADDR));
+
+		for (i = 0; i < SK_MAX_MACS; i++) {
+			pAPort = &pAC->Addr.Port[i];
+			pAPort->PromMode = SK_PROM_MODE_NONE;
+
+			pAPort->FirstExactMatchRlmt =
+				SK_ADDR_FIRST_MATCH_RLMT;
+			pAPort->FirstExactMatchDrv =
+				SK_ADDR_FIRST_MATCH_DRV;
+			pAPort->NextExactMatchRlmt =
+				SK_ADDR_FIRST_MATCH_RLMT;
+			pAPort->NextExactMatchDrv =
+				SK_ADDR_FIRST_MATCH_DRV;
+
+#if 0
+			/* Not here ... */
+
+			/* Reset Promiscuous mode. */
+
+			(void)SkAddrPromiscuousChange(
+				pAC,
+				IoC,
+				i,
+				SK_PROM_MODE_NONE);
+#endif	/* 0 */
+		}
+		
+#ifdef DEBUG
+		for (i = 0; i < SK_MAX_MACS; i++) {
+			if (pAC->Addr.Port[i].NextExactMatchRlmt <
+				SK_ADDR_FIRST_MATCH_RLMT) {
+				Next0[i] |= 4;
+			}
+		}
+#endif	/* DEBUG */
+
+		/* pAC->Addr.InitDone = SK_INIT_DATA; */
+		break;
+
+	case SK_INIT_IO:
+		pAC->Addr.ActivePort = pAC->Rlmt.MacActive;
+		
+#ifdef DEBUG
+		for (i = 0; i < SK_MAX_MACS; i++) {
+			if (pAC->Addr.Port[i].NextExactMatchRlmt <
+				SK_ADDR_FIRST_MATCH_RLMT) {
+				Next0[i] |= 8;
+			}
+		}
+#endif	/* DEBUG */
+
+		/* Read permanent virtual address from Control Register File. */
+
+		for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+			InAddr = (SK_U8 *)&pAC->Addr.PermanentMacAddress.a[j];
+			SK_IN8(IoC, B2_MAC_1 + j, InAddr);
+		}
+
+		if (!pAC->Addr.CurrentMacAddressSet) {
+			/*
+			 * Set the current virtual MAC address
+			 * to the permanent one.
+			 */
+
+			pAC->Addr.CurrentMacAddress =
+				pAC->Addr.PermanentMacAddress;
+			pAC->Addr.CurrentMacAddressSet = SK_TRUE;
+		}
+
+		/* Set the current virtual MAC address. */
+
+		pAC->Addr.Port[pAC->Addr.ActivePort].Exact[0] =
+			pAC->Addr.CurrentMacAddress;
+
+#ifdef xDEBUG
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_ADDR,
+			SK_DBGCAT_INIT,
+			("Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
+                                pAC->Addr.PermanentMacAddress.a[0],
+                                pAC->Addr.PermanentMacAddress.a[1],
+                                pAC->Addr.PermanentMacAddress.a[2],
+                                pAC->Addr.PermanentMacAddress.a[3],
+                                pAC->Addr.PermanentMacAddress.a[4],
+                                pAC->Addr.PermanentMacAddress.a[5]))
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_ADDR,
+			SK_DBGCAT_INIT,
+			("Virtual MAC Address: %02X %02X %02X %02X %02X %02X\n",
+                                pAC->Addr.CurrentMacAddress.a[0],
+                                pAC->Addr.CurrentMacAddress.a[1],
+                                pAC->Addr.CurrentMacAddress.a[2],
+                                pAC->Addr.CurrentMacAddress.a[3],
+                                pAC->Addr.CurrentMacAddress.a[4],
+                                pAC->Addr.CurrentMacAddress.a[5]))
+#endif	/* DEBUG */
+
+#if 0
+		/* Not here ... */
+
+		(void)SkAddrMcUpdate(pAC, IoC, pAC->Addr.ActivePort);
+#endif	/* 0 */
+
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			pAPort = &pAC->Addr.Port[i];
+
+			/*
+			 * Read permanent port addresses from
+			 * Control Register File.
+			 */
+
+			for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+				InAddr = (SK_U8 *)
+					&pAPort->PermanentMacAddress.a[j];
+				SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr);
+			}
+
+			if (!pAPort->CurrentMacAddressSet) {
+				/*
+				 * Set the current and previous physical
+				 * MAC address of this port to its permanent
+				 * MAC address.
+				 */
+
+				pAPort->CurrentMacAddress =
+					pAPort->PermanentMacAddress;
+				pAPort->PreviousMacAddress =
+					pAPort->PermanentMacAddress;
+				pAPort->CurrentMacAddressSet = SK_TRUE;
+			}
+
+			/* Set port's current MAC addresses. */
+
+			OutAddr = (SK_U16 *)&pAPort->CurrentMacAddress.a[0];
+			XM_OUTADDR(IoC, i, XM_SA, OutAddr);
+
+#ifdef xDEBUG
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_ADDR,
+				SK_DBGCAT_INIT,
+				("Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+					pAPort->PermanentMacAddress.a[0],
+					pAPort->PermanentMacAddress.a[1],
+					pAPort->PermanentMacAddress.a[2],
+					pAPort->PermanentMacAddress.a[3],
+					pAPort->PermanentMacAddress.a[4],
+					pAPort->PermanentMacAddress.a[5]))
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_ADDR,
+				SK_DBGCAT_INIT,
+				("Phsical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+					pAPort->CurrentMacAddress.a[0],
+					pAPort->CurrentMacAddress.a[1],
+					pAPort->CurrentMacAddress.a[2],
+					pAPort->CurrentMacAddress.a[3],
+					pAPort->CurrentMacAddress.a[4],
+					pAPort->CurrentMacAddress.a[5]))
+#endif	/* DEBUG */
+		}
+		/* pAC->Addr.InitDone = SK_INIT_IO; */
+		break;
+
+	case SK_INIT_RUN:
+#ifdef DEBUG
+		for (i = 0; i < SK_MAX_MACS; i++) {
+			if (pAC->Addr.Port[i].NextExactMatchRlmt <
+				SK_ADDR_FIRST_MATCH_RLMT) {
+				Next0[i] |= 16;
+			}
+		}
+#endif	/* DEBUG */
+
+		/* pAC->Addr.InitDone = SK_INIT_RUN; */
+		break;
+
+	default:	/* error */
+		break;
+	}
+
+	return (SK_ADDR_SUCCESS);
+}	/* SkAddrInit */
+
+
+/******************************************************************************
+ *
+ *	SkAddrMcClear - clear the multicast table
+ *
+ * Description:
+ *	This routine clears the multicast table
+ *	(either entry 2 or entries 3-16 and InexactFilter) of the given port.
+ *	If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
+ *	immediately.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
+ *	may be called after SK_INIT_IO without limitation
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrMcClear(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortIdx,	/* Index of affected port */
+int	Flags)		/* permanent/non-perm, sw-only */
+{
+	int i;
+
+	if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	if (Flags & SK_ADDR_PERMANENT) {
+
+		/* Clear RLMT multicast addresses. */
+
+		pAC->Addr.Port[PortIdx].NextExactMatchRlmt =
+			SK_ADDR_FIRST_MATCH_RLMT;
+	}
+	else {	/* not permanent => DRV */
+
+		/* Clear InexactFilter. */
+
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i] = 0;
+		}
+
+		/* Clear DRV multicast addresses. */
+
+		pAC->Addr.Port[PortIdx].NextExactMatchDrv =
+			SK_ADDR_FIRST_MATCH_DRV;
+	}
+
+	if (!(Flags & SK_MC_SW_ONLY)) {
+		(void)SkAddrMcUpdate(pAC, IoC, PortIdx);
+	}
+
+	return (SK_ADDR_SUCCESS);
+}	/* SkAddrMcClear */
+
+#ifndef SK_ADDR_CHEAT
+// RA;:;:
+/******************************************************************************
+ *
+ *	SkCrc32McHash - hash multicast address
+ *
+ * Description:
+ *	This routine computes the hash value for a multicast address.
+ *
+ * Notes:
+ *	The code was adapted from the XaQti data sheet.
+ *
+ * Context:
+ *	runtime, pageable
+ *
+ * Returns:
+ *	Hash value of multicast address.
+ */
+unsigned SkCrc32McHash(
+unsigned char *pMc)	/* Multicast address */
+{
+	unsigned Idx;
+	unsigned Bit;
+	unsigned Data;
+	unsigned Crc;
+
+	Crc = 0xFFFFFFFFUL;
+	for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) {
+                Data = *pMc++;
+		for (Bit = 0; Bit < 8; Bit++, Data >>= 1) {
+			Crc = (Crc >> 1) ^
+				(((Crc ^ Data) & 1) ? CRC32_POLY : 0);
+		}
+	}
+
+	return (Crc & ((1 << HASH_BITS) - 1));
+
+}	/* SkCrc32McHash */
+
+#endif	/* not SK_ADDR_CHEAT */
+
+/******************************************************************************
+ *
+ *	SkAddrMcAdd - add a multicast address to a port
+ *
+ * Description:
+ *	This routine enables reception for a given address on the given port.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ *	In the current version, only RLMT may add addresses to the non-active
+ *	port.
+ *
+ *	The multicast bit is only checked if there are no free exact match
+ *	entries.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_DATA
+ *
+ * Returns:
+ *	SK_MC_FILTERING_EXACT
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_MC_ILLEGAL_ADDRESS
+ *	SK_MC_ILLEGAL_PORT
+ *	SK_MC_RLMT_OVERFLOW
+ */
+int	SkAddrMcAdd(
+SK_AC		*pAC,		/* adapter context */
+SK_IOC		IoC,		/* I/O context */
+SK_U32		PortIdx,	/* Port Index */
+SK_MAC_ADDR	*pMc,		/* multicast address to be added */
+int		Flags)		/* permanent/non-permanent */
+{
+	int	i;
+	SK_U8	Inexact;
+#ifndef SK_ADDR_CHEAT
+	unsigned HashBit;
+#endif	/* !defined(SK_ADDR_CHEAT) */
+
+	if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	if (Flags & SK_ADDR_PERMANENT) {
+#ifdef DEBUG
+		if (pAC->Addr.Port[PortIdx].NextExactMatchRlmt <
+			SK_ADDR_FIRST_MATCH_RLMT) {
+			Next0[PortIdx] |= 1;
+			return (SK_MC_RLMT_OVERFLOW);
+		}
+#endif	/* DEBUG */
+		
+		if (pAC->Addr.Port[PortIdx].NextExactMatchRlmt >
+			SK_ADDR_LAST_MATCH_RLMT) {
+			return (SK_MC_RLMT_OVERFLOW);
+		}
+
+		/* Set an RLMT multicast address. */
+
+		pAC->Addr.Port[PortIdx].Exact[
+			pAC->Addr.Port[PortIdx].NextExactMatchRlmt++] = *pMc;
+
+		return (SK_MC_FILTERING_EXACT);
+	}
+
+	/* Not PERMANENT => DRV */
+
+	if (PortIdx != pAC->Addr.ActivePort) {
+
+		/* Only RLMT is allowed to do this. */
+
+		return (SK_MC_ILLEGAL_PORT);
+	}
+
+#ifdef DEBUG
+	if (pAC->Addr.Port[PortIdx].NextExactMatchDrv <
+		SK_ADDR_FIRST_MATCH_DRV) {
+			Next0[PortIdx] |= 2;
+		return (SK_MC_RLMT_OVERFLOW);
+	}
+#endif	/* DEBUG */
+	
+	if (pAC->Addr.Port[PortIdx].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
+
+		/* Set exact match entry. */
+
+		pAC->Addr.Port[PortIdx].Exact[
+			pAC->Addr.Port[PortIdx].NextExactMatchDrv++] = *pMc;
+
+		/* Clear InexactFilter. */
+
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortIdx
+				].InexactFilter.Bytes[i] = 0;
+		}
+	}
+	else {
+		if (!(pMc->a[0] & SK_MC_BIT)) {
+
+			/*
+			 * Hashing only possible with
+			 * multicast addresses.
+			 */
+
+			return (SK_MC_ILLEGAL_ADDRESS);
+		}
+#ifndef SK_ADDR_CHEAT
+		/* Compute hash value of address. */
+RA;:;: untested
+		HashBit = SkCrc32McHash(&pMc->a[0]);
+
+		/* Add bit to InexactFilter. */
+
+		pAC->Addr.Port[PortIdx].InexactFilter.Bytes[HashBit / 8] |=
+			1 << (HashBit % 8);
+
+#else	/* SK_ADDR_CHEAT */
+
+		/* Set all bits in InexactFilter. */
+
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i] = 0xFF;
+		}
+#endif	/* SK_ADDR_CHEAT */
+	}
+
+	for (Inexact = 0, i = 0; i < 8; i++) {
+		Inexact |= pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i];
+	}
+
+	if (Inexact == 0 && pAC->Addr.Port[PortIdx].PromMode == 0) {
+		return (SK_MC_FILTERING_EXACT);
+	}
+	else {
+		return (SK_MC_FILTERING_INEXACT);
+	}
+}	/* SkAddrMcAdd */
+
+
+/******************************************************************************
+ *
+ *	SkAddrMcUpdate - update the HW MC address table and set the MAC address
+ *
+ * Description:
+ *	This routine enables reception of the addresses contained in a local
+ *	table for a given port.
+ *	It also programs the port's current physical MAC address.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_MC_FILTERING_EXACT
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrMcUpdate(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortIdx)	/* Port Index */
+{
+	SK_U32		i;
+	SK_U8		Inexact;
+	SK_U16		*OutAddr;
+	SK_U16		LoMode;		/* Lower 16 bits of XMAC Mode Reg. */
+	SK_ADDR_PORT	*pAPort;
+
+	if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	SK_DBG_MSG(
+		pAC,
+		SK_DBGMOD_ADDR,
+		SK_DBGCAT_CTRL,
+		("SkAddrMcUpdate on Port %u.\n", PortIdx))
+	
+	pAPort = &pAC->Addr.Port[PortIdx];
+
+#ifdef DEBUG
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_ADDR,
+			SK_DBGCAT_CTRL,
+			("Next0 on Port %d: %d\n", PortIdx, Next0[PortIdx]))
+#endif	/* DEBUG */
+
+	for (i = 0;		/* Also program the virtual address. */
+		i < pAPort->NextExactMatchRlmt;
+		i++) {
+
+		/* Set exact match address i on HW. */
+
+		OutAddr = (SK_U16 *)&pAPort->Exact[i].a[0];
+		XM_OUTADDR(IoC, PortIdx, XM_EXM(i), OutAddr);
+	}
+
+	/* Clear other permanent exact match addresses on HW. */
+
+	if (pAPort->NextExactMatchRlmt <= SK_ADDR_LAST_MATCH_RLMT) {
+		SkXmClrExactAddr(
+			pAC,
+			IoC,
+			PortIdx,
+			pAPort->NextExactMatchRlmt,
+			SK_ADDR_LAST_MATCH_RLMT);
+	}
+
+	for (i = pAPort->FirstExactMatchDrv;
+		i < pAPort->NextExactMatchDrv;
+		i++) {
+
+		OutAddr = (SK_U16 *)&pAPort->Exact[i].a[0];
+		XM_OUTADDR(IoC, PortIdx, XM_EXM(i), OutAddr);
+
+	}
+
+	/* Clear other non-permanent exact match addresses on HW. */
+
+	if (pAPort->NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
+		SkXmClrExactAddr(
+			pAC,
+			IoC,
+			PortIdx,
+			pAPort->NextExactMatchDrv,
+			SK_ADDR_LAST_MATCH_DRV);
+	}
+
+	for (Inexact = 0xFF, i = 0; i < 8; i++) {
+		Inexact &= pAPort->InexactFilter.Bytes[i];
+	}
+	if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {
+
+		/* Set all bits in 64-bit hash register. */
+
+		XM_OUTHASH(IoC, PortIdx, XM_HSM, &OnesHash);
+
+		/* Set bit 15 in mode register. */
+
+		XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+		LoMode |= XM_MD_ENA_HSH;
+		XM_OUT16(IoC, PortIdx, XM_MODE, LoMode);
+	}
+	else if (Inexact != 0xFF) {
+
+		/* Clear bit 15 in mode register. */
+
+		XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+		LoMode &= ~XM_MD_ENA_HSH;
+		XM_OUT16(IoC, PortIdx, XM_MODE, LoMode);
+	}
+	else {
+		/* Set 64-bit hash register to InexactFilter. */
+
+		XM_OUTHASH(
+			IoC,
+			PortIdx,
+			XM_HSM,
+			&pAPort->InexactFilter.Bytes[0]);
+
+		/* Set bit 15 in mode register. */
+
+		XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+		LoMode |= XM_MD_ENA_HSH;
+		XM_OUT16(IoC, PortIdx, XM_MODE, LoMode);
+	}
+
+	if (pAPort->PromMode != SK_PROM_MODE_NONE) {
+		(void)SkAddrPromiscuousChange(
+			pAC,
+			IoC,
+			PortIdx,
+			pAPort->PromMode);
+	}
+
+	/* Set port's current MAC address. */
+
+	OutAddr = (SK_U16 *)&pAPort->CurrentMacAddress.a[0];
+	XM_OUTADDR(IoC, PortIdx, XM_SA, OutAddr);
+
+#ifdef DEBUG
+	for (i = 0;		/* Also program the virtual address. */
+		i < pAPort->NextExactMatchRlmt;
+		i++) {
+		SK_U8		InAddr8[6];
+		SK_U16		*InAddr;
+
+		/* Get exact match address i from port PortIdx. */
+
+		InAddr = (SK_U16 *)&InAddr8[0];
+		XM_INADDR(IoC, PortIdx, XM_EXM(i), InAddr);
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x --  %02x %02x %02x %02x %02x %02x.\n",
+				i,
+				PortIdx,
+				InAddr8[0],
+				InAddr8[1],
+				InAddr8[2],
+				InAddr8[3],
+				InAddr8[4],
+				InAddr8[5],
+				pAPort->Exact[i].a[0],
+				pAPort->Exact[i].a[1],
+				pAPort->Exact[i].a[2],
+				pAPort->Exact[i].a[3],
+				pAPort->Exact[i].a[4],
+				pAPort->Exact[i].a[5]))
+	}
+#endif	/* DEBUG */		
+
+	/* Determine return value. */
+
+	for (Inexact = 0, i = 0; i < 8; i++) {
+		Inexact |= pAPort->InexactFilter.Bytes[i];
+	}
+	if (Inexact == 0 && pAPort->PromMode == 0) {
+		return (SK_MC_FILTERING_EXACT);
+	}
+	else {
+		return (SK_MC_FILTERING_INEXACT);
+	}
+}	/* SkAddrMcUpdate */
+
+
+/******************************************************************************
+ *
+ *	SkAddrOverride - override a port's MAC address
+ *
+ * Description:
+ *	This routine overrides the MAC address of one port.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS if successful.
+ *	SK_ADDR_DUPLICATE_ADDRESS if duplicate MAC address.
+ *	SK_ADDR_MULTICAST_ADDRESS if multicast or broadcast address.
+ *	SK_ADDR_TOO_EARLY if SK_INIT_IO was not executed before.
+ */
+int	SkAddrOverride(
+SK_AC		*pAC,		/* adapter context */
+SK_IOC		IoC,		/* I/O context */
+SK_U32		PortIdx,	/* Port Index */
+SK_MAC_ADDR	*pNewAddr,	/* new MAC address */
+int		Flags)		/* logical/physical address */
+{
+	SK_U32		i;
+	SK_U16		*OutAddr;
+	SK_EVPARA	Para;
+#if 0
+	SK_MAC_ADDR	NewAddr;	/* new MAC address */
+	SK_U8		AddrBits;
+#endif	/* 0 */
+
+	if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	if (pNewAddr->a[0] & SK_MC_BIT) {
+		return (SK_ADDR_MULTICAST_ADDRESS);
+	}
+
+#if 0
+DANGEROUS!
+	if (Flags & SK_ADDR_PHYSICAL_ADDRESS) {	/* Physical address. */
+		if (!pAC->Addr.Port[PortIdx].CurrentMacAddressSet) {
+			pAC->Addr.Port[PortIdx].PreviousMacAddress = *pNewAddr;
+			pAC->Addr.Port[PortIdx].CurrentMacAddress = *pNewAddr;
+			pAC->Addr.Port[PortIdx].CurrentMacAddressSet = SK_TRUE;
+			return (SK_ADDR_SUCCESS);
+		}
+	}
+	else {
+		if (!pAC->Addr.CurrentMacAddressSet) {
+			pAC->Addr.CurrentMacAddress = *pNewAddr;
+			pAC->Addr.CurrentMacAddressSet = SK_TRUE;
+			return (SK_ADDR_SUCCESS);
+		}
+	}
+DANGEROUS!
+#endif	/* 0 */
+
+	if (!pAC->Addr.CurrentMacAddressSet) {
+		return (SK_ADDR_TOO_EARLY);
+	}
+
+	if (Flags & SK_ADDR_PHYSICAL_ADDRESS) {	/* Physical address. */
+		if (SK_ADDR_EQUAL(pNewAddr->a, pAC->Addr.CurrentMacAddress.a)) {
+			return (SK_ADDR_DUPLICATE_ADDRESS);
+		}
+
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+				return (SK_ADDR_TOO_EARLY);
+			}
+
+			if (SK_ADDR_EQUAL(
+				pNewAddr->a,
+				pAC->Addr.Port[i].CurrentMacAddress.a)) {
+				if (i == PortIdx) {
+					return (SK_ADDR_SUCCESS);
+				}
+				else {
+					return (SK_ADDR_DUPLICATE_ADDRESS);
+				}
+			}
+		}
+
+		pAC->Addr.Port[PortIdx].PreviousMacAddress =
+			pAC->Addr.Port[PortIdx].CurrentMacAddress;
+		pAC->Addr.Port[PortIdx].CurrentMacAddress = *pNewAddr;
+
+		/* Change port's address. */
+
+		OutAddr = (SK_U16 *)pNewAddr;
+		XM_OUTADDR(IoC, PortIdx, XM_SA, OutAddr);
+
+		/* Report address change to RLMT. */
+
+		Para.Para32[0] = PortIdx;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para);
+	}
+	else {	/* Logical Address. */
+		if (SK_ADDR_EQUAL(pNewAddr->a, pAC->Addr.CurrentMacAddress.a)) {
+			return (SK_ADDR_SUCCESS);
+		}
+		
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+				return (SK_ADDR_TOO_EARLY);
+			}
+
+			if (SK_ADDR_EQUAL(
+				pNewAddr->a,
+				pAC->Addr.Port[i].CurrentMacAddress.a)) {
+				return (SK_ADDR_DUPLICATE_ADDRESS);
+			}
+		}
+
+		pAC->Addr.CurrentMacAddress = *pNewAddr;
+		pAC->Addr.Port[PortIdx].Exact[0] = *pNewAddr;
+
+#ifdef DEBUG
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_ADDR,
+			SK_DBGCAT_CTRL,
+			("Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
+                                pAC->Addr.PermanentMacAddress.a[0],
+                                pAC->Addr.PermanentMacAddress.a[1],
+                                pAC->Addr.PermanentMacAddress.a[2],
+                                pAC->Addr.PermanentMacAddress.a[3],
+                                pAC->Addr.PermanentMacAddress.a[4],
+                                pAC->Addr.PermanentMacAddress.a[5]))
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_ADDR,
+			SK_DBGCAT_CTRL,
+			("New Virtual MAC Address: %02X %02X %02X %02X %02X %02X\n",
+                                pAC->Addr.CurrentMacAddress.a[0],
+                                pAC->Addr.CurrentMacAddress.a[1],
+                                pAC->Addr.CurrentMacAddress.a[2],
+                                pAC->Addr.CurrentMacAddress.a[3],
+                                pAC->Addr.CurrentMacAddress.a[4],
+                                pAC->Addr.CurrentMacAddress.a[5]))
+#endif	/* DEBUG */
+
+		/* Write address to first exact match entry of active port. */
+
+		(void)SkAddrMcUpdate(pAC, IoC, PortIdx);
+	}
+
+	return (SK_ADDR_SUCCESS);
+}	/* SkAddrOverride */
+
+
+/******************************************************************************
+ *
+ *	SkAddrPromiscuousChange - set promiscuous mode for given port
+ *
+ * Description:
+ *	This routine manages promiscuous mode:
+ *	- none
+ *	- all LLC frames
+ *	- all MC frames
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrPromiscuousChange(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortIdx,	/* port whose promiscuous mode changes */
+int	NewPromMode)	/* new promiscuous mode */
+{
+	int		i;
+	SK_BOOL		InexactModeBit;
+	SK_U8		Inexact;
+	SK_U8		HwInexact;
+	SK_FILTER64	HwInexactFilter;
+	SK_U16		LoMode;		/* Lower 16 bits of XMAC Mode Register. */
+	int		CurPromMode = SK_PROM_MODE_NONE;
+
+	if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	/* Read CurPromMode from Hardware. */
+
+	XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+
+	if (LoMode & XM_MD_ENA_PROM) {
+		CurPromMode |= SK_PROM_MODE_LLC;
+	}
+	
+	for (Inexact = 0xFF, i = 0; i < 8; i++) {
+		Inexact &= pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i];
+	}
+	if (Inexact == 0xFF) {
+		CurPromMode |= (pAC->Addr.Port[PortIdx].PromMode &
+			SK_PROM_MODE_ALL_MC);
+	}
+	else {
+		/* Read InexactModeBit (bit 15 in mode register). */
+
+		XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+
+                InexactModeBit = (LoMode & XM_MD_ENA_HSH) != 0;
+
+		/* Read 64-bit hash register from HW. */
+
+		XM_INHASH(IoC, PortIdx, XM_HSM, &HwInexactFilter.Bytes[0]);
+
+		for (HwInexact = 0xFF, i = 0; i < 8; i++) {
+			HwInexact &= HwInexactFilter.Bytes[i];
+		}
+
+		if (InexactModeBit && (HwInexact == 0xFF)) {
+			CurPromMode |= SK_PROM_MODE_ALL_MC;
+		}
+	}
+
+	pAC->Addr.Port[PortIdx].PromMode = NewPromMode;
+
+	if (NewPromMode == CurPromMode) {
+		return (SK_ADDR_SUCCESS);
+	}
+
+	if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
+		!(CurPromMode & SK_PROM_MODE_ALL_MC)) {	/* All MC. */
+
+		/* Set all bits in 64-bit hash register. */
+
+		XM_OUTHASH(IoC, PortIdx, XM_HSM, &OnesHash);
+
+		/* Set bit 15 in mode register. */
+
+		XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+		LoMode |= XM_MD_ENA_HSH;
+		XM_OUT16(IoC, PortIdx, XM_MODE, LoMode);
+	}
+	else if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
+		!(NewPromMode & SK_PROM_MODE_ALL_MC)) {	/* Norm MC. */
+
+		for (Inexact = 0, i = 0; i < 8; i++) {
+			Inexact |=
+				pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i];
+		}
+		if (Inexact == 0) {
+			/* Clear bit 15 in mode register. */
+
+			XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+			LoMode &= ~XM_MD_ENA_HSH;
+			XM_OUT16(IoC, PortIdx, XM_MODE, LoMode);
+		}
+		else {
+			/* Set 64-bit hash register to InexactFilter. */
+
+			XM_OUTHASH(
+				IoC,
+				PortIdx,
+				XM_HSM,
+				&pAC->Addr.Port[PortIdx
+					].InexactFilter.Bytes[0]);
+
+			/* Set bit 15 in mode register. */
+
+			XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+			LoMode |= XM_MD_ENA_HSH;
+			XM_OUT16(IoC, PortIdx, XM_MODE, LoMode);
+		}
+	}
+
+	if ((NewPromMode & SK_PROM_MODE_LLC) &&
+		!(CurPromMode & SK_PROM_MODE_LLC)) {	/* Prom. LLC */
+
+		/* Set promiscuous bit in mode register. */
+
+		XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+#if 0
+		/* Receive MAC frames. */
+
+		LoMode |= XM_MD_RX_MCTRL;
+#endif	/* 0 */
+		LoMode |= XM_MD_ENA_PROM;
+		XM_OUT16(IoC, PortIdx, XM_MODE, LoMode);
+	}
+	else if ((CurPromMode & SK_PROM_MODE_LLC) &&
+		!(NewPromMode & SK_PROM_MODE_LLC)) {	/* Norm. LLC. */
+
+		/* Clear promiscuous bit in mode register. */
+
+		XM_IN16(IoC, PortIdx, XM_MODE, &LoMode);
+#if 0
+		/* Don't receive MAC frames. */
+
+		LoMode &= ~XM_MD_RX_MCTRL;
+#endif	/* 0 */
+		LoMode &= ~XM_MD_ENA_PROM;
+		XM_OUT16(IoC, PortIdx, XM_MODE, LoMode);
+	}
+	
+	return (SK_ADDR_SUCCESS);
+}	/* SkAddrPromiscuousChange */
+
+
+/******************************************************************************
+ *
+ *	SkAddrSwap - swap address info
+ *
+ * Description:
+ *	This routine swaps address info of two ports.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrSwap(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	FromPortIdx,	/* Port1 Index */
+SK_U32	ToPortIdx)	/* Port2 Index */
+{
+	int		i;
+	SK_U8		Byte;
+	SK_MAC_ADDR	MacAddr;
+	SK_U32		DWord;
+
+	if (FromPortIdx >= (SK_U32)pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	if (ToPortIdx >= (SK_U32)pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	/*
+	 * Swap
+	 * - Exact Match Entries
+	 * - FirstExactMatchRlmt;
+	 * - NextExactMatchRlmt;
+	 * - FirstExactMatchDrv;
+	 * - NextExactMatchDrv;
+	 * - 64-bit filter
+	 * - Promiscuous Mode
+	 * of ports.
+	 */
+
+	for (i = 0; i < SK_ADDR_EXACT_MATCHES; i++) {
+		MacAddr = pAC->Addr.Port[FromPortIdx].Exact[i];
+		pAC->Addr.Port[FromPortIdx].Exact[i] =
+			pAC->Addr.Port[ToPortIdx].Exact[i];
+		pAC->Addr.Port[ToPortIdx].Exact[i] = MacAddr;
+	}
+
+	for (i = 0; i < 8; i++) {
+		Byte = pAC->Addr.Port[FromPortIdx].InexactFilter.Bytes[i];
+		pAC->Addr.Port[FromPortIdx].InexactFilter.Bytes[i] =
+			pAC->Addr.Port[ToPortIdx].InexactFilter.Bytes[i];
+		pAC->Addr.Port[ToPortIdx].InexactFilter.Bytes[i] = Byte;
+	}
+
+	i = pAC->Addr.Port[FromPortIdx].PromMode;
+	pAC->Addr.Port[FromPortIdx].PromMode =
+		pAC->Addr.Port[ToPortIdx].PromMode;
+	pAC->Addr.Port[ToPortIdx].PromMode = i;
+
+	DWord = pAC->Addr.Port[FromPortIdx].FirstExactMatchRlmt;
+	pAC->Addr.Port[FromPortIdx].FirstExactMatchRlmt =
+		pAC->Addr.Port[ToPortIdx].FirstExactMatchRlmt;
+	pAC->Addr.Port[ToPortIdx].FirstExactMatchRlmt = DWord;
+
+	DWord = pAC->Addr.Port[FromPortIdx].NextExactMatchRlmt;
+	pAC->Addr.Port[FromPortIdx].NextExactMatchRlmt =
+		pAC->Addr.Port[ToPortIdx].NextExactMatchRlmt;
+	pAC->Addr.Port[ToPortIdx].NextExactMatchRlmt = DWord;
+
+	DWord = pAC->Addr.Port[FromPortIdx].FirstExactMatchDrv;
+	pAC->Addr.Port[FromPortIdx].FirstExactMatchDrv =
+		pAC->Addr.Port[ToPortIdx].FirstExactMatchDrv;
+	pAC->Addr.Port[ToPortIdx].FirstExactMatchDrv = DWord;
+
+	DWord = pAC->Addr.Port[FromPortIdx].NextExactMatchDrv;
+	pAC->Addr.Port[FromPortIdx].NextExactMatchDrv =
+		pAC->Addr.Port[ToPortIdx].NextExactMatchDrv;
+	pAC->Addr.Port[ToPortIdx].NextExactMatchDrv = DWord;
+
+        pAC->Addr.ActivePort = ToPortIdx;
+
+	(void)SkAddrMcUpdate(pAC, IoC, FromPortIdx);
+	(void)SkAddrMcUpdate(pAC, IoC, ToPortIdx);
+
+	return (SK_ADDR_SUCCESS);
+}	/* SkAddrSwap */
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/skcsum.c linux.14p16/drivers/net/sk98lin/skcsum.c
--- linux.vanilla/drivers/net/sk98lin/skcsum.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/skcsum.c	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,847 @@
+/******************************************************************************
+ *
+ * Name:	skcsum.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.3 $
+ * Date:	$Date: 1999/05/10 08:39:33 $
+ * Purpose:	Store/verify Internet checksum in send/receive packets.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skge.c" for further 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 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skcsum.c,v $
+ *	Revision 1.3  1999/05/10 08:39:33  mkarl
+ *	prevent overflows in SKCS_HTON16
+ *	fixed a bug in pseudo header checksum calculation
+ *	added some comments
+ *	
+ *	Revision 1.2  1998/10/22 11:53:28  swolf
+ *	Now using SK_DBG_MSG.
+ *	
+ *	Revision 1.1  1998/09/01 15:35:41  swolf
+ *	initial revision
+ *
+ *	13-May-1998 sw	Created.
+ *
+ ******************************************************************************/
+
+#ifdef SK_USE_CSUM	/* Check if CSUM is to be used. */
+
+#ifndef lint
+static const char SysKonnectFileId[] = "@(#)"
+	"$Id: skcsum.c,v 1.3 1999/05/10 08:39:33 mkarl Exp $"
+	" (C) SysKonnect.";
+#endif	/* !lint */
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the "GEnesis" common module "CSUM".
+ *
+ * This module contains the code necessary to calculate, store, and verify the
+ * Internet Checksum of IP, TCP, and UDP frames.
+ *
+ * "GEnesis" is an abbreviation of "Gigabit Ethernet Network System in Silicon"
+ * and is the code name of this SysKonnect project.
+ *
+ * Compilation Options:
+ *
+ *	SK_USE_CSUM - Define if CSUM is to be used. Otherwise, CSUM will be an
+ *	empty module.
+ *
+ *	SKCS_OVERWRITE_PROTO - Define to overwrite the default protocol id
+ *	definitions. In this case, all SKCS_PROTO_xxx definitions must be made
+ *	external.
+ *
+ *	SKCS_OVERWRITE_STATUS - Define to overwrite the default return status
+ *	definitions. In this case, all SKCS_STATUS_xxx definitions must be made
+ *	external.
+ *
+ * Include File Hierarchy:
+ *
+ *	"h/skdrv1st.h"
+ *	"h/skcsum.h"
+ *	 "h/sktypes.h"
+ *	 "h/skqueue.h"
+ *	"h/skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#include "h/skdrv1st.h"
+#include "h/skcsum.h"
+#include "h/skdrv2nd.h"
+
+/* defines ********************************************************************/
+
+/* The size of an Ethernet MAC header. */
+#define SKCS_ETHERNET_MAC_HEADER_SIZE	(6+6+2)
+
+/* The size of the used topology's MAC header. */
+#define	SKCS_MAC_HEADER_SIZE	SKCS_ETHERNET_MAC_HEADER_SIZE
+
+/* The size of the IP header without any option fields. */
+#define SKCS_IP_HEADER_SIZE	20
+
+/*
+ * Field offsets within the IP header.
+ */
+
+/* "Internet Header Version" and "Length". */
+#define SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH	0
+
+/* "Total Length". */
+#define SKCS_OFS_IP_TOTAL_LENGTH		2
+
+/* "Flags" "Fragment Offset". */
+#define SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET	6
+
+/* "Next Level Protocol" identifier. */
+#define SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL		9
+
+/* Source IP address. */
+#define SKCS_OFS_IP_SOURCE_ADDRESS		12
+
+/* Destination IP address. */
+#define SKCS_OFS_IP_DESTINATION_ADDRESS		16
+
+/* IP "Next Level Protocol" identifiers (see RFC 790). */
+#define SKCS_PROTO_ID_TCP	6	/* Transport Control Protocol */
+#define SKCS_PROTO_ID_UDP	17	/* User Datagram Protocol */
+
+/* IP "Don't Fragment" bit. */
+#define SKCS_IP_DONT_FRAGMENT	SKCS_HTON16(0x4000)
+
+/* Add a byte offset to a pointer. */
+#define SKCS_IDX(pPtr, Ofs)	((void *) ((char *) (pPtr) + (Ofs)))
+
+/*
+ * Macros that convert host to network representation and vice versa, i.e.
+ * little/big endian conversion on little endian machines only.
+ */
+#ifdef SK_LITTLE_ENDIAN
+#define SKCS_HTON16(Val16)	(((unsigned) (Val16) >> 8) | (((Val16) & 0xFF) << 8))
+#endif	/* SK_LITTLE_ENDIAN */
+#ifdef SK_BIG_ENDIAN
+#define SKCS_HTON16(Val16)	(Val16)
+#endif	/* SK_BIG_ENDIAN */
+#define SKCS_NTOH16(Val16)	SKCS_HTON16(Val16)
+
+/* typedefs *******************************************************************/
+
+/* function prototypes ********************************************************/
+
+/******************************************************************************
+ *
+ *	SkCsGetSendInfo - get checksum information for a send packet
+ *
+ * Description:
+ *	Get all checksum information necessary to send a TCP or UDP packet. The
+ *	function checks the IP header passed to it. If the high-level protocol
+ *	is either TCP or UDP the pseudo header checksum is calculated and
+ *	returned.
+ *
+ *	The function returns the total length of the IP header (including any
+ *	IP option fields), which is the same as the start offset of the IP data
+ *	which in turn is the start offset of the TCP or UDP header.
+ *
+ *	The function also returns the TCP or UDP pseudo header checksum, which
+ *	should be used as the start value for the hardware checksum calculation.
+ *	(Note that any actual pseudo header checksum can never calculate to
+ *	zero.)
+ *
+ * Note:
+ *	There is a bug in the ASIC whic may lead to wrong checksums.
+ *
+ * Arguments:
+ *	pAc - A pointer to the adapter context struct.
+ *
+ *	pIpHeader - Pointer to IP header. Must be at least the IP header *not*
+ *	including any option fields, i.e. at least 20 bytes.
+ *
+ *	Note: This pointer will be used to address 8-, 16-, and 32-bit
+ *	variables with the respective alignment offsets relative to the pointer.
+ *	Thus, the pointer should point to a 32-bit aligned address. If the
+ *	target system cannot address 32-bit variables on non 32-bit aligned
+ *	addresses, then the pointer *must* point to a 32-bit aligned address.
+ *
+ *	pPacketInfo - A pointer to the packet information structure for this
+ *	packet. Before calling this SkCsGetSendInfo(), the following field must
+ *	be initialized:
+ *
+ *		ProtocolFlags - Initialize with any combination of
+ *		SKCS_PROTO_XXX bit flags. SkCsGetSendInfo() will only work on
+ *		the protocols specified here. Any protocol(s) not specified
+ *		here will be ignored.
+ *
+ *		Note: Only one checksum can be calculated in hardware. Thus, if
+ *		SKCS_PROTO_IP is specified in the 'ProtocolFlags',
+ *		SkCsGetSendInfo() must calculate the IP header checksum in
+ *		software. It might be a better idea to have the calling
+ *		protocol stack calculate the IP header checksum.
+ *
+ * Returns: N/A
+ *	On return, the following fields in 'pPacketInfo' may or may not have
+ *	been filled with information, depending on the protocol(s) found in the
+ *	packet:
+ *
+ *	ProtocolFlags - Returns the SKCS_PROTO_XXX bit flags of the protocol(s)
+ *	that were both requested by the caller and actually found in the packet.
+ *	Protocol(s) not specified by the caller and/or not found in the packet
+ *	will have their respective SKCS_PROTO_XXX bit flags reset.
+ *
+ *	Note: For IP fragments, TCP and UDP packet information is ignored.
+ *
+ *	IpHeaderLength - The total length in bytes of the complete IP header
+ *	including any option fields is returned here. This is the start offset
+ *	of the IP data, i.e. the TCP or UDP header if present.
+ *
+ *	IpHeaderChecksum - If IP has been specified in the 'ProtocolFlags', the
+ *	16-bit Internet Checksum of the IP header is returned here. This value
+ *	is to be stored into the packet's 'IP Header Checksum' field.
+ *
+ *	PseudoHeaderChecksum - If this is a TCP or UDP packet and if TCP or UDP
+ *	has been specified in the 'ProtocolFlags', the 16-bit Internet Checksum
+ *	of the TCP or UDP pseudo header is returned here.
+ */
+void SkCsGetSendInfo(
+SK_AC			*pAc,		/* Adapter context struct. */
+void			*pIpHeader,	/* IP header. */
+SKCS_PACKET_INFO	*pPacketInfo)	/* Packet information struct. */
+{
+	/* Internet Header Version found in IP header. */
+	unsigned InternetHeaderVersion;
+
+	/* Length of the IP header as found in IP header. */
+	unsigned IpHeaderLength;
+
+	/* Bit field specifiying the desired/found protocols. */
+	unsigned ProtocolFlags;
+
+	/* Next level protocol identifier found in IP header. */
+	unsigned NextLevelProtocol;
+
+	/* Length of IP data portion. */
+	unsigned IpDataLength;
+
+	/* TCP/UDP pseudo header checksum. */
+	unsigned long PseudoHeaderChecksum;
+
+	/* Pointer to next level protocol statistics structure. */
+	SKCS_PROTO_STATS *NextLevelProtoStats;
+
+	/* Temporary variable. */
+	unsigned Tmp;
+
+	Tmp = *(SK_U8 *)
+		SKCS_IDX(pIpHeader, SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH);
+
+	/* Get the Internet Header Version (IHV). */
+	/* Note: The IHV is stored in the upper four bits. */
+
+	InternetHeaderVersion = Tmp >> 4;
+
+	/* Check the Internet Header Version. */
+	/* Note: We currently only support IP version 4. */
+
+	if (InternetHeaderVersion != 4) {	/* IPv4? */
+		SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_TX,
+			("Tx: Unknown Internet Header Version %u.\n",
+			InternetHeaderVersion));
+		pPacketInfo->ProtocolFlags = 0;
+		pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].TxUnableCts++;
+		return;
+	}
+
+	/* Get the IP header length (IHL). */
+	/*
+	 * Note: The IHL is stored in the lower four bits as the number of
+	 * 4-byte words.
+	 */
+
+	IpHeaderLength = (Tmp & 0xf) * 4;
+	pPacketInfo->IpHeaderLength = IpHeaderLength;
+
+	/* Check the IP header length. */
+
+	/* 04-Aug-1998 sw - Really check the IHL? Necessary? */
+
+	if (IpHeaderLength < 5*4) {
+		SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_TX,
+			("Tx: Invalid IP Header Length %u.\n", IpHeaderLength));
+		pPacketInfo->ProtocolFlags = 0;
+		pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].TxUnableCts++;
+		return;
+	}
+
+	/* This is an IPv4 frame with a header of valid length. */
+
+	pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].TxOkCts++;
+
+	/* Check if we should calculate the IP header checksum. */
+
+	ProtocolFlags = pPacketInfo->ProtocolFlags;
+
+	if (ProtocolFlags & SKCS_PROTO_IP) {
+		pPacketInfo->IpHeaderChecksum =
+			SkCsCalculateChecksum(pIpHeader, IpHeaderLength);
+	}
+
+	/* Get the next level protocol identifier. */
+
+	NextLevelProtocol =
+		*(SK_U8 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL);
+
+	/*
+	 * Check if this is a TCP or UDP frame and if we should calculate the
+	 * TCP/UDP pseudo header checksum.
+	 *
+	 * Also clear all protocol bit flags of protocols not present in the
+	 * frame.
+	 */
+
+	if ((ProtocolFlags & SKCS_PROTO_TCP) != 0 &&
+		NextLevelProtocol == SKCS_PROTO_ID_TCP) {
+		/* TCP/IP frame. */
+		ProtocolFlags &= SKCS_PROTO_TCP | SKCS_PROTO_IP;
+		NextLevelProtoStats =
+			&pAc->Csum.ProtoStats[SKCS_PROTO_STATS_TCP];
+	}
+	else if ((ProtocolFlags & SKCS_PROTO_UDP) != 0 &&
+		NextLevelProtocol == SKCS_PROTO_ID_UDP) {
+		/* UDP/IP frame. */
+		ProtocolFlags &= SKCS_PROTO_UDP | SKCS_PROTO_IP;
+		NextLevelProtoStats =
+			&pAc->Csum.ProtoStats[SKCS_PROTO_STATS_UDP];
+	}
+	else {
+		/*
+		 * Either not a TCP or UDP frame and/or TCP/UDP processing not
+		 * specified.
+		 */
+		pPacketInfo->ProtocolFlags = ProtocolFlags & SKCS_PROTO_IP;
+		return;
+	}
+
+	/* Check if this is an IP fragment. */
+
+	/*
+	 * Note: An IP fragment has a non-zero "Fragment Offset" field and/or
+	 * the "More Fragments" bit set. Thus, if both the "Fragment Offset"
+	 * and the "More Fragments" are zero, it is *not* a fragment. We can
+	 * easily check both at the same time since they are in the same 16-bit
+	 * word.
+	 */
+
+	if ((*(SK_U16 *)
+		SKCS_IDX(pIpHeader, SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET) &
+		~SKCS_IP_DONT_FRAGMENT) != 0) {
+		/* IP fragment; ignore all other protocols. */
+		pPacketInfo->ProtocolFlags = ProtocolFlags & SKCS_PROTO_IP;
+		NextLevelProtoStats->TxUnableCts++;
+		return;
+	}
+
+	/*
+	 * Calculate the TCP/UDP pseudo header checksum.
+	 */
+
+	/* Get total length of IP header and data. */
+
+	IpDataLength =
+		*(SK_U16 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_TOTAL_LENGTH);
+
+	/* Get length of IP data portion. */
+
+	IpDataLength = SKCS_NTOH16(IpDataLength) - IpHeaderLength;
+
+	/* Calculate the sum of all pseudo header fields (16-bit). */
+
+	PseudoHeaderChecksum =
+		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
+			SKCS_OFS_IP_SOURCE_ADDRESS + 0) +
+		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
+			SKCS_OFS_IP_SOURCE_ADDRESS + 2) +
+		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
+			SKCS_OFS_IP_DESTINATION_ADDRESS + 0) +
+		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
+			SKCS_OFS_IP_DESTINATION_ADDRESS + 2) +
+		(unsigned long) (NextLevelProtocol << 8) +
+		(unsigned long) SKCS_HTON16(IpDataLength);
+
+	/* Add-in any carries. */
+
+	SKCS_OC_ADD(PseudoHeaderChecksum, PseudoHeaderChecksum, 0);
+
+	/* Add-in any new carry. */
+
+	SKCS_OC_ADD(pPacketInfo->PseudoHeaderChecksum, PseudoHeaderChecksum, 0);
+
+	NextLevelProtoStats->TxOkCts++;	/* Success. */
+}
+
+/******************************************************************************
+ *
+ *	SkCsGetReceiveInfo - verify checksum information for a received packet
+ *
+ * Description:
+ *	Verify a received frame's checksum. The function returns a status code
+ *	reflecting the result of the verification.
+ *
+ * Note:
+ *	Before calling this function you have to verify that the frame is
+ *	not padded and Checksum1 and Checksum2 are bigger than 1.
+ *
+ * Arguments:
+ *	pAc - Pointer to adapter context struct.
+ *
+ *	pIpHeader - Pointer to IP header. Must be at least the length in bytes
+ *	of the received IP header including any option fields.
+ *
+ *	Note: The actual length of the IP header is stored in the lower four
+ *	bits of the first octet of the IP header as the number of 4-byte words,
+ *	so it must be multiplied by four to get the length in bytes. Thus, the
+ *	maximum IP header length is 15 * 4 = 60 bytes.
+ *
+ *	Checksum1 - The first 16-bit Internet Checksum calculated by the
+ *	hardware starting at the offset returned by SkCsSetReceiveFlags().
+ *
+ *	Checksum2 - The second 16-bit Internet Checksum calculated by the
+ *	hardware starting at the offset returned by SkCsSetReceiveFlags().
+ *
+ * Returns:
+ *	SKCS_STATUS_UNKNOWN_IP_VERSION - Not an IP v4 frame.
+ *	SKCS_STATUS_IP_CSUM_ERROR - IP checksum error.
+ *	SKCS_STATUS_IP_FRAGMENT - IP fragment (IP checksum ok).
+ *	SKCS_STATUS_IP_CSUM_OK - IP checksum ok (not a TCP or UDP frame).
+ *	SKCS_STATUS_TCP_CSUM_ERROR - TCP checksum error (IP checksum ok).
+ *	SKCS_STATUS_UDP_CSUM_ERROR - UDP checksum error (IP checksum ok).
+ *	SKCS_STATUS_TCP_CSUM_OK - IP and TCP checksum ok.
+ *	SKCS_STATUS_UDP_CSUM_OK - IP and UDP checksum ok.
+ *
+ *	Note: The SKCS_STATUS_XXX values returned here are *not* defined by
+ *	the CSUM module but must be defined in some header file by the module
+ *	using CSUM. In this way, the calling module can assign return values
+ *	for its own needs, e.g. by assigning bit flags to the individual
+ *	protocols.
+ */
+SKCS_STATUS SkCsGetReceiveInfo(
+SK_AC		*pAc,		/* Adapter context struct. */
+void		*pIpHeader,	/* IP header. */
+unsigned	Checksum1,	/* Hardware checksum 1. */
+unsigned	Checksum2)	/* Hardware checksum 2. */
+{
+	/* Internet Header Version found in IP header. */
+	unsigned InternetHeaderVersion;
+
+	/* Length of the IP header as found in IP header. */
+	unsigned IpHeaderLength;
+
+	/* Length of IP data portion. */
+	unsigned IpDataLength;
+
+	/* IP header checksum. */
+	unsigned IpHeaderChecksum;
+
+	/* IP header options checksum, if any. */
+	unsigned IpOptionsChecksum;
+
+	/* IP data checksum, i.e. TCP/UDP checksum. */
+	unsigned IpDataChecksum;
+
+	/* Next level protocol identifier found in IP header. */
+	unsigned NextLevelProtocol;
+
+	/* The checksum of the "next level protocol", i.e. TCP or UDP. */
+	unsigned long NextLevelProtocolChecksum;
+
+	/* Pointer to next level protocol statistics structure. */
+	SKCS_PROTO_STATS *NextLevelProtoStats;
+
+	/* Temporary variable. */
+	unsigned Tmp;
+
+	Tmp = *(SK_U8 *)
+		SKCS_IDX(pIpHeader, SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH);
+
+	/* Get the Internet Header Version (IHV). */
+	/* Note: The IHV is stored in the upper four bits. */
+
+	InternetHeaderVersion = Tmp >> 4;
+
+	/* Check the Internet Header Version. */
+	/* Note: We currently only support IP version 4. */
+
+	if (InternetHeaderVersion != 4) {	/* IPv4? */
+		SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX,
+			("Rx: Unknown Internet Header Version %u.\n",
+			InternetHeaderVersion));
+		pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].RxUnableCts++;
+		return (SKCS_STATUS_UNKNOWN_IP_VERSION);
+	}
+
+	/* Get the IP header length (IHL). */
+	/*
+	 * Note: The IHL is stored in the lower four bits as the number of
+	 * 4-byte words.
+	 */
+
+	IpHeaderLength = (Tmp & 0xf) * 4;
+
+	/* Check the IP header length. */
+
+	/* 04-Aug-1998 sw - Really check the IHL? Necessary? */
+
+	if (IpHeaderLength < 5*4) {
+		SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX,
+			("Rx: Invalid IP Header Length %u.\n", IpHeaderLength));
+		pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].RxErrCts++;
+		return (SKCS_STATUS_IP_CSUM_ERROR);
+	}
+
+	/* This is an IPv4 frame with a header of valid length. */
+
+	/* Get the IP header and data checksum. */
+
+	IpDataChecksum = Checksum2;
+
+	/*
+	 * The IP header checksum is calculated as follows:
+	 *
+	 *	IpHeaderChecksum = Checksum1 - Checksum2
+	 */
+
+	SKCS_OC_SUB(IpHeaderChecksum, Checksum1, Checksum2);
+
+	/* Check if any IP header options. */
+
+	if (IpHeaderLength > SKCS_IP_HEADER_SIZE) {
+
+		/* Get the IP options checksum. */
+
+		IpOptionsChecksum = SkCsCalculateChecksum(
+			SKCS_IDX(pIpHeader, SKCS_IP_HEADER_SIZE),
+			IpHeaderLength - SKCS_IP_HEADER_SIZE);
+
+		/* Adjust the IP header and IP data checksums. */
+
+		SKCS_OC_ADD(IpHeaderChecksum,
+			IpHeaderChecksum, IpOptionsChecksum);
+
+		SKCS_OC_SUB(IpDataChecksum,
+			IpDataChecksum, IpOptionsChecksum);
+	}
+
+	/* Check if the IP header checksum is ok. */
+	/*
+	 * NOTE: We must check the IP header checksum even if the caller does
+	 * not want us to do so because we cannot do any further processing of
+	 * the packet without a valid IP checksum.
+	 */
+
+	if (IpHeaderChecksum != 0xFFFF) {
+		pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].RxErrCts++;
+		return (SKCS_STATUS_IP_CSUM_ERROR);
+	}
+
+	/* Get the next level protocol identifier. */
+
+	NextLevelProtocol =
+		*(SK_U8 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL);
+
+	/*
+	 * Check if this is a TCP or UDP frame and if we should calculate the
+	 * TCP/UDP pseudo header checksum.
+	 *
+	 * Also clear all protocol bit flags of protocols not present in the
+	 * frame.
+	 */
+
+	if ((pAc->Csum.ReceiveFlags & SKCS_PROTO_TCP) != 0 &&
+		NextLevelProtocol == SKCS_PROTO_ID_TCP) {
+		/* TCP/IP frame. */
+		NextLevelProtoStats =
+			&pAc->Csum.ProtoStats[SKCS_PROTO_STATS_TCP];
+	}
+	else if ((pAc->Csum.ReceiveFlags & SKCS_PROTO_UDP) != 0 &&
+		NextLevelProtocol == SKCS_PROTO_ID_UDP) {
+		/* UDP/IP frame. */
+		NextLevelProtoStats =
+			&pAc->Csum.ProtoStats[SKCS_PROTO_STATS_UDP];
+	}
+	else {
+		/*
+		 * Either not a TCP or UDP frame and/or TCP/UDP processing not
+		 * specified.
+		 */
+		return (SKCS_STATUS_IP_CSUM_OK);
+	}
+
+	/* Check if this is an IP fragment. */
+
+	/*
+	 * Note: An IP fragment has a non-zero "Fragment Offset" field and/or
+	 * the "More Fragments" bit set. Thus, if both the "Fragment Offset"
+	 * and the "More Fragments" are zero, it is *not* a fragment. We can
+	 * easily check both at the same time since they are in the same 16-bit
+	 * word.
+	 */
+
+	if ((*(SK_U16 *)
+		SKCS_IDX(pIpHeader, SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET) &
+		~SKCS_IP_DONT_FRAGMENT) != 0) {
+		/* IP fragment; ignore all other protocols. */
+		NextLevelProtoStats->RxUnableCts++;
+		return (SKCS_STATUS_IP_FRAGMENT);
+	}
+
+	/*
+	 * Calculate the TCP/UDP checksum.
+	 */
+
+	/* Get total length of IP header and data. */
+
+	IpDataLength =
+		*(SK_U16 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_TOTAL_LENGTH);
+
+	/* Get length of IP data portion. */
+
+	IpDataLength = SKCS_NTOH16(IpDataLength) - IpHeaderLength;
+
+	NextLevelProtocolChecksum =
+
+		/* Calculate the pseudo header checksum. */
+
+		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
+			SKCS_OFS_IP_SOURCE_ADDRESS + 0) +
+		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
+			SKCS_OFS_IP_SOURCE_ADDRESS + 2) +
+		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
+			SKCS_OFS_IP_DESTINATION_ADDRESS + 0) +
+		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
+			SKCS_OFS_IP_DESTINATION_ADDRESS + 2) +
+		(unsigned long) (NextLevelProtocol << 8) +
+		(unsigned long) SKCS_HTON16(IpDataLength) +
+
+		/* Add the TCP/UDP header checksum. */
+
+		(unsigned long) IpDataChecksum;
+
+	/* Add-in any carries. */
+
+	SKCS_OC_ADD(NextLevelProtocolChecksum, NextLevelProtocolChecksum, 0);
+
+	/* Add-in any new carry. */
+
+	SKCS_OC_ADD(NextLevelProtocolChecksum, NextLevelProtocolChecksum, 0);
+
+	/* Check if the TCP/UDP checksum is ok. */
+
+	if ((unsigned) NextLevelProtocolChecksum == 0xFFFF) {
+
+		/* TCP/UDP checksum ok. */
+
+		NextLevelProtoStats->RxOkCts++;
+
+		return (NextLevelProtocol == SKCS_PROTO_ID_TCP ?
+			SKCS_STATUS_TCP_CSUM_OK : SKCS_STATUS_UDP_CSUM_OK);
+	}
+	
+	/* TCP/UDP checksum error. */
+
+	NextLevelProtoStats->RxErrCts++;
+
+	return (NextLevelProtocol == SKCS_PROTO_ID_TCP ?
+		SKCS_STATUS_TCP_CSUM_ERROR : SKCS_STATUS_UDP_CSUM_ERROR);
+}
+
+/******************************************************************************
+ *
+ *	SkCsSetReceiveFlags - set checksum receive flags
+ *
+ * Description:
+ *	Use this function to set the various receive flags. According to the
+ *	protocol flags set by the caller, the start offsets within received
+ *	packets of the two hardware checksums are returned. These offsets must
+ *	be stored in all receive descriptors.
+ *
+ * Arguments:
+ *	pAc - Pointer to adapter context struct.
+ *
+ *	ReceiveFlags - Any combination of SK_PROTO_XXX flags of the protocols
+ *	for which the caller wants checksum information on received frames.
+ *
+ *	pChecksum1Offset - The start offset of the first receive descriptor
+ *	hardware checksum to be calculated for received frames is returned
+ *	here.
+ *
+ *	pChecksum2Offset - The start offset of the second receive descriptor
+ *	hardware checksum to be calculated for received frames is returned
+ *	here.
+ *
+ * Returns: N/A
+ *	Returns the two hardware checksum start offsets.
+ */
+void SkCsSetReceiveFlags(
+SK_AC		*pAc,			/* Adapter context struct. */
+unsigned	ReceiveFlags,		/* New receive flags. */
+unsigned	*pChecksum1Offset,	/* Offset for hardware checksum 1. */
+unsigned	*pChecksum2Offset)	/* Offset for hardware checksum 2. */
+{
+	/* Save the receive flags. */
+
+	pAc->Csum.ReceiveFlags = ReceiveFlags;
+
+	/* First checksum start offset is the IP header. */
+	*pChecksum1Offset = SKCS_MAC_HEADER_SIZE;
+
+	/*
+	 * Second checksum start offset is the IP data. Note that this may vary
+	 * if there are any IP header options in the actual packet.
+	 */
+	*pChecksum2Offset = SKCS_MAC_HEADER_SIZE + SKCS_IP_HEADER_SIZE;
+}
+
+#ifndef SkCsCalculateChecksum
+/******************************************************************************
+ *
+ *	SkCsCalculateChecksum - calculate checksum for specified data
+ *
+ * Description:
+ *	Calculate and return the 16-bit Internet Checksum for the specified
+ *	data.
+ *
+ * Arguments:
+ *	pData - Pointer to data for which the checksum shall be calculated.
+ *	Note: The pointer should be aligned on a 16-bit boundary.
+ *
+ *	Length - Length in bytes of data to checksum.
+ *
+ * Returns:
+ *	The 16-bit Internet Checksum for the specified data.
+ *
+ *	Note: The checksum is calculated in the machine's natural byte order,
+ *	i.e. little vs. big endian. Thus, the resulting checksum is different
+ *	for the same input data on little and big endian machines.
+ *
+ *	However, when written back to the network packet, the byte order is
+ *	always in correct network order.
+ */
+unsigned SkCsCalculateChecksum(
+void		*pData,		/* Data to checksum. */
+unsigned	Length)		/* Length of data. */
+{
+	SK_U16 *pU16;		/* Pointer to the data as 16-bit words. */
+	unsigned long Checksum;	/* Checksum; must be at least 32 bits. */
+
+	/* Sum up all 16-bit words. */
+
+	pU16 = (SK_U16 *) pData;
+	for (Checksum = 0; Length > 1; Length -= 2) {
+		Checksum += *pU16++;
+	}
+
+	/* If this is an odd number of bytes, add-in the last byte. */
+
+	if (Length > 0) {
+#ifdef SK_BIG_ENDIAN
+		/* Add the last byte as the high byte. */
+		Checksum += ((unsigned) *(SK_U8 *) pU16) << 8;
+#else	/* !SK_BIG_ENDIAN */
+		/* Add the last byte as the low byte. */
+		Checksum += *(SK_U8 *) pU16;
+#endif	/* !SK_BIG_ENDIAN */
+	}
+
+	/* Add-in any carries. */
+
+	SKCS_OC_ADD(Checksum, Checksum, 0);
+
+	/* Add-in any new carry. */
+
+	SKCS_OC_ADD(Checksum, Checksum, 0);
+
+	/* Note: All bits beyond the 16-bit limit are now zero. */
+
+	return ((unsigned) Checksum);
+}
+#endif /* SkCsCalculateChecksum */
+
+/******************************************************************************
+ *
+ *	SkCsEvent - the CSUM event dispatcher
+ *
+ * Description:
+ *	This is the event handler for the CSUM module.
+ *
+ * Arguments:
+ *	pAc - Pointer to adapter context.
+ *
+ *	Ioc - I/O context.
+ *
+ *	Event -	 Event id.
+ *
+ *	Param - Event dependent parameter.
+ *
+ * Returns:
+ *	The 16-bit Internet Checksum for the specified data.
+ *
+ *	Note: The checksum is calculated in the machine's natural byte order,
+ *	i.e. little vs. big endian. Thus, the resulting checksum is different
+ *	for the same input data on little and big endian machines.
+ *
+ *	However, when written back to the network packet, the byte order is
+ *	always in correct network order.
+ */
+int SkCsEvent(
+SK_AC		*pAc,	/* Pointer to adapter context. */
+SK_IOC		Ioc,	/* I/O context. */
+SK_U32		Event,	/* Event id. */
+SK_EVPARA	Param)	/* Event dependent parameter. */
+{
+	int ProtoIndex;
+
+	switch (Event) {
+	/*
+	 * Clear protocol statistics.
+	 *
+	 * Param - Protocol index, or -1 for all protocols.
+	 */
+	case SK_CSUM_EVENT_CLEAR_PROTO_STATS:
+
+		ProtoIndex = (int) Param.Para32[0];
+		if (ProtoIndex < 0) {	/* Clear for all protocols. */
+			memset(&pAc->Csum.ProtoStats[0], 0,
+				sizeof(pAc->Csum.ProtoStats));
+		}
+		else {			/* Clear for individual protocol. */
+			memset(&pAc->Csum.ProtoStats[ProtoIndex], 0,
+				sizeof(pAc->Csum.ProtoStats[ProtoIndex]));
+		}
+		break;
+	default:
+		break;
+	}
+	return (0);	/* Success. */
+}
+
+#endif	/* SK_USE_CSUM */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/skge.c linux.14p16/drivers/net/sk98lin/skge.c
--- linux.vanilla/drivers/net/sk98lin/skge.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/skge.c	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,3686 @@
+/******************************************************************************
+ *
+ * Name:      	skge.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.27 $
+ * Date:       	$Date: 1999/11/25 09:06:28 $
+ * Purpose:	The main driver source module
+ *
+ ******************************************************************************/
+ 
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	Driver for SysKonnect Gigabit Ethernet Server Adapters:
+ *
+ *	SK-9841 (single link 1000Base-LX)
+ *	SK-9842 (dual link   1000Base-LX)
+ *	SK-9843 (single link 1000Base-SX)
+ *	SK-9844 (dual link   1000Base-SX)
+ *	SK-9821 (single link 1000Base-T)
+ *	SK-9822 (dual link   1000Base-T)
+ *
+ *	Created 10-Feb-1999, based on Linux' acenic.c, 3c59x.c and 
+ *	SysKonnects GEnesis Solaris driver
+ *	Author: Christoph Goos (cgoos@syskonnect.de)
+ *
+ *	Address all question to: linux@syskonnect.de
+ *
+ *	The technical manual for the adapters is available from SysKonnect's
+ *	web pages: www.syskonnect.com
+ *	Goto "Support" and search Knowledge Base for "manual".
+ *	
+ *	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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skge.c,v $
+ *	Revision 1.27  1999/11/25 09:06:28  cgoos
+ *	Changed base_addr to unsigned long.
+ *	
+ *	Revision 1.26  1999/11/22 13:29:16  cgoos
+ *	Changed license header to GPL.
+ *	Changes for inclusion in linux kernel (2.2.13).
+ *	Removed 2.0.x defines.
+ *	Changed SkGeProbe to skge_probe.
+ *	Added checks in SkGeIoctl.
+ *	
+ *	Revision 1.25  1999/10/07 14:47:52  cgoos
+ *	Changed 984x to 98xx.
+ *	
+ *	Revision 1.24  1999/09/30 07:21:01  cgoos
+ *	Removed SK_RLMT_SLOW_LOOKAHEAD option.
+ *	Giving spanning tree packets also to OS now.
+ *	
+ *	Revision 1.23  1999/09/29 07:36:50  cgoos
+ *	Changed assignment for IsBc/IsMc.
+ *	
+ *	Revision 1.22  1999/09/28 12:57:09  cgoos
+ *	Added CheckQueue also to Single-Port-ISR.
+ *	
+ *	Revision 1.21  1999/09/28 12:42:41  cgoos
+ *	Changed parameter strings for RlmtMode.
+ *	
+ *	Revision 1.20  1999/09/28 12:37:57  cgoos
+ *	Added CheckQueue for fast delivery of RLMT frames.
+ *	
+ *	Revision 1.19  1999/09/16 07:57:25  cgoos
+ *	Copperfield changes.
+ *	
+ *	Revision 1.18  1999/09/03 13:06:30  cgoos
+ *	Fixed RlmtMode=CheckSeg bug: wrong DEV_KFREE_SKB in RLMT_SEND caused
+ *	double allocated skb's.
+ *	FrameStat in ReceiveIrq was accessed via wrong Rxd.
+ *	Queue size for async. standby Tx queue was zero.
+ *	FillRxLimit of 0 could cause problems with ReQueue, changed to 1.
+ *	Removed debug output of checksum statistic.
+ *	
+ *	Revision 1.17  1999/08/11 13:55:27  cgoos
+ *	Transmit descriptor polling was not reenabled after SkGePortInit.
+ *	
+ *	Revision 1.16  1999/07/27 15:17:29  cgoos
+ *	Added some "\n" in output strings (removed while debuging...).
+ *	
+ *	Revision 1.15  1999/07/23 12:09:30  cgoos
+ *	Performance optimization, rx checksumming, large frame support.
+ *	
+ *	Revision 1.14  1999/07/14 11:26:27  cgoos
+ *	Removed Link LED settings (now in RLMT).
+ *	Added status output at NET UP.
+ *	Fixed SMP problems with Tx and SWITCH running in parallel.
+ *	Fixed return code problem at RLMT_SEND event.
+ *	
+ *	Revision 1.13  1999/04/07 10:11:42  cgoos
+ *	Fixed Single Port problems.
+ *	Fixed Multi-Adapter problems.
+ *	Always display startup string.
+ *	
+ *	Revision 1.12  1999/03/29 12:26:37  cgoos
+ *	Reversed locking to fine granularity.
+ *	Fixed skb double alloc problem (caused by incorrect xmit return code).
+ *	Enhanced function descriptions.
+ *	
+ *	Revision 1.11  1999/03/15 13:10:51  cgoos
+ *	Changed device identifier in output string to ethX.
+ *	
+ *	Revision 1.10  1999/03/15 12:12:34  cgoos
+ *	Changed copyright notice.
+ *	
+ *	Revision 1.9  1999/03/15 12:10:17  cgoos
+ *	Changed locking to one driver lock.
+ *	Added check of SK_AC-size (for consistency with library).
+ *	
+ *	Revision 1.8  1999/03/08 11:44:02  cgoos
+ *	Fixed missing dev->tbusy in SkGeXmit.
+ *	Changed large frame (jumbo) buffer number.
+ *	Added copying of short frames.
+ *	
+ *	Revision 1.7  1999/03/04 13:26:57  cgoos
+ *	Fixed spinlock calls for SMP.
+ *	
+ *	Revision 1.6  1999/03/02 09:53:51  cgoos
+ *	Added descriptor revertion for big endian machines.
+ *	
+ *	Revision 1.5  1999/03/01 08:50:59  cgoos
+ *	Fixed SkGeChangeMtu.
+ *	Fixed pci config space accesses.
+ *	
+ *	Revision 1.4  1999/02/18 15:48:44  cgoos
+ *	Corrected some printk's.
+ *	
+ *	Revision 1.3  1999/02/18 12:45:55  cgoos
+ *	Changed SK_MAX_CARD_PARAM to default 16
+ *	
+ *	Revision 1.2  1999/02/18 10:55:32  cgoos
+ *	Removed SkGeDrvTimeStamp function.
+ *	Printing "ethX:" before adapter type at adapter init.
+ *	
+ *
+ *	10-Feb-1999 cg	Created, based on Linux' acenic.c, 3c59x.c and 
+ *			SysKonnects GEnesis Solaris driver
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Possible compiler options (#define xxx / -Dxxx):
+ *
+ *	debugging can be enable by changing SK_DEBUG_CHKMOD and 
+ *	SK_DEBUG_CHKCAT in makefile (described there).
+ *
+ ******************************************************************************/
+ 
+/******************************************************************************
+ *
+ * Description:
+ *
+ *	This is the main module of the Linux GE driver.
+ *	
+ *	All source files except skge.c, skdrv1st.h, skdrv2nd.h and sktypes.h
+ *	are part of SysKonnect's COMMON MODULES for the SK-98xx adapters.
+ *	Those are used for drivers on multiple OS', so some thing may seem
+ *	unnecessary complicated on Linux. Please do not try to 'clean up'
+ *	them without VERY good reasons, because this will make it more
+ *	difficult to keep the Linux driver in synchronisation with the
+ *	other versions.
+ *
+ * Include file hierarchy:
+ *
+ *	<linux/module.h>
+ *
+ *	"h/skdrv1st.h"
+ *		<linux/version.h>
+ *		<linux/types.h>
+ *		<linux/kernel.h>
+ *		<linux/string.h>
+ *		<linux/errno.h>
+ *		<linux/ioport.h>
+ *		<linux/malloc.h>
+ *		<linux/interrupt.h>
+ *		<linux/pci.h>
+ *		<asm/byteorder.h>
+ *		<asm/bitops.h>
+ *		<asm/io.h>
+ *		<linux/netdevice.h>
+ *		<linux/etherdevice.h>
+ *		<linux/skbuff.h>
+ *	    those three depending on kernel version used:
+ *		<linux/bios32.h>
+ *		<linux/init.h>
+ *		<asm/uaccess.h>
+ *		<net/checksum.h>
+ *
+ *		"h/skerror.h"
+ *		"h/skdebug.h"
+ *		"h/sktypes.h"
+ *		"h/lm80.h"
+ *		"h/xmac_ii.h"
+ *
+ *      "h/skdrv2nd.h"
+ *		"h/skqueue.h"
+ *		"h/skgehwt.h"
+ *		"h/sktimer.h"
+ *		"h/ski2c.h"
+ *		"h/skgepnmi.h"
+ *		"h/skvpd.h"
+ *		"h/skgehw.h"
+ *		"h/skgeinit.h"
+ *		"h/skaddr.h"
+ *		"h/skgesirq.h"
+ *		"h/skcsum.h"
+ *		"h/skrlmt.h"
+ *
+ ******************************************************************************/
+
+static const char SysKonnectFileId[] = "@(#)" __FILE__ " (C) SysKonnect.";
+static const char SysKonnectBuildNumber[] =
+	"@(#)SK-BUILD: 3.02 (19991111) PL: 01"; 
+
+#include	<linux/module.h>
+
+#include	"h/skdrv1st.h"
+#include	"h/skdrv2nd.h"
+
+/* defines ******************************************************************/
+
+#define BOOT_STRING	"sk98lin: Network Device Driver v3.02\n" \
+			"Copyright (C) 1999 SysKonnect"
+
+#define VER_STRING	"3.02"
+
+
+/* for debuging on x86 only */
+/* #define BREAKPOINT() asm(" int $3"); */
+
+/* use of a transmit complete interrupt */
+#define USE_TX_COMPLETE
+
+/* use interrupt moderation (for tx complete only) */
+// #define USE_INT_MOD
+#define INTS_PER_SEC	1000
+
+/*
+ * threshold for copying small receive frames
+ * set to 0 to avoid copying, set to 9001 to copy all frames
+ */
+#define SK_COPY_THRESHOLD	200
+
+/* number of adapters that can be configured via command line params */
+#define SK_MAX_CARD_PARAM	16
+
+/*
+ * use those defines for a compile-in version of the driver instead 
+ * of command line parameters
+ */
+// #define AUTO_NEG_A	{"Sense", }
+// #define AUTO_NEG_B	{"Sense", }
+// #define DUP_CAP_A	{"Both", }
+// #define DUP_CAP_B	{"Both", }
+// #define FLOW_CTRL_A	{"SymOrRem", }
+// #define FLOW_CTRL_B	{"SymOrRem", }
+// #define ROLE_A	{"Auto", }
+// #define ROLE_B	{"Auto", }
+// #define PREF_PORT	{"A", }
+// #define RLMT_MODE	{"CheckLink", }
+
+
+#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb);
+
+/* function prototypes ******************************************************/
+static void	FreeResources(struct device *dev);
+int		init_module(void);
+void		cleanup_module(void);
+static int	SkGeBoardInit(struct device *dev, SK_AC *pAC);
+static SK_BOOL	BoardAllocMem(SK_AC *pAC);
+static void	BoardFreeMem(SK_AC *pAC);
+static void	BoardInitMem(SK_AC *pAC);
+static void	SetupRing(SK_AC*, void*, uintptr_t, RXD**, RXD**, RXD**,
+			int*, SK_BOOL);
+
+static void	SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs);
+static void	SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs);
+static int	SkGeOpen(struct device *dev);
+static int	SkGeClose(struct device *dev);
+static int	SkGeXmit(struct sk_buff *skb, struct device *dev);
+static int	SkGeSetMacAddr(struct device *dev, void *p);
+static void	SkGeSetRxMode(struct device *dev);
+static struct net_device_stats *SkGeStats(struct device *dev);
+static int	SkGeIoctl(struct device *dev, struct ifreq *rq, int cmd);
+static void	GetConfiguration(SK_AC*);
+static void	ProductStr(SK_AC*);
+static int	XmitFrame(SK_AC*, TX_PORT*, struct sk_buff*);
+static void	FreeTxDescriptors(SK_AC*pAC, TX_PORT*);
+static void	FillRxRing(SK_AC*, RX_PORT*);
+static SK_BOOL	FillRxDescriptor(SK_AC*, RX_PORT*);
+static void	ReceiveIrq(SK_AC*, RX_PORT*);
+static void	ClearAndStartRx(SK_AC*, int);
+static void	ClearTxIrq(SK_AC*, int, int);
+static void	ClearRxRing(SK_AC*, RX_PORT*);
+static void	ClearTxRing(SK_AC*, TX_PORT*);
+static void	SetQueueSizes(SK_AC	*pAC);
+static int	SkGeChangeMtu(struct device *dev, int new_mtu);
+static void	PortReInitBmu(SK_AC*, int);
+static int	SkGeIocMib(SK_AC*, unsigned int, int);
+#ifdef DEBUG
+static void	DumpMsg(struct sk_buff*, char*);
+static void	DumpData(char*, int);
+static void	DumpLong(char*, int);
+#endif
+
+
+/* global variables *********************************************************/
+static const char *BootString = BOOT_STRING;
+static struct device *root_dev = NULL;
+static int probed __initdata = 0;
+
+/* local variables **********************************************************/
+static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}};
+static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480};
+
+/*****************************************************************************
+ *
+ * 	skge_probe - find all SK-98xx adapters
+ *
+ * Description:
+ *	This function scans the PCI bus for SK-98xx adapters. Resources for
+ *	each adapter are allocated and the adapter is brought into Init 1
+ *	state.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+__initfunc(int skge_probe (struct device *dev))
+{
+int boards_found = 0;
+int		version_disp = 0;
+SK_AC		*pAC;
+struct pci_dev	*pdev = NULL;
+unsigned long	base_address;
+
+	if (probed)
+		return -ENODEV;
+	probed++;
+	
+	/* display driver info */
+	if (!version_disp)
+	{
+		/* set display flag to TRUE so that */
+		/* we only display this string ONCE */
+		version_disp = 1;
+		printk("%s\n", BootString);
+	}
+
+	if (!pci_present())		/* is PCI support present? */
+		return -ENODEV;
+
+	while((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev)))
+	{
+		dev = NULL;
+
+		if (pdev->vendor != PCI_VENDOR_ID_SYSKONNECT || 
+			pdev->device != PCI_DEVICE_ID_SYSKONNECT_GE) {
+			continue;
+		}
+		dev = init_etherdev(dev, sizeof(SK_AC));
+
+		if (dev == NULL){
+			printk(KERN_ERR "Unable to allocate etherdev "
+			       "structure!\n");
+			break;
+		}
+
+		if (!dev->priv)
+			dev->priv = kmalloc(sizeof(SK_AC), GFP_KERNEL);
+		if (dev->priv == NULL){
+			printk(KERN_ERR "Unable to allocate adapter "
+			       "structure!\n");
+			break;
+		}
+
+		
+		memset(dev->priv, 0, sizeof(SK_AC));
+
+		pAC = dev->priv;
+		pAC->PciDev = *pdev;
+		pAC->PciDevId = pdev->device;
+		pAC->dev = dev;
+		sprintf(pAC->Name, "SysKonnect SK-98xx");
+		pAC->CheckQueue = SK_FALSE;
+
+		dev->irq = pdev->irq;
+
+		dev->open =		&SkGeOpen;
+		dev->stop =		&SkGeClose;
+		dev->hard_start_xmit =	&SkGeXmit;
+		dev->get_stats =	&SkGeStats;
+		dev->set_multicast_list = &SkGeSetRxMode;
+		dev->set_mac_address =	&SkGeSetMacAddr;
+		dev->do_ioctl =		&SkGeIoctl;
+		dev->change_mtu =	&SkGeChangeMtu;
+		
+		/*
+		 * Dummy value.
+		 */
+		dev->base_addr = 42;
+
+		pci_set_master(pdev);
+
+		base_address = pdev->base_address[0];
+
+#ifdef SK_BIG_ENDIAN
+		/*
+		 * On big endian machines, we use the adapter's aibility of
+		 * reading the descriptors as big endian.
+		 */
+		{
+		SK_U32		our2;
+			SkPciReadCfgDWord(pAC, PCI_OUR_REG_2, &our2);
+			our2 |= PCI_REV_DESC;
+			SkPciWriteCfgDWord(pAC, PCI_OUR_REG_2, our2);
+		}
+#endif /* BIG ENDIAN */
+
+		/*
+		 * Remap the regs into kernel space.
+		 */
+
+
+		pAC->IoBase = (char*)ioremap(base_address, 0x4000);
+		if (!pAC->IoBase){
+			printk(KERN_ERR "%s:  Unable to map I/O register, "
+			       "SK 98xx No. %i will be disabled.\n",
+			       dev->name, boards_found);
+			break;
+		}
+		pAC->Index = boards_found;
+
+		if (SkGeBoardInit(dev, pAC)) {
+			FreeResources(dev);
+			continue;
+		}
+
+                memcpy((caddr_t) &dev->dev_addr,
+			(caddr_t) &pAC->Addr.CurrentMacAddress, 6);
+ 
+		boards_found++;
+
+		/*
+		 * This is bollocks, but we need to tell the net-init
+		 * code that it shall go for the next device.
+		 */
+#ifndef MODULE
+		dev->base_addr = 0;
+#endif
+	}
+
+	/*
+	 * If we're at this point we're going through skge_probe() for
+	 * the first time.  Return success (0) if we've initialized 1
+	 * or more boards. Otherwise, return failure (-ENODEV).
+	 */
+
+#ifdef MODULE
+	return boards_found;
+#else
+	if (boards_found > 0)
+		return 0;
+	else
+		return -ENODEV;
+#endif
+} /* skge_probe */
+
+
+/*****************************************************************************
+ *
+ * 	FreeResources - release resources allocated for adapter
+ *
+ * Description:
+ *	This function releases the IRQ, unmaps the IO and
+ *	frees the desriptor ring.
+ *
+ * Returns: N/A
+ *	
+ */
+static void FreeResources(struct device *dev)
+{
+SK_U32 AllocFlag;
+SK_AC	*pAC;
+
+	if (dev->priv) {
+		pAC = (SK_AC*) dev->priv;
+		AllocFlag = pAC->AllocFlag;
+		if (AllocFlag & SK_ALLOC_IRQ) {
+			free_irq(dev->irq, dev);
+		}
+		if (pAC->IoBase) {
+			iounmap(pAC->IoBase);
+		}
+		if (pAC->pDescrMem) {
+			BoardFreeMem(pAC);
+		}
+	}
+	
+} /* FreeResources */
+
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Christoph Goos <cgoos@syskonnect.de>");
+MODULE_DESCRIPTION("SysKonnect SK-NET Gigabit Ethernet SK-98xx driver");
+MODULE_PARM(AutoNeg_A,  "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(AutoNeg_B,  "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(DupCap_A,   "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(DupCap_B,   "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(FlowCtrl_A, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(FlowCtrl_B, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(Role_A,	"1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(Role_B,	"1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(PrefPort,   "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(RlmtMode,   "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+/* not used, just there because every driver should have them: */
+MODULE_PARM(options,    "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "i");
+MODULE_PARM(debug,      "i");
+
+#endif // MODULE
+
+
+#ifdef AUTO_NEG_A
+static char *AutoNeg_A[SK_MAX_CARD_PARAM] = AUTO_NEG_A;
+#else
+static char *AutoNeg_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef DUP_CAP_A
+static char *DupCap_A[SK_MAX_CARD_PARAM] = DUP_CAP_A;
+#else
+static char *DupCap_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef FLOW_CTRL_A
+static char *FlowCtrl_A[SK_MAX_CARD_PARAM] = FLOW_CTRL_A;
+#else
+static char *FlowCtrl_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef ROLE_A
+static char *Role_A[SK_MAX_CARD_PARAM] = ROLE_A;
+#else
+static char *Role_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef AUTO_NEG_B
+static char *AutoNeg_B[SK_MAX_CARD_PARAM] = AUTO_NEG_B;
+#else
+static char *AutoNeg_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef DUP_CAP_B
+static char *DupCap_B[SK_MAX_CARD_PARAM] = DUP_CAP_B;
+#else
+static char *DupCap_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef FLOW_CTRL_B
+static char *FlowCtrl_B[SK_MAX_CARD_PARAM] = FLOW_CTRL_B;
+#else
+static char *FlowCtrl_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef ROLE_B
+static char *Role_B[SK_MAX_CARD_PARAM] = ROLE_B;
+#else
+static char *Role_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef PREF_PORT
+static char *PrefPort[SK_MAX_CARD_PARAM] = PREF_PORT;
+#else
+static char *PrefPort[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef RLMT_MODE
+static char *RlmtMode[SK_MAX_CARD_PARAM] = RLMT_MODE;
+#else
+static char *RlmtMode[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+
+#ifdef MODULE
+
+static int debug = 0; /* not used */
+static int options[SK_MAX_CARD_PARAM] = {0, }; /* not used */
+
+
+/*****************************************************************************
+ *
+ * 	init_module - module initialization function
+ *
+ * Description:
+ *	Very simple, only call skge_probe and return approriate result.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+int init_module(void)
+{
+int cards;
+
+	root_dev = NULL;
+	
+	/* just to avoid warnings ... */
+	debug = 0;
+	options[0] = 0;
+
+	cards = skge_probe(NULL);
+	if (cards == 0) {
+		printk("No adapter found\n");
+	}
+	return cards ? 0 : -ENODEV;
+} /* init_module */
+
+
+/*****************************************************************************
+ *
+ * 	cleanup_module - module unload function
+ *
+ * Description:
+ *	Disable adapter if it is still running, free resources,
+ *	free device struct.
+ *
+ * Returns: N/A
+ */
+void cleanup_module(void)
+{
+SK_AC	*pAC;
+struct device *next;
+unsigned long Flags;
+SK_EVPARA EvPara;
+
+	while (root_dev) {
+		pAC = (SK_AC*)root_dev->priv;
+		next = pAC->Next;
+
+		root_dev->tbusy = 1;
+		SkGeYellowLED(pAC, pAC->IoBase, 0);
+		
+		if(pAC->BoardLevel == 2) {
+			/* board is still alive */
+			spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+			SkEventDispatcher(pAC, pAC->IoBase);
+			/* disable interrupts */
+			SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+			SkGeDeInit(pAC, pAC->IoBase); 
+			spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+			pAC->BoardLevel = 0;
+			/* We do NOT check here, if IRQ was pending, of course*/
+		}
+	
+		if(pAC->BoardLevel == 1) {
+			/* board is still alive */
+			SkGeDeInit(pAC, pAC->IoBase); 
+			pAC->BoardLevel = 0;
+		}
+		
+		FreeResources(root_dev);
+		
+		root_dev->get_stats = NULL;
+		/* 
+		 * otherwise unregister_netdev calls get_stats with
+		 * invalid IO ...  :-(
+		 */
+		unregister_netdev(root_dev);
+		kfree(root_dev);
+
+		root_dev = next;
+	}
+}
+#endif /* cleanup_module */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeBoardInit - do level 0 and 1 initialization
+ *
+ * Description:
+ *	This function prepares the board hardware for running. The desriptor
+ *	ring is set up, the IRQ is allocated and the configuration settings
+ *	are examined.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+__initfunc(static int SkGeBoardInit(struct device *dev, SK_AC *pAC))
+{
+short	i;
+unsigned long Flags;
+char	*DescrString = "sk98lin: Driver for Linux"; /* this is given to PNMI */
+char	*VerStr	= VER_STRING;
+int	Ret;			/* return code of request_irq */
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("IoBase: %08lX\n", (unsigned long)pAC->IoBase));
+	for (i=0; i<SK_MAX_MACS; i++) {
+		pAC->TxPort[i][0].HwAddr = pAC->IoBase + TxQueueAddr[i][0];
+		pAC->TxPort[i][0].PortIndex = i;
+		pAC->RxPort[i].HwAddr = pAC->IoBase + RxQueueAddr[i];
+		pAC->RxPort[i].PortIndex = i;
+	}
+
+	/* Initialize the mutexes */
+
+	for (i=0; i<SK_MAX_MACS; i++) {
+		spin_lock_init(&pAC->TxPort[i][0].TxDesRingLock);
+		spin_lock_init(&pAC->RxPort[i].RxDesRingLock);
+	}
+	spin_lock_init(&pAC->SlowPathLock);
+
+	/* level 0 init common modules here */
+	
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	/* Does a RESET on board ...*/
+	if (SkGeInit(pAC, pAC->IoBase, 0) != 0) {
+		printk("HWInit (0) failed.\n");
+		spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+		return(-EAGAIN);
+	}
+	SkI2cInit(  pAC, pAC->IoBase, 0);
+	SkEventInit(pAC, pAC->IoBase, 0);
+	SkPnmiInit( pAC, pAC->IoBase, 0);
+	SkAddrInit( pAC, pAC->IoBase, 0);
+	SkRlmtInit( pAC, pAC->IoBase, 0);
+	SkTimerInit(pAC, pAC->IoBase, 0);
+	
+	pAC->BoardLevel = 0;
+	pAC->RxBufSize = ETH_BUF_SIZE;
+
+	SK_PNMI_SET_DRIVER_DESCR(pAC, DescrString);
+	SK_PNMI_SET_DRIVER_VER(pAC, VerStr);
+
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+	GetConfiguration(pAC);
+
+	/* level 1 init common modules here (HW init) */
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	if (SkGeInit(pAC, pAC->IoBase, 1) != 0) {
+		printk("HWInit (1) failed.\n");
+		spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+		return(-EAGAIN);
+	}
+	SkI2cInit(  pAC, pAC->IoBase, 1);
+	SkEventInit(pAC, pAC->IoBase, 1);
+	SkPnmiInit( pAC, pAC->IoBase, 1);
+	SkAddrInit( pAC, pAC->IoBase, 1);
+	SkRlmtInit( pAC, pAC->IoBase, 1);
+	SkTimerInit(pAC, pAC->IoBase, 1);
+
+	pAC->BoardLevel = 1;
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+	if (pAC->GIni.GIMacsFound == 2) {
+		 Ret = request_irq(dev->irq, SkGeIsr, SA_SHIRQ, pAC->Name, dev);
+	} else if (pAC->GIni.GIMacsFound == 1) {
+		Ret = request_irq(dev->irq, SkGeIsrOnePort, SA_SHIRQ,
+			pAC->Name, dev);
+	} else {
+		printk(KERN_WARNING "%s: illegal number of ports: %d\n",
+		       dev->name, pAC->GIni.GIMacsFound);
+		return -EAGAIN;
+	}
+	if (Ret) {
+		printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
+		       dev->name, dev->irq);
+		return -EAGAIN;
+	}
+	pAC->AllocFlag |= SK_ALLOC_IRQ;
+
+	/* Alloc memory for this board (Mem for RxD/TxD) : */
+	if(!BoardAllocMem(pAC)) {
+		printk("No memory for descriptor rings\n");
+       		return(-EAGAIN);
+	}
+
+	SkCsSetReceiveFlags(pAC,
+		SKCS_PROTO_IP | SKCS_PROTO_TCP | SKCS_PROTO_UDP,
+		&pAC->CsOfs1, &pAC->CsOfs2);
+	pAC->CsOfs = (pAC->CsOfs2 << 16) | pAC->CsOfs1;
+
+	BoardInitMem(pAC);
+
+	SetQueueSizes(pAC);
+
+	/* Print adapter specific string from vpd */
+	ProductStr(pAC);
+	printk("%s: %s\n", dev->name, pAC->DeviceStr);
+
+	SkGeYellowLED(pAC, pAC->IoBase, 1);
+
+	/*
+	 * Register the device here
+	 */
+	pAC->Next = root_dev;
+	root_dev = dev;
+
+	return (0);
+} /* SkGeBoardInit */
+
+
+/*****************************************************************************
+ *
+ * 	BoardAllocMem - allocate the memory for the descriptor rings
+ *
+ * Description:
+ *	This function allocates the memory for all descriptor rings.
+ *	Each ring is aligned for the desriptor alignment and no ring
+ *	has a 4 GByte boundary in it (because the upper 32 bit must
+ *	be constant for all descriptiors in one rings).
+ *
+ * Returns:
+ *	SK_TRUE, if all memory could be allocated
+ *	SK_FALSE, if not
+ */
+static SK_BOOL BoardAllocMem(
+SK_AC	*pAC)
+{
+caddr_t		pDescrMem;	/* pointer to descriptor memory area */
+size_t		AllocLength;	/* length of complete descriptor area */
+int		i;		/* loop counter */
+unsigned long	BusAddr;
+
+	
+	/* rings plus one for alignment (do not cross 4 GB boundary) */
+	/* RX_RING_SIZE is assumed bigger than TX_RING_SIZE */
+#if (BITS_PER_LONG == 32)
+	AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + 8;
+#else
+	AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound
+		+ RX_RING_SIZE + 8;
+#endif
+	pDescrMem = kmalloc(AllocLength, GFP_KERNEL);
+	if (pDescrMem == NULL) {
+		return (SK_FALSE);
+	}
+	pAC->pDescrMem = pDescrMem;
+	memset(pDescrMem, 0, AllocLength);
+	/* Descriptors need 8 byte alignment */
+	BusAddr = virt_to_bus(pDescrMem);
+	if (BusAddr & (DESCR_ALIGN-1)) {
+		pDescrMem += DESCR_ALIGN - (BusAddr & (DESCR_ALIGN-1));
+	}
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		if ((virt_to_bus(pDescrMem) & ~0xFFFFFFFFULL) != 
+		    (virt_to_bus(pDescrMem+TX_RING_SIZE) & ~0xFFFFFFFFULL)) {
+			pDescrMem += TX_RING_SIZE;
+		}
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+			("TX%d/A: pDescrMem: %lX,   PhysDescrMem: %lX\n",
+			i, (unsigned long) pDescrMem,
+			(unsigned long)virt_to_bus(pDescrMem)));
+		pAC->TxPort[i][0].pTxDescrRing = pDescrMem;
+		pAC->TxPort[i][0].VTxDescrRing = virt_to_bus(pDescrMem);
+		pDescrMem += TX_RING_SIZE;
+	
+		if ((virt_to_bus(pDescrMem) & ~0xFFFFFFFFULL) != 
+		    (virt_to_bus(pDescrMem+RX_RING_SIZE) & ~0xFFFFFFFFULL)) {
+			pDescrMem += RX_RING_SIZE;
+		}
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+			("RX%d: pDescrMem: %lX,   PhysDescrMem: %lX\n",
+			i, (unsigned long) pDescrMem,
+			(unsigned long)(virt_to_bus(pDescrMem))));
+		pAC->RxPort[i].pRxDescrRing = pDescrMem;
+		pAC->RxPort[i].VRxDescrRing = virt_to_bus(pDescrMem);
+		pDescrMem += RX_RING_SIZE;
+	} /* for */
+	
+	return (SK_TRUE);
+} /* BoardAllocMem */
+
+
+/****************************************************************************
+ *
+ *	BoardFreeMem - reverse of BoardAllocMem
+ *
+ * Description:
+ *	Free all memory allocated in BoardAllocMem: adapter context,
+ *	descriptor rings, locks.
+ *
+ * Returns:	N/A
+ */
+static void BoardFreeMem(
+SK_AC		*pAC)
+{
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("BoardFreeMem\n"));
+	kfree(pAC->pDescrMem);
+} /* BoardFreeMem */
+
+
+/*****************************************************************************
+ *
+ * 	BoardInitMem - initiate the descriptor rings
+ *
+ * Description:
+ *	This function sets the descriptor rings up in memory.
+ *	The adapter is initialized with the descriptor start addresses.
+ *
+ * Returns:	N/A
+ */
+static void BoardInitMem(
+SK_AC	*pAC)	/* pointer to adapter context */
+{
+int	i;		/* loop counter */
+int	RxDescrSize;	/* the size of a rx descriptor rounded up to alignment*/
+int	TxDescrSize;	/* the size of a tx descriptor rounded up to alignment*/
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("BoardInitMem\n"));
+
+	RxDescrSize = (((sizeof(RXD) - 1) / DESCR_ALIGN) + 1) * DESCR_ALIGN;
+	pAC->RxDescrPerRing = RX_RING_SIZE / RxDescrSize;
+	TxDescrSize = (((sizeof(TXD) - 1) / DESCR_ALIGN) + 1) * DESCR_ALIGN;
+	pAC->TxDescrPerRing = TX_RING_SIZE / RxDescrSize;
+	
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		SetupRing(
+			pAC,
+			pAC->TxPort[i][0].pTxDescrRing,
+			pAC->TxPort[i][0].VTxDescrRing,
+			(RXD**)&pAC->TxPort[i][0].pTxdRingHead,
+			(RXD**)&pAC->TxPort[i][0].pTxdRingTail,
+			(RXD**)&pAC->TxPort[i][0].pTxdRingPrev,
+			&pAC->TxPort[i][0].TxdRingFree,
+			SK_TRUE);
+		SetupRing(
+			pAC,
+			pAC->RxPort[i].pRxDescrRing,
+			pAC->RxPort[i].VRxDescrRing,
+			&pAC->RxPort[i].pRxdRingHead,
+			&pAC->RxPort[i].pRxdRingTail,
+			&pAC->RxPort[i].pRxdRingPrev,
+			&pAC->RxPort[i].RxdRingFree,
+			SK_FALSE);
+	}
+} /* BoardInitMem */
+
+
+/*****************************************************************************
+ *
+ * 	SetupRing - create one descriptor ring
+ *
+ * Description:
+ *	This function creates one descriptor ring in the given memory area.
+ *	The head, tail and number of free descriptors in the ring are set.
+ *
+ * Returns:
+ *	none
+ */
+static void SetupRing(
+SK_AC		*pAC,
+void		*pMemArea,	/* a pointer to the memory area for the ring */
+uintptr_t	VMemArea,	/* the virtual bus address of the memory area */
+RXD		**ppRingHead,	/* address where the head should be written */
+RXD		**ppRingTail,	/* address where the tail should be written */
+RXD		**ppRingPrev,	/* address where the tail should be written */
+int		*pRingFree,	/* address where the # of free descr. goes */
+SK_BOOL		IsTx)		/* flag: is this a tx ring */
+{
+int	i;		/* loop counter */
+int	DescrSize;	/* the size of a descriptor rounded up to alignment*/
+int	DescrNum;	/* number of descriptors per ring */
+RXD	*pDescr;	/* pointer to a descriptor (receive or transmit) */
+RXD	*pNextDescr;	/* pointer to the next descriptor */
+RXD	*pPrevDescr;	/* pointer to the previous descriptor */
+uintptr_t VNextDescr;	/* the virtual bus address of the next descriptor */
+
+	if (IsTx == SK_TRUE) {
+		DescrSize = (((sizeof(TXD) - 1) / DESCR_ALIGN) + 1) *
+			DESCR_ALIGN;
+		DescrNum = TX_RING_SIZE / DescrSize;
+	}
+	else {
+		DescrSize = (((sizeof(RXD) - 1) / DESCR_ALIGN) + 1) *
+			DESCR_ALIGN;
+		DescrNum = RX_RING_SIZE / DescrSize;
+	}
+	
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+		("Descriptor size: %d   Descriptor Number: %d\n",
+		DescrSize,DescrNum));
+	
+	pDescr = (RXD*) pMemArea;
+	pPrevDescr = NULL;
+	pNextDescr = (RXD*) (((char*)pDescr) + DescrSize);
+	VNextDescr = VMemArea + DescrSize;
+	for(i=0; i<DescrNum; i++) {
+		/* set the pointers right */
+		pDescr->VNextRxd = VNextDescr & 0xffffffffULL;
+		pDescr->pNextRxd = pNextDescr;
+		pDescr->TcpSumStarts = pAC->CsOfs;
+		/* advance on step */
+		pPrevDescr = pDescr;
+		pDescr = pNextDescr;
+		pNextDescr = (RXD*) (((char*)pDescr) + DescrSize);
+		VNextDescr += DescrSize;
+	}
+	pPrevDescr->pNextRxd = (RXD*) pMemArea;
+	pPrevDescr->VNextRxd = VMemArea;
+	pDescr = (RXD*) pMemArea;
+	*ppRingHead = (RXD*) pMemArea;
+	*ppRingTail = *ppRingHead;
+	*ppRingPrev = pPrevDescr;
+	*pRingFree = DescrNum;
+} /* SetupRing */
+
+
+/*****************************************************************************
+ *
+ * 	PortReInitBmu - re-initiate the descriptor rings for one port
+ *
+ * Description:
+ *	This function reinitializes the descriptor rings of one port
+ *	in memory. The port must be stopped before.
+ *	The HW is initialized with the descriptor start addresses.
+ *
+ * Returns:
+ *	none
+ */
+static void PortReInitBmu(
+SK_AC	*pAC,		/* pointer to adapter context */
+int	PortIndex)	/* index of the port for which to re-init */
+{
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("PortReInitBmu "));
+
+	/* set address of first descriptor of ring in BMU */
+	SK_OUT32(pAC->IoBase, TxQueueAddr[PortIndex][TX_PRIO_LOW]+
+		TX_Q_CUR_DESCR_LOW,
+		(uint32_t)(((caddr_t)
+		(pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxdRingHead) -
+		pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxDescrRing +
+		pAC->TxPort[PortIndex][TX_PRIO_LOW].VTxDescrRing) &
+		0xFFFFFFFF));
+	SK_OUT32(pAC->IoBase, TxQueueAddr[PortIndex][TX_PRIO_LOW]+
+		TX_Q_DESCR_HIGH,
+		(uint32_t)(((caddr_t)
+		(pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxdRingHead) -
+		pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxDescrRing +
+		pAC->TxPort[PortIndex][TX_PRIO_LOW].VTxDescrRing) >> 32));
+	SK_OUT32(pAC->IoBase, RxQueueAddr[PortIndex]+RX_Q_CUR_DESCR_LOW,
+		(uint32_t)(((caddr_t)(pAC->RxPort[PortIndex].pRxdRingHead) -
+		pAC->RxPort[PortIndex].pRxDescrRing +
+		pAC->RxPort[PortIndex].VRxDescrRing) & 0xFFFFFFFF));
+	SK_OUT32(pAC->IoBase, RxQueueAddr[PortIndex]+RX_Q_DESCR_HIGH,
+		(uint32_t)(((caddr_t)(pAC->RxPort[PortIndex].pRxdRingHead) -
+		pAC->RxPort[PortIndex].pRxDescrRing +
+		pAC->RxPort[PortIndex].VRxDescrRing) >> 32));
+} /* PortReInitBmu */
+
+
+/****************************************************************************
+ *
+ *	SkGeIsr - handle adapter interrupts
+ *
+ * Description:
+ *	The interrupt routine is called when the network adapter
+ *	generates an interrupt. It may also be called if another device
+ *	shares this interrupt vector with the driver.
+ *
+ * Returns: N/A
+ *
+ */
+static void SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+struct device *dev = (struct device *)dev_id;
+SK_AC		*pAC;
+SK_U32		IntSrc;		/* interrupts source register contents */	
+
+	pAC = (SK_AC*) dev->priv;
+	
+	/*
+	 * Check and process if its our interrupt
+	 */
+	SK_IN32(pAC->IoBase, B0_SP_ISRC, &IntSrc);
+	if (IntSrc == 0) {
+		return;
+	}
+
+	while (((IntSrc & IRQ_MASK) & ~SPECIAL_IRQS) != 0) {
+#if 0 /* software irq currently not used */
+		if (IntSrc & IRQ_SW) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("Software IRQ\n"));
+		}
+#endif
+		if (IntSrc & IRQ_EOF_RX1) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF RX1 IRQ\n"));
+			ReceiveIrq(pAC, &pAC->RxPort[0]);
+			SK_PNMI_CNT_RX_INTR(pAC);
+		}
+		if (IntSrc & IRQ_EOF_RX2) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF RX2 IRQ\n"));
+			ReceiveIrq(pAC, &pAC->RxPort[1]);
+			SK_PNMI_CNT_RX_INTR(pAC);
+		}
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+		if (IntSrc & IRQ_EOF_AS_TX1) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF AS TX1 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC);
+			spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+			FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]);
+			spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+		}
+		if (IntSrc & IRQ_EOF_AS_TX2) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF AS TX2 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC);
+			spin_lock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock);
+			FreeTxDescriptors(pAC, &pAC->TxPort[1][TX_PRIO_LOW]);
+			spin_unlock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock);
+		}
+#if 0 /* only if sync. queues used */
+		if (IntSrc & IRQ_EOF_SY_TX1) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF SY TX1 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC);
+			spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+			FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH);
+			spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+			ClearTxIrq(pAC, 0, TX_PRIO_HIGH);
+		}
+		if (IntSrc & IRQ_EOF_SY_TX2) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF SY TX2 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC);
+			spin_lock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock);
+			FreeTxDescriptors(pAC, 1, TX_PRIO_HIGH);
+			spin_unlock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock);
+			ClearTxIrq(pAC, 1, TX_PRIO_HIGH);
+		}
+#endif /* 0 */
+#endif /* USE_TX_COMPLETE */
+
+		/* do all IO at once */
+		if (IntSrc & IRQ_EOF_RX1)
+			ClearAndStartRx(pAC, 0);
+		if (IntSrc & IRQ_EOF_RX2)
+			ClearAndStartRx(pAC, 1);
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+		if (IntSrc & IRQ_EOF_AS_TX1)
+			ClearTxIrq(pAC, 0, TX_PRIO_LOW);
+		if (IntSrc & IRQ_EOF_AS_TX2)
+			ClearTxIrq(pAC, 1, TX_PRIO_LOW);
+#endif
+		SK_IN32(pAC->IoBase, B0_ISRC, &IntSrc);
+	} /* while (IntSrc & IRQ_MASK != 0) */
+
+	if ((IntSrc & SPECIAL_IRQS) || pAC->CheckQueue) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC,
+			("SPECIAL IRQ\n"));
+		pAC->CheckQueue = SK_FALSE;
+		spin_lock(&pAC->SlowPathLock);
+		if (IntSrc & SPECIAL_IRQS)
+			SkGeSirqIsr(pAC, pAC->IoBase, IntSrc);
+		SkEventDispatcher(pAC, pAC->IoBase);
+		spin_unlock(&pAC->SlowPathLock);
+	}
+	/*
+	 * do it all again is case we cleared an interrupt that 
+	 * came in after handling the ring (OUTs may be delayed
+	 * in hardware buffers, but are through after IN)
+	 */
+	ReceiveIrq(pAC, &pAC->RxPort[pAC->ActivePort]);
+//	ReceiveIrq(pAC, &pAC->RxPort[1]);
+
+#if 0
+// #ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+	spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+	FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]);
+	spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+
+	spin_lock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock);
+	FreeTxDescriptors(pAC, &pAC->TxPort[1][TX_PRIO_LOW]);
+	spin_unlock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock);
+
+#if 0	/* only if sync. queues used */
+	spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+	FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH);
+	spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+	
+	spin_lock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock);
+	FreeTxDescriptors(pAC, 1, TX_PRIO_HIGH);
+	spin_unlock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock);
+#endif /* 0 */
+#endif /* USE_TX_COMPLETE */
+
+	/* IRQ is processed - Enable IRQs again*/
+	SK_OUT32(pAC->IoBase, B0_IMSK, IRQ_MASK);
+
+	return;
+} /* SkGeIsr */
+
+
+/****************************************************************************
+ *
+ *	SkGeIsrOnePort - handle adapter interrupts for single port adapter
+ *
+ * Description:
+ *	The interrupt routine is called when the network adapter
+ *	generates an interrupt. It may also be called if another device
+ *	shares this interrupt vector with the driver.
+ *	This is the same as above, but handles only one port.
+ *
+ * Returns: N/A
+ *
+ */
+static void SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+struct device *dev = (struct device *)dev_id;
+SK_AC		*pAC;
+SK_U32		IntSrc;		/* interrupts source register contents */	
+
+	pAC = (SK_AC*) dev->priv;
+	
+	/*
+	 * Check and process if its our interrupt
+	 */
+	SK_IN32(pAC->IoBase, B0_SP_ISRC, &IntSrc);
+	if (IntSrc == 0) {
+		return;
+	}
+
+	while (((IntSrc & IRQ_MASK) & ~SPECIAL_IRQS) != 0) {
+#if 0 /* software irq currently not used */
+		if (IntSrc & IRQ_SW) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("Software IRQ\n"));
+		}
+#endif
+		if (IntSrc & IRQ_EOF_RX1) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF RX1 IRQ\n"));
+			ReceiveIrq(pAC, &pAC->RxPort[0]);
+			SK_PNMI_CNT_RX_INTR(pAC);
+		}
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+		if (IntSrc & IRQ_EOF_AS_TX1) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF AS TX1 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC);
+			spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+			FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]);
+			spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+		}
+#if 0 /* only if sync. queues used */
+		if (IntSrc & IRQ_EOF_SY_TX1) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF SY TX1 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC);
+			spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+			FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH);
+			spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+			ClearTxIrq(pAC, 0, TX_PRIO_HIGH);
+		}
+#endif /* 0 */
+#endif /* USE_TX_COMPLETE */
+
+		/* do all IO at once */
+		if (IntSrc & IRQ_EOF_RX1)
+			ClearAndStartRx(pAC, 0);
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+		if (IntSrc & IRQ_EOF_AS_TX1)
+			ClearTxIrq(pAC, 0, TX_PRIO_LOW);
+#endif
+		SK_IN32(pAC->IoBase, B0_ISRC, &IntSrc);
+	} /* while (IntSrc & IRQ_MASK != 0) */
+	
+	if ((IntSrc & SPECIAL_IRQS) || pAC->CheckQueue) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC,
+			("SPECIAL IRQ\n"));
+		pAC->CheckQueue = SK_FALSE;
+		spin_lock(&pAC->SlowPathLock);
+		if (IntSrc & SPECIAL_IRQS)
+			SkGeSirqIsr(pAC, pAC->IoBase, IntSrc);
+		SkEventDispatcher(pAC, pAC->IoBase);
+		spin_unlock(&pAC->SlowPathLock);
+	}
+	/*
+	 * do it all again is case we cleared an interrupt that 
+	 * came in after handling the ring (OUTs may be delayed
+	 * in hardware buffers, but are through after IN)
+	 */
+	ReceiveIrq(pAC, &pAC->RxPort[0]);
+
+#if 0
+// #ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+	spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+	FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]);
+	spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+
+#if 0	/* only if sync. queues used */
+	spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+	FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH);
+	spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+	
+#endif /* 0 */
+#endif /* USE_TX_COMPLETE */
+
+	/* IRQ is processed - Enable IRQs again*/
+	SK_OUT32(pAC->IoBase, B0_IMSK, IRQ_MASK);
+
+	return;
+} /* SkGeIsrOnePort */
+
+
+/****************************************************************************
+ *
+ *	SkGeOpen - handle start of initialized adapter
+ *
+ * Description:
+ *	This function starts the initialized adapter.
+ *	The board level variable is set and the adapter is
+ *	brought to full functionality.
+ *	The device flags are set for operation.
+ *	Do all necessary level 2 initialization, enable interrupts and
+ *	give start command to RLMT.
+ *
+ * Returns:
+ *	0 on success
+ *	!= 0 on error
+ */
+static int SkGeOpen(
+struct device	*dev)
+{
+SK_AC		*pAC;		/* pointer to adapter context struct */
+unsigned int	Flags;		/* for spin lock */
+int		i;
+SK_EVPARA	EvPara;		/* an event parameter union */
+
+	pAC = (SK_AC*) dev->priv;
+	
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeOpen: pAC=0x%lX:\n", (unsigned long)pAC));
+
+	if (pAC->BoardLevel == 0) {
+		/* level 1 init common modules here */
+		if (SkGeInit(pAC, pAC->IoBase, 1) != 0) {
+			printk("%s: HWInit(1) failed\n", pAC->dev->name);
+			return (-1);
+		}
+		SkI2cInit	(pAC, pAC->IoBase, 1);
+		SkEventInit	(pAC, pAC->IoBase, 1);
+		SkPnmiInit	(pAC, pAC->IoBase, 1);
+		SkAddrInit	(pAC, pAC->IoBase, 1);
+		SkRlmtInit	(pAC, pAC->IoBase, 1);
+		SkTimerInit	(pAC, pAC->IoBase, 1);
+		pAC->BoardLevel = 1;
+	}
+		
+	/* level 2 init modules here */
+	SkGeInit	(pAC, pAC->IoBase, 2);
+	SkI2cInit	(pAC, pAC->IoBase, 2);
+	SkEventInit	(pAC, pAC->IoBase, 2);
+	SkPnmiInit	(pAC, pAC->IoBase, 2);
+	SkAddrInit	(pAC, pAC->IoBase, 2);
+	SkRlmtInit	(pAC, pAC->IoBase, 2);
+	SkTimerInit	(pAC, pAC->IoBase, 2);
+	pAC->BoardLevel = 2;
+	
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		// Enable transmit descriptor polling.
+		SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE);
+		FillRxRing(pAC, &pAC->RxPort[i]);
+	}
+	SkGeYellowLED(pAC, pAC->IoBase, 1);
+
+#ifdef USE_INT_MOD
+// moderate only TX complete interrupts (these are not time critical)
+#define IRQ_MOD_MASK (IRQ_EOF_AS_TX1 | IRQ_EOF_AS_TX2)
+	{
+		unsigned long ModBase;
+		ModBase = 53125000 / INTS_PER_SEC;
+		SK_OUT32(pAC->IoBase, B2_IRQM_INI, ModBase);
+		SK_OUT32(pAC->IoBase, B2_IRQM_MSK, IRQ_MOD_MASK);
+		SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_START);
+	}
+#endif
+
+	/* enable Interrupts */
+	SK_OUT32(pAC->IoBase, B0_IMSK, IRQ_MASK);
+	SK_OUT32(pAC->IoBase, B0_HWE_IMSK, IRQ_HWE_MASK);
+
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+	if (pAC->RlmtMode != 0) {
+		EvPara.Para32[0] = pAC->RlmtMode;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_MODE_CHANGE,
+			EvPara);
+	}
+	SkEventDispatcher(pAC, pAC->IoBase);
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	MOD_INC_USE_COUNT;
+	
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeOpen suceeded\n"));
+
+	return (0);
+} /* SkGeOpen */
+
+
+/****************************************************************************
+ *
+ *	SkGeClose - Stop initialized adapter
+ *
+ * Description:
+ *	Close initialized adapter.
+ *
+ * Returns:
+ *	0 - on success
+ *	error code - on error
+ */
+static int SkGeClose(
+struct device	*dev)
+{
+SK_AC		*pAC;
+unsigned int	Flags;		/* for spin lock */
+int		i;
+SK_EVPARA	EvPara;
+
+	dev->start = 0;
+	set_bit(0, (void*)&dev->tbusy);
+	
+	pAC = (SK_AC*) dev->priv;
+	
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeClose: pAC=0x%lX ", (unsigned long)pAC));
+
+	/* 
+	 * Clear multicast table, promiscuous mode ....
+	 */
+	SkAddrMcClear(pAC, pAC->IoBase, pAC->ActivePort, 0);
+	SkAddrPromiscuousChange(pAC, pAC->IoBase, pAC->ActivePort,
+		SK_PROM_MODE_NONE);
+
+
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	/* disable interrupts */
+	SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+	SkEventDispatcher(pAC, pAC->IoBase);
+	SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+	/* stop the hardware */
+	SkGeDeInit(pAC, pAC->IoBase);
+	pAC->BoardLevel = 0;
+	
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		/* clear all descriptor rings */
+		ReceiveIrq(pAC, &pAC->RxPort[i]);
+		ClearRxRing(pAC, &pAC->RxPort[i]);
+		ClearTxRing(pAC, &pAC->TxPort[i][TX_PRIO_LOW]);
+	}
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeClose: done "));
+
+	MOD_DEC_USE_COUNT;
+	
+	return (0);
+} /* SkGeClose */
+
+/*****************************************************************************
+ *
+ * 	SkGeXmit - Linux frame transmit function
+ *
+ * Description:
+ *	The system calls this function to send frames onto the wire.
+ *	It puts the frame in the tx descriptor ring. If the ring is
+ *	full then, the 'tbusy' flag is set.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ * WARNING: returning 1 in 'tbusy' case caused system crashes (double
+ *	allocated skb's) !!!
+ */
+static int SkGeXmit(struct sk_buff *skb, struct device *dev)
+{
+SK_AC		*pAC;
+int		Rc;	/* return code of XmitFrame */
+	
+	pAC = (SK_AC*) dev->priv;
+
+	Rc = XmitFrame(pAC, &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW], skb);
+
+	if (Rc == 0) {
+		/* transmitter out of resources */
+		set_bit(0, (void*) &dev->tbusy);
+		return (0);
+	} 
+	dev->trans_start = jiffies;
+	return (0);
+} /* SkGeXmit */
+	
+
+/*****************************************************************************
+ *
+ * 	XmitFrame - fill one socket buffer into the transmit ring
+ *
+ * Description:
+ *	This function puts a message into the transmit descriptor ring
+ *	if there is a descriptors left.
+ *	Linux skb's consist of only one continuous buffer.
+ *	The first step locks the ring. It is held locked
+ *	all time to avoid problems with SWITCH_../PORT_RESET.
+ *	Then the descriptoris allocated.
+ *	The second part is linking the buffer to the descriptor.
+ *	At the very last, the Control field of the descriptor
+ *	is made valid for the BMU and a start TX command is given
+ *	if necessary.
+ *
+ * Returns:
+ *	> 0 - on succes: the number of bytes in the message
+ *	= 0 - on resource shortage: this frame sent or dropped, now
+ *        the ring is full ( -> set tbusy)
+ *	< 0 - on failure: other problems (not used)
+ */
+static int XmitFrame(
+SK_AC 		*pAC,		/* pointer to adapter context */
+TX_PORT		*pTxPort,	/* pointer to struct of port to send to */
+struct sk_buff	*pMessage)	/* pointer to send-message */
+{
+TXD		*pTxd;		/* the rxd to fill */
+unsigned int	Flags;
+SK_U64		PhysAddr;
+int		BytesSend;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+		("X"));
+
+	spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
+
+	if (pTxPort->TxdRingFree == 0) {
+		/* no enough free descriptors in ring at the moment */
+		FreeTxDescriptors(pAC, pTxPort);
+		if (pTxPort->TxdRingFree == 0) {
+			spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+			SK_PNMI_CNT_NO_TX_BUF(pAC);
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_TX_PROGRESS,
+				("XmitFrame failed\n"));
+			/* this message can not be sent now */
+			DEV_KFREE_SKB(pMessage);
+			return (0);
+		}
+	}
+	/* advance head counter behind descriptor needed for this frame */
+	pTxd = pTxPort->pTxdRingHead;
+	pTxPort->pTxdRingHead = pTxd->pNextTxd;
+	pTxPort->TxdRingFree--;
+	/* the needed descriptor is reserved now */
+	
+	/* 
+	 * everything allocated ok, so add buffer to descriptor
+	 */
+
+#ifdef SK_DUMP_TX
+	DumpMsg(pMessage, "XmitFrame");
+#endif
+
+	/* set up descriptor and CONTROL dword */
+	PhysAddr = virt_to_bus(pMessage->data);
+	pTxd->VDataLow = (SK_U32)  (PhysAddr & 0xffffffff);
+	pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+	pTxd->pMBuf = pMessage;
+	pTxd->TBControl = TX_CTRL_OWN_BMU | TX_CTRL_STF |
+		TX_CTRL_CHECK_DEFAULT | TX_CTRL_SOFTWARE |
+#ifdef USE_TX_COMPLETE
+		TX_CTRL_EOF | TX_CTRL_EOF_IRQ | pMessage->len;
+#else
+		TX_CTRL_EOF | pMessage->len;
+#endif
+	
+	if ((pTxPort->pTxdRingPrev->TBControl & TX_CTRL_OWN_BMU) == 0) {
+		/* previous descriptor already done, so give tx start cmd */
+		/* StartTx(pAC, pTxPort->HwAddr); */
+		SK_OUT8(pTxPort->HwAddr, TX_Q_CTRL, TX_Q_CTRL_START);
+	}
+	pTxPort->pTxdRingPrev = pTxd;
+	
+	
+	BytesSend = pMessage->len;
+	/* after releasing the lock, the skb may be immidiately freed */
+	if (pTxPort->TxdRingFree != 0) {
+		spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+		return (BytesSend);
+	}
+	else {
+		/* ring full: set tbusy on return */
+		spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+		return (0);
+	}
+} /* XmitFrame */
+
+
+/*****************************************************************************
+ *
+ * 	FreeTxDescriptors - release descriptors from the descriptor ring
+ *
+ * Description:
+ *	This function releases descriptors from a transmit ring if they
+ *	have been sent by the BMU.
+ *	If a descriptors is sent, it can be freed and the message can
+ *	be freed, too.
+ *	The SOFTWARE controllable bit is used to prevent running around a
+ *	completely free ring for ever. If this bit is no set in the
+ *	frame (by XmitFrame), this frame has never been sent or is
+ *	already freed.
+ *	The Tx descriptor ring lock must be held while calling this function !!!
+ *
+ * Returns:
+ *	none
+ */
+static void FreeTxDescriptors(
+SK_AC	*pAC,		/* pointer to the adapter context */
+TX_PORT	*pTxPort)	/* pointer to destination port structure */
+{
+TXD	*pTxd;		/* pointer to the checked descriptor */
+TXD	*pNewTail;	/* pointer to 'end' of the ring */
+SK_U32	Control;	/* TBControl field of descriptor */
+
+	pNewTail = pTxPort->pTxdRingTail;
+	pTxd = pNewTail;
+	
+	/* 
+	 * loop forever; exits if TX_CTRL_SOFTWARE bit not set in start frame
+	 * or TX_CTRL_OWN_BMU bit set in any frame
+	 */
+	while (1) {
+		Control = pTxd->TBControl;
+		if ((Control & TX_CTRL_SOFTWARE) == 0) {
+			/* 
+			 * software controllable bit is set in first
+			 * fragment when given to BMU. Not set means that
+			 * this fragment was never sent or is already 
+			 * freed ( -> ring completely free now).
+			 */
+			pTxPort->pTxdRingTail = pTxd;
+			pAC->dev->tbusy = 0;
+			return;
+		}
+		if (Control & TX_CTRL_OWN_BMU) {
+			pTxPort->pTxdRingTail = pTxd;
+			if (pTxPort->TxdRingFree > 0) {
+				pAC->dev->tbusy = 0;
+			}
+			return;
+		}
+		
+		DEV_KFREE_SKB(pTxd->pMBuf); /* free message */
+		pTxPort->TxdRingFree++;
+		pTxd->TBControl &= ~TX_CTRL_SOFTWARE;
+		pTxd = pTxd->pNextTxd; /* point behind fragment with EOF */
+	} /* while(forever) */
+} /* FreeTxDescriptors */
+
+
+/*****************************************************************************
+ *
+ * 	FillRxRing - fill the receive ring with valid descriptors
+ *
+ * Description:
+ *	This function fills the receive ring descriptors with data
+ *	segments and makes them valid for the BMU.
+ *	The active ring is filled completely, if possible.
+ *	The non-active ring is filled only partial to save memory.
+ *
+ * Description of rx ring structure:
+ *	head - points to the descriptor which will be used next by the BMU
+ *	tail - points to the next descriptor to give to the BMU
+ *	
+ * Returns:	N/A
+ */
+static void FillRxRing(
+SK_AC		*pAC,		/* pointer to the adapter context */
+RX_PORT		*pRxPort)	/* ptr to port struct for which the ring
+				   should be filled */
+{
+unsigned int	Flags;
+
+	spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags);
+	while (pRxPort->RxdRingFree > pRxPort->RxFillLimit) {
+		if(!FillRxDescriptor(pAC, pRxPort))
+			break;
+	}
+	spin_unlock_irqrestore(&pRxPort->RxDesRingLock, Flags);
+} /* FillRxRing */
+
+
+/*****************************************************************************
+ *
+ * 	FillRxDescriptor - fill one buffer into the receive ring
+ *
+ * Description:
+ *	The function allocates a new receive buffer and
+ *	puts it into the next descriptor.
+ *
+ * Returns:
+ *	SK_TRUE - a buffer was added to the ring
+ *	SK_FALSE - a buffer could not be added
+ */
+static SK_BOOL FillRxDescriptor(
+SK_AC		*pAC,		/* pointer to the adapter context struct */
+RX_PORT		*pRxPort)	/* ptr to port struct of ring to fill */
+{
+struct sk_buff	*pMsgBlock;	/* pointer to a new message block */
+RXD		*pRxd;		/* the rxd to fill */
+SK_U16		Length;		/* data fragment length */
+SK_U64		PhysAddr;	/* physical address of a rx buffer */
+
+	pMsgBlock = alloc_skb(pAC->RxBufSize, GFP_ATOMIC);
+	if (pMsgBlock == NULL) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+			SK_DBGCAT_DRV_ENTRY,
+			("%s: Allocation of rx buffer failed !\n",
+			pAC->dev->name));
+		SK_PNMI_CNT_NO_RX_BUF(pAC);
+		return(SK_FALSE);
+	}
+	skb_reserve(pMsgBlock, 2); /* to align IP frames */
+	/* skb allocated ok, so add buffer */
+	pRxd = pRxPort->pRxdRingTail;
+	pRxPort->pRxdRingTail = pRxd->pNextRxd;
+	pRxPort->RxdRingFree--;
+	Length = pAC->RxBufSize;
+	PhysAddr = virt_to_bus(pMsgBlock->data);
+	pRxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff);
+	pRxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+	pRxd->pMBuf = pMsgBlock;
+	pRxd->RBControl = RX_CTRL_OWN_BMU | RX_CTRL_STF |
+		RX_CTRL_EOF_IRQ | RX_CTRL_CHECK_CSUM | Length;
+	return (SK_TRUE);
+
+} /* FillRxDescriptor */
+
+
+/*****************************************************************************
+ *
+ * 	ReQueueRxBuffer - fill one buffer back into the receive ring
+ *
+ * Description:
+ *	Fill a given buffer back into the rx ring. The buffer
+ *	has been previously allocated and aligned, and its phys.
+ *	address calculated, so this is no more necessary.
+ *
+ * Returns: N/A
+ */
+static void ReQueueRxBuffer(
+SK_AC		*pAC,		/* pointer to the adapter context struct */
+RX_PORT		*pRxPort,	/* ptr to port struct of ring to fill */
+struct sk_buff	*pMsg,		/* pointer to the buffer */
+SK_U32		PhysHigh,	/* phys address high dword */
+SK_U32		PhysLow)	/* phys address low dword */
+{
+RXD		*pRxd;		/* the rxd to fill */
+SK_U16		Length;		/* data fragment length */
+
+	pRxd = pRxPort->pRxdRingTail;
+	pRxPort->pRxdRingTail = pRxd->pNextRxd;
+	pRxPort->RxdRingFree--;
+	Length = pAC->RxBufSize;
+	pRxd->VDataLow = PhysLow;
+	pRxd->VDataHigh = PhysHigh;
+	pRxd->pMBuf = pMsg;
+	pRxd->RBControl = RX_CTRL_OWN_BMU | RX_CTRL_STF |
+		RX_CTRL_EOF_IRQ | RX_CTRL_CHECK_CSUM | Length;
+	return;
+} /* ReQueueRxBuffer */
+
+
+/*****************************************************************************
+ *
+ * 	ReceiveIrq - handle a receive IRQ
+ *
+ * Description:
+ *	This function is called when a receive IRQ is set.
+ *	It walks the receive descriptor ring and sends up all
+ *	frames that are complete.
+ *
+ * Returns:	N/A
+ */
+static void ReceiveIrq(
+SK_AC		*pAC,		/* pointer to adapter context */
+RX_PORT		*pRxPort)	/* pointer to receive port struct */
+{
+RXD		*pRxd;		/* pointer to receive descriptors */
+SK_U32		Control;	/* control field of descriptor */
+struct sk_buff	*pMsg;		/* pointer to message holding frame */
+struct sk_buff	*pNewMsg;	/* pointer to a new message for copying frame */
+int		FrameLength;	/* total length of received frame */
+SK_MBUF		*pRlmtMbuf;	/* ptr to a buffer for giving a frame to rlmt */
+SK_EVPARA	EvPara;		/* an event parameter union */	
+int		PortIndex = pRxPort->PortIndex;
+unsigned int	Offset;
+unsigned int	NumBytes;
+unsigned int	ForRlmt;
+SK_BOOL		IsBc;
+SK_BOOL		IsMc;
+SK_U32		FrameStat;
+unsigned short	Csum1;
+unsigned short	Csum2;
+unsigned short	Type;
+int		Result;
+
+rx_start:	
+	/* do forever; exit if RX_CTRL_OWN_BMU found */
+	while (pRxPort->RxdRingFree < pAC->RxDescrPerRing) {
+		pRxd = pRxPort->pRxdRingHead;
+		
+		Control = pRxd->RBControl;
+		
+		/* check if this descriptor is ready */
+		if ((Control & RX_CTRL_OWN_BMU) != 0) {
+			/* this descriptor is not yet ready */
+			FillRxRing(pAC, pRxPort);
+			return;
+		}
+		
+		/* get length of frame and check it */
+		FrameLength = Control & RX_CTRL_LEN_MASK;
+		if (FrameLength > pAC->RxBufSize)
+			goto rx_failed;
+
+		/* check for STF and EOF */
+		if ((Control & (RX_CTRL_STF | RX_CTRL_EOF)) !=
+			(RX_CTRL_STF | RX_CTRL_EOF))
+			goto rx_failed;
+		
+		/* here we have a complete frame in the ring */
+		pMsg = pRxd->pMBuf;
+		
+		/*
+		 * if short frame then copy data to reduce memory waste
+		 */
+		if (FrameLength < SK_COPY_THRESHOLD) {
+			pNewMsg = alloc_skb(FrameLength+2, GFP_ATOMIC);
+			if (pNewMsg == NULL) {
+				/* use original skb */
+				/* set length in message */
+				skb_put(pMsg, FrameLength);
+			}
+			else {
+				/* alloc new skb and copy data */
+				skb_reserve(pNewMsg, 2);
+				skb_put(pNewMsg, FrameLength);
+				eth_copy_and_sum(pNewMsg, pMsg->data,
+					FrameLength, 0);
+				ReQueueRxBuffer(pAC, pRxPort, pMsg,
+					pRxd->VDataHigh, pRxd->VDataLow);
+				pMsg = pNewMsg;
+			}
+		}
+		else {
+			/* set length in message */
+			skb_put(pMsg, FrameLength);
+			/* hardware checksum */
+			Type = ntohs(*((short*)&pMsg->data[12]));
+			if (Type == 0x800) {
+				Csum1= pRxd->TcpSums & 0xffff;
+				Csum2=(pRxd->TcpSums >> 16) & 0xffff;
+				if ((Csum1 & 0xfffe) && (Csum2 & 0xfffe)) {
+					Result = SkCsGetReceiveInfo(pAC,
+						&pMsg->data[14], 
+						Csum1, Csum2);
+					if (Result == 
+						SKCS_STATUS_IP_FRAGMENT ||
+						Result ==
+						SKCS_STATUS_IP_CSUM_OK ||
+						Result ==
+						SKCS_STATUS_TCP_CSUM_OK ||
+						Result ==
+						SKCS_STATUS_UDP_CSUM_OK) {
+						pMsg->ip_summed =
+						CHECKSUM_UNNECESSARY;
+					}
+				} /* checksum calculation valid */
+			} /* IP frame */
+		} /* frame > SK_COPY_TRESHOLD */
+		
+		FrameStat = pRxd->FrameStat;
+		pRxd = pRxd->pNextRxd;
+		pRxPort->pRxdRingHead = pRxd;
+		pRxPort->RxdRingFree ++;
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS,
+			("Received frame of length %d on port %d\n",
+			FrameLength, PortIndex));
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS,
+			("Number of free rx descriptors: %d\n",
+			pRxPort->RxdRingFree));
+		
+		if ((Control & RX_CTRL_STAT_VALID) == RX_CTRL_STAT_VALID &&
+			(FrameStat & 
+			(XMR_FS_ANY_ERR | XMR_FS_1L_VLAN | XMR_FS_2L_VLAN))
+ 			 == 0) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_RX_PROGRESS,("V"));
+			ForRlmt = SK_RLMT_RX_PROTOCOL;
+			IsBc = (FrameStat & XMR_FS_BC)==XMR_FS_BC;
+			SK_RLMT_PRE_LOOKAHEAD(pAC, PortIndex, FrameLength,
+				IsBc, &Offset, &NumBytes);
+			if (NumBytes != 0) {
+				IsMc = (FrameStat & XMR_FS_MC)==XMR_FS_MC;
+				SK_RLMT_LOOKAHEAD(pAC, PortIndex, 
+					&pMsg->data[Offset],
+					IsBc, IsMc, &ForRlmt);
+			}
+			if (ForRlmt == SK_RLMT_RX_PROTOCOL) {
+				/* send up only frames from active port */
+			    	if (PortIndex == pAC->ActivePort) {
+					/* frame for upper layer */
+					SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 
+						SK_DBGCAT_DRV_RX_PROGRESS,
+						("U"));
+#ifdef DUMP_RX
+					DumpMsg(pMsg, "Rx");
+#endif
+					pMsg->dev = pAC->dev;
+					pMsg->protocol = eth_type_trans(pMsg,
+						pAC->dev);
+					SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,
+						FrameLength);
+					netif_rx(pMsg);
+					pAC->dev->last_rx = jiffies;
+				}
+				else {
+					/* drop frame */
+					SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 
+						SK_DBGCAT_DRV_RX_PROGRESS,
+						("D"));
+					DEV_KFREE_SKB(pMsg);
+				}
+			} /* if not for rlmt */
+			else {
+				/* packet for rlmt */
+				SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 
+					SK_DBGCAT_DRV_RX_PROGRESS, ("R"));
+				pRlmtMbuf = SkDrvAllocRlmtMbuf(pAC,
+					pAC->IoBase, FrameLength);
+				if (pRlmtMbuf != NULL) {
+					pRlmtMbuf->pNext = NULL;
+					pRlmtMbuf->Length = FrameLength;
+					pRlmtMbuf->PortIdx = PortIndex;
+					EvPara.pParaPtr = pRlmtMbuf;
+					memcpy((char*)(pRlmtMbuf->pData),
+					       (char*)(pMsg->data),
+					       FrameLength);
+					SkEventQueue(pAC, SKGE_RLMT,
+						SK_RLMT_PACKET_RECEIVED,
+						EvPara);
+					pAC->CheckQueue = SK_TRUE;
+					SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 
+						SK_DBGCAT_DRV_RX_PROGRESS,
+						("Q"));
+				}
+				if ((pAC->dev->flags & 
+					(IFF_PROMISC | IFF_ALLMULTI)) != 0 ||
+					(ForRlmt & SK_RLMT_RX_PROTOCOL) == 
+					SK_RLMT_RX_PROTOCOL) { 
+					pMsg->dev = pAC->dev;
+					pMsg->protocol = eth_type_trans(pMsg,
+						pAC->dev);
+					netif_rx(pMsg);
+					pAC->dev->last_rx = jiffies;
+				}
+				else {
+					DEV_KFREE_SKB(pMsg);
+				}
+
+			} /* if packet for rlmt */
+		} /* if valid frame */
+		else {
+			/* there is a receive error in this frame */
+			if ((FrameStat & XMR_FS_1L_VLAN) != 0) {
+				printk("%s: Received frame"
+					" with VLAN Level 1 header, check"
+					" switch configuration\n",
+					pAC->dev->name);
+			}
+			if ((FrameStat & XMR_FS_2L_VLAN) != 0) {
+				printk("%s: Received frame"
+					" with VLAN Level 2 header, check"
+					" switch configuration\n",
+					pAC->dev->name);
+			}
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_RX_PROGRESS,
+				("skge: Error in received frame, dropped!\n"
+				"Control: %x\nRxStat: %x\n",
+				Control, FrameStat));
+			DEV_KFREE_SKB(pMsg);
+		}
+	} /* while */
+	FillRxRing(pAC, pRxPort);
+	/* do not start if called from Close */
+	if (pAC->BoardLevel > 0) {
+		ClearAndStartRx(pAC, PortIndex);
+	}
+	return;
+
+rx_failed:
+	/* remove error frame */
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ERROR,
+		("Schrottdescriptor, length: 0x%x\n", FrameLength));
+	DEV_KFREE_SKB(pRxd->pMBuf);
+	pRxd->pMBuf = NULL;
+	pRxPort->RxdRingFree++;
+	pRxPort->pRxdRingHead = pRxd->pNextRxd;
+	goto rx_start;
+
+} /* ReceiveIrq */
+
+
+/*****************************************************************************
+ *
+ * 	ClearAndStartRx - give a start receive command to BMU, clear IRQ
+ *
+ * Description:
+ *	This function sends a start command and a clear interrupt
+ *	command for one receive queue to the BMU.
+ *
+ * Returns: N/A
+ *	none
+ */
+static void ClearAndStartRx(
+SK_AC	*pAC,		/* pointer to the adapter context */
+int	PortIndex)	/* index of the receive port (XMAC) */
+{
+	SK_OUT8(pAC->IoBase, RxQueueAddr[PortIndex]+RX_Q_CTRL,
+		RX_Q_CTRL_START | RX_Q_CTRL_CLR_I_EOF);
+} /* ClearAndStartRx */
+
+
+/*****************************************************************************
+ *
+ * 	ClearTxIrq - give a clear transmit IRQ command to BMU
+ *
+ * Description:
+ *	This function sends a clear tx IRQ command for one
+ *	transmit queue to the BMU.
+ *
+ * Returns: N/A
+ */
+static void ClearTxIrq(
+SK_AC	*pAC,		/* pointer to the adapter context */
+int	PortIndex,	/* index of the transmit port (XMAC) */
+int	Prio)		/* priority or normal queue */
+{
+	SK_OUT8(pAC->IoBase, TxQueueAddr[PortIndex][Prio]+TX_Q_CTRL,
+		TX_Q_CTRL_CLR_I_EOF);
+} /* ClearTxIrq */
+
+
+/*****************************************************************************
+ *
+ * 	ClearRxRing - remove all buffers from the receive ring
+ *
+ * Description:
+ *	This function removes all receive buffers from the ring.
+ *	The receive BMU must be stopped before calling this function.
+ *
+ * Returns: N/A
+ */
+static void ClearRxRing(
+SK_AC	*pAC,		/* pointer to adapter context */
+RX_PORT	*pRxPort)	/* pointer to rx port struct */
+{
+RXD		*pRxd;	/* pointer to the current descriptor */
+unsigned int	Flags;
+
+	if (pRxPort->RxdRingFree == pAC->RxDescrPerRing) {
+		return;
+	}
+	spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags);
+	pRxd = pRxPort->pRxdRingHead;
+	do {
+		if (pRxd->pMBuf != NULL) {
+			DEV_KFREE_SKB(pRxd->pMBuf);
+			pRxd->pMBuf = NULL;
+		}
+		pRxd->RBControl &= RX_CTRL_OWN_BMU;
+		pRxd = pRxd->pNextRxd;
+		pRxPort->RxdRingFree++;
+	} while (pRxd != pRxPort->pRxdRingTail);
+	pRxPort->pRxdRingTail = pRxPort->pRxdRingHead;
+	spin_unlock_irqrestore(&pRxPort->RxDesRingLock, Flags);
+} /* ClearRxRing */
+
+
+/*****************************************************************************
+ *
+ *	ClearTxRing - remove all buffers from the transmit ring
+ *
+ * Description:
+ *	This function removes all transmit buffers from the ring.
+ *	The transmit BMU must be stopped before calling this function
+ *	and transmitting at the upper level must be disabled.
+ *	The BMU own bit of all descriptors is cleared, the rest is
+ *	done by calling FreeTxDescriptors.
+ *
+ * Returns: N/A
+ */
+static void ClearTxRing(
+SK_AC	*pAC,		/* pointer to adapter context */
+TX_PORT	*pTxPort)	/* pointer to tx prt struct */
+{
+TXD		*pTxd;		/* pointer to the current descriptor */
+int		i;
+unsigned int	Flags;
+
+	spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
+	pTxd = pTxPort->pTxdRingHead;
+	for (i=0; i<pAC->TxDescrPerRing; i++) {
+		pTxd->TBControl &= ~TX_CTRL_OWN_BMU;
+		pTxd = pTxd->pNextTxd;
+	}
+	FreeTxDescriptors(pAC, pTxPort);
+	spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+} /* ClearTxRing */
+
+
+/*****************************************************************************
+ *
+ * 	SetQueueSizes - configure the sizes of rx and tx queues
+ *
+ * Description:
+ *	This function assigns the sizes for active and passive port
+ *	to the appropriate HWinit structure variables.
+ *	The passive port(s) get standard values, all remaining RAM
+ *	is given to the active port.
+ *	The queue sizes are in kbyte and must be multiple of 8.
+ *	The limits for the number of buffers filled into the rx rings
+ *	is also set in this routine.
+ *
+ * Returns:
+ *	none
+ */
+static void SetQueueSizes(
+SK_AC	*pAC)	/* pointer to the adapter context */
+{
+int	StandbyRam;	/* adapter RAM used for a standby port */
+int	RemainingRam;	/* adapter RAM available for the active port */
+int	RxRam;		/* RAM used for the active port receive queue */
+int	i;		/* loop counter */
+
+	StandbyRam = SK_RLMT_STANDBY_QRXSIZE + SK_RLMT_STANDBY_QXASIZE +
+		SK_RLMT_STANDBY_QXSSIZE;
+	RemainingRam = pAC->GIni.GIRamSize - 
+		(pAC->GIni.GIMacsFound-1) * StandbyRam;
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		pAC->GIni.GP[i].PRxQSize = SK_RLMT_STANDBY_QRXSIZE;
+		pAC->GIni.GP[i].PXSQSize = SK_RLMT_STANDBY_QXSSIZE;
+		pAC->GIni.GP[i].PXAQSize = SK_RLMT_STANDBY_QXASIZE;
+	}
+	RxRam = (RemainingRam * 8 / 10) & ~7;
+	pAC->GIni.GP[pAC->ActivePort].PRxQSize = RxRam;
+	pAC->GIni.GP[pAC->ActivePort].PXSQSize = 0;
+	pAC->GIni.GP[pAC->ActivePort].PXAQSize =
+		(RemainingRam - RxRam) & ~7;
+	pAC->RxQueueSize = RxRam;
+	pAC->TxSQueueSize = 0;
+	pAC->TxAQueueSize = (RemainingRam - RxRam) & ~7;
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("queue sizes settings - rx:%d  txA:%d txS:%d\n",
+		pAC->RxQueueSize,pAC->TxAQueueSize, pAC->TxSQueueSize));
+	
+	for (i=0; i<SK_MAX_MACS; i++) {
+		pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing;
+	}
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - 100;
+	}
+	/*
+	 * Do not set the Limit to 0, because this could cause
+	 * wrap around with ReQueue'ed buffers (a buffer could
+	 * be requeued in the same position, made accessable to
+	 * the hardware, and the hardware could change its
+	 * contents!
+	 */
+	pAC->RxPort[pAC->ActivePort].RxFillLimit = 1;
+
+#ifdef DEBUG
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+			("i: %d,  RxQSize: %d,  PXSQsize: %d, PXAQSize: %d\n",
+			i,
+			pAC->GIni.GP[i].PRxQSize,
+			pAC->GIni.GP[i].PXSQSize,
+			pAC->GIni.GP[i].PXAQSize));
+	}
+#endif
+} /* SetQueueSizes */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeSetMacAddr - Set the hardware MAC address
+ *
+ * Description:
+ *	This function sets the MAC address used by the adapter.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+static int SkGeSetMacAddr(struct device *dev, void *p)
+{
+SK_AC		*pAC = (SK_AC*) dev->priv;
+struct sockaddr	*addr = p;
+unsigned int	Flags;
+	
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeSetMacAddr starts now...\n"));
+	if(dev->start) {
+		return -EBUSY;
+	}
+	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
+	
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	SkAddrOverride(pAC, pAC->IoBase, pAC->ActivePort,
+		(SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS);
+	
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	return 0;
+} /* SkGeSetMacAddr */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeSetRxMode - set receive mode
+ *
+ * Description:
+ *	This function sets the receive mode of an adapter. The adapter
+ *	supports promiscuous mode, allmulticast mode and a number of
+ *	multicast addresses. If more multicast addresses the available
+ *	are selected, a hash function in the hardware is used.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+static void SkGeSetRxMode(struct device *dev)
+{
+SK_AC			*pAC;
+struct dev_mc_list	*pMcList;
+int			i;
+unsigned int		Flags;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeSetRxMode starts now... "));
+	pAC = (SK_AC*) dev->priv;
+	
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	if (dev->flags & IFF_PROMISC) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+			("PROMISCUOUS mode\n"));
+		SkAddrPromiscuousChange(pAC, pAC->IoBase, pAC->ActivePort,
+			SK_PROM_MODE_LLC);
+	} else if (dev->flags & IFF_ALLMULTI) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+			("ALLMULTI mode\n"));
+		SkAddrPromiscuousChange(pAC, pAC->IoBase, pAC->ActivePort,
+			SK_PROM_MODE_ALL_MC);
+	} else {
+		SkAddrPromiscuousChange(pAC, pAC->IoBase, pAC->ActivePort,
+			SK_PROM_MODE_NONE);
+		SkAddrMcClear(pAC, pAC->IoBase, pAC->ActivePort, 0);
+
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+			("Number of MC entries: %d ", dev->mc_count));
+		
+		pMcList = dev->mc_list;
+		for (i=0; i<dev->mc_count; i++, pMcList = pMcList->next) {
+			SkAddrMcAdd(pAC, pAC->IoBase, pAC->ActivePort,
+				(SK_MAC_ADDR*)pMcList->dmi_addr, 0);
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MCA,
+				("%02x:%02x:%02x:%02x:%02x:%02x\n",
+				pMcList->dmi_addr[0],
+				pMcList->dmi_addr[1],
+				pMcList->dmi_addr[2],
+				pMcList->dmi_addr[3],
+				pMcList->dmi_addr[4],
+				pMcList->dmi_addr[5]));
+		}
+		SkAddrMcUpdate(pAC, pAC->IoBase, pAC->ActivePort);					
+	
+	}
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	
+	return;
+} /* SkGeSetRxMode */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeChangeMtu - set the MTU to another value
+ *
+ * Description:
+ *	This function sets is called whenever the MTU size is changed
+ *	(ifconfig mtu xxx dev ethX). If the MTU is bigger than standard
+ *	ethernet MTU size, long frame support is activated.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+static int SkGeChangeMtu(struct device *dev, int NewMtu)
+{
+SK_AC		*pAC;
+unsigned int	Flags;
+int		i;
+SK_EVPARA 	EvPara;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeChangeMtu starts now...\n"));
+ 
+	pAC = (SK_AC*) dev->priv;
+	if ((NewMtu < 68) || (NewMtu > SK_JUMBO_MTU)) {
+		return -EINVAL;
+	}
+
+	pAC->RxBufSize = NewMtu + 32;
+	dev->mtu = NewMtu;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("New MTU: %d\n", NewMtu));
+
+	/* prevent reconfiguration while changing the MTU */
+
+	/* disable interrupts */
+	SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+	SkEventDispatcher(pAC, pAC->IoBase);
+
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		spin_lock_irqsave(
+			&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock, Flags);
+	}
+	pAC->dev->tbusy = 1;
+
+	/* 
+	 * adjust number of rx buffers allocated
+	 */
+	if (NewMtu > 1500) {
+		/* use less rx buffers */
+		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+			if (i == pAC->ActivePort)
+				pAC->RxPort[i].RxFillLimit =
+					pAC->RxDescrPerRing - 100;
+			else
+				pAC->RxPort[i].RxFillLimit =
+					pAC->RxDescrPerRing - 10;
+
+		}
+	}
+	else {
+		/* use normal anoumt of rx buffers */
+		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+			if (i == pAC->ActivePort)
+				pAC->RxPort[i].RxFillLimit = 1;
+			else
+				pAC->RxPort[i].RxFillLimit =
+					pAC->RxDescrPerRing - 100;
+		}
+	}
+	 
+	SkGeDeInit(pAC, pAC->IoBase); 
+
+	/* 
+	 * enable/disable hardware support for long frames
+	 */
+	if (NewMtu > 1500) {
+		pAC->GIni.GIPortUsage = SK_JUMBO_LINK;
+		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+			pAC->GIni.GP[i].PRxCmd = 
+				XM_RX_STRIP_FCS | XM_RX_LENERR_OK;
+		}
+	}
+	else {
+		pAC->GIni.GIPortUsage = SK_RED_LINK;
+		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+			pAC->GIni.GP[i].PRxCmd =
+				XM_RX_STRIP_FCS | XM_RX_LENERR_OK;
+		}
+	}
+
+	SkGeInit(   pAC, pAC->IoBase, 1);
+	SkI2cInit(  pAC, pAC->IoBase, 1);
+	SkEventInit(pAC, pAC->IoBase, 1);
+	SkPnmiInit( pAC, pAC->IoBase, 1);
+	SkAddrInit( pAC, pAC->IoBase, 1);
+	SkRlmtInit( pAC, pAC->IoBase, 1);
+	SkTimerInit(pAC, pAC->IoBase, 1);
+	
+	SkGeInit(   pAC, pAC->IoBase, 2);
+	SkI2cInit(  pAC, pAC->IoBase, 2);
+	SkEventInit(pAC, pAC->IoBase, 2);
+	SkPnmiInit( pAC, pAC->IoBase, 2);
+	SkAddrInit( pAC, pAC->IoBase, 2);
+	SkRlmtInit( pAC, pAC->IoBase, 2);
+	SkTimerInit(pAC, pAC->IoBase, 2);
+
+	/* 
+	 * clear and reinit the rx rings here
+	 */
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		ReceiveIrq(pAC, &pAC->RxPort[i]);
+		ClearRxRing(pAC, &pAC->RxPort[i]);
+		FillRxRing(pAC, &pAC->RxPort[i]);
+
+		// Enable transmit descriptor polling.
+		SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE);
+		FillRxRing(pAC, &pAC->RxPort[i]);
+	};
+
+	SkGeYellowLED(pAC, pAC->IoBase, 1);
+
+#ifdef USE_INT_MOD
+	{
+		unsigned long ModBase;
+		ModBase = 53125000 / INTS_PER_SEC;
+		SK_OUT32(pAC->IoBase, B2_IRQM_INI, ModBase);
+		SK_OUT32(pAC->IoBase, B2_IRQM_MSK, IRQ_MOD_MASK);
+		SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_START);
+	}
+#endif
+
+	pAC->dev->tbusy = 0;
+	for (i=pAC->GIni.GIMacsFound-1; i>=0; i--) {
+		spin_unlock_irqrestore(
+			&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock, Flags);
+	}
+
+	/* enable Interrupts */
+	SK_OUT32(pAC->IoBase, B0_IMSK, IRQ_MASK);
+	SK_OUT32(pAC->IoBase, B0_HWE_IMSK, IRQ_HWE_MASK);
+
+	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+	SkEventDispatcher(pAC, pAC->IoBase);
+
+
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	
+	return 0;
+} /* SkGeChangeMtu */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeStats - return ethernet device statistics
+ *
+ * Description:
+ *	This function return statistic data about the ethernet device
+ *	to the operating system.
+ *
+ * Returns:
+ *	pointer to the statistic structure.
+ */
+static struct net_device_stats *SkGeStats(struct device *dev)
+{
+SK_AC	*pAC = (SK_AC*) dev->priv;
+SK_PNMI_STRUCT_DATA *pPnmiStruct;       /* structure for all Pnmi-Data */
+SK_PNMI_STAT    *pPnmiStat;             /* pointer to virtual XMAC stat. data */SK_PNMI_CONF    *pPnmiConf;             /* pointer to virtual link config. */
+unsigned int    Size;                   /* size of pnmi struct */
+unsigned int	Flags;			/* for spin lock */
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeStats starts now...\n"));
+	pPnmiStruct = &pAC->PnmiStruct;
+        memset(pPnmiStruct, 0, sizeof(SK_PNMI_STRUCT_DATA));
+        spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+        Size = SK_PNMI_STRUCT_SIZE;
+        SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size);
+        spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+        pPnmiStat = &pPnmiStruct->Stat[0];
+        pPnmiConf = &pPnmiStruct->Conf[0];
+
+	pAC->stats.rx_packets = (SK_U32) pPnmiStruct->RxDeliveredCts & 0xFFFFFFFF;
+	pAC->stats.tx_packets = (SK_U32) pPnmiStat->StatTxOkCts & 0xFFFFFFFF;
+	pAC->stats.rx_bytes = (SK_U32) pPnmiStruct->RxOctetsDeliveredCts;
+	pAC->stats.tx_bytes = (SK_U32) pPnmiStat->StatTxOctetsOkCts;
+	pAC->stats.rx_errors = (SK_U32) pPnmiStruct->InErrorsCts & 0xFFFFFFFF;
+	pAC->stats.tx_errors = (SK_U32) pPnmiStat->StatTxSingleCollisionCts & 0xFFFFFFFF;
+	pAC->stats.rx_dropped = (SK_U32) pPnmiStruct->RxNoBufCts & 0xFFFFFFFF;
+	pAC->stats.tx_dropped = (SK_U32) pPnmiStruct->TxNoBufCts & 0xFFFFFFFF;
+	pAC->stats.multicast = (SK_U32) pPnmiStat->StatRxMulticastOkCts & 0xFFFFFFFF;
+	pAC->stats.collisions = (SK_U32) pPnmiStat->StatTxSingleCollisionCts & 0xFFFFFFFF;
+
+	/* detailed rx_errors: */
+	pAC->stats.rx_length_errors = (SK_U32) pPnmiStat->StatRxRuntCts & 0xFFFFFFFF;
+	pAC->stats.rx_over_errors = (SK_U32) pPnmiStat->StatRxFifoOverflowCts & 0xFFFFFFFF;
+	pAC->stats.rx_crc_errors = (SK_U32) pPnmiStat->StatRxFcsCts & 0xFFFFFFFF;
+	pAC->stats.rx_frame_errors = (SK_U32) pPnmiStat->StatRxFramingCts & 0xFFFFFFFF;
+	pAC->stats.rx_fifo_errors = (SK_U32) pPnmiStat->StatRxFifoOverflowCts & 0xFFFFFFFF;
+	pAC->stats.rx_missed_errors = (SK_U32) pPnmiStat->StatRxMissedCts & 0xFFFFFFFF;
+
+	/* detailed tx_errors */
+	pAC->stats.tx_aborted_errors = (SK_U32) 0;
+	pAC->stats.tx_carrier_errors = (SK_U32) pPnmiStat->StatTxCarrierCts & 0xFFFFFFFF;
+	pAC->stats.tx_fifo_errors = (SK_U32) pPnmiStat->StatTxFifoUnderrunCts & 0xFFFFFFFF;
+	pAC->stats.tx_heartbeat_errors = (SK_U32) pPnmiStat->StatTxCarrierCts & 0xFFFFFFFF;
+	pAC->stats.tx_window_errors = (SK_U32) 0;
+
+	return(&pAC->stats);
+} /* SkGeStats */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeIoctl - IO-control function
+ *
+ * Description:
+ *	This function is called if an ioctl is issued on the device.
+ *	There are three subfunction for reading, writing and test-writing
+ *	the private MIB data structure (usefull for SysKonnect-internal tools).
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+static int SkGeIoctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+SK_AC		*pAC;
+SK_GE_IOCTL	Ioctl;
+unsigned int	Err = 0;
+int		Size;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeIoctl starts now...\n"));
+	pAC = (SK_AC*) dev->priv;
+	
+	if(copy_from_user(&Ioctl, rq->ifr_data, sizeof(SK_GE_IOCTL))) {
+		return -EFAULT;
+	}
+
+	switch(cmd) {
+	case SK_IOCTL_SETMIB:
+	case SK_IOCTL_PRESETMIB:
+		if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ 	case SK_IOCTL_GETMIB:
+		if(copy_from_user(&pAC->PnmiStruct, Ioctl.pData, 
+			Ioctl.Len<sizeof(pAC->PnmiStruct)?
+			Ioctl.Len : sizeof(pAC->PnmiStruct))) {
+			return -EFAULT;
+		}
+		Size = SkGeIocMib(pAC, Ioctl.Len, cmd);
+		if(copy_to_user(Ioctl.pData, &pAC->PnmiStruct,
+			Ioctl.Len<Size? Ioctl.Len : Size)) {
+			return -EFAULT;
+		}
+		Ioctl.Len = Size;
+		if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) {
+			return -EFAULT;
+		}
+		break;
+	default:
+		Err = -EOPNOTSUPP;
+	}
+	return(Err);
+} /* SkGeIoctl */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeIocMib - handle a GetMib, SetMib- or PresetMib-ioctl message
+ *
+ * Description:
+ *	This function reads/writes the MIB data using PNMI (Private Network
+ *	Management Interface).
+ *	The destination for the data must be provided with the
+ *	ioctl call and is given to the driver in the form of
+ *	a user space address.
+ *	Copying from the user-provided data area into kernel messages
+ *	and back is done by copy_from_user and copy_to_user calls in
+ *	SkGeIoctl.
+ *
+ * Returns:
+ *	returned size from PNMI call
+ */
+static int SkGeIocMib(
+SK_AC		*pAC,	/* pointer to the adapter context */
+unsigned int	Size,	/* length of ioctl data */
+int		mode)	/* flag for set/preset */
+{
+unsigned int	Flags;	/* for spin lock */
+	
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeIocMib starts now...\n"));
+	/* access MIB */
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	switch(mode) {
+	case SK_IOCTL_GETMIB:
+		SkPnmiGetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size);
+		break;
+	case SK_IOCTL_PRESETMIB:
+		SkPnmiPreSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size);
+		break;
+	case SK_IOCTL_SETMIB:
+		SkPnmiSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size);
+		break;
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("MIB data access succeeded\n"));
+	return (Size);
+} /* SkGeIocMib */
+
+
+/*****************************************************************************
+ *
+ * 	GetConfiguration - read configuration information
+ *
+ * Description:
+ *	This function reads per-adapter configuration information from
+ *	the options provided on the command line.
+ *
+ * Returns:
+ *	none
+ */
+static void GetConfiguration(
+SK_AC	*pAC)	/* pointer to the adapter context structure */
+{
+SK_I32	Port;		/* preferred port */
+int	AutoNeg;	/* auto negotiation off (0) or on (1) */
+int	DuplexCap;	/* duplex capabilities (0=both, 1=full, 2=half */
+int	MSMode;		/* master / slave mode selection */
+SK_BOOL	AutoSet;
+SK_BOOL DupSet;
+/*
+ *	The two parameters AutoNeg. and DuplexCap. map to one configuration
+ *	parameter. The mapping is described by this table:
+ *	DuplexCap ->	|	both	|	full	|	half	|
+ *	AutoNeg		|		|		|		|
+ *	-----------------------------------------------------------------
+ *	Off		|    illegal	|	Full	|	Half	|
+ *	-----------------------------------------------------------------
+ *	On		|   AutoBoth	|   AutoFull	|   AutoHalf	|
+ *	-----------------------------------------------------------------
+ *	Sense		|   AutoSense	|   AutoSense	|   AutoSense	|
+ */
+int	Capabilities[3][3] = 
+		{ {		  -1, SK_LMODE_FULL,     SK_LMODE_HALF}, 
+		  {SK_LMODE_AUTOBOTH, SK_LMODE_AUTOFULL, SK_LMODE_AUTOHALF},
+		  {SK_LMODE_AUTOSENSE, SK_LMODE_AUTOSENSE, SK_LMODE_AUTOSENSE} };
+#define DC_BOTH	0
+#define DC_FULL 1
+#define DC_HALF 2
+#define AN_OFF	0
+#define AN_ON	1
+#define AN_SENS	2
+
+	/* settings for port A */
+	AutoNeg = AN_SENS; /* default: do auto Sense */
+	AutoSet = SK_FALSE;
+	if (AutoNeg_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		AutoNeg_A[pAC->Index] != NULL) {
+		AutoSet = SK_TRUE;
+		if (strcmp(AutoNeg_A[pAC->Index],"")==0) {
+			AutoSet = SK_FALSE;
+		}
+		else if (strcmp(AutoNeg_A[pAC->Index],"On")==0) {
+			AutoNeg = AN_ON;
+		}
+		else if (strcmp(AutoNeg_A[pAC->Index],"Off")==0) {
+			AutoNeg = AN_OFF;
+		}
+		else if (strcmp(AutoNeg_A[pAC->Index],"Sense")==0) {
+			AutoNeg = AN_SENS;
+		}
+		else printk("%s: Illegal value for AutoNeg_A\n",
+			pAC->dev->name);
+	}
+
+	DuplexCap = DC_BOTH;
+	DupSet = SK_FALSE;
+	if (DupCap_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		DupCap_A[pAC->Index] != NULL) {
+		DupSet = SK_TRUE;
+		if (strcmp(DupCap_A[pAC->Index],"")==0) {
+			DupSet = SK_FALSE;
+		}
+		else if (strcmp(DupCap_A[pAC->Index],"Both")==0) {
+			DuplexCap = DC_BOTH;
+		}
+		else if (strcmp(DupCap_A[pAC->Index],"Full")==0) {
+			DuplexCap = DC_FULL;
+		}
+		else if (strcmp(DupCap_A[pAC->Index],"Half")==0) {
+			DuplexCap = DC_HALF;
+		}
+		else printk("%s: Illegal value for DupCap_A\n",
+			pAC->dev->name);
+	}
+	
+	/* check for illegal combinations */
+	if (AutoSet && AutoNeg==AN_SENS && DupSet) {
+		printk("%s, Port A: DuplexCapabilities"
+			" ignored using Sense mode\n", pAC->dev->name);
+	}
+	if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){
+		printk("%s, Port A: Illegal combination"
+			" of values AutoNeg. and DuplexCap.\n    Using "
+			"Full Duplex\n", pAC->dev->name);
+
+		DuplexCap = DC_FULL;
+	}
+	if (AutoSet && AutoNeg==AN_OFF && !DupSet) {
+		DuplexCap = DC_FULL;
+	}
+	
+	if (!AutoSet && DupSet) {
+		printk("%s, Port A: Duplex setting not"
+			" possible in\n    default AutoNegotiation mode"
+			" (Sense).\n    Using AutoNegotiation On\n",
+			pAC->dev->name);
+		AutoNeg = AN_ON;
+	}
+	
+	/* set the desired mode */
+	pAC->GIni.GP[0].PLinkModeConf =
+		Capabilities[AutoNeg][DuplexCap];
+	
+	pAC->GIni.GP[0].PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM;
+	if (FlowCtrl_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		FlowCtrl_A[pAC->Index] != NULL) {
+		if (strcmp(FlowCtrl_A[pAC->Index],"") == 0) {
+		}
+		else if (strcmp(FlowCtrl_A[pAC->Index],"SymOrRem") == 0) {
+			pAC->GIni.GP[0].PFlowCtrlMode =
+				SK_FLOW_MODE_SYM_OR_REM;
+		}
+		else if (strcmp(FlowCtrl_A[pAC->Index],"Sym")==0) {
+			pAC->GIni.GP[0].PFlowCtrlMode =
+				SK_FLOW_MODE_SYMMETRIC;
+		}
+		else if (strcmp(FlowCtrl_A[pAC->Index],"LocSend")==0) {
+			pAC->GIni.GP[0].PFlowCtrlMode =
+				SK_FLOW_MODE_LOC_SEND;
+		}
+		else if (strcmp(FlowCtrl_A[pAC->Index],"None")==0) {
+			pAC->GIni.GP[0].PFlowCtrlMode =
+				SK_FLOW_MODE_NONE;
+		}
+		else printk("Illegal value for FlowCtrl_A\n");
+	}
+	if (AutoNeg==AN_OFF && pAC->GIni.GP[0].PFlowCtrlMode!=
+		SK_FLOW_MODE_NONE) {
+		printk("%s, Port A: FlowControl"
+			" impossible without AutoNegotiation,"
+			" disabled\n", pAC->dev->name);
+		pAC->GIni.GP[0].PFlowCtrlMode = SK_FLOW_MODE_NONE;
+	}
+
+	MSMode = SK_MS_MODE_AUTO; /* default: do auto select */
+	if (Role_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		Role_A[pAC->Index] != NULL) {
+		if (strcmp(Role_A[pAC->Index],"")==0) {
+		}
+		else if (strcmp(Role_A[pAC->Index],"Auto")==0) {
+			MSMode = SK_MS_MODE_AUTO;
+		}
+		else if (strcmp(Role_A[pAC->Index],"Master")==0) {
+			MSMode = SK_MS_MODE_MASTER;
+		}
+		else if (strcmp(Role_A[pAC->Index],"Slave")==0) {
+			MSMode = SK_MS_MODE_SLAVE;
+		}
+		else printk("%s: Illegal value for Role_A\n",
+			pAC->dev->name);
+	}
+	pAC->GIni.GP[0].PMSMode = MSMode;
+	
+	
+	/* settings for port B */
+	AutoNeg = AN_SENS; /* default: do auto Sense */
+	AutoSet = SK_FALSE;
+	if (AutoNeg_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		AutoNeg_B[pAC->Index] != NULL) {
+		AutoSet = SK_TRUE;
+		if (strcmp(AutoNeg_B[pAC->Index],"")==0) {
+			AutoSet = SK_FALSE;
+		}
+		else if (strcmp(AutoNeg_B[pAC->Index],"On")==0) {
+			AutoNeg = AN_ON;
+		}
+		else if (strcmp(AutoNeg_B[pAC->Index],"Off")==0) {
+			AutoNeg = AN_OFF;
+		}
+		else if (strcmp(AutoNeg_B[pAC->Index],"Sense")==0) {
+			AutoNeg = AN_SENS;
+		}
+		else printk("Illegal value for AutoNeg_B\n");
+	}
+
+	DuplexCap = DC_BOTH;
+	DupSet = SK_FALSE;
+	if (DupCap_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		DupCap_B[pAC->Index] != NULL) {
+		DupSet = SK_TRUE;
+		if (strcmp(DupCap_B[pAC->Index],"")==0) {
+			DupSet = SK_FALSE;
+		}
+		else if (strcmp(DupCap_B[pAC->Index],"Both")==0) {
+			DuplexCap = DC_BOTH;
+		}
+		else if (strcmp(DupCap_B[pAC->Index],"Full")==0) {
+			DuplexCap = DC_FULL;
+		}
+		else if (strcmp(DupCap_B[pAC->Index],"Half")==0) {
+			DuplexCap = DC_HALF;
+		}
+		else printk("Illegal value for DupCap_B\n");
+	}
+	
+	/* check for illegal combinations */
+	if (AutoSet && AutoNeg==AN_SENS && DupSet) {
+		printk("%s, Port B: DuplexCapabilities"
+			" ignored using Sense mode\n", pAC->dev->name);
+	}
+	if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){
+		printk("%s, Port B: Illegal combination"
+			" of values AutoNeg. and DuplexCap.\n    Using "
+			"Full Duplex\n", pAC->dev->name);
+
+		DuplexCap = DC_FULL;
+	}
+	if (AutoSet && AutoNeg==AN_OFF && !DupSet) {
+		DuplexCap = DC_FULL;
+	}
+	
+	if (!AutoSet && DupSet) {
+		printk("%s, Port B: Duplex setting not"
+			" possible in\n    default AutoNegotiation mode"
+			" (Sense).\n    Using AutoNegotiation On\n",
+			pAC->dev->name);
+		AutoNeg = AN_ON;
+	}
+	
+	/* set the desired mode */
+	pAC->GIni.GP[1].PLinkModeConf =
+		Capabilities[AutoNeg][DuplexCap];
+	
+	pAC->GIni.GP[1].PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM;
+	if (FlowCtrl_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		FlowCtrl_B[pAC->Index] != NULL) {
+		if (strcmp(FlowCtrl_B[pAC->Index],"") == 0) {
+		}
+		else if (strcmp(FlowCtrl_B[pAC->Index],"SymOrRem") == 0) {
+			pAC->GIni.GP[1].PFlowCtrlMode =
+				SK_FLOW_MODE_SYM_OR_REM;
+		}
+		else if (strcmp(FlowCtrl_B[pAC->Index],"Sym")==0) {
+			pAC->GIni.GP[1].PFlowCtrlMode =
+				SK_FLOW_MODE_SYMMETRIC;
+		}
+		else if (strcmp(FlowCtrl_B[pAC->Index],"LocSend")==0) {
+			pAC->GIni.GP[1].PFlowCtrlMode =
+				SK_FLOW_MODE_LOC_SEND;
+		}
+		else if (strcmp(FlowCtrl_B[pAC->Index],"None")==0) {
+			pAC->GIni.GP[1].PFlowCtrlMode =
+				SK_FLOW_MODE_NONE;
+		}
+		else printk("Illegal value for FlowCtrl_B\n");
+	}
+	if (AutoNeg==AN_OFF && pAC->GIni.GP[1].PFlowCtrlMode!=
+		SK_FLOW_MODE_NONE) {
+		printk("%s, Port B: FlowControl"
+			" impossible without AutoNegotiation,"
+			" disabled\n", pAC->dev->name);
+		pAC->GIni.GP[1].PFlowCtrlMode = SK_FLOW_MODE_NONE;
+	}
+
+	MSMode = SK_MS_MODE_AUTO; /* default: do auto select */
+	if (Role_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		Role_B[pAC->Index] != NULL) {
+		if (strcmp(Role_B[pAC->Index],"")==0) {
+		}
+		else if (strcmp(Role_B[pAC->Index],"Auto")==0) {
+			MSMode = SK_MS_MODE_AUTO;
+		}
+		else if (strcmp(Role_B[pAC->Index],"Master")==0) {
+			MSMode = SK_MS_MODE_MASTER;
+		}
+		else if (strcmp(Role_B[pAC->Index],"Slave")==0) {
+			MSMode = SK_MS_MODE_SLAVE;
+		}
+		else printk("%s: Illegal value for Role_B\n",
+			pAC->dev->name);
+	}
+	pAC->GIni.GP[1].PMSMode = MSMode;
+	
+	
+	/* settings for both ports */
+	pAC->ActivePort = 0;
+	if (PrefPort != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		PrefPort[pAC->Index] != NULL) {
+		if (strcmp(PrefPort[pAC->Index],"") == 0) { /* Auto */
+			pAC->ActivePort = 0;
+			pAC->Rlmt.MacPreferred = -1; /* auto */
+			pAC->Rlmt.PrefPort = 0;
+		}
+		else if (strcmp(PrefPort[pAC->Index],"A") == 0) {
+			/*
+			 * do not set ActivePort here, thus a port
+			 * switch is issued after net up.
+			 */
+			Port = 0;
+			pAC->Rlmt.MacPreferred = Port;
+			pAC->Rlmt.PrefPort = Port;
+		}
+		else if (strcmp(PrefPort[pAC->Index],"B") == 0) {
+			/*
+			 * do not set ActivePort here, thus a port
+			 * switch is issued after net up.
+			 */
+			Port = 1;
+			pAC->Rlmt.MacPreferred = Port;
+			pAC->Rlmt.PrefPort = Port;
+		}
+		else printk("%s: Illegal value for PrefPort\n",
+			pAC->dev->name);
+	}
+	
+	if (RlmtMode != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		RlmtMode[pAC->Index] != NULL) {
+		if (strcmp(RlmtMode[pAC->Index], "") == 0) {
+			pAC->RlmtMode = 0;
+		}
+		else if (strcmp(RlmtMode[pAC->Index], "CheckLinkState") == 0) {
+			pAC->RlmtMode = SK_RLMT_CHECK_LINK;
+		}
+		else if (strcmp(RlmtMode[pAC->Index], "CheckLocalPort") == 0) {
+			pAC->RlmtMode = SK_RLMT_CHECK_LINK |
+				SK_RLMT_CHECK_LOC_LINK;
+		}
+		else if (strcmp(RlmtMode[pAC->Index], "CheckSeg") == 0) {
+			pAC->RlmtMode = SK_RLMT_CHECK_LINK |
+				SK_RLMT_CHECK_LOC_LINK | 
+				SK_RLMT_CHECK_SEG;
+		}
+		else {
+			printk("%s: Illegal value for"
+				" RlmtMode, using default\n", pAC->dev->name);
+			pAC->RlmtMode = 0;
+		}
+	}
+	else {
+		pAC->RlmtMode = 0;
+	}
+} /* GetConfiguration */
+
+
+/*****************************************************************************
+ *
+ * 	ProductStr - return a adapter identification string from vpd
+ *
+ * Description:
+ *	This function reads the product name string from the vpd area
+ *	and puts it the field pAC->DeviceString.
+ *
+ * Returns: N/A
+ */
+static void ProductStr(
+SK_AC	*pAC		/* pointer to adapter context */
+)
+{
+int	StrLen = 80;		/* length of the string, defined in SK_AC */
+char	Keyword[] = VPD_NAME;	/* vpd productname identifier */
+int	ReturnCode;		/* return code from vpd_read */
+unsigned int Flags;
+
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	ReturnCode = VpdRead(pAC, pAC->IoBase, Keyword, pAC->DeviceStr,
+		&StrLen);
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	if (ReturnCode != 0) {
+		/* there was an error reading the vpd data */
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ERROR,
+			("Error reading VPD data: %d\n", ReturnCode));
+		pAC->DeviceStr[0] = '\0';
+	}
+} /* ProductStr */
+
+
+
+
+/****************************************************************************/
+/* functions for common modules *********************************************/
+/****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ *	SkDrvAllocRlmtMbuf - allocate an RLMT mbuf
+ *
+ * Description:
+ *	This routine returns an RLMT mbuf or NULL. The RLMT Mbuf structure
+ *	is embedded into a socket buff data area.
+ *
+ * Context:
+ *	runtime
+ *
+ * Returns:
+ *	NULL or pointer to Mbuf.
+ */
+SK_MBUF *SkDrvAllocRlmtMbuf(
+SK_AC		*pAC,		/* pointer to adapter context */
+SK_IOC		IoC,		/* the IO-context */
+unsigned	BufferSize)	/* size of the requested buffer */
+{
+SK_MBUF		*pRlmtMbuf;	/* pointer to a new rlmt-mbuf structure */
+struct sk_buff	*pMsgBlock;	/* pointer to a new message block */
+
+	pMsgBlock = alloc_skb(BufferSize + sizeof(SK_MBUF), GFP_ATOMIC);
+	if (pMsgBlock == NULL) {
+		return (NULL);
+	}
+	pRlmtMbuf = (SK_MBUF*) pMsgBlock->data;
+	skb_reserve(pMsgBlock, sizeof(SK_MBUF));
+	pRlmtMbuf->pNext = NULL;
+	pRlmtMbuf->pOs = pMsgBlock;
+	pRlmtMbuf->pData = pMsgBlock->data;	/* Data buffer. */
+	pRlmtMbuf->Size = BufferSize;		/* Data buffer size. */
+	pRlmtMbuf->Length = 0;		/* Length of packet (<= Size). */
+	return (pRlmtMbuf);
+
+} /* SkDrvAllocRlmtMbuf */
+
+
+/*****************************************************************************
+ *
+ *	SkDrvFreeRlmtMbuf - free an RLMT mbuf
+ *
+ * Description:
+ *	This routine frees one or more RLMT mbuf(s).
+ *
+ * Context:
+ *	runtime
+ *
+ * Returns:
+ *	Nothing
+ */
+void  SkDrvFreeRlmtMbuf(
+SK_AC		*pAC,		/* pointer to adapter context */  
+SK_IOC		IoC,		/* the IO-context */              
+SK_MBUF		*pMbuf)		/* size of the requested buffer */
+{
+SK_MBUF		*pFreeMbuf;
+SK_MBUF		*pNextMbuf;
+
+	pFreeMbuf = pMbuf;
+	do {
+		pNextMbuf = pFreeMbuf->pNext;
+		DEV_KFREE_SKB(pFreeMbuf->pOs);
+		pFreeMbuf = pNextMbuf;
+	} while ( pFreeMbuf != NULL );
+} /* SkDrvFreeRlmtMbuf */
+
+
+/*****************************************************************************
+ *
+ *	SkOsGetTime - provide a time value
+ *
+ * Description:
+ *	This routine provides a time value. The unit is 1/HZ (defined by Linux).
+ *	It is not used for absolute time, but only for time differences.
+ *
+ *
+ * Returns:
+ *	Time value
+ */
+SK_U64 SkOsGetTime(SK_AC *pAC)
+{
+	return jiffies;
+} /* SkOsGetTime */
+
+
+/*****************************************************************************
+ *
+ *	SkPciReadCfgDWord - read a 32 bit value from pci config space
+ *
+ * Description:
+ *	This routine reads a 32 bit value from the pci configuration
+ *	space.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciReadCfgDWord(
+SK_AC *pAC,		/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U32 *pVal)		/* pointer to store the read value */
+{
+	pci_read_config_dword(&pAC->PciDev, PciAddr, pVal);
+	return(0);
+} /* SkPciReadCfgDWord */
+
+
+/*****************************************************************************
+ *
+ *	SkPciReadCfgWord - read a 16 bit value from pci config space
+ *
+ * Description:
+ *	This routine reads a 16 bit value from the pci configuration
+ *	space.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciReadCfgWord(
+SK_AC *pAC,	/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U16 *pVal)		/* pointer to store the read value */
+{
+	pci_read_config_word(&pAC->PciDev, PciAddr, pVal);
+	return(0);
+} /* SkPciReadCfgWord */
+
+
+/*****************************************************************************
+ *
+ *	SkPciReadCfgByte - read a 8 bit value from pci config space
+ *
+ * Description:
+ *	This routine reads a 8 bit value from the pci configuration
+ *	space.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciReadCfgByte(
+SK_AC *pAC,	/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U8 *pVal)		/* pointer to store the read value */
+{
+	pci_read_config_byte(&pAC->PciDev, PciAddr, pVal);
+	return(0);
+} /* SkPciReadCfgByte */
+
+
+/*****************************************************************************
+ *
+ *	SkPciWriteCfgDWord - write a 32 bit value to pci config space
+ *
+ * Description:
+ *	This routine writes a 32 bit value to the pci configuration
+ *	space.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciWriteCfgDWord(
+SK_AC *pAC,	/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U32 Val)		/* pointer to store the read value */
+{
+	pci_write_config_dword(&pAC->PciDev, PciAddr, Val);
+	return(0);
+} /* SkPciWriteCfgDWord */
+
+
+/*****************************************************************************
+ *
+ *	SkPciWriteCfgWord - write a 16 bit value to pci config space
+ *
+ * Description:
+ *	This routine writes a 16 bit value to the pci configuration
+ *	space. The flag PciConfigUp indicates whether the config space
+ *	is accesible or must be set up first.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciWriteCfgWord(
+SK_AC *pAC,	/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U16 Val)		/* pointer to store the read value */
+{
+	pci_write_config_word(&pAC->PciDev, PciAddr, Val);
+	return(0);
+} /* SkPciWriteCfgWord */
+
+
+/*****************************************************************************
+ *
+ *	SkPciWriteCfgWord - write a 8 bit value to pci config space
+ *
+ * Description:
+ *	This routine writes a 8 bit value to the pci configuration
+ *	space. The flag PciConfigUp indicates whether the config space
+ *	is accesible or must be set up first.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciWriteCfgByte(
+SK_AC *pAC,	/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U8 Val)		/* pointer to store the read value */
+{
+	pci_write_config_byte(&pAC->PciDev, PciAddr, Val);
+	return(0);
+} /* SkPciWriteCfgByte */
+
+
+/*****************************************************************************
+ *
+ *	SkDrvEvent - handle driver events
+ *
+ * Description:
+ *	This function handles events from all modules directed to the driver
+ *
+ * Context:
+ *	Is called under protection of slow path lock.
+ *
+ * Returns:
+ *	0 if everything ok
+ *	< 0  on error
+ *	
+ */
+int SkDrvEvent(
+SK_AC *pAC,		/* pointer to adapter context */
+SK_IOC IoC,		/* io-context */
+SK_U32 Event,		/* event-id */
+SK_EVPARA Param)	/* event-parameter */
+{
+SK_MBUF		*pRlmtMbuf;	/* pointer to a rlmt-mbuf structure */
+struct sk_buff	*pMsg;		/* pointer to a message block */
+int		FromPort;	/* the port from which we switch away */
+int		ToPort;		/* the port we switch to */
+SK_EVPARA	NewPara;	/* parameter for further events */
+int		Stat;
+unsigned int	Flags;
+
+	switch (Event) {
+	case SK_DRV_ADAP_FAIL:
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("ADAPTER FAIL EVENT\n"));
+		printk("%s: Adapter failed.\n", pAC->dev->name);
+		/* disable interrupts */
+		SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+		/* cgoos */
+		break;
+	case SK_DRV_PORT_FAIL:
+		FromPort = Param.Para32[0];
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("PORT FAIL EVENT, Port: %d\n", FromPort));
+		if (FromPort == 0) {
+			printk("%s: Port A failed.\n", pAC->dev->name);
+		} else {
+			printk("%s: Port B failed.\n", pAC->dev->name);
+		}
+		/* cgoos */
+		break;
+	case SK_DRV_PORT_RESET:	 /* SK_U32 PortIdx */
+		/* action list 4 */
+		FromPort = Param.Para32[0];
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("PORT RESET EVENT, Port: %d ", FromPort));
+		NewPara.Para64 = FromPort;
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara);
+		spin_lock_irqsave(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_HARD_RST);
+		spin_unlock_irqrestore(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		
+		/* clear rx ring from received frames */
+		ReceiveIrq(pAC, &pAC->RxPort[FromPort]);
+		
+		ClearTxRing(pAC, &pAC->TxPort[FromPort][TX_PRIO_LOW]);
+		spin_lock_irqsave(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		SkGeInitPort(pAC, IoC, FromPort);
+		SkAddrMcUpdate(pAC,IoC, FromPort);
+		PortReInitBmu(pAC, FromPort);
+		SkGePollTxD(pAC, IoC, FromPort, SK_TRUE);
+		ClearAndStartRx(pAC, FromPort);
+		spin_unlock_irqrestore(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		break;
+	case SK_DRV_NET_UP:	 /* SK_U32 PortIdx */
+		/* action list 5 */
+		FromPort = Param.Para32[0];
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("NET UP EVENT, Port: %d ", Param.Para32[0]));
+		printk("%s: network connection up using"
+			" port %c\n", pAC->dev->name, 'A'+Param.Para32[0]);
+		printk("    speed:           1000\n");
+		Stat = pAC->GIni.GP[FromPort].PLinkModeStatus;
+		if (Stat == SK_LMODE_STAT_AUTOHALF ||
+			Stat == SK_LMODE_STAT_AUTOFULL) {
+			printk("    autonegotiation: yes\n");
+		}
+		else {
+			printk("    autonegotiation: no\n");
+		}
+		if (Stat == SK_LMODE_STAT_AUTOHALF ||
+			Stat == SK_LMODE_STAT_HALF) {
+			printk("    duplex mode:     half\n");
+		}
+		else {
+			printk("    duplex mode:     full\n");
+		}
+		Stat = pAC->GIni.GP[FromPort].PFlowCtrlStatus;
+		if (Stat == SK_FLOW_STAT_REM_SEND ) {
+			printk("    flowctrl:        remote send\n");
+		}
+		else if (Stat == SK_FLOW_STAT_LOC_SEND ){
+			printk("    flowctrl:        local send\n");
+		}
+		else if (Stat == SK_FLOW_STAT_SYMMETRIC ){
+			printk("    flowctrl:        symmetric\n");
+		}
+		else {
+			printk("    flowctrl:        none\n");
+		}
+		if (pAC->GIni.GP[FromPort].PhyType != SK_PHY_XMAC) {
+		Stat = pAC->GIni.GP[FromPort].PMSStatus;
+			if (Stat == SK_MS_STAT_MASTER ) {
+				printk("    role:            master\n");
+			}
+			else if (Stat == SK_MS_STAT_SLAVE ) {
+				printk("    role:            slave\n");
+			}
+			else {
+				printk("    role:            ???\n");
+			}
+		}
+		
+		if (Param.Para32[0] != pAC->ActivePort) {
+			NewPara.Para32[0] = pAC->ActivePort;
+			NewPara.Para32[1] = Param.Para32[0];
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_INTERN,
+				NewPara);
+		}
+		break;
+	case SK_DRV_NET_DOWN:	 /* SK_U32 Reason */
+		/* action list 7 */
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("NET DOWN EVENT "));
+		printk("%s: network connection down\n", pAC->dev->name);
+		break;
+	case SK_DRV_SWITCH_HARD: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("PORT SWITCH HARD "));
+	case SK_DRV_SWITCH_SOFT: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
+	/* action list 6 */
+		printk("%s: switching to port %c\n", pAC->dev->name,
+			'A'+Param.Para32[1]);
+	case SK_DRV_SWITCH_INTERN: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
+		FromPort = Param.Para32[0];
+		ToPort = Param.Para32[1];
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("PORT SWITCH EVENT, From: %d  To: %d (Pref %d) ",
+			FromPort, ToPort, pAC->Rlmt.PrefPort));
+		NewPara.Para64 = FromPort;
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara);
+		NewPara.Para64 = ToPort;
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara);
+		spin_lock_irqsave(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		spin_lock_irqsave(
+			&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags);
+		SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_SOFT_RST);
+		SkGeStopPort(pAC, IoC, ToPort, SK_STOP_ALL, SK_SOFT_RST);
+		spin_unlock_irqrestore(
+			&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags);
+		spin_unlock_irqrestore(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+
+		ReceiveIrq(pAC, &pAC->RxPort[FromPort]); /* clears rx ring */
+		ReceiveIrq(pAC, &pAC->RxPort[ToPort]); /* clears rx ring */
+		
+		ClearTxRing(pAC, &pAC->TxPort[FromPort][TX_PRIO_LOW]);
+		ClearTxRing(pAC, &pAC->TxPort[ToPort][TX_PRIO_LOW]);
+		spin_lock_irqsave(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, 
+			Flags);
+		spin_lock_irqsave(
+			&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags);
+		pAC->ActivePort = ToPort;
+		SetQueueSizes(pAC);
+		SkGeInitPort(pAC, IoC, FromPort);
+		SkGeInitPort(pAC, IoC, ToPort);
+		if (Event == SK_DRV_SWITCH_SOFT) {
+			SkXmRxTxEnable(pAC, IoC, FromPort);
+		}
+		SkXmRxTxEnable(pAC, IoC, ToPort);
+		SkAddrSwap(pAC, IoC, FromPort, ToPort);
+		SkAddrMcUpdate(pAC, IoC, FromPort);
+		SkAddrMcUpdate(pAC, IoC, ToPort);
+		PortReInitBmu(pAC, FromPort);
+		PortReInitBmu(pAC, ToPort);
+		SkGePollTxD(pAC, IoC, FromPort, SK_TRUE);
+		SkGePollTxD(pAC, IoC, ToPort, SK_TRUE);
+		ClearAndStartRx(pAC, FromPort);
+		ClearAndStartRx(pAC, ToPort);
+		spin_unlock_irqrestore(
+			&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags);
+		spin_unlock_irqrestore(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		break;
+	case SK_DRV_RLMT_SEND:	 /* SK_MBUF *pMb */
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("RLS "));
+		pRlmtMbuf = (SK_MBUF*) Param.pParaPtr;
+		pMsg = (struct sk_buff*) pRlmtMbuf->pOs;
+		skb_put(pMsg, pRlmtMbuf->Length);
+		XmitFrame(pAC, &pAC->TxPort[pRlmtMbuf->PortIdx][TX_PRIO_LOW],
+			pMsg);
+		break;
+	default:
+		break;
+	}
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+		("END EVENT "));
+	
+	return (0);
+} /* SkDrvEvent */
+
+
+/*****************************************************************************
+ *
+ *	SkErrorLog - log errors
+ *
+ * Description:
+ *	This function logs errors to the system buffer and to the console
+ *
+ * Returns:
+ *	0 if everything ok
+ *	< 0  on error
+ *	
+ */
+void SkErrorLog(
+SK_AC	*pAC,
+int	ErrClass,
+int	ErrNum,
+char	*pErrorMsg)
+{
+char	ClassStr[80];
+
+	switch (ErrClass) {
+	case SK_ERRCL_OTHER:
+		strcpy(ClassStr, "Other error");
+		break;
+	case SK_ERRCL_CONFIG:
+		strcpy(ClassStr, "Configuration error");
+		break;
+	case SK_ERRCL_INIT:
+		strcpy(ClassStr, "Initialization error");
+		break;
+	case SK_ERRCL_NORES:
+		strcpy(ClassStr, "Out of resources error");
+		break;
+	case SK_ERRCL_SW:
+		strcpy(ClassStr, "internal Software error");
+		break;
+	case SK_ERRCL_HW:
+		strcpy(ClassStr, "Hardware failure");
+		break;
+	case SK_ERRCL_COMM:
+		strcpy(ClassStr, "Communication error");
+		break;
+	}
+	printk(KERN_INFO "%s: -- ERROR --\n        Class:  %s\n"
+		"        Nr:  0x%x\n        Msg:  %s\n", pAC->dev->name,
+		ClassStr, ErrNum, pErrorMsg);
+
+} /* SkErrorLog */
+
+#ifdef DEBUG /***************************************************************/
+/* "debug only" section *****************************************************/
+/****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ *	DumpMsg - print a frame
+ *
+ * Description:
+ *	This function prints frames to the system logfile/to the console.
+ *
+ * Returns: N/A
+ *	
+ */
+static void DumpMsg(struct sk_buff *skb, char *str)
+{
+	int	msglen;
+
+	if (skb == NULL) {
+		printk("DumpMsg(): NULL-Message\n");
+		return;
+	}
+
+	if (skb->data == NULL) {
+		printk("DumpMsg(): Message empty\n");
+		return;
+	}
+
+	msglen = skb->len;
+	if (msglen > 64)
+		msglen = 64;
+
+	printk("--- Begin of message from %s , len %d (from %d) ----\n", str, msglen, skb->len);
+
+	DumpData((char *)skb->data, msglen);
+
+	printk("------- End of message ---------\n");
+} /* DumpMsg */
+
+
+
+/*****************************************************************************
+ *
+ *	DumpData - print a data area
+ *
+ * Description:
+ *	This function prints a area of data to the system logfile/to the 
+ *	console.
+ *
+ * Returns: N/A
+ *	
+ */
+static void DumpData(char *p, int size)
+{
+register int    i;
+int	haddr, addr;
+char	hex_buffer[180];
+char	asc_buffer[180];
+char	HEXCHAR[] = "0123456789ABCDEF";
+
+	addr = 0;
+	haddr = 0;
+	hex_buffer[0] = 0;
+	asc_buffer[0] = 0;
+	for (i=0; i < size; ) {
+		if (*p >= '0' && *p <='z')
+			asc_buffer[addr] = *p;
+		else
+			asc_buffer[addr] = '.';
+		addr++;
+		asc_buffer[addr] = 0;
+		hex_buffer[haddr] = HEXCHAR[(*p & 0xf0) >> 4];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[*p & 0x0f];
+		haddr++;
+		hex_buffer[haddr] = ' ';
+		haddr++;
+		hex_buffer[haddr] = 0;
+		p++;
+		i++;
+		if (i%16 == 0) {
+			printk("%s  %s\n", hex_buffer, asc_buffer);
+			addr = 0;
+			haddr = 0;
+		}
+	}
+} /* DumpData */
+
+
+/*****************************************************************************
+ *
+ *	DumpLong - print a data area as long values
+ *
+ * Description:
+ *	This function prints a area of data to the system logfile/to the 
+ *	console.
+ *
+ * Returns: N/A
+ *	
+ */
+static void DumpLong(char *pc, int size)
+{
+register int    i;
+int	haddr, addr;
+char	hex_buffer[180];
+char	asc_buffer[180];
+char	HEXCHAR[] = "0123456789ABCDEF";
+long	*p;
+int	l;
+
+	addr = 0;
+	haddr = 0;
+	hex_buffer[0] = 0;
+	asc_buffer[0] = 0;
+	p = (long*) pc;
+	for (i=0; i < size; ) {
+		l = (long) *p;
+		hex_buffer[haddr] = HEXCHAR[(l >> 28) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 24) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 20) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 16) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 12) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 8) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 4) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[l & 0x0f];
+		haddr++;
+		hex_buffer[haddr] = ' ';
+		haddr++;
+		hex_buffer[haddr] = 0;
+		p++;
+		i++;
+		if (i%8 == 0) {
+			printk("%4x %s\n", (i-8)*4, hex_buffer);
+			haddr = 0;
+		}
+	}
+	printk("------------------------\n");
+} /* DumpLong */
+
+#endif /* DEBUG */
+
+/*
+ * Local variables:
+ * compile-command: "make"
+ * End:
+ */
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/skgehwt.c linux.14p16/drivers/net/sk98lin/skgehwt.c
--- linux.vanilla/drivers/net/sk98lin/skgehwt.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/skgehwt.c	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,213 @@
+/******************************************************************************
+ *
+ * Name:	skgehwt.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.12 $
+ * Date:	$Date: 1998/10/15 15:11:34 $
+ * Purpose:	Hardware Timer.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skge.c" for further 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 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgehwt.c,v $
+ *	Revision 1.12  1998/10/15 15:11:34  gklug
+ *	fix: ID_sccs to SysKonnectFileId
+ *	
+ *	Revision 1.11  1998/10/08 15:27:51  gklug
+ *	chg: correction factor is host clock dependent
+ *	
+ *	Revision 1.10  1998/09/15 14:18:31  cgoos
+ *	Changed more BOOLEANs to SK_xxx
+ *
+ *	Revision 1.9  1998/09/15 14:16:06  cgoos
+ *	Changed line 107: FALSE to SK_FALSE
+ *	
+ *	Revision 1.8  1998/08/24 13:04:44  gklug
+ *	fix: typo
+ *	
+ *	Revision 1.7  1998/08/19 09:50:49  gklug
+ *	fix: remove struct keyword from c-code (see CCC) add typedefs
+ *	
+ *	Revision 1.6  1998/08/17 09:59:02  gklug
+ *	fix: typos
+ *	
+ *	Revision 1.5  1998/08/14 07:09:10  gklug
+ *	fix: chg pAc -> pAC
+ *	
+ *	Revision 1.4  1998/08/10 14:14:52  gklug
+ *	rmv: unneccessary SK_ADDR macro
+ *	
+ *	Revision 1.3  1998/08/07 12:53:44  gklug
+ *	fix: first compiled version
+ *	
+ *	Revision 1.2  1998/08/07 09:19:29  gklug
+ *	adapt functions to the C coding conventions
+ *	rmv unneccessary functions.
+ *	
+ *	Revision 1.1  1998/08/05 11:28:36  gklug
+ *	first version: adapted from SMT/FDDI
+ *	
+ *	
+ *	
+ *
+ ******************************************************************************/
+
+
+/*
+	Event queue and dispatcher
+*/
+static const char SysKonnectFileId[] =
+	"$Header: /usr56/projects/ge/schedule/skgehwt.c,v 1.12 1998/10/15 15:11:34 gklug Exp $" ;
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+	Hardware Timer function queue management.
+
+	General Description:
+
+ */
+intro()
+{}
+#endif
+
+/*
+ * Prototypes of local functions.
+ */
+#define	SK_HWT_MAX	(65000)
+
+/* correction factor */
+#define	SK_HWT_FAC	(1000 * (SK_U32)pAC->GIni.GIHstClkFact / 100)
+
+/*
+ * Initialize hardware timer.
+ *
+ * Must be called during init level 1.
+ */
+void	SkHwtInit(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	Ioc)	/* IoContext */
+{
+	pAC->Hwt.TStart = 0 ;
+	pAC->Hwt.TStop	= 0 ;
+	pAC->Hwt.TActive = SK_FALSE ;
+
+	SkHwtStop(pAC,Ioc) ;
+}
+
+/*
+ *
+ * Start hardware timer (clock ticks are 16us).
+ *
+ */
+void	SkHwtStart(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	Ioc,	/* IoContext */
+SK_U32	Time)	/* Time in units of 16us to load the timer with. */
+{
+	SK_U32	Cnt ;
+
+	if (Time > SK_HWT_MAX)
+		Time = SK_HWT_MAX ;
+
+	pAC->Hwt.TStart = Time ;
+	pAC->Hwt.TStop = 0L ;
+
+	Cnt = Time ;
+
+	/*
+	 * if time < 16 us
+	 *	time = 16 us
+	 */
+	if (!Cnt) {
+		Cnt++ ;
+	}
+
+	SK_OUT32(Ioc, B2_TI_INI, Cnt * SK_HWT_FAC) ;
+	SK_OUT16(Ioc, B2_TI_CRTL, TIM_START) ;	/* Start timer. */
+
+	pAC->Hwt.TActive = SK_TRUE ;
+}
+
+/*
+ * Stop hardware timer.
+ * and clear the timer IRQ
+ */
+void	SkHwtStop(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	Ioc)	/* IoContext */
+{
+	SK_OUT16(Ioc, B2_TI_CRTL, TIM_STOP) ;
+	SK_OUT16(Ioc, B2_TI_CRTL, TIM_CLR_IRQ) ;
+
+	pAC->Hwt.TActive = SK_FALSE ;
+}
+
+
+/*
+ *	Stop hardware timer and read time elapsed since last start.
+ *
+ * returns
+ *	The elapsed time since last start in units of 16us.
+ *
+ */
+SK_U32	SkHwtRead(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	Ioc)	/* IoContext */
+{
+	SK_U32	TRead ;
+	SK_U32	IStatus ;
+
+	if (pAC->Hwt.TActive) {
+		SkHwtStop(pAC,Ioc) ;
+
+		SK_IN32(Ioc, B2_TI_VAL, &TRead);
+		TRead /= SK_HWT_FAC;
+
+		SK_IN32(Ioc, B0_ISRC, &IStatus);
+
+		/* Check if timer expired (or wraparound). */
+		if ((TRead > pAC->Hwt.TStart) || (IStatus & IS_TIMINT)) {
+			SkHwtStop(pAC,Ioc) ;
+			pAC->Hwt.TStop = pAC->Hwt.TStart ;
+		} else {
+			pAC->Hwt.TStop = pAC->Hwt.TStart - TRead ;
+		}
+	}
+	return (pAC->Hwt.TStop) ;
+}
+
+/*
+ * interrupt source= timer
+ */
+void	SkHwtIsr(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	Ioc)	/* IoContext */
+{
+	SkHwtStop(pAC,Ioc);
+	pAC->Hwt.TStop = pAC->Hwt.TStart;
+	SkTimerDone(pAC,Ioc) ;
+}
+
+/* End of file */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/skgeinit.c linux.14p16/drivers/net/sk98lin/skgeinit.c
--- linux.vanilla/drivers/net/sk98lin/skgeinit.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/skgeinit.c	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,1847 @@
+/******************************************************************************
+ *
+ * Name:	skgeinit.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.54 $
+ * Date:	$Date: 1999/10/26 07:32:54 $
+ * Purpose:	Contains functions to initialize the GE HW
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skge.c" for further 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 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgeinit.c,v $
+ *	Revision 1.54  1999/10/26 07:32:54  malthoff
+ *	Initialize PHWLinkUp with SK_FALSE. Required for Diagnostics.
+ *	
+ *	Revision 1.53  1999/08/12 19:13:50  malthoff
+ *	Fix for 1000BT. Do not owerwrite XM_MMU_CMD when
+ *	disabling receiver and transmitter. Other bits
+ *	may be lost.
+ *	
+ *	Revision 1.52  1999/07/01 09:29:54  gklug
+ *	fix: DoInitRamQueue needs pAC
+ *	
+ *	Revision 1.51  1999/07/01 08:42:21  gklug
+ *	chg: use Store & forward for RAM buffer when Jumbos are used
+ *	
+ *	Revision 1.50  1999/05/27 13:19:38  cgoos
+ *	Added Tx PCI watermark initialization.
+ *	Removed Tx RAM queue Store & Forward setting.
+ *	
+ *	Revision 1.49  1999/05/20 14:32:45  malthoff
+ *	SkGeLinkLED() is completly removed now.
+ *	
+ *	Revision 1.48  1999/05/19 07:28:24  cgoos
+ *	SkGeLinkLED no more available for drivers.
+ *	Changes for 1000Base-T.
+ *	
+ *	Revision 1.47  1999/04/08 13:57:45  gklug
+ *	add: Init of new port struct fiels PLinkResCt
+ *	chg: StopPort Timer check
+ *	
+ *	Revision 1.46  1999/03/25 07:42:15  malthoff
+ *	SkGeStopPort(): Add workaround for cache incoherency.
+ *			Create error log entry, disable port, and
+ *			exit loop if it does not terminate.
+ *	Add XM_RX_LENERR_OK to the default value for the
+ *	XMAC receive command register.
+ *	
+ *	Revision 1.45  1999/03/12 16:24:47  malthoff
+ *	Remove PPollRxD and PPollTxD.
+ *	Add check for GIPollTimerVal.
+ *
+ *	Revision 1.44  1999/03/12 13:40:23  malthoff
+ *	Fix: SkGeXmitLED(), SK_LED_TST mode does not work.
+ *	Add: Jumbo frame support.
+ *	Chg: Resolution of parameter IntTime in SkGeCfgSync().
+ *
+ *	Revision 1.43  1999/02/09 10:29:46  malthoff
+ *	Bugfix: The previous modification again also for the second location.
+ *
+ *	Revision 1.42  1999/02/09 09:35:16  malthoff
+ *	Bugfix: The bits '66 MHz Capable' and 'NEWCAP are reset while
+ *		clearing the error bits in the PCI status register.
+ *
+ *	Revision 1.41  1999/01/18 13:07:02  malthoff
+ *	Bugfix: Do not use CFG cycles after during Init- or Runtime, because
+ *		they may not be available after Boottime.
+ *
+ *	Revision 1.40  1999/01/11 12:40:49  malthoff
+ *	Bug fix: PCI_STATUS: clearing error bits sets the UDF bit.
+ *
+ *	Revision 1.39  1998/12/11 15:17:33  gklug
+ *	chg: Init LipaAutoNeg with Unknown
+ *
+ *	Revision 1.38  1998/12/10 11:02:57  malthoff
+ *	Disable Error Log Message when calling SkGeInit(level 2)
+ *	more than once.
+ *
+ *	Revision 1.37  1998/12/07 12:18:25  gklug
+ *	add: refinement of autosense mode: take into account the autoneg cap of LiPa
+ *
+ *	Revision 1.36  1998/12/07 07:10:39  gklug
+ *	fix: init values of LinkBroken/ Capabilities for management
+ *
+ *	Revision 1.35  1998/12/02 10:56:20  gklug
+ *	fix: do NOT init LoinkSync Counter.
+ *
+ *	Revision 1.34  1998/12/01 10:53:21  gklug
+ *	add: init of additional Counters for workaround
+ *
+ *	Revision 1.33  1998/12/01 10:00:49  gklug
+ *	add: init PIsave var in Port struct
+ *
+ *	Revision 1.32  1998/11/26 14:50:40  gklug
+ *	chg: Default is autosensing with AUTOFULL mode
+ *
+ *	Revision 1.31  1998/11/25 15:36:16  gklug
+ *	fix: do NOT stop LED Timer when port should be stoped
+ *
+ *	Revision 1.30  1998/11/24 13:15:28  gklug
+ *	add: Init PCkeckPar struct member
+ *
+ *	Revision 1.29  1998/11/18 13:19:27  malthoff
+ *	Disable packet arbiter timeouts on receive side.
+ *	Use maximum timeout value for packet arbiter
+ *	transmit timeouts.
+ *	Add TestStopBit() function to handle stop RX/TX
+ *	problem with active descriptor poll timers.
+ *	Bug Fix: Descriptor Poll Timer not started, beacuse
+ *	GIPollTimerVal was initilaized with 0.
+ *
+ *	Revision 1.28  1998/11/13 14:24:26  malthoff
+ *	Bug Fix: SkGeStopPort() may hang if a Packet Arbiter Timout
+ *	is pending or occurs while waiting for TX_STOP and RX_STOP.
+ *	The PA timeout is cleared now while waiting for TX- or RX_STOP.
+ *
+ *	Revision 1.27  1998/11/02 11:04:36  malthoff
+ *	fix the last fix
+ *
+ *	Revision 1.26  1998/11/02 10:37:03  malthoff
+ *	Fix: SkGePollTxD() enables always the synchronounous poll timer.
+ *
+ *	Revision 1.25  1998/10/28 07:12:43  cgoos
+ *	Fixed "LED_STOP" in SkGeLnkSyncCnt, "== SK_INIT_IO" in SkGeInit.
+ *	Removed: Reset of RAM Interface in SkGeStopPort.
+ *
+ *	Revision 1.24  1998/10/27 08:13:12  malthoff
+ *	Remove temporary code.
+ *
+ *	Revision 1.23  1998/10/26 07:45:03  malthoff
+ *	Add Address Calculation Workaround: If the EPROM byte
+ *	Id is 3, the address offset is 512 kB.
+ *	Initialize default values for PLinkMode and PFlowCtrlMode.
+ *
+ *	Revision 1.22  1998/10/22 09:46:47  gklug
+ *	fix SysKonnectFileId typo
+ *
+ *	Revision 1.21  1998/10/20 12:11:56  malthoff
+ *	Don't dendy the Queue config if the size of the unused
+ *	rx qeueu is zero.
+ *
+ *	Revision 1.20  1998/10/19 07:27:58  malthoff
+ *	SkGeInitRamIface() is public to be called by diagnostics.
+ *
+ *	Revision 1.19  1998/10/16 13:33:45  malthoff
+ *	Fix: enabling descriptor polling is not allowed until
+ *	the descriptor addresses are set. Descriptor polling
+ *	must be handled by the driver.
+ *
+ *	Revision 1.18  1998/10/16 10:58:27  malthoff
+ *	Remove temp. code for Diag prototype.
+ *	Remove lint warning for dummy reads.
+ *	Call SkGeLoadLnkSyncCnt() during SkGeInitPort().
+ *
+ *	Revision 1.17  1998/10/14 09:16:06  malthoff
+ *	Change parameter LimCount and programming of
+ *	the limit counter in SkGeCfgSync().
+ *
+ *	Revision 1.16  1998/10/13 09:21:16  malthoff
+ *	Don't set XM_RX_SELF_RX in RxCmd Reg, because it's
+ *	like a Loopback Mode in half duplex.
+ *
+ *	Revision 1.15  1998/10/09 06:47:40  malthoff
+ *	SkGeInitMacArb(): set recovery counters init value
+ *	to zero although this counters are not uesd.
+ *	Bug fix in Rx Upper/Lower Pause Threshold calculation.
+ *	Add XM_RX_SELF_RX to RxCmd.
+ *
+ *	Revision 1.14  1998/10/06 15:15:53  malthoff
+ *	Make sure no pending IRQ is cleared in SkGeLoadLnkSyncCnt().
+ *
+ *	Revision 1.13  1998/10/06 14:09:36  malthoff
+ *	Add SkGeLoadLnkSyncCnt(). Modify
+ *	the 'port stopped' condition according
+ *	to the current problem report.
+ *
+ *	Revision 1.12  1998/10/05 08:17:21  malthoff
+ *	Add functions: SkGePollRxD(), SkGePollTxD(),
+ *	DoCalcAddr(), SkGeCheckQSize(),
+ *	DoInitRamQueue(), and SkGeCfgSync().
+ *	Add coding for SkGeInitMacArb(), SkGeInitPktArb(),
+ *	SkGeInitMacFifo(), SkGeInitRamBufs(),
+ *	SkGeInitRamIface(), and  SkGeInitBmu().
+ *
+ *	Revision 1.11  1998/09/29 08:26:29  malthoff
+ *	bug fix: SkGeInit0() 'i' should be increment.
+ *
+ *	Revision 1.10  1998/09/28 13:19:01  malthoff
+ *	Coding time: Save the done work.
+ *	Modify SkGeLinkLED(), add SkGeXmitLED(),
+ *	define SkGeCheckQSize(), SkGeInitMacArb(),
+ *	SkGeInitPktArb(), SkGeInitMacFifo(),
+ *	SkGeInitRamBufs(), SkGeInitRamIface(),
+ *	and SkGeInitBmu(). Do coding for SkGeStopPort(),
+ *	SkGeInit1(), SkGeInit2(), and SkGeInit3().
+ *	Do coding for SkGeDinit() and SkGeInitPort().
+ *
+ *	Revision 1.9  1998/09/16 14:29:05  malthoff
+ *	Some minor changes.
+ *
+ *	Revision 1.8  1998/09/11 05:29:14  gklug
+ *	add: init state of a port
+ *
+ *	Revision 1.7  1998/09/04 09:26:25  malthoff
+ *	Short temporary modification.
+ *
+ *	Revision 1.6  1998/09/04 08:27:59  malthoff
+ *	Remark the do-while in StopPort() because it never ends
+ *	without a GE adapter.
+ *
+ *	Revision 1.5  1998/09/03 14:05:45  malthoff
+ *	Change comment for SkGeInitPort(). Do not
+ *	repair the queue sizes if invalid.
+ *
+ *	Revision 1.4  1998/09/03 10:03:19  malthoff
+ *	Implement the new interface according to the
+ *	reviewed interface specification.
+ *
+ *	Revision 1.3  1998/08/19 09:11:25  gklug
+ *	fix: struct are removed from c-source (see CCC)
+ *
+ *	Revision 1.2  1998/07/28 12:33:58  malthoff
+ *	Add 'IoC' parameter in function declaration and SK IO macros.
+ *
+ *	Revision 1.1  1998/07/23 09:48:57  malthoff
+ *	Creation. First dummy 'C' file.
+ *	SkGeInit(Level 0) is card_start for ML.
+ *	SkGeDeInit() is card_stop for ML.
+ *
+ *
+ ******************************************************************************/
+
+#include "h/skdrv1st.h"
+#include "h/xmac_ii.h"
+#include "h/skdrv2nd.h"
+
+/* defines ********************************************************************/
+
+/* defines for SkGeXmitLed() */
+#define XMIT_LED_INI	0
+#define XMIT_LED_CNT	(RX_LED_VAL - RX_LED_INI)
+#define XMIT_LED_CTRL	(RX_LED_CTRL- RX_LED_INI)
+#define XMIT_LED_TST	(RX_LED_TST - RX_LED_INI)
+
+/* Queue Size units */
+#define QZ_UNITS	0x7
+
+/* Types of RAM Buffer Queues */
+#define SK_RX_SRAM_Q	1	/* small receive queue */
+#define SK_RX_BRAM_Q	2	/* big receive queue */
+#define SK_TX_RAM_Q	3	/* small or big transmit queue */
+
+/* typedefs *******************************************************************/
+/* global variables ***********************************************************/
+
+/* local variables ************************************************************/
+
+static const char SysKonnectFileId[] =
+	"@(#)$Id: skgeinit.c,v 1.54 1999/10/26 07:32:54 malthoff Exp $ (C) SK ";
+
+struct s_QOffTab {
+	int	RxQOff;		/* Receive Queue Address Offset */
+	int	XsQOff;		/* Sync Tx Queue Address Offset */
+	int	XaQOff;		/* Async Tx Queue Address Offset */
+};
+static struct s_QOffTab QOffTab[] = {
+	{ Q_R1, Q_XS1, Q_XA1 }, { Q_R2, Q_XS2, Q_XA2 }
+};
+
+
+/******************************************************************************
+ *
+ *	SkGePollRxD() - Enable/Disable Descriptor Polling of RxD Ring
+ *
+ * Description:
+ *	Enable or disable the descriptor polling the receive descriptor
+ *	ring (RxD) of port 'port'.
+ *	The new configuration is *not* saved over any SkGeStopPort() and
+ *	SkGeInitPort() calls.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGePollRxD(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL PollRxD)	/* SK_TRUE (enable pol.), SK_FALSE (disable pol.) */
+{
+	SK_GEPORT *pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (PollRxD) {
+		SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff,Q_CSR), CSR_ENA_POL);
+	}
+	else {
+		SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff,Q_CSR), CSR_DIS_POL);
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkGePollTxD() - Enable/Disable Descriptor Polling of TxD Rings
+ *
+ * Description:
+ *	Enable or disable the descriptor polling the transmit descriptor
+ *	ring(s) (RxD) of port 'port'.
+ *	The new configuration is *not* saved over any SkGeStopPort() and
+ *	SkGeInitPort() calls.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGePollTxD(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL PollTxD)	/* SK_TRUE (enable pol.), SK_FALSE (disable pol.) */
+{
+	SK_GEPORT *pPrt;
+	SK_U32	DWord;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (PollTxD) {
+		DWord = CSR_ENA_POL;
+	}
+	else {
+		DWord = CSR_DIS_POL;
+	}
+
+	if (pPrt->PXSQSize != 0) {
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff,Q_CSR), DWord);
+	}
+	if (pPrt->PXAQSize != 0) {
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff,Q_CSR), DWord);
+	}
+}
+
+
+/******************************************************************************
+ *
+ *	SkGeYellowLED() - Switch the yellow LED on or off.
+ *
+ * Description:
+ *	Switch the yellow LED on or off.
+ *
+ * Note:
+ *	This function may be called any time after SkGeInit(Level 1).
+ *
+ * Returns:
+ *	nothing
+ */
+void	SkGeYellowLED(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	State)		/* yellow LED state, 0 = OFF, 0 != ON */
+{
+	if (State == 0) {
+		/* Switch yellow LED OFF */
+		SK_OUT8(IoC, B0_LED, LED_STAT_OFF) ;
+	}
+	else {
+		/* Switch yellow LED ON */
+		SK_OUT8(IoC, B0_LED, LED_STAT_ON) ;
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkGeXmitLED() - Modify the Operational Mode of a transmission LED.
+ *
+ * Description:
+ *	The Rx or Tx LED which is specified by 'Led' will be
+ *	enabled, disabled or switched on in test mode.
+ *
+ * Note:
+ *	'Led' must contain the address offset of the LEDs INI register.
+ *
+ * Usage:
+ *	SkGeXmitLED(pAC, IoC, MR_ADDR(Port,TX_LED_INI), SK_LED_ENA);
+ *
+ * Returns:
+ *	nothing
+ */
+void	SkGeXmitLED(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Led,		/* offset to the LED Init Value register */
+int	Mode)		/* Mode may be SK_LED_DIS, SK_LED_ENA, SK_LED_TST */
+{
+	SK_U32	LedIni;
+
+	switch (Mode) {
+	case SK_LED_ENA:
+		LedIni = SK_XMIT_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100;
+		SK_OUT32(IoC, Led+XMIT_LED_INI, LedIni);
+		SK_OUT8(IoC, Led+XMIT_LED_CTRL, LED_START);
+		break ;
+	case SK_LED_TST:
+		SK_OUT8(IoC, Led+XMIT_LED_TST, LED_T_ON);
+		SK_OUT32(IoC, Led+XMIT_LED_CNT, 100);
+		SK_OUT8(IoC, Led+XMIT_LED_CTRL, LED_START);
+		break ;
+	case SK_LED_DIS:
+	default:
+		/*
+		 * Do NOT stop the LED Timer here. The LED might be
+		 * in on state. But it needs to go off.
+		 */
+		SK_OUT32(IoC, Led+XMIT_LED_CNT, 0);
+		SK_OUT8(IoC, Led+XMIT_LED_TST, LED_T_OFF);
+		break ;
+	}
+			
+	/*
+	 * 1000BT: The Transmit LED is driven by the PHY.
+	 * But the default LED configuration is used for
+	 * Level One and Broadcom PHYs.
+	 * (Broadcom: It may be that PHY_B_PEC_EN_LTR has to be set.)
+	 * (In this case it has to be added here. But we will see. XXX)
+	 */
+}
+
+/******************************************************************************
+ *
+ *	DoCalcAddr() - Calculates the start and the end address of a queue.
+ *
+ * Description:
+ *	This function calculates the start- end the end address
+ *	of a queue. Afterwards the 'StartVal' is incremented to the
+ *	next start position.
+ *	If the port is already initialized the calculated values
+ *	will be checked against the configured values and an
+ *	error will be returned, if they are not equal.
+ *	If the port is not initialized the values will be written to
+ *	*StartAdr and *EndAddr.
+ *
+ * Returns:
+ *	0:	success
+ *	1:	configuration error
+ */
+static int DoCalcAddr(
+SK_AC	*pAC,		/* adapter context */
+SK_GEPORT *pPrt,	/* port index */
+int	QuSize,		/* size of the queue to configure in kB */
+SK_U32	*StartVal,	/* start value for address calculation */
+SK_U32	*QuStartAddr,	/* start addr to calculate */
+SK_U32	*QuEndAddr)	/* end address to calculate */
+{
+	SK_U32	EndVal;
+	SK_U32	NextStart;
+	int	Rtv;
+
+	Rtv = 0;
+	if (QuSize == 0) {
+		EndVal = *StartVal;
+		NextStart = EndVal;
+	}
+	else {
+		EndVal = *StartVal + ((SK_U32)QuSize * 1024) - 1;
+		NextStart = EndVal + 1;
+	}
+
+	if (pPrt->PState >= SK_PRT_INIT) {
+		if (*StartVal != *QuStartAddr || EndVal != *QuEndAddr) {
+			Rtv = 1;
+		}
+	}
+	else {
+		*QuStartAddr = *StartVal;
+		*QuEndAddr = EndVal;
+	}
+
+	*StartVal = NextStart;
+	return (Rtv);
+}
+
+
+/******************************************************************************
+ *
+ *	SkGeCheckQSize() - Checks the Adapters Queue Size Configuration
+ *
+ * Description:
+ *	This function verifies the Queue Size Configuration specified
+ *	in the variabels PRxQSize, PXSQSize, and PXAQSize of all
+ *	used ports.
+ *	This requirements must be fullfilled to have a valid configuration:
+ *		- The size of all queues must not exceed GIRamSize.
+ *		- The queue sizes must be specified in units of 8 kB.
+ *		- The size of rx queues of available ports must not be
+ *		  smaller than 16kB.
+ *		- The RAM start and end addresses must not be changed
+ *		  for ports which are already initialized.
+ *	Furthermore SkGeCheckQSize() defines the Start and End
+ *	Addresses of all ports and stores them into the HWAC port
+ *	structure.
+ *
+ * Returns:
+ *	0:	Queue Size Configuration valid
+ *	1:	Queue Size Configuration invalid
+ */
+static int SkGeCheckQSize(
+SK_AC *pAC,		/* adapter context */
+int Port)		/* port index */
+{
+	SK_GEPORT *pPrt;
+	int	UsedMem;
+	int	i;
+	int	Rtv;
+	int	Rtv2;
+	SK_U32	StartAddr;
+
+	UsedMem = 0;
+	Rtv = 0;
+	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+		pPrt = &pAC->GIni.GP[i];
+
+		if (( pPrt->PRxQSize & QZ_UNITS) ||
+			(pPrt->PXSQSize & QZ_UNITS) ||
+			(pPrt->PXAQSize & QZ_UNITS)) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW,
+				SKERR_HWI_E012,
+				SKERR_HWI_E012MSG);
+			Rtv = 1;
+			goto CheckQSizeEnd;
+		}
+
+		UsedMem += pPrt->PRxQSize + pPrt->PXSQSize + pPrt->PXAQSize;
+
+		if (i == Port && pPrt->PRxQSize < SK_MIN_RXQ_SIZE) {
+			SK_ERR_LOG(pAC, SK_ERRCL_SW,
+				SKERR_HWI_E011,
+				SKERR_HWI_E011MSG);
+			Rtv = 1;
+			goto CheckQSizeEnd;
+		}
+	}
+	if (UsedMem > pAC->GIni.GIRamSize) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG);
+		Rtv = 1;
+		goto CheckQSizeEnd;
+	}
+
+	/* Now start address calculation */
+	StartAddr = pAC->GIni.GIRamOffs;
+	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+		pPrt = &pAC->GIni.GP[i];
+
+		/* Calculate/Check values for the receive queue */
+		Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PRxQSize, &StartAddr,
+			&pPrt->PRxQRamStart, &pPrt->PRxQRamEnd);
+		Rtv |= Rtv2;
+
+		/* Calculate/Check values for the synchronous tx queue */
+		Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXSQSize, &StartAddr,
+			&pPrt->PXsQRamStart, &pPrt->PXsQRamEnd);
+		Rtv |= Rtv2;
+
+		/* Calculate/Check values for the asynchronous tx queue */
+		Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXAQSize, &StartAddr,
+			&pPrt->PXaQRamStart, &pPrt->PXaQRamEnd);
+		Rtv |= Rtv2;
+
+		if (Rtv) {
+			SK_ERR_LOG(pAC, SK_ERRCL_SW,
+				SKERR_HWI_E013,
+				SKERR_HWI_E013MSG);
+			break;
+		}
+	}
+
+
+CheckQSizeEnd:
+	return (Rtv);
+}
+
+/******************************************************************************
+ *
+ *	SkGeInitMacArb() - Initialize the MAC Arbiter
+ *
+ * Description:
+ *	This function initializes the MAC Arbiter.
+ *	It must not be called if there is still an
+ *	initilaized or active port.
+ *
+ * Returns:
+ *	nothing:
+ */
+static void SkGeInitMacArb(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	/* release local reset */
+	SK_OUT16(IoC, B3_MA_TO_CTRL, MA_RST_CLR);
+
+	/* configure timeout values */
+	SK_OUT8(IoC, B3_MA_TOINI_RX1, SK_MAC_TO_53);
+	SK_OUT8(IoC, B3_MA_TOINI_RX2, SK_MAC_TO_53);
+	SK_OUT8(IoC, B3_MA_TOINI_TX1, SK_MAC_TO_53);
+	SK_OUT8(IoC, B3_MA_TOINI_TX2, SK_MAC_TO_53);
+
+	SK_OUT8(IoC, B3_MA_RCINI_RX1, 0);
+	SK_OUT8(IoC, B3_MA_RCINI_RX2, 0);
+	SK_OUT8(IoC, B3_MA_RCINI_TX1, 0);
+	SK_OUT8(IoC, B3_MA_RCINI_TX2, 0);
+
+	/* recovery values are needed for XMAC II Rev. B2 only */
+	/* Fast Output Enable Mode was intended to use with Rev. B2, but now? */
+
+	/*
+	 * There is not start or enable buttom to push, therefore
+	 * the MAC arbiter is configured and enabled now.
+	 */
+}
+
+/******************************************************************************
+ *
+ *	SkGeInitPktArb() - Initialize the Packet Arbiter
+ *
+ * Description:
+ *	This function initializes the Packet Arbiter.
+ *	It must not be called if there is still an
+ *	initilaized or active port.
+ *
+ * Returns:
+ *	nothing:
+ */
+static void SkGeInitPktArb(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	/* release local reset */
+	SK_OUT16(IoC, B3_PA_CTRL, PA_RST_CLR);
+
+	/* configure timeout values */
+	SK_OUT16(IoC, B3_PA_TOINI_RX1, SK_PKT_TO_MAX);
+	SK_OUT16(IoC, B3_PA_TOINI_RX2, SK_PKT_TO_MAX);
+	SK_OUT16(IoC, B3_PA_TOINI_TX1, SK_PKT_TO_MAX);
+	SK_OUT16(IoC, B3_PA_TOINI_TX2, SK_PKT_TO_MAX);
+
+	/* enable timeout timers if jumbo frames not used */
+	if (pAC->GIni.GIPortUsage != SK_JUMBO_LINK) {
+		if (pAC->GIni.GIMacsFound == 1) {
+			SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1);
+		}
+		else {
+			SK_OUT16(IoC, B3_PA_CTRL,(PA_ENA_TO_TX1|PA_ENA_TO_TX2));
+		}
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkGeInitMacFifo() - Initialize the MAC FIFOs
+ *
+ * Description:
+ *	Initialize all MAC FIFOs of the specified port
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInitMacFifo(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	/*
+	 * For each FIFO:
+	 *	- release local reset
+	 *	- use default value for MAC FIFO size
+	 *	- setup defaults for the control register
+	 *	- enable the FIFO
+	 */
+	/* Configure RX MAC FIFO */
+	SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_CLR);
+	SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_RX_CTRL_DEF);
+	SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_ENA_OP_MD);
+
+	/* Configure TX MAC FIFO */
+	SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_CLR);
+	SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
+	SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
+
+	/* Enable frame flushing if jumbo frames used */
+	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+		SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_FLUSH);
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkGeLoadLnkSyncCnt() - Load the Link Sync Counter and starts counting
+ *
+ * Description:
+ *	This function starts the Link Sync Counter of the specified
+ *	port and enables the generation of an Link Sync IRQ.
+ *	The Link Sync Counter may be used to detect an active link,
+ *	if autonegotiation is not used.
+ *
+ * Note:
+ *	o To ensure receiving the Link Sync Event the LinkSyncCounter
+ *	  should be initialized BEFORE clearing the XMACs reset!
+ *	o Enable IS_LNK_SYNC_M1 and IS_LNK_SYNC_M2 after calling this
+ *	  function.
+ *
+ * Retruns:
+ *	nothing
+ */
+void SkGeLoadLnkSyncCnt(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_U32	CntVal)		/* Counter value */
+{
+	SK_U32	OrgIMsk;
+	SK_U32	NewIMsk;
+	SK_U32	ISrc;
+	SK_BOOL	IrqPend;
+
+	/* stop counter */
+	SK_OUT8(IoC, MR_ADDR(Port,LNK_SYNC_CTRL), LED_STOP);
+
+	/*
+	 * ASIC problem:
+	 * Each time starting the Link Sync Counter an IRQ is generated
+	 * by the adapter. See problem report entry from 21.07.98
+	 *
+	 * Workaround:	Disable Link Sync IRQ and clear the unexpeced IRQ
+	 *		if no IRQ is already pending.
+	 */
+	IrqPend = SK_FALSE;
+	SK_IN32(IoC, B0_ISRC, &ISrc);
+	SK_IN32(IoC, B0_IMSK, &OrgIMsk);
+	if (Port == MAC_1) {
+		NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M1;
+		if (ISrc & IS_LNK_SYNC_M1) {
+			IrqPend = SK_TRUE;
+		}
+	}
+	else {
+		NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M2;
+		if (ISrc & IS_LNK_SYNC_M2) {
+			IrqPend = SK_TRUE;
+		}
+	}
+	if (!IrqPend) {
+		SK_OUT32(IoC, B0_IMSK, NewIMsk);
+	}
+
+	/* load counter */
+	SK_OUT32(IoC, MR_ADDR(Port,LNK_SYNC_INI), CntVal);
+
+	/* start counter */
+	SK_OUT8(IoC, MR_ADDR(Port,LNK_SYNC_CTRL), LED_START);
+
+	if (!IrqPend) {
+		/* clear the unexpected IRQ, and restore the interrupt mask */
+		SK_OUT8(IoC, MR_ADDR(Port,LNK_SYNC_CTRL), LED_CLR_IRQ);
+		SK_OUT32(IoC, B0_IMSK, OrgIMsk);
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkGeCfgSync() - Configure synchronous bandwidth for this port.
+ *
+ * Description:
+ *	This function may be used to configure synchronous bandwidth
+ *	to the specified port. This may be done any time after
+ *	initializing the port. The configuration values are NOT saved
+ *	in the HWAC port structure and will be overwritten any
+ *	time when stopping and starting the port.
+ *	Any values for the synchronous configuration will be ignored
+ *	if the size of the synchronous queue is zero!
+ *
+ *	The default configuration for the synchronous service is
+ *	TXA_ENA_FSYNC. This means if the size of
+ *	the synchronous queue is unequal zero but no specific
+ *	synchronous bandwidth is configured, the synchronous queue
+ *	will always have the 'unlimitted' transmit priority!
+ *
+ *	This mode will be restored if the synchronous bandwidth is
+ *	deallocated ('IntTime' = 0 and 'LimCount' = 0).
+ *
+ * Returns:
+ *	0:	success
+ *	1:	paramter configuration error
+ *	2:	try to configure quality of service although no
+ *		synchronous queue is configured
+ */
+int SkGeCfgSync(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_U32	IntTime,	/* Interval Timer Value in units of 8ns */
+SK_U32	LimCount,	/* Number of bytes to transfer during IntTime */
+int	SyncMode)	/* Sync Mode: TXA_ENA_ALLOC | TXA_DIS_ALLOC | 0 */
+{
+	int Rtv;
+
+	Rtv = 0;
+
+	/* check the parameters */
+	if (LimCount > IntTime ||
+		(LimCount == 0 && IntTime != 0) ||
+		(LimCount !=0 && IntTime == 0)) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG);
+		Rtv = 1;
+		goto CfgSyncEnd;
+	}
+	if (pAC->GIni.GP[Port].PXSQSize != 0) {
+		/* calculate register values */
+		IntTime = (IntTime / 2) * pAC->GIni.GIHstClkFact / 100;
+		LimCount = LimCount / 8;
+		if (IntTime > TXA_MAX_VAL || LimCount > TXA_MAX_VAL) {
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010,
+				SKERR_HWI_E010MSG);
+			Rtv = 1;
+			goto CfgSyncEnd;
+		}
+
+		/*
+		 * - Enable 'Force Sync' to ensure the synchronous queue
+		 *   has the priority while configuring the new values.
+		 * - Also 'disable alloc' to ensure the settings complies
+		 *   to the SyncMode parameter.
+		 * - Disable 'Rate Control' to configure the new values.
+		 * - write IntTime and Limcount
+		 * - start 'Rate Control' and disable 'Force Sync'
+		 *   if Interval Timer or Limit Counter not zero.
+		 */
+		SK_OUT8(IoC, MR_ADDR(Port,TXA_CTRL),
+			TXA_ENA_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
+		SK_OUT32(IoC, MR_ADDR(Port,TXA_ITI_INI), IntTime);
+		SK_OUT32(IoC, MR_ADDR(Port,TXA_LIM_INI), LimCount);
+		SK_OUT8(IoC, MR_ADDR(Port,TXA_CTRL),
+			(SyncMode & (TXA_ENA_ALLOC|TXA_DIS_ALLOC)));
+		if (IntTime != 0 || LimCount != 0) {
+			SK_OUT8(IoC, MR_ADDR(Port,TXA_CTRL),
+				TXA_DIS_FSYNC|TXA_START_RC);
+		}
+	}
+	else {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E009, SKERR_HWI_E009MSG);
+		Rtv = 2;
+	}
+
+CfgSyncEnd:
+	return (Rtv);
+}
+
+/******************************************************************************
+ *
+ *	DoInitRamQueue() - Initilaize the RAM Buffer Address of a single Queue
+ *
+ * Desccription:
+ *	If the queue is used, enable and initilaize it.
+ *	Make sure the queue is still reset, if it is not used.
+ *
+ * Returns:
+ *	nothing
+ */
+static void DoInitRamQueue(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	QuIoOffs,	/* Queue IO Address Offset */
+SK_U32	QuStartAddr,	/* Queue Start Address */
+SK_U32	QuEndAddr,	/* Queue End Address */
+int	QuType)		/* Queue Type (SK_RX_SRAM_Q|SK_RX_BRAM_Q|SK_TX_RAM_Q) */
+{
+	SK_U32	RxUpThresVal;
+	SK_U32	RxLoThresVal;
+
+	if (QuStartAddr != QuEndAddr) {
+		/* calculate thresholds, assume we have a big Rx queue */
+		RxUpThresVal = (QuEndAddr + 1 - QuStartAddr - SK_RB_ULPP) / 8;
+		RxLoThresVal = (QuEndAddr + 1 - QuStartAddr - SK_RB_LLPP_B)/8;
+
+		/* build HW address format */
+		QuStartAddr = QuStartAddr / 8;
+		QuEndAddr = QuEndAddr / 8;
+
+		/* release local reset */
+		SK_OUT8(IoC, RB_ADDR(QuIoOffs,RB_CTRL), RB_RST_CLR);
+
+		/* configure addresses */
+		SK_OUT32(IoC, RB_ADDR(QuIoOffs,RB_START), QuStartAddr);
+		SK_OUT32(IoC, RB_ADDR(QuIoOffs,RB_END), QuEndAddr);
+		SK_OUT32(IoC, RB_ADDR(QuIoOffs,RB_WP), QuStartAddr);
+		SK_OUT32(IoC, RB_ADDR(QuIoOffs,RB_RP), QuStartAddr);
+
+		switch (QuType) {
+		case SK_RX_SRAM_Q:
+			/* configure threshold for small Rx Queue */
+			RxLoThresVal += (SK_RB_LLPP_B - SK_RB_LLPP_S) / 8;
+
+			/* continue with SK_RX_BRAM_Q */
+		case SK_RX_BRAM_Q:
+			/* write threshold for Rx Queue */
+
+			SK_OUT32(IoC, RB_ADDR(QuIoOffs,RB_RX_UTPP),
+				RxUpThresVal);
+			SK_OUT32(IoC, RB_ADDR(QuIoOffs,RB_RX_LTPP),
+				RxLoThresVal);
+			/* the high priority threshold not used */
+			break;
+		case SK_TX_RAM_Q:
+			/*
+			 * Do NOT use Store and forward under normal
+			 * operation due to performance optimization.
+			 * But if Jumbo frames are configured we NEED
+			 * the store and forward of the RAM buffer.
+			 */
+			if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+				/*
+				 * enable Store & Forward Mode for the
+				 * Tx Side
+				 */
+				SK_OUT8(IoC, RB_ADDR(QuIoOffs,RB_CTRL),
+					RB_ENA_STFWD);
+			}
+			break;
+		}
+
+		/* set queue operational */
+		SK_OUT8(IoC, RB_ADDR(QuIoOffs,RB_CTRL), RB_ENA_OP_MD);
+	}
+	else {
+		/* ensure the queue is still disabled */
+		SK_OUT8(IoC, RB_ADDR(QuIoOffs,RB_CTRL), RB_RST_SET);
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkGeInitRamBufs() - Initialize the RAM Buffer Queues
+ *
+ * Description:
+ *	Initialize all RAM Buffer Queues of the specified port
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInitRamBufs(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT *pPrt;
+	int RxQType;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PRxQSize == SK_MIN_RXQ_SIZE) {
+		RxQType = SK_RX_SRAM_Q; 	/* small Rx Queue */
+	}
+	else {
+		RxQType = SK_RX_BRAM_Q;		/* big Rx Queue */
+	}
+
+	DoInitRamQueue(pAC, IoC, pPrt->PRxQOff, pPrt->PRxQRamStart,
+		pPrt->PRxQRamEnd, RxQType);
+	DoInitRamQueue(pAC, IoC, pPrt->PXsQOff, pPrt->PXsQRamStart,
+		pPrt->PXsQRamEnd, SK_TX_RAM_Q);
+	DoInitRamQueue(pAC, IoC, pPrt->PXaQOff, pPrt->PXaQRamStart,
+		pPrt->PXaQRamEnd, SK_TX_RAM_Q);
+}
+
+/******************************************************************************
+ *
+ *	SkGeInitRamIface() - Initialize the RAM Interface
+ *
+ * Description:
+ *	This function initializes the Adapbers RAM Interface.
+ *
+ * Note:
+ *	This function is used in the diagnostics.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGeInitRamIface(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	/* release local reset */
+	SK_OUT16(IoC, B3_RI_CTRL, RI_RST_CLR);
+
+	/* configure timeout values */
+	SK_OUT8(IoC, B3_RI_WTO_R1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_WTO_XA1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_WTO_XS1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_R1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_XA1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_XS1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_WTO_R2, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_WTO_XA2, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_WTO_XS2, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_R2, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_XA2, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_XS2, SK_RI_TO_53);
+}
+
+/******************************************************************************
+ *
+ *	SkGeInitBmu() - Initialize the BMU state machines
+ *
+ * Description:
+ *	Initialize all BMU state machines of the specified port
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInitBmu(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT *pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Rx Queue: Release all local resets and set the watermark */
+	SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff,Q_CSR), CSR_CLR_RESET);
+	SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff,Q_F), SK_BMU_RX_WM);
+
+	/*
+	 * Tx Queue: Release all local resets if the queue is used!
+	 * 		set watermark
+	 */
+	if (pPrt->PXSQSize != 0) {
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff,Q_CSR), CSR_CLR_RESET);
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff,Q_F), SK_BMU_TX_WM);
+	}
+	if (pPrt->PXAQSize != 0) {
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff,Q_CSR), CSR_CLR_RESET);
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff,Q_F), SK_BMU_TX_WM);
+	}
+	/*
+	 * Do NOT enable the descriptor poll timers here, because
+	 * the descriptor addresses are not specified yet.
+	 */
+}
+
+/******************************************************************************
+ *
+ *	TestStopBit() -	Test the stop bit of the queue
+ *
+ * Description:
+ *	Stopping a queue is not as simple as it seems to be.
+ *	If descriptor polling is enabled, it may happen
+ *	that RX/TX stop is done and SV idle is NOT set.
+ *	In this case we have to issue another stop command.
+ *
+ * Retruns:
+ *	The queues control status register
+ */
+static SK_U32 TestStopBit(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO Context */
+int	QuIoOffs)	/* Queue IO Address Offset */
+{
+	SK_U32	QuCsr;	/* CSR contents */
+
+	SK_IN32(IoC, Q_ADDR(QuIoOffs,Q_CSR), &QuCsr);
+	if ((QuCsr & (CSR_STOP|CSR_SV_IDLE)) == 0) {
+		SK_OUT32(IoC, Q_ADDR(QuIoOffs,Q_CSR), CSR_STOP);
+		SK_IN32(IoC, Q_ADDR(QuIoOffs,Q_CSR), &QuCsr);
+	}
+	return (QuCsr);
+}
+
+/******************************************************************************
+ *
+ *	SkGeStopPort() - Stop the Rx/Tx activity of the port 'Port'.
+ *
+ * Description:
+ *	After calling this function the descriptor rings and rx and tx
+ *	queues of this port may be reconfigured.
+ *
+ *	It is possible to stop the receive and transmit path seperate or
+ *	both together.
+ *
+ *	Dir =	SK_STOP_TX 	Stops the transmit path only and resets
+ *				the XMAC. The receive queue is still and
+ *				the pending rx frames may still transfered
+ *				into the RxD.
+ *		SK_STOP_RX	Stop the receive path. The tansmit path
+ *				has to be stoped once before.
+ *		SK_STOP_ALL	SK_STOP_TX + SK_STOP_RX
+ *
+ *	RstMode=SK_SOFT_RST	Resets the XMAC. The PHY is still alive.
+ *		SK_HARD_RST	Resets the XMAC and the PHY.
+ *
+ * Example:
+ *	1) A Link Down event was signaled for a port. Therefore the activity
+ *	of this port should be stoped and a hardware reset should be issued
+ *	to enable the workaround of XMAC errata #2. But the received frames
+ *	should not be discarded.
+ *		...
+ *		SkGeStopPort(pAC, IoC, Port, SK_STOP_TX, SK_HARD_RST);
+ *		(transfer all pending rx frames)
+ *		SkGeStopPort(pAC, IoC, Port, SK_STOP_RX, SK_HARD_RST);
+ *		...
+ *
+ *	2) An event was issued which request the driver to switch
+ *	the 'virtual active' link to an other already active port
+ *	as soon as possible. The frames in the receive queue of this
+ *	port may be lost. But the PHY must not be reset during this
+ *	event.
+ *		...
+ *		SkGeStopPort(pAC, IoC, Port, SK_STOP_ALL, SK_SOFT_RST);
+ *		...
+ *
+ * Extended Description:
+ *	If SK_STOP_TX is set,
+ *		o disable the XMACs receive and transmiter to prevent
+ *		  from sending incomplete frames
+ *		o stop the port's transmit queues before terminating the
+ *		  BMUs to prevent from performing incomplete PCI cycles
+ *		  on the PCI bus
+ *		- The network rx and tx activity and PCI tx transfer is
+ *		  disabled now.
+ *		o reset the XMAC depending on the RstMode
+ *		o Stop Interval Timer and Limit Counter of Tx Arbiter,
+ *		  also disable Force Sync bit and Enable Alloc bit.
+ *		o perform a local reset of the port's tx path
+ *			- reset the PCI FIFO of the async tx queue
+ *			- reset the PCI FIFO of the sync tx queue
+ *			- reset the RAM Buffer async tx queue
+ *			- reset the RAM Butter sync tx queue
+ *			- reset the MAC Tx FIFO
+ *		o switch Link and Tx LED off, stop the LED counters
+ *
+ *	If SK_STOP_RX is set,
+ *		o stop the port's receive queue
+ *		- The path data transfer activity is fully stopped now.
+ *		o perform a local reset of the port's rx path
+ *			- reset the PCI FIFO of the rx queue
+ *			- reset the RAM Buffer receive queue
+ *			- reset the MAC Rx FIFO
+ *		o switch Rx LED off, stop the LED counter
+ *
+ *	If all ports are stopped,
+ *		o reset the RAM Interface.
+ *
+ * Notes:
+ *	o This function may be called during the driver states RESET_PORT and
+ *	  SWITCH_PORT.
+ */
+void	SkGeStopPort(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int	Port,	/* port to stop (MAC_1 + n) */
+int	Dir,	/* Direction to Stop (SK_STOP_RX, SK_STOP_TX, SK_STOP_ALL) */
+int	RstMode)/* Reset Mode (SK_SOFT_RST, SK_HARD_RST) */
+{
+#ifndef	SK_DIAG
+	SK_EVPARA Para;
+#endif	/* !SK_DIAG */
+	SK_GEPORT *pPrt;
+	SK_U32	DWord;
+	SK_U16	Word;
+	SK_U32	XsCsr;
+	SK_U32	XaCsr;
+	int	i;
+	SK_BOOL	AllPortsDis;
+	SK_U64	ToutStart;
+	int	ToutCnt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (Dir & SK_STOP_TX) {
+		/* disable the XMACs receiver and transmitter */
+		XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+		XM_OUT16(IoC, Port, XM_MMU_CMD,
+			Word & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
+
+		/* dummy read to ensure writing */
+		XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+
+		/* stop both transmit queues */
+		/*
+		 * If the BMU is in the reset state CSR_STOP will terminate
+		 * immediately.
+		 */
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff,Q_CSR), CSR_STOP);
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff,Q_CSR), CSR_STOP);
+
+		ToutStart = SkOsGetTime(pAC);
+		ToutCnt = 0;
+		do {
+			/*
+			 * Clear packet arbiter timeout to make sure
+			 * this loop will terminate
+			 */
+			if (Port == MAC_1) {
+				Word = PA_CLR_TO_TX1;
+			}
+			else {
+				Word = PA_CLR_TO_TX2;
+			}
+			SK_OUT16(IoC, B3_PA_CTRL, Word);
+
+			/*
+			 * If the transfer stucks at the XMAC the STOP command
+			 * will not terminate if we don't flush the XMACs
+			 * transmit FIFO !
+			 */
+			XM_IN32(IoC, Port, XM_MODE, &DWord);
+			DWord |= XM_MD_FTF ;
+			XM_OUT32(IoC, Port, XM_MODE, DWord);
+
+			XsCsr = TestStopBit(pAC, IoC, pPrt->PXsQOff);
+			XaCsr = TestStopBit(pAC, IoC, pPrt->PXaQOff);
+
+			if (ToutStart + (SK_TICKS_PER_SEC / 18) <
+				SkOsGetTime(pAC)) {
+
+				/*
+				 * Timeout of 1/18 second reached.
+				 */
+				ToutCnt++;
+				switch (ToutCnt) {
+				case 1:
+					/*
+					 * Cache Incoherency workaround:
+					 * Assume a start command has been 
+					 * lost while sending the frame. 
+					 */
+					ToutStart = SkOsGetTime(pAC);
+					if (XsCsr & CSR_STOP) {
+						SK_OUT32(IoC,
+							Q_ADDR(pPrt->PXsQOff,
+							Q_CSR), CSR_START);
+					}
+					if (XaCsr & CSR_STOP) {
+						SK_OUT32(IoC,
+							Q_ADDR(pPrt->PXaQOff,
+							Q_CSR), CSR_START);
+					}
+					break;
+				case 2:
+				default:	/* Fatal Error, Loop aborted */
+					/* Create an Error Log Entry */
+					SK_ERR_LOG(pAC, SK_ERRCL_HW,
+						SKERR_HWI_E018,
+						SKERR_HWI_E018MSG);
+#ifndef SK_DIAG
+					Para.Para64 = Port;
+					SkEventQueue(pAC, SKGE_DRV,
+						SK_DRV_PORT_FAIL, Para);
+#endif	/* !SK_DIAG */
+					return;
+				}
+			}
+
+		/*
+		 * because of the ASIC problem report entry from 21.08.98
+		 * it is required to wait until CSR_STOP is reset and
+		 * CSR_SV_IDLE is set.
+		 */
+		} while ((XsCsr & (CSR_STOP|CSR_SV_IDLE)) != CSR_SV_IDLE ||
+			 (XaCsr & (CSR_STOP|CSR_SV_IDLE)) != CSR_SV_IDLE);
+
+		/* reset the XMAC depending on the RstMode */
+		if (RstMode == SK_SOFT_RST) {
+			SkXmSoftRst(pAC, IoC, Port);
+		}
+		else {
+			SkXmHardRst(pAC, IoC, Port);
+		}
+
+ 		/*
+		 * Stop Interval Timer and Limit Counter of Tx Arbiter,
+ 		 * also disable Force Sync bit and Enable Alloc bit.
+		 */
+		SK_OUT8(IoC, MR_ADDR(Port,TXA_CTRL),
+			TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
+		SK_OUT32(IoC, MR_ADDR(Port,TXA_ITI_INI), 0x00000000L);
+		SK_OUT32(IoC, MR_ADDR(Port,TXA_LIM_INI), 0x00000000L);
+
+		/*
+		 * perform a local reset of the port's tx path
+		 *	- reset the PCI FIFO of the async tx queue
+		 *	- reset the PCI FIFO of the sync tx queue
+		 *	- reset the RAM Buffer async tx queue
+		 *	- reset the RAM Butter sync tx queue
+		 *	- reset the MAC Tx FIFO
+		 */
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff,Q_CSR), CSR_SET_RESET);
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff,Q_CSR), CSR_SET_RESET);
+		SK_OUT8(IoC, RB_ADDR(pPrt->PXaQOff,RB_CTRL), RB_RST_SET);
+		SK_OUT8(IoC, RB_ADDR(pPrt->PXsQOff,RB_CTRL), RB_RST_SET);
+		/* Note: MFF_RST_SET does NOT reset the XMAC! */
+		SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_SET);
+
+		/* switch Link and Tx LED off, stop the LED counters */
+		/* Link LED is switched off by the RLMT and the Diag itself */
+		SkGeXmitLED(pAC, IoC, MR_ADDR(Port,TX_LED_INI), SK_LED_DIS);
+	}
+
+	if (Dir & SK_STOP_RX) {
+		/*
+		 * The RX Stop Command will not terminate if no buffers
+		 * are queued in the RxD ring. But it will always reach
+		 * the Idle state. Therefore we can use this feature to
+		 * stop the transfer of received packets.
+		 */
+		/* stop the port's receive queue */
+		SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff,Q_CSR), CSR_STOP);
+		i = 100;
+		do {
+			/*
+			 * Clear packet arbiter timeout to make sure
+			 * this loop will terminate
+			 */
+			if (Port == MAC_1) {
+				Word = PA_CLR_TO_RX1;
+			}
+			else {
+				Word = PA_CLR_TO_RX2;
+			}
+			SK_OUT16(IoC, B3_PA_CTRL, Word);
+
+			DWord = TestStopBit(pAC, IoC, pPrt->PRxQOff);
+			if (i != 0) {
+				i--;
+			}
+
+		/* finish if CSR_STOP is done or CSR_SV_IDLE is true and i==0 */
+		/*
+		 * because of the ASIC problem report entry from 21.08.98
+		 * it is required to wait until CSR_STOP is reset and
+		 * CSR_SV_IDLE is set.
+		 */
+		} while ((DWord & (CSR_STOP|CSR_SV_IDLE)) != CSR_SV_IDLE &&
+			((DWord & CSR_SV_IDLE) == 0 || i != 0));
+
+		/* The path data transfer activity is fully stopped now. */
+
+		/*
+		 * perform a local reset of the port's rx path
+		 *	- reset the PCI FIFO of the rx queue
+		 *	- reset the RAM Buffer receive queue
+		 *	- reset the MAC Rx FIFO
+		 */
+		SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff,Q_CSR), CSR_SET_RESET);
+		SK_OUT8(IoC, RB_ADDR(pPrt->PRxQOff,RB_CTRL), RB_RST_SET);
+		SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_SET);
+
+		/* switch Rx LED off, stop the LED counter */
+		SkGeXmitLED(pAC, IoC, MR_ADDR(Port,RX_LED_INI), SK_LED_DIS);
+
+	}
+
+ 	/*
+	 * If all ports are stopped reset the RAM Interface.
+	 */
+	for (i = 0, AllPortsDis = SK_TRUE; i < pAC->GIni.GIMacsFound; i++) {
+		if (pAC->GIni.GP[i].PState != SK_PRT_RESET &&
+			pAC->GIni.GP[i].PState != SK_PRT_STOP) {
+
+			AllPortsDis = SK_FALSE;
+			break;
+		}
+	}
+	if (AllPortsDis) {
+		pAC->GIni.GIAnyPortAct = SK_FALSE;
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkGeInit0() - Level 0 Initialization
+ *
+ * Description:
+ *	- Initialize the BMU address offsets
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInit0(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	int i;
+	SK_GEPORT *pPrt;
+
+	for (i = 0; i < SK_MAX_MACS; i++) {
+		pPrt = &pAC->GIni.GP[i];
+		pPrt->PState = SK_PRT_RESET;
+		pPrt->PRxQOff = QOffTab[i].RxQOff;
+		pPrt->PXsQOff = QOffTab[i].XsQOff;
+		pPrt->PXaQOff = QOffTab[i].XaQOff;
+		pPrt->PCheckPar = SK_FALSE;
+		pPrt->PRxCmd = XM_RX_STRIP_FCS | XM_RX_LENERR_OK;
+		pPrt->PIsave = 0;
+		pPrt->PPrevShorts = 0;
+		pPrt->PLinkResCt = 0;
+		pPrt->PPrevRx = 0;
+		pPrt->PPrevFcs = 0;
+		pPrt->PRxLim = SK_DEF_RX_WA_LIM;
+		pPrt->PLinkMode = SK_LMODE_AUTOFULL;
+		pPrt->PLinkModeConf = SK_LMODE_AUTOSENSE;
+		pPrt->PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM;
+		pPrt->PLinkBroken = SK_TRUE; /* See WA code */
+		pPrt->PLinkCap = (SK_LMODE_CAP_HALF | SK_LMODE_CAP_FULL |
+				SK_LMODE_CAP_AUTOHALF | SK_LMODE_CAP_AUTOFULL);
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN;
+		pPrt->PFlowCtrlCap = SK_FLOW_MODE_SYM_OR_REM;
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+		pPrt->PMSCap = (SK_MS_CAP_AUTO | SK_MS_CAP_MASTER | 
+				SK_MS_CAP_SLAVE);
+		pPrt->PMSMode = SK_MS_MODE_AUTO;
+		pPrt->PMSStatus = SK_MS_STAT_UNSET;
+		pPrt->PAutoNegFail = SK_FALSE;
+		pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
+		pPrt->PHWLinkUp = SK_FALSE;
+	}
+
+	pAC->GIni.GIPortUsage = SK_RED_LINK;
+	pAC->GIni.GIAnyPortAct = SK_FALSE;
+}
+
+/******************************************************************************
+ *
+ *	SkGeInit1() - Level 1 Initialization
+ *
+ * Description:
+ *	o Do a software reset.
+ *	o Clear all reset bits.
+ *	o Verify that the detected hardware is present.
+ *	  Return an error if not.
+ *	o Get the hardware configuration
+ *		+ Read the number of MACs/Ports.
+ *		+ Read the RAM size.
+ *		+ Read the PCI Revision ID.
+ *		+ Find out the adapters host clock speed
+ *		+ Read and check the PHY type
+ *
+ * Returns:
+ *	0:	success
+ *	5:	Unexpected PHY type detected
+ */
+static int SkGeInit1(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	SK_U8	Byte;
+	SK_U16	Word;
+	int	RetVal;
+	int	i;
+
+	RetVal = 0;
+
+	/* Do the reset */
+	SK_OUT8(IoC, B0_CTST, CS_RST_SET);
+
+	/* Release the reset */
+	SK_OUT8(IoC, B0_CTST, CS_RST_CLR);
+
+	/* Reset all error bits in the PCI STATUS register */
+	/*
+	 * Note: Cfg cycles cannot be used, because they are not
+	 *	 available on some platforms after 'boot time'.
+	 */
+	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+	SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+	SK_OUT16(IoC, PCI_C(PCI_STATUS), Word | PCI_ERRBITS);
+	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+	/* Release Master_Reset */
+	SK_OUT8(IoC, B0_CTST, CS_MRST_CLR);
+
+	/* Read number of MACs */
+	SK_IN8(IoC, B2_MAC_CFG, &Byte);
+	if (Byte & CFG_SNG_MAC) {
+		pAC->GIni.GIMacsFound = 1;
+	}
+	else {
+		pAC->GIni.GIMacsFound = 2;
+	}
+	SK_IN8(IoC, PCI_C(PCI_REV_ID), &Byte);
+	pAC->GIni.GIPciHwRev = (int) Byte;
+
+	/* Read the adapters RAM size */
+	SK_IN8(IoC, B2_E_0, &Byte);
+	if (Byte == 3) {
+		pAC->GIni.GIRamSize = (int)(Byte-1) * 512;
+		pAC->GIni.GIRamOffs = (SK_U32)512 * 1024;
+	}
+	else {
+		pAC->GIni.GIRamSize = (int)Byte * 512;
+		pAC->GIni.GIRamOffs = 0;
+	}
+
+	/* All known GE Adapters works with 53.125 MHz host clock */
+	pAC->GIni.GIHstClkFact = SK_FACT_53;
+	pAC->GIni.GIPollTimerVal =
+		SK_DPOLL_DEF * (SK_U32)pAC->GIni.GIHstClkFact / 100;
+	
+	/* Read the PHY type */
+	SK_IN8(IoC, B2_E_1, &Byte);
+	Byte &= 0x0f;	/* the PHY type is stored in the lower nibble */
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		pAC->GIni.GP[i].PhyType = Byte;
+		switch (Byte) {
+		case SK_PHY_XMAC:
+			pAC->GIni.GP[i].PhyAddr = PHY_ADDR_XMAC;
+			break;
+		case SK_PHY_BCOM:
+			pAC->GIni.GP[i].PhyAddr = PHY_ADDR_BCOM;
+			break;
+		case SK_PHY_LONE:
+			pAC->GIni.GP[i].PhyAddr = PHY_ADDR_LONE;
+			break;
+		case SK_PHY_NAT:
+			pAC->GIni.GP[i].PhyAddr = PHY_ADDR_NAT;
+			break;
+		default:
+			/* ERROR: unexpected PHY typ detected */
+			RetVal = 5;
+			break;
+		}
+	}
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_INIT,
+		("PHY type: %d  PHY addr: %x\n", pAC->GIni.GP[i].PhyType,
+		pAC->GIni.GP[i].PhyAddr)) ;
+
+	return (RetVal);
+}
+
+/******************************************************************************
+ *
+ *	SkGeInit2() - Level 2 Initialization
+ *
+ * Description:
+ *	- start the Blink Source Counter
+ *	- start the Descriptor Poll Timer
+ *	- configure the MAC-Arbiter
+ *	- configure the Packet-Arbiter
+ *	- enable the Tx Arbiters
+ *	- enable the RAM Interface Arbiter
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInit2(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	SK_GEPORT *pPrt;
+	SK_U32	DWord;
+	int	i;
+
+	/* start the Blink Source Counter */
+	DWord = SK_BLK_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100;
+	SK_OUT32(IoC, B2_BSC_INI, DWord);
+	SK_OUT8(IoC, B2_BSC_CTRL, BSC_START);
+
+	/* start the Descriptor Poll Timer */
+	if (pAC->GIni.GIPollTimerVal != 0) {
+		if (pAC->GIni.GIPollTimerVal > SK_DPOLL_MAX) {
+			pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX;
+
+			/* Create an Error Log Entry */
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E017,
+				SKERR_HWI_E017MSG);
+		}
+		SK_OUT32(IoC, B28_DPT_INI, pAC->GIni.GIPollTimerVal);
+		SK_OUT8(IoC, B28_DPT_CTRL, DPT_START);
+	}
+
+	/*
+	 * Configure
+	 *	- the MAC-Arbiter and
+	 *	- the Paket Arbiter
+	 *
+	 * The MAC and the packet arbiter will be started once
+	 * and never be stopped.
+	 */
+	SkGeInitMacArb(pAC, IoC);
+	SkGeInitPktArb(pAC, IoC);
+
+	/* enable the Tx Arbiters */
+	SK_OUT8(IoC, MR_ADDR(MAC_1,TXA_CTRL), TXA_ENA_ARB);
+	if (pAC->GIni.GIMacsFound > 1) {
+		SK_OUT8(IoC, MR_ADDR(MAC_2,TXA_CTRL), TXA_ENA_ARB);
+	}
+
+	/* enable the RAM Interface Arbiter */
+	SkGeInitRamIface(pAC, IoC);
+
+	for (i = 0; i < SK_MAX_MACS; i++) {
+		pPrt = &pAC->GIni.GP[i];
+		if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+			pPrt->PRxCmd |= XM_RX_BIG_PK_OK;
+		}
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkGeInit() - Initialize the GE Adapter with the specified level.
+ *
+ * Description:
+ *	Level	0:	Initialize the Module structures.
+ *	Level	1:	Generic Hardware Initialization. The
+ *			IOP/MemBase pointer has to be set before
+ *			calling this level.
+ *
+ *			o Do a software reset.
+ *			o Clear all reset bits.
+ *			o Verify that the detected hardware is present.
+ *			  Return an error if not.
+ *			o Get the hardware configuration
+ *				+ Set GIMacsFound with the number of MACs.
+ *				+ Store the RAM size in GIRamSize.
+ *				+ Save the PCI Revision ID in GIPciHwRev.
+ *			o return an error
+ *				if Number of MACs > SK_MAX_MACS
+ *
+ *			After returning from Level 0 the adapter
+ *			may be accessed with IO operations.
+ *
+ *	Level	2:	start the Blink Source Counter
+ *
+ * Returns:
+ *	0:	success
+ *	1:	Number of MACs exceeds SK_MAX_MACS	( after level 1)
+ *	2:	Adapter not present or not accessable
+ *	3:	Illegal initialization level
+ *	4:	Initialization Level 1 Call missing
+ *	5:	Unexpected PHY type detected
+ */
+int	SkGeInit(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Level)		/* initialization level */
+{
+	int	RetVal;		/* return value */
+	SK_U32	DWord;
+
+	RetVal = 0;
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_INIT,
+		("SkGeInit(Level %d)\n",Level)) ;
+
+	switch (Level) {
+	case SK_INIT_DATA:
+		/* Initialization Level 0 */
+		SkGeInit0(pAC,IoC) ;
+		pAC->GIni.GILevel = SK_INIT_DATA;
+		break;
+	case SK_INIT_IO:
+		/* Initialization Level 1 */
+		RetVal = SkGeInit1(pAC,IoC) ;
+
+		/* Check if the adapter seems to be accessable */
+		SK_OUT32(IoC, B2_IRQM_INI, 0x11335577L);
+		SK_IN32(IoC, B2_IRQM_INI, &DWord);
+		SK_OUT32(IoC, B2_IRQM_INI, 0x00000000L);
+		if (DWord != 0x11335577L) {
+			RetVal = 2;
+			break;
+		}
+
+		/* Check if the number of GIMacsFound matches SK_MAX_MACS */
+		if (pAC->GIni.GIMacsFound > SK_MAX_MACS) {
+			RetVal = 1;
+			break;
+		}
+
+		/* Level 1 successfully passed */
+		pAC->GIni.GILevel = SK_INIT_IO;
+		break;
+	case SK_INIT_RUN:
+		/* Initialization Level 2 */
+		if (pAC->GIni.GILevel != SK_INIT_IO) {
+#ifndef	SK_DIAG
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E002,
+				SKERR_HWI_E002MSG);
+#endif
+			RetVal = 4;
+			break;
+		}
+		SkGeInit2(pAC,IoC) ;
+
+		/* Level 2 successfully passed */
+		pAC->GIni.GILevel = SK_INIT_RUN;
+		break;
+	default:
+		/* Create an Error Log Entry */
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E003, SKERR_HWI_E003MSG);
+		RetVal = 3 ;
+		break;
+	}
+
+	return (RetVal);
+}
+
+/******************************************************************************
+ *
+ *	SkGeDeInit() - Deinitialize the adapter.
+ *
+ * Description:
+ *	All ports of the adapter will be stopped if not already done.
+ *	Do a software reset and switch off all LEDs.
+ *
+ * Returns:
+ *	nothing
+ */
+void	SkGeDeInit(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	int	i;
+	SK_U16	Word;
+
+	/* Stop all current transfer activity */
+	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+		if (pAC->GIni.GP[i].PState != SK_PRT_STOP &&
+			pAC->GIni.GP[i].PState != SK_PRT_RESET) {
+
+			SkGeStopPort(pAC, IoC, i, SK_STOP_ALL, SK_HARD_RST);
+		}
+	}
+
+	/* Reset all bits in the PCI STATUS register */
+	/*
+	 * Note: Cfg cycles cannot be used, because they are not
+	 *	 available on some platforms after 'boot time'.
+	 */
+	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+	SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+	SK_OUT16(IoC, PCI_C(PCI_STATUS), Word | PCI_ERRBITS);
+	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+	/* Do the reset, all LEDs are switched off now */
+	SK_OUT8(IoC, B0_CTST, CS_RST_SET);
+}
+
+/******************************************************************************
+ *
+ *	SkGeInitPort()	Initialize the specified prot.
+ *
+ * Description:
+ *	PRxQSize, PXSQSize, and PXAQSize has to be
+ *	configured for the specified port before calling this
+ *	function. The descriptor rings has to be initialized, too.
+ *
+ *	o (Re)configure queues of the specified port.
+ *	o configure the XMAC of the specified port.
+ *	o put ASIC and XMAC(s) in operational mode.
+ *	o initialize Rx/Tx and Sync LED
+ *	o initialize RAM Buffers and MAC FIFOs
+ *
+ *	The port is ready to connect when returning.
+ *
+ * Note:
+ *	The XMACs Rx and Tx state machine is still disabled when
+ *	returning.
+ *
+ * Returns:
+ *	0:	success
+ *	1:	Queue size initialization error. The configured values
+ *		for PRxQSize, PXSQSize, or PXAQSize are invalid for one
+ *		or more queues. The specified port was NOT initialized.
+ *		An error log entry was generated.
+ *	2:	The port has to be stopped before it can be initilaized again.
+ */
+int SkGeInitPort(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port to configure */
+{
+	SK_GEPORT *pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (SkGeCheckQSize(pAC,Port) != 0) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E004, SKERR_HWI_E004MSG);
+		return (1);
+	}
+	if (pPrt->PState == SK_PRT_INIT || pPrt->PState == SK_PRT_RUN) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E005, SKERR_HWI_E005MSG);
+		return (2);
+	}
+
+	/* Configuration ok, initialize the Port now */
+
+	/* Initialize Rx, Tx and Link LED */
+	/*
+	 * If 1000BT Phy needs LED initialization than swap
+	 * LED and XMAC initialization order
+	 */
+ 	SkGeXmitLED(pAC, IoC, MR_ADDR(Port,TX_LED_INI), SK_LED_ENA);
+ 	SkGeXmitLED(pAC, IoC, MR_ADDR(Port,RX_LED_INI), SK_LED_ENA);
+	/* The Link LED is initialized by RLMT or Diagnostics itself */ 
+
+	/* Do NOT initialize the Link Sync Counter */
+
+	/*
+	 * Configure
+	 *	- XMAC
+	 *	- MAC FIFOs
+	 *	- RAM Buffers
+	 *	- enable Force Sync bit if synchronous queue available
+	 *	- BMUs
+	 */
+	SkXmInitMac(pAC, IoC, Port);
+	SkGeInitMacFifo(pAC, IoC, Port);
+	SkGeInitRamBufs(pAC, IoC, Port);
+	if (pPrt->PXSQSize != 0) {
+		SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_ENA_FSYNC);
+	}
+	SkGeInitBmu(pAC, IoC, Port);
+
+	/* Mark port as initialized. */
+	pPrt->PState = SK_PRT_INIT;
+	pAC->GIni.GIAnyPortAct = SK_TRUE;
+
+	return (0);
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/skgepnmi.c linux.14p16/drivers/net/sk98lin/skgepnmi.c
--- linux.vanilla/drivers/net/sk98lin/skgepnmi.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/skgepnmi.c	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,7142 @@
+/*****************************************************************************
+ *
+ * Name:	skgepnmi.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.69 $
+ * Date:	$Date: 1999/10/18 11:42:15 $
+ * Purpose:	Private Network Management Interface
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skge.c" for further 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 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgepnmi.c,v $
+ *	Revision 1.69  1999/10/18 11:42:15  rwahl
+ *	Added typecasts for checking event dependent param (debug only).
+ *	
+ *	Revision 1.68  1999/10/06 09:35:59  cgoos
+ *	Added state check to PHY_READ call (hanged if called during startup).
+ *	
+ *	Revision 1.67  1999/09/22 09:53:20  rwahl
+ *	- Read Broadcom register for updating fcs error counter (1000Base-T).
+ *	
+ *	Revision 1.66  1999/08/26 13:47:56  rwahl
+ *	Added SK_DRIVER_SENDEVENT when queueing RLMT_CHANGE_THRES trap.
+ *	
+ *	Revision 1.65  1999/07/26 07:49:35  cgoos
+ *	Added two typecasts to avoid compiler warnings.
+ *	
+ *	Revision 1.64  1999/05/20 09:24:12  cgoos
+ *	Changes for 1000Base-T (sensors, Master/Slave).
+ *	
+ *	Revision 1.63  1999/04/13 15:11:58  mhaveman
+ *	Moved include of rlmt.h to header skgepnmi.h because some macros
+ *	are needed there.
+ *	
+ *	Revision 1.62  1999/04/13 15:08:07  mhaveman
+ *	Replaced again SK_RLMT_CHECK_LINK with SK_PNMI_RLMT_MODE_CHK_LINK
+ *	to grant unified interface by only using the PNMI header file.
+ *	SK_PNMI_RLMT_MODE_CHK_LINK is defined the same as SK_RLMT_CHECK_LINK.
+ *	
+ *	Revision 1.61  1999/04/13 15:02:48  mhaveman
+ *	Changes caused by review:
+ *	-Changed some comments
+ *	-Removed redundant check for OID_SKGE_PHYS_FAC_ADDR
+ *	-Optimized PRESET check.
+ *	-Meaning of error SK_ADDR_DUPLICATE_ADDRESS changed. Set of same
+ *	 address will now not cause this error. Removed corresponding check.
+ *	
+ *	Revision 1.60  1999/03/23 10:41:23  mhaveman
+ *	Added comments.
+ *	
+ *	Revision 1.59  1999/02/19 08:01:28  mhaveman
+ *	Fixed bug 10372 that after counter reset all ports were displayed
+ *	as inactive.
+ *	
+ *	Revision 1.58  1999/02/16 18:04:47  mhaveman
+ *	Fixed problem of twisted OIDs SENSOR_WAR_TIME and SENSOR_ERR_TIME.
+ *	
+ *	Revision 1.56  1999/01/27 12:29:11  mhaveman
+ *	SkTimerStart was called with time value in milli seconds but needs
+ *	micro seconds.
+ *	
+ *	Revision 1.55  1999/01/25 15:00:38  mhaveman
+ *	Added support to allow multiple ports to be active. If this feature in
+ *	future will be used, the Management Data Base variables PORT_ACTIVE
+ *	and PORT_PREFERED should be moved to the port specific part of RLMT.
+ *	Currently they return the values of the first active physical port
+ *	found. A set to the virtual port will actually change all active
+ *	physical ports. A get returns the melted values of all active physical
+ *	ports. If the port values differ a return value INDETERMINATED will
+ *	be returned. This effects especially the CONF group.
+ *	
+ *	Revision 1.54  1999/01/19 10:10:22  mhaveman
+ *	-Fixed bug 10354: Counter values of virtual port were wrong after port
+ *	 switches
+ *	-Added check if a switch to the same port is notified.
+ *	
+ *	Revision 1.53  1999/01/07 09:25:21  mhaveman
+ *	Forgot to initialize a variable.
+ *	
+ *	Revision 1.52  1999/01/05 10:34:33  mhaveman
+ *	Fixed little error in RlmtChangeEstimate calculation.
+ *	
+ *	Revision 1.51  1999/01/05 09:59:07  mhaveman
+ *	-Moved timer start to init level 2
+ *	-Redesigned port switch average calculation to avoid 64bit
+ *	 arithmetic.
+ *	
+ *	Revision 1.50  1998/12/10 15:13:59  mhaveman
+ *	-Fixed: PHYS_CUR_ADDR returned wrong addresses
+ *	-Fixed: RLMT_PORT_PREFERED and RLMT_CHANGE_THRES preset returned
+ *	        always BAD_VALUE.
+ *	-Fixed: TRAP buffer seemed to sometimes suddenly empty
+ *	
+ *	Revision 1.49  1998/12/09 16:17:07  mhaveman
+ *	Fixed: Couldnot delete VPD keys on UNIX.
+ *	
+ *	Revision 1.48  1998/12/09 14:11:10  mhaveman
+ *	-Add: Debugmessage for XMAC_RESET supressed to minimize output.
+ *	-Fixed: RlmtChangeThreshold will now be initialized.
+ *	-Fixed: VPD_ENTRIES_LIST extended value with unnecessary space char.
+ *	-Fixed: On VPD key creation an invalid key name could be created
+ *	        (e.g. A5)
+ *	-Some minor changes in comments and code.
+ *	
+ *	Revision 1.47  1998/12/08 16:00:31  mhaveman
+ *	-Fixed: For RLMT_PORT_ACTIVE will now be returned a 0 if no port
+ *		is active.
+ *	-Fixed: For the RLMT statistics group only the last value was
+ *		returned and the rest of the buffer was filled with 0xff
+ *	-Fixed: Mysteriously the preset on RLMT_MODE still returned
+ *		BAD_VALUE.
+ *	Revision 1.46  1998/12/08 10:04:56  mhaveman
+ *	-Fixed: Preset on RLMT_MODE returned always BAD_VALUE error.
+ *	-Fixed: Alignment error in GetStruct
+ *	-Fixed: If for Get/Preset/SetStruct the buffer size is equal or
+ *	        larger than SK_PNMI_MIN_STRUCT_SIZE the return value is stored
+ *		to the buffer. In this case the caller should always return
+ *	        ok to its upper routines. Only if the buffer size is less
+ *	        than SK_PNMI_MIN_STRUCT_SIZE and the return value is unequal
+ *	        to 0, an error should be returned by the caller.
+ *	-Fixed: Wrong number of instances with RLMT statistic.
+ *	-Fixed: Return now SK_LMODE_STAT_UNKNOWN if the LinkModeStatus is 0.
+ *	
+ *	Revision 1.45  1998/12/03 17:17:24  mhaveman
+ *	-Removed for VPD create action the buffer size limitation to 4 bytes.
+ *	-Pass now physical/active physical port to ADDR for CUR_ADDR set
+ *	
+ *	Revision 1.44  1998/12/03 15:14:35  mhaveman
+ *	Another change to Vpd instance evaluation.
+ *
+ *	Revision 1.43  1998/12/03 14:18:10  mhaveman
+ *	-Fixed problem in PnmiSetStruct. It was impossible to set any value.
+ *	-Removed VPD key evaluation for VPD_FREE_BYTES and VPD_ACTION.
+ *	
+ *	Revision 1.42  1998/12/03 11:31:47  mhaveman
+ *	Inserted cast to satisfy lint.
+ *	
+ *	Revision 1.41  1998/12/03 11:28:16  mhaveman
+ *	Removed SK_PNMI_CHECKPTR
+ *	
+ *	Revision 1.40  1998/12/03 11:19:07  mhaveman
+ *	Fixed problems
+ *	-A set to virtual port will now be ignored. A set with broadcast
+ *	 address to any port will be ignored.
+ *	-GetStruct function made VPD instance calculation wrong.
+ *	-Prefered port returned -1 instead of 0.
+ *	
+ *	Revision 1.39  1998/11/26 15:30:29  mhaveman
+ *	Added sense mode to link mode.
+ *	
+ *	Revision 1.38  1998/11/23 15:34:00  mhaveman
+ *	-Fixed bug for RX counters. On an RX overflow interrupt the high
+ *	 words of all RX counters were incremented.
+ *	-SET operations on FLOWCTRL_MODE and LINK_MODE accept now the
+ *	 value 0, which has no effect. It is usefull for multiple instance
+ *	 SETs.
+ *	
+ *	Revision 1.37  1998/11/20 08:02:04  mhaveman
+ *	-Fixed: Ports were compared with MAX_SENSORS
+ *	-Fixed: Crash in GetTrapEntry with MEMSET macro
+ *	-Fixed: Conversions between physical, logical port index and instance
+ *	
+ *	Revision 1.36  1998/11/16 07:48:53  mhaveman
+ *	Casted SK_DRIVER_SENDEVENT with (void) to eleminate compiler warnings
+ *	on Solaris.
+ *	
+ *	Revision 1.35  1998/11/16 07:45:34  mhaveman
+ *	SkAddrOverride now returns value and will be checked.
+ *	
+ *	Revision 1.34  1998/11/10 13:40:37  mhaveman
+ *	Needed to change interface, because NT driver needs a return value
+ *	of needed buffer space on TOO_SHORT errors. Therefore all
+ *	SkPnmiGet/Preset/Set functions now have a pointer to the length
+ *	parameter, where the needed space on error is returned.
+ *	
+ *	Revision 1.33  1998/11/03 13:52:46  mhaveman
+ *	Made file lint conform.
+ *	
+ *	Revision 1.32  1998/11/03 13:19:07  mhaveman
+ *	The events SK_HWEV_SET_LMODE and SK_HWEV_SET_FLOWMODE pass now in
+ *	Para32[0] the physical MAC index and in Para32[1] the new mode.
+ *	
+ *	Revision 1.31  1998/11/03 12:30:40  gklug
+ *	fix: compiler warning memset
+ *
+ *	Revision 1.30  1998/11/03 12:04:46  mhaveman
+ *	Fixed problem in SENSOR_VALUE, which wrote beyond the buffer end
+ *	Fixed alignment problem with CHIPSET.
+ *	
+ *	Revision 1.29  1998/11/02 11:23:54  mhaveman
+ *	Corrected SK_ERROR_LOG to SK_ERR_LOG. Sorry.
+ *	
+ *	Revision 1.28  1998/11/02 10:47:16  mhaveman
+ *	Added syslog messages for internal errors.
+ *	
+ *	Revision 1.27  1998/10/30 15:48:06  mhaveman
+ *	Fixed problems after simulation of SK_PNMI_EVT_CHG_EST_TIMER and
+ *	RlmtChangeThreshold calculation.
+ *	
+ *	Revision 1.26  1998/10/29 15:36:55  mhaveman
+ *	-Fixed bug in trap buffer handling.
+ *	-OID_SKGE_DRIVER_DESCR, OID_SKGE_DRIVER_VERSION, OID_SKGE_HW_DESCR,
+ *	 OID_SKGE_HW_VERSION, OID_SKGE_VPD_ENTRIES_LIST, OID_SKGE_VPD_KEY,
+ *	 OID_SKGE_VPD_VALUE, and OID_SKGE_SENSOR_DESCR return values with
+ *	 a leading octet before each string storing the string length.
+ *	-Perform a RlmtUpdate during SK_PNMI_EVT_XMAC_RESET to minimize
+ *	 RlmtUpdate calls in GetStatVal.
+ *	-Inserted SK_PNMI_CHECKFLAGS macro increase readability.
+ *	
+ *	Revision 1.25  1998/10/29 08:50:36  mhaveman
+ *	Fixed problems after second event simulation.
+ *	
+ *	Revision 1.24  1998/10/28 08:44:37  mhaveman
+ *	-Fixed alignment problem
+ *	-Fixed problems during event simulation
+ *	-Fixed sequence of error return code (INSTANCE -> ACCESS -> SHORT)
+ *	-Changed type of parameter Instance back to SK_U32 because of VPD
+ *	-Updated new VPD function calls
+ *	
+ *	Revision 1.23  1998/10/23 10:16:37  mhaveman
+ *	Fixed bugs after buffer test simulation.
+ *	
+ *	Revision 1.22  1998/10/21 13:23:52  mhaveman
+ *	-Call syntax of SkOsGetTime() changed to SkOsGetTime(pAc).
+ *	-Changed calculation of hundrets of seconds.
+ *	
+ *	Revision 1.20  1998/10/20 07:30:45  mhaveman
+ *	Made type changes to unsigned integer where possible.
+ *	
+ *	Revision 1.19  1998/10/19 10:51:30  mhaveman
+ *	-Made Bug fixes after simulation run
+ *	-Renamed RlmtMAC... to RlmtPort...
+ *	-Marked workarounds with Errata comments
+ *	
+ *	Revision 1.18  1998/10/14 07:50:08  mhaveman
+ *	-For OID_SKGE_LINK_STATUS the link down detection has moved from RLMT
+ *	 to HWACCESS.
+ *	-Provided all MEMCPY/MEMSET macros with (char *) pointers, because
+ *	 Solaris throwed warnings when mapping to bcopy/bset.
+ *	
+ *	Revision 1.17  1998/10/13 07:42:01  mhaveman
+ *	-Added OIDs OID_SKGE_TRAP_NUMBER and OID_SKGE_ALL_DATA
+ *	-Removed old cvs history entries
+ *	-Renamed MacNumber to PortNumber
+ *	
+ *	Revision 1.16  1998/10/07 10:52:49  mhaveman
+ *	-Inserted handling of some OID_GEN_ Ids for windows
+ *	-Fixed problem with 803.2 statistic.
+ *	
+ *	Revision 1.15  1998/10/01 09:16:29  mhaveman
+ *	Added Debug messages for function call and UpdateFlag tracing.
+ *	
+ *	Revision 1.14  1998/09/30 13:39:09  mhaveman
+ *	-Reduced namings of 'MAC' by replacing them with 'PORT'.
+ *	-Completed counting of OID_SKGE_RX_HW_ERROR_CTS,
+ *       OID_SKGE_TX_HW_ERROR_CTS,
+ *	 OID_SKGE_IN_ERRORS_CTS, and OID_SKGE_OUT_ERROR_CTS.
+ *	-SET check for RlmtMode
+ *	
+ *	Revision 1.13  1998/09/28 13:13:08  mhaveman
+ *	Hide strcmp, strlen, and strncpy behind macros SK_STRCMP, SK_STRLEN,
+ *	and SK_STRNCPY. (Same reasons as for mem.. and MEM..)
+ *	
+ *	Revision 1.12  1998/09/16 08:18:36  cgoos
+ *	Fix: XM_INxx and XM_OUTxx called with different parameter order:
+ *      sometimes IoC,Mac,...  sometimes Mac,IoC,... Now always first variant.
+ *	Fix: inserted "Pnmi." into some pAC->pDriverDescription / Version.
+ *	Change: memset, memcpy to makros SK_MEMSET, SK_MEMCPY
+ *
+ *	Revision 1.11  1998/09/04 17:01:45  mhaveman
+ *	Added SyncCounter as macro and OID_SKGE_.._NO_DESCR_CTS to
+ *	OID_SKGE_RX_NO_BUF_CTS.
+ *	
+ *	Revision 1.10  1998/09/04 14:35:35  mhaveman
+ *	Added macro counters, that are counted by driver.
+ *	
+ ****************************************************************************/
+
+
+static const char SysKonnectFileId[] =
+	"@(#) $Id: skgepnmi.c,v 1.69 1999/10/18 11:42:15 rwahl Exp $ (C) SysKonnect.";
+
+#include "h/skdrv1st.h"
+#include "h/sktypes.h"
+#include "h/xmac_ii.h"
+
+#include "h/skdebug.h"
+#include "h/skqueue.h"
+#include "h/skgepnmi.h"
+#include "h/skgesirq.h"
+#include "h/skcsum.h"
+#include "h/skvpd.h"
+#include "h/skgehw.h"
+#include "h/skgeinit.h"
+#include "h/skdrv2nd.h"
+#include "h/skgepnm2.h"
+
+
+/*
+ * Public Function prototypes
+ */
+int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int level);
+int SkPnmiGetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
+	unsigned int *pLen, SK_U32 Instance);
+int SkPnmiPreSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
+	unsigned int *pLen, SK_U32 Instance);
+int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
+	unsigned int *pLen, SK_U32 Instance);
+int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, unsigned int *pLen);
+int SkPnmiPreSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, unsigned int *pLen);
+int SkPnmiSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, unsigned int *pLen);
+int SkPnmiEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Param);
+
+
+/*
+ * Private Function prototypes
+ */
+static int Addr(SK_AC *pAC, SK_IOC IoC, int action,
+	SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex);
+static SK_U8 CalculateLinkModeStatus(SK_AC *pAC, SK_IOC IoC, unsigned int
+	PhysPortIndex);
+static SK_U8 CalculateLinkStatus(SK_AC *pAC, SK_IOC IoC, unsigned int
+	PhysPortIndex);
+static void CopyMac(char *pDst, SK_MAC_ADDR *pMac);
+static void CopyTrapQueue(SK_AC *pAC, char *pDstBuf);
+static int CsumStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex);
+static int General(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex);
+static SK_U64 GetPhysStatVal(SK_AC *pAC, SK_IOC IoC,
+	unsigned int PhysPortIndex, unsigned int StatIndex);
+static SK_U64 GetStatVal(SK_AC *pAC, SK_IOC IoC, unsigned int LogPortIndex,
+	unsigned int StatIndex);
+static char* GetTrapEntry(SK_AC *pAC, SK_U32 TrapId, unsigned int Size);
+static void GetTrapQueueLen(SK_AC *pAC, unsigned int *pLen,
+	unsigned int *pEntries);
+static int GetVpdKeyArr(SK_AC *pAC, SK_IOC IoC, char *pKeyArr,
+	unsigned int KeyArrLen, unsigned int *pKeyNo);
+static int LookupId(SK_U32 Id);
+static int Mac8023Stat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex);
+static int MacPrivateConf(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex);
+static int MacPrivateStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex);
+static int MacUpdate(SK_AC *pAC, SK_IOC IoC, unsigned int FirstMac,
+	unsigned int LastMac);
+static int Monitor(SK_AC *pAC, SK_IOC IoC, int action,
+	SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex);
+static int OidStruct(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex);
+static int Perform(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int* pLen, SK_U32 Instance,
+	unsigned int TableIndex);
+static int PnmiStruct(SK_AC *pAC, SK_IOC IoC, int Action, char *pBuf,
+	unsigned int *pLen);
+static int PnmiVar(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance);
+static void QueueRlmtNewMacTrap(SK_AC *pAC, unsigned int ActiveMac);
+static void QueueRlmtPortTrap(SK_AC *pAC, SK_U32 TrapId,
+	unsigned int PortIndex);
+static void QueueSensorTrap(SK_AC *pAC, SK_U32 TrapId,
+	unsigned int SensorIndex);
+static void QueueSimpleTrap(SK_AC *pAC, SK_U32 TrapId);
+static void ResetCounter(SK_AC *pAC, SK_IOC IoC);
+static int Rlmt(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex);
+static int RlmtStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex);
+static int RlmtUpdate(SK_AC *pAC, SK_IOC IoC);
+static int SensorStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex);
+static int SirqUpdate(SK_AC *pAC, SK_IOC IoC);
+static void VirtualConf(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, char *pBuf);
+static int Vpd(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex);
+
+
+/******************************************************************************
+ *
+ * Global variables
+ */
+
+/*
+ * Table to correlate OID with handler function and index to
+ * hardware register stored in StatAddress if applicable.
+ */
+static const SK_PNMI_TAB_ENTRY IdTable[] = {
+	{OID_GEN_XMIT_OK,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX},
+	{OID_GEN_RCV_OK,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX},
+	{OID_GEN_XMIT_ERROR,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_GEN_RCV_ERROR,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_GEN_RCV_NO_BUFFER,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_GEN_DIRECTED_FRAMES_XMIT,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_UNICAST},
+	{OID_GEN_MULTICAST_FRAMES_XMIT,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_MULTICAST},
+	{OID_GEN_BROADCAST_FRAMES_XMIT,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_BROADCAST},
+	{OID_GEN_DIRECTED_FRAMES_RCV,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_UNICAST},
+	{OID_GEN_MULTICAST_FRAMES_RCV,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_MULTICAST},
+	{OID_GEN_BROADCAST_FRAMES_RCV,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_BROADCAST},
+	{OID_GEN_RCV_CRC_ERROR,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_FCS},
+	{OID_GEN_TRANSMIT_QUEUE_LENGTH,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_802_3_PERMANENT_ADDRESS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, 0},
+	{OID_802_3_CURRENT_ADDRESS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, 0},
+	{OID_802_3_RCV_ERROR_ALIGNMENT,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_FRAMING},
+	{OID_802_3_XMIT_ONE_COLLISION,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_SINGLE_COL},
+	{OID_802_3_XMIT_MORE_COLLISIONS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_MULTI_COL},
+	{OID_802_3_XMIT_DEFERRED,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_DEFFERAL},
+	{OID_802_3_XMIT_MAX_COLLISIONS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_EXCESS_COL},
+	{OID_802_3_RCV_OVERRUN,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_OVERFLOW},
+	{OID_802_3_XMIT_UNDERRUN,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_UNDERRUN},
+	{OID_802_3_XMIT_TIMES_CRS_LOST,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_CARRIER},
+	{OID_802_3_XMIT_LATE_COLLISIONS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_LATE_COL},
+	{OID_SKGE_MDB_VERSION,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(MgmtDBVersion),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_SUPPORTED_LIST,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_ALL_DATA,
+		0,
+		0,
+		0,
+		SK_PNMI_RW, OidStruct, 0},
+	{OID_SKGE_VPD_FREE_BYTES,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(VpdFreeBytes),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_ENTRIES_LIST,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(VpdEntriesList),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_ENTRIES_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(VpdEntriesNumber),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_KEY,
+		SK_PNMI_VPD_ENTRIES,
+		sizeof(SK_PNMI_VPD),
+		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdKey),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_VALUE,
+		SK_PNMI_VPD_ENTRIES,
+		sizeof(SK_PNMI_VPD),
+		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdValue),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_ACCESS,
+		SK_PNMI_VPD_ENTRIES,
+		sizeof(SK_PNMI_VPD),
+		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdAccess),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_ACTION,
+		SK_PNMI_VPD_ENTRIES,
+		sizeof(SK_PNMI_VPD),
+		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdAction),
+		SK_PNMI_RW, Vpd, 0},
+	{OID_SKGE_PORT_NUMBER,		
+		1,
+		0,
+		SK_PNMI_MAI_OFF(PortNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_DEVICE_TYPE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(DeviceType),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_DRIVER_DESCR,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(DriverDescr),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_DRIVER_VERSION,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(DriverVersion),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_HW_DESCR,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(HwDescr),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_HW_VERSION,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(HwVersion),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_CHIPSET,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(Chipset),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_ACTION,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(Action),
+		SK_PNMI_RW, Perform, 0},
+	{OID_SKGE_RESULT,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TestResult),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_BUS_TYPE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(BusType),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_BUS_SPEED,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(BusSpeed),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_BUS_WIDTH,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(BusWidth),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_SW_QUEUE_LEN,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxSwQueueLen),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_SW_QUEUE_MAX,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxSwQueueMax),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_RETRY,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxRetryCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_INTR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxIntrCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_INTR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxIntrCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_NO_BUF_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxNoBufCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_NO_BUF_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxNoBufCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_USED_DESCR_NO,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxUsedDescrNo),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_DELIVERED_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxDeliveredCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_OCTETS_DELIV_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxOctetsDeliveredCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_HW_ERROR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxHwErrorsCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_HW_ERROR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxHwErrorsCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_IN_ERRORS_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(InErrorsCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_OUT_ERROR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(OutErrorsCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_ERR_RECOVERY_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(ErrRecoveryCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_SYSUPTIME,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(SysUpTime),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_SENSOR_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(SensorNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_SENSOR_INDEX,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorIndex),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_DESCR,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorDescr),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_TYPE,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorType),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_VALUE,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorValue),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_WAR_THRES_LOW,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningThresholdLow),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_WAR_THRES_UPP,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningThresholdHigh),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_ERR_THRES_LOW,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorThresholdLow),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_ERR_THRES_UPP,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorThresholdHigh),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_STATUS,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorStatus),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_WAR_CTS,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningCts),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_ERR_CTS,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorCts),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_WAR_TIME,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningTimestamp),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_ERR_TIME,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorTimestamp),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_CHKSM_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(ChecksumNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_CHKSM_RX_OK_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxOkCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_CHKSM_RX_UNABLE_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxUnableCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_CHKSM_RX_ERR_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxErrCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_CHKSM_TX_OK_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumTxOkCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_CHKSM_TX_UNABLE_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumTxUnableCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_STAT_TX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX},
+	{OID_SKGE_STAT_TX_OCTETS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxOctetsOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_OCTET},
+	{OID_SKGE_STAT_TX_BROADCAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxBroadcastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_BROADCAST},
+	{OID_SKGE_STAT_TX_MULTICAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMulticastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MULTICAST},
+	{OID_SKGE_STAT_TX_UNICAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxUnicastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_UNICAST},
+	{OID_SKGE_STAT_TX_LONGFRAMES,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxLongFramesCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_LONGFRAMES},
+	{OID_SKGE_STAT_TX_BURST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxBurstCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_BURST},
+	{OID_SKGE_STAT_TX_PFLOWC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxPauseMacCtrlCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_PMACC},
+	{OID_SKGE_STAT_TX_FLOWC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMacCtrlCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MACC},
+	{OID_SKGE_STAT_TX_SINGLE_COL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSingleCollisionCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SINGLE_COL},
+	{OID_SKGE_STAT_TX_MULTI_COL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMultipleCollisionCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MULTI_COL},
+	{OID_SKGE_STAT_TX_EXCESS_COL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxExcessiveCollisionCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_EXCESS_COL},
+	{OID_SKGE_STAT_TX_LATE_COL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxLateCollisionCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_LATE_COL},
+	{OID_SKGE_STAT_TX_DEFFERAL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxDeferralCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_DEFFERAL},
+	{OID_SKGE_STAT_TX_EXCESS_DEF,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxExcessiveDeferralCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_EXCESS_DEF},
+	{OID_SKGE_STAT_TX_UNDERRUN,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxFifoUnderrunCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_UNDERRUN},
+	{OID_SKGE_STAT_TX_CARRIER,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxCarrierCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_CARRIER},
+/*	{OID_SKGE_STAT_TX_UTIL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxUtilization),
+		SK_PNMI_RO, MacPrivateStat, (SK_U16)(-1)}, */
+	{OID_SKGE_STAT_TX_64,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx64Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_64},
+	{OID_SKGE_STAT_TX_127,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx127Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_127},
+	{OID_SKGE_STAT_TX_255,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx255Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_255},
+	{OID_SKGE_STAT_TX_511,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx511Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_511},
+	{OID_SKGE_STAT_TX_1023,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx1023Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_1023},
+	{OID_SKGE_STAT_TX_MAX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMaxCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MAX},
+	{OID_SKGE_STAT_TX_SYNC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSyncCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SYNC},
+	{OID_SKGE_STAT_TX_SYNC_OCTETS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSyncOctetsCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SYNC_OCTET},
+	{OID_SKGE_STAT_RX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX},
+	{OID_SKGE_STAT_RX_OCTETS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxOctetsOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_OCTET},
+	{OID_SKGE_STAT_RX_BROADCAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxBroadcastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_BROADCAST},
+	{OID_SKGE_STAT_RX_MULTICAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMulticastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MULTICAST},
+	{OID_SKGE_STAT_RX_UNICAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUnicastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_UNICAST},
+	{OID_SKGE_STAT_RX_PFLOWC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxPauseMacCtrlCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_PMACC},
+	{OID_SKGE_STAT_RX_FLOWC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMacCtrlCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MACC},
+	{OID_SKGE_STAT_RX_PFLOWC_ERR,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxPauseMacCtrlErrorCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_PMACC_ERR},
+	{OID_SKGE_STAT_RX_FLOWC_UNKWN,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMacCtrlUnknownCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MACC_UNKWN},
+	{OID_SKGE_STAT_RX_BURST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxBurstCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_BURST},
+	{OID_SKGE_STAT_RX_MISSED,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMissedCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MISSED},
+	{OID_SKGE_STAT_RX_FRAMING,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFramingCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_FRAMING},
+	{OID_SKGE_STAT_RX_OVERFLOW,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFifoOverflowCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_OVERFLOW},
+	{OID_SKGE_STAT_RX_JABBER,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxJabberCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_JABBER},
+	{OID_SKGE_STAT_RX_CARRIER,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxCarrierCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_CARRIER},
+	{OID_SKGE_STAT_RX_IR_LENGTH,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxIRLengthCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_IRLENGTH},
+	{OID_SKGE_STAT_RX_SYMBOL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxSymbolCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_SYMBOL},
+	{OID_SKGE_STAT_RX_SHORTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxShortsCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_SHORTS},
+	{OID_SKGE_STAT_RX_RUNT,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxRuntCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_RUNT},
+	{OID_SKGE_STAT_RX_CEXT,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxCextCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_CEXT},
+	{OID_SKGE_STAT_RX_TOO_LONG,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxTooLongCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_TOO_LONG},
+	{OID_SKGE_STAT_RX_FCS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFcsCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_FCS},
+/*	{OID_SKGE_STAT_RX_UTIL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUtilization),
+		SK_PNMI_RO, MacPrivateStat, (SK_U16)(-1)}, */
+	{OID_SKGE_STAT_RX_64,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx64Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_64},
+	{OID_SKGE_STAT_RX_127,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx127Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_127},
+	{OID_SKGE_STAT_RX_255,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx255Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_255},
+	{OID_SKGE_STAT_RX_511,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx511Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_511},
+	{OID_SKGE_STAT_RX_1023,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx1023Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_1023},
+	{OID_SKGE_STAT_RX_MAX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMaxCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MAX},
+	{OID_SKGE_PHYS_CUR_ADDR,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfMacCurrentAddr),
+		SK_PNMI_RW, Addr, 0},
+	{OID_SKGE_PHYS_FAC_ADDR,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfMacFactoryAddr),
+		SK_PNMI_RO, Addr, 0},
+	{OID_SKGE_PMD,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPMD),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_CONNECTOR,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfConnector),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_LINK_CAP,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkCapability),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_LINK_MODE,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkMode),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_LINK_MODE_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkModeStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_LINK_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_FLOWCTRL_CAP,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlCapability),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_FLOWCTRL_MODE,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlMode),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_FLOWCTRL_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_PHY_OPERATION_CAP,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationCapability),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_PHY_OPERATION_MODE,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationMode),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_PHY_OPERATION_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_TRAP,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(Trap),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TRAP_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TrapNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RLMT_MODE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtMode),
+		SK_PNMI_RW, Rlmt, 0},
+	{OID_SKGE_RLMT_PORT_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtPortNumber),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_PORT_ACTIVE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtPortActive),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_PORT_PREFERED,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtPortPreferred),
+		SK_PNMI_RW, Rlmt, 0},
+	{OID_SKGE_RLMT_CHANGE_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtChangeCts),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_CHANGE_TIME,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtChangeTime),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_CHANGE_ESTIM,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtChangeEstimate),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_CHANGE_THRES,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtChangeThreshold),
+		SK_PNMI_RW, Rlmt, 0},
+	{OID_SKGE_RLMT_PORT_INDEX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtIndex),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtStatus),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_TX_HELLO_CTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtTxHelloCts),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_RX_HELLO_CTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtRxHelloCts),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_TX_SP_REQ_CTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtTxSpHelloReqCts),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_RX_SP_CTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtRxSpHelloCts),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_MONITOR_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtMonitorNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RLMT_MONITOR_INDEX,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorIndex),
+		SK_PNMI_RO, Monitor, 0},
+	{OID_SKGE_RLMT_MONITOR_ADDR,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorAddr),
+		SK_PNMI_RO, Monitor, 0},
+	{OID_SKGE_RLMT_MONITOR_ERRS,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorErrorCts),
+		SK_PNMI_RO, Monitor, 0},
+	{OID_SKGE_RLMT_MONITOR_TIMESTAMP,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorTimestamp),
+		SK_PNMI_RO, Monitor, 0},
+	{OID_SKGE_RLMT_MONITOR_ADMIN,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorAdmin),
+		SK_PNMI_RW, Monitor, 0},
+};
+
+/*
+ * Table for hardware register saving on resets and port switches
+*/
+static const SK_PNMI_STATADDR StatAddress[SK_PNMI_MAX_IDX] = {
+	/*  0 */	{TRUE, XM_TXF_OK},
+	/*  1 */	{TRUE, 0},
+	/*  2 */	{FALSE, 0},
+	/*  3 */	{TRUE, XM_TXF_BC_OK},
+	/*  4 */	{TRUE, XM_TXF_MC_OK},
+	/*  5 */	{TRUE, XM_TXF_UC_OK},
+	/*  6 */	{TRUE, XM_TXF_LONG},
+	/*  7 */	{TRUE, XM_TXE_BURST},
+	/*  8 */	{TRUE, XM_TXF_MPAUSE},
+	/*  9 */	{TRUE, XM_TXF_MCTRL},
+	/* 10 */	{TRUE, XM_TXF_SNG_COL},
+	/* 11 */	{TRUE, XM_TXF_MUL_COL},
+	/* 12 */	{TRUE, XM_TXF_ABO_COL},
+	/* 13 */	{TRUE, XM_TXF_LAT_COL},
+	/* 14 */	{TRUE, XM_TXF_DEF},
+	/* 15 */	{TRUE, XM_TXF_EX_DEF},
+	/* 16 */	{TRUE, XM_TXE_FIFO_UR},
+	/* 17 */	{TRUE, XM_TXE_CS_ERR},
+	/* 18 */	{FALSE, 0},
+	/* 19 */	{FALSE, 0},
+	/* 20 */	{TRUE, XM_TXF_64B},
+	/* 21 */	{TRUE, XM_TXF_127B},
+	/* 22 */	{TRUE, XM_TXF_255B},
+	/* 23 */	{TRUE, XM_TXF_511B},
+	/* 24 */	{TRUE, XM_TXF_1023B},
+	/* 25 */	{TRUE, XM_TXF_MAX_SZ},
+	/* 26 */	{FALSE, 0},
+	/* 27 */	{FALSE, 0},
+	/* 28 */	{FALSE, 0},
+	/* 29 */	{FALSE, 0},
+	/* 30 */	{FALSE, 0},
+	/* 31 */	{FALSE, 0},
+	/* 32 */	{TRUE, XM_RXF_OK},
+	/* 33 */	{TRUE, 0},
+	/* 34 */	{FALSE, 0},
+	/* 35 */	{TRUE, XM_RXF_BC_OK},
+	/* 36 */	{TRUE, XM_RXF_MC_OK},
+	/* 37 */	{TRUE, XM_RXF_UC_OK},
+	/* 38 */	{TRUE, XM_RXF_MPAUSE},
+	/* 39 */	{TRUE, XM_RXF_MCTRL},
+	/* 40 */	{TRUE, XM_RXF_INV_MP},
+	/* 41 */	{TRUE, XM_RXF_INV_MOC},
+	/* 42 */	{TRUE, XM_RXE_BURST},
+	/* 43 */	{TRUE, XM_RXE_FMISS},
+	/* 44 */	{TRUE, XM_RXF_FRA_ERR},
+	/* 45 */	{TRUE, XM_RXE_FIFO_OV},
+	/* 46 */	{TRUE, XM_RXF_JAB_PKT},
+	/* 47 */	{TRUE, XM_RXE_CAR_ERR},
+	/* 48 */	{TRUE, XM_RXF_LEN_ERR},
+	/* 49 */	{TRUE, XM_RXE_SYM_ERR},
+	/* 50 */	{TRUE, XM_RXE_SHT_ERR},
+	/* 51 */	{TRUE, XM_RXE_RUNT},
+	/* 52 */	{TRUE, XM_RXF_LNG_ERR},
+	/* 53 */	{TRUE, XM_RXF_FCS_ERR},
+	/* 54 */	{FALSE, 0},
+	/* 55 */	{TRUE, XM_RXF_CEX_ERR},
+	/* 56 */	{FALSE, 0},
+	/* 57 */	{FALSE, 0},
+	/* 58 */	{TRUE, XM_RXF_64B},
+	/* 59 */	{TRUE, XM_RXF_127B},
+	/* 60 */	{TRUE, XM_RXF_255B},
+	/* 61 */	{TRUE, XM_RXF_511B},
+	/* 62 */	{TRUE, XM_RXF_1023B},
+	/* 63 */	{TRUE, XM_RXF_MAX_SZ},
+	/* 64 */	{FALSE, 0},
+	/* 65 */	{FALSE, 0}
+};
+
+
+/*****************************************************************************
+ *
+ * Public functions
+ *
+ */
+
+/*****************************************************************************
+ *
+ * SkPnmiInit - Init function of PNMI
+ *
+ * Description:
+ *	SK_INIT_DATA: Initialises the data structures
+ *	SK_INIT_IO:   Resets the XMAC statistics, determines the device and
+ *	              connector type.
+ *	SK_INIT_RUN:  Starts a timer event for port switch per hour
+ *	              calculation.
+ *
+ * Returns:
+ *	Always 0
+ */
+
+int SkPnmiInit(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Level)		/* Initialization level */
+{
+	unsigned int	PortMax;	/* Number of ports */
+	unsigned int	PortIndex;	/* Current port index in loop */
+	SK_U16		Val16;		/* Multiple purpose 16 bit variable */
+	SK_U8		Val8;		/* Mulitple purpose 8 bit variable */
+	SK_EVPARA	EventParam;	/* Event struct for timer event */
+
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiInit: Called, level=%d\n", Level));
+
+	switch (Level) {
+
+	case SK_INIT_DATA:
+		SK_MEMSET((char *)&pAC->Pnmi, 0, sizeof(pAC->Pnmi));
+		pAC->Pnmi.TrapBufFree = SK_PNMI_TRAP_QUEUE_LEN;
+		pAC->Pnmi.StartUpTime = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+		pAC->Pnmi.RlmtChangeThreshold = SK_PNMI_DEF_RLMT_CHG_THRES;
+		for (PortIndex = 0; PortIndex < SK_MAX_MACS; PortIndex ++) {
+
+			pAC->Pnmi.Port[PortIndex].ActiveFlag = SK_FALSE;
+		}
+		break;
+
+	case SK_INIT_IO:
+		/*
+		 * Reset MAC counters
+		 */
+		PortMax = pAC->GIni.GIMacsFound;
+
+		for (PortIndex = 0; PortIndex < PortMax; PortIndex ++) {
+
+			Val16 = XM_SC_CLR_RXC | XM_SC_CLR_TXC;
+			XM_OUT16(IoC, PortIndex, XM_STAT_CMD, Val16);
+			/* Clear two times according to Errata #3 */
+			XM_OUT16(IoC, PortIndex, XM_STAT_CMD, Val16);
+		}
+
+		/*
+		 * Get pci bus speed
+		 */
+		SK_IN16(IoC, B0_CTST, &Val16);
+		if ((Val16 & CS_BUS_CLOCK) == 0) {
+
+			pAC->Pnmi.PciBusSpeed = 33;
+		}
+		else {
+			pAC->Pnmi.PciBusSpeed = 66;
+		}
+
+		/*
+		 * Get pci bus width
+		 */
+		SK_IN16(IoC, B0_CTST, &Val16);
+		if ((Val16 & CS_BUS_SLOT_SZ) == 0) {
+
+			pAC->Pnmi.PciBusWidth = 32;
+		}
+		else {
+			pAC->Pnmi.PciBusWidth = 64;
+		}
+
+		/*
+		 * Get PMD and DeviceType
+		 */
+		SK_IN8(IoC, B2_PMD_TYP, &Val8);
+		switch (Val8) {
+		case 'S':
+			pAC->Pnmi.PMD = 3;
+			if (pAC->GIni.GIMacsFound > 1) {
+
+				pAC->Pnmi.DeviceType = 0x00020002;
+			}
+			else {
+				pAC->Pnmi.DeviceType = 0x00020001;
+			}
+			break;
+
+		case 'L':
+			pAC->Pnmi.PMD = 2;
+			if (pAC->GIni.GIMacsFound > 1) {
+
+				pAC->Pnmi.DeviceType = 0x00020004;
+			}
+			else {
+				pAC->Pnmi.DeviceType = 0x00020003;
+			}
+			break;
+
+		case 'C':
+			pAC->Pnmi.PMD = 4;
+			if (pAC->GIni.GIMacsFound > 1) {
+
+				pAC->Pnmi.DeviceType = 0x00020006;
+			}
+			else {
+				pAC->Pnmi.DeviceType = 0x00020005;
+			}
+			break;
+
+		case 'T':
+			pAC->Pnmi.PMD = 5;
+			if (pAC->GIni.GIMacsFound > 1) {
+
+				pAC->Pnmi.DeviceType = 0x00020008;
+			}
+			else {
+				pAC->Pnmi.DeviceType = 0x00020007;
+			}
+			break;
+
+		default :
+			pAC->Pnmi.PMD = 1;
+			pAC->Pnmi.DeviceType = 0;
+			break;
+		}
+
+		/*
+		 * Get connector
+		 */
+		SK_IN8(IoC, B2_CONN_TYP, &Val8);
+		switch (Val8) {
+		case 'C':
+			pAC->Pnmi.Connector = 2;
+			break;
+
+		case 'D':
+			pAC->Pnmi.Connector = 3;
+			break;
+
+		case 'F':
+			pAC->Pnmi.Connector = 4;
+			break;
+
+		case 'J':
+			pAC->Pnmi.Connector = 5;
+			break;
+
+		default:
+			pAC->Pnmi.Connector = 1;
+			break;
+		}
+		break;
+
+	case SK_INIT_RUN:
+		/*
+		 * Start timer for RLMT change counter
+		 */
+		SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+		SkTimerStart(pAC, IoC, &pAC->Pnmi.RlmtChangeEstimate.EstTimer,
+			28125000, SKGE_PNMI, SK_PNMI_EVT_CHG_EST_TIMER,
+			EventParam);
+		break;
+
+	default:
+		break; /* Nothing todo */
+	}
+
+	return (0);
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiGetVar - Retrieves the value of a single OID
+ *
+ * Description:
+ *	Calls a general sub-function for all this stuff. If the instance
+ *	-1 is passed, the values of all instances are returned in an
+ *	array of values.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
+ *	                         the data.
+ *	SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+int SkPnmiGetVar(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 Id,		/* Object ID that is to be processed */
+void *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance)	/* Instance (1..n) that is to be queried or -1 */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiGetVar: Called, Id=0x%x, BufLen=%d\n", Id,
+		*pLen));
+
+	return (PnmiVar(pAC, IoC, SK_PNMI_GET, Id, (char *)pBuf, pLen,
+		Instance));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiPreSetVar - Presets the value of a single OID
+ *
+ * Description:
+ *	Calls a general sub-function for all this stuff. The preset does
+ *	the same as a set, but returns just before finally setting the
+ *	new value. This is usefull to check if a set might be successfull.
+ *	If as instance a -1 is passed, an array of values is supposed and
+ *	all instance of the OID will be set.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+int SkPnmiPreSetVar(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 Id,		/* Object ID that is to be processed */
+void *pBuf,		/* Buffer which stores the mgmt data to be set */
+unsigned int *pLen,	/* Total length of mgmt data */
+SK_U32 Instance)	/* Instance (1..n) that is to be set or -1 */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiPreSetVar: Called, Id=0x%x, BufLen=%d\n",
+		Id, *pLen));
+
+	return (PnmiVar(pAC, IoC, SK_PNMI_PRESET, Id, (char *)pBuf, pLen,
+		Instance));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiSetVar - Sets the value of a single OID
+ *
+ * Description:
+ *	Calls a general sub-function for all this stuff. The preset does
+ *	the same as a set, but returns just before finally setting the
+ *	new value. This is usefull to check if a set might be successfull.
+ *	If as instance a -1 is passed, an array of values is supposed and
+ *	all instance of the OID will be set.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+int SkPnmiSetVar(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 Id,		/* Object ID that is to be processed */
+void *pBuf,		/* Buffer which stores the mgmt data to be set */
+unsigned int *pLen,	/* Total length of mgmt data */
+SK_U32 Instance)	/* Instance (1..n) that is to be set or -1 */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiSetVar: Called, Id=0x%x, BufLen=%d\n", Id,
+		*pLen));
+
+	return (PnmiVar(pAC, IoC, SK_PNMI_SET, Id, (char *)pBuf, pLen,
+		Instance));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiGetStruct - Retrieves the management database in SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ *	Runs through the IdTable, queries the single OIDs and stores the
+ *	returned data into the management database structure
+ *	SK_PNMI_STRUCT_DATA. The offset of the OID in the structure
+ *	is stored in the IdTable. The return value of the function will also
+ *	be stored in SK_PNMI_STRUCT_DATA if the passed buffer has the
+ *	minimum size of SK_PNMI_MIN_STRUCT_SIZE.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
+ *	                         the data.
+ */
+
+int SkPnmiGetStruct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+void *pBuf,		/* Buffer which will store the retrieved data */
+unsigned int *pLen)	/* Length of buffer */
+{
+	int		Ret;
+	unsigned int	TableIndex;
+	unsigned int	DstOffset;
+	unsigned int	InstanceNo;
+	unsigned int	InstanceCnt;
+	SK_U32		Instance;
+	unsigned int	TmpLen;
+	char		KeyArr[SK_PNMI_VPD_ARR_SIZE][SK_PNMI_VPD_STR_SIZE];
+
+	
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiGetStruct: Called, BufLen=%d\n", *pLen));
+
+	if (*pLen < SK_PNMI_STRUCT_SIZE) {
+
+		if (*pLen >= SK_PNMI_MIN_STRUCT_SIZE) {
+
+			SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_TOO_SHORT,
+				(SK_U32)(-1));
+		}
+
+		*pLen = SK_PNMI_STRUCT_SIZE;
+		return (SK_PNMI_ERR_TOO_SHORT);
+	}
+
+	/* Update statistic */
+	SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On call");
+
+	if ((Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1)) !=
+		SK_PNMI_ERR_OK) {
+
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (Ret);
+	}
+
+	if ((Ret = RlmtUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (Ret);
+	}
+
+	if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (Ret);
+	}
+
+	/*
+	 * Increment semaphores to indicate that an update was
+	 * already done
+	 */
+	pAC->Pnmi.MacUpdatedFlag ++;
+	pAC->Pnmi.RlmtUpdatedFlag ++;
+	pAC->Pnmi.SirqUpdatedFlag ++;
+
+	/* Get vpd keys for instance calculation */
+	Ret = GetVpdKeyArr(pAC, IoC, &KeyArr[0][0], sizeof(KeyArr), &TmpLen);
+	if (Ret != SK_PNMI_ERR_OK) {
+
+		pAC->Pnmi.MacUpdatedFlag --;
+		pAC->Pnmi.RlmtUpdatedFlag --;
+		pAC->Pnmi.SirqUpdatedFlag --;
+
+		SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	/* Retrieve values */
+	SK_MEMSET((char *)pBuf, 0, SK_PNMI_STRUCT_SIZE);
+	for (TableIndex = 0; TableIndex < sizeof(IdTable)/sizeof(IdTable[0]);
+		TableIndex ++) {
+
+		InstanceNo = IdTable[TableIndex].InstanceNo;
+
+		for (InstanceCnt = 1; InstanceCnt <= InstanceNo;
+			InstanceCnt ++) {
+
+			DstOffset = IdTable[TableIndex].Offset +
+				(InstanceCnt - 1) *
+				IdTable[TableIndex].StructSize;
+
+			/*
+			 * For the VPD the instance is not an index number
+			 * but the key itself. Determin with the instance
+			 * counter the VPD key to be used.
+			 */
+			if (IdTable[TableIndex].Id == OID_SKGE_VPD_KEY ||
+				IdTable[TableIndex].Id == OID_SKGE_VPD_VALUE ||
+				IdTable[TableIndex].Id == OID_SKGE_VPD_ACCESS ||
+				IdTable[TableIndex].Id == OID_SKGE_VPD_ACTION) {
+
+				SK_PNMI_READ_U32(KeyArr[InstanceCnt - 1],
+					Instance);
+			}
+			else {
+				Instance = (SK_U32)InstanceCnt;
+			}
+
+			TmpLen = *pLen - DstOffset;
+			Ret = IdTable[TableIndex].Func(pAC, IoC, SK_PNMI_GET,
+				IdTable[TableIndex].Id, (char *)pBuf +
+				DstOffset, &TmpLen, Instance, TableIndex);
+
+			/*
+			 * An unknown instance error means that we reached
+			 * the last instance of that variable. Proceed with
+			 * the next OID in the table and ignore the return
+			 * code.
+			 */
+			if (Ret == SK_PNMI_ERR_UNKNOWN_INST) {
+
+				break;
+			}
+
+			if (Ret != SK_PNMI_ERR_OK) {
+
+				pAC->Pnmi.MacUpdatedFlag --;
+				pAC->Pnmi.RlmtUpdatedFlag --;
+				pAC->Pnmi.SirqUpdatedFlag --;
+
+				SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
+				SK_PNMI_SET_STAT(pBuf, Ret, DstOffset);
+				*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+				return (Ret);
+			}
+		}
+	}
+
+	pAC->Pnmi.MacUpdatedFlag --;
+	pAC->Pnmi.RlmtUpdatedFlag --;
+	pAC->Pnmi.SirqUpdatedFlag --;
+
+	*pLen = SK_PNMI_STRUCT_SIZE;
+	SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
+	SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_OK, (SK_U32)(-1));
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiPreSetStruct - Presets the management database in SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ *	Calls a general sub-function for all this set stuff. The preset does
+ *	the same as a set, but returns just before finally setting the
+ *	new value. This is usefull to check if a set might be successfull.
+ *	The sub-function runs through the IdTable, checks which OIDs are able
+ *	to set, and calls the handler function of the OID to perform the
+ *	preset. The return value of the function will also be stored in
+ *	SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
+ *	SK_PNMI_MIN_STRUCT_SIZE.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ */
+
+int SkPnmiPreSetStruct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+void *pBuf,		/* Buffer which contains the data to be set */
+unsigned int *pLen)	/* Length of buffer */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiPreSetStruct: Called, BufLen=%d\n", *pLen));
+
+	return (PnmiStruct(pAC, IoC, SK_PNMI_PRESET, (char *)pBuf, pLen));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiSetStruct - Sets the management database in SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ *	Calls a general sub-function for all this set stuff. The return value
+ *	of the function will also be stored in SK_PNMI_STRUCT_DATA if the
+ *	passed buffer has the minimum size of SK_PNMI_MIN_STRUCT_SIZE.
+ *	The sub-function runs through the IdTable, checks which OIDs are able
+ *	to set, and calls the handler function of the OID to perform the
+ *	set. The return value of the function will also be stored in
+ *	SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
+ *	SK_PNMI_MIN_STRUCT_SIZE.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ */
+
+int SkPnmiSetStruct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+void *pBuf,		/* Buffer which contains the data to be set */
+unsigned int *pLen)	/* Length of buffer */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiSetStruct: Called, BufLen=%d\n", *pLen));
+
+	return (PnmiStruct(pAC, IoC, SK_PNMI_SET, (char *)pBuf, pLen));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiEvent - Event handler
+ *
+ * Description:
+ *	Handles the following events:
+ *	SK_PNMI_EVT_SIRQ_OVERFLOW     When a hardware counter overflows an
+ *	                              interrupt will be generated which is
+ *	                              first handled by SIRQ which generates a
+ *	                              this event. The event increments the
+ *	                              upper 32 bit of the 64 bit counter.
+ *	SK_PNMI_EVT_SEN_XXX           The event is generated by the I2C module
+ *	                              when a sensor reports a warning or
+ *	                              error. The event will store a trap
+ *	                              message in the trap buffer.
+ *	SK_PNMI_EVT_CHG_EST_TIMER     The timer event was initiated by this
+ *	                              module and is used to calculate the
+ *	                              port switches per hour.
+ *	SK_PNMI_EVT_CLEAR_COUNTER     The event clears all counters and
+ *	                              timestamps.
+ *	SK_PNMI_EVT_XMAC_RESET        The event is generated by the driver
+ *	                              before a hard reset of the XMAC is
+ *	                              performed. All counters will be saved
+ *	                              and added to the hardware counter
+ *	                              values after reset to grant continuous
+ *	                              counter values.
+ *	SK_PNMI_EVT_RLMT_PORT_UP      Generated by RLMT to notify that a port
+ *	                              went logically up. A trap message will
+ *	                              be stored to the trap buffer.
+ *	SK_PNMI_EVT_RLMT_PORT_DOWN    Generated by RLMT to notify that a port
+ *	                              went logically down. A trap message will
+ *	                              be stored to the trap buffer.
+ *	SK_PNMI_EVT_RLMT_PORT_SWITCH  Generated by RLMT to notify that the
+ *	                              active port switched. PNMI will split
+ *	                              this into two message ACTIVE_DOWN and
+ *	                              ACTIVE_UP to be future compatible with
+ *	                              load balancing and card fail over.
+ *	SK_PNMI_EVT_RLMT_SEGMENTATION Generated by RLMT to notify that two
+ *	                              spanning tree root bridges were
+ *	                              detected. A trap message will be stored
+ *	                              to the trap buffer.
+ *	SK_PNMI_EVT_RLMT_ACTIVE_DOWN  Notifies PNMI that an active port went
+ *	                              down. PNMI will not further add the
+ *	                              statistic values to the virtual port.
+ *	SK_PNMI_EVT_RLMT_ACTIVE_UP    Notifies PNMI that a port went up and
+ *	                              is now an active port. PNMI will now
+ *	                              add the statistic data of this port to
+ *	                              the virtual port.
+ *
+ * Returns:
+ *	Always 0
+ */
+
+int SkPnmiEvent(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 Event,		/* Event-Id */
+SK_EVPARA Param)	/* Event dependent parameter */
+{
+	unsigned int	PhysPortIndex;
+	int		CounterIndex;
+	int		Ret;
+	SK_U16		MacStatus;
+	SK_U64		OverflowStatus;
+	SK_U64		Mask;
+	SK_U32		MacCntEvent;
+	SK_U64		Value;
+	SK_U16		Register;
+	SK_EVPARA	EventParam;
+	SK_U64		NewestValue;
+	SK_U64		OldestValue;
+	SK_U64		Delta;
+	SK_PNMI_ESTIMATE *pEst;
+
+
+#ifdef DEBUG
+	if (Event != SK_PNMI_EVT_XMAC_RESET) {
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+			("PNMI: SkPnmiEvent: Called, Event=0x%x, Param=0x%x\n",
+			(unsigned long)Event, (unsigned long)Param.Para64));
+	}
+#endif
+	SK_PNMI_CHECKFLAGS("SkPnmiEvent: On call");
+
+	switch (Event) {
+
+	case SK_PNMI_EVT_SIRQ_OVERFLOW:
+		PhysPortIndex = (int)Param.Para32[0];
+		MacStatus = (SK_U16)Param.Para32[1];
+#ifdef DEBUG
+		if (PhysPortIndex >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SIRQ_OVERFLOW parameter wrong, PhysPortIndex=0x%x\n",
+				PhysPortIndex));
+			return (0);
+		}
+#endif
+		OverflowStatus = 0;
+
+		/*
+		 * Check which source caused an overflow interrupt. The
+		 * interrupt source is a self-clearing register. We only
+		 * need to check the interrupt source once. Another check
+		 * will be done by the SIRQ module to be sure that no
+		 * interrupt get lost during process time.
+		 */
+		if ((MacStatus & XM_IS_RXC_OV) == XM_IS_RXC_OV) {
+
+			XM_IN32(IoC, PhysPortIndex, XM_RX_CNT_EV,
+				&MacCntEvent);
+			OverflowStatus |= (SK_U64)MacCntEvent << 32;
+		}
+		if ((MacStatus & XM_IS_TXC_OV) == XM_IS_TXC_OV) {
+
+			XM_IN32(IoC, PhysPortIndex, XM_TX_CNT_EV,
+				&MacCntEvent);
+			OverflowStatus |= (SK_U64)MacCntEvent;
+		}
+		if (OverflowStatus == 0) {
+
+			SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+			return (0);
+		}
+
+		/*
+		 * Check the overflow status register and increment
+		 * the upper dword of corresponding counter.
+		 */
+		for (CounterIndex = 0; CounterIndex < sizeof(Mask) * 8;
+			CounterIndex ++) {
+
+			Mask = (SK_U64)1 << CounterIndex;
+			if ((OverflowStatus & Mask) == 0) {
+
+				continue;
+			}
+
+			switch (CounterIndex) {
+
+			case SK_PNMI_HTX_UTILUNDER:
+			case SK_PNMI_HTX_UTILOVER:
+				XM_IN16(IoC, PhysPortIndex, XM_TX_CMD,
+					&Register);
+				Register |= XM_TX_SAM_LINE;
+				XM_OUT16(IoC, PhysPortIndex, XM_TX_CMD,
+					Register);
+				break;
+
+			case SK_PNMI_HRX_UTILUNDER:
+			case SK_PNMI_HRX_UTILOVER:
+				XM_IN16(IoC, PhysPortIndex, XM_RX_CMD,
+					&Register);
+				Register |= XM_RX_SAM_LINE;
+				XM_OUT16(IoC, PhysPortIndex, XM_RX_CMD,
+					Register);
+				break;
+
+			case SK_PNMI_HTX_OCTETHIGH:
+			case SK_PNMI_HTX_OCTETLOW:
+			case SK_PNMI_HTX_RESERVED26:
+			case SK_PNMI_HTX_RESERVED27:
+			case SK_PNMI_HTX_RESERVED28:
+			case SK_PNMI_HTX_RESERVED29:
+			case SK_PNMI_HTX_RESERVED30:
+			case SK_PNMI_HTX_RESERVED31:
+			case SK_PNMI_HRX_OCTETHIGH:
+			case SK_PNMI_HRX_OCTETLOW:
+			case SK_PNMI_HRX_IRLENGTH:
+			case SK_PNMI_HRX_RESERVED22:
+			case SK_PNMI_HTX_SYNC:
+			case SK_PNMI_HTX_SYNC_OCTET:
+				break;
+
+			default:
+				pAC->Pnmi.Port[PhysPortIndex].
+					CounterHigh[CounterIndex] ++;
+			}
+		}
+		break;
+
+	case SK_PNMI_EVT_SEN_WAR_LOW:
+#ifdef DEBUG
+		if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_WAR_LOW parameter wrong, SensorIndex=%d\n",
+				(unsigned int)Param.Para64));
+			return (0);
+		}
+#endif
+		/*
+		 * Store a trap message in the trap buffer and generate
+		 * an event for user space applications with the
+		 * SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_WAR_LOW,
+			(unsigned int)Param.Para64);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+
+	case SK_PNMI_EVT_SEN_WAR_UPP:
+#ifdef DEBUG
+		if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR:SkPnmiEvent: SK_PNMI_EVT_SEN_WAR_UPP parameter wrong, SensorIndex=%d\n",
+				(unsigned int)Param.Para64));
+			return (0);
+		}
+#endif
+		/*
+		 * Store a trap message in the trap buffer and generate
+		 * an event for user space applications with the
+		 * SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_WAR_UPP,
+			(unsigned int)Param.Para64);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+
+	case SK_PNMI_EVT_SEN_ERR_LOW:
+#ifdef DEBUG
+		if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_ERR_LOW parameter wrong, SensorIndex=%d\n",
+				(unsigned int)Param.Para64));
+			return (0);
+		}
+#endif
+		/*
+		 * Store a trap message in the trap buffer and generate
+		 * an event for user space applications with the
+		 * SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_ERR_LOW,
+			(unsigned int)Param.Para64);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+	
+	case SK_PNMI_EVT_SEN_ERR_UPP:
+#ifdef DEBUG
+		if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_ERR_UPP parameter wrong, SensorIndex=%d\n",
+				(unsigned int)Param.Para64));
+			return (0);
+		}
+#endif
+		/*
+		 * Store a trap message in the trap buffer and generate
+		 * an event for user space applications with the
+		 * SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_ERR_UPP,
+			(unsigned int)Param.Para64);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+
+	case SK_PNMI_EVT_CHG_EST_TIMER:
+		/*
+		 * Calculate port switch average on a per hour basis
+		 *   Time interval for check       : 28125 ms
+		 *   Number of values for average  : 8
+		 *
+		 * Be careful in changing these values, on change check
+		 *   - typedef of SK_PNMI_ESTIMATE (Size of EstValue
+		 *     array one less than value number)
+		 *   - Timer initilization SkTimerStart() in SkPnmiInit
+		 *   - Delta value below must be multiplicated with
+		 *     power of 2
+		 *
+		 */
+		pEst = &pAC->Pnmi.RlmtChangeEstimate;
+		CounterIndex = pEst->EstValueIndex + 1;
+		if (CounterIndex == 7) {
+
+			CounterIndex = 0;
+		}
+		pEst->EstValueIndex = CounterIndex;
+
+		NewestValue = pAC->Pnmi.RlmtChangeCts;
+		OldestValue = pEst->EstValue[CounterIndex];
+		pEst->EstValue[CounterIndex] = NewestValue;
+
+		/*
+		 * Calculate average. Delta stores the number of
+		 * port switches per 28125 * 8 = 225000 ms
+		 */
+		if (NewestValue >= OldestValue) {
+
+			Delta = NewestValue - OldestValue;
+		}
+		else {
+			/* Overflow situation */
+			Delta = (SK_U64)(0 - OldestValue) + NewestValue;
+		}
+
+		/*
+		 * Extrapolate delta to port switches per hour.
+		 *     Estimate = Delta * (3600000 / 225000)
+		 *              = Delta * 16
+		 *              = Delta << 4
+		 */
+		pAC->Pnmi.RlmtChangeEstimate.Estimate = Delta << 4;
+
+		/*
+		 * Check if threshold is exceeded. If the threshold is
+		 * permanently exceeded every 28125 ms an event will be
+		 * generated to remind the user of this condition.
+		 */
+		if ((pAC->Pnmi.RlmtChangeThreshold != 0) &&
+			(pAC->Pnmi.RlmtChangeEstimate.Estimate >=
+			pAC->Pnmi.RlmtChangeThreshold)) {
+
+			QueueSimpleTrap(pAC, OID_SKGE_TRAP_RLMT_CHANGE_THRES);
+			(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		}
+
+		SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+		SkTimerStart(pAC, IoC, &pAC->Pnmi.RlmtChangeEstimate.EstTimer,
+			28125000, SKGE_PNMI, SK_PNMI_EVT_CHG_EST_TIMER,
+			EventParam);
+		break;
+
+	case SK_PNMI_EVT_CLEAR_COUNTER:
+		/*
+		 * Set all counters and timestamps to zero
+		 */
+		ResetCounter(pAC, IoC);
+		break;
+
+	case SK_PNMI_EVT_XMAC_RESET:
+		/*
+		 * To grant continuous counter values store the current
+		 * XMAC statistic values to the entries 1..n of the
+		 * CounterOffset array. XMAC Errata #2 
+		 */
+#ifdef DEBUG
+		if ((unsigned int)Param.Para64 >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_XMAC_RESET parameter wrong, PhysPortIndex=%d\n",
+				(unsigned int)Param.Para64));
+			return (0);
+		}
+#endif
+		PhysPortIndex = (unsigned int)Param.Para64;
+
+		/*
+		 * Update XMAC statistic to get fresh values
+		 */
+		Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+		if (Ret != SK_PNMI_ERR_OK) {
+
+			SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+			return (0);
+		}
+		/*
+		 * Increment semaphore to indicate that an update was
+		 * already done
+		 */
+		pAC->Pnmi.MacUpdatedFlag ++;
+
+		for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
+			CounterIndex ++) {
+
+			if (!StatAddress[CounterIndex].GetOffset) {
+
+				continue;
+			}
+
+			pAC->Pnmi.Port[PhysPortIndex].
+				CounterOffset[CounterIndex] = GetPhysStatVal(
+				pAC, IoC, PhysPortIndex, CounterIndex);
+			pAC->Pnmi.Port[PhysPortIndex].
+				CounterHigh[CounterIndex] = 0;
+		}
+
+		pAC->Pnmi.MacUpdatedFlag --;
+		break;
+
+	case SK_PNMI_EVT_RLMT_PORT_UP:
+#ifdef DEBUG
+		if ((unsigned int)Param.Para32[0] >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_UP parameter wrong, PhysPortIndex=%d\n",
+				(unsigned int)Param.Para32[0]));
+
+			return (0);
+		}
+#endif
+		/*
+		 * Store a trap message in the trap buffer and generate
+		 * an event for user space applications with the
+		 * SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_UP,
+			(unsigned int)Param.Para32[0]);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+
+	case SK_PNMI_EVT_RLMT_PORT_DOWN:
+#ifdef DEBUG
+		if ((unsigned int)Param.Para32[0] >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_DOWN parameter wrong, PhysPortIndex=%d\n",
+				(unsigned int)Param.Para32[0]));
+
+			return (0);
+		}
+#endif
+		/*
+		 * Store a trap message in the trap buffer and generate
+		 * an event for user space applications with the
+		 * SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_DOWN,
+			(unsigned int)Param.Para32[0]);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+
+	case SK_PNMI_EVT_RLMT_ACTIVE_DOWN:
+		PhysPortIndex = (unsigned int)Param.Para32[0];
+#ifdef DEBUG
+		if (PhysPortIndex >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, PhysPort=%d\n",
+				PhysPortIndex));
+		}
+#endif
+		/*
+		 * Nothing to do if port is already inactive
+		 */
+		if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+			return (0);
+		}
+
+		/*
+		 * Update statistic counters to calculate new offset
+		 * for the virtual port and increment semaphore to
+		 * indicate that an update was already done.
+		 */
+		if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) !=
+			SK_PNMI_ERR_OK) {
+
+			SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+			return (0);
+		}
+		pAC->Pnmi.MacUpdatedFlag ++;
+
+		/*
+		 * Calculate new counter offset for virtual port to
+		 * grant continous counting on port switches. The virtual
+		 * port consists of all currently active ports. The port
+		 * down event indicates that a port is removed fromt the
+		 * virtual port. Therefore add the counter value of the
+		 * removed port to the CounterOffset for the virtual port
+		 * to grant the same counter value.
+		 */
+		for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
+			CounterIndex ++) {
+
+			if (!StatAddress[CounterIndex].GetOffset) {
+
+				continue;
+			}
+
+			Value = GetPhysStatVal(pAC, IoC, PhysPortIndex,
+				CounterIndex);
+
+			pAC->Pnmi.VirtualCounterOffset[CounterIndex] += Value;
+		}
+
+		/*
+		 * Set port to inactive
+		 */
+		pAC->Pnmi.Port[PhysPortIndex].ActiveFlag = SK_FALSE;
+
+		pAC->Pnmi.MacUpdatedFlag --;
+		break;
+
+	case SK_PNMI_EVT_RLMT_ACTIVE_UP:
+		PhysPortIndex = (unsigned int)Param.Para32[0];
+#ifdef DEBUG
+		if (PhysPortIndex >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, PhysPort=%d\n",
+				PhysPortIndex));
+		}
+#endif
+		/*
+		 * Nothing to do if port is already active
+		 */
+		if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+			return (0);
+		}
+
+		/*
+		 * Statistic maintanence
+		 */
+		pAC->Pnmi.RlmtChangeCts ++;
+		pAC->Pnmi.RlmtChangeTime =
+			SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+
+		/*
+		 * Store a trap message in the trap buffer and generate
+		 * an event for user space applications with the
+		 * SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueRlmtNewMacTrap(pAC, PhysPortIndex);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+
+		/*
+		 * Update statistic counters to calculate new offset
+		 * for the virtual port and increment semaphore to indicate
+		 * that an update was already done.
+		 */
+		if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) !=
+			SK_PNMI_ERR_OK) {
+
+			SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+			return (0);
+		}
+		pAC->Pnmi.MacUpdatedFlag ++;
+
+		/*
+		 * Calculate new counter offset for virtual port to
+		 * grant continous counting on port switches. A new port
+		 * is added to the virtual port. Therefore substract the
+		 * counter value of the new port from the CounterOffset
+		 * for the virtual port to grant the same value.
+		 */
+		for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
+			CounterIndex ++) {
+
+			if (!StatAddress[CounterIndex].GetOffset) {
+
+				continue;
+			}
+
+			Value = GetPhysStatVal(pAC, IoC, PhysPortIndex,
+				CounterIndex);
+
+			pAC->Pnmi.VirtualCounterOffset[CounterIndex] -= Value;
+		}
+
+		/*
+		 * Set port to active
+		 */
+		pAC->Pnmi.Port[PhysPortIndex].ActiveFlag = SK_TRUE;
+
+		pAC->Pnmi.MacUpdatedFlag --;
+		break;
+
+	case SK_PNMI_EVT_RLMT_PORT_SWITCH:
+		/*
+		 * This event becomes obsolete if RLMT generates directly
+		 * the events SK_PNMI_EVT_RLMT_ACTIVE_DOWN and
+		 * SK_PNMI_EVT_RLMT_ACTIVE_UP. The events are here emulated.
+		 * PNMI handles that multiple ports may become active. 
+		 * Increment semaphore to indicate that an update was
+		 * already done.
+		 */
+		if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) !=
+			SK_PNMI_ERR_OK) {
+
+			SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+			return (0);
+		}
+		pAC->Pnmi.MacUpdatedFlag ++;
+
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Param);
+		Param.Para32[0] = Param.Para32[1];
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_RLMT_ACTIVE_UP, Param);
+
+		pAC->Pnmi.MacUpdatedFlag --;
+		break;
+
+	case SK_PNMI_EVT_RLMT_SEGMENTATION:
+		/*
+		 * Store a trap message in the trap buffer and generate
+		 * an event for user space applications with the
+		 * SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueSimpleTrap(pAC, OID_SKGE_TRAP_RLMT_SEGMENTATION);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+
+	default:
+		break;
+	}
+
+	SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+	return (0);
+}
+
+
+/******************************************************************************
+ *
+ * Private functions
+ *
+ */
+
+/*****************************************************************************
+ *
+ * PnmiVar - Gets, presets, and sets single OIDs
+ *
+ * Description:
+ *	Looks up the requested OID, calls the corresponding handler
+ *	function, and passes the parameters with the get, preset, or
+ *	set command. The function is called by SkGePnmiGetVar,
+ *	SkGePnmiPreSetVar, or SkGePnmiSetVar.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_XXX. For details have a look to the description of the
+ *	calling functions.
+ */
+
+static int PnmiVar(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer which stores the mgmt data to be set */
+unsigned int *pLen,	/* Total length of mgmt data */
+SK_U32 Instance)	/* Instance (1..n) that is to be set or -1 */
+{
+	unsigned int	TableIndex;
+	int		Ret;
+
+
+	if ((TableIndex = LookupId(Id)) == (unsigned int)(-1)) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_OID);
+	}
+
+	SK_PNMI_CHECKFLAGS("PnmiVar: On call");
+
+	Ret = IdTable[TableIndex].Func(pAC, IoC, Action, Id, pBuf, pLen,
+		Instance, TableIndex);
+
+	SK_PNMI_CHECKFLAGS("PnmiVar: On return");
+
+	return (Ret);
+}
+
+/*****************************************************************************
+ *
+ * PnmiStruct - Presets and Sets data in structure SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ *	The return value of the function will also be stored in
+ *	SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
+ *	SK_PNMI_MIN_STRUCT_SIZE. The sub-function runs through the IdTable,
+ *	checks which OIDs are able to set, and calls the handler function of
+ *	the OID to perform the set. The return value of the function will
+ *	also be stored in SK_PNMI_STRUCT_DATA if the passed buffer has the
+ *	minimum size of SK_PNMI_MIN_STRUCT_SIZE. The function is called
+ *	by SkGePnmiPreSetStruct and SkGePnmiSetStruct.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_XXX. The codes are described in the calling functions.
+ */
+
+static int PnmiStruct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int  Action,		/* Set action to be performed */
+char *pBuf,		/* Buffer which contains the data to be set */
+unsigned int *pLen)	/* Length of buffer */
+{
+	int		Ret;
+	unsigned int	TableIndex;
+	unsigned int	DstOffset;
+	unsigned int	Len;
+	unsigned int	InstanceNo;
+	unsigned int	InstanceCnt;
+	SK_U32		Instance;
+	SK_U32		Id;
+
+
+	/* Check if the passed buffer has the right size */
+	if (*pLen < SK_PNMI_STRUCT_SIZE) {
+
+		/* Check if we can return the error within the buffer */
+		if (*pLen >= SK_PNMI_MIN_STRUCT_SIZE) {
+
+			SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_TOO_SHORT,
+				(SK_U32)(-1));
+		}
+
+		*pLen = SK_PNMI_STRUCT_SIZE;
+		return (SK_PNMI_ERR_TOO_SHORT);
+	}
+	
+	SK_PNMI_CHECKFLAGS("PnmiStruct: On call");
+
+	/*
+	 * Update the values of RLMT and SIRQ and increment semaphores to
+	 * indicate that an update was already done.
+	 */
+	if ((Ret = RlmtUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (Ret);
+	}
+
+	if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (Ret);
+	}
+
+	pAC->Pnmi.RlmtUpdatedFlag ++;
+	pAC->Pnmi.SirqUpdatedFlag ++;
+
+	/* Preset/Set values */
+	for (TableIndex = 0; TableIndex < sizeof(IdTable)/sizeof(IdTable[0]);
+		TableIndex ++) {
+
+		if (IdTable[TableIndex].Access != SK_PNMI_RW) {
+
+			continue;
+		}
+
+		InstanceNo = IdTable[TableIndex].InstanceNo;
+		Id = IdTable[TableIndex].Id;
+
+		for (InstanceCnt = 1; InstanceCnt <= InstanceNo;
+			InstanceCnt ++) {
+
+			DstOffset = IdTable[TableIndex].Offset +
+				(InstanceCnt - 1) *
+				IdTable[TableIndex].StructSize;
+
+			/*
+			 * Because VPD multiple instance variables are
+			 * not setable we do not need to evaluate VPD
+			 * instances. Have a look to VPD instance
+			 * calculation in SkPnmiGetStruct().
+			 */
+			Instance = (SK_U32)InstanceCnt;
+
+			/*
+			 * Evaluate needed buffer length
+			 */
+			Len = 0;
+			Ret = IdTable[TableIndex].Func(pAC, IoC,
+				SK_PNMI_GET, IdTable[TableIndex].Id,
+				NULL, &Len, Instance, TableIndex);
+
+			if (Ret == SK_PNMI_ERR_UNKNOWN_INST) {
+
+				break;
+			}
+			if (Ret != SK_PNMI_ERR_TOO_SHORT) {
+
+				pAC->Pnmi.RlmtUpdatedFlag --;
+				pAC->Pnmi.SirqUpdatedFlag --;
+
+				SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
+				SK_PNMI_SET_STAT(pBuf,
+					SK_PNMI_ERR_GENERAL, DstOffset);
+				*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			if (Id == OID_SKGE_VPD_ACTION) {
+
+				switch (*(pBuf + DstOffset)) {
+
+				case SK_PNMI_VPD_CREATE:
+					Len = 3 + *(pBuf + DstOffset + 3);
+					break;
+
+				case SK_PNMI_VPD_DELETE:
+					Len = 3;
+					break;
+
+				default:
+					Len = 1;
+					break;
+				}
+			}
+
+			/* Call the OID handler function */
+			Ret = IdTable[TableIndex].Func(pAC, IoC, Action,
+				IdTable[TableIndex].Id, pBuf + DstOffset,
+				&Len, Instance, TableIndex);
+
+			if (Ret != SK_PNMI_ERR_OK) {
+
+				pAC->Pnmi.RlmtUpdatedFlag --;
+				pAC->Pnmi.SirqUpdatedFlag --;
+
+				SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
+				SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_BAD_VALUE,
+					DstOffset);
+				*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+		}
+	}
+
+	pAC->Pnmi.RlmtUpdatedFlag --;
+	pAC->Pnmi.SirqUpdatedFlag --;
+
+	SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
+	SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_OK, (SK_U32)(-1));
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * LookupId - Lookup an OID in the IdTable
+ *
+ * Description:
+ *	Scans the IdTable to find the table entry of an OID.
+ *
+ * Returns:
+ *	The table index or -1 if not found.
+ */
+
+static int LookupId(
+SK_U32 Id)		/* Object identifier to be searched */
+{
+	int i;
+	int Len = sizeof(IdTable)/sizeof(IdTable[0]);
+
+	for (i=0; i<Len; i++) {
+
+		if (IdTable[i].Id == Id) {
+
+			return i;
+		}
+	}
+
+	return (-1);
+}
+
+/*****************************************************************************
+ *
+ * OidStruct - Handler of OID_SKGE_ALL_DATA
+ *
+ * Description:
+ *	This OID performs a Get/Preset/SetStruct call and returns all data
+ *	in a SK_PNMI_STRUCT_DATA structure.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+static int OidStruct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex) /* Index to the Id table */
+{
+	if (Id != OID_SKGE_ALL_DATA) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR003,
+			SK_PNMI_ERR003MSG);
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	/*
+	 * Check instance. We only handle single instance variables
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	switch (Action) {
+
+	case SK_PNMI_GET:
+		return (SkPnmiGetStruct(pAC, IoC, pBuf, pLen));
+
+	case SK_PNMI_PRESET:
+		return (SkPnmiPreSetStruct(pAC, IoC, pBuf, pLen));
+
+	case SK_PNMI_SET:
+		return (SkPnmiSetStruct(pAC, IoC, pBuf, pLen));
+	}
+
+	SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR004, SK_PNMI_ERR004MSG);
+
+	*pLen = 0;
+	return (SK_PNMI_ERR_GENERAL);
+}
+
+/*****************************************************************************
+ *
+ * Perform - OID handler of OID_SKGE_ACTION
+ *
+ * Description:
+ *	None.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+static int Perform(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex) /* Index to the Id table */
+{
+	int	Ret;
+	SK_U32	ActionOp;
+
+
+	/*
+	 * Check instance. We only handle single instance variables
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	if (*pLen < sizeof(SK_U32)) {
+
+		*pLen = sizeof(SK_U32);
+		return (SK_PNMI_ERR_TOO_SHORT);
+	}
+
+	/* Check if a get should be performed */
+	if (Action == SK_PNMI_GET) {
+
+		/* A get is easy. We always return the same value */
+		ActionOp = (SK_U32)SK_PNMI_ACT_IDLE;
+		SK_PNMI_STORE_U32(pBuf, ActionOp);
+		*pLen = sizeof(SK_U32);
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	/* Continue with PRESET/SET action */
+	if (*pLen > sizeof(SK_U32)) {
+
+		return (SK_PNMI_ERR_BAD_VALUE);
+	}
+
+	/* Check if the command is a known one */
+	SK_PNMI_READ_U32(pBuf, ActionOp);
+	if (*pLen > sizeof(SK_U32) ||
+		(ActionOp != SK_PNMI_ACT_IDLE &&
+		ActionOp != SK_PNMI_ACT_RESET &&
+		ActionOp != SK_PNMI_ACT_SELFTEST &&
+		ActionOp != SK_PNMI_ACT_RESETCNT)) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_BAD_VALUE);
+	}
+
+	/* A preset ends here */
+	if (Action == SK_PNMI_PRESET) {
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	switch (ActionOp) {
+
+	case SK_PNMI_ACT_IDLE:
+		/* Nothing to do */
+		break;
+
+	case SK_PNMI_ACT_RESET:
+		/*
+		 * Perform a driver reset or something that comes near
+		 * to this.
+		 */
+		Ret = SK_DRIVER_RESET(pAC, IoC);
+		if (Ret != 0) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR005,
+				SK_PNMI_ERR005MSG);
+
+			return (SK_PNMI_ERR_GENERAL);
+		}
+		break;
+
+	case SK_PNMI_ACT_SELFTEST:
+		/*
+		 * Perform a driver selftest or something similar to this.
+		 * Currently this feature is not used and will probably
+		 * implemented in another way.
+		 */
+		Ret = SK_DRIVER_SELFTEST(pAC, IoC);
+		pAC->Pnmi.TestResult = Ret;
+		break;
+
+	case SK_PNMI_ACT_RESETCNT:
+		/* Set all counters and timestamps to zero */
+		ResetCounter(pAC, IoC);
+		break;
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR006,
+			SK_PNMI_ERR006MSG);
+
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Mac8023Stat - OID handler of OID_GEN_XXX and OID_802_3_XXX
+ *
+ * Description:
+ *	Retrieves the statistic values of the virtual port (logical
+ *	index 0). Only special OIDs of NDIS are handled which consist
+ *	of a 32 bit instead of a 64 bit value. The OIDs are public
+ *	because perhaps some other platform can use them too.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+static int Mac8023Stat(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex) /* Index to the Id table */
+{
+	int	Ret;
+	SK_U32	StatVal;
+
+
+	/*
+	 * Only the active Mac is returned
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	/*
+	 * Check action type
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Check length
+	 */
+	switch (Id) {
+
+	case OID_802_3_PERMANENT_ADDRESS:
+	case OID_802_3_CURRENT_ADDRESS:
+		if (*pLen < sizeof(SK_MAC_ADDR)) {
+
+			*pLen = sizeof(SK_MAC_ADDR);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	default:
+		if (*pLen < 4) {
+
+			*pLen = 4;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+	}
+
+	/*
+	 * Update all statistics, because we retrieve virtual MAC, which
+	 * consists of multiple physical statistics and increment semaphore
+	 * to indicate that an update was already done.
+	 */
+	Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+	if ( Ret != SK_PNMI_ERR_OK) {
+
+		*pLen = 0;
+		return (Ret);
+	}
+	pAC->Pnmi.MacUpdatedFlag ++;
+
+	/*
+	 * Get value (MAC Index 0 identifies the virtual MAC)
+	 */
+	switch (Id) {
+
+	case OID_802_3_PERMANENT_ADDRESS:
+		CopyMac(pBuf, &pAC->Addr.PermanentMacAddress);
+		*pLen = sizeof(SK_MAC_ADDR);
+		break;
+
+	case OID_802_3_CURRENT_ADDRESS:
+		CopyMac(pBuf, &pAC->Addr.CurrentMacAddress);
+		*pLen = sizeof(SK_MAC_ADDR);
+		break;
+
+	default:
+		StatVal = (SK_U32)GetStatVal(pAC, IoC, 0,
+			IdTable[TableIndex].Param);
+		SK_PNMI_STORE_U32(pBuf, StatVal);
+		*pLen = sizeof(SK_U32);
+		break;
+	}
+
+	pAC->Pnmi.MacUpdatedFlag --;
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * MacPrivateStat - OID handler function of OID_SKGE_STAT_XXX
+ *
+ * Description:
+ *	Retrieves the XMAC statistic data.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+static int MacPrivateStat(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex) /* Index to the Id table */
+{
+	unsigned int	LogPortMax;
+	unsigned int	LogPortIndex;
+	unsigned int	PhysPortMax;
+	unsigned int	Limit;
+	unsigned int	Offset;
+	int		Ret;
+	SK_U64		StatVal;
+
+
+	/*
+	 * Calculate instance if wished. MAC index 0 is the virtual
+	 * MAC.
+	 */
+	PhysPortMax = pAC->GIni.GIMacsFound;
+	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+
+	if ((Instance != (SK_U32)(-1))) {
+
+		if ((Instance < 1) || (Instance > LogPortMax)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+
+		LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
+		Limit = LogPortIndex + 1;
+	}
+	else {
+		LogPortIndex = 0;
+		Limit = LogPortMax;
+	}
+
+	/*
+	 * Check action
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Check length
+	 */
+	if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U64)) {
+
+		*pLen = (Limit - LogPortIndex) * sizeof(SK_U64);
+		return (SK_PNMI_ERR_TOO_SHORT);
+	}
+
+	/*
+	 * Update XMAC statistic and increment semaphore to indicate that
+	 * an update was already done.
+	 */
+	Ret = MacUpdate(pAC, IoC, 0, PhysPortMax - 1);
+	if (Ret != SK_PNMI_ERR_OK) {
+
+		*pLen = 0;
+		return (Ret);
+	}
+	pAC->Pnmi.MacUpdatedFlag ++;
+
+	/*
+	 * Get value
+	 */
+	Offset = 0;
+	for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+		switch (Id) {
+
+/* XXX not yet implemented due to XMAC problems
+		case OID_SKGE_STAT_TX_UTIL:
+			return (SK_PNMI_ERR_GENERAL);
+*/
+/* XXX not yet implemented due to XMAC problems
+		case OID_SKGE_STAT_RX_UTIL:
+			return (SK_PNMI_ERR_GENERAL);
+*/
+		default:
+			StatVal = GetStatVal(pAC, IoC, LogPortIndex,
+				IdTable[TableIndex].Param);
+			SK_PNMI_STORE_U64(pBuf + Offset, StatVal);
+			break;
+		}
+
+		Offset += sizeof(SK_U64);
+	}
+	*pLen = Offset;
+
+	pAC->Pnmi.MacUpdatedFlag --;
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Addr - OID handler function of OID_SKGE_PHYS_CUR_ADDR and _FAC_ADDR
+ *
+ * Description:
+ *	Get/Presets/Sets the current and factory MAC address. The MAC
+ *	address of the virtual port, which is reported to the OS, may
+ *	not be changed, but the physical ones. A set to the virtual port
+ *	will be ignored. No error should be reported because otherwise
+ *	a multiple instance set (-1) would always fail.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+static int Addr(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex) /* Index to the Id table */
+{
+	int		Ret;
+	unsigned int	LogPortMax;
+	unsigned int	PhysPortMax;
+	unsigned int	LogPortIndex;
+	unsigned int	PhysPortIndex;
+	unsigned int	Limit;
+	unsigned int	Offset = 0;
+
+
+	/*
+	 * Calculate instance if wished
+	 */
+	PhysPortMax = pAC->GIni.GIMacsFound;
+	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+
+	if ((Instance != (SK_U32)(-1))) {
+		
+		if ((Instance < 1) || (Instance > SKCS_NUM_PROTOCOLS)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+
+		LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
+		Limit = LogPortIndex + 1;
+	}
+	else {
+		LogPortIndex = 0;
+		Limit = LogPortMax;
+	}
+
+	/*
+	 * Perform Action
+	 */
+	if (Action == SK_PNMI_GET) {
+
+		/*
+		 * Check length
+		*/
+		if (*pLen < (Limit - LogPortIndex) * 6) {
+
+			*pLen = (Limit - LogPortIndex) * 6;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+
+		/*
+		 * Get value
+		 */
+		for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+			switch (Id) {
+
+			case OID_SKGE_PHYS_CUR_ADDR:
+				if (LogPortIndex == 0) {
+
+					CopyMac(pBuf + Offset, &pAC->Addr.
+						CurrentMacAddress);
+				}
+				else {
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+						pAC, LogPortIndex);
+
+					CopyMac(pBuf + Offset, &pAC->Addr.
+						Port[PhysPortIndex].
+						CurrentMacAddress);
+				}
+				Offset += 6;
+				break;
+
+			case OID_SKGE_PHYS_FAC_ADDR:
+				if (LogPortIndex == 0) {
+
+					CopyMac(pBuf + Offset, &pAC->Addr.
+						PermanentMacAddress);
+				}
+				else {
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+						pAC, LogPortIndex);
+
+					CopyMac(pBuf + Offset, &pAC->Addr.
+						Port[PhysPortIndex].
+						PermanentMacAddress);
+				}
+				Offset += 6;
+				break;
+
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR008,
+					SK_PNMI_ERR008MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+		}
+
+		*pLen = Offset;
+	}
+	else {
+		/*
+		 * The logical MAC address may not be changed only
+		 * the physical ones
+		 */
+		if (Id == OID_SKGE_PHYS_FAC_ADDR) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_READ_ONLY);
+		}
+
+		/*
+		 * Only the current address may be changed
+		 */
+		if (Id != OID_SKGE_PHYS_CUR_ADDR) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR009,
+				SK_PNMI_ERR009MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		/*
+		 * Check length
+		*/
+		if (*pLen < (Limit - LogPortIndex) * 6) {
+
+			*pLen = (Limit - LogPortIndex) * 6;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		if (*pLen > (Limit - LogPortIndex) * 6) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+
+		/*
+		 * Check Action
+		 */
+		if (Action == SK_PNMI_PRESET) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_OK);
+		}
+
+		/*
+		 * Set OID_SKGE_MAC_CUR_ADDR
+		 */
+		for (; LogPortIndex < Limit; LogPortIndex ++, Offset += 6) {
+
+			/*
+			 * A set to virtual port and set of broadcast
+			 * address will be ignored
+			 */
+			if (LogPortIndex == 0 || SK_MEMCMP(pBuf + Offset,
+				"\xff\xff\xff\xff\xff\xff", 6) == 0) {
+
+				continue;
+			}
+
+			PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC,
+				LogPortIndex);
+
+			Ret = SkAddrOverride(pAC, IoC, PhysPortIndex,
+				(SK_MAC_ADDR *)(pBuf + Offset),
+				(LogPortIndex == 0 ? SK_ADDR_VIRTUAL_ADDRESS :
+				SK_ADDR_PHYSICAL_ADDRESS));
+			if (Ret != SK_ADDR_OVERRIDE_SUCCESS) {
+
+				return (SK_PNMI_ERR_GENERAL);
+			}
+		}
+		*pLen = Offset;
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * CsumStat - OID handler function of OID_SKGE_CHKSM_XXX
+ *
+ * Description:
+ *	Retrieves the statistic values of the CSUM module. The CSUM data
+ *	structure must be available in the SK_AC even if the CSUM module
+ *	is not included, because PNMI reads the statistic data from the
+ *	CSUM part of SK_AC directly.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+static int CsumStat(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex) /* Index to the Id table */
+{
+	unsigned int	Index;
+	unsigned int	Limit;
+	unsigned int	Offset = 0;
+	SK_U64		StatVal;
+
+
+	/*
+	 * Calculate instance if wished
+	 */
+	if (Instance != (SK_U32)(-1)) {
+		
+		if ((Instance < 1) || (Instance > SKCS_NUM_PROTOCOLS)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+
+		Index = (unsigned int)Instance - 1;
+		Limit = (unsigned int)Instance;
+	}
+	else {
+		Index = 0;
+		Limit = SKCS_NUM_PROTOCOLS;
+	}
+
+	/*
+	 * Check action
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Check length
+	 */
+	if (*pLen < (Limit - Index) * sizeof(SK_U64)) {
+
+		*pLen = (Limit - Index) * sizeof(SK_U64);
+		return (SK_PNMI_ERR_TOO_SHORT);
+	}
+
+	/*
+	 * Get value
+	 */
+	for (; Index < Limit; Index ++) {
+
+		switch (Id) {
+
+		case OID_SKGE_CHKSM_RX_OK_CTS:
+			StatVal = pAC->Csum.ProtoStats[Index].RxOkCts;
+			break;
+
+		case OID_SKGE_CHKSM_RX_UNABLE_CTS:
+			StatVal = pAC->Csum.ProtoStats[Index].RxUnableCts;
+			break;
+
+		case OID_SKGE_CHKSM_RX_ERR_CTS:
+			StatVal = pAC->Csum.ProtoStats[Index].RxErrCts;
+			break;
+
+		case OID_SKGE_CHKSM_TX_OK_CTS:
+			StatVal = pAC->Csum.ProtoStats[Index].TxOkCts;
+			break;
+
+		case OID_SKGE_CHKSM_TX_UNABLE_CTS:
+			StatVal = pAC->Csum.ProtoStats[Index].TxUnableCts;
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR010,
+				SK_PNMI_ERR010MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		SK_PNMI_STORE_U64(pBuf + Offset, StatVal);
+		Offset += sizeof(SK_U64);
+	}
+
+	/*
+	 * Store used buffer space
+	 */
+	*pLen = Offset;
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * SensorStat - OID handler function of OID_SKGE_SENSOR_XXX
+ *
+ * Description:
+ *	Retrieves the statistic values of the I2C module, which handles
+ *	the temperature and voltage sensors.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+static int SensorStat(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex) /* Index to the Id table */
+{
+	unsigned int	i;
+	unsigned int	Index;
+	unsigned int	Limit;
+	unsigned int	Offset;
+	unsigned int	Len;
+	SK_U32		Val32;
+	SK_U64		Val64;
+
+
+	/*
+	 * Calculate instance if wished
+	 */
+	if ((Instance != (SK_U32)(-1))) {
+
+		if ((Instance < 1) || (Instance > (SK_U32)pAC->I2c.MaxSens)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+
+		Index = (unsigned int)Instance -1;
+		Limit = (unsigned int)Instance;
+	}
+	else {
+		Index = 0;
+		Limit = (unsigned int) pAC->I2c.MaxSens;
+	}
+
+	/*
+	 * Check action
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Check length
+	 */
+	switch (Id) {
+
+	case OID_SKGE_SENSOR_VALUE:
+	case OID_SKGE_SENSOR_WAR_THRES_LOW:
+	case OID_SKGE_SENSOR_WAR_THRES_UPP:
+	case OID_SKGE_SENSOR_ERR_THRES_LOW:
+	case OID_SKGE_SENSOR_ERR_THRES_UPP:
+		if (*pLen < (Limit - Index) * sizeof(SK_U32)) {
+
+			*pLen = (Limit - Index) * sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_SENSOR_DESCR:
+		for (Offset = 0, i = Index; i < Limit; i ++) {
+
+			Len = (unsigned int)
+				SK_STRLEN(pAC->I2c.SenTable[i].SenDesc) + 1;
+			if (Len >= SK_PNMI_STRINGLEN2) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR011,
+					SK_PNMI_ERR011MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			Offset += Len;
+		}
+		if (*pLen < Offset) {
+
+			*pLen = Offset;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_SENSOR_INDEX:
+	case OID_SKGE_SENSOR_TYPE:
+	case OID_SKGE_SENSOR_STATUS:
+		if (*pLen < Limit - Index) {
+
+			*pLen = Limit - Index;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_SENSOR_WAR_CTS:
+	case OID_SKGE_SENSOR_WAR_TIME:
+	case OID_SKGE_SENSOR_ERR_CTS:
+	case OID_SKGE_SENSOR_ERR_TIME:
+		if (*pLen < (Limit - Index) * sizeof(SK_U64)) {
+
+			*pLen = (Limit - Index) * sizeof(SK_U64);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR012,
+			SK_PNMI_ERR012MSG);
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+
+	}
+
+	/*
+	 * Get value
+	 */
+	for (Offset = 0; Index < Limit; Index ++) {
+
+		switch (Id) {
+
+		case OID_SKGE_SENSOR_INDEX:
+			*(pBuf + Offset) = (char)Index;
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_SENSOR_DESCR:
+			Len = SK_STRLEN(pAC->I2c.SenTable[Index].SenDesc);
+			SK_MEMCPY(pBuf + Offset + 1,
+				pAC->I2c.SenTable[Index].SenDesc, Len);
+			*(pBuf + Offset) = (char)Len;
+			Offset += Len + 1;
+			break;
+
+		case OID_SKGE_SENSOR_TYPE:
+			*(pBuf + Offset) =
+				(char)pAC->I2c.SenTable[Index].SenType;
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_SENSOR_VALUE:
+			Val32 = (SK_U32)pAC->I2c.SenTable[Index].SenValue;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_SENSOR_WAR_THRES_LOW:
+			Val32 = (SK_U32)pAC->I2c.SenTable[Index].
+				SenThreWarnLow;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_SENSOR_WAR_THRES_UPP:
+			Val32 = (SK_U32)pAC->I2c.SenTable[Index].
+				SenThreWarnHigh;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_SENSOR_ERR_THRES_LOW:
+			Val32 = (SK_U32)pAC->I2c.SenTable[Index].
+				SenThreErrLow;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_SENSOR_ERR_THRES_UPP:
+			Val32 = pAC->I2c.SenTable[Index].SenThreErrHigh;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_SENSOR_STATUS:
+			*(pBuf + Offset) =
+				(char)pAC->I2c.SenTable[Index].SenErrFlag;
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_SENSOR_WAR_CTS:
+			Val64 = pAC->I2c.SenTable[Index].SenWarnCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_SENSOR_ERR_CTS:
+			Val64 = pAC->I2c.SenTable[Index].SenErrCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_SENSOR_WAR_TIME:
+			Val64 = SK_PNMI_HUNDREDS_SEC(pAC->I2c.SenTable[Index].
+				SenBegWarnTS);
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_SENSOR_ERR_TIME:
+			Val64 = SK_PNMI_HUNDREDS_SEC(pAC->I2c.SenTable[Index].
+				SenBegErrTS);
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR013,
+				SK_PNMI_ERR013MSG);
+
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	}
+
+	/*
+	 * Store used buffer space
+	 */
+	*pLen = Offset;
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Vpd - OID handler function of OID_SKGE_VPD_XXX
+ *
+ * Description:
+ *	Get/preset/set of VPD data. As instance the name of a VPD key
+ *	can be passed. The Instance parameter is a SK_U32 and can be
+ *	used as a string buffer for the VPD key, because their maximum
+ *	length is 4 byte.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+static int Vpd(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex) /* Index to the Id table */
+{
+	SK_VPD_STATUS	*pVpdStatus;
+	unsigned int	BufLen;
+	char		Buf[256];
+	char		KeyArr[SK_PNMI_VPD_ARR_SIZE][SK_PNMI_VPD_STR_SIZE];
+	char		KeyStr[SK_PNMI_VPD_STR_SIZE];
+	unsigned int	KeyNo;
+	unsigned int	Offset;
+	unsigned int	Index;
+	unsigned int	FirstIndex;
+	unsigned int	LastIndex;
+	unsigned int	Len;
+	int		Ret;
+	SK_U32		Val32;
+
+	/*
+	 * Get array of all currently stored VPD keys
+	 */
+	Ret = GetVpdKeyArr(pAC, IoC, &KeyArr[0][0], sizeof(KeyArr),
+		&KeyNo);
+	if (Ret != SK_PNMI_ERR_OK) {
+
+		*pLen = 0;
+		return (Ret);
+	}
+
+	/*
+	 * If instance is not -1, try to find the requested VPD key for
+	 * the multiple instance variables. The other OIDs as for example
+	 * OID VPD_ACTION are single instance variables and must be
+	 * handled separatly.
+	 */
+	FirstIndex = 0;
+	LastIndex = KeyNo;
+
+	if ((Instance != (SK_U32)(-1))) {
+
+		if (Id == OID_SKGE_VPD_KEY || Id == OID_SKGE_VPD_VALUE ||
+			Id == OID_SKGE_VPD_ACCESS) {
+
+			SK_STRNCPY(KeyStr, (char *)&Instance, 4);
+			KeyStr[4] = 0;
+
+			for (Index = 0; Index < KeyNo; Index ++) {
+
+				if (SK_STRCMP(KeyStr, KeyArr[Index]) == 0) {
+
+					FirstIndex = Index;
+					LastIndex = Index+1;
+					break;
+				}
+			}
+			if (Index == KeyNo) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_UNKNOWN_INST);
+			}
+		}
+		else if (Instance != 1) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+	}
+
+	/*
+	 * Get value, if a query should be performed
+	 */
+	if (Action == SK_PNMI_GET) {
+
+		switch (Id) {
+
+		case OID_SKGE_VPD_FREE_BYTES:
+			/* Check length of buffer */
+			if (*pLen < sizeof(SK_U32)) {
+
+				*pLen = sizeof(SK_U32);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			/* Get number of free bytes */
+			pVpdStatus = VpdStat(pAC, IoC);
+			if (pVpdStatus == NULL) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR017,
+					SK_PNMI_ERR017MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			if ((pVpdStatus->vpd_status & VPD_VALID) == 0) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR018,
+					SK_PNMI_ERR018MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			
+			Val32 = (SK_U32)pVpdStatus->vpd_free_rw;
+			SK_PNMI_STORE_U32(pBuf, Val32);
+			*pLen = sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_VPD_ENTRIES_LIST:
+			/* Check length */
+			for (Len = 0, Index = 0; Index < KeyNo; Index ++) {
+
+				Len += SK_STRLEN(KeyArr[Index]) + 1;
+			}
+			if (*pLen < Len) {
+
+				*pLen = Len;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+
+			/* Get value */
+			*(pBuf) = (char)Len - 1;
+			for (Offset = 1, Index = 0; Index < KeyNo; Index ++) {
+
+				Len = SK_STRLEN(KeyArr[Index]);
+				SK_MEMCPY(pBuf + Offset, KeyArr[Index], Len);
+
+				Offset += Len;
+
+				if (Index < KeyNo - 1) {
+
+					*(pBuf + Offset) = ' ';
+					Offset ++;
+				}
+			}
+			*pLen = Offset;
+			break;
+
+		case OID_SKGE_VPD_ENTRIES_NUMBER:
+			/* Check length */
+			if (*pLen < sizeof(SK_U32)) {
+
+				*pLen = sizeof(SK_U32);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+
+			Val32 = (SK_U32)KeyNo;
+			SK_PNMI_STORE_U32(pBuf, Val32);
+			*pLen = sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_VPD_KEY:
+			/* Check buffer length, if it is large enough */
+			for (Len = 0, Index = FirstIndex;
+				Index < LastIndex; Index ++) {
+
+				Len += SK_STRLEN(KeyArr[Index]) + 1;
+			}
+			if (*pLen < Len) {
+
+				*pLen = Len;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+
+			/*
+			 * Get the key to an intermediate buffer, because
+			 * we have to prepend a length byte.
+			 */
+			for (Offset = 0, Index = FirstIndex;
+				Index < LastIndex; Index ++) {
+
+				Len = SK_STRLEN(KeyArr[Index]);
+
+				*(pBuf + Offset) = (char)Len;
+				SK_MEMCPY(pBuf + Offset + 1, KeyArr[Index],
+					Len);
+				Offset += Len + 1;
+			}
+			*pLen = Offset;
+			break;
+
+		case OID_SKGE_VPD_VALUE:
+			/* Check the buffer length if it is large enough */
+			for (Offset = 0, Index = FirstIndex;
+				Index < LastIndex; Index ++) {
+
+				BufLen = 256;
+				if (VpdRead(pAC, IoC, KeyArr[Index], Buf,
+					(int *)&BufLen) > 0 ||
+					BufLen >= SK_PNMI_VPD_DATALEN) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR021,
+						SK_PNMI_ERR021MSG);
+
+					return (SK_PNMI_ERR_GENERAL);
+				}
+				Offset += BufLen + 1;
+			}
+			if (*pLen < Offset) {
+
+				*pLen = Offset;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+
+			/*
+			 * Get the value to an intermediate buffer, because
+			 * we have to prepend a length byte.
+			 */
+			for (Offset = 0, Index = FirstIndex;
+				Index < LastIndex; Index ++) {
+
+				BufLen = 256;
+				if (VpdRead(pAC, IoC, KeyArr[Index], Buf,
+					(int *)&BufLen) > 0 ||
+					BufLen >= SK_PNMI_VPD_DATALEN) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR022,
+						SK_PNMI_ERR022MSG);
+
+					*pLen = 0;
+					return (SK_PNMI_ERR_GENERAL);
+				}
+
+				*(pBuf + Offset) = (char)BufLen;
+				SK_MEMCPY(pBuf + Offset + 1, Buf, BufLen);
+				Offset += BufLen + 1;
+			}
+			*pLen = Offset;
+			break;
+
+		case OID_SKGE_VPD_ACCESS:
+			if (*pLen < LastIndex - FirstIndex) {
+
+				*pLen = LastIndex - FirstIndex;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+
+			for (Offset = 0, Index = FirstIndex;
+				Index < LastIndex; Index ++) {
+
+				if (VpdMayWrite(KeyArr[Index])) {
+
+					*(pBuf + Offset) = SK_PNMI_VPD_RW;
+				}
+				else {
+					*(pBuf + Offset) = SK_PNMI_VPD_RO;
+				}
+				Offset ++;
+			}
+			*pLen = Offset;
+			break;
+
+		case OID_SKGE_VPD_ACTION:
+			Offset = LastIndex - FirstIndex;
+			if (*pLen < Offset) {
+
+				*pLen = Offset;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			SK_MEMSET(pBuf, 0, Offset);
+			*pLen = Offset;
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR023,
+				SK_PNMI_ERR023MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	} 
+	else {
+		/* The only OID which can be set is VPD_ACTION */
+		if (Id != OID_SKGE_VPD_ACTION) {
+
+			if (Id == OID_SKGE_VPD_FREE_BYTES ||
+				Id == OID_SKGE_VPD_ENTRIES_LIST ||
+				Id == OID_SKGE_VPD_ENTRIES_NUMBER ||
+				Id == OID_SKGE_VPD_KEY ||
+				Id == OID_SKGE_VPD_VALUE ||
+				Id == OID_SKGE_VPD_ACCESS) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_READ_ONLY);
+			}
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR024,
+				SK_PNMI_ERR024MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		/*
+		 * From this point we handle VPD_ACTION. Check the buffer
+		 * length. It should at least have the size of one byte.
+		 */
+		if (*pLen < 1) {
+
+			*pLen = 1;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+
+		/*
+		 * The first byte contains the VPD action type we should
+		 * perform.
+		 */
+		switch (*pBuf) {
+
+		case SK_PNMI_VPD_IGNORE:
+			/* Nothing to do */
+			break;
+
+		case SK_PNMI_VPD_CREATE:
+			/*
+			 * We have to create a new VPD entry or we modify
+			 * an existing one. Check first the buffer length.
+			 */
+			if (*pLen < 4) {
+
+				*pLen = 4;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			KeyStr[0] = pBuf[1];
+			KeyStr[1] = pBuf[2];
+			KeyStr[2] = 0;
+
+			/*
+			 * Is the entry writable or does it belong to the
+			 * read-only area?
+			 */
+			if (!VpdMayWrite(KeyStr)) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			Offset = (int)pBuf[3] & 0xFF;
+
+			SK_MEMCPY(Buf, pBuf + 4, Offset);
+			Buf[Offset] = 0;
+
+			/* A preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			/* Write the new entry or modify an existing one */
+			Ret = VpdWrite(pAC, IoC, KeyStr, Buf);
+			if (Ret == SK_PNMI_VPD_NOWRITE ) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+			else if (Ret != SK_PNMI_VPD_OK) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR025,
+					SK_PNMI_ERR025MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+
+			/*
+			 * Perform an update of the VPD data. This is
+			 * not mandantory, but just to be sure.
+			 */
+			Ret = VpdUpdate(pAC, IoC);
+			if (Ret != SK_PNMI_VPD_OK) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR026,
+					SK_PNMI_ERR026MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			break;
+
+		case SK_PNMI_VPD_DELETE:
+			/* Check if the buffer size is plausible */
+			if (*pLen < 3) {
+
+				*pLen = 3;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			if (*pLen > 3) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+			KeyStr[0] = pBuf[1];
+			KeyStr[1] = pBuf[2];
+			KeyStr[2] = 0;
+
+			/* Find the passed key in the array */
+			for (Index = 0; Index < KeyNo; Index ++) {
+
+				if (SK_STRCMP(KeyStr, KeyArr[Index]) == 0) {
+
+					break;
+				}
+			}
+			/*
+			 * If we cannot find the key it is wrong, so we
+			 * return an appropriate error value.
+			 */
+			if (Index == KeyNo) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			/* Ok, you wanted it and you will get it */
+			Ret = VpdDelete(pAC, IoC, KeyStr);
+			if (Ret != SK_PNMI_VPD_OK) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR027,
+					SK_PNMI_ERR027MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+
+			/*
+			 * Perform an update of the VPD data. This is
+			 * not mandantory, but just to be sure.
+			 */
+			Ret = VpdUpdate(pAC, IoC);
+			if (Ret != SK_PNMI_VPD_OK) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR028,
+					SK_PNMI_ERR028MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			break;
+
+		default:
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * General - OID handler function of various single instance OIDs
+ *
+ * Description:
+ *	The code is simple. No description necessary.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+static int General(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex) /* Index to the Id table */
+{
+	int		Ret;
+	unsigned int	Index;
+	unsigned int	Len;
+	unsigned int	Offset;
+	unsigned int	Val;
+	SK_U8		Val8;
+	SK_U16		Val16;
+	SK_U32		Val32;
+	SK_U64		Val64;
+	SK_U64		Val64RxHwErrs = 0;
+	SK_U64		Val64TxHwErrs = 0;
+	char		Buf[256];
+
+
+	/*
+	 * Check instance. We only handle single instance variables
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	/*
+	 * Check action. We only allow get requests.
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Check length for the various supported OIDs
+	 */
+	switch (Id) {
+
+	case OID_SKGE_PORT_NUMBER:
+	case OID_SKGE_DEVICE_TYPE:
+	case OID_SKGE_RESULT:
+	case OID_SKGE_RLMT_MONITOR_NUMBER:
+	case OID_GEN_XMIT_ERROR:
+	case OID_GEN_RCV_ERROR:
+	case OID_GEN_RCV_NO_BUFFER:
+	case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+	case OID_SKGE_TRAP_NUMBER:
+	case OID_SKGE_MDB_VERSION:
+		if (*pLen < sizeof(SK_U32)) {
+
+			*pLen = sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_CHIPSET:
+		if (*pLen < sizeof(SK_U16)) {
+
+			*pLen = sizeof(SK_U16);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_BUS_TYPE:
+	case OID_SKGE_BUS_SPEED:
+	case OID_SKGE_BUS_WIDTH:
+	case OID_SKGE_SENSOR_NUMBER:
+	case OID_SKGE_CHKSM_NUMBER:
+		if (*pLen < sizeof(SK_U8)) {
+
+			*pLen = sizeof(SK_U8);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_TX_SW_QUEUE_LEN:
+	case OID_SKGE_TX_SW_QUEUE_MAX:
+	case OID_SKGE_TX_RETRY:
+	case OID_SKGE_RX_INTR_CTS:
+	case OID_SKGE_TX_INTR_CTS:
+	case OID_SKGE_RX_NO_BUF_CTS:
+	case OID_SKGE_TX_NO_BUF_CTS:
+	case OID_SKGE_TX_USED_DESCR_NO:
+	case OID_SKGE_RX_DELIVERED_CTS:
+	case OID_SKGE_RX_OCTETS_DELIV_CTS:
+	case OID_SKGE_RX_HW_ERROR_CTS:
+	case OID_SKGE_TX_HW_ERROR_CTS:
+	case OID_SKGE_IN_ERRORS_CTS:
+	case OID_SKGE_OUT_ERROR_CTS:
+	case OID_SKGE_ERR_RECOVERY_CTS:
+	case OID_SKGE_SYSUPTIME:
+		if (*pLen < sizeof(SK_U64)) {
+
+			*pLen = sizeof(SK_U64);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	default:
+		/* Checked later */
+		break;
+	}
+
+	/* Update statistic */
+	if (Id == OID_SKGE_RX_HW_ERROR_CTS ||
+		Id == OID_SKGE_TX_HW_ERROR_CTS ||
+		Id == OID_SKGE_IN_ERRORS_CTS ||
+		Id == OID_SKGE_OUT_ERROR_CTS ||
+		Id == OID_GEN_XMIT_ERROR ||
+		Id == OID_GEN_RCV_ERROR) {
+
+		/* Force the XMAC to update its statistic counters and
+		 * Increment semaphore to indicate that an update was
+		 * already done.
+		 */
+		Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+		if (Ret != SK_PNMI_ERR_OK) {
+
+			*pLen = 0;
+			return (Ret);
+		}
+		pAC->Pnmi.MacUpdatedFlag ++;
+
+		/*
+		 * Some OIDs consist of multiple hardware counters. Those
+		 * values which are contained in all of them will be added
+		 * now.
+		 */
+		switch (Id) {
+
+		case OID_SKGE_RX_HW_ERROR_CTS:
+		case OID_SKGE_IN_ERRORS_CTS:
+		case OID_GEN_RCV_ERROR:
+			Val64RxHwErrs =
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_MISSED) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FRAMING) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_OVERFLOW)+
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_JABBER) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CARRIER) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_IRLENGTH)+
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SYMBOL) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SHORTS) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_RUNT) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_TOO_LONG)+
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FCS) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CEXT);
+			break;
+
+		case OID_SKGE_TX_HW_ERROR_CTS:
+		case OID_SKGE_OUT_ERROR_CTS:
+		case OID_GEN_XMIT_ERROR:
+			Val64TxHwErrs =
+				GetStatVal(pAC, IoC, 0,
+				SK_PNMI_HTX_EXCESS_COL) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_LATE_COL)+
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_UNDERRUN)+
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_CARRIER)+
+				GetStatVal(pAC, IoC, 0,
+				SK_PNMI_HTX_EXCESS_COL);
+			break;
+		}
+	}
+
+	/*
+	 * Retrieve value
+	 */
+	switch (Id) {
+
+	case OID_SKGE_SUPPORTED_LIST:
+		Len = sizeof(IdTable)/sizeof(IdTable[0]) * sizeof(SK_U32);
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		for (Offset = 0, Index = 0; Offset < Len;
+			Offset += sizeof(SK_U32), Index ++) {
+
+			Val32 = (SK_U32)IdTable[Index].Id;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+		}
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_PORT_NUMBER:
+		Val32 = (SK_U32)pAC->GIni.GIMacsFound;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_DEVICE_TYPE:
+		Val32 = (SK_U32)pAC->Pnmi.DeviceType;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_DRIVER_DESCR:
+		if (pAC->Pnmi.pDriverDescription == NULL) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR007,
+				SK_PNMI_ERR007MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		Len = SK_STRLEN(pAC->Pnmi.pDriverDescription) + 1;
+		if (Len > SK_PNMI_STRINGLEN1) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR029,
+				SK_PNMI_ERR029MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		*pBuf = (char)(Len - 1);
+		SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverDescription, Len - 1);
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_DRIVER_VERSION:
+		if (pAC->Pnmi.pDriverVersion == NULL) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030,
+				SK_PNMI_ERR030MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		Len = SK_STRLEN(pAC->Pnmi.pDriverVersion) + 1;
+		if (Len > SK_PNMI_STRINGLEN1) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031,
+				SK_PNMI_ERR031MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		*pBuf = (char)(Len - 1);
+		SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverVersion, Len - 1);
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_HW_DESCR:
+		/*
+		 * The hardware description is located in the VPD. This
+		 * query may move to the initialisation routine. But
+		 * the VPD data is cached and therefore a call here
+		 * will not make much difference.
+		 */
+		Len = 256;
+		if (VpdRead(pAC, IoC, VPD_NAME, Buf, (int *)&Len) > 0) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR032,
+				SK_PNMI_ERR032MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+		Len ++;
+		if (Len > SK_PNMI_STRINGLEN1) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR033,
+				SK_PNMI_ERR033MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		*pBuf = (char)(Len - 1);
+		SK_MEMCPY(pBuf + 1, Buf, Len - 1);
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_HW_VERSION:
+		/* Oh, I love to do some string manipulation */
+		if (*pLen < 5) {
+
+			*pLen = 5;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		Val8 = (SK_U8)pAC->GIni.GIPciHwRev;
+		pBuf[0] = 4;
+		pBuf[1] = 'v';
+		pBuf[2] = (char)(0x30 | ((Val8 >> 4) & 0x0F));
+		pBuf[3] = '.';
+		pBuf[4] = (char)(0x30 | (Val8 & 0x0F));
+		*pLen = 5;
+		break;
+
+	case OID_SKGE_CHIPSET:
+		Val16 = SK_PNMI_CHIPSET;
+		SK_PNMI_STORE_U16(pBuf, Val16);
+		*pLen = sizeof(SK_U16);
+		break;
+
+	case OID_SKGE_BUS_TYPE:
+		*pBuf = (char)SK_PNMI_BUS_PCI;
+		*pLen = sizeof(char);
+		break;
+
+	case OID_SKGE_BUS_SPEED:
+		*pBuf = pAC->Pnmi.PciBusSpeed;
+		*pLen = sizeof(char);
+		break;
+
+	case OID_SKGE_BUS_WIDTH:
+		*pBuf = pAC->Pnmi.PciBusWidth;
+		*pLen = sizeof(char);
+		break;
+
+	case OID_SKGE_RESULT:
+		Val32 = pAC->Pnmi.TestResult;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_SENSOR_NUMBER:
+		*pBuf = (char)pAC->I2c.MaxSens;
+		*pLen = sizeof(char);
+		break;
+
+	case OID_SKGE_CHKSM_NUMBER:
+		*pBuf = SKCS_NUM_PROTOCOLS;
+		*pLen = sizeof(char);
+		break;
+
+	case OID_SKGE_TRAP_NUMBER:
+		GetTrapQueueLen(pAC, &Len, &Val);
+		Val32 = (SK_U32)Val;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_TRAP:
+		GetTrapQueueLen(pAC, &Len, &Val);
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		CopyTrapQueue(pAC, pBuf);
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_RLMT_MONITOR_NUMBER:
+/* XXX Not yet implemented by RLMT therefore we return zero elements */
+		Val32 = 0;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_TX_SW_QUEUE_LEN:
+		Val64 = pAC->Pnmi.TxSwQueueLen;
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_TX_SW_QUEUE_MAX:
+		Val64 = pAC->Pnmi.TxSwQueueMax;
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_TX_RETRY:
+		Val64 = pAC->Pnmi.TxRetryCts;
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_RX_INTR_CTS:
+		Val64 = pAC->Pnmi.RxIntrCts;
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_TX_INTR_CTS:
+		Val64 = pAC->Pnmi.TxIntrCts;
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_RX_NO_BUF_CTS:
+		Val64 = pAC->Pnmi.RxNoBufCts;
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_TX_NO_BUF_CTS:
+		Val64 = pAC->Pnmi.TxNoBufCts;
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_TX_USED_DESCR_NO:
+		Val64 = pAC->Pnmi.TxUsedDescrNo;
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_RX_DELIVERED_CTS:
+		Val64 = pAC->Pnmi.RxDeliveredCts;
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_RX_OCTETS_DELIV_CTS:
+		Val64 = pAC->Pnmi.RxOctetsDeliveredCts;
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_RX_HW_ERROR_CTS:
+		SK_PNMI_STORE_U64(pBuf, Val64RxHwErrs);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_TX_HW_ERROR_CTS:
+		SK_PNMI_STORE_U64(pBuf, Val64TxHwErrs);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_IN_ERRORS_CTS:
+		Val64 = Val64RxHwErrs + pAC->Pnmi.RxNoBufCts;
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_OUT_ERROR_CTS:
+		Val64 = Val64TxHwErrs + pAC->Pnmi.TxNoBufCts;
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_ERR_RECOVERY_CTS:
+		Val64 = pAC->Pnmi.ErrRecoveryCts;
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_SYSUPTIME:
+		Val64 = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+		Val64 -= pAC->Pnmi.StartUpTime;
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_MDB_VERSION:
+		Val32 = SK_PNMI_MDB_VERSION;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_GEN_RCV_ERROR:
+		Val32 = (SK_U32)(Val64RxHwErrs + pAC->Pnmi.RxNoBufCts);
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_GEN_XMIT_ERROR:
+		Val32 = (SK_U32)(Val64TxHwErrs + pAC->Pnmi.TxNoBufCts);
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_GEN_RCV_NO_BUFFER:
+		Val32 = (SK_U32)pAC->Pnmi.RxNoBufCts;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+		Val32 = (SK_U32)pAC->Pnmi.TxSwQueueLen;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR034,
+			SK_PNMI_ERR034MSG);
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	if (Id == OID_SKGE_RX_HW_ERROR_CTS ||
+		Id == OID_SKGE_TX_HW_ERROR_CTS ||
+		Id == OID_SKGE_IN_ERRORS_CTS ||
+		Id == OID_SKGE_OUT_ERROR_CTS ||
+		Id == OID_GEN_XMIT_ERROR ||
+		Id == OID_GEN_RCV_ERROR) {
+
+		pAC->Pnmi.MacUpdatedFlag --;
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Rlmt - OID handler function of OID_SKGE_RLMT_XXX single instance.
+ *
+ * Description:
+ *	Get/Presets/Sets the RLMT OIDs.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+static int Rlmt(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex) /* Index to the Id table */
+{
+	int		Ret;
+	unsigned int	PhysPortIndex;
+	unsigned int	PhysPortMax;
+	SK_EVPARA	EventParam;
+	SK_U32		Val32;
+	SK_U64		Val64;
+
+
+	/*
+	 * Check instance. Only single instance OIDs are allowed here.
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	/*
+	 * Perform the requested action
+	 */
+	if (Action == SK_PNMI_GET) {
+
+		/*
+		 * Check if the buffer length is large enough.
+		 */
+
+		switch (Id) {
+
+		case OID_SKGE_RLMT_MODE:
+		case OID_SKGE_RLMT_PORT_ACTIVE:
+		case OID_SKGE_RLMT_PORT_PREFERED:
+			if (*pLen < sizeof(SK_U8)) {
+
+				*pLen = sizeof(SK_U8);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		case OID_SKGE_RLMT_PORT_NUMBER:
+			if (*pLen < sizeof(SK_U32)) {
+
+				*pLen = sizeof(SK_U32);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_CTS:
+		case OID_SKGE_RLMT_CHANGE_TIME:
+		case OID_SKGE_RLMT_CHANGE_ESTIM:
+		case OID_SKGE_RLMT_CHANGE_THRES:
+			if (*pLen < sizeof(SK_U64)) {
+
+				*pLen = sizeof(SK_U64);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR035,
+				SK_PNMI_ERR035MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		/*
+		 * Update RLMT statistic and increment semaphores to indicate
+		 * that an update was already done. Maybe RLMT will hold its
+		 * statistic always up to date some time. Then we can
+		 * remove this type of call.
+		 */
+		if ((Ret = RlmtUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+			*pLen = 0;
+			return (Ret);
+		}
+		pAC->Pnmi.RlmtUpdatedFlag ++;
+
+		/*
+		 * Retrieve Value
+		*/
+		switch (Id) {
+
+		case OID_SKGE_RLMT_MODE:
+			*pBuf = (char)pAC->Rlmt.RlmtMode;
+			*pLen = sizeof(char);
+			break;
+
+		case OID_SKGE_RLMT_PORT_NUMBER:
+			Val32 = (SK_U32)pAC->GIni.GIMacsFound;
+			SK_PNMI_STORE_U32(pBuf, Val32);
+			*pLen = sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_RLMT_PORT_ACTIVE:
+			*pBuf = 0;
+			/*
+			 * If multiple ports may become active this OID
+			 * doesn't make sense any more. A new variable in
+			 * the port structure should be created. However,
+			 * for this variable the first active port is
+			 * returned.
+			 */
+			PhysPortMax = pAC->GIni.GIMacsFound;
+
+			for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
+				PhysPortIndex ++) {
+
+				if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+					*pBuf = (char)SK_PNMI_PORT_PHYS2LOG(
+						PhysPortIndex);
+					break;
+				}
+			}
+			*pLen = sizeof(char);
+			break;
+
+		case OID_SKGE_RLMT_PORT_PREFERED:
+			*pBuf = (char)SK_PNMI_PORT_PHYS2LOG(
+				pAC->Rlmt.MacPreferred);
+			*pLen = sizeof(char);
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_CTS:
+			Val64 = pAC->Pnmi.RlmtChangeCts;
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_TIME:
+			Val64 = pAC->Pnmi.RlmtChangeTime;
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_ESTIM:
+			Val64 = pAC->Pnmi.RlmtChangeEstimate.Estimate;
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_THRES:
+			Val64 = pAC->Pnmi.RlmtChangeThreshold;
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR036,
+				SK_PNMI_ERR036MSG);
+
+			pAC->Pnmi.RlmtUpdatedFlag --;
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		pAC->Pnmi.RlmtUpdatedFlag --;
+	}
+	else {
+		/* Perform a preset or set */
+		switch (Id) {
+
+		case OID_SKGE_RLMT_MODE:
+			/* Check if the buffer length is plausible */
+			if (*pLen < sizeof(char)) {
+
+				*pLen = sizeof(char);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			/* Check if the value range is correct */
+			if (*pLen != sizeof(char) ||
+				(*pBuf & SK_PNMI_RLMT_MODE_CHK_LINK) == 0 ||
+				*(SK_U8 *)pBuf > 15) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_OK);
+			}
+			/* Send an event to RLMT to change the mode */
+			SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+			EventParam.Para32[0] |= (SK_U32)(*pBuf);
+			if (SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE,
+				EventParam) > 0) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR037,
+					SK_PNMI_ERR037MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			break;
+
+		case OID_SKGE_RLMT_PORT_PREFERED:
+			/* Check if the buffer length is plausible */
+			if (*pLen < sizeof(char)) {
+
+				*pLen = sizeof(char);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			/* Check if the value range is correct */
+			if (*pLen != sizeof(char) || *(SK_U8 *)pBuf >
+				(SK_U8)pAC->GIni.GIMacsFound) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_OK);
+			}
+
+			/*
+			 * Send an event to RLMT change the preferred port.
+			 * A param of -1 means automatic mode. RLMT will
+			 * make the decision which is the preferred port.
+			 */
+			SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+			EventParam.Para32[0] = (SK_U32)(*pBuf) - 1;
+			if (SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE,
+				EventParam) > 0) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR038,
+					SK_PNMI_ERR038MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_THRES:
+			/* Check if the buffer length is plausible */
+			if (*pLen < sizeof(SK_U64)) {
+
+				*pLen = sizeof(SK_U64);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			/*
+			 * There are not many restrictions to the
+			 * value range.
+			 */
+			if (*pLen != sizeof(SK_U64)) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+			/* A preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_OK);
+			}
+			/*
+			 * Store the new threshold, which will be taken
+			 * on the next timer event.
+			 */
+			SK_PNMI_READ_U64(pBuf, Val64);
+			pAC->Pnmi.RlmtChangeThreshold = Val64;
+			break;
+
+		default:
+			/* The other OIDs are not be able for set */
+			*pLen = 0;
+			return (SK_PNMI_ERR_READ_ONLY);
+		}
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * RlmtStat - OID handler function of OID_SKGE_RLMT_XXX multiple instance.
+ *
+ * Description:
+ *	Performs get requests on multiple instance variables.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+static int RlmtStat(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex) /* Index to the Id table */
+{
+	unsigned int	PhysPortMax;
+	unsigned int	PhysPortIndex;
+	unsigned int	Limit;
+	unsigned int	Offset;
+	int		Ret;
+	SK_U32		Val32;
+	SK_U64		Val64;
+
+
+	/*
+	 * Calculate the port indexes from the instance
+	 */
+	PhysPortMax = pAC->GIni.GIMacsFound;
+
+	if ((Instance != (SK_U32)(-1))) {
+
+		if ((Instance < 1) || (Instance > PhysPortMax)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+
+		PhysPortIndex = Instance - 1;
+		Limit = PhysPortIndex + 1;
+	}
+	else {
+		PhysPortIndex = 0;
+		Limit = PhysPortMax;
+	}
+
+	/*
+	 * Currently only get requests are allowed.
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Check if the buffer length is large enough.
+	 */
+	switch (Id) {
+
+	case OID_SKGE_RLMT_PORT_INDEX:
+	case OID_SKGE_RLMT_STATUS:
+		if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U32)) {
+
+			*pLen = (Limit - PhysPortIndex) * sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_RLMT_TX_HELLO_CTS:
+	case OID_SKGE_RLMT_RX_HELLO_CTS:
+	case OID_SKGE_RLMT_TX_SP_REQ_CTS:
+	case OID_SKGE_RLMT_RX_SP_CTS:
+		if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U64)) {
+
+			*pLen = (Limit - PhysPortIndex) * sizeof(SK_U64);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR039,
+			SK_PNMI_ERR039MSG);
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+
+	}
+
+	/*
+	 * Update statistic and increment semaphores to indicate that
+	 * an update was already done.
+	 */
+	if ((Ret = RlmtUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+		*pLen = 0;
+		return (Ret);
+	}
+	pAC->Pnmi.RlmtUpdatedFlag ++;
+
+	/*
+	 * Get value
+	 */
+	Offset = 0;
+	for (; PhysPortIndex < Limit; PhysPortIndex ++) {
+
+		switch (Id) {
+
+		case OID_SKGE_RLMT_PORT_INDEX:
+			Val32 = PhysPortIndex;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_RLMT_STATUS:
+			if (pAC->Rlmt.Port[PhysPortIndex].PortState ==
+				SK_RLMT_PS_INIT ||
+				pAC->Rlmt.Port[PhysPortIndex].PortState ==
+				SK_RLMT_PS_DOWN) {
+
+				Val32 = SK_PNMI_RLMT_STATUS_ERROR;
+			}
+			else if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+				Val32 = SK_PNMI_RLMT_STATUS_ACTIVE;
+			}
+			else {
+				Val32 = SK_PNMI_RLMT_STATUS_STANDBY;
+			}
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_RLMT_TX_HELLO_CTS:
+			Val64 = pAC->Rlmt.Port[PhysPortIndex].TxHelloCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_RX_HELLO_CTS:
+			Val64 = pAC->Rlmt.Port[PhysPortIndex].RxHelloCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_TX_SP_REQ_CTS:
+			Val64 = pAC->Rlmt.Port[PhysPortIndex].TxSpHelloReqCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_RX_SP_CTS:
+			Val64 = pAC->Rlmt.Port[PhysPortIndex].RxSpHelloCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR040,
+				SK_PNMI_ERR040MSG);
+
+			pAC->Pnmi.RlmtUpdatedFlag --;
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	}
+	*pLen = Offset;
+
+	pAC->Pnmi.RlmtUpdatedFlag --;
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * MacPrivateConf - OID handler function of OIDs concerning the configuration
+ *
+ * Description:
+ *	Get/Presets/Sets the OIDs concerning the configuration.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+static int MacPrivateConf(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex) /* Index to the Id table */
+{
+	unsigned int	PhysPortMax;
+	unsigned int	PhysPortIndex;
+	unsigned int	LogPortMax;
+	unsigned int	LogPortIndex;
+	unsigned int	Limit;
+	unsigned int	Offset;
+	char		Val8;
+	int		Ret;
+	SK_EVPARA	EventParam;
+
+
+	/*
+	 * Calculate instance if wished. MAC index 0 is the virtual
+	 * MAC.
+	 */
+	PhysPortMax = pAC->GIni.GIMacsFound;
+	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+
+	if ((Instance != (SK_U32)(-1))) {
+
+		if ((Instance < 1) || (Instance > LogPortMax)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+
+		LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
+		Limit = LogPortIndex + 1;
+	}
+	else {
+		LogPortIndex = 0;
+		Limit = LogPortMax;
+	}
+
+	/*
+	 * Perform action
+	 */
+	if (Action == SK_PNMI_GET) {
+
+		/*
+		 * Check length
+		 */
+		switch (Id) {
+
+		case OID_SKGE_PMD:
+		case OID_SKGE_CONNECTOR:
+		case OID_SKGE_LINK_CAP:
+		case OID_SKGE_LINK_MODE:
+		case OID_SKGE_LINK_MODE_STATUS:
+		case OID_SKGE_LINK_STATUS:
+		case OID_SKGE_FLOWCTRL_CAP:
+		case OID_SKGE_FLOWCTRL_MODE:
+		case OID_SKGE_FLOWCTRL_STATUS:
+		case OID_SKGE_PHY_OPERATION_CAP:
+		case OID_SKGE_PHY_OPERATION_MODE:
+		case OID_SKGE_PHY_OPERATION_STATUS:
+			if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U8)) {
+
+				*pLen = (Limit - LogPortIndex) *
+					sizeof(SK_U8);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR041,
+				SK_PNMI_ERR041MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		/*
+		 * Update statistic and increment semaphore to indicate
+		 * that an update was already done.
+		 */
+		if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+			*pLen = 0;
+			return (Ret);
+		}
+		pAC->Pnmi.SirqUpdatedFlag ++;
+
+		/*
+		 * Get value
+		 */
+		Offset = 0;
+		for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+			switch (Id) {
+
+			case OID_SKGE_PMD:
+				*(pBuf + Offset) = pAC->Pnmi.PMD;
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_CONNECTOR:
+				*(pBuf + Offset) = pAC->Pnmi.Connector;
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_LINK_CAP:
+				if (LogPortIndex == 0) {
+
+					/* Get value for virtual port */
+					VirtualConf(pAC, IoC, Id, pBuf +
+						Offset);
+				}
+				else {
+					/* Get value for physical ports */
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+						pAC, LogPortIndex);
+
+					*(pBuf + Offset) = pAC->GIni.GP[
+						PhysPortIndex].PLinkCap;
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_LINK_MODE:
+				if (LogPortIndex == 0) {
+
+					/* Get value for virtual port */
+					VirtualConf(pAC, IoC, Id, pBuf +
+						Offset);
+				}
+				else {
+					/* Get value for physical ports */
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+						pAC, LogPortIndex);
+
+					*(pBuf + Offset) = pAC->GIni.GP[
+						PhysPortIndex].PLinkModeConf;
+				}
+
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_LINK_MODE_STATUS:
+				if (LogPortIndex == 0) {
+
+					/* Get value for virtual port */
+					VirtualConf(pAC, IoC, Id, pBuf +
+						Offset);
+				}
+				else {
+					/* Get value for physical port */
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+						pAC, LogPortIndex);
+
+					*(pBuf + Offset) =
+						CalculateLinkModeStatus(pAC,
+							IoC, PhysPortIndex);
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_LINK_STATUS:
+				if (LogPortIndex == 0) {
+
+					/* Get value for virtual port */
+					VirtualConf(pAC, IoC, Id, pBuf +
+						Offset);
+				}
+				else {
+					/* Get value for physical ports */
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+						pAC, LogPortIndex);
+
+					*(pBuf + Offset) =
+						CalculateLinkStatus(pAC,
+							IoC, PhysPortIndex);
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_FLOWCTRL_CAP:
+				if (LogPortIndex == 0) {
+
+					/* Get value for virtual port */
+					VirtualConf(pAC, IoC, Id, pBuf +
+						Offset);
+				}
+				else {
+					/* Get value for physical ports */
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+						pAC, LogPortIndex);
+
+					*(pBuf + Offset) = pAC->GIni.GP[
+						PhysPortIndex].PFlowCtrlCap;
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_FLOWCTRL_MODE:
+				if (LogPortIndex == 0) {
+
+					/* Get value for virtual port */
+					VirtualConf(pAC, IoC, Id, pBuf +
+						Offset);
+				}
+				else {
+					/* Get value for physical port */
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+						pAC, LogPortIndex);
+
+					*(pBuf + Offset) = pAC->GIni.GP[
+						PhysPortIndex].PFlowCtrlMode;
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_FLOWCTRL_STATUS:
+				if (LogPortIndex == 0) {
+
+					/* Get value for virtual port */
+					VirtualConf(pAC, IoC, Id, pBuf +
+						Offset);
+				}
+				else {
+					/* Get value for physical port */
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+						pAC, LogPortIndex);
+
+					*(pBuf + Offset) = pAC->GIni.GP[
+						PhysPortIndex].PFlowCtrlStatus;
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_PHY_OPERATION_CAP:
+				if (LogPortIndex == 0) {
+
+					/* Get value for virtual port */
+					VirtualConf(pAC, IoC, Id, pBuf +
+						Offset);
+				}
+				else {
+					/* Get value for physical ports */
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+						pAC, LogPortIndex);
+
+					*(pBuf + Offset) = pAC->GIni.GP[
+						PhysPortIndex].PMSCap;
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_PHY_OPERATION_MODE:
+				if (LogPortIndex == 0) {
+
+					/* Get value for virtual port */
+					VirtualConf(pAC, IoC, Id, pBuf +
+						Offset);
+				}
+				else {
+					/* Get value for physical port */
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+						pAC, LogPortIndex);
+
+					*(pBuf + Offset) = pAC->GIni.GP[
+						PhysPortIndex].PMSMode;
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_PHY_OPERATION_STATUS:
+				if (LogPortIndex == 0) {
+
+					/* Get value for virtual port */
+					VirtualConf(pAC, IoC, Id, pBuf +
+						Offset);
+				}
+				else {
+					/* Get value for physical port */
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+						pAC, LogPortIndex);
+
+					*(pBuf + Offset) = pAC->GIni.GP[
+						PhysPortIndex].PMSStatus;
+				}
+				Offset += sizeof(char);
+				break;
+
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR042,
+					SK_PNMI_ERR042MSG);
+
+				pAC->Pnmi.SirqUpdatedFlag --;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+		}
+		*pLen = Offset;
+		pAC->Pnmi.SirqUpdatedFlag --;
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	/*
+	 * From here SET or PRESET action. Check if the passed
+	 * buffer length is plausible.
+	 */
+	switch (Id) {
+
+	case OID_SKGE_LINK_MODE:
+	case OID_SKGE_FLOWCTRL_MODE:
+		if (*pLen < Limit - LogPortIndex) {
+
+			*pLen = Limit - LogPortIndex;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		if (*pLen != Limit - LogPortIndex) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+		break;
+
+	default:
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Perform preset or set
+	 */
+	Offset = 0;
+	for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+		switch (Id) {
+
+		case OID_SKGE_LINK_MODE:
+			/* Check the value range */
+			Val8 = *(pBuf + Offset);
+			if (Val8 == 0) {
+
+				Offset += sizeof(char);
+				break;
+			}
+			if (Val8 < SK_LMODE_HALF ||
+				Val8 > SK_LMODE_AUTOSENSE) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			if (LogPortIndex == 0) {
+
+				/*
+				 * The virtual port consists of all currently
+				 * active ports. Find them and send an event
+				 * with the new link mode to SIRQ.
+				 */
+				for (PhysPortIndex = 0;
+					PhysPortIndex < PhysPortMax;
+					PhysPortIndex ++) {
+
+					if (!pAC->Pnmi.Port[PhysPortIndex].
+						ActiveFlag) {
+
+						continue;
+					}
+
+					EventParam.Para32[0] = PhysPortIndex;
+					EventParam.Para32[1] = (SK_U32)Val8;
+					if (SkGeSirqEvent(pAC, IoC,
+						SK_HWEV_SET_LMODE,
+						EventParam) > 0) {
+
+						SK_ERR_LOG(pAC, SK_ERRCL_SW,
+							SK_PNMI_ERR043,
+							SK_PNMI_ERR043MSG);
+
+						*pLen = 0;
+						return (SK_PNMI_ERR_GENERAL);
+					}
+				}
+			}
+			else {
+				/*
+				 * Send an event with the new link mode to
+				 * the SIRQ module.
+				 */
+				EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+					pAC, LogPortIndex);
+				EventParam.Para32[1] = (SK_U32)Val8;
+				if (SkGeSirqEvent(pAC, IoC, SK_HWEV_SET_LMODE,
+					EventParam) > 0) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR043,
+						SK_PNMI_ERR043MSG);
+
+					*pLen = 0;
+					return (SK_PNMI_ERR_GENERAL);
+				}
+			}
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_FLOWCTRL_MODE:
+			/* Check the value range */
+			Val8 = *(pBuf + Offset);
+			if (Val8 == 0) {
+
+				Offset += sizeof(char);
+				break;
+			}
+			if (Val8 < SK_FLOW_MODE_NONE ||
+				Val8 > SK_FLOW_MODE_SYM_OR_REM) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			if (LogPortIndex == 0) {
+
+				/*
+				 * The virtual port consists of all currently
+				 * active ports. Find them and send an event
+				 * with the new flow control mode to SIRQ.
+				 */
+				for (PhysPortIndex = 0;
+					PhysPortIndex < PhysPortMax;
+					PhysPortIndex ++) {
+
+					if (!pAC->Pnmi.Port[PhysPortIndex].
+						ActiveFlag) {
+
+						continue;
+					}
+
+					EventParam.Para32[0] = PhysPortIndex;
+					EventParam.Para32[1] = (SK_U32)Val8;
+					if (SkGeSirqEvent(pAC, IoC,
+						SK_HWEV_SET_FLOWMODE,
+						EventParam) > 0) {
+
+						SK_ERR_LOG(pAC, SK_ERRCL_SW,
+							SK_PNMI_ERR044,
+							SK_PNMI_ERR044MSG);
+
+						*pLen = 0;
+						return (SK_PNMI_ERR_GENERAL);
+					}
+				}
+			}
+			else {
+				/*
+				 * Send an event with the new flow control
+				 * mode to the SIRQ module.
+				 */
+				EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+					pAC, LogPortIndex);
+				EventParam.Para32[1] = (SK_U32)Val8;
+				if (SkGeSirqEvent(pAC, IoC,
+					SK_HWEV_SET_FLOWMODE, EventParam)
+					> 0) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR044,
+						SK_PNMI_ERR044MSG);
+
+					*pLen = 0;
+					return (SK_PNMI_ERR_GENERAL);
+				}
+			}
+			Offset += sizeof(char);
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR045,
+				SK_PNMI_ERR045MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Monitor - OID handler function for RLMT_MONITOR_XXX
+ *
+ * Description:
+ *	Because RLMT currently does not support the monitoring of
+ *	remote adapter cards, we return always an empty table.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+static int Monitor(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex) /* Index to the Id table */
+{
+	unsigned int	Index;
+	unsigned int	Limit;
+	unsigned int	Offset;
+	unsigned int	Entries;
+
+	
+	/*
+	 * Calculate instance if wished.
+	 */
+/* XXX Not yet implemented. Return always an empty table. */
+	Entries = 0;
+
+	if ((Instance != (SK_U32)(-1))) {
+
+		if ((Instance < 1) || (Instance > Entries)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+
+		Index = (unsigned int)Instance - 1;
+		Limit = (unsigned int)Instance;
+	}
+	else {
+		Index = 0;
+		Limit = Entries;
+	}
+
+	/*
+	 * Get/Set value
+	*/
+	if (Action == SK_PNMI_GET) {
+
+		for (Offset=0; Index < Limit; Index ++) {
+
+			switch (Id) {
+
+			case OID_SKGE_RLMT_MONITOR_INDEX:
+			case OID_SKGE_RLMT_MONITOR_ADDR:
+			case OID_SKGE_RLMT_MONITOR_ERRS:
+			case OID_SKGE_RLMT_MONITOR_TIMESTAMP:
+			case OID_SKGE_RLMT_MONITOR_ADMIN:
+				break;
+
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR046,
+					SK_PNMI_ERR046MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+		}
+		*pLen = Offset;
+	}
+	else {
+		/* Only MONITOR_ADMIN can be set */
+		if (Id != OID_SKGE_RLMT_MONITOR_ADMIN) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_READ_ONLY);
+		}
+
+		/* Check if the length is plausible */
+		if (*pLen < (Limit - Index)) {
+
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		/* Okay, we have a wide value range */
+		if (*pLen != (Limit - Index)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+/*
+		for (Offset=0; Index < Limit; Index ++) {
+		}
+*/
+/*
+ * XXX Not yet implemented. Return always BAD_VALUE, because the table
+ * is empty.
+ */
+		*pLen = 0;
+		return (SK_PNMI_ERR_BAD_VALUE);
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * VirtualConf - Calculates the values of configuration OIDs for virtual port
+ *
+ * Description:
+ *	We handle here the get of the configuration group OIDs, which are
+ *	a little bit complicated. The virtual port consists of all currently
+ *	active physical ports. If multiple ports are active and configured
+ *	differently we get in some trouble to return a single value. So we
+ *	get the value of the first active port and compare it with that of
+ *	the other active ports. If they are not the same, we return a value
+ *	that indicates that the state is indeterminated.
+ *
+ * Returns:
+ *	Nothing
+ */
+
+static void VirtualConf(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf)		/* Buffer to which to mgmt data will be retrieved */
+{
+	unsigned int	PhysPortMax;
+	unsigned int	PhysPortIndex;
+	SK_U8		Val8;
+	SK_BOOL		PortActiveFlag;
+
+
+	*pBuf = 0;
+	PortActiveFlag = SK_FALSE;
+	PhysPortMax = pAC->GIni.GIMacsFound;
+
+	for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
+		PhysPortIndex ++) {
+
+		/* Check if the physical port is active */
+		if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+			continue;
+		}
+
+		PortActiveFlag = SK_TRUE;
+
+		switch (Id) {
+
+		case OID_SKGE_LINK_CAP:
+
+			/*
+			 * Different capabilities should not happen, but
+			 * in the case of the cases OR them all together.
+			 * From a curious point of view the virtual port
+			 * is capable of all found capabilities.
+			 */
+			*pBuf |= pAC->GIni.GP[PhysPortIndex].PLinkCap;
+			break;
+
+		case OID_SKGE_LINK_MODE:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].
+					PLinkModeConf;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different link
+			 * mode than the first one we return a value that
+			 * indicates that the link mode is indeterminated.
+			 */
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].PLinkModeConf
+				) {
+
+				*pBuf = SK_LMODE_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_LINK_MODE_STATUS:
+			/* Get the link mode of the physical port */
+			Val8 = CalculateLinkModeStatus(pAC, IoC,
+				PhysPortIndex);
+
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = Val8;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different link
+			 * mode status than the first one we return a value
+			 * that indicates that the link mode status is
+			 * indeterminated.
+			 */
+			if (*pBuf != Val8) {
+
+				*pBuf = SK_LMODE_STAT_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_LINK_STATUS:
+			/* Get the link status of the physical port */
+			Val8 = CalculateLinkStatus(pAC, IoC, PhysPortIndex);
+
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = Val8;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different link
+			 * status than the first one, we return a value
+			 * that indicates that the link status is
+			 * indeterminated.
+			 */
+			if (*pBuf != Val8) {
+
+				*pBuf = SK_PNMI_RLMT_LSTAT_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_FLOWCTRL_CAP:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].
+					PFlowCtrlCap;
+				continue;
+			}
+
+			/*
+			 * From a curious point of view the virtual port
+			 * is capable of all found capabilities.
+			 */
+			*pBuf |= pAC->GIni.GP[PhysPortIndex].PFlowCtrlCap;
+			break;
+
+		case OID_SKGE_FLOWCTRL_MODE:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].
+					PFlowCtrlMode;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different flow
+			 * control mode than the first one, we return a value
+			 * that indicates that the mode is indeterminated.
+			 */
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].
+				PFlowCtrlMode) {
+
+				*pBuf = SK_FLOW_MODE_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_FLOWCTRL_STATUS:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].
+					PFlowCtrlStatus;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different flow
+			 * control status than the first one, we return a
+			 * value that indicates that the status is
+			 * indeterminated.
+			 */
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].
+				PFlowCtrlStatus) {
+
+				*pBuf = SK_FLOW_STAT_INDETERMINATED;
+			}
+			break;
+		case OID_SKGE_PHY_OPERATION_CAP:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].
+					PMSCap;
+				continue;
+			}
+
+			/*
+			 * From a curious point of view the virtual port
+			 * is capable of all found capabilities.
+			 */
+			*pBuf |= pAC->GIni.GP[PhysPortIndex].PMSCap;
+			break;
+
+		case OID_SKGE_PHY_OPERATION_MODE:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].
+					PMSMode;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different master/
+			 * slave mode than the first one, we return a value
+			 * that indicates that the mode is indeterminated.
+			 */
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].
+				PMSMode) {
+
+				*pBuf = SK_MS_MODE_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_PHY_OPERATION_STATUS:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].
+					PMSStatus;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different master/
+			 * slave status than the first one, we return a
+			 * value that indicates that the status is
+			 * indeterminated.
+			 */
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].
+				PMSStatus) {
+
+				*pBuf = SK_MS_STAT_INDETERMINATED;
+			}
+			break;
+		}
+	}
+
+	/*
+	 * If no port is active return an indeterminated answer
+	 */
+	if (!PortActiveFlag) {
+
+		switch (Id) {
+
+		case OID_SKGE_LINK_CAP:
+			*pBuf = SK_LMODE_CAP_INDETERMINATED;
+			break;
+
+		case OID_SKGE_LINK_MODE:
+			*pBuf = SK_LMODE_INDETERMINATED;
+			break;
+
+		case OID_SKGE_LINK_MODE_STATUS:
+			*pBuf = SK_LMODE_STAT_INDETERMINATED;
+			break;
+
+		case OID_SKGE_LINK_STATUS:
+			*pBuf = SK_PNMI_RLMT_LSTAT_INDETERMINATED;
+			break;
+
+		case OID_SKGE_FLOWCTRL_CAP:
+		case OID_SKGE_FLOWCTRL_MODE:
+			*pBuf = SK_FLOW_MODE_INDETERMINATED;
+			break;
+
+		case OID_SKGE_FLOWCTRL_STATUS:
+			*pBuf = SK_FLOW_STAT_INDETERMINATED;
+			break;
+			
+		case OID_SKGE_PHY_OPERATION_CAP:
+			*pBuf = SK_MS_CAP_INDETERMINATED;
+			break;
+
+		case OID_SKGE_PHY_OPERATION_MODE:
+			*pBuf = SK_MS_MODE_INDETERMINATED;
+			break;
+
+		case OID_SKGE_PHY_OPERATION_STATUS:
+			*pBuf = SK_MS_STAT_INDETERMINATED;
+			break;
+		}
+	}
+}
+
+/*****************************************************************************
+ *
+ * CalculateLinkStatus - Determins the link status of a physical port
+ *
+ * Description:
+ *	Determins the link status the following way:
+ *	  LSTAT_PHY_DOWN:  Link is down
+ *	  LSTAT_AUTONEG:   Auto-negotiation failed
+ *	  LSTAT_LOG_DOWN:  Link is up but RLMT did not yet put the port
+ *	                   logically up.
+ *	  LSTAT_LOG_UP:    RLMT marked the port as up
+ *
+ * Returns:
+ *	Link status of physical port
+ */
+
+static SK_U8 CalculateLinkStatus(
+SK_AC *pAC,			/* Pointer to adapter context */
+SK_IOC IoC,			/* IO context handle */
+unsigned int PhysPortIndex)	/* Physical port index */
+{
+	SK_U8	Result;
+
+
+	if (!pAC->GIni.GP[PhysPortIndex].PHWLinkUp) {
+
+		Result = SK_PNMI_RLMT_LSTAT_PHY_DOWN;
+	}
+	else if (pAC->GIni.GP[PhysPortIndex].PAutoNegFail > 0) {
+
+		Result = SK_PNMI_RLMT_LSTAT_AUTONEG;
+				}
+	else if (!pAC->Rlmt.Port[PhysPortIndex].PortDown) {
+
+		Result = SK_PNMI_RLMT_LSTAT_LOG_UP;
+	}
+	else {
+		Result = SK_PNMI_RLMT_LSTAT_LOG_DOWN;
+	}
+
+	return (Result);
+}
+
+/*****************************************************************************
+ *
+ * CalculateLinkModeStatus - Determins the link mode status of a phys. port
+ *
+ * Description:
+ *	The COMMON module only tells us if the mode is half or full duplex.
+ *	But in the decade of auto sensing it is usefull for the user to
+ *	know if the mode was negotiated or forced. Therefore we have a
+ *	look to the mode, which was last used by the negotiation process.
+ *
+ * Returns:
+ *	The link mode status
+ */
+
+static SK_U8 CalculateLinkModeStatus(
+SK_AC *pAC,			/* Pointer to adapter context */
+SK_IOC IoC,			/* IO context handle */
+unsigned int PhysPortIndex)	/* Physical port index */
+{
+	SK_U8	Result;
+
+
+	/* Get the current mode, which can be full or half duplex */
+	Result = pAC->GIni.GP[PhysPortIndex].PLinkModeStatus;
+
+	/* Check if no valid mode could be found (link is down) */
+	if (Result < SK_LMODE_STAT_HALF) {
+
+		Result = SK_LMODE_STAT_UNKNOWN;
+	} 
+	else if (pAC->GIni.GP[PhysPortIndex].PLinkMode >= SK_LMODE_AUTOHALF) {
+
+		/*
+		 * Auto-negotiation was used to bring up the link. Change
+		 * the already found duplex status that it indicates
+		 * auto-negotiation was involved.
+		 */
+		if (Result == SK_LMODE_STAT_HALF) {
+
+			Result = SK_LMODE_STAT_AUTOHALF;
+		}
+		else if (Result == SK_LMODE_STAT_FULL) {
+
+			Result = SK_LMODE_STAT_AUTOFULL;
+		}
+	}
+
+	return (Result);
+}
+
+/*****************************************************************************
+ *
+ * GetVpdKeyArr - Obtain an array of VPD keys
+ *
+ * Description:
+ *	Read the VPD keys and build an array of VPD keys, which are
+ *	easy to access.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK	     Task successfully performed.
+ *	SK_PNMI_ERR_GENERAL  Something went wrong.
+ */
+
+static int GetVpdKeyArr(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+char *pKeyArr,		/* Ptr KeyArray */
+unsigned int KeyArrLen,	/* Length of array in bytes */
+unsigned int *pKeyNo)	/* Number of keys */
+{
+	unsigned int		BufKeysLen = 128;
+	char			BufKeys[128];
+	unsigned int		StartOffset;
+	unsigned int		Offset;
+	int			Index;
+	int			Ret;
+
+
+	SK_MEMSET(pKeyArr, 0, KeyArrLen);
+
+	/*
+	 * Get VPD key list
+	 */
+	Ret = VpdKeys(pAC, IoC, (char *)&BufKeys, (int *)&BufKeysLen,
+		(int *)pKeyNo);
+	if (Ret > 0) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR014,
+			SK_PNMI_ERR014MSG);
+
+		return (SK_PNMI_ERR_GENERAL);
+	}
+	/* If no keys are available return now */
+	if (*pKeyNo == 0 || BufKeysLen == 0) {
+
+		return (SK_PNMI_ERR_OK);
+	}
+	/*
+	 * If the key list is too long for us trunc it and give a
+	 * errorlog notification. This case should not happen because
+	 * the maximum number of keys is limited due to RAM limitations
+	 */
+	if (*pKeyNo > SK_PNMI_VPD_ARR_SIZE) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR015,
+			SK_PNMI_ERR015MSG);
+
+		*pKeyNo = SK_PNMI_VPD_ARR_SIZE;
+	}
+
+	/*
+	 * Now build an array of fixed string length size and copy
+	 * the keys together.
+	 */
+	for (Index = 0, StartOffset = 0, Offset = 0; Offset < BufKeysLen;
+		Offset ++) {
+
+		if (BufKeys[Offset] != 0) {
+
+			continue;
+		}
+
+		if (Offset - StartOffset > SK_PNMI_VPD_STR_SIZE) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR016,
+				SK_PNMI_ERR016MSG);
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_STR_SIZE,
+			&BufKeys[StartOffset], SK_PNMI_VPD_STR_SIZE);
+
+		Index ++;
+		StartOffset = Offset + 1;
+	}
+
+	/* Last key not zero terminated? Get it anyway */
+	if (StartOffset < Offset) {
+
+		SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_STR_SIZE,
+			&BufKeys[StartOffset], SK_PNMI_VPD_STR_SIZE);
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * SirqUpdate - Let the SIRQ update its internal values
+ *
+ * Description:
+ *	Just to be sure that the SIRQ module holds its internal data
+ *	structures up to date, we send an update event before we make
+ *	any access.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK	     Task successfully performed.
+ *	SK_PNMI_ERR_GENERAL  Something went wrong.
+ */
+
+static int SirqUpdate(
+SK_AC *pAC,	/* Pointer to adapter context */
+SK_IOC IoC)	/* IO context handle */
+{
+	SK_EVPARA	EventParam;
+
+
+	/* Was the module already updated during the current PNMI call? */
+	if (pAC->Pnmi.SirqUpdatedFlag > 0) {
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	/* Send an synchronuous update event to the module */
+	SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+	if (SkGeSirqEvent(pAC, IoC, SK_HWEV_UPDATE_STAT, EventParam) > 0) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR047,
+			SK_PNMI_ERR047MSG);
+
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * RlmtUpdate - Let the RLMT update its internal values
+ *
+ * Description:
+ *	Just to be sure that the RLMT module holds its internal data
+ *	structures up to date, we send an update event before we make
+ *	any access.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK	     Task successfully performed.
+ *	SK_PNMI_ERR_GENERAL  Something went wrong.
+ */
+
+static int RlmtUpdate(
+SK_AC *pAC,	/* Pointer to adapter context */
+SK_IOC IoC)	/* IO context handle */
+{
+	SK_EVPARA	EventParam;
+
+
+	/* Was the module already updated during the current PNMI call? */
+	if (pAC->Pnmi.RlmtUpdatedFlag > 0) {
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	/* Send an synchronuous update event to the module */
+	SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+	if (SkRlmtEvent(pAC, IoC, SK_RLMT_STATS_UPDATE, EventParam) > 0) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR048,
+			SK_PNMI_ERR048MSG);
+
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * MacUpdate - Force the XMAC to output the current statistic
+ *
+ * Description:
+ *	The XMAC holds its statistic internally. To obtain the current
+ *	values we must send a command so that the statistic data will
+ *	be written to a predefined memory area on the adapter. 
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK	     Task successfully performed.
+ *	SK_PNMI_ERR_GENERAL  Something went wrong.
+ */
+
+static int MacUpdate(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+unsigned int FirstMac,	/* Index of the first Mac to be updated */
+unsigned int LastMac)	/* Index of the last Mac to be updated */
+{
+	unsigned int	MacIndex;
+	SK_U16		StatReg;
+	unsigned int	WaitIndex;
+
+
+	/*
+	 * Were the statistics already updated during the
+	 * current PNMI call?
+	 */
+	if (pAC->Pnmi.MacUpdatedFlag > 0) {
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	/* Send an update command to all XMACs specified */
+	for (MacIndex = FirstMac; MacIndex <= LastMac; MacIndex ++) {
+
+		StatReg = XM_SC_SNP_TXC | XM_SC_SNP_RXC;
+		XM_OUT16(IoC, MacIndex, XM_STAT_CMD, StatReg);
+
+		/*
+		 * It is an auto-clearing register. If the command bits
+		 * went to zero again, the statistics are transfered.
+		 * Normally the command should be executed immediately.
+		 * But just to be sure we execute a loop.
+		 */
+		for (WaitIndex = 0; WaitIndex < 10; WaitIndex ++) {
+
+			XM_IN16(IoC, MacIndex, XM_STAT_CMD, &StatReg);
+			if ((StatReg & (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) ==
+				0) {
+
+				break;
+			}
+		}
+		if (WaitIndex == 10 ) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_HW, SK_PNMI_ERR050,
+				SK_PNMI_ERR050MSG);
+
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * GetStatVal - Retrieve an XMAC statistic counter
+ *
+ * Description:
+ *	Retrieves the statistic counter of a virtual or physical port. The
+ *	virtual port is identified by the index 0. It consists of all
+ *	currently active ports. To obtain the counter value for this port
+ *	we must add the statistic counter of all active ports. To grant
+ *	continuous counter values for the virtual port even when port
+ *	switches occur we must additionally add a delta value, which was
+ *	calculated during a SK_PNMI_EVT_RLMT_ACTIVE_UP event.
+ *
+ * Returns:
+ *	Requested statistic value
+ */
+
+static SK_U64 GetStatVal(
+SK_AC *pAC,			/* Pointer to adapter context */
+SK_IOC IoC,			/* IO context handle */
+unsigned int LogPortIndex,	/* Index of the logical Port to be processed */
+unsigned int StatIndex)		/* Index to statistic value */
+{
+	unsigned int	PhysPortIndex;
+	unsigned int	PhysPortMax;
+	SK_U64		Val = 0;
+
+
+	if (LogPortIndex == 0) {
+
+		PhysPortMax = pAC->GIni.GIMacsFound;
+
+		/* Add counter of all active ports */
+		for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
+			PhysPortIndex ++) {
+
+			if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+				Val += GetPhysStatVal(pAC, IoC, PhysPortIndex,
+					StatIndex);
+			}
+		}
+
+		/* Correct value because of port switches */
+		Val += pAC->Pnmi.VirtualCounterOffset[StatIndex];
+	}
+	else {
+		/* Get counter value of physical port */
+		PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
+		Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
+	}
+
+	return (Val);
+}
+
+/*****************************************************************************
+ *
+ * GetPhysStatVal - Get counter value for physical port
+ *
+ * Description:
+ *	Builds a 64bit counter value. Except for the octet counters
+ *	the lower 32bit are counted in hardware and the upper 32bit
+ *	in software by monitoring counter overflow interrupts in the
+ *	event handler. To grant continous counter values during XMAC
+ *	resets (caused by a workaround) we must add a delta value.
+ *	The delta was calculated in the event handler when a
+ *	SK_PNMI_EVT_XMAC_RESET was received.
+ *
+ * Returns:
+ *	Counter value
+ */
+
+static SK_U64 GetPhysStatVal(
+SK_AC *pAC,			/* Pointer to adapter context */
+SK_IOC IoC,			/* IO context handle */
+unsigned int PhysPortIndex,	/* Index of the logical Port to be processed */
+unsigned int StatIndex)		/* Index to statistic value */
+{
+	SK_U64		Val = 0;
+	SK_U32		LowVal;
+	SK_U32		HighVal;
+
+
+	switch (StatIndex) {
+
+	case SK_PNMI_HTX_OCTET:
+		XM_IN32(IoC, PhysPortIndex, XM_TXO_OK_LO, &LowVal);
+		XM_IN32(IoC, PhysPortIndex, XM_TXO_OK_HI, &HighVal);
+		break;
+
+	case SK_PNMI_HRX_OCTET:
+		XM_IN32(IoC, PhysPortIndex, XM_RXO_OK_LO, &LowVal);
+		XM_IN32(IoC, PhysPortIndex, XM_RXO_OK_HI, &HighVal);
+		break;
+
+	case SK_PNMI_HTX_OCTETLOW:
+	case SK_PNMI_HRX_OCTETLOW:
+		return (Val);
+
+	case SK_PNMI_HTX_SYNC:
+		LowVal = (SK_U32)pAC->Pnmi.Port[PhysPortIndex].StatSyncCts;
+		HighVal = (SK_U32)
+			(pAC->Pnmi.Port[PhysPortIndex].StatSyncCts >> 32);
+		break;
+
+	case SK_PNMI_HTX_SYNC_OCTET:
+		LowVal = (SK_U32)pAC->Pnmi.Port[PhysPortIndex].
+			StatSyncOctetsCts;
+		HighVal = (SK_U32)
+			(pAC->Pnmi.Port[PhysPortIndex].StatSyncOctetsCts >>
+			32);
+		break;
+
+	case SK_PNMI_HRX_FCS:
+		/* 
+		 * Broadcom filters fcs errors and counts it in 
+		 * Receive Error Counter register
+		 */
+		if (pAC->GIni.GP[PhysPortIndex].PhyType == SK_PHY_BCOM) {
+			/* do not read while not initialized (PHY_READ hangs!)*/
+			if (pAC->GIni.GP[PhysPortIndex].PState) {
+				PHY_READ(IoC, &pAC->GIni.GP[PhysPortIndex],
+					 PhysPortIndex, PHY_BCOM_RE_CTR,
+					&LowVal);
+			}
+			else {
+				LowVal = 0;
+			}
+			HighVal = pAC->Pnmi.Port[PhysPortIndex].CounterHigh[StatIndex];
+		}
+		else {
+			XM_IN32(IoC, PhysPortIndex,
+				StatAddress[StatIndex].Param, &LowVal);
+			HighVal = pAC->Pnmi.Port[PhysPortIndex].CounterHigh[StatIndex];
+		}
+	default:
+		XM_IN32(IoC, PhysPortIndex, StatAddress[StatIndex].Param,
+			&LowVal);
+		HighVal = pAC->Pnmi.Port[PhysPortIndex].CounterHigh[StatIndex];
+		break;
+	}
+
+	Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
+
+	/* Correct value because of possible XMAC reset. XMAC Errata #2 */
+	Val += pAC->Pnmi.Port[PhysPortIndex].CounterOffset[StatIndex];
+
+	return (Val);
+}
+
+/*****************************************************************************
+ *
+ * ResetCounter - Set all counters and timestamps to zero
+ *
+ * Description:
+ *	Notifies other common modules which store statistic data to
+ *	reset their counters and finally reset our own counters.
+ *
+ * Returns:
+ *	Nothing
+ */
+
+static void ResetCounter(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC)		/* IO context handle */
+{
+	unsigned int	PhysPortIndex;
+	SK_EVPARA	EventParam;
+
+
+	SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+
+	/* Notify sensor module */
+	SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_CLEAR, EventParam);
+
+	/* Notify RLMT module */
+	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STATS_CLEAR, EventParam);
+
+	/* Notify SIRQ module */
+	SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_CLEAR_STAT, EventParam);
+
+	/* Notify CSUM module */
+#ifdef SK_USE_CSUM
+	EventParam.Para64 = (SK_U64)(-1);
+	SkEventQueue(pAC, SKGE_CSUM, SK_CSUM_EVENT_CLEAR_PROTO_STATS,
+		EventParam);
+#endif
+
+	/* Clear XMAC statistic */
+	for (PhysPortIndex = 0; PhysPortIndex <
+		(unsigned int)pAC->GIni.GIMacsFound; PhysPortIndex ++) {
+
+		XM_OUT16(IoC, PhysPortIndex, XM_STAT_CMD,
+			XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+		/* Clear two times according to Errata #3 */
+		XM_OUT16(IoC, PhysPortIndex, XM_STAT_CMD,
+			XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].CounterHigh,
+			0, sizeof(pAC->Pnmi.Port[PhysPortIndex].CounterHigh));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+			CounterOffset, 0, sizeof(pAC->Pnmi.Port[
+			PhysPortIndex].CounterOffset));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].StatSyncCts,
+			0, sizeof(pAC->Pnmi.Port[PhysPortIndex].StatSyncCts));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+			StatSyncOctetsCts, 0, sizeof(pAC->Pnmi.Port[
+			PhysPortIndex].StatSyncOctetsCts));
+	}
+
+	/*
+	 * Clear local statistics
+	 */
+	pAC->Pnmi.RlmtChangeCts = 0;
+	pAC->Pnmi.RlmtChangeTime = 0;
+	SK_MEMSET((char *)&pAC->Pnmi.RlmtChangeEstimate.EstValue[0], 0,
+		sizeof(pAC->Pnmi.RlmtChangeEstimate.EstValue));
+	pAC->Pnmi.RlmtChangeEstimate.EstValueIndex = 0;
+	pAC->Pnmi.RlmtChangeEstimate.Estimate = 0;
+	pAC->Pnmi.TxSwQueueMax = 0;
+	pAC->Pnmi.TxRetryCts = 0;
+	pAC->Pnmi.RxIntrCts = 0;
+	pAC->Pnmi.TxIntrCts = 0;
+	pAC->Pnmi.RxNoBufCts = 0;
+	pAC->Pnmi.TxNoBufCts = 0;
+	pAC->Pnmi.TxUsedDescrNo = 0;
+	pAC->Pnmi.RxDeliveredCts = 0;
+	pAC->Pnmi.RxOctetsDeliveredCts = 0;
+	pAC->Pnmi.ErrRecoveryCts = 0;
+}
+
+/*****************************************************************************
+ *
+ * GetTrapEntry - Get an entry in the trap buffer
+ *
+ * Description:
+ *	The trap buffer stores various events. A user application somehow
+ *	gets notified that an event occured and retrieves the trap buffer
+ *	contens (or simply polls the buffer). The buffer is organized as
+ *	a ring which stores the newest traps at the beginning. The oldest
+ *	traps are overwritten by the newest ones. Each trap entry has a
+ *	unique number, so that applications may detect new trap entries.
+ *
+ * Returns:
+ *	A pointer to the trap entry
+ */
+
+static char* GetTrapEntry(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_U32 TrapId,		/* SNMP ID of the trap */
+unsigned int Size)	/* Space needed for trap entry */
+{
+	unsigned int		BufPad = pAC->Pnmi.TrapBufPad;
+	unsigned int		BufFree = pAC->Pnmi.TrapBufFree;
+	unsigned int		Beg = pAC->Pnmi.TrapQueueBeg;
+	unsigned int		End = pAC->Pnmi.TrapQueueEnd;
+	char			*pBuf = &pAC->Pnmi.TrapBuf[0];
+	int			Wrap;
+	unsigned int		NeededSpace;
+	unsigned int		EntrySize;
+	SK_U32			Val32;
+	SK_U64			Val64;
+
+
+	/* Last byte of entry will get a copy of the entry length */
+	Size ++;
+
+	/*
+	 * Calculate needed buffer space */
+	if (Beg >= Size) {
+
+		NeededSpace = Size;
+		Wrap = FALSE;
+	}
+	else {
+		NeededSpace = Beg + Size;
+		Wrap = TRUE;
+	}
+
+	/*
+	 * Check if enough buffer space is provided. Otherwise
+	 * free some entries. Leave one byte space between begin
+	 * and end of buffer to make it possible to detect whether
+	 * the buffer is full or empty
+	 */
+	while (BufFree < NeededSpace + 1) {
+
+		if (End == 0) {
+
+			End = SK_PNMI_TRAP_QUEUE_LEN;
+		}
+
+		EntrySize = (unsigned int)*((unsigned char *)pBuf + End - 1);
+		BufFree += EntrySize;
+		End -= EntrySize;
+#ifdef DEBUG
+		SK_MEMSET(pBuf + End, (char)(-1), EntrySize);
+#endif
+		if (End == BufPad) {
+#ifdef DEBUG
+			SK_MEMSET(pBuf, (char)(-1), End);
+#endif
+			BufFree += End;
+			End = 0;
+			BufPad = 0;
+		}
+	}
+
+	/* 
+	 * Insert new entry as first entry. Newest entries are
+	 * stored at the beginning of the queue.
+	 */
+	if (Wrap) {
+
+		BufPad = Beg;
+		Beg = SK_PNMI_TRAP_QUEUE_LEN - Size;
+	}
+	else {
+		Beg = Beg - Size;
+	}
+	BufFree -= NeededSpace;
+
+	/* Save the current offsets */
+	pAC->Pnmi.TrapQueueBeg = Beg;
+	pAC->Pnmi.TrapQueueEnd = End;
+	pAC->Pnmi.TrapBufPad = BufPad;
+	pAC->Pnmi.TrapBufFree = BufFree;
+
+	/* Initialize the trap entry */
+	*(pBuf + Beg + Size - 1) = (char)Size;
+	*(pBuf + Beg) = (char)Size;
+	Val32 = (pAC->Pnmi.TrapUnique) ++;
+	SK_PNMI_STORE_U32(pBuf + Beg + 1, Val32);
+	SK_PNMI_STORE_U32(pBuf + Beg + 1 + sizeof(SK_U32), TrapId);
+	Val64 = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+	SK_PNMI_STORE_U64(pBuf + Beg + 1 + 2 * sizeof(SK_U32), Val64);
+
+	return (pBuf + Beg);
+}
+
+/*****************************************************************************
+ *
+ * CopyTrapQueue - Copies the trap buffer for the TRAP OID
+ *
+ * Description:
+ *	On a query of the TRAP OID the trap buffer contents will be
+ *	copied continuously to the request buffer, which must be large
+ *	enough. No length check is performed.
+ *
+ * Returns:
+ *	Nothing
+ */
+
+static void CopyTrapQueue(
+SK_AC *pAC,		/* Pointer to adapter context */
+char *pDstBuf)		/* Buffer to which the queued traps will be copied */
+{
+	unsigned int	BufPad = pAC->Pnmi.TrapBufPad;
+	unsigned int	Trap = pAC->Pnmi.TrapQueueBeg;
+	unsigned int	End = pAC->Pnmi.TrapQueueEnd;
+	char		*pBuf = &pAC->Pnmi.TrapBuf[0];
+	unsigned int	Len;
+	unsigned int	DstOff = 0;
+
+
+	while (Trap != End) {
+
+		Len = (unsigned int)*(pBuf + Trap);
+
+		/*
+		 * Last byte containing a copy of the length will
+		 * not be copied.
+		 */
+		*(pDstBuf + DstOff) = (char)(Len - 1);
+		SK_MEMCPY(pDstBuf + DstOff + 1, pBuf + Trap + 1, Len - 2);
+		DstOff += Len - 1;
+
+		Trap += Len;
+		if (Trap == SK_PNMI_TRAP_QUEUE_LEN) {
+
+			Trap = BufPad;
+		}
+	}
+}
+
+/*****************************************************************************
+ *
+ * GetTrapQueueLen - Get the length of the trap buffer
+ *
+ * Description:
+ *	Evaluates the number of currently stored traps and the needed
+ *	buffer size to retrieve them.
+ *
+ * Returns:
+ *	Nothing
+ */
+
+static void GetTrapQueueLen(
+SK_AC *pAC,		/* Pointer to adapter context */
+unsigned int *pLen,	/* Length in Bytes of all queued traps */
+unsigned int *pEntries)	/* Returns number of trapes stored in queue */
+{
+	unsigned int	BufPad = pAC->Pnmi.TrapBufPad;
+	unsigned int	Trap = pAC->Pnmi.TrapQueueBeg;
+	unsigned int	End = pAC->Pnmi.TrapQueueEnd;
+	char		*pBuf = &pAC->Pnmi.TrapBuf[0];
+	unsigned int	Len;
+	unsigned int	Entries = 0;
+	unsigned int	TotalLen = 0;
+
+
+	while (Trap != End) {
+
+		Len = (unsigned int)*(pBuf + Trap);
+		TotalLen += Len - 1;
+		Entries ++;
+
+		Trap += Len;
+		if (Trap == SK_PNMI_TRAP_QUEUE_LEN) {
+
+			Trap = BufPad;
+		}
+	}
+
+	*pEntries = Entries;
+	*pLen = TotalLen;
+}
+
+/*****************************************************************************
+ *
+ * QueueSimpleTrap - Store a simple trap to the trap buffer
+ *
+ * Description:
+ *	A simple trap is a trap with now additional data. It consists
+ *	simply of a trap code.
+ *
+ * Returns:
+ *	Nothing
+ */
+
+static void QueueSimpleTrap(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_U32 TrapId)		/* Type of sensor trap */
+{
+	GetTrapEntry(pAC, TrapId, SK_PNMI_TRAP_SIMPLE_LEN);
+}
+
+/*****************************************************************************
+ *
+ * QueueSensorTrap - Stores a sensor trap in the trap buffer
+ *
+ * Description:
+ *	Gets an entry in the trap buffer and fills it with sensor related
+ *	data.
+ *
+ * Returns:
+ *	Nothing
+ */
+
+static void QueueSensorTrap(
+SK_AC *pAC,			/* Pointer to adapter context */
+SK_U32 TrapId,			/* Type of sensor trap */
+unsigned int SensorIndex)	/* Index of sensor which caused the trap */
+{
+	char		*pBuf;
+	unsigned int	Offset;
+	unsigned int	DescrLen;
+	SK_U32		Val32;
+
+
+	/* Get trap buffer entry */
+	DescrLen = SK_STRLEN(pAC->I2c.SenTable[SensorIndex].SenDesc);
+	pBuf = GetTrapEntry(pAC, TrapId,
+		SK_PNMI_TRAP_SENSOR_LEN_BASE + DescrLen);
+	Offset = SK_PNMI_TRAP_SIMPLE_LEN;
+
+	/* Store additionally sensor trap related data */
+	Val32 = OID_SKGE_SENSOR_INDEX;
+	SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+	*(pBuf + Offset + 4) = 4;
+	Val32 = (SK_U32)SensorIndex;
+	SK_PNMI_STORE_U32(pBuf + Offset + 5, Val32);
+	Offset += 9;
+	
+	Val32 = (SK_U32)OID_SKGE_SENSOR_DESCR;
+	SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+	*(pBuf + Offset + 4) = (char)DescrLen;
+	SK_MEMCPY(pBuf + Offset + 5, pAC->I2c.SenTable[SensorIndex].SenDesc,
+		DescrLen);
+	Offset += DescrLen + 5;
+
+	Val32 = OID_SKGE_SENSOR_TYPE;
+	SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+	*(pBuf + Offset + 4) = 1;
+	*(pBuf + Offset + 5) = (char)pAC->I2c.SenTable[SensorIndex].SenType;
+	Offset += 6;
+
+	Val32 = OID_SKGE_SENSOR_VALUE;
+	SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+	*(pBuf + Offset + 4) = 4;
+	Val32 = (SK_U32)pAC->I2c.SenTable[SensorIndex].SenValue;
+	SK_PNMI_STORE_U32(pBuf + Offset + 5, Val32);
+}
+
+/*****************************************************************************
+ *
+ * QueueRlmtNewMacTrap - Store a port switch trap in the trap buffer
+ *
+ * Description:
+ *	Nothing further to explain.
+ *
+ * Returns:
+ *	Nothing
+ */
+
+static void QueueRlmtNewMacTrap(
+SK_AC *pAC,		/* Pointer to adapter context */
+unsigned int ActiveMac)	/* Index (0..n) of the currently active port */
+{
+	char	*pBuf;
+	SK_U32	Val32;
+
+
+	pBuf = GetTrapEntry(pAC, OID_SKGE_TRAP_RLMT_CHANGE_PORT,
+		SK_PNMI_TRAP_RLMT_CHANGE_LEN);
+
+	Val32 = OID_SKGE_RLMT_PORT_ACTIVE;
+	SK_PNMI_STORE_U32(pBuf + SK_PNMI_TRAP_SIMPLE_LEN, Val32);
+	*(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 4) = 1;
+	*(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 5) = (char)ActiveMac;
+}
+
+/*****************************************************************************
+ *
+ * QueueRlmtPortTrap - Store port related RLMT trap to trap buffer
+ *
+ * Description:
+ *	Nothing further to explain.
+ *
+ * Returns:
+ *	Nothing
+ */
+
+static void QueueRlmtPortTrap(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_U32 TrapId,		/* Type of RLMT port trap */
+unsigned int PortIndex)	/* Index of the port, which changed its state */
+{
+	char	*pBuf;
+	SK_U32	Val32;
+
+
+	pBuf = GetTrapEntry(pAC, TrapId, SK_PNMI_TRAP_RLMT_PORT_LEN);
+
+	Val32 = OID_SKGE_RLMT_PORT_INDEX;
+	SK_PNMI_STORE_U32(pBuf + SK_PNMI_TRAP_SIMPLE_LEN, Val32);
+	*(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 4) = 1;
+	*(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 5) = (char)PortIndex;
+}
+
+/*****************************************************************************
+ *
+ * CopyMac - Copies a MAC address
+ *
+ * Description:
+ *	Nothing further to explain.
+ *
+ * Returns:
+ *	Nothing
+ */
+
+static void CopyMac(
+char *pDst,		/* Pointer to destination buffer */
+SK_MAC_ADDR *pMac)	/* Pointer of Source */
+{
+	int	i;
+
+
+	for (i = 0; i < sizeof(SK_MAC_ADDR); i ++) {
+
+		*(pDst + i) = pMac->a[i];
+	}
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/skgesirq.c linux.14p16/drivers/net/sk98lin/skgesirq.c
--- linux.vanilla/drivers/net/sk98lin/skgesirq.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/skgesirq.c	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,1921 @@
+/******************************************************************************
+ *
+ * Name:	skgesirq.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.46 $
+ * Date:	$Date: 1999/09/16 10:30:07 $
+ * Purpose:	Special IRQ module
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skge.c" for further 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 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgesirq.c,v $
+ *	Revision 1.46  1999/09/16 10:30:07  cgoos
+ *	Removed debugging output statement from Linux.
+ *	
+ *	Revision 1.45  1999/09/16 07:32:55  cgoos
+ *	Fixed dual-port copperfield bug (PHY_READ from resetted port).
+ *	Removed some unused variables.
+ *	
+ *	Revision 1.44  1999/08/03 15:25:04  cgoos
+ *	Removed workaround for disabled interrupts in half duplex mode.
+ *	
+ *	Revision 1.43  1999/08/03 14:27:58  cgoos
+ *	Removed SENSE mode code from SkGePortCheckUpBcom.
+ *	
+ *	Revision 1.42  1999/07/26 09:16:54  cgoos
+ *	Added some typecasts to avoid compiler warnings.
+ *	
+ *	Revision 1.41  1999/05/19 07:28:59  cgoos
+ *	Changes for 1000Base-T.
+ *	
+ *	Revision 1.40  1999/04/08 13:59:39  gklug
+ *	fix: problem with 3Com switches endless RESTARTs
+ *	
+ *	Revision 1.39  1999/03/08 10:10:52  gklug
+ *	fix: AutoSensing did switch to next mode even if LiPa indicated offline
+ *	
+ *	Revision 1.38  1999/03/08 09:49:03  gklug
+ *	fix: Bug using pAC instead of IoC, causing AIX problems
+ *	fix: change compare for Linux compiler bug workaround
+ *	
+ *	Revision 1.37  1999/01/28 14:51:33  gklug
+ *	fix: monitor for autosensing and extra RESETS the RX on wire counters
+ *	
+ *	Revision 1.36  1999/01/22 09:19:55  gklug
+ *	fix: Init DupMode and InitPauseMd are now called in RxTxEnable
+ *	
+ *	Revision 1.35  1998/12/11 15:22:59  gklug
+ *	chg: autosensing: check for receive if manual mode was guessed
+ *	chg: simplified workaround for XMAC errata
+ *	chg: wait additional 100 ms before link goes up.
+ *	chg: autoneg timeout to 600 ms
+ *	chg: restart autoneg even if configured to autonegotiation
+ *	
+ *	Revision 1.34  1998/12/10 10:33:14  gklug
+ *	add: more debug messages
+ *	fix: do a new InitPhy if link went down (AutoSensing problem)
+ *	chg: Check for zero shorts if link is NOT up
+ *	chg: reset Port if link goes down
+ *	chg: wait additional 100 ms when link comes up to check shorts
+ *	fix: dummy read extended autoneg status to prevent link going down immediately
+ *	
+ *	Revision 1.33  1998/12/07 12:18:29  gklug
+ *	add: refinement of autosense mode: take into account the autoneg cap of LiPa
+ *	
+ *	Revision 1.32  1998/12/07 07:11:21  gklug
+ *	fix: compiler warning
+ *	
+ *	Revision 1.31  1998/12/02 09:29:05  gklug
+ *	fix: WA XMAC Errata: FCSCt check was not correct.
+ *	fix: WA XMAC Errata: Prec Counter were NOT updated in case of short checks.
+ *	fix: Clear Stat : now clears the Prev counters of all known Ports
+ *	
+ *	Revision 1.30  1998/12/01 10:54:15  gklug
+ *	dd: workaround for XMAC errata changed. Check RX count and CRC err Count, too.
+ *	
+ *	Revision 1.29  1998/12/01 10:01:53  gklug
+ *	fix: if MAC IRQ occurs during port down, this will be handled correctly
+ *	
+ *	Revision 1.28  1998/11/26 16:22:11  gklug
+ *	fix: bug in autosense if manual modes are used
+ *	
+ *	Revision 1.27  1998/11/26 15:50:06  gklug
+ *	fix: PNMI needs to set PLinkModeConf
+ *	
+ *	Revision 1.26  1998/11/26 14:51:58  gklug
+ *	add: AutoSensing functionalty
+ *	
+ *	Revision 1.25  1998/11/26 07:34:37  gklug
+ *	fix: Init PrevShorts when restarting port due to Link connection
+ *	
+ *	Revision 1.24  1998/11/25 10:57:32  gklug
+ *	fix: remove unreferenced local vars
+ *	
+ *	Revision 1.23  1998/11/25 08:26:40  gklug
+ *	fix: don't do a RESET on a starting or stopping port
+ *	
+ *	Revision 1.22  1998/11/24 13:29:44  gklug
+ *	add: Workaround for MAC parity errata
+ *	
+ *	Revision 1.21  1998/11/18 15:31:06  gklug
+ *	fix: lint bugs
+ *	
+ *	Revision 1.20  1998/11/18 12:58:54  gklug
+ *	fix: use PNMI query instead of hardware access
+ *	
+ *	Revision 1.19  1998/11/18 12:54:55  gklug
+ *	chg: add new workaround for XMAC Errata
+ *	add: short event counter monitoring on active link too
+ *	
+ *	Revision 1.18  1998/11/13 14:27:41  malthoff
+ *	Bug Fix: Packet Arbiter Timeout was not cleared correctly
+ *	for timeout on TX1 and TX2.
+ *	
+ *	Revision 1.17  1998/11/04 07:01:59  cgoos
+ *	Moved HW link poll sequence.
+ *	Added call to SkXmRxTxEnable.
+ *	
+ *	Revision 1.16  1998/11/03 13:46:03  gklug
+ *	add: functionality of SET_LMODE and SET_FLOW_MODE
+ *	fix: send RLMT LinkDown event when Port stop is given with LinkUp
+ *	
+ *	Revision 1.15  1998/11/03 12:56:47  gklug
+ *	fix: Needs more events
+ *	
+ *	Revision 1.14  1998/10/30 07:36:35  gklug
+ *	rmv: unnecessary code
+ *	
+ *	Revision 1.13  1998/10/29 15:21:57  gklug
+ *	add: Poll link feature for activating HW link
+ *	fix: Deactivate HWLink when Port STOP is given
+ *	
+ *	Revision 1.12  1998/10/28 07:38:57  cgoos
+ *	Checking link status at begin of SkHWLinkUp.
+ *	
+ *	Revision 1.11  1998/10/22 09:46:50  gklug
+ *	fix SysKonnectFileId typo
+ *	
+ *	Revision 1.10  1998/10/14 13:57:47  gklug
+ *	add: Port start/stop event
+ *	
+ *	Revision 1.9  1998/10/14 05:48:29  cgoos
+ *	Added definition for Para.
+ *	
+ *	Revision 1.8  1998/10/14 05:40:09  gklug
+ *	add: Hardware Linkup signal used
+ *	
+ *	Revision 1.7  1998/10/09 06:50:20  malthoff
+ *	Remove ID_sccs by SysKonnectFileId.
+ *
+ *	Revision 1.6  1998/10/08 09:11:49  gklug
+ *	add: clear IRQ commands
+ *	
+ *	Revision 1.5  1998/10/02 14:27:35  cgoos
+ *	Fixed some typos and wrong event names.
+ *	
+ *	Revision 1.4  1998/10/02 06:24:17  gklug
+ *	add: HW error function
+ *	fix: OUT macros
+ *	
+ *	Revision 1.3  1998/10/01 07:03:00  gklug
+ *	add: ISR for the usual interrupt source register
+ *	
+ *	Revision 1.2  1998/09/03 13:50:33  gklug
+ *	add: function prototypes
+ *	
+ *	Revision 1.1  1998/08/27 11:50:21  gklug
+ *	initial revision
+ *	
+ *
+ *
+ ******************************************************************************/
+
+
+/*
+	Special Interrupt handler
+
+	The following abstract should show how this module is included
+	in the driver path:
+
+	In the ISR of the driver the bits for frame transmission complete and
+	for receive complete are checked and handled by the driver itself.
+	The bits of the slow path mask are checked after this and then the
+	entry into the so-called "slow path" is prepared. It is an implemetors
+	decision whether this is executed directly or just scheduled by
+	disabling the mask. In the interrupt service routine events may be
+	generated, so it would be a good idea to call the EventDispatcher
+	right after this ISR.
+
+	The Interrupt service register of the adapter is NOT read by this
+	module. SO if the drivers implemetor needs a while loop around the
+	slow data paths Interrupt bits, he needs to call the SkGeIsr() for
+	each loop entered.
+
+	However, the XMAC Interrupt status registers are read in a while loop.
+
+*/
+static const char SysKonnectFileId[] =
+	"$Id: skgesirq.c,v 1.46 1999/09/16 10:30:07 cgoos Exp $" ;
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/skgepnmi.h"		/* PNMI Definitions */
+#include "h/skrlmt.h"		/* RLMT Definitions */
+#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
+
+
+/* local function prototypes */
+static int	SkGePortCheckUpXmac(SK_AC*, SK_IOC, int);
+static int	SkGePortCheckUpBcom(SK_AC*, SK_IOC, int);
+static int	SkGePortCheckUpLone(SK_AC*, SK_IOC, int);
+static int	SkGePortCheckUpNat(SK_AC*, SK_IOC, int);
+static void	SkPhyIsrBcom(SK_AC*, SK_IOC, int, SK_U16);
+static void	SkPhyIsrLone(SK_AC*, SK_IOC, int, SK_U16);
+
+
+#ifdef __C2MAN__
+/*
+	Special IRQ function
+
+	General Description:
+
+ */
+intro()
+{}
+#endif
+
+/*
+ * Define return codes of SkGePortCheckUp and CheckShort
+ */
+#define	SK_HW_PS_NONE		0	/* No action needed */
+#define	SK_HW_PS_RESTART	1	/* Restart needed */
+#define	SK_HW_PS_LINK		2	/* Link Up actions needed */
+
+/******************************************************************************
+ *
+ *	SkHWInitDefSense() - Default Autosensing mode initialization
+ *
+ * Description:
+ *	This function handles the Hardware link down signal
+ *
+ * Note:
+ *
+ */
+void	SkHWInitDefSense(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port] ;
+
+	pPrt->PAutoNegTimeOut = 0;
+
+	if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) {
+		pPrt->PLinkMode = pPrt->PLinkModeConf;
+		return;
+	}
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
+		("AutoSensing: First mode %d on Port %d\n",
+		(int) SK_LMODE_AUTOFULL,
+		 Port));
+
+	pPrt->PLinkMode = SK_LMODE_AUTOFULL;
+
+	return;
+}
+
+/******************************************************************************
+ *
+ *	SkHWSenseGetNext() - GetNextAutosensing Mode
+ *
+ * Description:
+ *	This function handles the AutoSensing
+ *
+ * Note:
+ *
+ */
+SK_U8	SkHWSenseGetNext(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port] ;
+
+	pPrt->PAutoNegTimeOut = 0;
+
+	if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) {
+		/* Leave all as configured */
+		return(pPrt->PLinkModeConf);
+	}
+
+	if (pPrt->PLinkMode == SK_LMODE_AUTOFULL) {
+		/* Return next mode AUTOBOTH */
+		return(SK_LMODE_AUTOBOTH);
+	}
+
+	/* Return default autofull */
+	return(SK_LMODE_AUTOFULL);
+}
+
+/******************************************************************************
+ *
+ *	SkHWSenseSetNext() - Autosensing Set next mode
+ *
+ * Description:
+ *	This function sets the appropriate next mode.
+ *
+ * Note:
+ *
+ */
+void	SkHWSenseSetNext(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_U8	NewMode)	/* New Mode to be written in sense mode */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port] ;
+
+	pPrt->PAutoNegTimeOut = 0;
+
+	if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) {
+		return;
+	}
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
+		("AutoSensing: next mode %d on Port %d\n", (int) NewMode,
+		 Port));
+	pPrt->PLinkMode = NewMode;
+
+	return;
+}
+
+/******************************************************************************
+ *
+ *	SkHWLinkDown() - Link Down handling
+ *
+ * Description:
+ *	This function handles the Hardware link down signal
+ *
+ * Note:
+ *
+ */
+void	SkHWLinkDown(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Word;
+
+	pPrt = &pAC->GIni.GP[Port] ;
+
+	/* Disable all XMAC interrupts */
+	XM_OUT16(IoC, Port, XM_IMSK, 0xffff);
+
+	/* Disable Receive and Transmitter */
+	XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+	XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~(XM_MMU_ENA_RX|XM_MMU_ENA_TX));
+	
+	/* disable all PHY interrupts */
+	switch (pAC->GIni.GP[Port].PhyType) {
+		case SK_PHY_BCOM:
+			PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, 
+				0xffff);
+			break;
+		case SK_PHY_LONE:
+			PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, 
+				0x0);
+			break;
+		case SK_PHY_NAT:
+			/* todo: National
+			PHY_WRITE(IoC, pPrt, Port, PHY_NAT_INT_MASK, 
+				0xffff); */
+			break;
+	}
+
+	/* Init default sense mode */
+	SkHWInitDefSense(pAC, IoC, Port);
+
+	if (!pPrt->PHWLinkUp) {
+		return;
+	} 
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
+		("Link down Port %d\n", Port));
+
+	/* Set Link to DOWN */
+	pPrt->PHWLinkUp = SK_FALSE;
+
+	/* Reset Port stati */
+	pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN;
+	pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE ;
+
+	/*
+	 * Reinit Phy especially when the AutoSense default is set now
+	 */
+	SkXmInitPhy(pAC, IoC, Port, SK_FALSE);
+
+	/*
+	 * GP0: used for workaround of Rev. C
+	 * Errata 2
+	 */
+
+	/* Do NOT signal to RLMT */
+
+	/* Do NOT start the timer here */
+}
+
+/******************************************************************************
+ *
+ *	SkHWLinkUp() - Link Up handling
+ *
+ * Description:
+ *	This function handles the Hardware link up signal
+ *
+ * Note:
+ *
+ */
+void	SkHWLinkUp(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port] ;
+
+	if (pPrt->PHWLinkUp) {
+		/* We do NOT need to proceed on active link */
+		return;
+	} 
+
+	pPrt->PHWLinkUp = SK_TRUE ;
+	pPrt->PAutoNegFail = SK_FALSE ;
+	pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN;
+
+	if (pPrt->PLinkMode != SK_LMODE_AUTOHALF &&
+	    pPrt->PLinkMode != SK_LMODE_AUTOFULL &&
+	    pPrt->PLinkMode != SK_LMODE_AUTOBOTH) {
+		/* Link is up and no Autonegotiation should be done */
+
+		/* Configure Port */
+
+		/* Set Link Mode */
+		if (pPrt->PLinkMode == SK_LMODE_FULL) {
+			pPrt->PLinkModeStatus = SK_LMODE_STAT_FULL;
+		} else {
+			pPrt->PLinkModeStatus = SK_LMODE_STAT_HALF;
+		}
+
+		/* No flow control without autonegotiation */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE ;
+
+		/* RX/TX enable */
+		SkXmRxTxEnable(pAC, IoC, Port);
+	}
+}
+
+/******************************************************************************
+ *
+ * SkMacParity	- does everything to handle MAC parity errors correctly
+ *
+ */
+static	void	SkMacParity(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index of the port failed */
+{
+	SK_EVPARA	Para;
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	SK_U64		TxMax;		/* TxMax Counter */
+	unsigned int	Len;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Clear IRQ */
+	SK_OUT16(IoC, MR_ADDR(Port,TX_MFF_CTRL1), MFF_CLR_PERR) ;
+
+	if (pPrt->PCheckPar) {
+		if (Port == MAC_1) {
+			SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E016,
+				SKERR_SIRQ_E016MSG) ;
+		} else {
+			SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E017,
+				SKERR_SIRQ_E017MSG) ;
+		}
+		Para.Para64 = Port;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		Para.Para32[0] = Port;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+
+		return;
+	}
+
+
+	/* Check whether frames with a size of 1k were sent */
+	Len = sizeof(SK_U64);
+	SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_MAX, (char *) &TxMax,
+		&Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(Port));
+
+	if (TxMax > 0) {
+		/* From now on check the parity */
+		pPrt->PCheckPar = SK_TRUE;
+	}
+}
+
+/******************************************************************************
+ *
+ *	Hardware Error service routine
+ *
+ * Description:
+ *
+ * Notes:
+ */
+static	void	SkGeHwErr(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+SK_U32	HwStatus)	/* Interrupt status word */
+{
+	SK_EVPARA	Para;
+
+	if (HwStatus & IS_IRQ_STAT) {
+		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E013,
+			SKERR_SIRQ_E013MSG) ;
+		Para.Para64 = 0;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
+	}
+
+	if (HwStatus & IS_IRQ_MST_ERR) {
+		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E012,
+			SKERR_SIRQ_E012MSG) ;
+		Para.Para64 = 0;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
+	}
+
+	if (HwStatus & IS_NO_STAT_M1) {
+		/* Ignore it */
+		/* This situation is also indicated in the descriptor */
+		SK_OUT16(IoC, MR_ADDR(MAC_1,RX_MFF_CTRL1), MFF_CLR_INSTAT) ;
+	}
+
+	if (HwStatus & IS_NO_STAT_M2) {
+		/* Ignore it */
+		/* This situation is also indicated in the descriptor */
+		SK_OUT16(IoC, MR_ADDR(MAC_2,RX_MFF_CTRL1), MFF_CLR_INSTAT) ;
+	}
+
+	if (HwStatus & IS_NO_TIST_M1) {
+		/* Ignore it */
+		/* This situation is also indicated in the descriptor */
+		SK_OUT16(IoC, MR_ADDR(MAC_1,RX_MFF_CTRL1), MFF_CLR_INTIST) ;
+	}
+
+	if (HwStatus & IS_NO_TIST_M2) {
+		/* Ignore it */
+		/* This situation is also indicated in the descriptor */
+		SK_OUT16(IoC, MR_ADDR(MAC_2,RX_MFF_CTRL1), MFF_CLR_INTIST) ;
+	}
+
+	if (HwStatus & IS_RAM_RD_PAR) {
+		SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_RD_PERR) ;
+		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E014,
+			SKERR_SIRQ_E014MSG) ;
+		Para.Para64 = 0;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
+	}
+
+	if (HwStatus & IS_RAM_WR_PAR) {
+		SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_WR_PERR) ;
+		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E015,
+			SKERR_SIRQ_E015MSG) ;
+		Para.Para64 = 0;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
+	}
+
+	if (HwStatus & IS_M1_PAR_ERR) {
+		SkMacParity(pAC, IoC, MAC_1) ;
+	}
+
+	if (HwStatus & IS_M2_PAR_ERR) {
+		SkMacParity(pAC, IoC, MAC_2) ;
+	}
+
+	if (HwStatus & IS_R1_PAR_ERR) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_P) ;
+
+		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E018,
+			SKERR_SIRQ_E018MSG) ;
+		Para.Para64 = MAC_1;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		Para.Para32[0] = MAC_1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+	if (HwStatus & IS_R2_PAR_ERR) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_P) ;
+
+		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E019,
+			SKERR_SIRQ_E019MSG) ;
+		Para.Para64 = MAC_2;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		Para.Para32[0] = MAC_2;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+}
+
+/******************************************************************************
+ *
+ *	Interrupt service routine
+ *
+ * Description:
+ *
+ * Notes:
+ */
+void	SkGeSirqIsr(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+SK_U32	Istatus)	/* Interrupt status word */
+{
+	SK_U32		RegVal32;	/* Read register Value */
+	SK_EVPARA	Para;
+	SK_U16		XmIsr;
+
+	if (Istatus & IS_HW_ERR) {
+		SK_IN32(IoC, B0_HWE_ISRC, &RegVal32) ;
+		SkGeHwErr(pAC, IoC, RegVal32) ;
+	}
+
+	/*
+	 * Packet Timeout interrupts
+	 */
+	/* Check whether XMACs are correctly initialized */
+	if ((Istatus & (IS_PA_TO_RX1 | IS_PA_TO_TX1)) &&
+	    !pAC->GIni.GP[MAC_1].PState) {
+		/* XMAC was not initialized but Packet timeout occured */
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E004,
+			SKERR_SIRQ_E004MSG) ;
+	}
+
+	if ((Istatus & (IS_PA_TO_RX2 | IS_PA_TO_TX2)) &&
+	    !pAC->GIni.GP[MAC_2].PState) {
+		/* XMAC was not initialized but Packet timeout occured */
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E005,
+			SKERR_SIRQ_E005MSG) ;
+	}
+
+	if (Istatus & IS_PA_TO_RX1) {
+		/* Means network is filling us up */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E002,
+			SKERR_SIRQ_E002MSG) ;
+		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX1) ;
+	}
+
+	if (Istatus & IS_PA_TO_RX2) {
+		/* Means network is filling us up */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E003,
+			SKERR_SIRQ_E003MSG) ;
+		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX2) ;
+	}
+
+	if (Istatus & IS_PA_TO_TX1) {
+		/* May be a normal situation in a server with a slow network */
+		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX1) ;
+	}
+
+	if (Istatus & IS_PA_TO_TX2) {
+		/* May be a normal situation in a server with a slow network */
+		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX2) ;
+	}
+
+	/*
+	 * Check interrupts of the particular queues.
+	 */
+	if (Istatus & IS_R1_C) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_C) ;
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E006,
+			SKERR_SIRQ_E006MSG) ;
+		Para.Para64 = MAC_1;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		Para.Para32[0] = MAC_1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+	if (Istatus & IS_R2_C) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_C) ;
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E007,
+			SKERR_SIRQ_E007MSG) ;
+		Para.Para64 = MAC_2;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		Para.Para32[0] = MAC_2;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+	if (Istatus & IS_XS1_C) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_XS1_CSR, CSR_IRQ_CL_C) ;
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E008,
+			SKERR_SIRQ_E008MSG) ;
+		Para.Para64 = MAC_1;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		Para.Para32[0] = MAC_1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+	if (Istatus & IS_XA1_C) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_XA1_CSR, CSR_IRQ_CL_C) ;
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E009,
+			SKERR_SIRQ_E009MSG) ;
+		Para.Para64 = MAC_1;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		Para.Para32[0] = MAC_1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+	if (Istatus & IS_XS2_C) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_XS2_CSR, CSR_IRQ_CL_C) ;
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E010,
+			SKERR_SIRQ_E010MSG) ;
+		Para.Para64 = MAC_2;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		Para.Para32[0] = MAC_2;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+	if (Istatus & IS_XA2_C) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_XA2_CSR, CSR_IRQ_CL_C) ;
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E011,
+			SKERR_SIRQ_E011MSG) ;
+		Para.Para64 = MAC_2;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		Para.Para32[0] = MAC_2;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+	/*
+	 * I2C Ready interrupt
+	 */
+	if (Istatus & IS_I2C_READY) {
+		SK_U16 	PhyInt;
+		SK_U16 	PhyIMsk;
+		SK_BOOL	IsPhyInt = SK_FALSE;
+		int	i;
+		/* test IRQs from PHY */
+		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+			switch (pAC->GIni.GP[i].PhyType) {
+			case SK_PHY_XMAC:
+				break;
+			case SK_PHY_BCOM:
+	    			if(pAC->GIni.GP[i].PState) {
+					PHY_READ(IoC, &pAC->GIni.GP[i], i,
+						PHY_BCOM_INT_STAT, &PhyInt);
+					PHY_READ(IoC, &pAC->GIni.GP[i], i,
+						PHY_BCOM_INT_MASK, &PhyIMsk);
+					
+					if (PhyInt & (~PhyIMsk)) {
+						SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
+							SK_DBGCAT_IRQ,
+							("Port %d Bcom Int: %x "
+							" Mask: %x\n",
+							i, PhyInt, PhyIMsk));
+						SkPhyIsrBcom(pAC, IoC, i,
+							(SK_U16) 
+							(PhyInt & (~PhyIMsk)));
+						IsPhyInt = SK_TRUE;
+					}
+				}
+				else {
+				}
+				break;
+			case SK_PHY_LONE:
+				PHY_READ(IoC, &pAC->GIni.GP[i], i,
+					PHY_LONE_INT_STAT, &PhyInt);
+				PHY_READ(IoC, &pAC->GIni.GP[i], i,
+					PHY_LONE_INT_ENAB, &PhyIMsk);
+				
+				if (PhyInt & PhyIMsk) {
+					SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
+						SK_DBGCAT_IRQ,
+						("Port %d  Lone Int: %x "
+						" Mask: %x\n",
+						i, PhyInt, PhyIMsk));
+					SkPhyIsrLone(pAC, IoC, i,
+						(SK_U16) (PhyInt & PhyIMsk));
+					IsPhyInt = SK_TRUE;
+				}
+				break;
+			case SK_PHY_NAT:
+				/* todo: National */
+				break;
+			}
+		}
+		if (!IsPhyInt) {
+			SkI2cIsr(pAC, IoC);
+		}
+	}
+
+	if (Istatus & IS_LNK_SYNC_M1) {
+		/*
+		 * We do NOT need the Link Sync interrupt, because it shows
+		 * us only a link going down.
+		 */
+		/* clear interrupt */
+		SK_OUT8(IoC, MR_ADDR(MAC_1,LNK_SYNC_CTRL), LED_CLR_IRQ);
+	}
+
+	/* Check MAC after link sync counter */
+	if (Istatus & IS_MAC1) {
+		XM_IN16(IoC, MAC_1, XM_ISRC, &XmIsr) ;
+		SkXmIrq(pAC, IoC, MAC_1, XmIsr);
+	}
+
+	if (Istatus & IS_LNK_SYNC_M2) {
+		/*
+		 * We do NOT need the Link Sync interrupt, because it shows
+		 * us only a link going down.
+		 */
+		/* clear interrupt */
+		SK_OUT8(IoC, MR_ADDR(MAC_2,LNK_SYNC_CTRL), LED_CLR_IRQ);
+	}
+
+	/* Check MAC after link sync counter */
+	if (Istatus & IS_MAC2) {
+		XM_IN16(IoC, MAC_2, XM_ISRC, &XmIsr) ;
+		SkXmIrq(pAC, IoC, MAC_2, XmIsr);
+	}
+
+	/*
+	 * Timer interrupt
+	 *  To be served last
+	 */
+	if (Istatus & IS_TIMINT) {
+		SkHwtIsr(pAC, IoC);
+	}
+}
+
+/*
+ * Define an array of RX counter which are checked
+ * in AutoSense mode to check whether a link is not able to autonegotiate.
+ */
+static const SK_U32 SkGeRxOids[]= {
+	OID_SKGE_STAT_RX_64,
+	OID_SKGE_STAT_RX_127,
+	OID_SKGE_STAT_RX_255,
+	OID_SKGE_STAT_RX_511,
+	OID_SKGE_STAT_RX_1023,
+	OID_SKGE_STAT_RX_MAX,
+} ;
+/******************************************************************************
+ *
+ * SkGePortCheckShorts - Implementing of the Workaround Errata # 2
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ */
+int	SkGePortCheckShorts(
+SK_AC	*pAC,		/* Adapters context */
+SK_IOC	IoC,		/* IO Context */
+int	Port)		/* Which port should be checked */
+{
+	SK_U64		Shorts;		/* Short Event Counter */
+	SK_U64		CheckShorts;	/* Check value for Short Event Counter */
+	SK_U64		RxCts;		/* RX Counter (packets on network) */
+	SK_U64		RxTmp;		/* RX temp. Counter */
+	SK_U64		FcsErrCts;	/* FCS Error Counter */
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	unsigned int	Len;
+	int		Rtv;		/* Return value */
+	int		i;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Default: no action */
+	Rtv = SK_HW_PS_NONE;
+
+	/*
+	 * Extra precaution: check for short Event counter
+	 */
+	Len = sizeof(SK_U64);
+	SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_RX_SHORTS, (char *) &Shorts,
+		&Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(Port));
+
+	/*
+	 * Read RX counter (packets seen on the network and not neccesarily
+	 * really received.
+	 */
+	Len = sizeof(SK_U64);
+	RxCts = 0;
+
+	for (i = 0; i < sizeof(SkGeRxOids)/sizeof(SK_U32) ; i++) {
+		SkPnmiGetVar(pAC, IoC, SkGeRxOids[i], (char *) &RxTmp,
+			&Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(Port));
+		RxCts += RxTmp;
+	}
+
+	/* On default: check shorts against zero */
+	CheckShorts = 0;
+
+	/*
+	 * Extra extra precaution on active links:
+	 */
+	if (pPrt->PHWLinkUp) {
+		/*
+		 * Reset Link Restart counter
+		 */
+		pPrt->PLinkResCt = 0;
+
+		/* If link is up check for 2 */
+		CheckShorts = 2;
+
+		Len = sizeof(SK_U64);
+		SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_RX_FCS,
+			(char *) &FcsErrCts, &Len,
+			(SK_U32) SK_PNMI_PORT_PHYS2INST(Port));
+		
+		if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+		    pPrt->PLipaAutoNeg == SK_LIPA_UNKNOWN &&
+		    (pPrt->PLinkMode == SK_LMODE_HALF ||
+		     pPrt->PLinkMode == SK_LMODE_FULL)) {
+			/*
+			 * This is autosensing and we are in the fallback
+			 * manual full/half duplex mode.
+			 */
+			if (RxCts == pPrt->PPrevRx) {
+				/*
+				 * Nothing received
+				 * restart link
+				 */
+				pPrt->PPrevFcs = FcsErrCts;
+				pPrt->PPrevShorts = Shorts;
+				return(SK_HW_PS_RESTART);
+			} else {
+				pPrt->PLipaAutoNeg = SK_LIPA_MANUAL;
+			}
+		}
+
+		if (((RxCts - pPrt->PPrevRx) > pPrt->PRxLim) ||
+		    (!(FcsErrCts - pPrt->PPrevFcs))) {
+			/*
+			 * Note: The compare with zero above has to be done
+			 * the way shown, otherwise the Linux driver will
+			 * have a problem.
+			 */
+			/*
+			 * we received a bunch of frames or no
+			 * CRC error occured on the network ->
+			 * ok.
+			 */
+			pPrt->PPrevRx = RxCts;
+			pPrt->PPrevFcs = FcsErrCts;
+			pPrt->PPrevShorts = Shorts;
+
+			return(SK_HW_PS_NONE) ;
+		}
+
+		pPrt->PPrevFcs = FcsErrCts;
+	}
+
+
+	if ((Shorts - pPrt->PPrevShorts) > CheckShorts) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
+			("Short Event Count Restart Port %d \n", Port));
+		Rtv = SK_HW_PS_RESTART;
+	}
+
+	pPrt->PPrevShorts = Shorts;
+	pPrt->PPrevRx = RxCts;
+
+	return(Rtv);
+}
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUp - Implementing of the Workaround Errata # 2
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	2	Link came up
+ */
+int	SkGePortCheckUp(
+SK_AC	*pAC,		/* Adapters context */
+SK_IOC	IoC,		/* IO Context */
+int	Port)		/* Which port should be checked */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	switch (pPrt->PhyType) {
+	case SK_PHY_XMAC:
+		return (SkGePortCheckUpXmac(pAC, IoC, Port));
+	case SK_PHY_BCOM:
+		return (SkGePortCheckUpBcom(pAC, IoC, Port));
+	case SK_PHY_LONE:
+		return (SkGePortCheckUpLone(pAC, IoC, Port));
+	case SK_PHY_NAT:
+		return (SkGePortCheckUpNat(pAC, IoC, Port));
+	}
+	
+	return(SK_HW_PS_NONE) ;
+}
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUpXmac - Implementing of the Workaround Errata # 2
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	2	Link came up
+ */
+static int	SkGePortCheckUpXmac(
+SK_AC	*pAC,		/* Adapters context */
+SK_IOC	IoC,		/* IO Context */
+int	Port)		/* Which port should be checked */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	SK_BOOL		AutoNeg;	/* Is Autonegotiation used ? */
+	SK_U16		Isrc;		/* Interrupt source register */
+	SK_U32		GpReg;		/* General Purpose register value */
+	SK_U16		IsrcSum;	/* Interrupt source register sum */
+	SK_U16		LpAb;		/* Link Partner Ability */
+	SK_U16		ResAb;		/* Resolved Ability */
+	SK_U64		Shorts;		/* Short Event Counter */
+	unsigned int	Len;
+	SK_U8		NextMode;	/* Next AutoSensing Mode */
+	SK_U16		ExtStat;	/* Extended Status Register */
+	int		Done;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PHWLinkUp) {
+		if (pPrt->PhyType != SK_PHY_XMAC) {
+			return(SK_HW_PS_NONE) ;
+		}
+		else {
+			return(SkGePortCheckShorts(pAC, IoC, Port)) ;
+		}
+	}
+
+	IsrcSum = pPrt->PIsave;
+	pPrt->PIsave = 0;
+
+	/* Now wait for each ports link */
+	if (pPrt->PLinkMode == SK_LMODE_HALF ||
+	    pPrt->PLinkMode == SK_LMODE_FULL) {
+		AutoNeg = SK_FALSE;
+	} else {
+		AutoNeg = SK_TRUE;
+	}
+
+	if (pPrt->PLinkBroken) {
+		/* Link was broken */
+		XM_IN32(IoC,Port,XM_GP_PORT, &GpReg) ;
+
+		if ((GpReg & XM_GP_INP_ASS) == 0) {
+			/* The Link is in sync */
+			XM_IN16(IoC,Port,XM_ISRC, &Isrc) ;
+			IsrcSum |= Isrc;
+			SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum);
+			if ((Isrc & XM_IS_INP_ASS) == 0) {
+				/* It has been in sync since last Time */
+				/* Restart the PORT */
+	
+				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
+					("Link in sync Restart Port %d\n",
+					 Port));
+
+				/*
+				 * We now need to reinitialize the PrevSHorts
+				 * counter.
+				 */
+				Len = sizeof(SK_U64);
+				SkPnmiGetVar(pAC, IoC,
+					OID_SKGE_STAT_RX_SHORTS,
+					(char *) &Shorts,
+					&Len,
+					(SK_U32) SK_PNMI_PORT_PHYS2INST(Port));
+				pPrt->PPrevShorts = Shorts;
+
+				pAC->GIni.GP[Port].PLinkBroken = SK_FALSE ;
+
+				/*
+				 * Link Restart Workaround:
+				 *  it may be possible that the other Link side
+				 *  restarts its link as well an we detect
+				 *  another LinkBroken. To prevent this
+				 *  happening we check for a maximum number
+				 *  of consecutive restart. If those happens,
+				 *  we do NOT restart the active link and
+				 *  check whether the lionk is now o.k.
+				 */
+				pAC->GIni.GP[Port].PLinkResCt ++;
+				pPrt->PAutoNegTimeOut = 0;
+
+				if (pAC->GIni.GP[Port].PLinkResCt <
+					SK_MAX_LRESTART) {
+					return(SK_HW_PS_RESTART) ;
+				}
+
+				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+					("Do NOT restart on Port %d %x %x\n",
+					Port, Isrc, IsrcSum));
+				pAC->GIni.GP[Port].PLinkResCt = 0;
+			} else {
+				pPrt->PIsave = (SK_U16) (IsrcSum & (XM_IS_AND));
+				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+					("Save Sync/nosync Port %d %x %x\n",
+					Port, Isrc, IsrcSum));
+				/* Do nothing more if link is broken */
+				return(SK_HW_PS_NONE) ;
+			}
+		} else {
+			/* Do nothing more if link is broken */
+			return(SK_HW_PS_NONE) ;
+		}
+
+	} else {
+		/* Link was not broken, check if it is */
+		XM_IN16(IoC,Port,XM_ISRC, &Isrc) ;
+		IsrcSum |= Isrc;
+		if ((Isrc & XM_IS_INP_ASS) == XM_IS_INP_ASS) {
+			XM_IN16(IoC,Port,XM_ISRC, &Isrc) ;
+			IsrcSum |= Isrc;
+			if ((Isrc & XM_IS_INP_ASS) == XM_IS_INP_ASS) {
+				XM_IN16(IoC,Port,XM_ISRC, &Isrc) ;
+				IsrcSum |= Isrc;
+				if ((Isrc & XM_IS_INP_ASS) == XM_IS_INP_ASS) {
+					pPrt->PLinkBroken = SK_TRUE ;
+					/*
+					 * Re-Init Link partner Autoneg flag
+					 */
+					pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
+					SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
+					   SK_DBGCAT_IRQ,
+					   ("Link broken Port %d\n",
+						 Port));
+
+					/* cable removed-> reinit Sensemode */
+					/* Init default sense mode */
+					SkHWInitDefSense(pAC, IoC, Port);
+
+					return(SK_HW_PS_RESTART) ;
+				}
+			}
+		} else {
+			SkXmAutoNegLipaXmac(pAC, IoC, Port, Isrc);
+			if (SkGePortCheckShorts(pAC, IoC, Port) ==
+				SK_HW_PS_RESTART) {
+				return(SK_HW_PS_RESTART) ;
+			}
+		}
+	}
+
+	/*
+	 * here we usually can check whether the link is in sync and
+	 * autonegotiation is done.
+	 */
+	XM_IN32(IoC,Port,XM_GP_PORT, &GpReg) ;
+	XM_IN16(IoC,Port,XM_ISRC, &Isrc) ;
+	IsrcSum |= Isrc;
+
+	SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum);
+	if ((GpReg & XM_GP_INP_ASS) != 0 || (IsrcSum & XM_IS_INP_ASS) != 0) {
+		if ((GpReg & XM_GP_INP_ASS) == 0) {
+			/*
+			 * Save Autonegotiation Done interrupt only if link 
+			 * is in sync
+			 */
+			pPrt->PIsave = (SK_U16) (IsrcSum & (XM_IS_AND));
+		}
+#ifdef	DEBUG
+		if (pPrt->PIsave & (XM_IS_AND)) {
+			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+				("AutoNeg done rescheduled Port %d\n", Port));
+		}
+#endif
+		return(SK_HW_PS_NONE) ;
+	}
+
+	if (AutoNeg) {
+		if (IsrcSum & XM_IS_AND) {
+			SkHWLinkUp(pAC, IoC, Port) ;
+			Done = SkXmAutoNegDone(pAC,IoC,Port);
+			if (Done != SK_AND_OK) {
+				/* Get PHY parameters, for debuging only */
+				PHY_READ(IoC, pPrt, Port, PHY_XMAC_AUNE_LP,
+					&LpAb);
+				PHY_READ(IoC, pPrt, Port, PHY_XMAC_RES_ABI,
+					&ResAb);
+				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+					("AutoNeg FAIL Port %d (LpAb %x, ResAb %x)\n",
+					 Port, LpAb, ResAb));
+					
+				/* Try next possible mode */
+				NextMode = SkHWSenseGetNext(pAC, IoC, Port);
+				SkHWLinkDown(pAC, IoC, Port) ;
+				if (Done == SK_AND_DUP_CAP) {
+					/* GoTo next mode */
+					SkHWSenseSetNext(pAC, IoC, Port,
+						NextMode);
+				}
+
+				return(SK_HW_PS_RESTART) ;
+
+			} else {
+				/*
+				 * Dummy Read extended status to prevent
+				 * extra link down/ups
+				 * (clear Page Received bit if set)
+				 */
+				PHY_READ(IoC, pPrt, Port, PHY_XMAC_AUNE_EXP, &ExtStat);
+				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+					("AutoNeg done Port %d\n", Port));
+				return(SK_HW_PS_LINK) ;
+			}
+		} 
+		
+		/*
+		 * AutoNeg not done, but HW link is up. Check for timeouts
+		 */
+		pPrt->PAutoNegTimeOut ++;
+		if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
+			/*
+			 * Timeout occured.
+			 * What do we need now?
+			 */
+			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
+				SK_DBGCAT_IRQ,
+				("AutoNeg timeout Port %d\n",
+				 Port));
+			if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+				pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
+				/*
+				 * Timeout occured
+				 * Set Link manually up.
+				 */
+				SkHWSenseSetNext(pAC, IoC, Port,
+					SK_LMODE_FULL);
+				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
+					SK_DBGCAT_IRQ,
+					("Set manual full duplex Port %d\n",
+					 Port));
+			}
+
+			/*
+			 * Do the restart
+			 */
+			return(SK_HW_PS_RESTART) ;
+		}
+	} else {
+		/*
+		 * Link is up and we don't need more.
+		 */
+#ifdef	DEBUG
+		if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+				("ERROR: Lipa auto detected on port %d\n",
+				Port));
+		}
+#endif
+
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
+			("Link sync(GP), Port %d\n", Port));
+		SkHWLinkUp(pAC, IoC, Port) ;
+		return(SK_HW_PS_LINK) ;
+	}
+
+	return(SK_HW_PS_NONE) ;
+}
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUpBcom - Check, if the link is up
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	2	Link came up
+ */
+static int	SkGePortCheckUpBcom(
+SK_AC	*pAC,		/* Adapters context */
+SK_IOC	IoC,		/* IO Context */
+int	Port)		/* Which port should be checked */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	SK_BOOL		AutoNeg;	/* Is Autonegotiation used ? */
+	SK_U16		Isrc;		/* Interrupt source register */
+	SK_U16		LpAb;		/* Link Partner Ability */
+	SK_U16		ExtStat;	/* Extended Status Register */
+	SK_U16		PhyStat;	/* Phy Status Register */
+	int		Done;
+	SK_U16		ResAb;
+
+	pPrt = &pAC->GIni.GP[Port];
+	PHY_READ(IoC, pPrt, Port, PHY_BCOM_STAT, &PhyStat);
+
+	if (pPrt->PHWLinkUp) {
+		return(SK_HW_PS_NONE) ;
+	}
+
+	pPrt->PIsave = 0;
+
+	/* Now wait for each ports link */
+	if (pPrt->PLinkMode == SK_LMODE_HALF ||
+	    pPrt->PLinkMode == SK_LMODE_FULL) {
+		AutoNeg = SK_FALSE;
+	} else {
+		AutoNeg = SK_TRUE;
+	}
+
+	/*
+	 * here we usually can check whether the link is in sync and
+	 * autonegotiation is done.
+	 */
+	XM_IN16(IoC, Port, XM_ISRC, &Isrc) ;
+
+	PHY_READ(IoC, pPrt, Port, PHY_BCOM_STAT, &PhyStat);
+
+	SkXmAutoNegLipaBcom(pAC, IoC, Port, PhyStat);
+	if ((PhyStat & PHY_ST_LSYNC) == 0){
+		return(SK_HW_PS_NONE) ; 
+	}
+
+	if (AutoNeg) {
+		if (PhyStat & PHY_ST_AN_OVER) {
+			SkHWLinkUp(pAC, IoC, Port) ;
+			Done = SkXmAutoNegDone(pAC,IoC,Port);
+			if (Done != SK_AND_OK) {
+				/* Get PHY parameters, for debuging only */
+				PHY_READ(IoC, pPrt, Port,
+					PHY_BCOM_AUNE_LP,
+					&LpAb);
+				PHY_READ(IoC, pPrt, Port,
+					PHY_BCOM_1000T_STAT,
+					&ExtStat);
+				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+					("AutoNeg FAIL Port %d (LpAb %x, "
+					"1000TStat %x)\n",
+					 Port, LpAb, ExtStat));
+				return(SK_HW_PS_RESTART) ;
+
+			} else {
+				/*
+				 * Dummy Read interrupt status to prevent
+				 * extra link down/ups
+				 */
+				PHY_READ(IoC, pPrt, Port, PHY_BCOM_INT_STAT,
+					&ExtStat);
+				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+					("AutoNeg done Port %d\n", Port));
+				return(SK_HW_PS_LINK) ;
+			}
+		} 
+	} else {
+		/*
+		 * Link is up and we don't need more.
+		 */
+#ifdef	DEBUG
+		if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+				("ERROR: Lipa auto detected on port %d\n",
+				Port));
+		}
+#endif
+		PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb);
+		if (ResAb & (PHY_B_1000S_MSF)) {
+			/* Error */
+			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+				("Master/Slave Fault port %d\n", Port));
+			pPrt->PAutoNegFail = SK_TRUE;
+			pPrt->PMSStatus = SK_MS_STAT_FAULT;
+			return (SK_AND_OTHER);
+		} else if (ResAb & PHY_B_1000S_MSR) {
+			pPrt->PMSStatus = SK_MS_STAT_MASTER ;
+		} else {
+			pPrt->PMSStatus = SK_MS_STAT_SLAVE ;
+		}
+
+
+		/*
+		 * Dummy Read interrupt status to prevent
+		 * extra link down/ups
+		 */
+		PHY_READ(IoC, pPrt, Port, PHY_BCOM_INT_STAT, &ExtStat);
+		
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
+			("Link sync(GP), Port %d\n", Port));
+		SkHWLinkUp(pAC, IoC, Port) ;
+		return(SK_HW_PS_LINK) ;
+	}
+
+	return(SK_HW_PS_NONE) ;
+}
+
+/******************************************************************************
+ *
+ * SkGePortCheckUpLone - Check if the link is up
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	2	Link came up
+ */
+static int	SkGePortCheckUpLone(
+SK_AC	*pAC,		/* Adapters context */
+SK_IOC	IoC,		/* IO Context */
+int	Port)		/* Which port should be checked */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	SK_BOOL		AutoNeg;	/* Is Autonegotiation used ? */
+	SK_U16		Isrc;		/* Interrupt source register */
+	SK_U16		LpAb;		/* Link Partner Ability */
+	SK_U8		NextMode;	/* Next AutoSensing Mode */
+	SK_U16		ExtStat;	/* Extended Status Register */
+	SK_U16		PhyStat;	/* Phy Status Register */
+	SK_U16		StatSum;
+	int		Done;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PHWLinkUp) {
+		return(SK_HW_PS_NONE) ;
+	}
+
+	StatSum = pPrt->PIsave;
+	pPrt->PIsave = 0;
+
+	/* Now wait for each ports link */
+	if (pPrt->PLinkMode == SK_LMODE_HALF ||
+	    pPrt->PLinkMode == SK_LMODE_FULL) {
+		AutoNeg = SK_FALSE;
+	} else {
+		AutoNeg = SK_TRUE;
+	}
+
+	/*
+	 * here we usually can check whether the link is in sync and
+	 * autonegotiation is done.
+	 */
+	XM_IN16(IoC, Port, XM_ISRC, &Isrc) ;
+	PHY_READ(IoC, pPrt, Port, PHY_LONE_STAT, &PhyStat);
+	StatSum |= PhyStat;
+
+	SkXmAutoNegLipaLone(pAC, IoC, Port, PhyStat);
+	if ((PhyStat & PHY_ST_LSYNC) == 0){
+		/*
+		 * Save Autonegotiation Done bit
+		 */
+		pPrt->PIsave = (SK_U16) (StatSum & PHY_ST_AN_OVER);
+#ifdef DEBUG
+		if (pPrt->PIsave & PHY_ST_AN_OVER) {
+			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+				("AutoNeg done rescheduled Port %d\n", Port));
+		}
+#endif
+		return(SK_HW_PS_NONE) ;
+	}
+
+	if (AutoNeg) {
+		if (StatSum & PHY_ST_AN_OVER) {
+			SkHWLinkUp(pAC, IoC, Port) ;
+			Done = SkXmAutoNegDone(pAC,IoC,Port);
+			if (Done != SK_AND_OK) {
+				/* Get PHY parameters, for debuging only */
+				PHY_READ(IoC, pPrt, Port,
+					PHY_LONE_AUNE_LP,
+					&LpAb);
+				PHY_READ(IoC, pPrt, Port,
+					PHY_LONE_1000T_STAT,
+					&ExtStat);
+				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+					("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n",
+					 Port, LpAb, ExtStat));
+					
+				/* Try next possible mode */
+				NextMode = SkHWSenseGetNext(pAC, IoC, Port);
+				SkHWLinkDown(pAC, IoC, Port) ;
+				if (Done == SK_AND_DUP_CAP) {
+					/* GoTo next mode */
+					SkHWSenseSetNext(pAC, IoC, Port,
+						NextMode);
+				}
+
+				return(SK_HW_PS_RESTART) ;
+
+			} else {
+				/*
+				 * Dummy Read interrupt status to prevent
+				 * extra link down/ups
+				 */
+				PHY_READ(IoC, pPrt, Port, PHY_LONE_INT_STAT,
+					&ExtStat);
+				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+					("AutoNeg done Port %d\n", Port));
+				return(SK_HW_PS_LINK) ;
+			}
+		} 
+		
+		/*
+		 * AutoNeg not done, but HW link is up. Check for timeouts
+		 */
+		pPrt->PAutoNegTimeOut ++;
+		if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
+			/*
+			 * Timeout occured.
+			 * What do we need now?
+			 */
+			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
+				SK_DBGCAT_IRQ,
+				("AutoNeg timeout Port %d\n",
+				 Port));
+			if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+				pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
+				/*
+				 * Timeout occured
+				 * Set Link manually up.
+				 */
+				SkHWSenseSetNext(pAC, IoC, Port,
+					SK_LMODE_FULL);
+				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
+					SK_DBGCAT_IRQ,
+					("Set manual full duplex Port %d\n",
+					 Port));
+			}
+
+			/*
+			 * Do the restart
+			 */
+			return(SK_HW_PS_RESTART) ;
+		}
+	} else {
+		/*
+		 * Link is up and we don't need more.
+		 */
+#ifdef	DEBUG
+		if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+				("ERROR: Lipa auto detected on port %d\n",
+				Port));
+		}
+#endif
+
+		/*
+		 * Dummy Read interrupt status to prevent
+		 * extra link down/ups
+		 */
+		PHY_READ(IoC, pPrt, Port, PHY_LONE_INT_STAT, &ExtStat);
+		
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
+			("Link sync(GP), Port %d\n", Port));
+		SkHWLinkUp(pAC, IoC, Port) ;
+		return(SK_HW_PS_LINK) ;
+	}
+
+	return(SK_HW_PS_NONE) ;
+}
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUpNat - Check if the link is up
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	2	Link came up
+ */
+static int	SkGePortCheckUpNat(
+SK_AC	*pAC,		/* Adapters context */
+SK_IOC	IoC,		/* IO Context */
+int	Port)		/* Which port should be checked */
+{
+	/* todo: National */
+	return(SK_HW_PS_NONE) ;
+}
+
+
+/******************************************************************************
+ *
+ *	Event service routine
+ *
+ * Description:
+ *
+ * Notes:
+ */
+int	SkGeSirqEvent(
+SK_AC		*pAC,		/* Adapters context */
+SK_IOC		IoC,		/* Io Context */
+SK_U32		Event,		/* Module specific Event */
+SK_EVPARA	Para)		/* Event specific Parameter */
+{
+	SK_U32	Port;
+	SK_U32	Time;
+	SK_U8	Val8 ;
+	int	PortStat;
+
+	Port = Para.Para32[0];
+
+	switch (Event) {
+	case SK_HWEV_WATIM:
+		/* Check whether port came up */
+		PortStat = SkGePortCheckUp(pAC, IoC, Port);
+
+		switch (PortStat) {
+		case SK_HW_PS_RESTART:
+			if (pAC->GIni.GP[Port].PHWLinkUp) {
+				/*
+				 * Set Link to down.
+				 */
+				SkHWLinkDown(pAC, IoC, Port);
+
+				/*
+				 * Signal directly to RLMT to ensure correct
+				 * sequence of SWITCH and RESET event.
+				 */
+				Para.Para32[0] = (SK_U32) Port;
+				SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
+
+				/* Start workaround Errata #2 timer */
+				SkTimerStart(pAC, IoC,
+					&pAC->GIni.GP[Port].PWaTimer,
+					SK_WA_INA_TIME,
+					SKGE_HWAC,
+					SK_HWEV_WATIM,
+					Para);
+			}
+
+			/* Restart needed */
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
+			break;
+
+		case SK_HW_PS_LINK:
+			/* Signal to RLMT */
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_UP, Para);
+			break;
+
+		}
+
+		/* Start again the check Timer */
+		if (pAC->GIni.GP[Port].PHWLinkUp) {
+			Time = SK_WA_ACT_TIME;
+		} else {
+			Time = SK_WA_INA_TIME;
+		}
+
+		/* todo: still needed for non-Xmac-PHYs ??? */
+		/* Start workaround Errata #2 timer */
+		SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer, Time,
+			SKGE_HWAC, SK_HWEV_WATIM, Para);
+
+		break;
+
+	case SK_HWEV_PORT_START:
+		if (pAC->GIni.GP[Port].PHWLinkUp) {
+			/*
+			 * Signal directly to RLMT to ensure correct
+			 * sequence of SWITCH and RESET event.
+			 */
+			Para.Para32[0] = (SK_U32) Port;
+			SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
+		}
+
+		SkHWLinkDown(pAC, IoC, Port) ;
+
+		/* Schedule Port RESET */
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
+
+		/* Start workaround Errata #2 timer */
+		SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer,
+			SK_WA_INA_TIME,SKGE_HWAC,SK_HWEV_WATIM,Para);
+		break;
+
+	case SK_HWEV_PORT_STOP:
+		if (pAC->GIni.GP[Port].PHWLinkUp) {
+			/*
+			 * Signal directly to RLMT to ensure correct
+			 * sequence of SWITCH and RESET event.
+			 */
+			Para.Para32[0] = (SK_U32) Port;
+			SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
+		}
+		/* Stop Workaround Timer */
+		SkTimerStop(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer) ;
+
+		SkHWLinkDown(pAC, IoC, Port) ;
+		break;
+
+	case SK_HWEV_UPDATE_STAT:
+		/* We do NOT need to update any statistics */
+		break;
+
+	case SK_HWEV_CLEAR_STAT:
+		/* We do NOT need to clear any statistics */
+		for (Port = 0; Port < (SK_U32) pAC->GIni.GIMacsFound; Port++) {
+			pAC->GIni.GP[Port].PPrevRx = 0;
+			pAC->GIni.GP[Port].PPrevFcs = 0;
+			pAC->GIni.GP[Port].PPrevShorts = 0;
+		}
+		break;
+
+	case SK_HWEV_SET_LMODE:
+		Val8 = (SK_U8) Para.Para32[1];
+		if (pAC->GIni.GP[Port].PLinkModeConf != Val8) {
+			/* Set New link mode */
+			pAC->GIni.GP[Port].PLinkModeConf = Val8;
+
+			/* Restart Port */
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+		}
+		break;
+
+	case SK_HWEV_SET_FLOWMODE:
+		Val8 = (SK_U8) Para.Para32[1];
+		if (pAC->GIni.GP[Port].PFlowCtrlMode != Val8) {
+			/* Set New Flow Control mode */
+			pAC->GIni.GP[Port].PFlowCtrlMode = Val8;
+
+			/* Restart Port */
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+		}
+		break;
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_SIRQ_E001,
+			SKERR_SIRQ_E001MSG);
+		break;
+	}
+
+	return(0) ;
+}
+
+
+/******************************************************************************
+ *
+ *	SkPhyIsrBcom - PHY interrupt service routine
+ *
+ * Description: handle all interrupts from BCOM PHY
+ *
+ * Returns: N/A
+ */
+static void SkPhyIsrBcom(
+SK_AC		*pAC,		/* Adapters context */
+SK_IOC		IoC,		/* Io Context */
+int		Port,		/* Port Num = PHY Num */
+SK_U16		IStatus)	/* Interrupts masked with PHY-Mask */
+{
+	SK_EVPARA	Para;
+
+	if (IStatus & PHY_B_IS_PSE) {
+		/* incorrectable pair swap error */
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E022,
+			SKERR_SIRQ_E022MSG) ;
+	}
+	
+	if (IStatus & PHY_B_IS_MDXI_SC) {
+		/* not used */
+	}
+	
+	if (IStatus & PHY_B_IS_HCT) {
+		/* not used */
+	}
+	
+	if (IStatus & PHY_B_IS_LCT) {
+		/* not used */
+	}
+	
+	if (IStatus & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) {
+		SkHWLinkDown(pAC, IoC, Port);
+
+		/* Signal to RLMT */
+		Para.Para32[0] = (SK_U32) Port;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+
+		/* Start workaround Errata #2 timer */
+		SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer,
+			SK_WA_INA_TIME,SKGE_HWAC,SK_HWEV_WATIM,Para);
+	}
+
+	if (IStatus & PHY_B_IS_NO_HDCL) {
+		/* not used */
+	}
+
+	if (IStatus & PHY_B_IS_NO_HDC) {
+		/* not used */
+	}
+
+	if (IStatus & PHY_B_IS_NEG_USHDC) {
+		/* not used */
+	}
+
+	if (IStatus & PHY_B_IS_SCR_S_ER) {
+		/* not used */
+	}
+
+	if (IStatus & PHY_B_IS_RRS_CHANGE) {
+		/* not used */
+	}
+
+	if (IStatus & PHY_B_IS_LRS_CHANGE) {
+		/* not used */
+	}
+
+	if (IStatus & PHY_B_IS_DUP_CHANGE) {
+		/* not used */
+	}
+
+	if (IStatus & PHY_B_IS_LSP_CHANGE) {
+		/* not used */
+	}
+
+	if (IStatus & PHY_B_IS_CRC_ER) {
+		/* not used */
+	}
+
+}
+
+
+/******************************************************************************
+ *
+ *	SkPhyIsrLone - PHY interrupt service routine
+ *
+ * Description: handle all interrupts from LONE PHY
+ *
+ * Returns: N/A
+ */
+static void SkPhyIsrLone(
+SK_AC		*pAC,		/* Adapters context */
+SK_IOC		IoC,		/* Io Context */
+int		Port,		/* Port Num = PHY Num */
+SK_U16		IStatus)	/* Interrupts masked with PHY-Mask */
+{
+	SK_EVPARA	Para;
+
+	if (IStatus & PHY_L_IS_CROSS) {
+		/* not used */
+	}
+	
+	if (IStatus & PHY_L_IS_POL) {
+		/* not used */
+	}
+	
+	if (IStatus & PHY_L_IS_SS) {
+		/* not used */
+	}
+	
+	if (IStatus & PHY_L_IS_CFULL) {
+		/* not used */
+	}
+	
+	if (IStatus & PHY_L_IS_AN_C) {
+		/* not used */
+	}
+	
+	if (IStatus & PHY_L_IS_SPEED) {
+		/* not used */
+	}
+	
+	if (IStatus & PHY_L_IS_CFULL) {
+		/* not used */
+	}
+	
+	if (IStatus & (PHY_L_IS_DUP | PHY_L_IS_ISOL)) {
+		SkHWLinkDown(pAC, IoC, Port);
+
+		/* Signal to RLMT */
+		Para.Para32[0] = (SK_U32) Port;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+
+		/* Start workaround Errata #2 timer */
+		SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer,
+			SK_WA_INA_TIME,SKGE_HWAC,SK_HWEV_WATIM,Para);
+	}
+
+	if (IStatus & PHY_L_IS_MDINT) {
+		/* not used */
+	}
+
+}
+
+
+/* End of File */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/ski2c.c linux.14p16/drivers/net/sk98lin/ski2c.c
--- linux.vanilla/drivers/net/sk98lin/ski2c.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/ski2c.c	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,1181 @@
+/******************************************************************************
+ *
+ * Name:	ski2c.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.41 $
+ * Date:	$Date: 1999/09/14 14:11:30 $
+ * Purpose:	Funktions to access Voltage and Temperature Sensor
+ *		(taken from Monalisa (taken from Concentrator))
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skge.c" for further 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 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: ski2c.c,v $
+ *	Revision 1.41  1999/09/14 14:11:30  malthoff
+ *	The 1000BT Dual Link adapter has got only one Fan.
+ *	The second Fan has been removed.
+ *	
+ *	Revision 1.40  1999/05/27 13:37:27  malthoff
+ *	Set divisor of 1 for fan count calculation.
+ *	
+ *	Revision 1.39  1999/05/20 14:54:43  malthoff
+ *	I2c.DummyReads is not used in Diagnostics.
+ *	
+ *	Revision 1.38  1999/05/20 09:20:56  cgoos
+ *	Changes for 1000Base-T (up to 9 sensors and fans).
+ *	
+ *	Revision 1.37  1999/03/25 15:11:36  gklug
+ *	fix: reset error flag if sensor reads correct value
+ *	
+ *	Revision 1.36  1999/01/07 14:11:16  gklug
+ *	fix: break added
+ *	
+ *	Revision 1.35  1999/01/05 15:31:49  gklug
+ *	fix: CLEAR STAT command is now added correctly
+ *	
+ *	Revision 1.34  1998/12/01 13:45:16  gklug
+ *	fix: introduced Init level, because we don't need reinits
+ *	
+ *	Revision 1.33  1998/11/09 14:54:25  malthoff
+ *	Modify I2C Transfer Timeout handling for Diagnostics.
+ *	
+ *	Revision 1.32  1998/11/03 06:54:35  gklug
+ *	fix: Need dummy reads at the beginning to init sensors
+ *
+ *	Revision 1.31  1998/11/03 06:42:42  gklug
+ *	fix: select correctVIO range only if between warning levels
+ *	
+ *	Revision 1.30  1998/11/02 07:36:53  gklug
+ *	fix: Error should not include WARNING message
+ *	
+ *	Revision 1.29  1998/10/30 15:07:43  malthoff
+ *	Disable 'I2C does not compelete' error log for diagnostics.
+ *	
+ *	Revision 1.28  1998/10/22 09:48:11  gklug
+ *	fix: SysKonnectFileId typo
+ *	
+ *	Revision 1.27  1998/10/20 09:59:46  gklug
+ *	add: parameter to SkOsGetTime
+ *	
+ *	Revision 1.26  1998/10/09 06:10:59  malthoff
+ *	Remove ID_sccs by SysKonnectFileId.
+ *	
+ *	Revision 1.25  1998/09/08 12:40:26  gklug
+ *	fix: syntax error in if clause
+ *	
+ *	Revision 1.24  1998/09/08 12:19:42  gklug
+ *	chg: INIT Level checking
+ *	
+ *	Revision 1.23  1998/09/08 07:37:20  gklug
+ *	fix: log error if PCI_IO voltage sensor could not be initialized
+ *	
+ *	Revision 1.22  1998/09/04 08:30:03  malthoff
+ *	Bugfixes during SK_DIAG testing:
+ *	- correct NS2BCLK() macro
+ *	- correct SkI2cSndDev()
+ *	- correct SkI2cWait() loop waiting for an event
+ *	
+ *	Revision 1.21  1998/08/27 14:46:01  gklug
+ *	chg: if-then-else replaced by switch
+ *
+ *	Revision 1.20  1998/08/27 14:40:07  gklug
+ *	test: integral types
+ *	
+ *	Revision 1.19  1998/08/25 07:51:54  gklug
+ *	fix: typos for compiling
+ *	
+ *	Revision 1.18  1998/08/25 06:12:24  gklug
+ *	add: count errors and warnings
+ *	fix: check not the sensor state but the ErrFlag!
+ *	
+ *	Revision 1.17  1998/08/25 05:56:48  gklug
+ *	add: CheckSensor function
+ *	
+ *	Revision 1.16  1998/08/20 11:41:10  gklug
+ *	chg: omit STRCPY macro by using char * as Sensor Description
+ *	
+ *	Revision 1.15  1998/08/20 11:37:35  gklug
+ *	chg: change Ioc to IoC
+ *	
+ *	Revision 1.14  1998/08/20 11:32:52  gklug
+ *	fix: Para compile error
+ *	
+ *	Revision 1.13  1998/08/20 11:27:41  gklug
+ *	fix: Compile bugs with new awrning constants
+ *	
+ *	Revision 1.12  1998/08/20 08:53:05  gklug
+ *	fix: compiler errors
+ *	add: Threshold values
+ *	
+ *	Revision 1.11  1998/08/19 12:39:22  malthoff
+ *	Compiler Fix: Some names have changed.
+ *	
+ *	Revision 1.10  1998/08/19 12:20:56  gklug
+ *	fix: remove struct from C files (see CCC)
+ *	
+ *	Revision 1.9  1998/08/19 06:28:46  malthoff
+ *	SkOsGetTime returns SK_U64 now.
+ *	
+ *	Revision 1.8  1998/08/17 13:53:33  gklug
+ *	fix: Parameter of event function and its result
+ *	
+ *	Revision 1.7  1998/08/17 07:02:15  malthoff
+ *	Modify the functions for accessing the I2C SW Registers.
+ *	Modify SkI2cWait().
+ *	Put Lm80RcvReg into sklm80.c
+ *	Remove Compiler Errors.
+ *	
+ *	Revision 1.6  1998/08/14 07:13:20  malthoff
+ *	remove pAc with pAC
+ *	remove smc with pAC
+ *	change names to new convention
+ *
+ *	Revision 1.5  1998/08/14 06:24:49  gklug
+ *	add: init level 1 and 2
+ *
+ *	Revision 1.4  1998/08/12 14:31:12  gklug
+ *	add: error log for unknown event
+ *
+ *	Revision 1.3  1998/08/12 13:37:04  gklug
+ *	add: Init 0 function
+ *
+ *	Revision 1.2  1998/08/11 07:27:15  gklug
+ *	add: functions of the interface
+ *	adapt rest of source to C coding Conventions
+ *	rmv: unneccessary code taken from Mona Lisa
+ *
+ *	Revision 1.1  1998/06/19 14:28:43  malthoff
+ *	Created. Sources taken from ML Projekt.
+ *	Sources have to be reworked for GE.
+ *
+ *
+ ******************************************************************************/
+
+
+/*
+	i2C Protocol
+*/
+static const char SysKonnectFileId[] =
+	"$Id: ski2c.c,v 1.41 1999/09/14 14:11:30 malthoff Exp $" ;
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/lm80.h"
+#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+	I2C protocol implemetation.
+
+	General Description:
+
+	The I2C protocol is used for the temperature sensors and for
+	the serial EEPROM which hold the configuration.
+
+	This file covers functions that allow to read write and do
+	some bulk requests a specified I2C address.
+
+	The Genesis has 2 I2C busses. One for the EEPROM which holds
+	the VPD Data and one for temperature and voltage sensor.
+	The following picture shows the I2C busses, I2C devices and
+	there control registers.
+
+	Note: The VPD functions are in skvpd.c
+.
+.	PCI Config I2C Bus for VPD Data:
+.
+.		      +------------+
+.		      | VPD EEPROM |
+.		      +------------+
+.			     |
+.			     | <-- I2C
+.			     |
+.		 +-----------+-----------+
+.		 |			 |
+.	+-----------------+	+-----------------+
+.	| PCI_VPD_ADR_REG |	| PCI_VPD_DAT_REG |
+.	+-----------------+	+-----------------+
+.
+.
+.	I2C Bus for LM80 sensor:
+.
+.			+-----------------+
+.			| Temperature and |
+.			| Voltage Sensor  |
+.			| 	LM80	  |
+.			+-----------------+
+.				|
+.				|
+.			I2C --> |
+.				|
+.			     +----+
+.	     +-------------->| OR |<--+
+.	     |		     +----+   |
+.     +------+------+		      |
+.     |		    |		      |
+. +--------+	+--------+	+----------+
+. | B2_I2C |	| B2_I2C |	|  B2_I2C  |
+. | _CTRL  |	| _DATA  |	|   _SW    |
+. +--------+	+--------+	+----------+
+.
+	The I2C bus may be driven by the B2_I2C_SW or by the B2_I2C_CTRL
+	and B2_I2C_DATA registers.
+	For driver software it is recommended to use the I2C control and
+	data register, because I2C bus timing is done by the ASIC and
+	an interrupt may be received when the I2C request is completed.
+
+	Clock Rate Timing:			MIN	MAX	generated by
+		VPD EEPROM:			50 kHz	100 kHz		HW
+		LM80 over I2C Ctrl/Data reg.	50 kHz	100 kHz		HW
+		LM80 over B2_I2C_SW register	0	400 kHz		SW
+
+	Note:	The clock generated by the hardware is dependend on the
+		PCI clock. If the PCI bus clock is 33 MHz, the I2C/VPD
+		clock is 50 kHz.
+ */
+intro()
+{}
+#endif
+
+#ifdef	SK_DIAG
+/*
+ * I2C Fast Mode timing values used by the LM80.
+ * If new devices are added to the I2C bus the timing values have to be checked.
+ */
+#ifndef I2C_SLOW_TIMING
+#define	T_CLK_LOW		1300L	/* clock low time in ns */
+#define	T_CLK_HIGH		 600L	/* clock high time in ns */
+#define T_DATA_IN_SETUP		 100L	/* data in Set-UP Time */
+#define T_START_HOLD		 600L	/* start condition hold time */
+#define T_START_SETUP		 600L	/* start condition Set-up time */
+#define	T_STOP_SETUP		 600L	/* stop condition Set-up time */
+#define T_BUS_IDLE		1300L	/* time the bus must free after tx */
+#define	T_CLK_2_DATA_OUT	 900L	/* max. clock low to data output valid */
+#else	/* I2C_SLOW_TIMING */
+/* I2C Standard Mode Timing */
+#define	T_CLK_LOW		4700L	/* clock low time in ns */
+#define	T_CLK_HIGH		4000L	/* clock high time in ns */
+#define T_DATA_IN_SETUP		 250L	/* data in Set-UP Time */
+#define T_START_HOLD		4000L	/* start condition hold time */
+#define T_START_SETUP		4700L	/* start condition Set_up time */
+#define	T_STOP_SETUP		4000L	/* stop condition Set-up time */
+#define T_BUS_IDLE		4700L	/* time the bus must free after tx */
+#endif	/* !I2C_SLOW_TIMING */
+
+#define NS2BCLK(x)	(((x)*125)/10000)
+
+/*
+ * I2C Wire Operations
+ *
+ * About I2C_CLK_LOW():
+ *
+ * The Data Direction bit (I2C_DATA_DIR) has to be set to input when setting
+ * clock to low, to prevent the ASIC and the I2C data client from driving the
+ * serial data line simultaneously (ASIC: last bit of a byte = '1', I2C client
+ * send an 'ACK'). See also Concentrator Bugreport No. 10192.
+ */
+#define I2C_DATA_HIGH(IoC)	SK_I2C_SET_BIT(IoC,I2C_DATA)
+#define	I2C_DATA_LOW(IoC)	SK_I2C_CLR_BIT(IoC,I2C_DATA)
+#define	I2C_DATA_OUT(IoC)	SK_I2C_SET_BIT(IoC,I2C_DATA_DIR)
+#define	I2C_DATA_IN(IoC)	SK_I2C_CLR_BIT(IoC,I2C_DATA_DIR|I2C_DATA)
+#define	I2C_CLK_HIGH(IoC)	SK_I2C_SET_BIT(IoC,I2C_CLK)
+#define	I2C_CLK_LOW(IoC)	SK_I2C_CLR_BIT(IoC,I2C_CLK|I2C_DATA_DIR)
+#define	I2C_START_COND(IoC)	SK_I2C_CLR_BIT(IoC,I2C_CLK)
+
+#define NS2CLKT(x)	((x*125L)/10000)
+
+/*--------------- I2C Interface Register Functions --------------- */
+
+/*
+ * sending one bit
+ */
+void SkI2cSndBit(
+SK_IOC	IoC,	/* IoContext */
+SK_U8	Bit)	/* Bit to send */
+{
+	I2C_DATA_OUT(IoC) ;
+	if (Bit) {
+		I2C_DATA_HIGH(IoC);
+	} else {
+		I2C_DATA_LOW(IoC);
+	}
+	SkDgWaitTime(IoC,NS2BCLK(T_DATA_IN_SETUP));
+	I2C_CLK_HIGH(IoC);
+	SkDgWaitTime(IoC,NS2BCLK(T_CLK_HIGH));
+	I2C_CLK_LOW(IoC);
+}
+
+
+
+/*
+ * Signal a start to the i2C Bus.
+ *
+ * A start is signaled when data goes to low in a high clock cycle.
+ *
+ * Ends with Clock Low.
+ *
+ * Status: not tested
+ */
+void SkI2cStart(SK_IOC	IoC)	/* I/O Context */
+{
+	/* Init data and Clock to output lines */
+	/* Set Data high */
+	I2C_DATA_OUT(IoC) ;
+	I2C_DATA_HIGH(IoC) ;
+	/* Set Clock high */
+	I2C_CLK_HIGH(IoC) ;
+
+	SkDgWaitTime(IoC,NS2BCLK(T_START_SETUP)) ;
+
+	/* Set Data Low */
+	I2C_DATA_LOW(IoC) ;
+
+	SkDgWaitTime(IoC,NS2BCLK(T_START_HOLD)) ;
+
+	/* Clock low without Data to Input */
+	I2C_START_COND(IoC) ;
+
+	SkDgWaitTime(IoC,NS2BCLK(T_CLK_LOW)) ;
+}
+
+
+void SkI2cStop(SK_IOC	IoC)	/* I/O Context */
+{
+	/* Init data and Clock to output lines */
+	/* Set Data low */
+	I2C_DATA_OUT(IoC) ;
+	I2C_DATA_LOW(IoC) ;
+
+	SkDgWaitTime(IoC,NS2BCLK(T_CLK_2_DATA_OUT)) ;
+
+	/* Set Clock high */
+	I2C_CLK_HIGH(IoC) ;
+
+	SkDgWaitTime(IoC,NS2BCLK(T_STOP_SETUP)) ;
+
+	/*
+	 * Set Data High:	Do it by setting the Data Line to Input.
+	 *			Because of a pull up resistor the Data Line
+	 *			floods to high.
+	 */
+	I2C_DATA_IN(IoC) ;
+
+	/*
+	 *	When I2C activity is stopped
+	 *	 o	DATA should be set to input and
+	 *	 o	CLOCK should be set to high!
+	 */
+	SkDgWaitTime(IoC,NS2BCLK(T_BUS_IDLE)) ;
+}
+
+/*
+ * Receive just one bit via the i2C bus.
+ *
+ * Note:	Clock must be set to LOW before calling this function.
+ *
+ * Returns The received bit.
+ */
+int SkI2cRcvBit(SK_IOC	IoC)	/* I/O Context */
+{
+	int	Bit;
+	SK_U8	I2cSwCtrl;
+
+	/* Init data as input line */
+	I2C_DATA_IN(IoC);
+
+	SkDgWaitTime(IoC,NS2BCLK(T_CLK_2_DATA_OUT)) ;
+
+	I2C_CLK_HIGH(IoC);
+
+	SkDgWaitTime(IoC,NS2BCLK(T_CLK_HIGH)) ;
+
+	SK_I2C_GET_SW(IoC,&I2cSwCtrl) ;
+	if (I2cSwCtrl & I2C_DATA) {
+		Bit = 1;
+	} else {
+		Bit = 0;
+	}
+
+	I2C_CLK_LOW(IoC);
+	SkDgWaitTime(IoC,NS2BCLK(T_CLK_LOW-T_CLK_2_DATA_OUT)) ;
+
+	return(Bit);
+}
+
+/*
+ * Receive an ACK.
+ *
+ * returns	0 If acknoledged
+ *		1 in case of an error
+ */
+int SkI2cRcvAck(SK_IOC IoC)	/* I/O Context */
+{
+	/*
+	 * Received bit must be zero.
+	 */
+	return (SkI2cRcvBit(IoC) != 0) ;
+}
+
+/*
+ * Send an NACK.
+ */
+void SkI2cSndNAck(SK_IOC IoC)	/* I/O Context */
+{
+	/*
+	 * Received bit must be zero.
+	 */
+	SkI2cSndBit(IoC,1) ;
+}
+
+/*
+ * Send an ACK.
+ */
+void SkI2cSndAck(SK_IOC IoC)	/* I/O Context */
+{
+	/*
+	 * Received bit must be zero.
+	 *
+	 */
+	SkI2cSndBit(IoC,0) ;
+}
+
+/*
+ * Send one byte to the i2C device and wait for ACK.
+ *
+ * Return acknoleged status.
+ */
+int SkI2cSndByte(
+SK_IOC	IoC,	/* I/O Context */
+int	Byte)	/* byte to send */
+{
+	int	i;
+
+	for (i=0; i<8; i++) {
+		if (Byte & (1<<(7-i))) {
+			SkI2cSndBit(IoC,1) ;
+		} else {
+			SkI2cSndBit(IoC,0) ;
+		}
+	}
+
+	return(SkI2cRcvAck(IoC)) ;
+}
+
+
+/*
+ * Receive one byte and ack it.
+ *
+ * Return byte.
+ */
+int SkI2cRcvByte(
+SK_IOC	IoC,	/* I/O Context */
+int	Last)	/* Last Byte Flag */
+{
+	int	i;
+	int	Byte = 0;
+
+	for (i=0; i<8; i++) {
+		Byte <<= 1 ;
+		Byte |= SkI2cRcvBit(IoC) ;
+	}
+
+	if (Last) {
+		SkI2cSndNAck(IoC) ;
+	} else {
+		SkI2cSndAck(IoC) ;
+	}
+
+	return(Byte) ;
+}
+
+
+/*
+ * Start dialog and send device address
+ *
+ * Return 0 if acknoleged, 1 in case of an error
+ */
+int	SkI2cSndDev(
+SK_IOC	IoC,	/* I/O Context */
+int	Addr,	/* Device Address */
+int	Rw)	/* Read / Write Flag */
+{
+	SkI2cStart(IoC) ;
+	Rw = ~Rw ; 
+	Rw &= I2C_WRITE ;
+	return(SkI2cSndByte(IoC, (Addr<<1) | Rw)) ;
+}
+
+#endif	/* SK_DIAG */
+
+/*----------------- I2C CTRL Register Functions ----------*/
+
+/*
+ * waits for a completetion of a I2C transfer
+ *
+ * returns	0:	success, transfer completes
+ *		1:	error,	 transfer does not complete, I2C transfer
+ *				 killed, wait loop terminated.
+ */
+int	SkI2cWait(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* IoContext */
+int	Event)	/* complete event to wait for (I2C_READ or I2C_WRITE) */
+{
+	SK_U64	StartTime ;
+	SK_U32	I2cCtrl ;
+
+	StartTime = SkOsGetTime(pAC) ;
+	do {
+		if (SkOsGetTime(pAC) - StartTime > SK_TICKS_PER_SEC/16) {
+			SK_I2C_STOP(IoC) ;
+#ifndef SK_DIAG
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E002,
+				SKERR_I2C_E002MSG) ;
+#endif	/* !SK_DIAG */
+			return(1) ;
+		}
+		SK_I2C_GET_CTL(IoC,&I2cCtrl) ;
+	} while((I2cCtrl & I2C_FLAG) == (SK_U32)Event << 31) ;
+
+	return(0) ;
+}
+
+#ifdef	SK_DIAG
+/*
+ * writes a single byte or 4 bytes into the I2C device
+ *
+ * returns	0:	success
+ *		1:	error
+ */
+int SkI2cWrite(
+SK_AC	*pAC,	/* Adapter Context */
+SK_U32	I2cData,	/* I2C Data to write */
+int	I2cDev,		/* I2C Device Address */
+int	I2cReg,		/* I2C Device Register Address */
+int	I2cBurst)	/* I2C Burst Flag ( 0 || I2C_BURST ) */
+{
+	SK_OUT32(pAC,B2_I2C_DATA,I2cData) ;
+	SK_I2C_CTL(pAC,I2C_WRITE,I2cDev,I2cReg,I2cBurst);
+	return(SkI2cWait(pAC,pAC,I2C_WRITE)) ;
+}
+
+/*
+ * reads a single byte or 4 bytes from the I2C device
+ *
+ * returns	the word read
+ */
+SK_U32 SkI2cRead(
+SK_AC	*pAC,	/* Adapter Context */
+int	I2cDev,		/* I2C Device Address */
+int	I2cReg,		/* I2C Device Register Address */
+int	I2cBurst)	/* I2C Burst Flag ( 0 || I2C_BURST ) */
+{
+	SK_U32	Data ;
+
+	SK_OUT32(pAC,B2_I2C_DATA,0) ;
+	SK_I2C_CTL(pAC,I2C_READ,I2cDev,I2cReg,I2cBurst);
+	if (SkI2cWait(pAC,pAC,I2C_READ)) {
+		w_print("I2c Transfer Timeout!\n"); 
+	}
+	SK_IN32(pAC,B2_I2C_DATA,&Data) ;
+	return(Data) ;
+}
+#endif	/* SK_DIAG */
+
+/*
+ * read a sensors value
+ *
+ * This function read a sensors value from the I2c sensor chip. The sensor
+ * is defined by its index into the sensors database in the struct pAC points
+ * to.
+ * Returns	1 if the read is completed
+ *		0 if the read must be continued (I2c Bus still allocated)
+ */
+int	SkI2cReadSensor(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* IoContext */
+SK_SENSOR	*pSen)	/* Sensor to be read */
+{
+	return((*pSen->SenRead)(pAC,IoC,pSen)) ;
+}
+
+/*
+ * Do the Init state 0 initialization
+ */
+static	int	SkI2cInit0(
+SK_AC	*pAC)	/* Adapter Context */
+{
+	int	i;
+
+	/* Begin with first sensor */
+	pAC->I2c.CurrSens = 0;
+	
+	/* Set to mimimum sensor number */
+	pAC->I2c.MaxSens = SK_MIN_SENSORS;
+
+#ifndef	SK_DIAG
+	/* Initialize Number of Dummy Reads */
+	pAC->I2c.DummyReads = SK_MAX_SENSORS;
+#endif
+
+	for (i=0; i < SK_MAX_SENSORS; i ++) {
+		switch (i) {
+		case 0:
+			pAC->I2c.SenTable[i].SenDesc = "Temperature" ;
+			pAC->I2c.SenTable[i].SenType = SK_SEN_TEMP;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH0;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW0;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_WARNHIGH0;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_WARNLOW0;
+			pAC->I2c.SenTable[i].SenReg = LM80_TEMP_IN;
+			pAC->I2c.SenTable[i].SenInit = SK_TRUE;
+			break;
+		case 1:
+			pAC->I2c.SenTable[i].SenDesc = "Voltage PCI";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH1;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW1;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_WARNHIGH1;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_WARNLOW1;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT0_IN;
+			pAC->I2c.SenTable[i].SenInit = SK_TRUE;
+			break;
+		case 2:
+			pAC->I2c.SenTable[i].SenDesc = "Voltage PCI-IO";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH2;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW2;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_WARNHIGH2;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_WARNLOW2;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT1_IN;
+			pAC->I2c.SenTable[i].SenInit = SK_FALSE;
+			break;
+		case 3:
+			pAC->I2c.SenTable[i].SenDesc = "Voltage ASIC";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH3;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW3;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_WARNHIGH3;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_WARNLOW3;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT2_IN;
+			pAC->I2c.SenTable[i].SenInit = SK_TRUE;
+			break;
+		case 4:
+			pAC->I2c.SenTable[i].SenDesc = "Voltage PMA";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH4;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW4;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_WARNHIGH4;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_WARNLOW4;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT3_IN;
+			pAC->I2c.SenTable[i].SenInit = SK_TRUE;
+			break;
+		case 5:
+			pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 2V5";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH5;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW5;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_WARNHIGH5;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_WARNLOW5;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT4_IN;
+			pAC->I2c.SenTable[i].SenInit = SK_TRUE;
+			break;
+		case 6:
+			pAC->I2c.SenTable[i].SenDesc = "Voltage PHY B PLL";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH6;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW6;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_WARNHIGH6;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_WARNLOW6;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT5_IN;
+			pAC->I2c.SenTable[i].SenInit = SK_TRUE;
+			break;
+		case 7:
+			pAC->I2c.SenTable[i].SenDesc = "Speed Fan";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_FAN;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_WARNHIGH;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_WARNLOW;
+			pAC->I2c.SenTable[i].SenReg = LM80_FAN2_IN;
+			pAC->I2c.SenTable[i].SenInit = SK_TRUE;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_INIT | SK_ERRCL_SW,
+				SKERR_I2C_E001, SKERR_I2C_E001MSG);
+			break;
+		}
+
+		pAC->I2c.SenTable[i].SenValue = 0;
+		pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK;
+		pAC->I2c.SenTable[i].SenErrCts = 0;
+		pAC->I2c.SenTable[i].SenBegErrTS = 0;
+		pAC->I2c.SenTable[i].SenState = SK_SEN_IDLE;
+		pAC->I2c.SenTable[i].SenRead = SkLm80ReadSensor;
+		pAC->I2c.SenTable[i].SenDev = LM80_ADDR;
+	}
+
+	/* Now we are INIT dataed */
+	pAC->I2c.InitLevel = SK_INIT_DATA;
+	return(0);
+}
+
+/*
+ * Do the init state 1 initialization
+ *
+ * initialize the following register of the LM80:
+ * Configuration register:
+ * - START, noINT, activeLOW, noINT#Clear, noRESET, noCI, noGPO#, noINIT
+ *
+ * Interrupt Mask Register 1:
+ * - all interrupts are Disabled (0xff)
+ *
+ * Interrupt Mask Register 2:
+ * - all interrupts are Disabled (0xff) Interrupt modi doesn't matter.
+ *
+ * Fan Divisor/RST_OUT register:
+ * - Divisors set to 1 (bits 00), all others 0s.
+ *
+ * OS# Configuration/Temperature resolution Register:
+ * - all 0s
+ *
+ */
+static	int	SkI2cInit1(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC)	/* IoContext needed in level 1 */
+{
+	if (pAC->I2c.InitLevel != SK_INIT_DATA) {
+		/* ReInit not needed in I2C module */
+		return(0);
+	}
+
+	SK_OUT32(IoC, B2_I2C_DATA, 0);
+	SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_CFG, 0);
+	(void)SkI2cWait(pAC, IoC, I2C_WRITE) ;
+
+	SK_OUT32(IoC, B2_I2C_DATA, 0xff);
+	SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_IMSK_1, 0);
+	(void)SkI2cWait(pAC, IoC, I2C_WRITE) ;
+
+	SK_OUT32(IoC, B2_I2C_DATA, 0xff);
+	SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_IMSK_2, 0);
+	(void)SkI2cWait(pAC, IoC, I2C_WRITE) ;
+
+	SK_OUT32(IoC, B2_I2C_DATA, 0x0);
+	SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_FAN_CTRL, 0);
+	(void)SkI2cWait(pAC, IoC, I2C_WRITE) ;
+
+	SK_OUT32(IoC, B2_I2C_DATA, 0);
+	SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_TEMP_CTRL, 0);
+	(void)SkI2cWait(pAC, IoC, I2C_WRITE) ;
+
+	SK_OUT32(IoC, B2_I2C_DATA, LM80_CFG_START);
+	SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_CFG, 0);
+	(void)SkI2cWait(pAC, IoC, I2C_WRITE) ;
+
+	/*
+	 * MaxSens has to be initialized here, because PhyType is not
+	 * set when performing Init Level 1
+	 */
+	switch (pAC->GIni.GP[0].PhyType) {
+	case SK_PHY_XMAC:
+		pAC->I2c.MaxSens = 5;
+		break;
+	case SK_PHY_BCOM:
+		pAC->I2c.SenTable[4].SenDesc = "Voltage PHY A PLL";
+		if (pAC->GIni.GIMacsFound == 1) {
+			pAC->I2c.MaxSens = 6;
+		} 
+		else {
+			pAC->I2c.MaxSens = 8;
+		}
+		break;
+	case SK_PHY_LONE:
+		pAC->I2c.MaxSens = 5;
+		break;
+	}
+	
+#ifndef	SK_DIAG
+	pAC->I2c.DummyReads = pAC->I2c.MaxSens;
+#endif	/* !SK_DIAG */
+	
+	/* Now we are IO initialized */
+	pAC->I2c.InitLevel = SK_INIT_IO;
+	return(0);
+}
+
+/*
+ * Init level 2: Start first sensors read
+ */
+static	int	SkI2cInit2(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC)	/* IoContext needed in level 1 */
+{
+	int		ReadComplete;
+	SK_SENSOR	*pSen;
+
+	if (pAC->I2c.InitLevel != SK_INIT_IO) {
+		/* ReInit not needed in I2C module */
+		/* Init0 and Init2 not permitted */
+		return(0);
+	}
+
+	pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+	ReadComplete = SkI2cReadSensor(pAC,IoC,pSen);
+
+	if (ReadComplete) {
+		SK_ERR_LOG(pAC, SK_ERRCL_INIT, SKERR_I2C_E008,
+			SKERR_I2C_E008MSG);
+	}
+
+	/* Now we are correctly initialized */
+	pAC->I2c.InitLevel = SK_INIT_RUN;
+
+	return(0);
+}
+
+/*
+ * Initialize I2C devices
+ *
+ * Get the first voltage value and discard it.
+ * Go into temperature read mode. A default pointer is not set.
+ *
+ * The things to be done depend on the init level in the parameter list:
+ * Level 0:
+ *	Initialize only the data structures. Do NOT access hardware.
+ * Level 1:
+ *	Initialize hardware through SK_IN?OUT commands. Do NOT use interrupts.
+ * Level 2:
+ *	Everything is possible. Interrupts may be used from now on.
+ *
+ * return:	0 = success
+ *		other = error.
+ */
+int	SkI2cInit(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* IoContext needed in level 1 */
+int	Level)	/* Init Level */
+{
+
+	switch (Level) {
+	case SK_INIT_DATA:
+		return(SkI2cInit0(pAC)) ;
+	case SK_INIT_IO:
+		return(SkI2cInit1(pAC, IoC)) ;
+	case SK_INIT_RUN:
+		return(SkI2cInit2(pAC, IoC)) ;
+	default:
+		break;
+	}
+
+	return(0) ;
+}
+
+#ifndef SK_DIAG
+/*
+ * Interrupt service function for the I2c Interface
+ *
+ * Clears the Interrupt source
+ *
+ * Reads the register and check it for sending a trap.
+ *
+ * Starts the timer if necessary.
+ */
+void	SkI2cIsr(
+SK_AC	*pAC,		/* Adapters context */
+SK_IOC	IoC)		/* Io Context */
+{
+	SK_EVPARA	Para;
+
+	/* Clear the interrupt source */
+	SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ) ;
+
+	Para.Para64 = 0;
+	SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_IRQ, Para);
+}
+
+/*
+ * Check this sensors Value against the threshold and send events.
+ */
+static	void	SkI2cCheckSensor(
+SK_AC		*pAC,		/* Adapters context */
+SK_SENSOR	*pSen)
+{
+	SK_EVPARA	ParaLocal;
+	SK_BOOL		TooHigh;	/* Is sensor too high? */
+	SK_BOOL		TooLow;		/* Is sensor too low? */
+	SK_U64		CurrTime;	/* current Time */
+	SK_BOOL		DoTrapSend;	/* We need to send a trap */
+	SK_BOOL		DoErrLog;	/* We need to log the error */
+	SK_BOOL		IsError;	/* We need to log the error */
+
+	/* Check Dummy Reads first */
+	if (pAC->I2c.DummyReads > 0) {
+		pAC->I2c.DummyReads -- ;
+		return;
+	}
+
+	/* Get the current time */
+	CurrTime = SkOsGetTime(pAC) ;
+
+	/* Set para to the most usefull setting:
+	 * The current sensor.
+	 */
+	ParaLocal.Para64 = (SK_U64) pAC->I2c.CurrSens;
+
+	/* Check the Value against the thresholds */
+	/* First: Error Thresholds */
+	TooHigh = (pSen->SenValue > pSen->SenThreErrHigh) ;
+	TooLow = (pSen->SenValue < pSen->SenThreErrLow) ;
+		
+	IsError = SK_FALSE ;
+	if (TooHigh || TooLow) {
+		/* Error condition is satiesfied */
+		DoTrapSend = SK_TRUE;
+		DoErrLog = SK_TRUE;
+
+		/* Now error condition is satisfied */
+		IsError = SK_TRUE ;
+
+		if (pSen->SenErrFlag == SK_SEN_ERR_ERR) {
+			/* This state is the former one */
+
+			/* So check first whether we have to send a trap */
+			if (pSen->SenLastErrTrapTS + SK_SEN_ERR_TR_HOLD >
+			    CurrTime) {
+				/*
+				 * Do NOT send the Trap. The hold back time
+				 * has to run out first.
+				 */
+				DoTrapSend = SK_FALSE;
+			}
+
+			/* Check now whether we have to log an Error */
+			if (pSen->SenLastErrLogTS + SK_SEN_ERR_LOG_HOLD >
+			    CurrTime) {
+				/*
+				 * Do NOT log the error. The hold back time
+				 * has to run out first.
+				 */
+				DoErrLog = SK_FALSE;
+			}
+		} else {
+			/* We came from a different state */
+			/* -> Set Begin Time Stamp */
+			pSen->SenBegErrTS = CurrTime;
+			pSen->SenErrFlag = SK_SEN_ERR_ERR ;
+		}
+
+		if (DoTrapSend) {
+			/* Set current Time */
+			pSen->SenLastErrTrapTS = CurrTime;
+			pSen->SenErrCts ++;
+
+			/* Queue PNMI Event */
+			SkEventQueue(pAC, SKGE_PNMI, (TooHigh ?
+				SK_PNMI_EVT_SEN_ERR_UPP :
+				SK_PNMI_EVT_SEN_ERR_LOW),
+				ParaLocal) ;
+		}
+
+		if (DoErrLog) {
+			/* Set current Time */
+			pSen->SenLastErrLogTS = CurrTime;
+
+			if (pSen->SenType == SK_SEN_TEMP) {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E011,
+					SKERR_I2C_E011MSG);
+			} else if (pSen->SenType == SK_SEN_VOLT) {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E012,
+					SKERR_I2C_E012MSG);
+			} else
+			{
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E015,
+					SKERR_I2C_E015MSG);
+			}
+		}
+	}
+
+	/* Check the Value against the thresholds */
+	/* 2nd: Warning thresholds */
+	TooHigh = (pSen->SenValue > pSen->SenThreWarnHigh) ;
+	TooLow = (pSen->SenValue < pSen->SenThreWarnLow) ;
+		
+
+	if (!IsError && (TooHigh || TooLow)) {
+		/* Error condition is satiesfied */
+		DoTrapSend = SK_TRUE;
+		DoErrLog = SK_TRUE;
+
+		if (pSen->SenErrFlag == SK_SEN_ERR_WARN) {
+			/* This state is the former one */
+
+			/* So check first whether we have to send a trap */
+			if (pSen->SenLastWarnTrapTS + SK_SEN_WARN_TR_HOLD >
+			    CurrTime) {
+				/*
+				 * Do NOT send the Trap. The hold back time
+				 * has to run out first.
+				 */
+				DoTrapSend = SK_FALSE;
+			}
+
+			/* Check now whether we have to log an Error */
+			if (pSen->SenLastWarnLogTS + SK_SEN_WARN_LOG_HOLD >
+			    CurrTime) {
+				/*
+				 * Do NOT log the error. The hold back time
+				 * has to run out first.
+				 */
+				DoErrLog = SK_FALSE;
+			}
+		} else {
+			/* We came from a different state */
+			/* -> Set Begin Time Stamp */
+			pSen->SenBegWarnTS = CurrTime;
+			pSen->SenErrFlag = SK_SEN_ERR_WARN ;
+		}
+
+		if (DoTrapSend) {
+			/* Set current Time */
+			pSen->SenLastWarnTrapTS = CurrTime;
+			pSen->SenWarnCts ++;
+
+			/* Queue PNMI Event */
+			SkEventQueue(pAC, SKGE_PNMI, (TooHigh ?
+				SK_PNMI_EVT_SEN_WAR_UPP :
+				SK_PNMI_EVT_SEN_WAR_LOW),
+				ParaLocal) ;
+		}
+
+		if (DoErrLog) {
+			/* Set current Time */
+			pSen->SenLastWarnLogTS = CurrTime;
+
+			if (pSen->SenType == SK_SEN_TEMP) {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E009,
+					SKERR_I2C_E009MSG);
+			} else if (pSen->SenType == SK_SEN_VOLT) {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E009,
+					SKERR_I2C_E009MSG);
+			} else
+			{
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E014,
+					SKERR_I2C_E014MSG);
+			}
+		}
+	}
+
+	/* Check for NO error at all */
+	if (!IsError && !TooHigh && !TooLow) {
+		/* Set o.k. Status if no error and no warning condition */
+		pSen->SenErrFlag = SK_SEN_ERR_OK ;
+	}
+
+	/* End of check against the thresholds */
+
+	/*
+	 * Check initialization state:
+	 * The VIO Thresholds need adaption
+	 */
+	if (!pSen->SenInit && pSen->SenReg == LM80_VT1_IN &&
+	     pSen->SenValue > SK_SEN_WARNLOW2C &&
+	     pSen->SenValue < SK_SEN_WARNHIGH2) {
+		pSen->SenThreErrLow = SK_SEN_ERRLOW2C; 
+		pSen->SenThreWarnLow = SK_SEN_WARNLOW2C; 
+		pSen->SenInit = SK_TRUE;
+	}
+
+	if (!pSen->SenInit && pSen->SenReg == LM80_VT1_IN &&
+	     pSen->SenValue > SK_SEN_WARNLOW2 &&
+	     pSen->SenValue < SK_SEN_WARNHIGH2C) {
+		pSen->SenThreErrHigh = SK_SEN_ERRHIGH2C; 
+		pSen->SenThreWarnHigh = SK_SEN_WARNHIGH2C; 
+		pSen->SenInit = SK_TRUE;
+	}
+
+	if (!pSen->SenInit) {
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E013, SKERR_I2C_E013MSG);
+	}
+}
+
+/*
+ * The only Event to be served is the timeout event
+ *
+ */
+int	SkI2cEvent(
+SK_AC		*pAC,		/* Adapters context */
+SK_IOC		IoC,		/* Io Context */
+SK_U32		Event,		/* Module specific Event */
+SK_EVPARA	Para)		/* Event specific Parameter */
+{
+	int		ReadComplete;
+	SK_SENSOR	*pSen;
+	SK_U32		Time;
+	SK_EVPARA	ParaLocal;
+	int		i;
+
+	switch (Event) {
+	case SK_I2CEV_IRQ:
+	case SK_I2CEV_TIM:
+		pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+		ReadComplete = SkI2cReadSensor(pAC, IoC, pSen);
+
+		if (ReadComplete) {
+			/* Check sensor against defined thresholds */
+			SkI2cCheckSensor (pAC, pSen) ;
+
+			/* Increment Current and set appropriate Timeout */
+			Time = SK_I2C_TIM_SHORT;
+
+			pAC->I2c.CurrSens ++;
+			if (pAC->I2c.CurrSens == pAC->I2c.MaxSens) {
+				pAC->I2c.CurrSens = 0;
+				Time = SK_I2C_TIM_LONG;
+			}
+
+			/* Start Timer */
+			ParaLocal.Para64 = (SK_U64) 0;
+			SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time,
+				SKGE_I2C, SK_I2CEV_TIM, ParaLocal) ;
+		}
+		break;
+	case SK_I2CEV_CLEAR:
+		for (i=0; i < SK_MAX_SENSORS; i ++) {
+			pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK;
+			pAC->I2c.SenTable[i].SenErrCts = 0;
+			pAC->I2c.SenTable[i].SenWarnCts = 0;
+			pAC->I2c.SenTable[i].SenBegErrTS = 0;
+			pAC->I2c.SenTable[i].SenBegWarnTS = 0;
+			pAC->I2c.SenTable[i].SenLastErrTrapTS = (SK_U64) 0;
+			pAC->I2c.SenTable[i].SenLastErrLogTS = (SK_U64) 0;
+			pAC->I2c.SenTable[i].SenLastWarnTrapTS = (SK_U64) 0;
+			pAC->I2c.SenTable[i].SenLastWarnLogTS = (SK_U64) 0;
+		}
+		break;
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E006, SKERR_I2C_E006MSG);
+	}
+
+	return(0);
+}
+#endif	/* !SK_DIAG */
+/* End of File */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/sklm80.c linux.14p16/drivers/net/sk98lin/sklm80.c
--- linux.vanilla/drivers/net/sk98lin/sklm80.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/sklm80.c	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,270 @@
+/******************************************************************************
+ *
+ * Name:	sklm80.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.16 $
+ * Date:	$Date: 1999/05/27 14:05:47 $
+ * Purpose:	Funktions to access Voltage and Temperature Sensor (LM80)
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skge.c" for further 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 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: sklm80.c,v $
+ *	Revision 1.16  1999/05/27 14:05:47  malthoff
+ *	Fans: Set SenVal to 0 if the fan value is 0 or 0xff. Both values
+ *	are outside the limits (0: div zero error, 0xff: value not in
+ *	range, assume 0).
+ *	
+ *	Revision 1.15  1999/05/27 13:38:51  malthoff
+ *	Pervent from Division by zero errors.
+ *	
+ *	Revision 1.14  1999/05/20 09:20:01  cgoos
+ *	Changes for 1000Base-T (Fan sensors).
+ *	
+ *	Revision 1.13  1998/10/22 09:48:14  gklug
+ *	fix: SysKonnectFileId typo
+ *	
+ *	Revision 1.12  1998/10/09 06:12:06  malthoff
+ *	Remove ID_sccs by SysKonnectFileId.
+ *	
+ *	Revision 1.11  1998/09/04 08:33:48  malthoff
+ *	bug fix: SenState = SK_SEN_IDLE when
+ *	leaving SK_SEN_VALEXT state
+ *	
+ *	Revision 1.10  1998/08/20 12:02:10  gklug
+ *	fix: compiler warnings type mismatch
+ *
+ *	Revision 1.9  1998/08/20 11:37:38  gklug
+ *	chg: change Ioc to IoC
+ *	
+ *	Revision 1.8  1998/08/19 12:20:58  gklug
+ *	fix: remove struct from C files (see CCC)
+ *	
+ *	Revision 1.7  1998/08/17 07:04:57  malthoff
+ *	Take SkLm80RcvReg() function from ski2c.c.
+ *	Add IoC parameter to BREAK_OR_WAIT() macro.
+ *	
+ *	Revision 1.6  1998/08/14 07:11:28  malthoff
+ *	remove pAc with pAC.
+ *
+ *	Revision 1.5  1998/08/14 06:46:55  gklug
+ *	fix: temperature can get negative
+ *
+ *	Revision 1.4  1998/08/13 08:27:04  gklug
+ *	add: temperature reading now o.k.
+ *	fix: pSen declaration, SK_ERR_LOG call, ADDR macro
+ *
+ *	Revision 1.3  1998/08/13 07:28:21  gklug
+ *	fix: pSen was wrong initialized
+ *	add: correct conversion for voltage readings
+ *
+ *	Revision 1.2  1998/08/11 07:52:14  gklug
+ *	add: Lm80 read sensor function
+ *
+ *	Revision 1.1  1998/07/17 09:57:12  gklug
+ *	initial version
+ *
+ *
+ *
+ ******************************************************************************/
+
+
+/*
+	LM80 functions
+*/
+static const char SysKonnectFileId[] =
+	"$Id: sklm80.c,v 1.16 1999/05/27 14:05:47 malthoff Exp $" ;
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/lm80.h"
+#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
+
+#ifdef	SK_DIAG
+#define	BREAK_OR_WAIT(pAC,IoC,Event)	SkI2cWait(pAC,IoC,Event)
+#else	/* nSK_DIAG */
+#define	BREAK_OR_WAIT(pAC,IoC,Event)	break
+#endif	/* nSK_DIAG */
+
+#ifdef	SK_DIAG
+/*
+ * read the regeister 'reg' from the device 'device'
+ *
+ * return 	read error	-1
+ *		success		the read value
+ */
+int	SkLm80RcvReg(
+SK_IOC	IoC,		/* Adapter Context */
+int	Dev,		/* I2C device address */
+int	Reg)		/* register to read */
+{
+	int	Val = 0;
+	int	TempExt;
+
+	/* Signal device number */
+	if (SkI2cSndDev(IoC, Dev, I2C_WRITE)) {
+		return(-1);
+	}
+
+	if (SkI2cSndByte(IoC, Reg)) {
+		return(-1);
+	}
+
+	/* repeat start */
+	if (SkI2cSndDev(IoC, Dev, I2C_READ)) {
+		return(-1);
+	}
+
+	switch(Reg) {
+	case LM80_TEMP_IN:
+		Val = (int)SkI2cRcvByte(IoC, 1) ;
+
+		/* First: correct the value: it might be negative */
+		if ((Val & 0x80) != 0) {
+			/* Value is negative */
+			Val = Val - 256;
+		}
+		Val = Val * SK_LM80_TEMP_LSB;
+		SkI2cStop(IoC);
+		TempExt = (int) SkLm80RcvReg(IoC,LM80_ADDR,LM80_TEMP_CTRL);
+		if (Val > 0) {
+			Val += ((TempExt >> 7) * SK_LM80_TEMPEXT_LSB);
+		}
+		else {
+			Val -= ((TempExt >> 7) * SK_LM80_TEMPEXT_LSB);
+		}
+		return(Val);
+		break;
+	case LM80_VT0_IN:
+	case LM80_VT1_IN:
+	case LM80_VT2_IN:
+	case LM80_VT3_IN:
+		Val = (int) SkI2cRcvByte(IoC, 1) * SK_LM80_VT_LSB;
+		break;
+	default:
+		Val = (int) SkI2cRcvByte(IoC, 1);
+		break;
+	}
+
+	SkI2cStop(IoC);
+	return(Val);
+}
+#endif	/* SK_DIAG */
+
+/*
+ * read a sensors value (LM80 specific)
+ *
+ * This function reads a sensors value from the I2c sensor chip LM80. The
+ * sensor is defined by its index into the sensors database in the struct
+ * pAC points to.
+ *
+ * Returns	1 if the read is completed
+ *		0 if the read must be continued (I2c Bus still allocated)
+ */
+int	SkLm80ReadSensor(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* IoContext needed in level 1 and 2 */
+SK_SENSOR	*pSen)	/* Sensor to be read */
+{
+	SK_I32		Value;
+
+	switch(pSen->SenState) {
+	case SK_SEN_IDLE:
+		/* Send address to ADDR register */
+		SK_I2C_CTL(IoC,I2C_READ,pSen->SenDev,pSen->SenReg,0);
+
+		pSen->SenState = SK_SEN_VALUE ;
+		BREAK_OR_WAIT(pAC, IoC, I2C_READ) ;
+	case SK_SEN_VALUE:
+		/* Read value from data register */
+		SK_IN32(IoC,B2_I2C_DATA, ((SK_U32 *)&Value));
+		Value &= 0xff; /* only least significant byte is valid */
+
+		/* Do NOT check the Value against the thresholds */
+		/* Checking is done in the calling instance */
+
+		if (pSen->SenType == SK_SEN_VOLT) {
+			/* Voltage sensor */
+			pSen->SenValue = Value * SK_LM80_VT_LSB;
+			pSen->SenState = SK_SEN_IDLE ;
+			return(1);
+		}
+
+		if (pSen->SenType == SK_SEN_FAN) {
+			if (Value != 0 && Value != 0xff) {
+				/* Fan speed counter */
+				pSen->SenValue = SK_LM80_FAN_FAKTOR/Value;
+			}
+			else {
+				/* Indicate Fan error */
+				pSen->SenValue = 0;
+			}
+			pSen->SenState = SK_SEN_IDLE ;
+			return(1);
+		}
+
+		/* First: correct the value: it might be negative */
+		if ((Value & 0x80) != 0) {
+			/* Value is negative */
+			Value = Value - 256;
+		}
+
+		/* We have a temperature sensor and need to get the signed
+		 * extension. For now we get the extension from the last
+		 * reading, so in the normal case we won't see flickering
+		 * temperatures.
+		 */
+		pSen->SenValue = (Value * SK_LM80_TEMP_LSB) +
+			(pSen->SenValue % SK_LM80_TEMP_LSB);
+
+		/* Send address to ADDR register */
+		SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, LM80_TEMP_CTRL, 0);
+
+		pSen->SenState = SK_SEN_VALEXT ;
+		BREAK_OR_WAIT(pAC, IoC, I2C_READ) ;
+	case SK_SEN_VALEXT:
+		/* Read value from data register */
+		SK_IN32(IoC,B2_I2C_DATA,((SK_U32 *)&Value));
+		Value &= LM80_TEMP_LSB_9; /* only bit 7 is valid */
+
+		/* cut the LSB bit */
+		pSen->SenValue = ((pSen->SenValue / SK_LM80_TEMP_LSB) *
+			SK_LM80_TEMP_LSB) ;
+
+		if (pSen->SenValue < 0) {
+			/* Value negative: The bit value must be subtracted */
+			pSen->SenValue -= ((Value >> 7) * SK_LM80_TEMPEXT_LSB);
+		} else {
+			/* Value positive: The bit value must be added */
+			pSen->SenValue += ((Value >> 7) * SK_LM80_TEMPEXT_LSB);
+		}
+
+		pSen->SenState = SK_SEN_IDLE ;
+		return(1);
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E007,
+			SKERR_I2C_E007MSG) ;
+		return(1);
+	}
+
+	/* Not completed */
+	return(0) ;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/skqueue.c linux.14p16/drivers/net/sk98lin/skqueue.c
--- linux.vanilla/drivers/net/sk98lin/skqueue.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/skqueue.c	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,204 @@
+/******************************************************************************
+ *
+ * Name:	skqueue.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.14 $
+ * Date:	$Date: 1998/10/15 15:11:35 $
+ * Purpose:	Management of an event queue.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skge.c" for further 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 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skqueue.c,v $
+ *	Revision 1.14  1998/10/15 15:11:35  gklug
+ *	fix: ID_sccs to SysKonnectFileId
+ *	
+ *	Revision 1.13  1998/09/08 08:47:52  gklug
+ *	add: init level handling
+ *	
+ *	Revision 1.12  1998/09/08 07:43:20  gklug
+ *	fix: Sirq Event function name
+ *	
+ *	Revision 1.11  1998/09/08 05:54:34  gklug
+ *	chg: define SK_CSUM is replaced by SK_USE_CSUM
+ *	
+ *	Revision 1.10  1998/09/03 14:14:49  gklug
+ *	add: CSUM and HWAC Eventclass and function.
+ *	
+ *	Revision 1.9  1998/08/19 09:50:50  gklug
+ *	fix: remove struct keyword from c-code (see CCC) add typedefs
+ *	
+ *	Revision 1.8  1998/08/17 13:43:11  gklug
+ *	chg: Parameter will be union of 64bit para, 2 times SK_U32 or SK_PTR
+ *	
+ *	Revision 1.7  1998/08/14 07:09:11  gklug
+ *	fix: chg pAc -> pAC
+ *	
+ *	Revision 1.6  1998/08/11 12:13:14  gklug
+ *	add: return code feature of Event service routines
+ *	add: correct Error log calls
+ *	
+ *	Revision 1.5  1998/08/07 12:53:45  gklug
+ *	fix: first compiled version
+ *	
+ *	Revision 1.4  1998/08/07 09:20:48  gklug
+ *	adapt functions to C coding conventions.
+ *	
+ *	Revision 1.3  1998/08/05 11:29:32  gklug
+ *	rmv: Timer event entry. Timer will queue event directly
+ *	
+ *	Revision 1.2  1998/07/31 11:22:40  gklug
+ *	Initial version
+ *	
+ *	Revision 1.1  1998/07/30 15:14:01  gklug
+ *	Initial version. Adapted from SMT
+ *	
+ *	
+ *
+ ******************************************************************************/
+
+
+/*
+	Event queue and dispatcher
+*/
+static const char SysKonnectFileId[] =
+	"$Header: /usr56/projects/ge/schedule/skqueue.c,v 1.14 1998/10/15 15:11:35 gklug Exp $" ;
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/skqueue.h"		/* Queue Definitions */
+#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+	Event queue management.
+
+	General Description:
+
+ */
+intro()
+{}
+#endif
+
+#define PRINTF(a,b,c)
+
+/*
+ * init event queue management
+ *
+ * Must be called during init level 0.
+ */
+void	SkEventInit(
+SK_AC	*pAC,	/* Adapter context */
+SK_IOC	Ioc,	/* IO context */
+int	Level)	/* Init level */
+{
+	switch (Level) {
+	case SK_INIT_DATA:
+		pAC->Event.EvPut = pAC->Event.EvGet = pAC->Event.EvQueue ;
+		break;
+	default:
+		break;
+	}
+}
+
+/*
+ * add event to queue
+ */
+void	SkEventQueue(
+SK_AC		*pAC,	/* Adapters context */
+SK_U32		Class,	/* Event Class */
+SK_U32		Event,	/* Event to be queued */
+SK_EVPARA	Para)	/* Event parameter */
+{
+	pAC->Event.EvPut->Class = Class ;
+	pAC->Event.EvPut->Event = Event ;
+	pAC->Event.EvPut->Para = Para ;
+	if (++pAC->Event.EvPut == &pAC->Event.EvQueue[SK_MAX_EVENT])
+		pAC->Event.EvPut = pAC->Event.EvQueue ;
+
+	if (pAC->Event.EvPut == pAC->Event.EvGet) {
+		SK_ERR_LOG(pAC, SK_ERRCL_NORES, SKERR_Q_E001, SKERR_Q_E001MSG) ;
+	}
+}
+
+/*
+ * event dispatcher
+ *	while event queue is not empty
+ *		get event from queue
+ *		send command to state machine
+ *	end
+ *	return error reported by individual Event function
+ *		0 if no error occured.
+ */
+int	SkEventDispatcher(
+SK_AC	*pAC,	/* Adapters Context */
+SK_IOC	Ioc)	/* Io context */
+{
+	SK_EVENTELEM	*pEv ;	/* pointer into queue */
+	SK_U32			Class ;
+	int			Rtv ;
+
+	pEv = pAC->Event.EvGet ;
+	PRINTF("dispatch get %x put %x\n",pEv,pAC->Event.ev_put) ;
+	while (pEv != pAC->Event.EvPut) {
+		PRINTF("dispatch Class %d Event %d\n",pEv->Class,pEv->Event) ;
+		switch(Class = pEv->Class) {
+		case SKGE_DRV :		/* Driver Event */
+			Rtv = SkDrvEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+		case SKGE_RLMT :	/* RLMT Event */
+			Rtv = SkRlmtEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+		case SKGE_I2C :		/* I2C Event */
+			Rtv = SkI2cEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+		case SKGE_PNMI :
+			Rtv = SkPnmiEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+		case SKGE_HWAC :
+			Rtv = SkGeSirqEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+#ifdef	SK_USE_CSUM
+		case SKGE_CSUM :
+			Rtv = SkCsEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+#endif	/* SK_USE_CSUM */
+		default :
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_Q_E002,
+				SKERR_Q_E002MSG) ;
+			Rtv = 0;
+		}
+
+		if (Rtv != 0) {
+			return(Rtv) ;
+		}
+
+		if (++pEv == &pAC->Event.EvQueue[SK_MAX_EVENT])
+			pEv = pAC->Event.EvQueue ;
+
+		/* Renew get: it is used in queue_events to detect overruns */
+		pAC->Event.EvGet = pEv;
+	}
+
+	return(0) ;
+}
+
+/* End of file */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/skrlmt.c linux.14p16/drivers/net/sk98lin/skrlmt.c
--- linux.vanilla/drivers/net/sk98lin/skrlmt.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/skrlmt.c	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,3423 @@
+/******************************************************************************
+ *
+ * Name:	skrlmt.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.48 $
+ * Date:	$Date: 1999/10/04 14:01:17 $
+ * Purpose:	Manage links on SK-NET Adapters, esp. redundant ones.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skge.c" for further 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 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skrlmt.c,v $
+ *	Revision 1.48  1999/10/04 14:01:17  rassmann
+ *	Corrected reaction to reception of BPDU frames.
+ *	Added parameter descriptions to "For Readme" section skrlmt.txt.
+ *	Clarified usage of lookahead result *pForRlmt.
+ *	Requested driver to present RLMT packets as soon as poosible.
+ *	
+ *	Revision 1.47  1999/07/20 12:53:36  rassmann
+ *	Fixed documentation errors for lookahead macros.
+ *	
+ *	Revision 1.46  1999/05/28 13:29:16  rassmann
+ *	Replaced C++-style comment.
+ *	
+ *	Revision 1.45  1999/05/28 13:28:08  rassmann
+ *	Corrected syntax error (xxx).
+ *	
+ *	Revision 1.44  1999/05/28 11:15:54  rassmann
+ *	Changed behaviour to reflect Design Spec v1.2.
+ *	Controlling Link LED(s).
+ *	Introduced RLMT Packet Version field in RLMT Packet.
+ *	Newstyle lookahead macros (checking meta-information before looking at
+ *	  the packet).
+ *	
+ *	Revision 1.43  1999/01/28 13:12:43  rassmann
+ *	Corrected Lookahead (bug introduced in previous Rev.).
+ *	
+ *	Revision 1.42  1999/01/28 12:50:41  rassmann
+ *	Not using broadcast time stamps in CheckLinkState mode.
+ *	
+ *	Revision 1.41  1999/01/27 14:13:02  rassmann
+ *	Monitoring broadcast traffic.
+ *	Switching more reliably and not too early if switch is
+ *	 configured for spanning tree.
+ *	
+ *	Revision 1.40  1999/01/22 13:17:30  rassmann
+ *	Informing PNMI of NET_UP.
+ *	Clearing RLMT multicast addresses before first setting them.
+ *	Reporting segmentation earlier, setting a "quiet time"
+ *	 after a report.
+ *	
+ *	Revision 1.39  1998/12/10 15:29:53  rassmann
+ *	Corrected SuspectStatus in SkRlmtBuildCheckChain().
+ *	Corrected CHECK_SEG mode.
+ *	
+ *	Revision 1.38  1998/12/08 13:11:23  rassmann
+ *	Stopping SegTimer at RlmtStop.
+ *	
+ *	Revision 1.37  1998/12/07 16:51:42  rassmann
+ *	Corrected comments.
+ *	
+ *	Revision 1.36  1998/12/04 10:58:56  rassmann
+ *	Setting next pointer to NULL when receiving.
+ *	
+ *	Revision 1.35  1998/12/03 16:12:42  rassmann
+ *	Ignoring/correcting illegal PrefPort values.
+ *	
+ *	Revision 1.34  1998/12/01 11:45:35  rassmann
+ *	Code cleanup.
+ *	
+ *	Revision 1.33  1998/12/01 10:29:32  rassmann
+ *	Starting standby ports before getting the net up.
+ *	Checking if a port is started when the link comes up.
+ *	
+ *	Revision 1.32  1998/11/30 16:19:50  rassmann
+ *	New default for PortNoRx.
+ *	
+ *	Revision 1.31  1998/11/27 19:17:13  rassmann
+ *	Corrected handling of LINK_DOWN coming shortly after LINK_UP.
+ *	
+ *	Revision 1.30  1998/11/24 12:37:31  rassmann
+ *	Implemented segmentation check.
+ *	
+ *	Revision 1.29  1998/11/18 13:04:32  rassmann
+ *	Secured PortUpTimer event.
+ *	Waiting longer before starting standby port(s).
+ *	
+ *	Revision 1.28  1998/11/17 13:43:04  rassmann
+ *	Handling (logical) tx failure.
+ *	Sending packet on logical address after PORT_SWITCH.
+ *	
+ *	Revision 1.27  1998/11/13 17:09:50  rassmann
+ *	Secured some events against being called in wrong state.
+ *	
+ *	Revision 1.26  1998/11/13 16:56:54  rassmann
+ *	Added macro version of SkRlmtLookaheadPacket.
+ *	
+ *	Revision 1.25  1998/11/06 18:06:04  rassmann
+ *	Corrected timing when RLMT checks fail.
+ *	Clearing tx counter earlier in periodical checks.
+ *	
+ *	Revision 1.24  1998/11/05 10:37:27  rassmann
+ *	Checking destination address in Lookahead.
+ *	
+ *	Revision 1.23  1998/11/03 13:53:49  rassmann
+ *	RLMT should switch now (at least in mode 3).
+ *	
+ *	Revision 1.22  1998/10/29 14:34:49  rassmann
+ *	Clearing SK_RLMT struct at startup.
+ *	Initializing PortsUp during SK_RLMT_START.
+ *	
+ *	Revision 1.21  1998/10/28 11:30:17  rassmann
+ *	Default mode is now SK_RLMT_CHECK_LOC_LINK.
+ *	
+ *	Revision 1.20  1998/10/26 16:02:03  rassmann
+ *	Ignoring LINK_DOWN for links that are down.
+ *	
+ *	Revision 1.19  1998/10/22 15:54:01  rassmann
+ *	Corrected EtherLen.
+ *	Starting Link Check when second port comes up.
+ *	
+ *	Revision 1.18  1998/10/22 11:39:50  rassmann
+ *	Corrected signed/unsigned mismatches.
+ *	Corrected receive list handling and address recognition.
+ *	
+ *	Revision 1.17  1998/10/19 17:01:20  rassmann
+ *	More detailed checking of received packets.
+ *	
+ *	Revision 1.16  1998/10/15 15:16:34  rassmann
+ *	Finished Spanning Tree checking.
+ *	Checked with lint.
+ *	
+ *	Revision 1.15  1998/09/24 19:16:07  rassmann
+ *	Code cleanup.
+ *	Introduced Timer for PORT_DOWN due to no RX.
+ *	
+ *	Revision 1.14  1998/09/18 20:27:14  rassmann
+ *	Added address override.
+ *	
+ *	Revision 1.13  1998/09/16 11:31:48  rassmann
+ *	Including skdrv1st.h again. :(
+ *	
+ *	Revision 1.12  1998/09/16 11:09:50  rassmann
+ *	Syntax corrections.
+ *	
+ *	Revision 1.11  1998/09/15 12:32:03  rassmann
+ *	Syntax correction.
+ *	
+ *	Revision 1.10  1998/09/15 11:28:49  rassmann
+ *	Syntax corrections.
+ *	
+ *	Revision 1.9  1998/09/14 17:07:37  rassmann
+ *	Added code for port checking via LAN.
+ *	Changed Mbuf definition.
+ *	
+ *	Revision 1.8  1998/09/07 11:14:14  rassmann
+ *	Syntax corrections.
+ *	
+ *	Revision 1.7  1998/09/07 09:06:07  rassmann
+ *	Syntax corrections.
+ *	
+ *	Revision 1.6  1998/09/04 19:41:33  rassmann
+ *	Syntax corrections.
+ *	Started entering code for checking local links.
+ *	
+ *	Revision 1.5  1998/09/04 12:14:27  rassmann
+ *	Interface cleanup.
+ *	
+ *	Revision 1.4  1998/09/02 16:55:28  rassmann
+ *	Updated to reflect new DRV/HWAC/RLMT interface.
+ *	
+ *	Revision 1.3  1998/08/27 14:29:03  rassmann
+ *	Code cleanup.
+ *	
+ *	Revision 1.2  1998/08/27 14:26:24  rassmann
+ *	Updated interface.
+ *	
+ *	Revision 1.1  1998/08/21 08:26:49  rassmann
+ *	First public version.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module contains code for Link ManagemenT (LMT) of SK-NET Adapters.
+ * It is mainly intended for adapters with more than one link.
+ * For such adapters, this module realizes Redundant Link ManagemenT (RLMT).
+ *
+ * Include File Hierarchy:
+ *
+ *	"skdrv1st.h"
+ *	"skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef	lint
+static const char SysKonnectFileId[] =
+	"@(#) $Id: skrlmt.c,v 1.48 1999/10/04 14:01:17 rassmann Exp $ (C) SysKonnect.";
+#endif	/* !defined(lint) */
+
+#define __SKRLMT_C
+
+#ifdef __cplusplus
+xxxx	/* not supported yet - force error */
+extern "C" {
+#endif	/* cplusplus */
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* defines ********************************************************************/
+
+#ifndef SK_HWAC_LINK_LED
+#define SK_HWAC_LINK_LED(a,b,c,d)
+#endif	/* !defined(SK_HWAC_LINK_LED) */
+
+#ifndef DEBUG
+#define RLMT_STATIC	static
+#else	/* DEBUG */
+#define RLMT_STATIC
+
+#ifndef SK_LITTLE_ENDIAN
+/* First 32 bits */
+#define OFFS_LO32	1
+/* Second 32 bits */
+#define OFFS_HI32	0
+#else	/* SK_LITTLE_ENDIAN */
+/* First 32 bits */
+#define OFFS_LO32	0
+/* Second 32 bits */
+#define OFFS_HI32	1
+#endif	/* SK_LITTLE_ENDIAN */
+
+#endif	/* DEBUG */
+
+/* ----- Private timeout values ----- */
+
+#define SK_RLMT_MIN_TO_VAL		   125000	/* 1/8 sec. */
+#define SK_RLMT_DEF_TO_VAL		  1000000	/* 1 sec. */
+#define SK_RLMT_PORTDOWN_TIM_VAL	   900000	/* another 0.9 sec. */
+#define SK_RLMT_PORTSTART_TIM_VAL	   100000	/* 0.1 sec. */
+#define SK_RLMT_PORTUP_TIM_VAL		  2500000	/* 2.5 sec. */
+#define SK_RLMT_SEG_TO_VAL		900000000	/* 15 min. */
+
+/*
+ * Amount that a time stamp must be later to be recognized as "substantially
+ * later". This is about 1/128 sec.
+ */
+
+#define SK_RLMT_BC_DELTA	((SK_TICKS_PER_SEC >> 7) + 1)
+
+/* ----- Private RLMT defaults ----- */
+
+#define SK_RLMT_DEF_PREF_PORT	0			/* "Lower" port. */
+#define SK_RLMT_DEF_MODE 	SK_RLMT_CHECK_LINK	/* Default RLMT Mode. */
+
+/* ----- Private RLMT checking states ----- */
+
+#define SK_RLMT_RCS_SEG		1	/* RLMT Check State: check seg. */
+#define SK_RLMT_RCS_START_SEG	2	/* RLMT Check State: start check seg. */
+#define SK_RLMT_RCS_SEND_SEG	4	/* RLMT Check State: send BPDU packet */
+#define SK_RLMT_RCS_REPORT_SEG	8	/* RLMT Check State: report seg. */
+
+/* ----- Private PORT checking states ----- */
+
+#define SK_RLMT_PCS_TX		1	/* Port Check State: check tx. */
+#define SK_RLMT_PCS_RX		2	/* Port Check State: check rx. */
+
+/* ----- Private PORT events ----- */
+
+/* Note: Update simulation when changing these. */
+
+#define SK_RLMT_PORTSTART_TIM	1100	/* Port start timeout. */
+#define SK_RLMT_PORTUP_TIM	1101	/* Port can now go up. */
+#define SK_RLMT_PORTDOWN_RX_TIM	1102	/* Port did not receive once ... */
+#define SK_RLMT_PORTDOWN	1103	/* Port went down. */
+#define SK_RLMT_PORTDOWN_TX_TIM	1104	/* Partner did not receive ... */
+
+/* ----- Private RLMT events ----- */
+
+/* Note: Update simulation when changing these. */
+
+#define SK_RLMT_TIM		2100	/* RLMT timeout. */
+#define SK_RLMT_SEG_TIM		2101	/* RLMT segmentation check timeout. */
+
+#define TO_SHORTEN(tim)	((tim) / 2)
+
+/* Error numbers and messages. */
+
+#define SKERR_RLMT_E001		(SK_ERRBASE_RLMT + 0)
+#define SKERR_RLMT_E001_MSG	"No Packet."
+#define SKERR_RLMT_E002		(SKERR_RLMT_E001 + 1)
+#define SKERR_RLMT_E002_MSG	"Short Packet."
+#define SKERR_RLMT_E003		(SKERR_RLMT_E002 + 1)
+#define SKERR_RLMT_E003_MSG	"Unknown RLMT event."
+#define SKERR_RLMT_E004		(SKERR_RLMT_E003 + 1)
+#define SKERR_RLMT_E004_MSG	"PortsUp incorrect."
+#define SKERR_RLMT_E005		(SKERR_RLMT_E004 + 1)
+#define SKERR_RLMT_E005_MSG	\
+ "Net seems to be segmented (different root bridges are reported on the ports)."
+#define SKERR_RLMT_E006		(SKERR_RLMT_E005 + 1)
+#define SKERR_RLMT_E006_MSG	"Duplicate MAC Address detected."
+#define SKERR_RLMT_E007		(SKERR_RLMT_E006 + 1)
+#define SKERR_RLMT_E007_MSG	"LinksUp incorrect."
+#define SKERR_RLMT_E008		(SKERR_RLMT_E007 + 1)
+#define SKERR_RLMT_E008_MSG	"Port not started but link came up."
+#define SKERR_RLMT_E009		(SKERR_RLMT_E008 + 1)
+#define SKERR_RLMT_E009_MSG	"Corrected illegal setting of Preferred Port."
+#define SKERR_RLMT_E010		(SKERR_RLMT_E009 + 1)
+#define SKERR_RLMT_E010_MSG	"Ignored illegal Preferred Port."
+
+/* LLC field values. */
+
+#define LLC_COMMAND_RESPONSE_BIT	1
+#define LLC_TEST_COMMAND		0xE3
+#define LLC_UI				0x03
+
+/* RLMT Packet fields. */
+
+#define	SK_RLMT_DSAP			0
+#define	SK_RLMT_SSAP			0
+#define SK_RLMT_CTRL			(LLC_TEST_COMMAND)
+#define SK_RLMT_INDICATOR0		0x53	/* S */
+#define SK_RLMT_INDICATOR1		0x4B	/* K */
+#define SK_RLMT_INDICATOR2		0x2D	/* - */
+#define SK_RLMT_INDICATOR3		0x52	/* R */
+#define SK_RLMT_INDICATOR4		0x4C	/* L */
+#define SK_RLMT_INDICATOR5		0x4D	/* M */
+#define SK_RLMT_INDICATOR6		0x54	/* T */
+#define SK_RLMT_PACKET_VERSION	0
+
+/* RLMT SPT Flag values. */
+
+#define	SK_RLMT_SPT_FLAG_CHANGE		0x01
+#define	SK_RLMT_SPT_FLAG_CHANGE_ACK	0x80
+
+/* RLMT SPT Packet fields. */
+
+#define	SK_RLMT_SPT_DSAP		0x42
+#define	SK_RLMT_SPT_SSAP		0x42
+#define SK_RLMT_SPT_CTRL		(LLC_UI)
+#define	SK_RLMT_SPT_PROTOCOL_ID0	0x00
+#define	SK_RLMT_SPT_PROTOCOL_ID1	0x00
+#define	SK_RLMT_SPT_PROTOCOL_VERSION_ID	0x00
+#define	SK_RLMT_SPT_BPDU_TYPE		0x00
+#define	SK_RLMT_SPT_FLAGS		0x00	/* ?? */
+#define	SK_RLMT_SPT_ROOT_ID0		0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_ROOT_ID1		0xFF	/* Lowest possible priority. */
+
+/* Remaining 6 bytes will be the current port address. */
+
+#define	SK_RLMT_SPT_ROOT_PATH_COST0	0x00
+#define	SK_RLMT_SPT_ROOT_PATH_COST1	0x00
+#define	SK_RLMT_SPT_ROOT_PATH_COST2	0x00
+#define	SK_RLMT_SPT_ROOT_PATH_COST3	0x00
+#define	SK_RLMT_SPT_BRIDGE_ID0		0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_BRIDGE_ID1		0xFF	/* Lowest possible priority. */
+
+/* Remaining 6 bytes will be the current port address. */
+
+#define	SK_RLMT_SPT_PORT_ID0		0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_PORT_ID1		0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_MSG_AGE0		0x00
+#define	SK_RLMT_SPT_MSG_AGE1		0x00
+#define	SK_RLMT_SPT_MAX_AGE0		0x00
+#define	SK_RLMT_SPT_MAX_AGE1		0xFF
+#define	SK_RLMT_SPT_HELLO_TIME0		0x00
+#define	SK_RLMT_SPT_HELLO_TIME1		0xFF
+#define	SK_RLMT_SPT_FWD_DELAY0		0x00
+#define	SK_RLMT_SPT_FWD_DELAY1		0x40
+
+/* Size defines. */
+
+#define SK_RLMT_MIN_PACKET_SIZE	34
+#define SK_RLMT_MAX_PACKET_SIZE	(SK_RLMT_MAX_TX_BUF_SIZE)
+#define SK_PACKET_DATA_LEN	(SK_RLMT_MAX_PACKET_SIZE - \
+				 SK_RLMT_MIN_PACKET_SIZE)
+
+/* ----- RLMT packet types ----- */
+
+#define SK_PACKET_ANNOUNCE	1	/* Port announcement. */
+#define SK_PACKET_ALIVE		2	/* Alive packet to port. */
+#define SK_PACKET_ADDR_CHANGED	3	/* Port address changed. */
+#define SK_PACKET_CHECK_TX	4	/* Check your tx line. */
+
+#ifdef SK_LITTLE_ENDIAN
+#define SK_U16_TO_NETWORK_ORDER(Val,Addr) { \
+	SK_U8	*_Addr = (SK_U8*)(Addr); \
+	SK_U16	_Val = (SK_U16)(Val); \
+	*_Addr++ = (SK_U8)(_Val >> 8); \
+	*_Addr = (SK_U8)(_Val & 0xFF); \
+}
+#endif	/* SK_LITTLE_ENDIAN */
+
+#ifdef SK_BIG_ENDIAN
+#define SK_U16_TO_NETWORK_ORDER(Val,Addr) (*(SK_U16*)(Addr) = (SK_U16)(Val))
+#endif	/* SK_BIG_ENDIAN */
+
+#define AUTONEG_FAILED	SK_FALSE
+#define AUTONEG_SUCCESS	SK_TRUE
+
+
+/* typedefs *******************************************************************/
+
+/* RLMT packet.  Length: SK_RLMT_MAX_PACKET_SIZE (60) bytes. */
+
+typedef struct s_RlmtPacket {
+	SK_U8	DstAddr[SK_MAC_ADDR_LEN];
+	SK_U8	SrcAddr[SK_MAC_ADDR_LEN];
+	SK_U8	TypeLen[2];
+	SK_U8	DSap;
+	SK_U8	SSap;
+	SK_U8	Ctrl;
+	SK_U8	Indicator[7];
+	SK_U8	RlmtPacketType[2];
+	SK_U8	Align1[2];
+	SK_U8	Random[4];	/* Random value of requesting(!) station. */
+	SK_U8	RlmtPacketVersion[2];	/* RLMT Packet version */
+	SK_U8	Data[SK_PACKET_DATA_LEN];
+} SK_RLMT_PACKET;
+
+typedef struct s_SpTreeRlmtPacket {
+	SK_U8	DstAddr[SK_MAC_ADDR_LEN];
+	SK_U8	SrcAddr[SK_MAC_ADDR_LEN];
+	SK_U8	TypeLen[2];
+	SK_U8	DSap;
+	SK_U8	SSap;
+	SK_U8	Ctrl;
+	SK_U8	ProtocolId[2];
+	SK_U8	ProtocolVersionId;
+	SK_U8	BpduType;
+	SK_U8	Flags;
+	SK_U8	RootId[8];
+	SK_U8	RootPathCost[4];
+	SK_U8	BridgeId[8];
+	SK_U8	PortId[2];
+	SK_U8	MessageAge[2];
+	SK_U8	MaxAge[2];
+	SK_U8	HelloTime[2];
+	SK_U8	ForwardDelay[2];
+} SK_SPTREE_PACKET;
+
+/* global variables ***********************************************************/
+
+SK_MAC_ADDR	SkRlmtMcAddr = {{0x01,  0x00,  0x5A,  0x52,  0x4C,  0x4D}};
+SK_MAC_ADDR	BridgeMcAddr = {{0x01,  0x80,  0xC2,  0x00,  0x00,  0x00}};
+SK_MAC_ADDR	BcAddr = {{0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF}};
+
+/* local variables ************************************************************/
+
+/* None. */
+
+/* functions ******************************************************************/
+
+RLMT_STATIC void	SkRlmtCheckSwitch(
+	SK_AC	*pAC,
+	SK_IOC	IoC);
+RLMT_STATIC void	SkRlmtCheckSeg(
+	SK_AC	*pAC,
+	SK_IOC	IoC);
+
+/******************************************************************************
+ *
+ *	SkRlmtInit - initialize data, set state to init
+ *
+ * Description:
+ *
+ *	SK_INIT_DATA
+ *	============
+ *
+ *	This routine initializes all RLMT-related variables to a known state.
+ *	The initial state is SK_RLMT_RS_INIT.
+ *	All ports are initialized to SK_RLMT_PS_INIT.
+ *
+ *
+ *	SK_INIT_IO
+ *	==========
+ *
+ *	Nothing.
+ *
+ *
+ *	SK_INIT_RUN
+ *	===========
+ *
+ *	Determine the adapter's random value.
+ *	Set the hw registers, the "logical adapter address", the
+ *	RLMT multicast address, and eventually the BPDU multicast address.
+ *
+ * Context:
+ *	init, pageable
+ *
+ * Returns:
+ *	Nothing.
+ */
+void	SkRlmtInit(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* I/O context */
+int	Level)	/* initialization level */
+{
+	SK_U32		i, j;
+	SK_U64		Random;
+	SK_EVPARA	Para;
+
+	SK_DBG_MSG(
+		pAC,
+		SK_DBGMOD_RLMT,
+		SK_DBGCAT_INIT,
+		("RLMT Init level %d.\n", Level))
+
+	switch (Level) {
+	case SK_INIT_DATA:	/* Initialize data structures. */
+		SK_MEMSET((char *)&pAC->Rlmt, 0, sizeof(SK_RLMT));
+
+		for (i = 0; i < SK_MAX_MACS; i++) {
+			pAC->Rlmt.Port[i].PortState = SK_RLMT_PS_INIT;
+			pAC->Rlmt.Port[i].LinkDown = SK_TRUE;
+			pAC->Rlmt.Port[i].PortDown = SK_TRUE;
+			pAC->Rlmt.Port[i].PortStarted = SK_FALSE;
+			pAC->Rlmt.Port[i].PortNoRx = SK_FALSE;
+			pAC->Rlmt.Port[i].RootIdSet = SK_FALSE;
+		}
+
+		pAC->Rlmt.RlmtState = SK_RLMT_RS_INIT;
+		pAC->Rlmt.RootIdSet = SK_FALSE;
+		pAC->Rlmt.MacPreferred = 0xFFFFFFFF;	  /* Automatic. */
+		pAC->Rlmt.PrefPort = SK_RLMT_DEF_PREF_PORT;
+		pAC->Rlmt.MacActive = pAC->Rlmt.PrefPort; /* Just assuming. */
+		pAC->Rlmt.RlmtMode = SK_RLMT_DEF_MODE;
+		pAC->Rlmt.TimeoutValue = SK_RLMT_DEF_TO_VAL;
+		break;
+
+	case SK_INIT_IO:	/* GIMacsFound first available here. */
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_INIT,
+			("RLMT: %d MACs were detected.\n",
+				pAC->GIni.GIMacsFound))
+
+		/* Initialize HW registers? */
+
+		if (pAC->GIni.GIMacsFound < 2) {
+			Para.Para32[0] = SK_RLMT_CHECK_LINK;
+			(void)SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE, Para);
+		}
+		break;
+
+	case SK_INIT_RUN:
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			Random = SkOsGetTime(pAC);
+			*(SK_U32*)&pAC->Rlmt.Port[i].Random = *(SK_U32*)&Random;
+
+			for (j = 0; j < 4; j++) {
+				pAC->Rlmt.Port[i].Random[j] ^= pAC->Addr.Port[i
+					].CurrentMacAddress.a[SK_MAC_ADDR_LEN -
+					1 - j];
+			}
+
+			(void)SkAddrMcClear(
+				pAC,
+				IoC,
+				i,
+				SK_ADDR_PERMANENT | SK_MC_SW_ONLY);
+			
+			/* Add RLMT MC address. */
+
+			(void)SkAddrMcAdd(
+				pAC,
+				IoC,
+				i,
+				&SkRlmtMcAddr,
+				SK_ADDR_PERMANENT);
+
+			if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) {
+				/* Add BPDU MC address. */
+
+				(void)SkAddrMcAdd(
+					pAC,
+					IoC,
+					i,
+					&BridgeMcAddr,
+					SK_ADDR_PERMANENT);
+			}
+
+			(void)SkAddrMcUpdate(pAC, IoC, i);
+		}
+		break;
+
+	default:	/* error */
+		break;
+	}
+
+	return;
+
+}	/* SkRlmtInit */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtBuildCheckChain - build the check chain
+ *
+ * Description:
+ *	This routine builds the local check chain:
+ *	- Each port that is up checks the next port.
+ *	- The last port that is up checks the first port that is up.
+ *
+ * Notes:
+ *	- Currently only local ports are considered when building the chain.
+ *	- Currently the SuspectState is just reset;
+ *	  it would be better to save it ...
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtBuildCheckChain(
+SK_AC	*pAC)	/* adapter context */
+{
+	SK_U32	i;
+	SK_U32	NumMacsUp;
+	SK_U32	FirstMacUp=0;
+	SK_U32	PrevMacUp=0;
+
+	if (!(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK)) {
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			pAC->Rlmt.Port[i].PortsChecked = 0;
+		}
+		return;	/* Nothing to build. */
+	}
+
+	SK_DBG_MSG(
+		pAC,
+		SK_DBGMOD_RLMT,
+		SK_DBGCAT_CTRL,
+		("SkRlmtBuildCheckChain.\n"))
+
+	NumMacsUp = 0;
+
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		pAC->Rlmt.Port[i].PortsChecked = 0;
+		pAC->Rlmt.Port[i].PortsSuspect = 0;
+		pAC->Rlmt.Port[i].CheckingState &=
+			~(SK_RLMT_PCS_RX | SK_RLMT_PCS_TX);
+
+		/*
+		 * If more than two links are detected we should consider
+		 * checking at least two other ports:
+		 * 1. the next port that is not LinkDown and
+		 * 2. the next port that is not PortDown.
+		 */
+
+		if (!pAC->Rlmt.Port[i].LinkDown) {
+			if (NumMacsUp == 0) {
+				FirstMacUp = i;
+			}
+			else {
+				pAC->Rlmt.Port[PrevMacUp].PortCheck[
+					pAC->Rlmt.Port[
+					PrevMacUp].PortsChecked].CheckAddr =
+					pAC->Addr.Port[i].CurrentMacAddress;
+				pAC->Rlmt.Port[PrevMacUp].PortCheck[
+					pAC->Rlmt.Port[
+					PrevMacUp].PortsChecked].SuspectTx =
+					SK_FALSE;
+				pAC->Rlmt.Port[PrevMacUp].PortsChecked++;
+			}
+			PrevMacUp = i;
+			NumMacsUp++;
+		}
+	}
+
+	if (NumMacsUp > 1) {
+		pAC->Rlmt.Port[PrevMacUp].PortCheck[pAC->Rlmt.Port[
+			PrevMacUp].PortsChecked].CheckAddr =
+			pAC->Addr.Port[FirstMacUp].CurrentMacAddress;
+		pAC->Rlmt.Port[PrevMacUp].PortCheck[pAC->Rlmt.Port[
+			PrevMacUp].PortsChecked].SuspectTx = SK_FALSE;
+		pAC->Rlmt.Port[PrevMacUp].PortsChecked++;
+	}
+
+#ifdef DEBUG
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+                SK_DBG_MSG(
+                        pAC,
+                        SK_DBGMOD_RLMT,
+                        SK_DBGCAT_CTRL,
+                        ("Port %d checks %d other ports: %2X.\n",
+				i,
+				pAC->Rlmt.Port[i].PortsChecked,
+				pAC->Rlmt.Port[i].PortCheck[0].CheckAddr.a[5]))
+	}
+#endif	/* DEBUG */
+
+	return;       
+}	/* SkRlmtBuildCheckChain */
+
+#ifdef SK_RLMT_SLOW_LOOKAHEAD
+
+/******************************************************************************
+ *
+ *	SkRlmtLookaheadPacket - examine received packet shortly, count s-th
+ *
+ * Description:
+ *	This routine examines each received packet fast and short and
+ *	increments some counters.
+ *	The received packet has to be stored virtually contiguous.
+ *	This function does the following:
+ *	- Increment some counters.
+ *	- Ensure length is sufficient.
+ *	- Ensure that destination address is physical port address,
+ *	  RLMT multicast, or BPDU multicast address.
+ *
+ * Notes:
+ *	This function is fully reentrant while the fast path is not blocked.
+ *
+ * Context:
+ *	isr/dpr, not pageable
+ *
+ * Returns:
+ *	SK_FALSE packet for upper layers
+ *	SK_TRUE  packet for RLMT
+ */
+SK_BOOL	SkRlmtLookaheadPacket(
+SK_AC		*pAC,		/* adapter context */
+SK_U32		PortIdx,	/* receiving port */
+SK_U8		*pLaPacket,	/* received packet's data */
+unsigned	PacketLength,	/* received packet's length */ /* Necessary? */
+unsigned	LaLength)	/* lookahead length */
+{
+	int	i;
+	SK_BOOL	IsBc;		/* Broadcast address? */
+	int	RxDest;		/* Receive destination? */
+	int	Offset;		/* Offset of data to present to LOOKAHEAD. */
+	int	NumBytes;	/* #Bytes to present to LOOKAHEAD. */
+	SK_RLMT_PACKET	*pRPacket;
+	SK_ADDR_PORT	*pAPort;
+
+#ifdef DEBUG
+	PacketLength = PacketLength;
+#endif	/* DEBUG */
+
+	pRPacket = (SK_RLMT_PACKET*)pLaPacket;
+	pAPort = &pAC->Addr.Port[PortIdx];
+
+#ifdef DEBUG
+	if (pLaPacket == NULL) {
+
+		/* Create error log entry. */
+
+		SK_ERR_LOG(
+			pAC,
+			SK_ERRCL_SW,
+			SKERR_RLMT_E001,
+			SKERR_RLMT_E001_MSG);
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_RX,
+			("SkRlmtLookaheadPacket: NULL pointer.\n"))
+
+		return (SK_FALSE);
+	}
+#endif	/* DEBUG */
+
+	/* Drivers should get IsBc from the descriptor. */
+
+	IsBc = SK_TRUE;
+	for (i = 0; IsBc && i < SK_MAC_ADDR_LEN; i++) {
+		IsBc = IsBc && (pLaPacket[i] == 0xFF);
+	}
+
+	SK_RLMT_PRE_LOOKAHEAD(
+		pAC,
+		PortIdx,
+		PacketLength,
+		IsBc,
+		&Offset,
+		&NumBytes)
+
+	if (NumBytes == 0) {
+		return (SK_FALSE);
+	}
+
+	SK_RLMT_LOOKAHEAD(
+		pAC,
+		PortIdx,
+		&pLaPacket[Offset],
+		IsBc,
+		pLaPacket[0] & 1,	/* Drivers: Get info from descriptor. */
+		&RxDest)
+
+	if (RxDest & SK_RLMT_RX_RLMT) {
+		return (SK_TRUE);
+	}
+
+	return (SK_FALSE);
+}	/* SkRlmtLookaheadPacket */
+
+#endif	/* SK_RLMT_SLOW_LOOKAHEAD */
+
+/******************************************************************************
+ *
+ *	SkRlmtBuildPacket - build an RLMT packet
+ *
+ * Description:
+ *	This routine sets up an RLMT packet.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	NULL or pointer to RLMT mbuf
+ */
+RLMT_STATIC SK_MBUF	*SkRlmtBuildPacket(
+SK_AC		*pAC,		/* adapter context */
+SK_IOC		IoC,		/* I/O context */
+SK_U32		PortIdx,	/* sending port */
+SK_U16		PacketType,	/* RLMT packet type */
+SK_MAC_ADDR	*SrcAddr,	/* source address */
+SK_MAC_ADDR	*DestAddr)	/* destination address */
+{
+	int		i;
+	SK_U16		Length;
+	SK_MBUF		*pMb;
+	SK_RLMT_PACKET	*pPacket;
+
+	if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) !=
+		NULL) {
+		pPacket = (SK_RLMT_PACKET*)pMb->pData;
+		for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+			pPacket->DstAddr[i] = DestAddr->a[i];
+			pPacket->SrcAddr[i] = SrcAddr->a[i];
+		}
+		pPacket->DSap = SK_RLMT_DSAP;
+		pPacket->SSap = SK_RLMT_SSAP;
+		pPacket->Ctrl = SK_RLMT_CTRL;
+		pPacket->Indicator[0] = SK_RLMT_INDICATOR0;
+		pPacket->Indicator[1] = SK_RLMT_INDICATOR1;
+		pPacket->Indicator[2] = SK_RLMT_INDICATOR2;
+		pPacket->Indicator[3] = SK_RLMT_INDICATOR3;
+		pPacket->Indicator[4] = SK_RLMT_INDICATOR4;
+		pPacket->Indicator[5] = SK_RLMT_INDICATOR5;
+		pPacket->Indicator[6] = SK_RLMT_INDICATOR6;
+
+		SK_U16_TO_NETWORK_ORDER(
+			PacketType,
+			&pPacket->RlmtPacketType[0]);
+
+		for (i = 0; i < 4; i++) {
+			pPacket->Random[i] = pAC->Rlmt.Port[PortIdx].Random[i];
+		}
+		
+		SK_U16_TO_NETWORK_ORDER(
+			SK_RLMT_PACKET_VERSION,
+			&pPacket->RlmtPacketVersion[0]);
+
+		for (i = 0; i < SK_PACKET_DATA_LEN; i++) {
+			pPacket->Data[i] = 0x00;
+		}
+
+		Length = SK_RLMT_MAX_PACKET_SIZE;	/* Or smaller. */
+		pMb->Length = Length;
+		pMb->PortIdx = PortIdx;
+		Length -= 14;
+		SK_U16_TO_NETWORK_ORDER(Length, &pPacket->TypeLen[0]);
+
+		if (PacketType == SK_PACKET_ALIVE) {
+			pAC->Rlmt.Port[PortIdx].TxHelloCts++;
+		}
+	}
+
+	return (pMb);       
+}	/* SkRlmtBuildPacket */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtBuildSpanningTreePacket - build spanning tree check packet
+ *
+ * Description:
+ *	This routine sets up a BPDU packet for spanning tree check.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	NULL or pointer to RLMT mbuf
+ */
+RLMT_STATIC SK_MBUF	*SkRlmtBuildSpanningTreePacket(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortIdx)	/* sending port */
+{
+	unsigned		i;
+	SK_U16			Length;
+	SK_MBUF			*pMb;
+	SK_SPTREE_PACKET	*pSPacket;
+
+	if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) !=
+		NULL) {
+		pSPacket = (SK_SPTREE_PACKET*)pMb->pData;
+		for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+			pSPacket->DstAddr[i] = BridgeMcAddr.a[i];
+			pSPacket->SrcAddr[i] =
+				pAC->Addr.Port[PortIdx].CurrentMacAddress.a[i];
+		}
+		pSPacket->DSap = SK_RLMT_SPT_DSAP;
+		pSPacket->SSap = SK_RLMT_SPT_SSAP;
+		pSPacket->Ctrl = SK_RLMT_SPT_CTRL;
+
+		pSPacket->ProtocolId[0] = SK_RLMT_SPT_PROTOCOL_ID0;
+		pSPacket->ProtocolId[1] = SK_RLMT_SPT_PROTOCOL_ID1;
+		pSPacket->ProtocolVersionId = SK_RLMT_SPT_PROTOCOL_VERSION_ID;
+		pSPacket->BpduType = SK_RLMT_SPT_BPDU_TYPE;
+		pSPacket->Flags = SK_RLMT_SPT_FLAGS;
+		pSPacket->RootId[0] = SK_RLMT_SPT_ROOT_ID0;
+		pSPacket->RootId[1] = SK_RLMT_SPT_ROOT_ID1;
+		pSPacket->RootPathCost[0] = SK_RLMT_SPT_ROOT_PATH_COST0;
+		pSPacket->RootPathCost[1] = SK_RLMT_SPT_ROOT_PATH_COST1;
+		pSPacket->RootPathCost[2] = SK_RLMT_SPT_ROOT_PATH_COST2;
+		pSPacket->RootPathCost[3] = SK_RLMT_SPT_ROOT_PATH_COST3;
+		pSPacket->BridgeId[0] = SK_RLMT_SPT_BRIDGE_ID0;
+		pSPacket->BridgeId[1] = SK_RLMT_SPT_BRIDGE_ID1;
+
+		/*
+		 * Use virtual address as bridge ID and filter these packets
+		 * on receive.
+		 */
+
+		for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+			pSPacket->BridgeId[i + 2] = pSPacket->RootId[i + 2] =
+				pAC->Addr.CurrentMacAddress.a[i];
+		}
+		pSPacket->PortId[0] = SK_RLMT_SPT_PORT_ID0;
+		pSPacket->PortId[1] = SK_RLMT_SPT_PORT_ID1;
+		pSPacket->MessageAge[0] = SK_RLMT_SPT_MSG_AGE0;
+		pSPacket->MessageAge[1] = SK_RLMT_SPT_MSG_AGE1;
+		pSPacket->MaxAge[0] = SK_RLMT_SPT_MAX_AGE0;
+		pSPacket->MaxAge[1] = SK_RLMT_SPT_MAX_AGE1;
+		pSPacket->HelloTime[0] = SK_RLMT_SPT_HELLO_TIME0;
+		pSPacket->HelloTime[1] = SK_RLMT_SPT_HELLO_TIME1;
+		pSPacket->ForwardDelay[0] = SK_RLMT_SPT_FWD_DELAY0;
+		pSPacket->ForwardDelay[1] = SK_RLMT_SPT_FWD_DELAY1;
+
+		Length = SK_RLMT_MAX_PACKET_SIZE;	/* Or smaller. */
+		pMb->Length = Length;
+		pMb->PortIdx = PortIdx;
+		Length -= 14;
+		SK_U16_TO_NETWORK_ORDER(Length, &pSPacket->TypeLen[0]);
+
+		pAC->Rlmt.Port[PortIdx].TxSpHelloReqCts++;
+	}
+
+	return (pMb);       
+}	/* SkRlmtBuildSpanningTreePacket */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSend - build and send check packets
+ *
+ * Description:
+ *	Depending on the RLMT state and the checking state, several packets
+ *	are sent through the indicated port.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing.
+ */
+RLMT_STATIC void	SkRlmtSend(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* I/O context */
+SK_U32	PortIdx)
+{
+	unsigned	j;
+	SK_EVPARA	Para;
+	SK_RLMT_PORT	*pRPort;
+
+	pRPort = &pAC->Rlmt.Port[PortIdx];
+	if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
+		if (pRPort->CheckingState &
+			(SK_RLMT_PCS_TX | SK_RLMT_PCS_RX)) {
+
+			/*
+			 * Port is suspicious. Send the RLMT packet to the
+			 * RLMT multicast address.
+			 */
+
+			if ((Para.pParaPtr = SkRlmtBuildPacket(
+				pAC,
+				IoC,
+				PortIdx,
+				SK_PACKET_ALIVE,
+				&pAC->Addr.Port[PortIdx].CurrentMacAddress,
+				&SkRlmtMcAddr)) != NULL) {
+				SkEventQueue(
+					pAC,
+					SKGE_DRV,
+					SK_DRV_RLMT_SEND,
+					Para);
+			}
+		}
+		else {
+			/*
+			 * Send a directed RLMT packet to all ports that are
+			 * checked by the indicated port.
+			 */
+
+			for (j = 0; j < pRPort->PortsChecked; j++) {
+				if ((Para.pParaPtr =
+					SkRlmtBuildPacket(
+						pAC,
+						IoC,
+						PortIdx,
+						SK_PACKET_ALIVE,
+						&pAC->Addr.Port[PortIdx].CurrentMacAddress,
+						&pRPort->PortCheck[j].CheckAddr)
+						) != NULL) {
+					SkEventQueue(
+						pAC,
+						SKGE_DRV,
+						SK_DRV_RLMT_SEND,
+						Para);
+				}
+			}
+		}
+	}
+
+	if ((pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) &&
+		(pAC->Rlmt.CheckingState & SK_RLMT_RCS_SEND_SEG)) {
+
+		/*
+		 * Send a BPDU packet to make a connected switch tell us
+		 * the correct root bridge.
+		 */
+
+		if ((Para.pParaPtr =
+			SkRlmtBuildSpanningTreePacket(
+				pAC,
+				IoC,
+				PortIdx)
+			) != NULL) {
+			
+			pAC->Rlmt.CheckingState &= ~SK_RLMT_RCS_SEND_SEG;
+			pRPort->RootIdSet = SK_FALSE;
+
+			SkEventQueue(
+				pAC,
+				SKGE_DRV,
+				SK_DRV_RLMT_SEND,
+				Para);
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_TX,
+				("SkRlmtSend: BPDU Packet on Port %u.\n",
+					PortIdx))
+		}
+	}
+
+	return;
+
+}	/* SkRlmtSend */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtPortReceives - check if port is (going) down and bring it up
+ *
+ * Description:
+ *	This routine checks if a port who received a non-BPDU packet
+ *	needs to go up or needs to be stopped going down.
+ *
+* Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing.
+ */
+RLMT_STATIC void	SkRlmtPortReceives(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortIdx)	/* port to check */
+{
+	SK_RLMT_PORT	*pRPort;
+	SK_EVPARA	Para;
+
+	pRPort = &pAC->Rlmt.Port[PortIdx];
+	pRPort->PortNoRx = SK_FALSE;
+
+	if ((pRPort->PortState == SK_RLMT_PS_DOWN) &&
+		!(pRPort->CheckingState & SK_RLMT_PCS_TX)) {
+
+		/*
+		 * Port is marked down (rx), but received a non-BPDU packet.
+		 * Bring it up.
+		 */
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_RX,
+			("SkRlmtPacketReceive: Received on PortDown.\n"))
+
+		pRPort->PortState = SK_RLMT_PS_GOING_UP;
+		pRPort->GuTimeStamp = SkOsGetTime(pAC);
+		Para.Para32[0] = PortIdx;
+		SkTimerStart(
+			pAC,
+			IoC,
+			&pRPort->UpTimer,
+			SK_RLMT_PORTUP_TIM_VAL,
+			SKGE_RLMT,
+			SK_RLMT_PORTUP_TIM,
+			Para);
+		SkRlmtCheckSwitch(pAC, IoC);
+	}
+	else if (pRPort->CheckingState & SK_RLMT_PCS_RX) {
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_RX,
+			("SkRlmtPacketReceive: Stop bringing port down.\n"))
+		SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+		SkRlmtCheckSwitch(pAC, IoC);
+	}
+
+	pRPort->CheckingState &= ~SK_RLMT_PCS_RX;
+	return;
+}	/* SkRlmtPortReceives */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtPacketReceive - receive a packet for closer examination
+ *
+ * Description:
+ *	This routine examines a packet more closely than SkRlmtLookahead*().
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing.
+ */
+RLMT_STATIC void	SkRlmtPacketReceive(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* I/O context */
+SK_MBUF	*pMb)	/* received packet */
+{
+#ifdef xDEBUG
+	extern	void DumpData(char *p, int size);
+#endif	/* DEBUG */
+	int			i;
+	unsigned		j;
+	SK_U16			PacketType;
+	SK_U32			PortIdx;
+	SK_ADDR_PORT		*pAPort;
+	SK_RLMT_PORT		*pRPort;
+	SK_RLMT_PACKET		*pRPacket;
+	SK_SPTREE_PACKET	*pSPacket;
+	SK_EVPARA		Para;
+
+	PortIdx	= pMb->PortIdx;
+	pAPort = &pAC->Addr.Port[PortIdx];
+	pRPort = &pAC->Rlmt.Port[PortIdx];
+
+	SK_DBG_MSG(
+		pAC,
+		SK_DBGMOD_RLMT,
+		SK_DBGCAT_RX,
+		("SkRlmtPacketReceive: PortIdx == %d.\n", PortIdx))
+
+	pRPacket = (SK_RLMT_PACKET*)pMb->pData;
+	pSPacket = (SK_SPTREE_PACKET*)pRPacket;
+
+#ifdef xDEBUG
+	DumpData((char *)pRPacket, 32);
+#endif	/* DEBUG */
+
+	if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) != 0) {
+		SkRlmtPortReceives(pAC, IoC, PortIdx);
+	}
+	
+	/* Check destination address. */
+
+	if (!SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->DstAddr) &&
+		!SK_ADDR_EQUAL(SkRlmtMcAddr.a, pRPacket->DstAddr) &&
+		!SK_ADDR_EQUAL(BridgeMcAddr.a, pRPacket->DstAddr)) {
+
+		/*
+		 * Not sent to current MAC or registered MC address
+		 * => Trash it.
+		 */
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_RX,
+			("SkRlmtPacketReceive: Not for me.\n"))
+
+		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+		return;
+	}
+	else if (SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->SrcAddr)) {
+
+		/*
+		 * Was sent by same port (may happen during port switching
+		 * or in case of duplicate MAC addresses).
+		 */
+
+		/*
+		 * Check for duplicate address here:
+		 * If Packet.Random != My.Random => DupAddr.
+		 */
+
+		for (i = 3; i >= 0; i--) {
+			if (pRPort->Random[i] !=
+				pRPacket->Random[i]) {
+				break;
+			}
+		}
+
+		/*
+		 * CAUTION: Do not check for duplicate MAC
+		 * address in RLMT Alive Reply packets.
+		 */
+
+		if (i >= 0 && pRPacket->DSap == SK_RLMT_DSAP &&
+			pRPacket->Ctrl == SK_RLMT_CTRL &&
+			pRPacket->SSap == SK_RLMT_SSAP &&
+			pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 &&
+			pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 &&
+			pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 &&
+			pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 &&
+			pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 &&
+			pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 &&
+			pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) {
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Duplicate MAC Address.\n"))
+
+			/* Error Log entry. */
+
+			SK_ERR_LOG(
+				pAC,
+				SK_ERRCL_COMM,
+				SKERR_RLMT_E006,
+				SKERR_RLMT_E006_MSG);
+		}
+		else {
+			/* Simply trash it. */
+
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Sent by me.\n"))
+		}
+
+		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+
+		return;
+	}
+
+	/* Check SuspectTx entries. */
+
+	if (pRPort->PortsSuspect > 0) {
+		for (j = 0; j < pRPort->PortsChecked; j++) {
+			if (pRPort->PortCheck[j].SuspectTx &&
+				SK_ADDR_EQUAL(
+					pRPacket->SrcAddr,
+					pRPort->PortCheck[j].CheckAddr.a)) {
+				pRPort->PortCheck[j].SuspectTx = SK_FALSE;
+				pRPort->PortsSuspect--;
+				break;
+			}
+		}
+	}
+
+	/* Determine type of packet. */
+
+	if (pRPacket->DSap == SK_RLMT_DSAP &&
+		pRPacket->Ctrl == SK_RLMT_CTRL &&
+		(pRPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SSAP &&
+		pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 &&
+		pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 &&
+		pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 &&
+		pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 &&
+		pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 &&
+		pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 &&
+		pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) {
+
+		/* It's an RLMT packet. */
+
+		PacketType = (SK_U16)((pRPacket->RlmtPacketType[0] << 8) |
+			pRPacket->RlmtPacketType[1]);
+
+		switch (PacketType) {
+		case SK_PACKET_ANNOUNCE:	/* Not yet used. */
+#if 0
+			/* Build the check chain. */
+
+			SkRlmtBuildCheckChain(pAC);
+#endif	/* 0 */
+
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Announce.\n"))
+
+			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+			break;
+
+		case SK_PACKET_ALIVE:
+			if (pRPacket->SSap & LLC_COMMAND_RESPONSE_BIT) {
+				SK_DBG_MSG(
+					pAC,
+					SK_DBGMOD_RLMT,
+					SK_DBGCAT_RX,
+					("SkRlmtPacketReceive: Alive Reply.\n"))
+
+				/* Alive Reply Packet. */
+
+#if 0
+				pRPort->RlmtAcksPerTimeSlot++;
+#endif	/* 0 */
+
+				if (!(pAC->Addr.Port[PortIdx].PromMode &
+					SK_PROM_MODE_LLC) ||
+					SK_ADDR_EQUAL(
+						pRPacket->DstAddr,
+						pAPort->CurrentMacAddress.a)) {
+
+					/* Obviously we could send something. */
+
+					if (pRPort->CheckingState &
+						SK_RLMT_PCS_TX) {
+						pRPort->CheckingState &=
+							~SK_RLMT_PCS_TX;
+						SkTimerStop(
+							pAC,
+							IoC,
+							&pRPort->DownTxTimer);
+					}
+
+					if ((pRPort->PortState ==
+						SK_RLMT_PS_DOWN) &&
+						!(pRPort->CheckingState &
+						SK_RLMT_PCS_RX)) {
+						pRPort->PortState =
+							SK_RLMT_PS_GOING_UP;
+						pRPort->GuTimeStamp =
+							SkOsGetTime(pAC);
+
+						SkTimerStop(
+							pAC,
+							IoC,
+							&pRPort->DownTxTimer);
+
+						Para.Para32[0] = PortIdx;
+						SkTimerStart(
+							pAC,
+							IoC,
+							&pRPort->UpTimer,
+							SK_RLMT_PORTUP_TIM_VAL,
+							SKGE_RLMT,
+							SK_RLMT_PORTUP_TIM,
+							Para);
+					}
+				}
+
+				/* Mark sending port as alive? */
+
+				SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+			}
+			else {	/* Alive Request Packet. */
+				SK_DBG_MSG(
+					pAC,
+					SK_DBGMOD_RLMT,
+					SK_DBGCAT_RX,
+					("SkRlmtPacketReceive: Alive Request.\n"))
+
+				pRPort->RxHelloCts++;
+#if 0
+				pRPort->RlmtChksPerTimeSlot++;
+#endif	/* 0 */
+
+				/* Answer. */
+
+				for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+					pRPacket->DstAddr[i] =
+						pRPacket->SrcAddr[i];
+					pRPacket->SrcAddr[i] = pAC->Addr.Port[
+						PortIdx].CurrentMacAddress.a[i];
+				}
+				pRPacket->SSap |= LLC_COMMAND_RESPONSE_BIT;
+
+				Para.pParaPtr = pMb;
+				SkEventQueue(
+					pAC,
+					SKGE_DRV,
+					SK_DRV_RLMT_SEND,
+					Para);
+			}
+			break;
+
+		case SK_PACKET_CHECK_TX:
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Check your tx line.\n"))
+
+			/*
+			 * A port checking us requests us to check our tx line.
+			 */
+
+			pRPort->CheckingState |= SK_RLMT_PCS_TX;
+
+			/* Start PortDownTx timer. */
+
+			Para.Para32[0] = PortIdx;
+			SkTimerStart(
+				pAC,
+				IoC,
+				&pRPort->DownTxTimer,
+				SK_RLMT_PORTDOWN_TIM_VAL,
+				SKGE_RLMT,
+				SK_RLMT_PORTDOWN_TX_TIM,
+				Para);
+
+			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+
+			if ((Para.pParaPtr = SkRlmtBuildPacket(
+				pAC,
+				IoC,
+				PortIdx,
+				SK_PACKET_ALIVE,
+				&pAC->Addr.Port[PortIdx].CurrentMacAddress,
+				&SkRlmtMcAddr)) != NULL) {
+				SkEventQueue(
+					pAC,
+					SKGE_DRV,
+					SK_DRV_RLMT_SEND,
+					Para);
+			}
+			break;
+
+		case SK_PACKET_ADDR_CHANGED:
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Address Change.\n"))
+
+			/* Build the check chain. */
+
+			SkRlmtBuildCheckChain(pAC);
+			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+			break;
+
+		default:
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Unknown RLMT packet.\n"))
+
+			/* RA;:;: ??? */
+
+			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+		}
+	}
+	else if (pSPacket->DSap == SK_RLMT_SPT_DSAP &&
+		pSPacket->Ctrl == SK_RLMT_SPT_CTRL &&
+		(pSPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) ==
+		SK_RLMT_SPT_SSAP) {
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_RX,
+			("SkRlmtPacketReceive: BPDU Packet.\n"))
+
+		/* Spanning Tree packet. */
+
+		pRPort->RxSpHelloCts++;
+
+		if (!SK_ADDR_EQUAL(
+			&pSPacket->RootId[2],
+			&pAC->Addr.CurrentMacAddress.a[0])) {
+
+			/*
+			 * Check segmentation if a new root bridge is set and
+			 * the segmentation check is not currently running.
+			 */
+
+			if (!SK_ADDR_EQUAL(
+					&pSPacket->RootId[2],
+					&pRPort->Root.Id[2]) &&
+				(pAC->Rlmt.LinksUp > 1) &&
+				(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) &&
+				!(pAC->Rlmt.CheckingState & SK_RLMT_RCS_SEG)) {
+				pAC->Rlmt.CheckingState |=
+					SK_RLMT_RCS_START_SEG |
+					SK_RLMT_RCS_SEND_SEG;
+			}
+
+			/* Store tree view of this port. */
+
+			for (i = 0; i < 8; i++) {
+				pRPort->Root.Id[i] = pSPacket->RootId[i];
+			}
+			pRPort->RootIdSet = SK_TRUE;
+		}
+
+		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+
+		if (pAC->Rlmt.CheckingState & SK_RLMT_RCS_REPORT_SEG) {
+			SkRlmtCheckSeg(pAC, IoC);
+		}
+	}
+	else {
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_RX,
+			("SkRlmtPacketReceive: Unknown Packet Type.\n"))
+
+		/* Unknown packet. */
+
+		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+	}
+	return;
+}	/* SkRlmtPacketReceive */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtCheckPort - check if a port works
+ *
+ * Description:
+ *	This routine checks if a port whose link is up received something
+ *	and if it seems to transmit successfully.
+ *
+ *	# PortState: PsInit, PsLinkDown, PsDown, PsGoingUp, PsUp
+ *	# PortCheckingState (Bitfield): ChkTx, ChkRx, ChkSeg
+ *	# RlmtCheckingState (Bitfield): ChkSeg, StartChkSeg, ReportSeg
+ *
+ *	if (Rx - RxBpdu == 0) {	# No rx.
+ *		if (state == PsUp) {
+ *			PortCheckingState |= ChkRx
+ *		}
+ *		if (ModeCheckSeg && (Timeout ==
+ *			TO_SHORTEN(RLMT_DEFAULT_TIMEOUT))) {
+ *			RlmtCheckingState |= ChkSeg)
+ *			PortCheckingState |= ChkSeg
+ *		}
+ *		NewTimeout = TO_SHORTEN(Timeout)
+ *		if (NewTimeout < RLMT_MIN_TIMEOUT) {
+ *			NewTimeout = RLMT_MIN_TIMEOUT
+ *			PortState = PsDown
+ *			...
+ *		}
+ *	}
+ *	else {	# something was received
+ *		# Set counter to 0 at LinkDown?
+ *		#   No - rx may be reported after LinkDown ???
+ *		PortCheckingState &= ~ChkRx
+ *		NewTimeout = RLMT_DEFAULT_TIMEOUT
+ *		if (RxAck == 0) {
+ *			possible reasons:
+ *			is my tx line bad? --
+ *				send RLMT multicast and report
+ *				back internally? (only possible
+ *				between ports on same adapter)
+ *		}
+ *		if (RxChk == 0) {
+ *			possible reasons:
+ *			- tx line of port set to check me
+ *			  maybe bad
+ *			- no other port/adapter available or set
+ *			  to check me
+ *			- adapter checking me has a longer
+ *			  timeout
+ *			??? anything that can be done here?
+ *		}
+ *	}
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	New timeout value.
+ */
+RLMT_STATIC SK_U32	SkRlmtCheckPort(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortIdx)	/* port to check */
+{
+	unsigned	i;
+	SK_U32		NewTimeout;
+	SK_RLMT_PORT	*pRPort;
+	SK_EVPARA	Para;
+
+	pRPort = &pAC->Rlmt.Port[PortIdx];
+
+	if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) == 0) {
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SkRlmtCheckPort %d: No (%d) receives in last time slot.\n",
+				PortIdx,
+				pRPort->PacketsPerTimeSlot))
+
+		/*
+		 * Check segmentation if there was no receive at least twice
+		 * in a row (PortNoRx is already set) and the segmentation
+		 * check is not currently running.
+		 */
+
+		if (pRPort->PortNoRx && (pAC->Rlmt.LinksUp > 1) &&
+			(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) &&
+			!(pAC->Rlmt.CheckingState & SK_RLMT_RCS_SEG)) {
+			pAC->Rlmt.CheckingState |=
+				SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG;
+		}
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SkRlmtCheckPort: PortsSuspect %d, PcsRx %d.\n",
+				pRPort->PortsSuspect,
+				pRPort->CheckingState & SK_RLMT_PCS_RX))
+
+		if (pRPort->PortState != SK_RLMT_PS_DOWN) {
+			NewTimeout = TO_SHORTEN(pAC->Rlmt.TimeoutValue);
+			if (NewTimeout < SK_RLMT_MIN_TO_VAL) {
+				NewTimeout = SK_RLMT_MIN_TO_VAL;
+			}
+
+			if (!(pRPort->CheckingState & SK_RLMT_PCS_RX)) {
+				Para.Para32[0] = PortIdx;
+				pRPort->CheckingState |= SK_RLMT_PCS_RX;
+
+				/*
+				 * What shall we do if the port checked
+				 * by this one receives our request
+				 * frames?  What's bad - our rx line
+				 * or his tx line?
+				 */
+
+				SkTimerStart(
+					pAC,
+					IoC,
+					&pRPort->DownRxTimer,
+					SK_RLMT_PORTDOWN_TIM_VAL,
+					SKGE_RLMT,
+					SK_RLMT_PORTDOWN_RX_TIM,
+					Para);
+
+				for (i = 0; i < pRPort->PortsChecked; i++) {
+					if (pRPort->PortCheck[i].SuspectTx) {
+						continue;
+					}
+					pRPort->PortCheck[i].SuspectTx = SK_TRUE;
+					pRPort->PortsSuspect++;
+					if ((Para.pParaPtr =
+						SkRlmtBuildPacket(
+							pAC,
+							IoC,
+							PortIdx,
+							SK_PACKET_CHECK_TX,
+							&pAC->Addr.Port[PortIdx].CurrentMacAddress,
+							&pRPort->PortCheck[i].CheckAddr)
+							) != NULL) {
+						SkEventQueue(
+							pAC,
+							SKGE_DRV,
+							SK_DRV_RLMT_SEND,
+							Para);
+					}
+				}
+			}
+		}
+		else {	/* PortDown -- or all partners suspect. */
+			NewTimeout = SK_RLMT_DEF_TO_VAL;
+		}
+		pRPort->PortNoRx = SK_TRUE;
+	}
+	else {	/* A non-BPDU packet was received. */
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SkRlmtCheckPort %d: %d (%d) receives in last time slot.\n",
+				PortIdx,
+                                pRPort->PacketsPerTimeSlot -
+					pRPort->BpduPacketsPerTimeSlot,
+				pRPort->PacketsPerTimeSlot))
+		
+		SkRlmtPortReceives(pAC, IoC, PortIdx);
+		NewTimeout = SK_RLMT_DEF_TO_VAL;              
+	}
+
+	return (NewTimeout);       
+}	/* SkRlmtCheckPort */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSelectBcRx - select new active port, criteria 1 (CLP)
+ *
+ * Description:
+ *	This routine selects the port that received a broadcast frame
+ *	substantially later than all other ports.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	SK_BOOL
+ */
+RLMT_STATIC SK_BOOL	SkRlmtSelectBcRx(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* I/O context */
+SK_U32	A,	/* active port */
+SK_U32	P,	/* preferred port */
+SK_U32	*N)	/* new active port */
+{
+	SK_U64		BcTimeStamp;
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+        BcTimeStamp = 0;	/* Not totally necessary, but feeling better. */
+	PortFound = SK_FALSE;
+	
+	/* Select port with the latest TimeStamp. */
+
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("TimeStamp Port %d: %.08x%.08x.\n",
+			i,
+			*((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_HI32),
+			*((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_LO32)))
+		if (!pAC->Rlmt.Port[i].PortDown &&
+			!pAC->Rlmt.Port[i].PortNoRx) {
+			if (!PortFound ||
+				pAC->Rlmt.Port[i].BcTimeStamp > BcTimeStamp) {
+				BcTimeStamp = pAC->Rlmt.Port[i].BcTimeStamp;
+				*N = i;
+				PortFound = SK_TRUE;
+			}
+		}
+	}
+
+	if (PortFound) {
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("Port %d received the last broadcast.\n", *N))
+
+		/* Look if another port's time stamp is similar. */
+
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			if (i == *N) {
+				continue;
+			}
+			if (!pAC->Rlmt.Port[i].PortDown &&
+				!pAC->Rlmt.Port[i].PortNoRx &&
+				(pAC->Rlmt.Port[i].BcTimeStamp >
+				BcTimeStamp - SK_RLMT_BC_DELTA ||
+				pAC->Rlmt.Port[i].BcTimeStamp
+				+ SK_RLMT_BC_DELTA > BcTimeStamp)) {
+				PortFound = SK_FALSE;
+				SK_DBG_MSG(
+					pAC,
+					SK_DBGMOD_RLMT,
+					SK_DBGCAT_CTRL,
+					("Port %d received a broadcast %s.\n",
+					i,
+					"at a similar time"))
+				break;
+			}
+		}
+	}
+
+#ifdef DEBUG
+	if (PortFound) {
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_CHECK_SWITCH found Port %d receiving %s.\n",
+				*N,
+				"the substantially latest broadcast"))
+	}
+#endif	/* DEBUG */
+
+	return (PortFound);
+}	/* SkRlmtSelectBcRx */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSelectNotSuspect - select new active port, criteria 2 (CLP)
+ *
+ * Description:
+ *	This routine selects a good port (it is PortUp && !SuspectRx).
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	SK_BOOL
+ */
+RLMT_STATIC SK_BOOL	SkRlmtSelectNotSuspect(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* I/O context */
+SK_U32	A,	/* active port */
+SK_U32	P,	/* preferred port */
+SK_U32	*N)	/* new active port */
+{
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	PortFound = SK_FALSE;
+
+	/* Select first port that is PortUp && !SuspectRx. */
+
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		if (!pAC->Rlmt.Port[i].PortDown &&
+			!(pAC->Rlmt.Port[i].CheckingState & SK_RLMT_PCS_RX)) {
+			*N = i;
+			if (!pAC->Rlmt.Port[A].PortDown &&
+				!(pAC->Rlmt.Port[A].CheckingState &
+				SK_RLMT_PCS_RX)) {
+				*N = A;
+			}
+			if (!pAC->Rlmt.Port[P].PortDown &&
+				!(pAC->Rlmt.Port[P].CheckingState &
+				SK_RLMT_PCS_RX)) {
+				*N = P;
+			}
+			PortFound = SK_TRUE;
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_CTRL,
+				("SK_RLMT_CHECK_SWITCH found Port %d up and not check RX.\n",
+					*N))
+			break;
+		}
+	}
+
+	return (PortFound);
+}	/* SkRlmtSelectNotSuspect */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSelectUp - select new active port, criteria 3, 4 (CLP)
+ *
+ * Description:
+ *	This routine selects a port that is up.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	SK_BOOL
+ */
+RLMT_STATIC SK_BOOL	SkRlmtSelectUp(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* I/O context */
+SK_U32	A,	/* active port */
+SK_U32	P,	/* preferred port */
+SK_U32	*N,	/* new active port */
+SK_BOOL	AutoNegDone)	/* successfully auto-negotiated? */
+{
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	PortFound = SK_FALSE;
+
+	/* Select first port that is PortUp. */
+
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_UP &&
+			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+			*N = i;
+			if (pAC->Rlmt.Port[A].PortState == SK_RLMT_PS_UP &&
+				pAC->GIni.GP[A].PAutoNegFail != AutoNegDone) {
+				*N = A;
+			}
+			if (pAC->Rlmt.Port[P].PortState == SK_RLMT_PS_UP &&
+				pAC->GIni.GP[P].PAutoNegFail != AutoNegDone) {
+				*N = P;
+			}
+			PortFound = SK_TRUE;
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_CTRL,
+				("SK_RLMT_CHECK_SWITCH found Port %d up.\n",
+					*N))
+			break;
+		}
+	}
+
+	return (PortFound);
+}	/* SkRlmtSelectUp */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSelectGoingUp - select new active port, criteria 5, 6 (CLP)
+ *
+ * Description:
+ *	This routine selects the port that is going up for the longest time.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	SK_BOOL
+ */
+RLMT_STATIC SK_BOOL	SkRlmtSelectGoingUp(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* I/O context */
+SK_U32	A,	/* active port */
+SK_U32	P,	/* preferred port */
+SK_U32	*N,	/* new active port */
+SK_BOOL	AutoNegDone)	/* successfully auto-negotiated? */
+{
+	SK_U64		GuTimeStamp=0;
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	PortFound = SK_FALSE;
+
+	/* Select port that is PortGoingUp for the longest time. */
+
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP &&
+			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+                        GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp;
+			*N = i;
+			PortFound = SK_TRUE;
+			break;
+		}
+	}
+
+	if (!PortFound) {
+		return (SK_FALSE);
+	}
+
+	for (i = *N + 1; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP &&
+                        pAC->Rlmt.Port[i].GuTimeStamp < GuTimeStamp &&
+			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+
+                        GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp;
+			*N = i;
+		}
+	}
+
+	SK_DBG_MSG(
+		pAC,
+		SK_DBGMOD_RLMT,
+		SK_DBGCAT_CTRL,
+		("SK_RLMT_CHECK_SWITCH found Port %d going up.\n", *N))
+
+	return (SK_TRUE);
+}	/* SkRlmtSelectGoingUp */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSelectDown - select new active port, criteria 7, 8 (CLP)
+ *
+ * Description:
+ *	This routine selects a port that is down.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	SK_BOOL
+ */
+RLMT_STATIC SK_BOOL	SkRlmtSelectDown(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* I/O context */
+SK_U32	A,	/* active port */
+SK_U32	P,	/* preferred port */
+SK_U32	*N,	/* new active port */
+SK_BOOL	AutoNegDone)	/* successfully auto-negotiated? */
+{
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	PortFound = SK_FALSE;
+
+	/* Select first port that is PortDown. */
+
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_DOWN &&
+			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+			*N = i;
+			if (pAC->Rlmt.Port[A].PortState == SK_RLMT_PS_DOWN &&
+				pAC->GIni.GP[A].PAutoNegFail != AutoNegDone) {
+				*N = A;
+			}
+			if (pAC->Rlmt.Port[P].PortState == SK_RLMT_PS_DOWN &&
+				pAC->GIni.GP[P].PAutoNegFail != AutoNegDone) {
+				*N = P;
+			}
+			PortFound = SK_TRUE;
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_CTRL,
+				("SK_RLMT_CHECK_SWITCH found Port %d down.\n",
+					*N))
+			break;
+		}
+	}
+
+	return (PortFound);
+}	/* SkRlmtSelectDown */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtCheckSwitch - select new active port and switch to it
+ *
+ * Description:
+ *	This routine decides which port should be the active one and queues
+ *	port switching if necessary.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing.
+ */
+RLMT_STATIC void	SkRlmtCheckSwitch(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC)	/* I/O context */
+{
+	SK_EVPARA	Para;
+	SK_U32		A;
+	SK_U32		P;
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	if (pAC->Rlmt.RlmtState == SK_RLMT_RS_INIT) {
+		return;
+	}
+
+	A = pAC->Rlmt.MacActive;	/* Index of active port. */
+	P = pAC->Rlmt.PrefPort;		/* Index of preferred port. */
+	PortFound = SK_FALSE;
+
+	if (pAC->Rlmt.LinksUp == 0) {
+
+		/*
+		 * Last link went down - shut down the net.
+		 */
+
+		pAC->Rlmt.RlmtState = SK_RLMT_RS_NET_DOWN;
+		Para.Para32[0] = SK_RLMT_NET_DOWN_TEMP;
+		SkEventQueue(
+			pAC,
+			SKGE_DRV,
+			SK_DRV_NET_DOWN,
+			Para);
+
+		return;
+	}
+	else if (pAC->Rlmt.LinksUp == 1 &&
+		pAC->Rlmt.RlmtState == SK_RLMT_RS_NET_DOWN) {
+
+		/* First link came up - get the net up. */
+
+		pAC->Rlmt.RlmtState = SK_RLMT_RS_NET_UP;
+
+		/*
+		 * If pAC->Rlmt.MacActive != Para.Para32[0],
+		 * the DRV switches to the port that came up.
+		 */
+
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			if (!pAC->Rlmt.Port[i].LinkDown) {
+				if (!pAC->Rlmt.Port[A].LinkDown) {
+					i = A;
+				}
+				if (!pAC->Rlmt.Port[P].LinkDown) {
+					i = P;
+				}
+				PortFound = SK_TRUE;
+				break;
+			}
+		}
+
+		if (PortFound) {
+			Para.Para32[0] = pAC->Rlmt.MacActive;
+			Para.Para32[1] = i;
+			SkEventQueue(
+				pAC,
+				SKGE_PNMI,
+				SK_PNMI_EVT_RLMT_PORT_SWITCH,
+				Para);
+
+			pAC->Rlmt.MacActive = i;
+			Para.Para32[0] = i;
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_UP, Para);
+
+			if ((Para.pParaPtr = SkRlmtBuildPacket(
+					pAC,
+					IoC,
+					i,
+					SK_PACKET_ANNOUNCE,
+					&pAC->Addr.CurrentMacAddress,
+					&SkRlmtMcAddr)
+				) != NULL) {
+
+				/*
+				 * Send packet to RLMT multicast address
+				 * to force switches to learn the new
+				 * location of the address.
+				 */
+
+				SkEventQueue(
+					pAC,
+					SKGE_DRV,
+					SK_DRV_RLMT_SEND,
+					Para);
+			}
+		}
+		else {
+			SK_ERR_LOG(
+				pAC,
+				SK_ERRCL_SW,
+				SKERR_RLMT_E007,
+				SKERR_RLMT_E007_MSG);
+		}
+
+		return;
+	}
+	else {
+		Para.Para32[0] = A;
+
+		/*
+		 * Preselection:
+		 *   If RLMT Mode != CheckLinkState
+		 *     select port that received a broadcast frame
+		 *     substantially later than all other ports
+		 *   else select first port that is not SuspectRx
+		 *   else select first port that is PortUp
+		 *   else select port that is PortGoingUp for the longest time
+		 *   else select first port that is PortDown
+		 *   else stop.
+		 *
+		 * For the preselected port:
+		 *   If ActivePort is equal in quality, select ActivePort.
+		 *
+		 *   If PrefPort is equal in quality, select PrefPort.
+		 *
+		 *   If MacActive != SelectedPort,
+		 *     If old ActivePort is LinkDown,
+		 *       SwitchHard
+		 *     else
+		 *       SwitchSoft
+		 */
+
+		if (pAC->Rlmt.RlmtMode != SK_RLMT_CHECK_LINK) {
+			if (!PortFound) {
+				PortFound = SkRlmtSelectBcRx(pAC, IoC,
+					A, P, &Para.Para32[1]);
+			}
+
+			if (!PortFound) {
+				PortFound = SkRlmtSelectNotSuspect(pAC, IoC,
+					A, P, &Para.Para32[1]);
+			}
+		}
+
+		if (!PortFound) {
+			PortFound = SkRlmtSelectUp(pAC, IoC,
+				A, P, &Para.Para32[1], AUTONEG_SUCCESS);
+		}
+
+		if (!PortFound) {
+			PortFound = SkRlmtSelectUp(pAC, IoC,
+				A, P, &Para.Para32[1], AUTONEG_FAILED);
+		}
+
+		if (!PortFound) {
+			PortFound = SkRlmtSelectGoingUp(pAC, IoC,
+				A, P, &Para.Para32[1], AUTONEG_SUCCESS);
+		}
+
+		if (!PortFound) {
+			PortFound = SkRlmtSelectGoingUp(pAC, IoC,
+				A, P,&Para.Para32[1], AUTONEG_FAILED);
+		}
+
+		if (pAC->Rlmt.RlmtMode != SK_RLMT_CHECK_LINK) {
+			if (!PortFound) {
+				PortFound = SkRlmtSelectDown(pAC, IoC,
+					A, P,&Para.Para32[1], AUTONEG_SUCCESS);
+			}
+
+			if (!PortFound) {
+				PortFound = SkRlmtSelectDown(pAC, IoC,
+					A, P,&Para.Para32[1], AUTONEG_FAILED);
+			}
+		}
+
+		if (PortFound) {
+			if (Para.Para32[1] != A) {
+				pAC->Rlmt.MacActive = Para.Para32[1];
+				SK_HWAC_LINK_LED(
+					pAC,
+					IoC,
+					Para.Para32[1],
+					SK_LED_ACTIVE);
+				if (pAC->Rlmt.Port[A].LinkDown) {
+					SkEventQueue(
+						pAC,
+						SKGE_DRV,
+						SK_DRV_SWITCH_HARD,
+						Para);
+				}
+				else {
+					SK_HWAC_LINK_LED(
+						pAC,
+						IoC,
+						Para.Para32[0],
+						SK_LED_STANDBY);
+					SkEventQueue(
+						pAC,
+						SKGE_DRV,
+						SK_DRV_SWITCH_SOFT,
+						Para);
+				}
+				SkEventQueue(
+					pAC,
+					SKGE_PNMI,
+					SK_PNMI_EVT_RLMT_PORT_SWITCH,
+					Para);
+				if ((Para.pParaPtr = SkRlmtBuildPacket(
+						pAC,
+						IoC,
+						Para.Para32[1],
+						SK_PACKET_ANNOUNCE,
+						&pAC->Addr.CurrentMacAddress,
+						&SkRlmtMcAddr)
+					) != NULL) {
+
+					/*
+					 * Send "new" packet to RLMT multicast
+					 * address to force switches to learn
+					 * the new location of the MAC address.
+					 */
+
+					SkEventQueue(
+						pAC,
+						SKGE_DRV,
+						SK_DRV_RLMT_SEND,
+						Para);
+				}
+			}
+		}
+		else {
+			SK_ERR_LOG(
+				pAC,
+				SK_ERRCL_SW,
+				SKERR_RLMT_E004,
+				SKERR_RLMT_E004_MSG);
+		}
+	}
+
+	return;
+}	/* SkRlmtCheckSwitch */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtCheckSeg - Report if segmentation is detected
+ *
+ * Description:
+ *	This routine checks if the ports see different root bridges and reports
+ *	segmentation in such a case.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing.
+ */
+RLMT_STATIC void	SkRlmtCheckSeg(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC)	/* I/O context */
+{
+	SK_BOOL	Equal;
+	SK_U32	i, j;
+
+	pAC->Rlmt.RootIdSet = SK_FALSE;
+	Equal = SK_TRUE;
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		if (pAC->Rlmt.Port[i].LinkDown ||
+			!pAC->Rlmt.Port[i].RootIdSet) {
+			continue;
+		}
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
+				i,
+				pAC->Rlmt.Port[i].Root.Id[0],
+				pAC->Rlmt.Port[i].Root.Id[1],
+				pAC->Rlmt.Port[i].Root.Id[2],
+				pAC->Rlmt.Port[i].Root.Id[3],
+				pAC->Rlmt.Port[i].Root.Id[4],
+				pAC->Rlmt.Port[i].Root.Id[5],
+				pAC->Rlmt.Port[i].Root.Id[6],
+				pAC->Rlmt.Port[i].Root.Id[7]))
+
+		if (!pAC->Rlmt.RootIdSet) {
+			pAC->Rlmt.Root = pAC->Rlmt.Port[i].Root;
+			pAC->Rlmt.RootIdSet = SK_TRUE;
+			continue;
+		}
+
+		for (j = 0; j < 8; j ++) {
+			Equal &= pAC->Rlmt.Port[i].Root.Id[j] ==
+				pAC->Rlmt.Root.Id[j];
+			if (!Equal) {
+				break;
+			}
+		}
+		
+		if (!Equal) {
+			SK_ERR_LOG(
+				pAC,
+				SK_ERRCL_COMM,
+				SKERR_RLMT_E005,
+				SKERR_RLMT_E005_MSG);
+#ifdef SK_PNMI_EVT_SEGMENTATION
+			SkEventQueue(
+				pAC,
+				SKGE_PNMI,
+				SK_PNMI_EVT_SEGMENTATION,
+				Para);
+#endif	/* SK_PNMI_EVT_SEGMENTATION */
+			pAC->Rlmt.CheckingState &= ~SK_RLMT_RCS_REPORT_SEG;
+			break;
+		}
+	}
+}	/* SkRlmtCheckSeg */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtPortStart - initialize port variables and start port
+ *
+ * Description:
+ *	This routine initializes a port's variables and issues a PORT_START
+ *	to the HWAC module.  This handles retries if the start fails or the
+ *	link eventually goes down.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtPortStart(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortIdx)	/* event code */
+{
+	SK_EVPARA	Para;
+
+	pAC->Rlmt.Port[PortIdx].PortState = SK_RLMT_PS_LINK_DOWN;
+	pAC->Rlmt.Port[PortIdx].PortStarted = SK_TRUE;
+	pAC->Rlmt.Port[PortIdx].LinkDown = SK_TRUE;
+	pAC->Rlmt.Port[PortIdx].PortDown = SK_TRUE;
+	pAC->Rlmt.Port[PortIdx].CheckingState = 0;
+	pAC->Rlmt.Port[PortIdx].RootIdSet = SK_FALSE;
+	Para.Para32[0] = PortIdx;
+	SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+}	/* SkRlmtPortStart */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvent - a PORT- or an RLMT-specific event happened
+ *
+ * Description:
+ *	This routine handles PORT- and RLMT-specific events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	0
+ */
+int	SkRlmtEvent(
+SK_AC		*pAC,	/* adapter context */
+SK_IOC		IoC,	/* I/O context */
+SK_U32		Event,	/* event code */
+SK_EVPARA	Para)	/* event-specific parameter */
+{
+	SK_U32		i, j;
+	SK_RLMT_PORT	*pRPort;
+	SK_EVPARA	Para2;
+	SK_MBUF		*pMb;
+	SK_MBUF		*pNextMb;
+	SK_MAC_ADDR	*pOldMacAddr;
+	SK_MAC_ADDR	*pNewMacAddr;
+	SK_U32		Timeout;
+	SK_U32		NewTimeout;
+	SK_U32		PrevRlmtMode;
+
+	switch (Event) {
+	case SK_RLMT_PORTSTART_TIM:	/* From RLMT via TIME. */
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTSTART_TIMEOUT Port %d Event (%d) BEGIN.\n", Para.Para32[0], Event))
+
+		/*
+		 * Used to start non-preferred ports if the preferred one
+		 * does not come up.
+		 * This timeout needs only be set when starting the first
+		 * (preferred) port.
+		 */
+
+		if (pAC->Rlmt.Port[Para.Para32[0]].LinkDown) {
+
+			/* PORT_START failed. */
+
+			for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+				if (!pAC->Rlmt.Port[i].PortStarted) {
+					SkRlmtPortStart(pAC, IoC, i);
+				}
+			}
+		}
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTSTART_TIMEOUT Event (%d) END.\n", Event))
+		break;
+
+	case SK_RLMT_LINK_UP:		/* From SIRQ. */
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_LINK_UP Port %d Event (%d) BEGIN.\n",
+				Para.Para32[0], Event))
+
+		pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+
+		if (!pRPort->PortStarted) {
+			SK_ERR_LOG(
+				pAC,
+				SK_ERRCL_SW,
+				SKERR_RLMT_E008,
+				SKERR_RLMT_E008_MSG);
+
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_CTRL,
+				("SK_RLMT_LINK_UP Event (%d) EMPTY.\n", Event))
+			break;
+		}
+
+		if (!pRPort->LinkDown) {
+			/* RA;:;: Any better solution? */
+
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_CTRL,
+				("SK_RLMT_LINK_UP Event (%d) EMPTY.\n", Event))
+			break;
+		}
+
+		SkTimerStop(pAC, IoC, &pRPort->UpTimer);
+		SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+		SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+
+		/* Do something if timer already fired? */
+
+		pRPort->LinkDown = SK_FALSE;
+		pRPort->PortState = SK_RLMT_PS_GOING_UP;
+		pRPort->GuTimeStamp = SkOsGetTime(pAC);
+		pRPort->BcTimeStamp = 0;
+		if (pAC->Rlmt.LinksUp == 0) {
+			SK_HWAC_LINK_LED(
+				pAC,
+				IoC,
+				Para.Para32[0],
+				SK_LED_ACTIVE);
+		}
+		else {
+			SK_HWAC_LINK_LED(
+				pAC,
+				IoC,
+				Para.Para32[0],
+				SK_LED_STANDBY);
+		}
+		pAC->Rlmt.LinksUp++;
+
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			if (!pAC->Rlmt.Port[i].PortStarted) {
+				SkRlmtPortStart(pAC, IoC, i);
+			}
+		}
+
+		SkRlmtCheckSwitch(pAC, IoC);
+
+		if (pAC->Rlmt.LinksUp >= 2) {
+			if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
+
+				/* Build the check chain. */
+
+				SkRlmtBuildCheckChain(pAC);
+			}
+		}
+
+		/*
+		 * If the first link comes up, start the periodical
+		 * RLMT timeout.
+		 */
+
+		if (pAC->GIni.GIMacsFound > 1 && pAC->Rlmt.LinksUp == 1 &&
+			(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_OTHERS)) {
+			SkTimerStart(
+				pAC,
+				IoC,
+				&pAC->Rlmt.LocTimer,
+				pAC->Rlmt.TimeoutValue,
+				SKGE_RLMT,
+				SK_RLMT_TIM,
+				Para);
+		}
+
+		SkTimerStart(
+			pAC,
+			IoC,
+			&pRPort->UpTimer,
+			SK_RLMT_PORTUP_TIM_VAL,
+			SKGE_RLMT,
+			SK_RLMT_PORTUP_TIM,
+			Para);
+
+		/*
+		 * Later:
+		 * if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) &&
+		 */
+
+		if ((pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LINK) &&
+			(Para2.pParaPtr = SkRlmtBuildPacket(
+				pAC,
+				IoC,
+				Para.Para32[0],
+				SK_PACKET_ANNOUNCE,
+				&pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress,
+				&SkRlmtMcAddr)
+			) != NULL) {
+
+			/* Send "new" packet to RLMT multicast address. */
+
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
+		}
+
+		if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) {
+			if ((Para2.pParaPtr =
+				SkRlmtBuildSpanningTreePacket(
+					pAC,
+					IoC,
+					Para.Para32[0])
+				) != NULL) {
+				
+				pAC->Rlmt.Port[Para.Para32[0]].RootIdSet =
+					SK_FALSE;
+				pAC->Rlmt.CheckingState |=
+					SK_RLMT_RCS_SEG |
+					SK_RLMT_RCS_REPORT_SEG;
+				
+				SkEventQueue(
+					pAC,
+					SKGE_DRV,
+					SK_DRV_RLMT_SEND,
+					Para2);
+
+				SkTimerStart(
+					pAC,
+					IoC,
+					&pAC->Rlmt.SegTimer,
+					SK_RLMT_SEG_TO_VAL,
+					SKGE_RLMT,
+					SK_RLMT_SEG_TIM,
+					Para);
+			}
+		}
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_LINK_UP Event (%d) END.\n", Event))
+		break;
+
+	case SK_RLMT_PORTUP_TIM:	/* From RLMT via TIME. */
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTUP_TIM Port %d Event (%d) BEGIN.\n", Para.Para32[0], Event))
+
+		pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+
+		if (pRPort->LinkDown || (pRPort->PortState == SK_RLMT_PS_UP)) {
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_CTRL,
+				("SK_RLMT_PORTUP_TIM Port %d Event (%d) EMPTY.\n",
+					Para.Para32[0],
+					Event))
+			break;
+		}
+
+		pRPort->PortDown = SK_FALSE;
+                pRPort->PortState = SK_RLMT_PS_UP;
+		pAC->Rlmt.PortsUp++;
+
+		if (pAC->Rlmt.RlmtState != SK_RLMT_RS_INIT) {
+			SkRlmtCheckSwitch(pAC, IoC);
+
+			SkEventQueue(
+				pAC,
+				SKGE_PNMI,
+				SK_PNMI_EVT_RLMT_PORT_UP,
+				Para);
+		}
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTUP_TIM Event (%d) END.\n", Event))
+		break;
+
+	case SK_RLMT_PORTDOWN:		/* From RLMT. */
+	case SK_RLMT_PORTDOWN_RX_TIM:	/* From RLMT via TIME. */
+	case SK_RLMT_PORTDOWN_TX_TIM:	/* From RLMT via TIME. */
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTDOWN* Port %d Event (%d) BEGIN.\n", Para.Para32[0], Event))
+
+		pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+
+		if (!pRPort->PortStarted ||
+			(Event == SK_RLMT_PORTDOWN_TX_TIM &&
+			!(pRPort->CheckingState & SK_RLMT_PCS_TX))) {
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_CTRL,
+				("SK_RLMT_PORTDOWN* Event (%d) EMPTY.\n", Event))
+			break;
+		}
+		/* Stop port's timers. */
+
+		SkTimerStop(pAC, IoC, &pRPort->UpTimer);
+		SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+		SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+
+		if (pRPort->PortState != SK_RLMT_PS_LINK_DOWN) {
+			pRPort->PortState = SK_RLMT_PS_DOWN;
+		}
+
+		if (!pRPort->PortDown) {
+			pAC->Rlmt.PortsUp--;
+			pRPort->PortDown = SK_TRUE;
+
+			SkEventQueue(
+				pAC,
+				SKGE_PNMI,
+				SK_PNMI_EVT_RLMT_PORT_DOWN,
+				Para);
+		}
+
+		pRPort->PacketsPerTimeSlot = 0;
+		pRPort->DataPacketsPerTimeSlot = 0;
+		pRPort->BpduPacketsPerTimeSlot = 0;
+#if 0
+		pRPort->RlmtChksPerTimeSlot = 0;
+		pRPort->RlmtAcksPerTimeSlot = 0;
+#endif	/* 0 */
+
+		/*
+		 * RA;:;: To be checked:
+		 * - actions at RLMT_STOP: We should not switch anymore.
+		 */
+
+		if (pAC->Rlmt.RlmtState != SK_RLMT_RS_INIT) {
+			if (Para.Para32[0] == pAC->Rlmt.MacActive) {
+
+				/* Active Port went down. */
+
+				SkRlmtCheckSwitch(pAC, IoC);
+			}
+		}
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTDOWN* Event (%d) END.\n", Event))
+		break;
+
+	case SK_RLMT_LINK_DOWN:		/* From SIRQ. */
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_LINK_DOWN Port %d Event (%d) BEGIN.\n",
+				Para.Para32[0], Event))
+
+		if (!pAC->Rlmt.Port[Para.Para32[0]].LinkDown) {
+			pAC->Rlmt.LinksUp--;
+			pAC->Rlmt.Port[Para.Para32[0]].LinkDown = SK_TRUE;
+			pAC->Rlmt.Port[Para.Para32[0]].PortState =
+					SK_RLMT_PS_LINK_DOWN;
+			SK_HWAC_LINK_LED(
+				pAC,
+				IoC,
+				Para.Para32[0],
+				SK_LED_OFF);
+
+			if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
+
+				/* Build the check chain. */
+
+				SkRlmtBuildCheckChain(pAC);
+			}
+
+			/* Ensure that port is marked down. */
+
+			(void)SkRlmtEvent(
+				pAC,
+				IoC,
+				SK_RLMT_PORTDOWN,
+				Para);
+		}
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_LINK_DOWN Event (%d) END.\n", Event))
+		break;
+
+	case SK_RLMT_PORT_ADDR:		/* From ADDR. */
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_PORT_ADDR Port %d Event (%d) BEGIN.\n", Para.Para32[0], Event))
+
+		/* Port's physical MAC address changed. */
+
+		pOldMacAddr =
+			&pAC->Addr.Port[Para.Para32[0]].PreviousMacAddress;
+		pNewMacAddr =
+			&pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress;
+
+		/*
+		 * NOTE: This is not scalable for solutions where ports are
+		 *	 checked remotely.  There, we need to send an RLMT
+		 *	 address change packet - and how do we ensure delivery?
+		 */
+
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			pRPort = &pAC->Rlmt.Port[i];
+			for (j = 0; j < pRPort->PortsChecked; j++) {
+				if (SK_ADDR_EQUAL(
+					pRPort->PortCheck[j].CheckAddr.a,
+					pOldMacAddr->a)) {
+					pRPort->PortCheck[j].CheckAddr =
+						*pNewMacAddr;
+				}
+			}
+		}
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_PORT_ADDR Event (%d) END.\n", Event))
+		break;
+
+	/* ----- RLMT events ----- */
+
+	case SK_RLMT_START:		/* From DRV. */
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event (%d) BEGIN.\n", Event))
+
+		if (pAC->Rlmt.RlmtState != SK_RLMT_RS_INIT) {
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_CTRL,
+				("SK_RLMT_START Event (%d) EMPTY.\n", Event))
+			break;
+		}
+
+		if (pAC->Rlmt.PrefPort >= (SK_U32)pAC->GIni.GIMacsFound) {
+			SK_ERR_LOG(
+				pAC,
+				SK_ERRCL_SW,
+				SKERR_RLMT_E009,
+				SKERR_RLMT_E009_MSG);
+
+			/* Change PrefPort to internal default. */
+
+			Para.Para32[0] = 0xFFFFFFFF;
+			(void)SkRlmtEvent(
+				pAC,
+				IoC,
+				SK_RLMT_PREFPORT_CHANGE,
+				Para);
+		}
+#if 0
+		if (pAC->GIni.GIMacsFound == 1 &&
+			pAC->Rlmt.RlmtMode != SK_RLMT_CHECK_LINK) {
+			Para.Para32[0] = SK_RLMT_CHECK_LINK;
+			(void)SkRlmtEvent(
+				pAC,
+				IoC,
+				SK_RLMT_MODE_CHANGE,
+				Para);
+		}
+#endif	/* 0 */
+		pAC->Rlmt.LinksUp = 0;
+		pAC->Rlmt.PortsUp = 0;
+		pAC->Rlmt.CheckingState = 0;
+		pAC->Rlmt.RlmtState = SK_RLMT_RS_NET_DOWN;
+
+		SkRlmtPortStart(pAC, IoC, pAC->Rlmt.PrefPort);
+
+		/* Start Timer (for first port only). */
+
+		Para2.Para32[0] = pAC->Rlmt.PrefPort;
+		SkTimerStart(
+			pAC,
+			IoC,
+			&pAC->Rlmt.Port[pAC->Rlmt.PrefPort].UpTimer,
+			SK_RLMT_PORTSTART_TIM_VAL,
+			SKGE_RLMT,
+			SK_RLMT_PORTSTART_TIM,
+			Para2);
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event (%d) END.\n", Event))
+		break;
+
+	case SK_RLMT_STOP:		/* From DRV. */
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_STOP Event (%d) BEGIN.\n", Event))
+
+		if (pAC->Rlmt.RlmtState == SK_RLMT_RS_INIT) {
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_CTRL,
+				("SK_RLMT_STOP Event (%d) EMPTY.\n", Event))
+			break;
+		}
+
+		/* Stop RLMT timers. */
+
+		SkTimerStop(pAC, IoC, &pAC->Rlmt.LocTimer); 
+		SkTimerStop(pAC, IoC, &pAC->Rlmt.SegTimer);
+
+		/* Stop Net. */
+
+		pAC->Rlmt.RlmtState = SK_RLMT_RS_INIT;
+		pAC->Rlmt.RootIdSet = SK_FALSE;
+		Para2.Para32[0] = SK_RLMT_NET_DOWN_FINAL;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para2);
+
+		/* Stop ports. */
+
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			if (pAC->Rlmt.Port[i].PortState != SK_RLMT_PS_INIT) {
+				SkTimerStop(
+					pAC,
+					IoC,
+					&pAC->Rlmt.Port[i].UpTimer);
+				SkTimerStop(
+					pAC,
+					IoC,
+					&pAC->Rlmt.Port[i].DownRxTimer);
+				SkTimerStop(
+					pAC,
+					IoC,
+					&pAC->Rlmt.Port[i].DownTxTimer);
+
+				pAC->Rlmt.Port[i].PortState = SK_RLMT_PS_INIT;
+				pAC->Rlmt.Port[i].RootIdSet = SK_FALSE;
+				pAC->Rlmt.Port[i].PortStarted = SK_FALSE;
+				Para2.Para32[0] = i;
+				SkEventQueue(
+					pAC,
+					SKGE_HWAC,
+					SK_HWEV_PORT_STOP,
+					Para2);
+			}
+		}
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_STOP Event (%d) END.\n", Event))
+		break;
+
+	case SK_RLMT_TIM:		/* From RLMT via TIME. */
+#if 0
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_TIM Event (%d) BEGIN.\n", Event))
+#endif	/* 0 */
+
+		if (!(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_OTHERS) ||
+			pAC->Rlmt.LinksUp == 0) {
+
+			/*
+			 * Mode changed or all links down:
+			 * No more link checking.
+			 */
+
+			break;
+		}
+
+#if 0
+                pAC->Rlmt.SwitchCheckCounter--;
+		if (pAC->Rlmt.SwitchCheckCounter == 0) {
+			pAC->Rlmt.SwitchCheckCounter;
+		}
+#endif	/* 0 */
+
+		NewTimeout = SK_RLMT_DEF_TO_VAL;
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			pRPort = &pAC->Rlmt.Port[i];
+			if (!pRPort->LinkDown) {
+				Timeout = SkRlmtCheckPort(pAC, IoC, i);
+				if (Timeout < NewTimeout) {
+					NewTimeout = Timeout;
+				}
+
+				/*
+				 * This counter should be set to 0 for all
+				 * ports before the first frame is sent in the
+				 * next loop.
+				 */
+
+				pRPort->PacketsPerTimeSlot = 0;
+				pRPort->DataPacketsPerTimeSlot = 0;
+				pRPort->BpduPacketsPerTimeSlot = 0;
+#if 0
+				pRPort->RlmtChksPerTimeSlot = 0;
+				pRPort->RlmtAcksPerTimeSlot = 0;
+#endif	/* 0 */
+			}
+		}
+		pAC->Rlmt.TimeoutValue = NewTimeout;
+
+		if (pAC->Rlmt.LinksUp > 1) {
+			/*
+			 * If checking remote ports, also send packets if
+			 *   (LinksUp == 1) &&
+			 *   this port checks at least one (remote) port.
+			 */
+
+			/*
+			 * Must be new loop, as SkRlmtCheckPort can request to
+			 * check segmentation when e.g. checking the last port.
+			 */
+
+			for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+				pRPort = &pAC->Rlmt.Port[i];
+				if (!pRPort->LinkDown) {	/* !PortDown? */
+					SkRlmtSend(pAC, IoC, i);
+				}
+			}
+		}
+
+		SkTimerStart(
+			pAC,
+			IoC,
+			&pAC->Rlmt.LocTimer,
+			pAC->Rlmt.TimeoutValue,
+			SKGE_RLMT,
+			SK_RLMT_TIM,
+			Para);
+
+		if (pAC->Rlmt.LinksUp > 1 &&
+			(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) &&
+			(pAC->Rlmt.CheckingState & SK_RLMT_RCS_START_SEG)) {
+			SkTimerStart(
+				pAC,
+				IoC,
+				&pAC->Rlmt.SegTimer,
+				SK_RLMT_SEG_TO_VAL,
+				SKGE_RLMT,
+				SK_RLMT_SEG_TIM,
+				Para);
+			pAC->Rlmt.CheckingState &=
+				~SK_RLMT_RCS_START_SEG;
+			pAC->Rlmt.CheckingState |=
+				SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG;
+		}
+
+#if 0
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_TIM Event (%d) END.\n", Event))
+#endif	/* 0 */
+		break;
+
+	case SK_RLMT_SEG_TIM:
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_SEG_TIM Event (%d) BEGIN.\n", Event))
+
+#ifdef DEBUG
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			SK_U8		InAddr8[6];
+			SK_U16		*InAddr;
+			SK_ADDR_PORT	*pAPort;
+
+			InAddr = (SK_U16 *)&InAddr8[0];
+			pAPort = &pAC->Addr.Port[i];
+			for (j = 0;
+				j < pAPort->NextExactMatchRlmt;
+				j++) {
+
+				/* Get exact match address j from port i. */
+
+				XM_INADDR(IoC, i, XM_EXM(j), InAddr);
+				SK_DBG_MSG(
+					pAC,
+					SK_DBGMOD_RLMT,
+					SK_DBGCAT_CTRL,
+					("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x --  %02x %02x %02x %02x %02x %02x.\n",
+						j,
+       						i,
+       						InAddr8[0],
+       						InAddr8[1],
+       						InAddr8[2],
+       						InAddr8[3],
+       						InAddr8[4],
+       						InAddr8[5],
+						pAPort->Exact[j].a[0],
+						pAPort->Exact[j].a[1],
+						pAPort->Exact[j].a[2],
+						pAPort->Exact[j].a[3],
+						pAPort->Exact[j].a[4],
+						pAPort->Exact[j].a[5]))
+			}
+		}
+#endif	/* DEBUG */
+				   
+		pAC->Rlmt.CheckingState &= ~SK_RLMT_RCS_SEG;
+
+		SkRlmtCheckSeg(pAC, IoC);
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_SEG_TIM Event (%d) END.\n", Event))
+		break;
+
+	case SK_RLMT_PACKET_RECEIVED:	/* From DRV. */
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_PACKET_RECEIVED Event (%d) BEGIN.\n", Event))
+
+		/* Should we ignore frames during port switching? */
+
+#ifdef DEBUG
+		pMb = Para.pParaPtr;
+		if (pMb == NULL) {
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_CTRL,
+				("No mbuf.\n"))
+		}
+		else if (pMb->pNext != NULL) {
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_CTRL,
+				("More than one mbuf or pMb->pNext not set.\n"))
+		}
+#endif	/* DEBUG */
+
+		for (pMb = Para.pParaPtr; pMb != NULL; pMb = pNextMb) {
+			pNextMb = pMb->pNext;
+			pMb->pNext = NULL;
+			SkRlmtPacketReceive(pAC, IoC, pMb);
+		}
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_PACKET_RECEIVED Event (%d) END.\n", Event))
+		break;
+
+	case SK_RLMT_STATS_CLEAR:	/* From PNMI. */
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_STATS_CLEAR Event (%d) BEGIN.\n", Event))
+
+		/* Clear statistics for virtual and physical ports. */
+
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			pAC->Rlmt.Port[i].TxHelloCts = 0;
+			pAC->Rlmt.Port[i].RxHelloCts = 0;
+			pAC->Rlmt.Port[i].TxSpHelloReqCts = 0;
+			pAC->Rlmt.Port[i].RxSpHelloCts = 0;
+		}
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_STATS_CLEAR Event (%d) END.\n", Event))
+		break;
+
+	case SK_RLMT_STATS_UPDATE:	/* From PNMI. */
+#if 0
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_STATS_UPDATE Event (%d) BEGIN.\n", Event))
+
+		/* Update statistics. */
+
+		/* Currently always up-to-date. */
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_STATS_UPDATE Event (%d) END.\n", Event))
+#endif	/* 0 */
+		break;
+
+	case SK_RLMT_PREFPORT_CHANGE:	/* From PNMI. */
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_PREFPORT_CHANGE to Port %d Event (%d) BEGIN.\n", Para.Para32[0], Event))
+
+		/* 0xFFFFFFFF == auto-mode. */
+
+		if (Para.Para32[0] == 0xFFFFFFFF) {
+			pAC->Rlmt.PrefPort = SK_RLMT_DEF_PREF_PORT;
+		}
+		else {
+			if (Para.Para32[0] >= (SK_U32)pAC->GIni.GIMacsFound) {
+				SK_ERR_LOG(
+					pAC,
+					SK_ERRCL_SW,
+					SKERR_RLMT_E010,
+					SKERR_RLMT_E010_MSG);
+
+				SK_DBG_MSG(
+					pAC,
+					SK_DBGMOD_RLMT,
+					SK_DBGCAT_CTRL,
+					("SK_RLMT_PREFPORT_CHANGE Event (%d) EMPTY.\n", Event))
+				break;
+			}
+
+			pAC->Rlmt.PrefPort = Para.Para32[0];
+		}
+
+		pAC->Rlmt.MacPreferred = Para.Para32[0];
+
+		SkRlmtCheckSwitch(pAC, IoC);
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_PREFPORT_CHANGE Event (%d) END.\n", Event))
+		break;
+
+	case SK_RLMT_MODE_CHANGE:	/* From PNMI. */
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_MODE_CHANGE Event (%d) BEGIN.\n", Event))
+
+		if (pAC->GIni.GIMacsFound < 2) {
+			pAC->Rlmt.RlmtMode = SK_RLMT_CHECK_LINK;
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_CTRL,
+				("Forced RLMT mode to CLS on single link adapter.\n"))
+			SK_DBG_MSG(
+				pAC,
+				SK_DBGMOD_RLMT,
+				SK_DBGCAT_CTRL,
+				("SK_RLMT_MODE_CHANGE Event (%d) EMPTY.\n",
+					Event))
+			break;
+		}
+
+		/* Update RLMT mode. */
+
+		PrevRlmtMode = pAC->Rlmt.RlmtMode;
+		pAC->Rlmt.RlmtMode = Para.Para32[0] | SK_RLMT_CHECK_LINK;
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("RLMT: Changed Mode to %X.\n", pAC->Rlmt.RlmtMode))
+
+		if ((PrevRlmtMode & SK_RLMT_CHECK_LOC_LINK) !=
+			(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK)) {
+			if (!(PrevRlmtMode & SK_RLMT_CHECK_OTHERS) &&
+				pAC->GIni.GIMacsFound > 1 &&
+				pAC->Rlmt.PortsUp == 1) {
+				SkTimerStart(
+					pAC,
+					IoC,
+					&pAC->Rlmt.LocTimer,
+					pAC->Rlmt.TimeoutValue,
+					SKGE_RLMT,
+					SK_RLMT_TIM,
+					Para);
+			}
+		}
+
+		if ((PrevRlmtMode & SK_RLMT_CHECK_SEG) !=
+			(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG)) {
+
+			for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+				(void)SkAddrMcClear(
+					pAC,
+					IoC,
+					i,
+					SK_ADDR_PERMANENT | SK_MC_SW_ONLY);
+
+				/* Add RLMT MC address. */
+
+				(void)SkAddrMcAdd(
+					pAC,
+					IoC,
+					i,
+					&SkRlmtMcAddr,
+					SK_ADDR_PERMANENT);
+
+				if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) {
+					/* Add BPDU MC address. */
+
+					(void)SkAddrMcAdd(
+						pAC,
+						IoC,
+						i,
+						&BridgeMcAddr,
+						SK_ADDR_PERMANENT);
+
+					if (pAC->Rlmt.RlmtState !=
+						SK_RLMT_RS_INIT) {
+						if (!pAC->Rlmt.Port[i].LinkDown &&
+							(Para2.pParaPtr =
+							SkRlmtBuildSpanningTreePacket(
+								pAC,
+								IoC,
+								i)
+							) != NULL) {
+							
+							pAC->Rlmt.Port[i
+								].RootIdSet =
+								SK_FALSE;
+
+							SkEventQueue(
+								pAC,
+								SKGE_DRV,
+								SK_DRV_RLMT_SEND,
+								Para2);
+						}
+					}
+				}
+
+				(void)SkAddrMcUpdate(pAC, IoC, i);
+			}
+
+			if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) {
+				SkTimerStart(
+					pAC,
+					IoC,
+					&pAC->Rlmt.SegTimer,
+					SK_RLMT_SEG_TO_VAL,
+					SKGE_RLMT,
+					SK_RLMT_SEG_TIM,
+					Para);
+			}
+		}
+
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("SK_RLMT_MODE_CHANGE Event (%d) END.\n", Event))
+		break;
+
+	default:	/* Create error log entry. */
+		SK_DBG_MSG(
+			pAC,
+			SK_DBGMOD_RLMT,
+			SK_DBGCAT_CTRL,
+			("Unknown RLMT Event %d.\n", Event))
+
+		SK_ERR_LOG(
+			pAC,
+			SK_ERRCL_SW,
+			SKERR_RLMT_E003,
+			SKERR_RLMT_E003_MSG);
+		break;
+	}
+
+	return (0);       
+}	/* SkRlmtEvent */
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/sktimer.c linux.14p16/drivers/net/sk98lin/sktimer.c
--- linux.vanilla/drivers/net/sk98lin/sktimer.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/sktimer.c	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,290 @@
+/******************************************************************************
+ *
+ * Name:	sktimer.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.11 $
+ * Date:	$Date: 1998/12/17 13:24:13 $
+ * Purpose:	High level timer functions.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skge.c" for further 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 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: sktimer.c,v $
+ *	Revision 1.11  1998/12/17 13:24:13  gklug
+ *	fix: restart problem: do NOT destroy timer queue if init 1 is done
+ *	
+ *	Revision 1.10  1998/10/15 15:11:36  gklug
+ *	fix: ID_sccs to SysKonnectFileId
+ *	
+ *	Revision 1.9  1998/09/15 15:15:04  cgoos
+ *	Changed TRUE/FALSE to SK_TRUE/SK_FALSE
+ *	
+ *	Revision 1.8  1998/09/08 08:47:55  gklug
+ *	add: init level handling
+ *	
+ *	Revision 1.7  1998/08/19 09:50:53  gklug
+ *	fix: remove struct keyword from c-code (see CCC) add typedefs
+ *	
+ *	Revision 1.6  1998/08/17 13:43:13  gklug
+ *	chg: Parameter will be union of 64bit para, 2 times SK_U32 or SK_PTR
+ *	
+ *	Revision 1.5  1998/08/14 07:09:14  gklug
+ *	fix: chg pAc -> pAC
+ *	
+ *	Revision 1.4  1998/08/07 12:53:46  gklug
+ *	fix: first compiled version
+ *	
+ *	Revision 1.3  1998/08/07 09:31:53  gklug
+ *	fix: delta spelling
+ *	
+ *	Revision 1.2  1998/08/07 09:31:02  gklug
+ *	adapt functions to new c coding conventions
+ *	rmv: "fast" handling
+ *	chg: inserting of new timer in queue.
+ *	chg: event queue generation when timer runs out
+ *	
+ *	Revision 1.1  1998/08/05 11:27:55  gklug
+ *	first version: adapted from SMT
+ *	
+ *	
+ *	
+ *
+ ******************************************************************************/
+
+
+/*
+	Event queue and dispatcher
+*/
+static const char SysKonnectFileId[] =
+	"$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.11 1998/12/17 13:24:13 gklug Exp $" ;
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+	Event queue management.
+
+	General Description:
+
+ */
+intro()
+{}
+#endif
+
+
+/* Forward declaration */
+static void timer_done(SK_AC *pAC,SK_IOC Ioc,int Restart);
+
+
+/*
+ * Inits the software timer
+ *
+ * needs to be called during Init level 1.
+ */
+void	SkTimerInit(
+SK_AC	*pAC,		/* Adapters context */
+SK_IOC	Ioc,		/* IoContext */
+int	Level)		/* Init Level */
+{
+	switch (Level) {
+	case SK_INIT_DATA:
+		pAC->Tim.StQueue = 0 ;
+		break;
+	case SK_INIT_IO:
+		SkHwtInit(pAC,Ioc) ;
+		SkTimerDone(pAC, Ioc);
+		break;
+	default:
+		break;
+	}
+}
+
+/*
+ * Stops a high level timer
+ * - If a timer is not in the queue the function returns normally, too.
+ */
+void	SkTimerStop(
+SK_AC		*pAC,		/* Adapters context */
+SK_IOC		Ioc,		/* IoContext */
+SK_TIMER	*pTimer)	/* Timer Pointer to be started */
+{
+	SK_TIMER	**ppTimPrev ;
+	SK_TIMER	*pTm ;
+
+	/*
+	 * remove timer from queue
+	 */
+	pTimer->TmActive = SK_FALSE ;
+	if (pAC->Tim.StQueue == pTimer && !pTimer->TmNext) {
+		SkHwtStop(pAC,Ioc) ;
+	}
+	for (ppTimPrev = &pAC->Tim.StQueue ; (pTm = *ppTimPrev) ;
+		ppTimPrev = &pTm->TmNext ) {
+		if (pTm == pTimer) {
+			/*
+			 * Timer found in queue
+			 * - dequeue it and
+			 * - correct delta of the next timer
+			 */
+			*ppTimPrev = pTm->TmNext ;
+
+			if (pTm->TmNext) {
+				/* correct delta of next timer in queue */
+				pTm->TmNext->TmDelta += pTm->TmDelta ;
+			}
+			return ;
+		}
+	}
+}
+
+/*
+ * Start a high level software timer
+ */
+void	SkTimerStart(
+SK_AC		*pAC,		/* Adapters context */
+SK_IOC		Ioc,		/* IoContext */
+SK_TIMER	*pTimer,	/* Timer Pointer to be started */
+SK_U32		Time,		/* Time value */
+SK_U32		Class,		/* Event Class for this timer */
+SK_U32		Event,		/* Event Value for this timer */
+SK_EVPARA	Para)		/* Event Parameter for this timer */
+{
+	SK_TIMER	**ppTimPrev ;
+	SK_TIMER	*pTm ;
+	SK_U32		Delta ;
+
+	Time /= 16 ;		/* input is uS, clock ticks are 16uS */
+	if (!Time)
+		Time = 1 ;
+
+	SkTimerStop(pAC,Ioc,pTimer) ;
+
+	pTimer->TmClass = Class ;
+	pTimer->TmEvent = Event ;
+	pTimer->TmPara = Para ;
+	pTimer->TmActive = SK_TRUE ;
+
+	if (!pAC->Tim.StQueue) {
+		/* First Timer to be started */
+		pAC->Tim.StQueue = pTimer ;
+		pTimer->TmNext = 0 ;
+		pTimer->TmDelta = Time ;
+		SkHwtStart(pAC,Ioc,Time) ;
+		return ;
+	}
+
+	/*
+	 * timer correction
+	 */
+	timer_done(pAC,Ioc,0) ;
+
+	/*
+	 * find position in queue
+	 */
+	Delta = 0 ;
+	for (ppTimPrev = &pAC->Tim.StQueue ; (pTm = *ppTimPrev) ;
+		ppTimPrev = &pTm->TmNext ) {
+		if (Delta + pTm->TmDelta > Time) {
+			/* Position found */
+			/* Here the timer needs to be inserted. */
+			break ;
+		}
+		Delta += pTm->TmDelta ;
+	}
+
+	/* insert in queue */
+	*ppTimPrev = pTimer ;
+	pTimer->TmNext = pTm ;
+	pTimer->TmDelta = Time - Delta ;
+
+	if (pTm) {
+		/* There is a next timer
+		 * -> correct its Delta value.
+		 */
+		pTm->TmDelta -= pTimer->TmDelta ;
+	}
+
+	/*
+	 * start new with first
+	 */
+	SkHwtStart(pAC,Ioc,pAC->Tim.StQueue->TmDelta) ;
+}
+
+
+void	SkTimerDone(
+SK_AC	*pAC,		/* Adapters context */
+SK_IOC	Ioc)		/* IoContext */
+{
+	timer_done(pAC,Ioc,1) ;
+}
+
+
+static void	timer_done(
+SK_AC	*pAC,		/* Adapters context */
+SK_IOC	Ioc,		/* IoContext */
+int	Restart)	/* Do we need to restart the Hardware timer ? */
+{
+	SK_U32		Delta ;
+	SK_TIMER	*pTm ;
+	SK_TIMER	*pTComp ;	/* Timer completed now now */
+	SK_TIMER	**ppLast ;	/* Next field of Last timer to be deq */
+	int		Done = 0 ;
+
+	Delta = SkHwtRead(pAC,Ioc) ;
+	ppLast = &pAC->Tim.StQueue ;
+	pTm = pAC->Tim.StQueue ;
+	while (pTm && !Done) {
+		if (Delta >= pTm->TmDelta) {
+			/* Timer ran out */
+			pTm->TmActive = SK_FALSE ;
+			Delta -= pTm->TmDelta ;
+			ppLast = &pTm->TmNext ;
+			pTm = pTm->TmNext ;
+		} else {
+			/* We found the first timer that did not run out */
+			pTm->TmDelta -= Delta ;
+			Delta = 0 ;
+			Done = 1 ;
+		}
+	}
+	*ppLast = 0 ;
+	/*
+	 * pTm points to the first Timer that did not run out.
+	 * StQueue points to the first Timer that run out.
+	 */
+
+	for ( pTComp = pAC->Tim.StQueue ; pTComp ; pTComp = pTComp->TmNext) {
+		SkEventQueue(pAC,pTComp->TmClass, pTComp->TmEvent,
+			pTComp->TmPara) ;
+	}
+
+	/* Set head of timer queue to the first timer that did not run out */
+	pAC->Tim.StQueue = pTm ;
+
+	if (Restart && pAC->Tim.StQueue) {
+		/* Restart HW timer */
+		SkHwtStart(pAC,Ioc,pAC->Tim.StQueue->TmDelta) ;
+	}
+}
+
+/* End of file */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/skvpd.c linux.14p16/drivers/net/sk98lin/skvpd.c
--- linux.vanilla/drivers/net/sk98lin/skvpd.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/skvpd.c	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,1198 @@
+/******************************************************************************
+ *
+ * Name:	skvpd.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.24 $
+ * Date:	$Date: 1999/03/11 14:25:49 $
+ * Purpose:	Shared software to read and write VPD data
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skge.c" for further 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 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skvpd.c,v $
+ *	Revision 1.24  1999/03/11 14:25:49  malthoff
+ *	Replace __STDC__ with SK_KR_PROTO.
+ *	
+ *	Revision 1.23  1999/01/11 15:13:11  gklug
+ *	fix: syntax error
+ *	
+ *	Revision 1.22  1998/10/30 06:41:15  gklug
+ *	rmv: WARNING
+ *	
+ *	Revision 1.21  1998/10/29 07:15:14  gklug
+ *	fix: Write Stream function needs verify.
+ *	
+ *	Revision 1.20  1998/10/28 18:05:08  gklug
+ *	chg: no DEBUG in VpdMayWrite
+ *	
+ *	Revision 1.19  1998/10/28 15:56:11  gklug
+ *	fix: Return len at end of ReadStream
+ *	fix: Write even less than 4 bytes correctly
+ *	
+ *	Revision 1.18  1998/10/28 09:00:47  gklug
+ *	fix: unreferenced local vars
+ *	
+ *	Revision 1.17  1998/10/28 08:25:45  gklug
+ *	fix: WARNING
+ *	
+ *	Revision 1.16  1998/10/28 08:17:30  gklug
+ *	fix: typo
+ *	
+ *	Revision 1.15  1998/10/28 07:50:32  gklug
+ *	fix: typo
+ *	
+ *	Revision 1.14  1998/10/28 07:20:38  gklug
+ *	chg: Interface functions to use IoC as parameter as well
+ *	fix: VpdRead/WriteDWord now return SK_U32
+ *	chg: VPD_IN/OUT names conform to SK_IN/OUT
+ *	add: usage of VPD_IN/OUT8 macros
+ *	add: VpdRead/Write Stream functions to r/w a stream of data
+ *	fix: VpdTransferBlock swapped illeagal
+ *	add: VpdMayWrite
+ *	
+ *	Revision 1.13  1998/10/22 10:02:37  gklug
+ *	fix: SysKonnectFileId typo
+ *	
+ *	Revision 1.12  1998/10/20 10:01:01  gklug
+ *	fix: parameter to SkOsGetTime
+ *	
+ *	Revision 1.11  1998/10/15 12:51:48  malthoff
+ *	Remove unrequired parameter p in vpd_setup_para().
+ *	
+ *	Revision 1.10  1998/10/08 14:52:43  malthoff
+ *	Remove CvsId by SysKonnectFileId.
+ *	
+ *	Revision 1.9  1998/09/16 07:33:52  malthoff
+ *	remove memcmp() by SK_MEMCMP and
+ *	memcpy() by SK_MEMCPY() to be
+ *	independant from the 'C' Standard Library.
+ *	
+ *	Revision 1.8  1998/08/19 12:52:35  malthoff
+ *	compiler fix: use SK_VPD_KEY instead of S_VPD.
+ *	
+ *	Revision 1.7  1998/08/19 08:14:01  gklug
+ *	fix: remove struct keyword as much as possible from the c-code (see CCC)
+ *	
+ *	Revision 1.6  1998/08/18 13:03:58  gklug
+ *	SkOsGetTime now returns SK_U64
+ *	
+ *	Revision 1.5  1998/08/18 08:17:29  malthoff
+ *	Ensure we issue a VPD read in vpd_read_dword().
+ *	Discard all VPD keywords other than Vx or Yx, where
+ *	x is '0..9' or 'A..Z'.
+ *	
+ *	Revision 1.4  1998/07/03 14:52:19  malthoff
+ *	Add category SK_DBGCAT_FATAL to some debug macros.
+ *	bug fix: correct the keyword name check in vpd_write().
+ *	
+ *	Revision 1.3  1998/06/26 11:16:53  malthoff
+ *	Correct the modified File Identifier.
+ *	
+ *	Revision 1.2  1998/06/26 11:13:43  malthoff
+ *	Modify the File Identifier.
+ *	
+ *	Revision 1.1  1998/06/19 14:11:08  malthoff
+ *	Created, Tests with AIX were performed successfully
+ *	
+ *
+ ******************************************************************************/
+
+/*
+	Please refer skvpd.txt for infomation how to include this module
+ */
+static const char SysKonnectFileId[] =
+	"@(#)$Id: skvpd.c,v 1.24 1999/03/11 14:25:49 malthoff Exp $ (C) SK" ;
+
+#include "h/skdrv1st.h"
+#include "h/sktypes.h"
+#include "h/skdebug.h"
+#include "h/skdrv2nd.h"
+
+/*
+ * Static functions
+ */
+#ifndef SK_KR_PROTO
+static SK_VPD_PARA	*vpd_find_para(
+	SK_AC	*pAC,
+	char		*key,
+	SK_VPD_PARA *p) ;
+#else	/* SK_KR_PROTO */
+static SK_VPD_PARA	*vpd_find_para() ;
+#endif	/* SK_KR_PROTO */
+
+/*
+ * waits for a completetion of a VPD transfer
+ * The VPD transfer must complete within SK_TICKS_PER_SEC/16
+ *
+ * returns	0:	success, transfer completes
+ *		error	exit(9) with a error message
+ */
+static int	VpdWait(
+SK_AC		*pAC,	/* Adapters context */
+SK_IOC		IoC,	/* IO Context */
+int		event)	/* event to wait for (VPD_READ / VPD_write) completion*/
+{
+	SK_U64	start_time ;
+	SK_U16	state ;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
+		("vpd wait for %s\n",event?"Write":"Read")) ;
+	start_time = SkOsGetTime(pAC) ;
+	do {
+		if (SkOsGetTime(pAC) - start_time > SK_TICKS_PER_SEC/16) {
+			VPD_STOP(pAC,IoC) ;
+			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,
+				SK_DBGCAT_FATAL|SK_DBGCAT_ERR,
+				("ERROR:vpd wait timeout\n")) ;
+			return(1) ;
+		}
+		VPD_IN16(pAC,IoC,PCI_VPD_ADR_REG,&state) ;
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
+			("state = %x, event %x\n",state,event)) ;
+	} while((int)(state & PCI_VPD_FLAG) == event) ;
+
+	return(0) ;
+}
+
+
+/*
+ * Read the dword at address 'addr' from the VPD EEPROM.
+ *
+ * Needed Time:	MIN 1,3 ms	MAX 2,6 ms
+ *
+ * Note: The DWord is returned in the endianess of the machine the routine
+ *       is running on.
+ *
+ * Returns the data read.
+ */
+SK_U32		VpdReadDWord(
+SK_AC		*pAC,	/* Adapters context */
+SK_IOC		IoC,	/* IO Context */
+int		addr)	/* VPD address */
+{
+	SK_U32	Rtv ;
+
+	/* start VPD read */
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
+		("vpd read dword at 0x%x\n",addr)) ;
+	addr &= ~VPD_WRITE ;		/* ensure the R/W bit is set to read */
+
+	VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, (SK_U16) addr) ;
+
+	/* ignore return code here */
+	(void)VpdWait(pAC,IoC,VPD_READ) ;
+
+	/* Don't swap here, it's a data stream of bytes */
+	Rtv = 0 ;
+
+	VPD_IN32(pAC,IoC,PCI_VPD_DAT_REG,&Rtv) ;
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
+		("vpd read dword data = 0x%x\n",Rtv)) ;
+	return (Rtv) ;
+}
+
+/*
+	Write the dword 'data' at address 'addr' into the VPD EEPROM, and
+	verify that the data is written.
+
+ Needed Time:
+
+.				MIN		MAX
+. -------------------------------------------------------------------
+. write				1.8 ms		3.6 ms
+. internal write cyles		0.7 ms		7.0 ms
+. -------------------------------------------------------------------
+. over all program time	 	2.5 ms		10.6 ms
+. read				1.3 ms		2.6 ms
+. -------------------------------------------------------------------
+. over all 			3.8 ms		13.2 ms
+.
+
+
+ Returns	0:	success
+		1:	error,	I2C transfer does not terminate
+		2:	error,	data verify error
+
+ */
+static int	VpdWriteDWord(
+SK_AC		*pAC,	/* pAC pointer */
+SK_IOC		IoC,	/* IO Context */
+int		addr,	/* VPD address */
+SK_U32		data)	/* VPD data to write */
+{
+	/* start VPD write */
+	/* Don't swap here, it's a data stream of bytes */
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
+		("vpd write dword at addr 0x%x, data = 0x%x\n",addr,data)) ;
+	VPD_OUT32(pAC,IoC,PCI_VPD_DAT_REG, (SK_U32)data) ;
+	/* But do it here */
+	addr |= VPD_WRITE ;
+
+	VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, (SK_U16)(addr | VPD_WRITE)) ;
+
+	/* this may take up to 10,6 ms */
+	if (VpdWait(pAC,IoC,VPD_WRITE)) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+			("Write Timed Out\n")) ;
+		return(1) ;
+	} ;
+
+	/* verify data */
+	if (VpdReadDWord(pAC,IoC,addr) != data) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR|SK_DBGCAT_FATAL,
+			("Data Verify Error\n")) ;
+		return(2) ;
+	}
+	return(0) ;
+}
+
+/*
+ *	Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
+ *	or to the I2C EEPROM.
+ *
+ * Returns number of bytes read / written.
+ */
+static int	VpdWriteStream(
+SK_AC		*pAC,	/* Adapters context */
+SK_IOC		IoC,	/* IO Context */
+char		*buf,	/* data buffer */
+int		Addr,	/* VPD start address */
+int		Len)	/* number of bytes to read / to write */
+{
+	int		i ;
+	int		j ;
+	SK_U16		AdrReg ;
+	int		Rtv ;
+	SK_U8		* pComp;	/* Compare pointer */
+	SK_U8		Data ;		/* Input Data for Compare */
+
+	/* Init Compare Pointer */
+	pComp = (SK_U8 *) buf;
+
+	for (i=0; i < Len; i ++, buf++) {
+		if ((i%sizeof(SK_U32)) == 0) {
+			/*
+			 * At the begin of each cycle read the Data Reg
+			 * So it is initialized even if only a few bytes
+			 * are written.
+			 */
+			AdrReg = (SK_U16) Addr ;
+			AdrReg &= ~VPD_WRITE ;	/* READ operation */
+
+			VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ;
+
+			/* ignore return code here */
+			Rtv = VpdWait(pAC,IoC,VPD_READ) ;
+			if (Rtv != 0) {
+				return(i) ;
+			}
+		}
+
+		/* Write current Byte */
+		VPD_OUT8(pAC,IoC,PCI_VPD_DAT_REG+(i%sizeof(SK_U32)),
+				*(SK_U8*)buf) ;
+
+		if (((i%sizeof(SK_U32)) == 3) || (i == (Len - 1))) {
+			/* New Address needs to be written to VPD_ADDR reg */
+			AdrReg = (SK_U16) Addr ;
+			Addr += sizeof(SK_U32);
+			AdrReg |= VPD_WRITE ;	/* WRITE operation */
+
+			VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ;
+
+			/* Wait for termination */
+			Rtv = VpdWait(pAC,IoC,VPD_WRITE) ;
+			if (Rtv != 0) {
+				SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+					("Write Timed Out\n")) ;
+				return(i - (i%sizeof(SK_U32))) ;
+			}
+
+			/*
+			 * Now re-read to verify
+			 */
+			AdrReg &= ~VPD_WRITE ;	/* READ operation */
+
+			VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ;
+
+			/* Wait for termination */
+			Rtv = VpdWait(pAC,IoC,VPD_READ) ;
+			if (Rtv != 0) {
+				SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+					("Verify Timed Out\n")) ;
+				return(i - (i%sizeof(SK_U32))) ;
+			}
+
+			for (j = 0; j <= (int) (i%sizeof(SK_U32));
+				j ++, pComp ++ ) {
+				VPD_IN8(pAC,IoC,PCI_VPD_DAT_REG+j, &Data) ;
+				if (Data != *pComp) {
+					/* Verify Error */
+					SK_DBG_MSG(pAC,SK_DBGMOD_VPD,
+						SK_DBGCAT_ERR,
+						("WriteStream Verify Error\n"));
+					return(i - (i%sizeof(SK_U32)) + j);
+				}
+			}
+
+		}
+	}
+
+	return(Len);
+}
+	
+
+/*
+ *	Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
+ *	or to the I2C EEPROM.
+ *
+ * Returns number of bytes read / written.
+ */
+static int	VpdReadStream(
+SK_AC		*pAC,	/* Adapters context */
+SK_IOC		IoC,	/* IO Context */
+char		*buf,	/* data buffer */
+int		Addr,	/* VPD start address */
+int		Len)	/* number of bytes to read / to write */
+{
+	int		i ;
+	SK_U16		AdrReg ;
+	int		Rtv ;
+
+	for (i=0; i < Len; i ++, buf++) {
+		if ((i%sizeof(SK_U32)) == 0) {
+			/* New Address needs to be written to VPD_ADDR reg */
+			AdrReg = (SK_U16) Addr ;
+			Addr += sizeof(SK_U32);
+			AdrReg &= ~VPD_WRITE ;	/* READ operation */
+
+			VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ;
+
+			/* ignore return code here */
+			Rtv = VpdWait(pAC,IoC,VPD_READ) ;
+			if (Rtv != 0) {
+				return(i) ;
+			}
+
+		}
+		VPD_IN8(pAC,IoC,PCI_VPD_DAT_REG+(i%sizeof(SK_U32)),
+			(SK_U8 *)buf) ;
+	}
+
+	return(Len) ;
+}
+
+/*
+ *	Read ore wirtes 'len' bytes of VPD data, starting at 'addr' from
+ *	or to the I2C EEPROM.
+ *
+ * Returns number of bytes read / written.
+ */
+static int	VpdTransferBlock(
+SK_AC		*pAC,	/* Adapters context */
+SK_IOC		IoC,	/* IO Context */
+char		*buf,	/* data buffer */
+int		addr,	/* VPD start address */
+int		len,	/* number of bytes to read / to write */
+int		dir)	/* transfer direction may be VPD_READ or VPD_WRITE */
+{
+	int		Rtv ;	/* Return value */
+	int		vpd_rom_size ;
+	SK_U32		our_reg2 ;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
+		("vpd %s block, addr = 0x%x, len = %d\n",
+		dir?"write":"read",addr,len)) ;
+
+	if (len == 0)
+		return (0) ;
+
+	VPD_IN32(pAC,IoC,PCI_OUR_REG_2,&our_reg2) ;
+	vpd_rom_size = 256 << ((our_reg2 & PCI_VPD_ROM_SZ) >> 14);
+	if (addr > vpd_rom_size - 4) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR|SK_DBGCAT_FATAL,
+			("Address error: 0x%x, exp. < 0x%x\n",
+			addr, vpd_rom_size - 4)) ;
+		return (0) ;
+	}
+	if (addr + len > vpd_rom_size) {
+		len = vpd_rom_size - addr ;
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+			("Warning: len was cut to %d\n",len)) ;
+	}
+
+	if (dir == VPD_READ) {
+		Rtv = VpdReadStream(pAC, IoC, buf, addr, len);
+	} else {
+		Rtv = VpdWriteStream(pAC, IoC, buf, addr, len);
+	}
+
+	return (Rtv) ;
+}
+
+#ifdef SKDIAG
+
+/*
+ *	Read 'len' bytes of VPD data, starting at 'addr'.
+ *
+ * Returns number of bytes read.
+ */
+int		VpdReadBlock(
+SK_AC		*pAC,	/* pAC pointer */
+SK_IOC		IoC,	/* IO Context */
+char		*buf,	/* buffer were the data should be stored */
+int		addr,	/* start reading at the VPD address */
+int		len)	/* number of bytes to read */
+{
+	return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_READ)) ;
+}
+
+/*
+ *	Write 'len' bytes of *but to the VPD EEPROM, starting at 'addr'.
+ *
+ * Returns number of bytes writes.
+ */
+int		VpdWriteBlock(
+SK_AC		*pAC,	/* pAC pointer */
+SK_IOC		IoC,	/* IO Context */
+char		*buf,	/* buffer, holds the data to write */
+int		addr,	/* start writing at the VPD address */
+int		len)	/* number of bytes to write */
+{
+	return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_WRITE)) ;
+}
+#endif	/* SKDIAG */
+
+/*
+ * (re)initialize the VPD buffer
+ *
+ * Reads the VPD data from the EEPROM into the VPD buffer.
+ * Get the remaining read only and read / write space.
+ *
+ * return	0:	success
+ *		1:	fatal VPD error
+ */
+static int	VpdInit(
+SK_AC		*pAC,	/* Adapters context */
+SK_IOC		IoC)	/* IO Context */
+{
+	SK_VPD_PARA *r, rp ;	/* RW or RV */
+	int		i ;
+	unsigned char	x ;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_INIT,("VpdInit .. ")) ;
+	/* read the VPD data into the VPD buffer */
+	if (VpdTransferBlock(pAC,IoC,pAC->vpd.vpd_buf,0,VPD_SIZE,VPD_READ)
+		!= VPD_SIZE) {
+
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+			("Block Read Error\n")) ;
+		return(1) ;
+	}
+
+	/* find the end tag of the RO area */
+	if (!(r = vpd_find_para(pAC,VPD_RV,&rp))) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Encoding Error: RV Tag not found\n")) ;
+		return (1) ;
+	}
+	if (r->p_val + r->p_len > pAC->vpd.vpd_buf + VPD_SIZE/2) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Encoding Error: Invalid VPD struct size\n")) ;
+		return (1) ;
+	}
+	pAC->vpd.v.vpd_free_ro = r->p_len - 1 ;
+
+	/* test the checksum */
+	for (i = 0, x = 0; (unsigned)i<=(unsigned)VPD_SIZE/2 - r->p_len; i++) {
+		x += pAC->vpd.vpd_buf[i] ;
+	}
+	if (x != 0) {
+		/* checksum error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("VPD Checksum Error\n")) ;
+		return (1) ;
+	}
+
+	/* find and check the end tag of the RW area */
+	if (!(r = vpd_find_para(pAC,VPD_RW,&rp))) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Encoding Error: RV Tag not found\n")) ;
+		return (1) ;
+	}
+	if (r->p_val < pAC->vpd.vpd_buf + VPD_SIZE/2) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Encoding Error: Invalid VPD struct size\n")) ;
+		return (1) ;
+	}
+	pAC->vpd.v.vpd_free_rw = r->p_len ;
+
+	/* everything seems to be ok */
+	pAC->vpd.v.vpd_status |= VPD_VALID ;
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_INIT,
+		("done. Free RO = %d, Free RW = %d\n",
+		pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)) ;
+
+	return(0) ;
+}
+
+/*
+ *	find the Keyword 'key' in the VPD buffer and fills the
+ *	parameter sturct 'p' with it's values
+ *
+ * returns	*p	success
+ *		0:	parameter was not found or VPD encoding error
+ */
+static SK_VPD_PARA *vpd_find_para(
+SK_AC *pAC,	/* common data base */
+char *key,		/* keyword to find (e.g. "MN") */
+SK_VPD_PARA *p)	/* parameter description struct */
+{
+	char *v	;	/* points to vpd buffer */
+	int max ;	/* Maximum Number of Iterations */
+
+	v = pAC->vpd.vpd_buf ;
+	max = 128 ;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
+		("vpd find para %s .. ",key)) ;
+
+	/* check mandatory resource type ID string (Product Name) */
+	if (*v != (char) RES_ID) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Error: 0x%x missing\n",RES_ID)) ;
+		return (0) ;
+	}
+
+	if (strcmp(key,VPD_NAME) == 0) {
+		p->p_len = VPD_GET_RES_LEN(v) ;
+		p->p_val = VPD_GET_VAL(v) ;
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
+			("found, len = %d\n",p->p_len)) ;
+		return(p) ;
+	}
+
+	v += 3 + VPD_GET_RES_LEN(v) + 3 ;
+	for ( ; ; ) {
+		if (SK_MEMCMP(key,v,2) == 0) {
+			p->p_len = VPD_GET_VPD_LEN(v) ;
+			p->p_val = VPD_GET_VAL(v) ;
+			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
+				("found, len = %d\n",p->p_len)) ;
+			return (p) ;
+		}
+
+		/* exit when reaching the "RW" Tag or the maximum of itera. */
+		max-- ;
+		if (SK_MEMCMP(VPD_RW,v,2) == 0 || max == 0) {
+			break ;
+		}
+
+		if (SK_MEMCMP(VPD_RV,v,2) == 0) {
+			v += 3 + VPD_GET_VPD_LEN(v) + 3 ;	/* skip VPD-W */
+		} else {
+			v += 3 + VPD_GET_VPD_LEN(v) ;
+		}
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
+			("scanning '%c%c' len = %d\n",v[0],v[1],v[2])) ;
+	}
+
+#ifdef DEBUG
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,("not found\n")) ;
+	if (max == 0) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Key/Len Encoding error\n")) ;
+	}
+#endif
+	return (0) ;
+}
+
+/*
+ *	Move 'n' bytes. Begin with the last byte if 'n' is > 0,
+ *	Start with the last byte if n is < 0.
+ *
+ * returns nothing
+ */
+static void vpd_move_para(
+char *start,		/* start of memory block */
+char *end,		/* end of memory block to move */
+int n)			/* number of bytes the memory block has to be moved */
+{
+	char *p ;
+	int i ;		/* number of byte copied */
+
+	if (n == 0)
+		return ;
+
+	i = end - start + 1 ;
+	if (n < 0) {
+		p = start + n ;
+		while (i != 0) {
+			*p++ = *start++ ;
+			i-- ;
+		}
+	} else {
+		p = end + n ;
+		while (i != 0) {
+			*p-- = *end-- ;
+			i-- ;
+		}
+	}
+}
+
+/*
+ *	setup the VPD keyword 'key' at 'ip'.
+ *
+ * returns nothing
+ */
+static void vpd_insert_key(
+char *key,		/* keyword to insert */
+char *buf,		/* buffer with the keyword value */
+int len,		/* length of the value string */
+char *ip)		/* inseration point */
+{
+	SK_VPD_KEY *p ;
+
+	p = (SK_VPD_KEY *) ip ;
+	p->p_key[0] = key[0] ;
+	p->p_key[1] = key[1] ;
+	p->p_len = (unsigned char) len ;
+	SK_MEMCPY(&p->p_val,buf,len) ;
+}
+
+/*
+ *	Setup the VPD end tag "RV" / "RW".
+ *	Also correct the remaining space variables vpd_free_ro / vpd_free_rw.
+ *
+ * returns	0:	success
+ *		1:	encoding error
+ */
+static int vpd_mod_endtag(
+SK_AC *pAC,	/* common data base */
+char *etp)		/* end pointer input position */
+{
+	SK_VPD_KEY *p ;
+	unsigned char	x ;
+	int	i ;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
+		("vpd modify endtag at 0x%x = '%c%c'\n",etp,etp[0],etp[1])) ;
+
+	p = (SK_VPD_KEY *) etp ;
+
+	if (p->p_key[0] != 'R' || (p->p_key[1] != 'V' && p->p_key[1] != 'W')) {
+		/* something wrong here, encoding error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Encoding Error: invalid end tag\n")) ;
+		return(1) ;
+	}
+	if (etp > pAC->vpd.vpd_buf + VPD_SIZE/2) {
+		/* create "RW" tag */
+		p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE-etp-3-1) ;
+		pAC->vpd.v.vpd_free_rw = (int) p->p_len ;
+		i = pAC->vpd.v.vpd_free_rw ;
+		etp += 3 ;
+	} else {
+		/* create "RV" tag */
+		p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE/2-etp-3) ;
+		pAC->vpd.v.vpd_free_ro = (int) p->p_len - 1 ;
+
+		/* setup checksum */
+		for (i = 0, x = 0; i < VPD_SIZE/2 - p->p_len; i++) {
+			x += pAC->vpd.vpd_buf[i] ;
+		}
+		p->p_val = (char) 0 - x ;
+		i = pAC->vpd.v.vpd_free_ro ;
+		etp += 4 ;
+	}
+	while (i) {
+		*etp++ = 0x00 ;
+		i-- ;
+	}
+
+	return (0) ;
+}
+
+/*
+ *	Insert a VPD keyword into the VPD buffer.
+ *
+ *	The keyword 'key' is inserted at the position 'ip' in the
+ *	VPD buffer.
+ *	The keywords behind the input position will
+ *	be moved. The VPD end tag "RV" or "RW" is generated again.
+ *
+ * returns	0:	success
+ *		2:	value string was cut
+ *		4:	VPD full, keyword was not written
+ *		6:	fatal VPD error
+ *
+ */
+int	VpdSetupPara(
+SK_AC	*pAC,		/* common data base */
+char	*key,		/* keyword to insert */
+char	*buf,		/* buffer with the keyword value */
+int	len,		/* length of the keyword value */
+int	type,		/* VPD_RO_KEY or VPD_RW_KEY */
+int	op)			/* operation to do: ADD_KEY or OWR_KEY */
+{
+	SK_VPD_PARA vp ;
+	char	*etp ;		/* end tag position */
+	int	free ;		/* remaining space in selected area */
+	char	*ip ;		/* input position inside the VPD buffer */
+	int	rtv ;		/* return code */
+	int	head ;		/* additional haeder bytes to move */
+	int	found ;		/* additinoal bytes if the keyword was found */
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
+		("vpd setup para key = %s, val = %s\n",key,buf)) ;
+
+	rtv = 0 ;
+	ip = 0 ;
+	if (type == VPD_RW_KEY) {
+		/* end tag is "RW" */
+		free = pAC->vpd.v.vpd_free_rw ;
+		etp = pAC->vpd.vpd_buf + (VPD_SIZE - free - 1 - 3) ;
+	} else {
+		/* end tag is "RV" */
+		free = pAC->vpd.v.vpd_free_ro ;
+		etp = pAC->vpd.vpd_buf + (VPD_SIZE/2 - free - 4) ;
+	}
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
+		("Free RO = %d, Free RW = %d\n",
+		pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)) ;
+
+	head = 0 ;
+	found = 0 ;
+	if (op == OWR_KEY) {
+		if (vpd_find_para(pAC,key,&vp)) {
+			found = 3 ;
+			ip = vp.p_val - 3 ;
+			free += vp.p_len + 3 ;
+			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
+				("Overwrite Key\n")) ;
+		} else {
+			op = ADD_KEY ;
+			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
+				("Add Key\n")) ;
+		}
+	}
+	if (op == ADD_KEY) {
+		ip = etp ;
+		vp.p_len = 0 ;
+		head = 3 ;
+	}
+
+	if (len + 3 > free) {
+		if (free < 7) {
+			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+				("VPD Buffer Overflow, keyword not written\n"));
+			return (4) ;
+		}
+		/* cut it again */
+		len = free - 3 ;
+		rtv = 2 ;
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+			("VPD Buffer Full, Keyword was cut\n")) ;
+	}
+
+	vpd_move_para(ip + vp.p_len + found, etp+2, len-vp.p_len+head) ;
+	vpd_insert_key(key, buf, len, ip) ;
+	if (vpd_mod_endtag(pAC, etp + len - vp.p_len + head)) {
+		pAC->vpd.v.vpd_status &= ~VPD_VALID ;
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+			("VPD Encoding Error\n")) ;
+		return(6) ;
+	}
+
+	return (rtv) ;
+}
+
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the
+ *	VPD buffer if not already done.
+ *
+ * return:	A pointer to the vpd_status structure. The structure contain
+ *		this fields.
+ */
+SK_VPD_STATUS	*VpdStat(
+SK_AC		*pAC,	/* Adapters context */
+SK_IOC		IoC)	/* IO Context */
+{
+	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
+		(void)VpdInit(pAC,IoC) ;
+	}
+	return(&pAC->vpd.v) ;
+}
+
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the VPD
+ *	buffer if not already done.
+ *	Scan the VPD buffer for VPD keywords and create the VPD
+ *	keyword list by copying the keywords to 'buf', all after
+ *	each other and terminated with a '\0'.
+ *
+ * Exceptions:	o The Resource Type ID String (product name) is called "Name"
+ *		o The VPD end tags 'RV' and 'RW' are not listed
+ *
+ *	The number of copied keywords is counted in 'elements'.
+ *
+ * returns	0:	success
+ *		2:	buffer overfull, one or more keywords are missing
+ *		6:	fatal VPD error
+ *
+ *	example values after returning:
+ *
+ *		buf =	"Name\0PN\0EC\0MN\0SN\0CP\0VF\0VL\0YA\0"
+ *		*len =		30
+ *		*elements =	 9
+ */
+int		VpdKeys(
+SK_AC		*pAC,		/* common data base */
+SK_IOC		IoC,		/* IO Context */
+char		*buf,		/* buffer where to copy the keywords */
+int		*len,		/* buffer length */
+int		*elements)	/* number of keywords returned */
+{
+	char *v ;
+	int n ;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("list vpd keys .. ")) ;
+	*elements = 0 ;
+	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
+		if (VpdInit(pAC,IoC) != 0 ) {
+			*len = 0 ;
+			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+				("VPD Init Error, terminated\n")) ;
+			return(6) ;
+		}
+	}
+
+	if ((signed)strlen(VPD_NAME) + 1 <= *len) {
+		v = pAC->vpd.vpd_buf ;
+		strcpy(buf,VPD_NAME) ;
+		n = strlen(VPD_NAME) + 1 ;
+		buf += n ;
+		*elements = 1 ;
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,
+			("'%c%c' ",v[0],v[1])) ;
+	} else {
+		*len = 0 ;
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+			("buffer overflow\n")) ;
+		return(2) ;
+	}
+
+	v += 3 + VPD_GET_RES_LEN(v) + 3 ;
+	for ( ; ; ) {
+		/* exit when reaching the "RW" Tag */
+		if (SK_MEMCMP(VPD_RW,v,2) == 0) {
+			break ;
+		}
+
+		if (SK_MEMCMP(VPD_RV,v,2) == 0) {
+			v += 3 + VPD_GET_VPD_LEN(v) + 3 ;	/* skip VPD-W */
+			continue ;
+		}
+
+		if (n+3 <= *len) {
+			SK_MEMCPY(buf,v,2) ;
+			buf += 2 ;
+			*buf++ = '\0' ;
+			n += 3 ;
+			v += 3 + VPD_GET_VPD_LEN(v) ;
+			*elements += 1 ;
+			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,
+				("'%c%c' ",v[0],v[1])) ;
+		} else {
+			*len = n ;
+			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+				("buffer overflow\n")) ;
+			return (2) ;
+		}
+	}
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("\n")) ;
+	*len = n ;
+	return(0) ;
+}
+
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the
+ *	VPD buffer if not already done. Search for the VPD keyword
+ *	'key' and copy its value to 'buf'. Add a terminating '\0'.
+ *	If the value does not fit into the buffer cut it after
+ *	'len' - 1 bytes.
+ *
+ * returns	0:	success
+ *		1:	keyword not found
+ *		2:	value string was cut
+ *		3:	VPD transfer timeout
+ *		6:	fatal VPD error
+ */
+int		VpdRead(
+SK_AC		*pAC,	/* common data base */
+SK_IOC		IoC,	/* IO Context */
+char		*key,	/* keyword to read (e.g. "MN") */
+char		*buf,	/* buffer where to copy the keyword value */
+int		*len)	/* buffer length */
+{
+	SK_VPD_PARA *p, vp ;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("vpd read %s .. ",key)) ;
+	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
+		if (VpdInit(pAC,IoC) != 0 ) {
+			*len = 0 ;
+			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+				("vpd init error\n")) ;
+			return(6) ;
+		}
+	}
+
+	if ((p = vpd_find_para(pAC,key,&vp))) {
+		if (p->p_len > (*(unsigned *)len)-1) {
+			p->p_len = *len - 1 ;
+		}
+		SK_MEMCPY(buf,p->p_val,p->p_len) ;
+		buf[p->p_len] = '\0' ;
+		*len = p->p_len ;
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,
+			("%c%c%c%c.., len = %d\n",
+			buf[0],buf[1],buf[2],buf[3],*len)) ;
+	} else {
+		*len = 0 ;
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,("not found\n")) ;
+		return (1) ;
+	}
+	return (0) ;
+}
+
+
+/*
+ *	Check whether a given key may be written
+ *
+ * returns
+ *	SK_TRUE		Yes it may be written
+ *	SK_FALSE	No it may be written
+ */
+SK_BOOL		VpdMayWrite(
+char		*key)	/* keyword to write (allowed values "Yx", "Vx") */
+{
+	if ((*key != 'Y' && *key != 'V') ||
+		key[1] < '0' || key[1] > 'Z' ||
+		(key[1] > '9' && key[1] < 'A') || strlen(key) != 2) {
+
+		return (SK_FALSE) ;
+	}
+	return (SK_TRUE) ;
+}
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the VPD
+ *	buffer if not already done. Insert/overwrite the keyword 'key'
+ *	in the VPD buffer. Cut the keyword value if it does not fit
+ *	into the VPD read / write area.
+ *
+ * returns	0:	success
+ *		2:	value string was cut
+ *		3:	VPD transfer timeout
+ *		4:	VPD full, keyword was not written
+ *		5:	keyword cannot be written
+ *		6:	fatal VPD error
+ */
+int		VpdWrite(
+SK_AC		*pAC,	/* common data base */
+SK_IOC		IoC,	/* IO Context */
+char		*key,	/* keyword to write (allowed values "Yx", "Vx") */
+char		*buf)	/* buffer where the keyword value can be read from */
+{
+	int len ;			/* lenght of the keyword to write */
+	int rtv ;			/* return code */
+	int rtv2 ;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,
+		("vpd write %s = %s\n",key,buf)) ;
+
+	if ((*key != 'Y' && *key != 'V') ||
+		key[1] < '0' || key[1] > 'Z' ||
+		(key[1] > '9' && key[1] < 'A') || strlen(key) != 2) {
+
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+			("illegal key tag, keyword not written\n")) ;
+		return (5) ;
+	}
+
+	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
+		if (VpdInit(pAC,IoC) != 0 ) {
+			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+				("vpd init error\n")) ;
+			return(6) ;
+		}
+	}
+
+	rtv = 0 ;
+	len = strlen(buf) ;
+	if (len > VPD_MAX_LEN) {
+		/* cut it */
+		len = VPD_MAX_LEN ;
+		rtv = 2 ;
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+			("keyword to long, cut after %d bytes\n",VPD_MAX_LEN)) ;
+	}
+	if ((rtv2 = VpdSetupPara(pAC,key,buf,len,VPD_RW_KEY,OWR_KEY)) != 0) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+			("vpd write error\n")) ;
+		return(rtv2) ;
+	}
+
+	return (rtv) ;
+}
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the
+ *	VPD buffer if not already done. Remove the VPD keyword
+ *	'key' from the VPD buffer.
+ *	Only the keywords in the read/write area can be deleted.
+ *	Keywords in the read only area cannot be deleted.
+ *
+ * returns	0:	success, keyword was removed
+ *		1:	keyword not found
+ *		5:	keyword cannot be deleted
+ *		6:	fatal VPD error
+ */
+int		VpdDelete(
+SK_AC		*pAC,	/* common data base */
+SK_IOC		IoC,	/* IO Context */
+char		*key)	/* keyword to read (e.g. "MN") */
+{
+	SK_VPD_PARA *p, vp ;
+	char *etp ;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd delete key %s\n",key)) ;
+	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
+		if (VpdInit(pAC,IoC) != 0 ) {
+			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+				("vpd init error\n")) ;
+			return(6) ;
+		}
+	}
+
+	if ((p = vpd_find_para(pAC,key,&vp))) {
+		if (p->p_val < pAC->vpd.vpd_buf + VPD_SIZE/2) {
+			/* try to delete read only keyword */
+			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+				("cannot delete RO keyword\n")) ;
+			return (5) ;
+		}
+
+		etp = pAC->vpd.vpd_buf + (VPD_SIZE-pAC->vpd.v.vpd_free_rw-1-3) ;
+
+		vpd_move_para(vp.p_val+vp.p_len, etp+2,
+			- ((int)(vp.p_len + 3))) ;
+		if (vpd_mod_endtag(pAC, etp - vp.p_len - 3)) {
+			pAC->vpd.v.vpd_status &= ~VPD_VALID ;
+			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+				("vpd encoding error\n")) ;
+			return(6) ;
+		}
+	} else {
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+			("keyword not found\n")) ;
+		return (1) ;
+	}
+
+	return (0) ;
+}
+
+/*
+ *	If the VPD buffer contains valid data write the VPD
+ *	read/write area back to the VPD EEPROM.
+ *
+ * returns	0:	success
+ *		3:	VPD transfer timeout
+ */
+int		VpdUpdate(
+SK_AC		*pAC,	/* Adapters context */
+SK_IOC		IoC)	/* IO Context */
+{
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd update .. ")) ;
+	if (pAC->vpd.v.vpd_status & VPD_VALID) {
+		if (VpdTransferBlock(pAC,IoC,pAC->vpd.vpd_buf + VPD_SIZE/2,
+			VPD_SIZE/2, VPD_SIZE/2, VPD_WRITE) != VPD_SIZE/2) {
+
+			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+				("transfer timed out\n")) ;
+			return(3) ;
+		}
+	}
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("done\n")) ;
+	return (0) ;
+}
+
+
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the VPD buffer
+ *	if not already done. If the keyword "VF" is not present it will be
+ *	created and the error log message will be stored to this keyword.
+ *	If "VF" is not present the error log message will be stored to the
+ *	keyword "VL". "VL" will created or overwritten if "VF" is present.
+ *	The VPD read/write area is saved to the VPD EEPROM.
+ *
+ * returns nothing, errors will be ignored.
+ */
+void		VpdErrLog(
+SK_AC		*pAC,	/* common data base */
+SK_IOC		IoC,	/* IO Context */
+char		*msg)	/* error log message */
+{
+	SK_VPD_PARA *v, vf ;	/* VF */
+	int len ;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,
+		("vpd error log msg %s\n",msg)) ;
+	if (!(pAC->vpd.v.vpd_status & VPD_VALID)) {
+		if (VpdInit(pAC,IoC) != 0 ) {
+			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+				("vpd init error\n")) ;
+			return ;
+		}
+	}
+
+	len = strlen(msg) ;
+	if (len > VPD_MAX_LEN) {
+		/* cut it */
+		len = VPD_MAX_LEN ;
+	}
+	if ((v = vpd_find_para(pAC,VPD_VF,&vf))) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("overwrite VL\n")) ;
+		(void)VpdSetupPara(pAC,VPD_VL,msg,len,VPD_RW_KEY,OWR_KEY) ;
+	} else {
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("write VF\n")) ;
+		(void)VpdSetupPara(pAC,VPD_VF,msg,len,VPD_RW_KEY,ADD_KEY) ;
+	}
+
+	(void)VpdUpdate(pAC,IoC) ;
+}
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk98lin/skxmac2.c linux.14p16/drivers/net/sk98lin/skxmac2.c
--- linux.vanilla/drivers/net/sk98lin/skxmac2.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/net/sk98lin/skxmac2.c	Thu Dec  9 15:33:38 1999
@@ -0,0 +1,2047 @@
+/******************************************************************************
+ *
+ * Name:	skxmac2.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.49 $
+ * Date:	$Date: 1999/11/22 08:12:13 $
+ * Purpose:	Contains functions to initialize the XMAC II
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skge.c" for further 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 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skxmac2.c,v $
+ *	Revision 1.49  1999/11/22 08:12:13  malthoff
+ *	Add workaround for power consumption feature of Bcom C0 chip.
+ *	
+ *	Revision 1.48  1999/11/16 08:39:01  malthoff
+ *	Fix: MDIO preamble suppression is port dependend.
+ *	
+ *	Revision 1.47  1999/08/27 08:55:35  malthoff
+ *	1000BT: Optimizing MDIO transfer by oppressing MDIO preamble.
+ *	
+ *	Revision 1.46  1999/08/13 11:01:12  malthoff
+ *	Fix for 1000BT: pFlowCtrlMode was not set correctly.
+ *	
+ *	Revision 1.45  1999/08/12 19:18:28  malthoff
+ *	1000BT Fixes: Do not owerwrite XM_MMU_CMD.
+ *	Do not execute BCOM A1 workaround for B1 chips.
+ *	Fix pause frame setting.
+ *	Always set PHY_B_AC_TX_TST in PHY_BCOM_AUX_CTRL.
+ *	
+ *	Revision 1.44  1999/08/03 15:23:48  cgoos
+ *	Fixed setting of PHY interrupt mask in half duplex mode.
+ *	
+ *	Revision 1.43  1999/08/03 15:22:17  cgoos
+ *	Added some debug output.
+ *	Disabled XMac GP0 interrupt for external PHYs.
+ *	
+ *	Revision 1.42  1999/08/02 08:39:23  malthoff
+ *	BCOM PHY: TX LED: To get the mono flop behaviour it is required
+ *	to set the LED Traffic Mode bit in PHY_BCOM_P_EXT_CTRL.
+ *	
+ *	Revision 1.41  1999/07/30 06:54:31  malthoff
+ *	Add temp. workarounds for the BCOM Phy revision A1.
+ *	
+ *	Revision 1.40  1999/06/01 07:43:26  cgoos
+ *	Changed Link Mode Status in SkXmAutoNegDone... from FULL/HALF to
+ *	AUTOFULL/AUTOHALF.
+ *	
+ *	Revision 1.39  1999/05/19 07:29:51  cgoos
+ *	Changes for 1000Base-T.
+ *	
+ *	Revision 1.38  1999/04/08 14:35:10  malthoff
+ *	Add code for enabling signal detect. Enabling signal
+ *	detect is disabled.
+ *	
+ *	Revision 1.37  1999/03/12 13:42:54  malthoff
+ *	Add: Jumbo Frame Support.
+ *	Add: Receive modes SK_LENERR_OK_ON/OFF and
+ *	SK_BIG_PK_OK_ON/OFF in SkXmSetRxCmd().
+ *	
+ *	Revision 1.36  1999/03/08 10:10:55  gklug
+ *	fix: AutoSensing did switch to next mode even if LiPa indicated offline
+ *
+ *	Revision 1.35  1999/02/22 15:16:41  malthoff
+ *	Remove some compiler warnings.
+ *
+ *	Revision 1.34  1999/01/22 09:19:59  gklug
+ *	fix: Init DupMode and InitPauseMd are now called in RxTxEnable
+ *
+ *	Revision 1.33  1998/12/11 15:19:11  gklug
+ *	chg: lipa autoneg stati
+ *	chg: debug messages
+ *	chg: do NOT use spurious XmIrq
+ *
+ *	Revision 1.32  1998/12/10 11:08:44  malthoff
+ *	bug fix: pAC has been used for IOs in SkXmHardRst().
+ *	SkXmInitPhy() is also called for the Diag in SkXmInitMac().
+ *
+ *	Revision 1.31  1998/12/10 10:39:11  gklug
+ *	fix: do 4 RESETS of the XMAC at the beginning
+ *	fix: dummy read interrupt source register BEFORE initializing the Phy
+ *	add: debug messages
+ *	fix: Linkpartners autoneg capability cannot be shown by TX_PAGE interrupt
+ *
+ *	Revision 1.30  1998/12/07 12:18:32  gklug
+ *	add: refinement of autosense mode: take into account the autoneg cap of LiPa
+ *
+ *	Revision 1.29  1998/12/07 07:12:29  gklug
+ *	fix: if page is received the link is  down.
+ *
+ *	Revision 1.28  1998/12/01 10:12:47  gklug
+ *	chg: if spurious IRQ from XMAC encountered, save it
+ *
+ *	Revision 1.27  1998/11/26 07:33:38  gklug
+ *	add: InitPhy call is now in XmInit function
+ *
+ *	Revision 1.26  1998/11/18 13:38:24  malthoff
+ *	'Imsk' is also unused in SkXmAutoNegDone.
+ *
+ *	Revision 1.25  1998/11/18 13:28:01  malthoff
+ *	Remove unused variable 'Reg' in SkXmAutoNegDone().
+ *
+ *	Revision 1.24  1998/11/18 13:18:45  gklug
+ *	add: workaround for xmac errata #1
+ *	add: detect Link Down also when Link partner requested config
+ *	chg: XMIrq is only used when link is up
+ *
+ *	Revision 1.23  1998/11/04 07:07:04  cgoos
+ *	Added function SkXmRxTxEnable.
+ *
+ *	Revision 1.22  1998/10/30 07:35:54  gklug
+ *	fix: serve LinkDown interrupt when link is already down
+ *
+ *	Revision 1.21  1998/10/29 15:32:03  gklug
+ *	fix: Link Down signaling
+ *
+ *	Revision 1.20  1998/10/29 11:17:27  gklug
+ *	fix: AutoNegDone bug
+ *
+ *	Revision 1.19  1998/10/29 10:14:43  malthoff
+ *	Add endainesss comment for reading/writing MAC addresses.
+ *
+ *	Revision 1.18  1998/10/28 07:48:55  cgoos
+ *	Fix: ASS somtimes signaled although link is up.
+ *
+ *	Revision 1.17  1998/10/26 07:55:39  malthoff
+ *	Fix in SkXmInitPauseMd(): Pause Mode
+ *	was disabled and not enabled.
+ *	Fix in SkXmAutoNegDone(): Checking Mode bits
+ *	always failed, becaues of some missing braces.
+ *
+ *	Revision 1.16  1998/10/22 09:46:52  gklug
+ *	fix SysKonnectFileId typo
+ *
+ *	Revision 1.15  1998/10/21 05:51:37  gklug
+ *	add: para DoLoop to InitPhy function for loopback set-up
+ *
+ *	Revision 1.14  1998/10/16 10:59:23  malthoff
+ *	Remove Lint warning for dummy reads.
+ *
+ *	Revision 1.13  1998/10/15 14:01:20  malthoff
+ *	Fix: SkXmAutoNegDone() is (int) but does not return a value.
+ *
+ *	Revision 1.12  1998/10/14 14:45:04  malthoff
+ *	Remove SKERR_SIRQ_E0xx and SKERR_SIRQ_E0xxMSG by
+ *	SKERR_HWI_Exx and SKERR_HWI_E0xxMSG to be independant
+ *	from the Sirq module.
+ *
+ *	Revision 1.11  1998/10/14 13:59:01  gklug
+ *	add: InitPhy function
+ *
+ *	Revision 1.10  1998/10/14 11:20:57  malthoff
+ *	Make SkXmAutoNegDone() public, because it's
+ *	used in diagnostics, too.
+ *	The Link Up event to the RLMT is issued in
+ *	SkXmIrq(). SkXmIrq() is not available in
+ *	diagnostics. Use PHY_READ when reading
+ *	PHY registers.
+ *
+ *	Revision 1.9  1998/10/14 05:50:10  cgoos
+ *	Added definition for Para.
+ *
+ *	Revision 1.8  1998/10/14 05:41:28  gklug
+ *	add: Xmac IRQ
+ *	add: auto negotiation done function
+ *
+ *	Revision 1.7  1998/10/09 06:55:20  malthoff
+ *	The configuration of the XMACs Tx Request Threshold
+ *	depends from the drivers port usage now. The port
+ *	usage is configured in GIPortUsage.
+ *
+ *	Revision 1.6  1998/10/05 07:48:00  malthoff
+ *	minor changes
+ *
+ *	Revision 1.5  1998/10/01 07:03:54  gklug
+ *	add: dummy function for XMAC ISR
+ *
+ *	Revision 1.4  1998/09/30 12:37:44  malthoff
+ *	Add SkXmSetRxCmd() and related code.
+ *
+ *	Revision 1.3  1998/09/28 13:26:40  malthoff
+ *	Add SkXmInitMac(), SkXmInitDupMd(), and SkXmInitPauseMd()
+ *
+ *	Revision 1.2  1998/09/16 14:34:21  malthoff
+ *	Add SkXmClrExactAddr(), SkXmClrSrcCheck(),
+ *	SkXmClrHashAddr(), SkXmFlushTxFifo(),
+ *	SkXmFlushRxFifo(), and SkXmHardRst().
+ *	Finish Coding of SkXmSoftRst().
+ *	The sources may be compiled now.
+ *
+ *	Revision 1.1  1998/09/04 10:05:56  malthoff
+ *	Created.
+ *
+ *
+ ******************************************************************************/
+
+#include "h/skdrv1st.h"
+#include "h/xmac_ii.h"
+#include "h/skdrv2nd.h"
+
+/* defines ********************************************************************/
+/* typedefs *******************************************************************/
+/* global variables ***********************************************************/
+
+/* local variables ************************************************************/
+
+static const char SysKonnectFileId[] =
+	"@(#)$Id: skxmac2.c,v 1.49 1999/11/22 08:12:13 malthoff Exp $ (C) SK ";
+
+/* BCOM PHY magic pattern list */
+typedef struct s_PhyHack {
+	int	PhyReg;		/* Phy register */
+	SK_U16	PhyVal;		/* Value to write */
+} BCOM_HACK;
+
+BCOM_HACK BcomRegA1Hack[] = {
+ { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 }, { 0x17, 0x0013 },
+ { 0x15, 0x0404 }, { 0x17, 0x8006 }, { 0x15, 0x0132 }, { 0x17, 0x8006 },
+ { 0x15, 0x0232 }, { 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 },
+ { 0, 0 }
+};
+BCOM_HACK BcomRegC0Hack[] = {
+ { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1204 }, { 0x17, 0x0013 },
+ { 0x15, 0x0A04 }, { 0x18, 0x0420 },
+ { 0, 0 }
+};
+
+/* function prototypes ********************************************************/
+static void	SkXmInitPhyXmac(SK_AC*, SK_IOC, int, SK_BOOL);
+static void	SkXmInitPhyBcom(SK_AC*, SK_IOC, int, SK_BOOL);
+static void	SkXmInitPhyLone(SK_AC*, SK_IOC, int, SK_BOOL);
+static void	SkXmInitPhyNat (SK_AC*, SK_IOC, int, SK_BOOL);
+static int	SkXmAutoNegDoneXmac(SK_AC*, SK_IOC, int);
+static int	SkXmAutoNegDoneBcom(SK_AC*, SK_IOC, int);
+static int	SkXmAutoNegDoneLone(SK_AC*, SK_IOC, int);
+static int	SkXmAutoNegDoneNat (SK_AC*, SK_IOC, int);
+
+/******************************************************************************
+ *
+ *	SkXmSetRxCmd() - Modify the value of the XMACs Rx Command Register
+ *
+ * Description:
+ *	The features
+ *	 o FCS stripping,			SK_STRIP_FCS_ON/OFF
+ *	 o pad byte stripping,			SK_STRIP_PAD_ON/OFF
+ *	 o don't set XMR_FS_ERR in frame	SK_LENERR_OK_ON/OFF
+ *	   status for inrange length error
+ *	   frames, and
+ *	 o don't set XMR_FS_ERR in frame	SK_BIG_PK_OK_ON/OFF
+ *	   status for frames > 1514 bytes
+ *
+ *	for incomming packets may be enabled/disabled by this function.
+ *	Additional modes may be added later.
+ *	Multiple modes can be enabled/disabled at the same time.
+ *	The new configuration is stored into the HWAC port configuration
+ *	and is written to the Receive Command register immediatlely.
+ *	The new configuration is saved over any SkGePortStop() and
+ *	SkGeInitPort() calls. The configured value will be overwritten
+ *	when SkGeInit(Level 0) is executed.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmSetRxCmd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* The XMAC to handle with belongs to this Port */
+int	Mode)		/* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF,
+				SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */
+{
+	SK_GEPORT *pPrt;
+	SK_U16	OldRxMode;
+
+	pPrt = &pAC->GIni.GP[Port];
+	OldRxMode = pPrt->PRxCmd;
+
+	switch(Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) {
+	case SK_STRIP_FCS_ON:
+		pPrt->PRxCmd |= XM_RX_STRIP_FCS;
+		break;
+	case SK_STRIP_FCS_OFF:
+		pPrt->PRxCmd &= ~XM_RX_STRIP_FCS;
+		break;
+	}
+
+	switch(Mode & (SK_STRIP_PAD_ON | SK_STRIP_PAD_OFF)) {
+	case SK_STRIP_PAD_ON:
+		pPrt->PRxCmd |= XM_RX_STRIP_PAD;
+		break;
+	case SK_STRIP_PAD_OFF:
+		pPrt->PRxCmd &= ~XM_RX_STRIP_PAD;
+		break;
+	}
+
+	switch(Mode & (SK_LENERR_OK_ON | SK_LENERR_OK_OFF)) {
+	case SK_LENERR_OK_ON:
+		pPrt->PRxCmd |= XM_RX_LENERR_OK;
+		break;
+	case SK_LENERR_OK_OFF:
+		pPrt->PRxCmd &= ~XM_RX_LENERR_OK;
+		break;
+	}
+
+	switch(Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) {
+	case SK_BIG_PK_OK_ON:
+		pPrt->PRxCmd |= XM_RX_BIG_PK_OK;
+		break;
+	case SK_BIG_PK_OK_OFF:
+		pPrt->PRxCmd &= ~XM_RX_BIG_PK_OK;
+		break;
+	}
+
+	/* Write the new mode to the receive command register if required */
+	if (OldRxMode != pPrt->PRxCmd) {
+		XM_OUT16(IoC, Port, XM_RX_CMD, pPrt->PRxCmd);
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkXmClrExactAddr() - Clear Exact Match Address Registers
+ *
+ * Description:
+ *	All Exact Match Address registers of the XMAC 'Port' will be
+ *	cleared starting with 'StartNum' up to (and including) the
+ *	Exact Match address number of 'StopNum'.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmClrExactAddr(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* The XMAC to handle with belongs to this Port */
+int	StartNum,	/* Begin with this Address Register Index (0..15) */
+int	StopNum)	/* Stop after finished with this Register Idx (0..15) */
+{
+	int	i;
+	SK_U16	ZeroAddr[3] = { 0x0000, 0x0000, 0x0000 };
+
+	if ((unsigned)StartNum > 15 || (unsigned)StopNum > 15 ||
+		StartNum > StopNum) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E001, SKERR_HWI_E001MSG);
+		return;
+	}
+
+	for (i = StartNum; i <= StopNum; i++) {
+		XM_OUTADDR(IoC, Port, XM_EXM(i), &ZeroAddr[0]);
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkXmClrSrcCheck() - Clear Source Check Address Register
+ *
+ * Description:
+ *	The Source Check Address Register of the XMAC 'Port' number
+ *	will be cleared.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmClrSrcCheck(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int	Port)	/* The XMAC to handle with belongs to this Port (MAC_1 + n) */
+{
+	SK_U16	ZeroAddr[3] = { 0x0000, 0x0000, 0x0000 };
+
+	XM_OUTHASH(IoC, Port, XM_SRC_CHK, &ZeroAddr);
+}
+
+/******************************************************************************
+ *
+ *	SkXmClrHashAddr() - Clear Hash Address Registers
+ *
+ * Description:
+ *	The Hash Address Register of the XMAC 'Port' will be cleared.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmClrHashAddr(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int	Port)	/* The XMAC to handle with belongs to this Port (MAC_1 + n) */
+{
+	SK_U16	ZeroAddr[4] = { 0x0000, 0x0000, 0x0000, 0x0000 };
+
+	XM_OUTHASH(IoC, Port, XM_HSM, &ZeroAddr);
+}
+
+/******************************************************************************
+ *
+ *	SkXmFlushTxFifo() - Flush the XMACs transmit FIFO
+ *
+ * Description:
+ *	Flush the transmit FIFO of the XMAC specified by the index 'Port'
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmFlushTxFifo(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int	Port)	/* The XMAC to handle with belongs to this Port (MAC_1 + n) */
+{
+	SK_U32	MdReg;
+
+	XM_IN32(IoC, Port, XM_MODE, &MdReg);
+	MdReg |= XM_MD_FTF;
+	XM_OUT32(IoC, Port, XM_MODE, MdReg);
+}
+
+/******************************************************************************
+ *
+ *	SkXmFlushRxFifo() - Flush the XMACs receive FIFO
+ *
+ * Description:
+ *	Flush the receive FIFO of the XMAC specified by the index 'Port'
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmFlushRxFifo(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int	Port)	/* The XMAC to handle with belongs to this Port (MAC_1 + n) */
+{
+	SK_U32	MdReg;
+
+	XM_IN32(IoC, Port, XM_MODE, &MdReg);
+	MdReg |= XM_MD_FRF;
+	XM_OUT32(IoC, Port, XM_MODE, MdReg);
+}
+
+/******************************************************************************
+ *
+ *	SkXmSoftRst() - Do a XMAC software reset
+ *
+ * Description:
+ *	The PHY registers should not be destroyed during this
+ *	kind of software reset. Therefore the XMAC Software Reset
+ *	(XM_GP_RES_MAC bit in XM_GP_PORT) must not be used!
+ *
+ *	The software reset is done by
+ *		- disabling the Rx and Tx state maschine,
+ *		- reseting the statistics module,
+ *		- clear all other significant XMAC Mode,
+ *		  Command, and Control Registers
+ *		- clearing the Hash Register and the
+ *		  Exact Match Address registers, and
+ *		- flushing the XMAC's Rx and Tx FIFOs.
+ *
+ * Note:
+ *	Another requirement when stopping the XMAC is to
+ *	avoid sending corrupted frames on the network.
+ *	Disabling the Tx state maschine will NOT interrupt
+ *	the currently transmitted frame. But we must take care
+ *	that the tx FIFO is cleared AFTER the current frame
+ *	is complete sent to the network.
+ *
+ *	It takes about 12ns to send a frame with 1538 bytes.
+ *	One PCI clock goes at least 15ns (66MHz). Therefore
+ *	after reading XM_GP_PORT back, we are sure that the
+ *	transmitter is disabled AND idle. And this means
+ *	we may flush the transmit FIFO now.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmSoftRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int	Port)	/* port to stop (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16	Word;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* disable the receiver and transmitter */
+	XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+	XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~(XM_MMU_ENA_RX|XM_MMU_ENA_TX));
+
+	/* reset the statistics module */
+	XM_OUT32(IoC, Port, XM_GP_PORT, XM_GP_RES_STAT);
+
+	/*
+	 * clear all other significant XMAC Mode,
+	 * Command, and Control Registers
+	 */
+	XM_OUT16(IoC, Port, XM_IMSK, 0xffff);		/* disable all IRQs */
+	XM_OUT32(IoC, Port, XM_MODE, 0x00000000);	/* clear Mode Reg */
+	XM_OUT16(IoC, Port, XM_TX_CMD, 0x0000);		/* reset TX CMD Reg */
+	XM_OUT16(IoC, Port, XM_RX_CMD, 0x0000);		/* reset RX CMD Reg */
+	
+	/* disable all PHY IRQs */
+	switch (pAC->GIni.GP[Port].PhyType) {
+		case SK_PHY_BCOM:
+			PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, 
+				0xffff);
+			break;
+		case SK_PHY_LONE:
+			PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, 
+				0x0);
+			break;
+		case SK_PHY_NAT:
+			/* todo: National
+			 PHY_WRITE(IoC, pPrt, Port, PHY_NAT_INT_MASK, 
+				0xffff); */
+			break;
+	}
+
+	/* clear the Hash Register */
+	SkXmClrHashAddr(pAC, IoC, Port);
+
+	/* clear the Exact Match Address registers */
+	SkXmClrExactAddr(pAC, IoC, Port, 0, 15);
+	SkXmClrSrcCheck(pAC, IoC, Port);
+
+	/* flush the XMAC's Rx and Tx FIFOs */
+	SkXmFlushTxFifo(pAC, IoC, Port);
+	SkXmFlushRxFifo(pAC, IoC, Port);
+
+	pAC->GIni.GP[Port].PState = SK_PRT_STOP;
+}
+
+/******************************************************************************
+ *
+ *	SkXmHardRst() - Do a XMAC hardware reset
+ *
+ * Description:
+ *	The XMAC of the specified 'Port' and all connected devices
+ *	(PHY and SERDES) will receive a reset signal on its *Reset
+ *	pins.
+ *	External PHYs must be reset be clearing a bit in the GPIO
+ *	register (Timing requirements: Broadcom: 400ns, Level One:
+ *	none, National: 80ns).
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmHardRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int	Port)	/* port to stop (MAC_1 + n) */
+{
+	SK_U16	Word;
+	int	i;
+	SK_U32	Reg;
+
+	for (i=0; i<4; i++) {
+		/* TX_MFF_CTRL1 is a 32 bit register but only the lowest 16 */
+		/* bit contains buttoms to press */
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1),
+			(SK_U16) MFF_CLR_MAC_RST);
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1),
+			(SK_U16) MFF_SET_MAC_RST);
+		do {
+			SK_IN16(IoC,MR_ADDR(Port,TX_MFF_CTRL1), &Word);
+		} while ((Word & MFF_SET_MAC_RST) == 0);
+	}
+	if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) {
+
+		/* reset external PHY */
+		SK_IN32(IoC, B2_GP_IO, &Reg);
+		if (Port == 0) {
+			Reg |= GP_DIR_0; /* set to output */
+			Reg &= ~GP_IO_0;
+		}
+		else {
+			Reg |= GP_DIR_2; /* set to output */
+			Reg &= ~GP_IO_2;
+		}
+		SK_OUT32(IoC, B2_GP_IO, Reg);
+
+		/* short delay */
+		SK_IN32(IoC, B2_GP_IO, &Reg);
+	}
+
+	pAC->GIni.GP[Port].PState = SK_PRT_RESET;
+}
+
+/******************************************************************************
+ *
+ *	SkXmInitMac() - Initialize the XMAC II
+ *
+ * Description:
+ *	Initialize all the XMAC of the specified port.
+ *	The XMAC must be reset or stopped before calling this function.
+ *
+ * Note:
+ *	The XMACs Rx and Tx state machine is still disabled when
+ *	returning.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmInitMac(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT *pPrt;
+	SK_U16	SWord;
+	int	i;
+	SK_U32	Reg;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PState == SK_PRT_STOP) {
+		/* Port State: SK_PRT_STOP */
+		/* Verify that the reset bit is cleared */
+		SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &SWord);
+		if (SWord & (SK_U16) MFF_SET_MAC_RST) {
+			/* PState does not match HW state */
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006,
+				SKERR_HWI_E006MSG);
+			/* correct it */
+			pPrt->PState = SK_PRT_RESET;
+		}
+	}
+	if (pPrt->PState == SK_PRT_RESET) {
+		/*
+		 * clear HW reset
+		 * Note: The SW reset is self clearing, therefore there is
+		 *	 nothing to do here.
+		 */
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1),
+			(SK_U16) MFF_CLR_MAC_RST);
+		
+		/*
+		 * clear PHY reset
+		 */
+		if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) {
+
+			SK_IN32(IoC, B2_GP_IO, &Reg);
+			if (Port == 0) {
+				Reg |= GP_DIR_0; /* set to output */
+				Reg |= GP_IO_0;
+			}
+			else {
+				Reg |= GP_DIR_2; /* set to output */
+				Reg |= GP_IO_2;
+			}
+			SK_OUT32(IoC, B2_GP_IO, Reg);
+
+			/* enable GMII interface */
+			XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_GMII_MD);
+
+			/* optimize MDIO transfer by oppressing preamble */
+			XM_IN16(IoC, Port, XM_MMU_CMD, &SWord);
+			XM_OUT16(IoC, Port, XM_MMU_CMD, SWord | XM_MMU_NO_PRE);
+
+			/* Workaround BCOM Errata for the A1 type */
+			/* Write magic patterns to reserved registers */
+			PHY_READ(IoC, pPrt, Port, PHY_XMAC_ID1, &SWord);
+			if (SWord == 0x6041) {
+				i = 0;
+				while (BcomRegA1Hack[i].PhyReg != 0) {
+					PHY_WRITE(IoC, pPrt, Port,
+						BcomRegA1Hack[i].PhyReg,
+						BcomRegA1Hack[i].PhyVal);
+					i++;
+				}
+			}
+			/* Workaround BCOM Errata for the C0 type */
+			/* Write magic patterns to reserved registers */
+			if (SWord == 0x6044) {
+				i = 0;
+				while (BcomRegC0Hack[i].PhyReg != 0) {
+					PHY_WRITE(IoC, pPrt, Port,
+						BcomRegC0Hack[i].PhyReg,
+						BcomRegC0Hack[i].PhyVal);
+					i++;
+				}
+			}
+
+			/*
+			 * PHY LED initialization is performed in
+			 * SkGeXmitLED() (but not here).
+			 */
+		}
+
+		/* Dummy read the Interrupt source register */
+		XM_IN16(IoC, Port, XM_ISRC, &SWord);
+		
+		/*
+		 * The autonegotiation process starts immediately after
+		 * clearing the reset. Autonegotiation process should be
+		 * started by the SIRQ, therefore stop it here immediately.
+		 */
+		SkXmInitPhy(pAC, IoC, Port, SK_FALSE);
+
+#if 0
+		/* temp. code: enable signal detect */
+		/* WARNING: do not override GMII setting above */
+		XM_OUT16(pAC, Port, XM_HW_CFG, XM_HW_COM4SIG);
+#endif
+	}
+
+	/*
+	 * configure the XMACs Station Address
+	 * B2_MAC_2 = xx xx xx xx xx x1 is programed to XMAC A
+	 * B2_MAC_3 = xx xx xx xx xx x2 is programed to XMAC B
+	 */
+	for (i = 0; i < 3; i++) {
+		/*
+		 * The following 2 statements are together endianess
+		 * independant. Remember this when changing.
+		 */
+		SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord);
+		XM_OUT16(IoC, Port, (XM_SA + i * 2), SWord);
+	}
+
+	/* Tx Inter Packet Gap (XM_TX_IPG):	use default */
+	/* Tx High Water Mark (XM_TX_HI_WM):	use default */
+	/* Tx Low Water Mark (XM_TX_LO_WM):	use default */
+	/* Host Request Threshold (XM_HT_THR):	use default */
+	/* Rx Request Threshold (XM_RX_THR):	use default */
+	/* Rx Low Water Mark (XM_RX_LO_WM):	use default */
+
+	/* configure Rx High Water Mark (XM_RX_HI_WM) */
+	XM_OUT16(IoC, Port, XM_RX_HI_WM, 0x05aa);
+
+	if (pAC->GIni.GIMacsFound > 1) {
+		switch (pAC->GIni.GIPortUsage) {
+		case SK_RED_LINK:
+			/* Configure Tx Request Threshold for red. link */
+			XM_OUT16(IoC, Port, XM_TX_THR, SK_XM_THR_REDL);
+			break;
+		case SK_MUL_LINK:
+			/* Configure Tx Request Threshold for load bal. */
+			XM_OUT16(IoC, Port, XM_TX_THR, SK_XM_THR_MULL);
+			break;
+		case SK_JUMBO_LINK:
+			/* Configure Tx Request Threshold for jumbo frames */
+			XM_OUT16(IoC, Port, XM_TX_THR, SK_XM_THR_JUMBO);
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E014,
+				SKERR_HWI_E014MSG);
+			break;
+		}
+	}
+	else {
+		/* Configure Tx Request Threshold for single port */
+		XM_OUT16(IoC, Port, XM_TX_THR, SK_XM_THR_SL);
+	}
+
+	/*
+	 * setup register defaults for the Rx Command Register
+	 *	- Enable Automatic Frame Padding on Tx side
+	 */
+	XM_OUT16(IoC, Port, XM_TX_CMD, XM_TX_AUTO_PAD);
+
+	/*
+	 * setup register defaults for the Rx Command Register,
+	 * program value of PRxCmd
+	 */
+	XM_OUT16(IoC, Port, XM_RX_CMD, pPrt->PRxCmd);
+
+	/*
+	 * setup register defaults for the Mode Register
+	 *	- Don't strip error frames to avoid Store & Forward
+	 *	  on the rx side.
+	 *	- Enable 'Check Station Address' bit
+	 *	- Enable 'Check Address Array' bit
+	 */
+	XM_OUT32(IoC, Port, XM_MODE, XM_DEF_MODE);
+
+	/*
+	 * Initialize the Receive Counter Event Mask (XM_RX_EV_MSK)
+	 *	- Enable all bits excepting 'Octets Rx OK Low CntOv'
+	 *	  and 'Octets Rx OK Hi Cnt Ov'.
+	 */
+	XM_OUT32(IoC, Port, XM_RX_EV_MSK, XMR_DEF_MSK);
+
+	/*
+	 * Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK)
+	 *	- Enable all bits excepting 'Octets Tx OK Low CntOv'
+	 *	  and 'Octets Tx OK Hi Cnt Ov'.
+	 */
+	XM_OUT32(IoC, Port, XM_TX_EV_MSK, XMT_DEF_MSK);
+
+	/*
+	 * Do NOT init XMAC interrupt mask here.
+	 * All interrupts remain disable until link comes up!
+	 */
+	pPrt->PState = SK_PRT_INIT;
+
+	/*
+	 * Any additional configuration changes may be done now.
+	 * The last action is to enable the rx and tx state machine.
+	 * This should be done after the autonegotiation process
+	 * has been completed successfully.
+	 */
+}
+
+/******************************************************************************
+ *
+ *	SkXmInitDupMd() - Initialize the XMACs Duplex Mode
+ *
+ * Description:
+ *	This function initilaizes the XMACs Duplex Mode.
+ *	It should be called after successfully finishing
+ *	the Autonegotiation Process
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmInitDupMd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	switch (pAC->GIni.GP[Port].PLinkModeStatus) {
+	case SK_LMODE_STAT_AUTOHALF:
+	case SK_LMODE_STAT_HALF:
+		/* Configuration Actions for Half Duplex Mode */
+		/*
+		 * XM_BURST = default value. We are propable not quick
+		 * 	enough at the 'XMAC' bus to burst 8kB.
+		 *	The XMAC stopps bursting if no transmit frames
+		 *	are available or the burst limit is exceeded.
+		 */
+		/* XM_TX_RT_LIM = default value (15) */
+		/* XM_TX_STIME = default value (0xff = 4096 bit times) */
+		break;
+	case SK_LMODE_STAT_AUTOFULL:
+	case SK_LMODE_STAT_FULL:
+		/* Configuration Actions for Full Duplex Mode */
+		/*
+		 * The duplex mode is configured by the PHY,
+		 * therefore it seems to be that there is nothing
+		 * to do here.
+		 */
+		break;
+	case SK_LMODE_STAT_UNKNOWN:
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E007, SKERR_HWI_E007MSG);
+		break;
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkXmInitPauseMd() - initialize the Pause Mode to be used for this port
+ *
+ * Description:
+ *	This function initilaizes the Pause Mode which should
+ *	be used for this port.
+ *	It should be called after successfully finishing
+ *	the Autonegotiation Process
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmInitPauseMd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Word;
+	SK_U32		DWord;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_NONE ||
+		pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) {
+
+		/* Disable Pause Frame Reception */
+		XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+		XM_OUT16(IoC, Port, XM_MMU_CMD, Word | XM_MMU_IGN_PF);
+	}
+	else {
+		/*
+		 * enabling pause frame reception is required for 1000BT 
+		 * because the XMAC is not reset if the link is going down
+		 */
+		/* Enable Pause Frame Reception */
+		XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+		XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~XM_MMU_IGN_PF);
+	}	
+
+	if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_SYMMETRIC ||
+		pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) {
+
+		/*
+		 * Configure Pause Frame Generation
+		 * Use internal and external Pause Frame Generation.
+		 * Sending pause frames is edge triggert. Send a
+		 * Pause frame with the maximum pause time if
+		 * internal oder external FIFO full condition
+		 * occurs. Send a zero pause time frame to
+		 * start transmission again.
+		 */
+
+		/* XM_PAUSE_DA = '010000C28001' (default) */
+
+		/* XM_MAC_PTIME = 0xffff (maximum) */
+		/* remember this value is defined in big endian (!) */
+		XM_OUT16(IoC, Port, XM_MAC_PTIME, 0xffff);
+
+		/* Set Pause Mode in Mode Register */
+		XM_IN32(IoC, Port, XM_MODE, &DWord);
+		XM_OUT32(IoC, Port, XM_MODE, DWord | XM_PAUSE_MODE);
+
+		/* Set Pause Mode in MAC Rx FIFO */
+		SK_OUT16(IoC, MR_ADDR(Port,RX_MFF_CTRL1), MFF_ENA_PAUSE);
+	}
+	else {
+		/*
+		 * disable pause frame generation is required for 1000BT 
+		 * because the XMAC is not reset if the link is going down
+		 */
+		/* Disable Pause Mode in Mode Register */
+		XM_IN32(IoC, Port, XM_MODE, &DWord);
+		XM_OUT32(IoC, Port, XM_MODE, DWord & ~XM_PAUSE_MODE);
+
+		/* Disable Pause Mode in MAC Rx FIFO */
+		SK_OUT16(IoC, MR_ADDR(Port,RX_MFF_CTRL1), MFF_DIS_PAUSE);
+	}
+
+}
+
+
+/******************************************************************************
+ *
+ *	SkXmInitPhy() - Initialize the XMAC II Phy registers
+ *
+ * Description:
+ *	Initialize all the XMACs Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmInitPhy(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+	switch (pPrt->PhyType) {
+	case SK_PHY_XMAC:
+		SkXmInitPhyXmac(pAC, IoC, Port, DoLoop);
+		break;
+	case SK_PHY_BCOM:
+		SkXmInitPhyBcom(pAC, IoC, Port, DoLoop);
+		break;
+	case SK_PHY_LONE:
+		SkXmInitPhyLone(pAC, IoC, Port, DoLoop);
+		break;
+	case SK_PHY_NAT:
+		SkXmInitPhyNat(pAC, IoC, Port, DoLoop);
+		break;
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkXmInitPhyXmac() - Initialize the XMAC II Phy registers
+ *
+ * Description:
+ *	Initialize all the XMACs Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmInitPhyXmac(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Crtl;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Autonegotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF ||
+	    pPrt->PLinkMode == SK_LMODE_FULL) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("InitPhyXmac: no autonegotiation Port %d\n", Port));
+		/* No Autonegiotiation */
+		/* Set DuplexMode in Config register */
+		Crtl = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
+
+		/*
+		 * Do NOT enable Autonegotiation here. This would hold
+		 * the link down because no IDLES are transmitted
+		 */
+	} else {
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("InitPhyXmac: with autonegotiation Port %d\n", Port));
+		/* Set Autonegotiation advertisement */
+		Crtl = 0;
+
+		/* Set Full/half duplex capabilities */
+		switch (pPrt->PLinkMode) {
+		case SK_LMODE_AUTOHALF:
+			Crtl |= PHY_X_AN_HD;
+			break;
+		case SK_LMODE_AUTOFULL:
+			Crtl |= PHY_X_AN_FD;
+			break;
+		case SK_LMODE_AUTOBOTH:
+			Crtl |= PHY_X_AN_FD | PHY_X_AN_HD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
+				SKERR_HWI_E015, SKERR_HWI_E015MSG) ;
+		}
+
+		switch (pPrt->PFlowCtrlMode) {
+		case SK_FLOW_MODE_NONE:
+			Crtl |= PHY_X_P_NO_PAUSE;
+			break;
+		case SK_FLOW_MODE_LOC_SEND:
+			Crtl |= PHY_X_P_ASYM_MD;
+			break;
+		case SK_FLOW_MODE_SYMMETRIC:
+			Crtl |= PHY_X_P_SYM_MD;
+			break;
+		case SK_FLOW_MODE_SYM_OR_REM:
+			Crtl |= PHY_X_P_BOTH_MD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
+				SKERR_HWI_E016, SKERR_HWI_E016MSG) ;
+		}
+
+		/* Write AutoNeg Advertisement Register */
+		PHY_WRITE(IoC, pPrt, Port, PHY_XMAC_AUNE_ADV, Crtl) ;
+
+		/* Restart Autonegotiation */
+		Crtl = PHY_CT_ANE | PHY_CT_RE_CFG;
+	}
+
+	if (DoLoop) {
+		/* Set the Phy Loopback bit, too */
+		Crtl |= PHY_CT_LOOP;
+	}
+
+	/* Write to the Phy control register */
+	PHY_WRITE(IoC, pPrt, Port, PHY_XMAC_CTRL, Crtl) ;
+}
+
+/******************************************************************************
+ *
+ *	SkXmInitPhyBcom() - Initialize the Broadcom Phy registers
+ *
+ * Description:
+ *	Initialize all the Broadcom Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmInitPhyBcom(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Crtl1 = PHY_B_CT_SP1000;
+	SK_U16		Crtl2 = 0;
+	SK_U16		Crtl3 = PHY_SEL_TYPE;
+	SK_U16		Crtl4 = PHY_B_PEC_EN_LTR;
+	SK_U16		Crtl5 = PHY_B_AC_TX_TST;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* manuell Master/Slave ? */
+	if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+		Crtl2 |= PHY_B_1000C_MSE;
+		if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+			Crtl2 |= PHY_B_1000C_MSC;
+		}
+	}
+	/* Autonegotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF ||
+	    pPrt->PLinkMode == SK_LMODE_FULL) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("InitPhyBcom: no autonegotiation Port %d\n", Port));
+		/* No Autonegiotiation */
+		/* Set DuplexMode in Config register */
+		Crtl1 |= (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
+
+		/* Determine Master/Slave manuell if not already done */
+		if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+			Crtl2 |= PHY_B_1000C_MSE;	/* set it to Slave */
+		}
+
+		/*
+		 * Do NOT enable Autonegotiation here. This would hold
+		 * the link down because no IDLES are transmitted
+		 */
+	} else {
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("InitPhyBcom: with autonegotiation Port %d\n", Port));
+		/* Set Autonegotiation advertisement */
+
+		/* Set Full/half duplex capabilities */
+		switch (pPrt->PLinkMode) {
+		case SK_LMODE_AUTOHALF:
+			Crtl2 |= PHY_B_1000C_AHD;
+			break;
+		case SK_LMODE_AUTOFULL:
+			Crtl2 |= PHY_B_1000C_AFD;
+			break;
+		case SK_LMODE_AUTOBOTH:
+			Crtl2 |= PHY_B_1000C_AFD | PHY_B_1000C_AHD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
+				SKERR_HWI_E015, SKERR_HWI_E015MSG) ;
+		}
+
+		switch (pPrt->PFlowCtrlMode) {
+		case SK_FLOW_MODE_NONE:
+			Crtl3 |= PHY_B_P_NO_PAUSE;
+			break;
+		case SK_FLOW_MODE_LOC_SEND:
+			Crtl3 |= PHY_B_P_ASYM_MD;
+			break;
+		case SK_FLOW_MODE_SYMMETRIC:
+			Crtl3 |= PHY_B_P_SYM_MD;
+			break;
+		case SK_FLOW_MODE_SYM_OR_REM:
+			Crtl3 |= PHY_B_P_BOTH_MD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
+				SKERR_HWI_E016, SKERR_HWI_E016MSG);
+		}
+
+		/* Restart Autonegotiation */
+		Crtl1 |= PHY_CT_ANE | PHY_CT_RE_CFG;
+
+	}
+	
+	/* Initialize LED register here? */
+	/* No. Please do it in SkDgXmitLed() (if required) and swap
+	   init order of LEDs and XMAC. (MAl) */
+	
+	/* Write 1000Base-T Control Register */
+	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_1000T_CTRL, Crtl2);
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		("1000Base-T Control Reg = %x\n", Crtl2));
+	
+	/* Write AutoNeg Advertisement Register */
+	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUNE_ADV, Crtl3);
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		("AutoNeg Advertisment Reg = %x\n", Crtl3));
+	
+
+	if (DoLoop) {
+		/* Set the Phy Loopback bit, too */
+		Crtl1 |= PHY_CT_LOOP;
+	}
+
+	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+		/* configure fifo to high latency for xmission of ext. packets*/
+		Crtl4 |= PHY_B_PEC_HIGH_LA;
+
+		/* configure reception of extended packets */
+		Crtl5 |= PHY_B_AC_LONG_PACK;
+
+		PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, Crtl5);
+	}
+
+	/* Configure LED Traffic Mode and Jumbo Frame usage if specified */
+	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_P_EXT_CTRL, Crtl4);
+	
+	/* Write to the Phy control register */
+	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, Crtl1);
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		("PHY Control Reg = %x\n", Crtl1));
+}
+
+/******************************************************************************
+ *
+ *	SkXmInitPhyLone() - Initialize the Level One Phy registers
+ *
+ * Description:
+ *	Initialize all the Level One Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmInitPhyLone(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Crtl1 = PHY_L_CT_SP1000;
+	SK_U16		Crtl2 = 0;
+	SK_U16		Crtl3 = PHY_SEL_TYPE;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* manuell Master/Slave ? */
+	if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+		Crtl2 |= PHY_L_1000C_MSE;
+		if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+			Crtl2 |= PHY_L_1000C_MSC;
+		}
+	}
+	/* Autonegotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF ||
+	    pPrt->PLinkMode == SK_LMODE_FULL) {
+		/*
+		 * level one spec say: "1000Mbps: manual mode not allowed"
+		 * but lets see what happens...
+		 */
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
+			0, "Level One PHY only works with Autoneg");
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("InitPhyLone: no autonegotiation Port %d\n", Port));
+		/* No Autonegiotiation */
+		/* Set DuplexMode in Config register */
+		Crtl1 = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
+
+		/* Determine Master/Slave manuell if not already done */
+		if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+			Crtl2 |= PHY_L_1000C_MSE;	/* set it to Slave */
+		}
+
+		/*
+		 * Do NOT enable Autonegotiation here. This would hold
+		 * the link down because no IDLES are transmitted
+		 */
+	} else {
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("InitPhyLone: with autonegotiation Port %d\n", Port));
+		/* Set Autonegotiation advertisement */
+
+		/* Set Full/half duplex capabilities */
+		switch (pPrt->PLinkMode) {
+		case SK_LMODE_AUTOHALF:
+			Crtl2 |= PHY_L_1000C_AHD;
+			break;
+		case SK_LMODE_AUTOFULL:
+			Crtl2 |= PHY_L_1000C_AFD;
+			break;
+		case SK_LMODE_AUTOBOTH:
+			Crtl2 |= PHY_L_1000C_AFD | PHY_L_1000C_AHD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
+				SKERR_HWI_E015, SKERR_HWI_E015MSG) ;
+		}
+
+		switch (pPrt->PFlowCtrlMode) {
+		case SK_FLOW_MODE_NONE:
+			Crtl3 |= PHY_L_P_NO_PAUSE;
+			break;
+		case SK_FLOW_MODE_LOC_SEND:
+			Crtl3 |= PHY_L_P_ASYM_MD;
+			break;
+		case SK_FLOW_MODE_SYMMETRIC:
+			Crtl3 |= PHY_L_P_SYM_MD;
+			break;
+		case SK_FLOW_MODE_SYM_OR_REM:
+			Crtl3 |= PHY_L_P_BOTH_MD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
+				SKERR_HWI_E016, SKERR_HWI_E016MSG);
+		}
+
+		/* Restart Autonegotiation */
+		Crtl1 = PHY_CT_ANE | PHY_CT_RE_CFG;
+
+	}
+	
+	/* Initialize LED register here ? */
+	/* No. Please do it in SkDgXmitLed() (if required) and swap
+	   init order of LEDs and XMAC. (MAl) */
+	
+	/* Write 1000Base-T Control Register */
+	PHY_WRITE(IoC, pPrt, Port, PHY_LONE_1000T_CTRL, Crtl2);
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		("1000Base-T Control Reg = %x\n", Crtl2));
+	
+	/* Write AutoNeg Advertisement Register */
+	PHY_WRITE(IoC, pPrt, Port, PHY_LONE_AUNE_ADV, Crtl3);
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		("AutoNeg Advertisment Reg = %x\n", Crtl3));
+	
+
+	if (DoLoop) {
+		/* Set the Phy Loopback bit, too */
+		Crtl1 |= PHY_CT_LOOP;
+	}
+
+	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+		/*
+		 * nothing to do for Level one.
+		 * PHY supports frames up to 10k.
+		 */
+	}
+	
+	/* Write to the Phy control register */
+	PHY_WRITE(IoC, pPrt, Port, PHY_LONE_CTRL, Crtl1);
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		("PHY Control Reg = %x\n", Crtl1));
+}
+
+/******************************************************************************
+ *
+ *	SkXmInitPhyNat() - Initialize the National Phy registers
+ *
+ * Description:
+ *	Initialize all the National Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmInitPhyNat(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
+{
+/* todo: National */
+}
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegLipaXmac() - Decides whether Link Partner could do autoneg
+ *
+ *	This function analyses the Interrupt status word. If any of the
+ *	Autonegotiating interrupt bits are set, the PLipaAutoNeg variable
+ *	is set true.
+ */
+void	SkXmAutoNegLipaXmac(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_U16	IStatus)	/* Interrupt Status word to analyse */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
+		(IStatus & (XM_IS_LIPA_RC|XM_IS_RX_PAGE|XM_IS_AND))) {
+
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, IStatus));
+		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegLipaBcom() - Decides whether Link Partner could do autoneg
+ *
+ *	This function analyses the PHY status word. If any of the
+ *	Autonegotiating bits are set, The PLipaAutoNeg variable
+ *	is set true.
+ */
+void	SkXmAutoNegLipaBcom(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_U16	PhyStat)	/* PHY Status word to analyse */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
+		(PhyStat & (PHY_ST_AN_OVER))) {
+
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, PhyStat));
+		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegLipaLone() - Decides whether Link Partner could do autoneg
+ *
+ *	This function analyses the PHY status word. If any of the
+ *	Autonegotiating bits are set, The PLipaAutoNeg variable
+ *	is set true.
+ */
+void	SkXmAutoNegLipaLone(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_U16	PhyStat)	/* PHY Status word to analyse */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
+		(PhyStat & (PHY_ST_AN_OVER))) {
+
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, PhyStat));
+		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
+	}
+}
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegLipaNat() - Decides whether Link Partner could do autoneg
+ *
+ *	This function analyses the PHY status word. If any of the
+ *	Autonegotiating bits are set, The PLipaAutoNeg variable
+ *	is set true.
+ */
+void	SkXmAutoNegLipaNat(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_U16	PhyStat)	/* PHY Status word to analyse */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
+		(PhyStat & (PHY_ST_AN_OVER))) {
+
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, PhyStat));
+		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
+	}
+}
+/******************************************************************************
+ *
+ *	SkXmAutoNegDone() - Auto negotiation handling
+ *
+ * Description:
+ *	This function handles the autonegotiation if the Done bit is set.
+ *
+ * Note:
+ *	o The XMACs interrupt source register is NOT read here.
+ *	o This function is public because it is used in the diagnostics
+ *	  tool, too.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+int	SkXmAutoNegDone(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	switch (pPrt->PhyType) {
+	case SK_PHY_XMAC:
+		return (SkXmAutoNegDoneXmac(pAC, IoC, Port));
+	case SK_PHY_BCOM:
+		return (SkXmAutoNegDoneBcom(pAC, IoC, Port));
+	case SK_PHY_LONE:
+		return (SkXmAutoNegDoneLone(pAC, IoC, Port));
+	case SK_PHY_NAT:
+		return (SkXmAutoNegDoneNat(pAC, IoC, Port));
+	}
+	return(SK_AND_OTHER);
+}
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegDoneXmac() - Auto negotiation handling
+ *
+ * Description:
+ *	This function handles the autonegotiation if the Done bit is set.
+ *
+ * Note:
+ *	o The XMACs interrupt source register is NOT read here.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+static int	SkXmAutoNegDoneXmac(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		ResAb ;		/* Resolved Ability */
+	SK_U16		LPAb ;		/* Link Partner Ability */
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegDoneXmac"
+		"Port %d\n",Port));
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Get PHY parameters */
+	PHY_READ(IoC, pPrt, Port, PHY_XMAC_AUNE_LP, &LPAb);
+	PHY_READ(IoC, pPrt, Port, PHY_XMAC_RES_ABI, &ResAb);
+
+	if (LPAb & PHY_X_AN_RFB) {
+		/* At least one of the remote fault bit is set */
+		/* Error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegFail: Remote fault bit set Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE ;
+		return (SK_AND_OTHER) ;
+	}
+
+	/* Check Duplex mismatch */
+	if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_FD) {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL ;
+	} else if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_HD) {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF ;
+	} else {
+		/* Error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegFail: Duplex mode mismatch port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE ;
+		return (SK_AND_DUP_CAP) ;
+	}
+
+	/* Check PAUSE mismatch */
+	/* We are NOT using chapter 4.23 of the Xaqti manual */
+	/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+	if ((pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYMMETRIC ||
+	     pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM) &&
+	    (LPAb & PHY_X_P_SYM_MD)) {
+		/* Symmetric PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+	} else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM &&
+		   (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) {
+		/* Enable PAUSE receive, disable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+	} else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND &&
+		   (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) {
+		/* Disable PAUSE receive, enable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+	} else {
+		/* PAUSE mismatch -> no PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+	}
+
+	/* We checked everything and may now enable the link */
+	pPrt->PAutoNegFail = SK_FALSE ;
+
+	SkXmRxTxEnable(pAC, IoC, Port);
+	return(SK_AND_OK) ;
+}
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegDoneBcom() - Auto negotiation handling
+ *
+ * Description:
+ *	This function handles the autonegotiation if the Done bit is set.
+ *
+ * Note:
+ *	o The XMACs interrupt source register is NOT read here.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+static int	SkXmAutoNegDoneBcom(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		ResAb ;		/* Resolved Ability */
+	SK_U16		LPAb ;		/* Link Partner Ability */
+	SK_U16		AuxStat;	/* Auxiliary Status */
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegDoneBcom,"
+		" Port %d\n",Port));
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Get PHY parameters */
+	PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUNE_LP, &LPAb);
+	PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb);
+	PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_STAT, &AuxStat);
+
+	if (LPAb & PHY_B_AN_RF) {
+		/* Remote fault bit is set */
+		/* Error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegFail: Remote fault bit set Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE ;
+		return (SK_AND_OTHER) ;
+	}
+
+	/* Check Duplex mismatch */
+	if ((AuxStat & PHY_B_AS_AN_RES) == PHY_B_RES_1000FD) {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL ;
+	} else 	if ((AuxStat & PHY_B_AS_AN_RES) == PHY_B_RES_1000HD) {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF ;
+	} else {
+		/* Error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegFail: Duplex mode mismatch port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE ;
+		return (SK_AND_DUP_CAP) ;
+	}
+	
+	/* Check Master/Slave resolution */
+	if (ResAb & (PHY_B_1000S_MSF)) {
+		/* Error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("Master/Slave Fault port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		pPrt->PMSStatus = SK_MS_STAT_FAULT;
+		return (SK_AND_OTHER);
+	} else if (ResAb & PHY_B_1000S_MSR) {
+		pPrt->PMSStatus = SK_MS_STAT_MASTER ;
+	} else {
+		pPrt->PMSStatus = SK_MS_STAT_SLAVE ;
+	}
+
+	/* Check PAUSE mismatch */
+	/* We are NOT using chapter 4.23 of the Xaqti manual */
+	/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+	if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == 
+		(PHY_B_AS_PRR | PHY_B_AS_PRT)) {
+		/* Symmetric PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+	} else if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == PHY_B_AS_PRR) {
+		/* Enable PAUSE receive, disable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+	} else if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == PHY_B_AS_PRT) {
+		/* Disable PAUSE receive, enable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+	} else {
+		/* PAUSE mismatch -> no PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+	}
+
+	/* We checked everything and may now enable the link */
+	pPrt->PAutoNegFail = SK_FALSE ;
+
+	SkXmRxTxEnable(pAC, IoC, Port);
+	return(SK_AND_OK) ;
+}
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegDoneLone() - Auto negotiation handling
+ *
+ * Description:
+ *	This function handles the autonegotiation if the Done bit is set.
+ *
+ * Note:
+ *	o The XMACs interrupt source register is NOT read here.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+static int	SkXmAutoNegDoneLone(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		ResAb ;		/* Resolved Ability */
+	SK_U16		LPAb ;		/* Link Partner Ability */
+	SK_U16		QuickStat;	/* Auxiliary Status */
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegDoneLone"
+		"Port %d\n",Port));
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Get PHY parameters */
+	PHY_READ(IoC, pPrt, Port, PHY_LONE_AUNE_LP, &LPAb);
+	PHY_READ(IoC, pPrt, Port, PHY_LONE_1000T_STAT, &ResAb);
+	PHY_READ(IoC, pPrt, Port, PHY_LONE_Q_STAT, &QuickStat);
+
+	if (LPAb & PHY_L_AN_RF) {
+		/* Remote fault bit is set */
+		/* Error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("AutoNegFail: Remote fault bit set Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE ;
+		return (SK_AND_OTHER) ;
+	}
+
+	/* Check Duplex mismatch */
+	if (QuickStat & PHY_L_QS_DUP_MOD) {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL ;
+	} else {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF ;
+	}
+	
+	/* Check Master/Slave resolution */
+	if (ResAb & (PHY_L_1000S_MSF)) {
+		/* Error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+			("Master/Slave Fault port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		pPrt->PMSStatus = SK_MS_STAT_FAULT ;
+		return (SK_AND_OTHER);
+	} else if (ResAb & PHY_L_1000S_MSR) {
+		pPrt->PMSStatus = SK_MS_STAT_MASTER ;
+	} else {
+		pPrt->PMSStatus = SK_MS_STAT_SLAVE ;
+	}
+
+	/* Check PAUSE mismatch */
+	/* We are NOT using chapter 4.23 of the Xaqti manual */
+	/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+	/* we must manually resolve the abilities here */
+	pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+	switch (pPrt->PFlowCtrlMode) {
+	case SK_FLOW_MODE_NONE:
+		/* default */
+		break;
+	case SK_FLOW_MODE_LOC_SEND:
+		if ((QuickStat & (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) ==
+			(PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) {
+			/* Disable PAUSE receive, enable PAUSE transmit */
+			pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+		}
+		break;
+	case SK_FLOW_MODE_SYMMETRIC:
+		if ((QuickStat & PHY_L_QS_PAUSE) == PHY_L_QS_PAUSE) {
+			/* Symmetric PAUSE */
+			pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+		}
+		break;
+	case SK_FLOW_MODE_SYM_OR_REM:
+		if ((QuickStat & (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) ==
+			PHY_L_QS_AS_PAUSE) {
+			/* Enable PAUSE receive, disable PAUSE transmit */
+			pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+		}
+		else if ((QuickStat & PHY_L_QS_PAUSE) == PHY_L_QS_PAUSE) {
+			/* Symmetric PAUSE */
+			pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+		}
+		break;
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
+			SKERR_HWI_E016, SKERR_HWI_E016MSG);
+	}
+
+	/* We checked everything and may now enable the link */
+	pPrt->PAutoNegFail = SK_FALSE ;
+
+	SkXmRxTxEnable(pAC, IoC, Port);
+	return(SK_AND_OK);
+}
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegDoneNat() - Auto negotiation handling
+ *
+ * Description:
+ *	This function handles the autonegotiation if the Done bit is set.
+ *
+ * Note:
+ *	o The XMACs interrupt source register is NOT read here.
+ *	o This function is public because it is used in the diagnostics
+ *	  tool, too.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+static int	SkXmAutoNegDoneNat(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+/* todo: National */
+	return(SK_AND_OK);
+}
+
+/******************************************************************************
+ *
+ *	SkXmRxTxEnable() - Enable RxTx activity if port is up
+ *
+ * Description:
+ *
+ * Note:
+ *	o The XMACs interrupt source register is NOT read here.
+ *
+ * Returns:
+ *	0	o.k.
+ *	!= 0	Error happened
+ */
+int SkXmRxTxEnable(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Reg ;		/* 16bit register value */
+	SK_U16		IntMask;	/* XMac interrupt mask */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (!pPrt->PHWLinkUp) {
+		/* The Hardware link is NOT up */
+		return(0) ;
+	}
+
+	if ((pPrt->PLinkMode == SK_LMODE_AUTOHALF ||
+	     pPrt->PLinkMode == SK_LMODE_AUTOFULL ||
+	     pPrt->PLinkMode == SK_LMODE_AUTOBOTH) &&
+	     pPrt->PAutoNegFail) {
+		/* Autonegotiation is not done or failed */
+		return(0) ;
+	}
+
+	/* Set Dup Mode and Pause Mode */
+	SkXmInitDupMd (pAC, IoC, Port);
+	SkXmInitPauseMd (pAC, IoC, Port);
+
+	/*
+	 * Initialize the Interrupt Mask Register. Default IRQs are...
+	 *	- Link Asynchronous Event
+	 *	- Link Partner requests config
+	 *	- Auto Negotiation Done
+	 *	- Rx Counter Event Overflow
+	 *	- Tx Counter Event Overflow
+	 *	- Transmit FIFO Underrun
+	 */
+	if (pPrt->PhyType == SK_PHY_XMAC) {
+		IntMask = XM_DEF_MSK;
+	}
+	else {
+		/* disable GP0 interrupt bit */
+		IntMask = XM_DEF_MSK | XM_IS_INP_ASS;
+	}
+	XM_OUT16(IoC, Port, XM_IMSK, IntMask);
+
+	/* RX/TX enable */
+	XM_IN16(IoC, Port, XM_MMU_CMD, &Reg);
+	if (pPrt->PhyType != SK_PHY_XMAC &&
+		(pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL || 
+		 pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL)) {
+		Reg |= XM_MMU_GMII_FD;
+	}
+	switch (pPrt->PhyType) {
+	case SK_PHY_BCOM:
+		PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, 
+			PHY_B_DEF_MSK);
+		break;
+	case SK_PHY_LONE:
+		PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, 
+			PHY_L_DEF_MSK);
+		break;
+	case SK_PHY_NAT:
+		/* todo National:
+		PHY_WRITE(IoC, pPrt, Port, PHY_NAT_INT_MASK, 
+			PHY_N_DEF_MSK); */
+		/* no interrupts possible from National ??? */
+		break;
+	}
+	XM_OUT16(IoC, Port, XM_MMU_CMD, Reg | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+				      
+	return (0);
+}
+
+#ifndef SK_DIAG
+/******************************************************************************
+ *
+ *	SkXmIrq() - Interrupt service routine
+ *
+ * Description:
+ *	Services an Interrupt of the XMAC II
+ *
+ * Note:
+ *	The XMACs interrupt source register is NOT read here.
+ *	With an external PHY, some interrupt bits are not meaningfull
+ *	any more:
+ *	- LinkAsyncEvent (bit #14)              XM_IS_LNK_AE
+ *	- LinkPartnerReqConfig (bit #10)	XM_IS_LIPA_RC
+ *	- Page Received (bit #9)		XM_IS_RX_PAGE
+ *	- NextPageLoadedForXmt (bit #8)		XM_IS_TX_PAGE
+ *	- AutoNegDone (bit #7)			XM_IS_AND
+ *	Also probably not valid any more is the GP0 input bit:
+ *	- GPRegisterBit0set			XM_IS_INP_ASS
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmIrq(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int	Port,		/* Port Index (MAC_1 + n) */
+SK_U16	IStatus)	/* Interrupt status read from the XMAC */
+{
+	SK_GEPORT	*pPrt;
+	SK_EVPARA	Para;
+
+	pPrt = &pAC->GIni.GP[Port];
+	
+	if (pPrt->PhyType != SK_PHY_XMAC) {
+		/* mask bits that are not used with ext. PHY */
+		IStatus &= ~(XM_IS_LNK_AE | XM_IS_LIPA_RC |
+			XM_IS_RX_PAGE | XM_IS_TX_PAGE |
+			XM_IS_AND | XM_IS_INP_ASS);
+	}
+	
+	/*
+	 * LinkPartner Autonegable ?
+	 */
+	if (pPrt->PhyType == SK_PHY_XMAC) {
+		SkXmAutoNegLipaXmac(pAC, IoC, Port, IStatus);
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+		("XmacIrq Port %d Isr %x\n", Port, IStatus));
+
+	if (!pPrt->PHWLinkUp) {
+		/* Spurious XMAC interrupt */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("SkXmIrq: spurious interrupt on port %d\n",
+			 Port));
+		return;
+	}
+
+	if (IStatus & XM_IS_LNK_AE) {
+		/* not used GP0 is used instead */
+	}
+
+	if (IStatus & XM_IS_TX_ABORT) {
+		/* not used */
+	}
+
+	if (IStatus & XM_IS_FRC_INT) {
+		/* not used. use ASIC IRQ instead if needed */
+	}
+
+	if (IStatus & (XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE)) {
+		SkHWLinkDown(pAC, IoC, Port);
+
+		/* Signal to RLMT */
+		Para.Para32[0] = (SK_U32) Port;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+
+		/* Start workaround Errata #2 timer */
+		SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer,
+			SK_WA_INA_TIME,SKGE_HWAC,SK_HWEV_WATIM,Para);
+	}
+
+	if (IStatus & XM_IS_RX_PAGE) {
+		/* not used */
+	}
+
+	if (IStatus & XM_IS_TX_PAGE) {
+		/* not used */
+	}
+
+	if (IStatus & XM_IS_AND) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
+			("SkXmIrq: AND on link that is up port %d\n", Port));
+	}
+
+	if (IStatus & XM_IS_TSC_OV) {
+		/* not used */
+	}
+
+	if (IStatus & XM_IS_RXC_OV) {
+		Para.Para32[0] = (SK_U32) Port;
+		Para.Para32[1] = (SK_U32) IStatus;
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para);
+	}
+
+	if (IStatus & XM_IS_TXC_OV) {
+		Para.Para32[0] = (SK_U32) Port;
+		Para.Para32[1] = (SK_U32) IStatus;
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para);
+	}
+
+	if (IStatus & XM_IS_RXF_OV) {
+		/* normal situation -> no effect */
+	}
+
+	if (IStatus & XM_IS_TXF_UR) {
+		/* may NOT happen -> error log */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E020,
+			SKERR_SIRQ_E020MSG) ;
+	}
+
+	if (IStatus & XM_IS_TX_COMP) {
+		/* not served here */
+	}
+
+	if (IStatus & XM_IS_RX_COMP) {
+		/* not served here */
+	}
+
+}
+#endif /* !SK_DIAG */
+
+/* End of file */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sktr.c linux.14p16/drivers/net/sktr.c
--- linux.vanilla/drivers/net/sktr.c	Wed Oct 20 01:12:39 1999
+++ linux.14p16/drivers/net/sktr.c	Thu Dec  9 15:33:31 1999
@@ -258,12 +258,12 @@
 		/* Remove I/O space marker in bit 0. */
 		pci_ioaddr &= ~3;
 
-		if((vendor != PCI_VENDOR_ID_SK) &&
+		if((vendor != PCI_VENDOR_ID_SYSKONNECT) &&
 		   (vendor != PCI_VENDOR_ID_COMPAQ))
 			continue;
 
-		if((vendor == PCI_VENDOR_ID_SK) && 
-		   (device != PCI_DEVICE_ID_SK_TR))
+		if((vendor == PCI_VENDOR_ID_SYSKONNECT) && 
+		   (device != PCI_DEVICE_ID_SYSKONNECT_TR))
 			continue;
 		else if((vendor == PCI_VENDOR_ID_COMPAQ) && 
 			(device != PCI_DEVICE_ID_COMPAQ_TOKENRING))
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/slhc.c linux.14p16/drivers/net/slhc.c
--- linux.vanilla/drivers/net/slhc.c	Fri Dec 18 17:40:56 1998
+++ linux.14p16/drivers/net/slhc.c	Thu Dec  9 15:33:26 1999
@@ -760,12 +760,6 @@
 
 #endif /* MODULE */
 #else /* CONFIG_INET */
-EXPORT_SYMBOL(slhc_init);
-EXPORT_SYMBOL(slhc_free);
-EXPORT_SYMBOL(slhc_remember);
-EXPORT_SYMBOL(slhc_compress);
-EXPORT_SYMBOL(slhc_uncompress);
-EXPORT_SYMBOL(slhc_toss);
 
 int
 slhc_toss(struct slcompress *comp)
@@ -806,5 +800,11 @@
   printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init");
   return NULL;
 }
+EXPORT_SYMBOL(slhc_init);
+EXPORT_SYMBOL(slhc_free);
+EXPORT_SYMBOL(slhc_remember);
+EXPORT_SYMBOL(slhc_compress);
+EXPORT_SYMBOL(slhc_uncompress);
+EXPORT_SYMBOL(slhc_toss);
 
 #endif /* CONFIG_INET */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sunbmac.c linux.14p16/drivers/net/sunbmac.c
--- linux.vanilla/drivers/net/sunbmac.c	Tue Mar 16 00:11:30 1999
+++ linux.14p16/drivers/net/sunbmac.c	Thu Dec  9 15:33:32 1999
@@ -85,7 +85,7 @@
 	}
 	if(tries)
 		return 0;
-	printk("BigMAC: Cannot reset the QEC.\n");
+	printk(KERN_ERR "BigMAC: Cannot reset the QEC.\n");
 	return -1;
 }
 
@@ -133,8 +133,8 @@
 		udelay(20);
 
 	if(!tries) {
-		printk("BIGMAC: Transmitter will not reset.\n");
-		printk("BIGMAC: tx_cfg is %08x\n", bregs->tx_cfg);
+		printk(KERN_ERR "BIGMAC: Transmitter will not reset.\n");
+		printk(KERN_ERR "BIGMAC: tx_cfg is %08x\n", bregs->tx_cfg);
 	}
 }
 
@@ -147,8 +147,8 @@
 		udelay(20);
 
 	if(!tries) {
-		printk("BIGMAC: Receiver will not reset.\n");
-		printk("BIGMAC: rx_cfg is %08x\n", bregs->rx_cfg);
+		printk(KERN_ERR "BIGMAC: Receiver will not reset.\n");
+		printk(KERN_ERR "BIGMAC: rx_cfg is %08x\n", bregs->rx_cfg);
 	}
 }
 
@@ -292,7 +292,7 @@
 					 MGMT_PAL_DCLOCK);
 		garbage = tregs->mgmt_pal;
 	} else {
-		printk("write_tcvr_bit: No transceiver type known!\n");
+		printk(KERN_ERR "write_tcvr_bit: No transceiver type known!\n");
 	}
 }
 
@@ -314,7 +314,7 @@
 		garbage = tregs->mgmt_pal;
 		retval = (tregs->mgmt_pal & MGMT_PAL_EXT_MDIO) >> 2;
 	} else {
-		printk("read_tcvr_bit: No transceiver type known!\n");
+		printk(KERN_ERR "read_tcvr_bit: No transceiver type known!\n");
 	}
 	return retval;
 }
@@ -337,7 +337,7 @@
 		tregs->mgmt_pal = (MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK);
 		garbage = tregs->mgmt_pal;
 	} else {
-		printk("read_tcvr_bit2: No transceiver type known!\n");
+		printk(KERN_ERR "read_tcvr_bit2: No transceiver type known!\n");
 	}
 	return retval;
 }
@@ -367,7 +367,7 @@
 		break;
 
 	default:
-		printk("bigmac_tcvr_read: Whoops, no known transceiver type.\n");
+		printk(KERN_ERR "bigmac_tcvr_read: Whoops, no known transceiver type.\n");
 		return;
 	};
 
@@ -406,7 +406,7 @@
 		break;
 
 	default:
-		printk("bigmac_tcvr_read: Whoops, no known transceiver type.\n");
+		printk(KERN_ERR "bigmac_tcvr_read: Whoops, no known transceiver type.\n");
 		return 0xffff;
 	};
 
@@ -493,9 +493,9 @@
 				    TCVR_PAL_LTENABLE);
 		garbage = tregs->tcvr_pal;
 	} else {
-		printk("BIGMAC: AIEEE, neither internal nor "
+		printk(KERN_ERR "BIGMAC: AIEEE, neither internal nor "
 		       "external MDIO available!\n");
-		printk("BIGMAC: mgmt_pal[%08x] tcvr_pal[%08x]\n",
+		printk(KERN_ERR "BIGMAC: mgmt_pal[%08x] tcvr_pal[%08x]\n",
 		       tregs->mgmt_pal, tregs->tcvr_pal);
 	}
 }
@@ -521,7 +521,7 @@
 			udelay(20);
 		}
 		if(timeout == 0)
-			printk("%s: PHY reset failed.\n", bp->dev->name);
+			printk(KERN_ERR "%s: PHY reset failed.\n", bp->dev->name);
 
 		bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);
 
@@ -546,7 +546,7 @@
 		bp->sw_bmsr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMSR);
 		bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);
 		if(bp->sw_bmsr & BMSR_LSTATUS) {
-			printk("%s: Link is now up at %s.\n",
+			printk(KERN_INFO "%s: Link is now up at %s.\n",
 			       bp->dev->name,
 			       (bp->sw_bmcr & BMCR_SPEED100) ?
 			       "100baseT" : "10baseT");
@@ -558,11 +558,11 @@
 
 				ret = try_next_permutation(bp, tregs);
 				if(ret == -1) {
-					printk("%s: Link down, cable problem?\n",
+					printk(KERN_ERR "%s: Link down, cable problem?\n",
 					       bp->dev->name);
 					ret = bigmac_init(bp, 0);
 					if(ret) {
-						printk("%s: Error, cannot re-init the "
+						printk(KERN_ERR "%s: Error, cannot re-init the "
 						       "BigMAC.\n", bp->dev->name);
 					}
 					return;
@@ -575,7 +575,7 @@
 		}
 	} else {
 		/* Can't happens.... */
-		printk("%s: Aieee, link timer is asleep but we got one anyways!\n",
+		printk(KERN_ERR "%s: Aieee, link timer is asleep but we got one anyways!\n",
 		       bp->dev->name);
 		restart_timer = 0;
 		bp->timer_ticks = 0;
@@ -614,7 +614,7 @@
 		udelay(20);
 	}
 	if(timeout == 0)
-		printk("%s: PHY reset failed.\n", bp->dev->name);
+		printk(KERN_ERR "%s: PHY reset failed.\n", bp->dev->name);
 
 	bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);
 
@@ -724,7 +724,7 @@
 				  unsigned int qec_status,
 				  unsigned int bmac_status)
 {
-	printk("bigmac_is_medium_rare: ");
+	printk(KERN_ERR "bigmac_is_medium_rare: ");
 	if(qec_status & (GLOB_STAT_ER | GLOB_STAT_BM)) {
 		if(qec_status & GLOB_STAT_ER)
 			printk("QEC_ERROR, ");
@@ -838,7 +838,7 @@
 #ifdef NEED_DMA_SYNCHRONIZATION
 #ifdef __sparc_v9__
 		if ((unsigned long) (skb->data + skb->len) >= MAX_DMA_ADDRESS) {
-			printk("sunbmac: Bogus DMA buffer address "
+			printk(KERN_CRIT "sunbmac: Bogus DMA buffer address "
 			       "[%016lx]\n", ((unsigned long) skb->data));
 			panic("DMA address too large, tell DaveM");
 		}
@@ -895,7 +895,7 @@
 	}
 	bp->rx_new = elem;
 	if(drops)
-		printk("%s: Memory squeeze, deferring packet.\n", bp->dev->name);
+		printk(KERN_NOTICE "%s: Memory squeeze, deferring packet.\n", bp->dev->name);
 }
 
 #ifndef __sparc_v9__
@@ -948,7 +948,7 @@
 	}
 	bp->rx_new = elem;
 	if(drops)
-		printk("%s: Memory squeeze, deferring packet.\n", bp->dev->name);
+		printk(KERN_NOTICE "%s: Memory squeeze, deferring packet.\n", bp->dev->name);
 }
 #endif
 
@@ -1024,14 +1024,14 @@
 	if(sparc_cpu_model == sun4c) {
 		if(request_irq(dev->irq, &sun4c_bigmac_interrupt,
 			       SA_SHIRQ, "BIG MAC", (void *) bp)) {
-			printk("BIGMAC: Can't order irq %d to go.\n", dev->irq);
+			printk(KERN_ERR "BIGMAC: Can't order irq %d to go.\n", dev->irq);
 			return -EAGAIN;
 		}
 	} else
 #endif
 	if(request_irq(dev->irq, &bigmac_interrupt,
 		       SA_SHIRQ, "BIG MAC", (void *) bp)) {
-		printk("BIGMAC: Can't order irq %d to go.\n", dev->irq);
+		printk(KERN_ERR "BIGMAC: Can't order irq %d to go.\n", dev->irq);
 		return -EAGAIN;
 	}
 	init_timer(&bp->bigmac_timer);
@@ -1069,7 +1069,7 @@
 		if (tickssofar < 40) {
 			return 1;
 		} else {
-			printk ("%s: transmit timed out, resetting\n", dev->name);
+			printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
 			bp->enet_stats.tx_errors++;
 			bigmac_init(bp, 0);
 			dev->tbusy = 0;
@@ -1080,7 +1080,7 @@
 	}
 
 	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
-		printk("%s: Transmitter access conflict.\n", dev->name);
+		printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
 		return 1;
 	}
 
@@ -1138,7 +1138,7 @@
 		if (tickssofar < 40) {
 			return 1;
 		} else {
-			printk ("%s: transmit timed out, resetting\n", dev->name);
+			printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
 			bp->enet_stats.tx_errors++;
 			bigmac_init(bp, 0);
 			dev->tbusy = 0;
@@ -1148,7 +1148,7 @@
 	}
 
 	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
-		printk("%s: Transmitter access conflict.\n", dev->name);
+		printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
 		return 1;
 	}
 
@@ -1266,10 +1266,10 @@
 	dev = init_etherdev(0, sizeof(struct bigmac));
 
 	if(version_printed++ == 0)
-		printk(version);
+		printk(KERN_INFO "%s", version);
 
 	/* Report what we have found to the user. */
-	printk("%s: BigMAC 100baseT Ethernet ", dev->name);
+	printk(KERN_INFO "%s: BigMAC 100baseT Ethernet ", dev->name);
 	dev->base_addr = (long) qec_sdev;
 	for(i = 0; i < 6; i++)
 		printk("%2.2x%c", dev->dev_addr[i] = idprom->id_ethaddr[i],
@@ -1287,10 +1287,10 @@
 	/* Verify the registers we expect, are actually there. */
 	if((bp->bigmac_sbus_dev->num_registers != 3) ||
 	   (bp->qec_sbus_dev->num_registers != 2)) {
-		printk("BIGMAC: Device does not have 2 and 3 regs, it has %d and %d.\n",
+		printk(KERN_ERR "BIGMAC: Device does not have 2 and 3 regs, it has %d and %d.\n",
 		       bp->qec_sbus_dev->num_registers,
 		       bp->bigmac_sbus_dev->num_registers);
-		printk("BIGMAC: Would you like that for here or to go?\n");
+		printk(KERN_ERR "BIGMAC: Would you like that for here or to go?\n");
 		goto fail_and_cleanup;
 	}
 
@@ -1309,7 +1309,7 @@
 				   qranges[k].ot_child_space)
 					break;
 			if(k >= num_qranges) {
-				printk("BigMAC: Aieee, bogus QEC range for space %08x\n",
+				printk(KERN_ERR "BigMAC: Aieee, bogus QEC range for space %08x\n",
 				       bp->bigmac_sbus_dev->reg_addrs[j].which_io);
 				goto fail_and_cleanup;
 			}
@@ -1338,13 +1338,13 @@
 				   bp->qec_sbus_dev->reg_addrs[0].which_io,
 				   0);
 	if(!bp->gregs) {
-		printk("BIGMAC: Cannot map QEC global registers.\n");
+		printk(KERN_ERR "BIGMAC: Cannot map QEC global registers.\n");
 		goto fail_and_cleanup;
 	}
 
 	/* Make sure QEC is in BigMAC mode. */
 	if((bp->gregs->ctrl & 0xf0000000) != GLOB_CTRL_BMODE) {
-		printk("BigMAC: AIEEE, QEC is not in BigMAC mode!\n");
+		printk(KERN_ERR "BigMAC: AIEEE, QEC is not in BigMAC mode!\n");
 		goto fail_and_cleanup;
 	}
 
@@ -1380,7 +1380,7 @@
 				  bp->bigmac_sbus_dev->reg_addrs[0].which_io,
 				  0);
 	if(!bp->creg) {
-		printk("BIGMAC: Cannot map QEC channel registers.\n");
+		printk(KERN_ERR "BIGMAC: Cannot map QEC channel registers.\n");
 		goto fail_and_cleanup;
 	}
 
@@ -1392,7 +1392,7 @@
 				   bp->bigmac_sbus_dev->reg_addrs[1].which_io,
 				   0);
 	if(!bp->bregs) {
-		printk("BIGMAC: Cannot map BigMAC primary registers.\n");
+		printk(KERN_ERR "BIGMAC: Cannot map BigMAC primary registers.\n");
 		goto fail_and_cleanup;
 	}
 
@@ -1406,7 +1406,7 @@
 				   bp->bigmac_sbus_dev->reg_addrs[2].which_io,
 				   0);
 	if(!bp->tregs) {
-		printk("BIGMAC: Cannot map BigMAC transceiver registers.\n");
+		printk(KERN_ERR "BIGMAC: Cannot map BigMAC transceiver registers.\n");
 		goto fail_and_cleanup;
 	}
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sunhme.c linux.14p16/drivers/net/sunhme.c
--- linux.vanilla/drivers/net/sunhme.c	Wed Oct 20 01:12:39 1999
+++ linux.14p16/drivers/net/sunhme.c	Thu Dec  9 15:33:27 1999
@@ -297,7 +297,7 @@
 	while(!(hme_read32(hp, &tregs->frame) & 0x10000) && --tries)
 		udelay(20);
 	if(!tries) {
-		printk("happy meal: Aieee, transceiver MIF read bolixed\n");
+		printk(KERN_ERR "happy meal: Aieee, transceiver MIF read bolixed\n");
 		return TCVR_FAILURE;
 	}
 	retval = hme_read32(hp, &tregs->frame) & 0xffff;
@@ -328,7 +328,7 @@
 
 	/* Anything else? */
 	if(!tries)
-		printk("happy meal: Aieee, transceiver MIF write bolixed\n");
+		printk(KERN_ERR "happy meal: Aieee, transceiver MIF write bolixed\n");
 
 	/* Fifty-two cents is your change, have a nice day. */
 }
@@ -391,7 +391,7 @@
 
 static void display_link_mode(struct happy_meal *hp, struct hmeal_tcvregs *tregs)
 {
-	printk("%s: Link is up using ", hp->dev->name);
+	printk(KERN_INFO "%s: Link is up using ", hp->dev->name);
 	if(hp->tcvr_type == external)
 		printk("external ");
 	else
@@ -413,7 +413,7 @@
 
 static void display_forced_link_mode(struct happy_meal *hp, struct hmeal_tcvregs *tregs)
 {
-	printk("%s: Link has been forced up using ", hp->dev->name);
+	printk(KERN_INFO "%s: Link has been forced up using ", hp->dev->name);
 	if(hp->tcvr_type == external)
 		printk("external ");
 	else
@@ -492,6 +492,25 @@
 
 static int happy_meal_init(struct happy_meal *hp, int from_irq);
 
+static int is_lucent_phy(struct happy_meal *hp)
+{
+	struct hmeal_tcvregs *tregs = hp->tcvregs;
+	unsigned short mr2, mr3;
+	int ret = 0;
+
+	mr2 = happy_meal_tcvr_read(hp, tregs, 2);
+	mr3 = happy_meal_tcvr_read(hp, tregs, 3);
+	if ((mr2 & 0xffff) == 0x0180 &&
+	    ((mr3 & 0xffff) >> 10) == 0x1d) {
+#if 0
+		printk("HMEDEBUG: Lucent PHY detected.\n");
+#endif
+		ret = 1;
+	}
+
+	return ret;
+}
+
 static void happy_meal_timer(unsigned long data)
 {
 	struct happy_meal *hp = (struct happy_meal *) data;
@@ -508,19 +527,22 @@
 			/* Enter force mode. */
 	do_force_mode:
 			hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
-			printk("%s: Auto-Negotiation unsuccessful, trying force link mode\n",
+			printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful, trying force link mode\n",
 			       hp->dev->name);
 			hp->sw_bmcr = BMCR_SPEED100;
 			happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
 
-			/* OK, seems we need do disable the transceiver for the first
-			 * tick to make sure we get an accurate link state at the
-			 * second tick.
-			 */
-			hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG);
-			hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
-			happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig);
-
+			if (!is_lucent_phy(hp)) {
+				/* OK, seems we need do disable the transceiver for
+				 * the first tick to make sure we get an accurate
+				 * link state at the second tick.
+				 */
+				hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
+								       DP83840_CSCONFIG);
+				hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
+				happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG,
+						      hp->sw_csconfig);
+			}
 			hp->timer_state = ltrywait;
 			hp->timer_ticks = 0;
 			restart_timer = 1;
@@ -567,7 +589,7 @@
 			restart_timer = 0;
 		} else {
 			if(hp->timer_ticks >= 10) {
-				printk("%s: Auto negotiation successful, link still "
+				printk(KERN_NOTICE "%s: Auto negotiation successful, link still "
 				       "not completely up.\n", hp->dev->name);
 				hp->timer_ticks = 0;
 				restart_timer = 1;
@@ -587,15 +609,24 @@
 		hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG);
 		if(hp->timer_ticks == 1) {
 			/* Re-enable transceiver, we'll re-enable the transceiver next
-			 * tick, then check link state on the following tick. */
-			hp->sw_csconfig |= CSCONFIG_TCVDISAB;
-			happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig);
+			 * tick, then check link state on the following tick.
+			 * XXX But dont do this on Lucent PHY -DaveM
+			 */
+			if (!is_lucent_phy(hp)) {
+				hp->sw_csconfig |= CSCONFIG_TCVDISAB;
+				happy_meal_tcvr_write(hp, tregs,
+						      DP83840_CSCONFIG, hp->sw_csconfig);
+			}
 			restart_timer = 1;
 			break;
 		}
 		if(hp->timer_ticks == 2) {
-			hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
-			happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig);
+			/* XXX See above about Lucent PHY -DaveM */
+			if (!is_lucent_phy(hp)) {
+				hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
+				happy_meal_tcvr_write(hp, tregs,
+						      DP83840_CSCONFIG, hp->sw_csconfig);
+			}
 			restart_timer = 1;
 			break;
 		}
@@ -616,20 +647,25 @@
 					 */
 
 					/* Let the user know... */
-					printk("%s: Link down, cable problem?\n",
+					printk(KERN_NOTICE "%s: Link down, cable problem?\n",
 					       hp->dev->name);
 
 					ret = happy_meal_init(hp, 0);
 					if(ret) {
 						/* ho hum... */
-						printk("%s: Error, cannot re-init the "
+						printk(KERN_ERR "%s: Error, cannot re-init the "
 						       "Happy Meal.\n", hp->dev->name);
 					}
 					return;
 				}
-				hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG);
-				hp->sw_csconfig |= CSCONFIG_TCVDISAB;
-				happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig);
+				hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
+								       DP83840_CSCONFIG);
+				if (!is_lucent_phy(hp)) {
+					hp->sw_csconfig |= CSCONFIG_TCVDISAB;
+					happy_meal_tcvr_write(hp, tregs,
+							      DP83840_CSCONFIG,
+							      hp->sw_csconfig);
+				}
 				hp->timer_ticks = 0;
 				restart_timer = 1;
 			} else {
@@ -641,7 +677,7 @@
 	case asleep:
 	default:
 		/* Can't happens.... */
-		printk("%s: Aieee, link timer is asleep but we got one anyways!\n",
+		printk(KERN_ERR "%s: Aieee, link timer is asleep but we got one anyways!\n",
 		       hp->dev->name);
 		restart_timer = 0;
 		hp->timer_ticks = 0;
@@ -672,7 +708,7 @@
 
 	/* Lettuce, tomato, buggy hardware (no extra charge)? */
 	if(!tries)
-		printk("happy meal: Transceiver BigMac ATTACK!");
+		printk(KERN_ERR "happy meal: Transceiver BigMac ATTACK!");
 
 	/* Take care. */
 	HMD(("done\n"));
@@ -692,7 +728,7 @@
 
 	/* Will that be all? */
 	if(!tries)
-		printk("happy meal: Receiver BigMac ATTACK!");
+		printk(KERN_ERR "happy meal: Receiver BigMac ATTACK!");
 
 	/* Don't forget your vik_1137125_wa.  Have a nice day. */
 	HMD(("done\n"));
@@ -714,7 +750,7 @@
 
 	/* Come back next week when we are "Sun Microelectronics". */
 	if(!tries)
-		printk("happy meal: Fry guys.");
+		printk(KERN_ERR "happy meal: Fry guys.");
 
 	/* Remember: "Different name, same old buggy as shit hardware." */
 	HMD(("done\n"));
@@ -910,8 +946,11 @@
 		return -1;
 	}
 	ASD((" SUCCESS and CSCONFIG_DFBYPASS\n"));
-	result = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG);
-	happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, (result | CSCONFIG_DFBYPASS));
+	if (!is_lucent_phy(hp)) {
+		result = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG);
+		happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG,
+				      (result | CSCONFIG_DFBYPASS));
+	}
 	return 0;
 }
 
@@ -972,7 +1011,7 @@
 				hp->tcvr_type = internal;
 				ASD(("<internal>\n"));
 			} else {
-				printk("happy meal: Transceiver and a coke please.");
+				printk(KERN_ERR "happy meal: Transceiver and a coke please.");
 				hp->tcvr_type = none; /* Grrr... */
 				ASD(("<none>\n"));
 			}
@@ -1201,9 +1240,9 @@
 			udelay(10);
 		}
 		if(!timeout) {
-			printk("%s: Happy Meal would not start auto negotiation "
+			printk(KERN_ERR "%s: Happy Meal would not start auto negotiation "
 			       "BMCR=0x%04x\n", hp->dev->name, hp->sw_bmcr);
-			printk("%s: Performing force link detection.\n",
+			printk(KERN_NOTICE "%s: Performing force link detection.\n",
 			       hp->dev->name);
 			goto force_link;
 		} else {
@@ -1230,17 +1269,17 @@
 				hp->sw_bmcr |= BMCR_FULLDPLX;
 		}
 		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
-
-		/* OK, seems we need do disable the transceiver for the first
-		 * tick to make sure we get an accurate link state at the
-		 * second tick.
-		 */
-		hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
-						       DP83840_CSCONFIG);
-		hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
-		happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG,
-				      hp->sw_csconfig);
-
+		if (!is_lucent_phy(hp)) {
+			/* OK, seems we need do disable the transceiver for the first
+			 * tick to make sure we get an accurate link state at the
+			 * second tick.
+			 */
+			hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
+							       DP83840_CSCONFIG);
+			hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
+			happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG,
+					      hp->sw_csconfig);
+		}
 		hp->timer_state = ltrywait;
 	}
 
@@ -1479,8 +1518,8 @@
 	regtmp = hme_read32(hp, &erxregs->cfg);
 	hme_write32(hp, &erxregs->cfg, ERX_CFG_DEFAULT(RX_OFFSET));
 	if(hme_read32(hp, &erxregs->cfg) != ERX_CFG_DEFAULT(RX_OFFSET)) {
-		printk("happy meal: Eieee, rx config register gets greasy fries.\n");
-		printk("happy meal: Trying to set %08x, reread gives %08lx\n",
+		printk(KERN_ERR "happy meal: Eieee, rx config register gets greasy fries.\n");
+		printk(KERN_ERR "happy meal: Trying to set %08x, reread gives %08lx\n",
 		       ERX_CFG_DEFAULT(RX_OFFSET), regtmp);
 		/* XXX Should return failure here... */
 	}
@@ -1605,24 +1644,24 @@
 		     GREG_STAT_MIFIRQ | GREG_STAT_TXEACK | GREG_STAT_TXLERR |
 		     GREG_STAT_TXPERR | GREG_STAT_TXTERR | GREG_STAT_SLVERR |
 		     GREG_STAT_SLVPERR))
-		printk("%s: Error interrupt for happy meal, status = %08lx\n",
+		printk(KERN_ERR "%s: Error interrupt for happy meal, status = %08lx\n",
 		       hp->dev->name, status);
 
 	if(status & GREG_STAT_RFIFOVF) {
 		/* The receive FIFO overflowwed, usually a DMA error. */
-		printk("%s: Happy Meal receive FIFO overflow.\n", hp->dev->name);
+		printk(KERN_ERR "%s: Happy Meal receive FIFO overflow.\n", hp->dev->name);
 		reset = 1;
 	}
 
 	if(status & GREG_STAT_STSTERR) {
 		/* BigMAC SQE link test failed. */
-		printk("%s: Happy Meal BigMAC SQE test failed.\n", hp->dev->name);
+		printk(KERN_ERR "%s: Happy Meal BigMAC SQE test failed.\n", hp->dev->name);
 		reset = 1;
 	}
 
 	if(status & GREG_STAT_TFIFO_UND) {
 		/* Transmit FIFO underrun, again DMA error likely. */
-		printk("%s: Happy Meal transmitter FIFO underrun, DMA error.\n",
+		printk(KERN_ERR "%s: Happy Meal transmitter FIFO underrun, DMA error.\n",
 		       hp->dev->name);
 		reset = 1;
 	}
@@ -1631,7 +1670,7 @@
 		/* Driver error, tried to transmit something larger
 		 * than ethernet max mtu.
 		 */
-		printk("%s: Happy Meal MAX Packet size error.\n", hp->dev->name);
+		printk(KERN_ERR "%s: Happy Meal MAX Packet size error.\n", hp->dev->name);
 		reset = 1;
 	}
 
@@ -1648,7 +1687,7 @@
 
 	if(status & (GREG_STAT_RXERR|GREG_STAT_RXPERR|GREG_STAT_RXTERR)) {
 		/* All sorts of DMA receive errors. */
-		printk("%s: Happy Meal rx DMA errors [ ", hp->dev->name);
+		printk(KERN_ERR "%s: Happy Meal rx DMA errors [ ", hp->dev->name);
 		if(status & GREG_STAT_RXERR)
 			printk("GenericError ");
 		if(status & GREG_STAT_RXPERR)
@@ -1663,20 +1702,20 @@
 		/* Driver bug, didn't set EOP bit in tx descriptor given
 		 * to the happy meal.
 		 */
-		printk("%s: EOP not set in happy meal transmit descriptor!\n",
+		printk(KERN_ERR "%s: EOP not set in happy meal transmit descriptor!\n",
 		       hp->dev->name);
 		reset = 1;
 	}
 
 	if(status & GREG_STAT_MIFIRQ) {
 		/* MIF signalled an interrupt, were we polling it? */
-		printk("%s: Happy Meal MIF interrupt.\n", hp->dev->name);
+		printk(KERN_ERR "%s: Happy Meal MIF interrupt.\n", hp->dev->name);
 	}
 
 	if(status &
 	   (GREG_STAT_TXEACK|GREG_STAT_TXLERR|GREG_STAT_TXPERR|GREG_STAT_TXTERR)) {
 		/* All sorts of transmit DMA errors. */
-		printk("%s: Happy Meal tx DMA errors [ ", hp->dev->name);
+		printk(KERN_ERR "%s: Happy Meal tx DMA errors [ ", hp->dev->name);
 		if(status & GREG_STAT_TXEACK)
 			printk("GenericError ");
 		if(status & GREG_STAT_TXLERR)
@@ -1693,14 +1732,14 @@
 		/* Bus or parity error when cpu accessed happy meal registers
 		 * or it's internal FIFO's.  Should never see this.
 		 */
-		printk("%s: Happy Meal register access SBUS slave (%s) error.\n",
+		printk(KERN_ERR "%s: Happy Meal register access SBUS slave (%s) error.\n",
 		       hp->dev->name,
 		       (status & GREG_STAT_SLVPERR) ? "parity" : "generic");
 		reset = 1;
 	}
 
 	if(reset) {
-		printk("%s: Resetting...\n", hp->dev->name);
+		printk(KERN_NOTICE "%s: Resetting...\n", hp->dev->name);
 		happy_meal_init(hp, 1);
 		return 1;
 	}
@@ -1711,22 +1750,22 @@
 					    struct hmeal_gregs *gregs,
 					    struct hmeal_tcvregs *tregs)
 {
-	printk("%s: Link status change.\n", hp->dev->name);
+	printk(KERN_INFO "%s: Link status change.\n", hp->dev->name);
 	hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
 	hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, DP83840_LPA);
 
 	/* Use the fastest transmission protocol possible. */
 	if(hp->sw_lpa & LPA_100FULL) {
-		printk("%s: Switching to 100Mbps at full duplex.", hp->dev->name);
+		printk(KERN_INFO "%s: Switching to 100Mbps at full duplex.", hp->dev->name);
 		hp->sw_bmcr |= (BMCR_FULLDPLX | BMCR_SPEED100);
 	} else if(hp->sw_lpa & LPA_100HALF) {
-		printk("%s: Switching to 100MBps at half duplex.", hp->dev->name);
+		printk(KERN_INFO "%s: Switching to 100MBps at half duplex.", hp->dev->name);
 		hp->sw_bmcr |= BMCR_SPEED100;
 	} else if(hp->sw_lpa & LPA_10FULL) {
-		printk("%s: Switching to 10MBps at full duplex.", hp->dev->name);
+		printk(KERN_INFO "%s: Switching to 10MBps at full duplex.", hp->dev->name);
 		hp->sw_bmcr |= BMCR_FULLDPLX;
 	} else {
-		printk("%s: Using 10Mbps at half duplex.", hp->dev->name);
+		printk(KERN_INFO "%s: Using 10Mbps at half duplex.", hp->dev->name);
 	}
 	happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
 
@@ -1942,7 +1981,7 @@
 	}
 	hp->rx_new = elem;
 	if(drops)
-		printk("%s: Memory squeeze, deferring packet.\n", hp->dev->name);
+		printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", hp->dev->name);
 	RXD((">"));
 }
 
@@ -2061,7 +2100,7 @@
 	}
 	hp->rx_new = elem;
 	if(drops)
-		printk("%s: Memory squeeze, deferring packet.\n", hp->dev->name);
+		printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", hp->dev->name);
 	RXD((">"));
 }
 #endif
@@ -2126,7 +2165,7 @@
 	}
 	hp->rx_new = elem;
 	if(drops)
-		printk("%s: Memory squeeze, deferring packet.\n", hp->dev->name);
+		printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", hp->dev->name);
 	RXD((">"));
 }
 
@@ -2235,7 +2274,7 @@
 	}
 	hp->rx_new = elem;
 	if(drops)
-		printk("%s: Memory squeeze, deferring packet.\n", hp->dev->name);
+		printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", hp->dev->name);
 	RXD((">"));
 }
 #endif
@@ -2487,14 +2526,14 @@
 		if(request_irq(dev->irq, &sun4c_happy_meal_interrupt,
 			       SA_SHIRQ, "HAPPY MEAL", (void *) dev)) {
 			HMD(("EAGAIN\n"));
-			printk("happy meal: Can't order irq %d to go.\n", dev->irq);
+			printk(KERN_ERR "happy meal: Can't order irq %d to go.\n", dev->irq);
 			return -EAGAIN;
 		}
 	} else if (sparc_cpu_model == sun4d) {
 		if(request_irq(dev->irq, &sun4d_happy_meal_interrupt,
 			       SA_SHIRQ, "HAPPY MEAL", (void *) dev)) {
 			HMD(("EAGAIN\n"));
-			printk("happy_meal(SBUS): Can't order irq %s to go.\n",
+			printk(KERN_ERR "happy_meal(SBUS): Can't order irq %s to go.\n",
 			       __irq_itoa(dev->irq));
 			return -EAGAIN;
 		}
@@ -2505,7 +2544,7 @@
 		if(request_irq(dev->irq, &pci_happy_meal_interrupt,
 			       SA_SHIRQ, "HAPPY MEAL (PCI)", dev)) {
 		HMD(("EAGAIN\n"));
-		printk("happy_meal(PCI: Can't order irq %s to go.\n",
+		printk(KERN_ERR "happy_meal(PCI: Can't order irq %s to go.\n",
 		       __irq_itoa(dev->irq));
 			return -EAGAIN;
 		}
@@ -2514,7 +2553,7 @@
 	if(request_irq(dev->irq, &happy_meal_interrupt,
 		       SA_SHIRQ, "HAPPY MEAL", (void *)dev)) {
 		HMD(("EAGAIN\n"));
-		printk("happy_meal(SBUS): Can't order irq %s to go.\n",
+		printk(KERN_ERR "happy_meal(SBUS): Can't order irq %s to go.\n",
 		       __irq_itoa(dev->irq));
 		return -EAGAIN;
 	}
@@ -2568,10 +2607,10 @@
 		int tickssofar = jiffies - dev->trans_start;
 	    
 		if (tickssofar >= 40) {
-			printk ("%s: transmit timed out, resetting\n", dev->name);
+			printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
 			hp->net_stats.tx_errors++;
 			tx_dump_log();
-			printk ("%s: Happy Status %08x TX[%08x:%08x]\n", dev->name,
+			printk (KERN_ERR "%s: Happy Status %08x TX[%08x:%08x]\n", dev->name,
 				hme_read32(hp, &hp->gregs->stat),
 				hme_read32(hp, &hp->etxregs->cfg),
 				hme_read32(hp, &hp->bigmacregs->tx_cfg));
@@ -2633,7 +2672,7 @@
 		if (tickssofar >= 40) {
 			unsigned long flags;
 
-			printk ("%s: transmit timed out, resetting\n", dev->name);
+			printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
 
 			save_and_cli(flags);
 			tx_dump_log();
@@ -2690,7 +2729,7 @@
 		if (tickssofar < 40) {
 			return 1;
 		} else {
-			printk ("%s: transmit timed out, resetting\n", dev->name);
+			printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
 			hp->net_stats.tx_errors++;
 			happy_meal_init(hp, 0);
 			dev->tbusy = 0;
@@ -2700,7 +2739,7 @@
 	}
 
 	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
-		printk("happy meal: Transmitter access conflict.\n");
+		printk(KERN_ERR "happy meal: Transmitter access conflict.\n");
 		return 1;
 	}
 
@@ -2742,10 +2781,10 @@
 		int tickssofar = jiffies - dev->trans_start;
 	    
 		if (tickssofar >= 40) {
-			printk ("%s: transmit timed out, resetting\n", dev->name);
+			printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
 			hp->net_stats.tx_errors++;
 			tx_dump_log();
-			printk ("%s: Happy Status %08x TX[%08x:%08x]\n", dev->name,
+			printk (KERN_ERR "%s: Happy Status %08x TX[%08x:%08x]\n", dev->name,
 				hme_read32(hp, &hp->gregs->stat),
 				hme_read32(hp, &hp->etxregs->cfg),
 				hme_read32(hp, &hp->bigmacregs->tx_cfg));
@@ -3085,7 +3124,7 @@
 				  SA_SHIRQ, "Quattro",
 				  qp);
 		if(err != 0) {
-			printk("Quattro: Fatal IRQ registery error %d.\n", err);
+			printk(KERN_ERR "Quattro: Fatal IRQ registery error %d.\n", err);
 			panic("QFE request irq");
 		}
 	}
@@ -3117,13 +3156,13 @@
 			return -ENOMEM;
 	}
 	if(hme_version_printed++ == 0)
-		printk(version);
+		printk(KERN_INFO "%s", version);
 
 	if(qfe_slot != -1)
-		printk("%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
+		printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
 		       dev->name, qfe_slot);
 	else
-		printk("%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
+		printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
 		       dev->name);
 
 	dev->base_addr = (long) sdev;
@@ -3148,9 +3187,9 @@
 #endif
 
 	if(sdev->num_registers != 5) {
-		printk("happymeal: Device does not have 5 regs, it has %d.\n",
+		printk(KERN_ERR "happymeal: Device does not have 5 regs, it has %d.\n",
 		       sdev->num_registers);
-		printk("happymeal: Would you like that for here or to go?\n");
+		printk(KERN_ERR "happymeal: Would you like that for here or to go?\n");
 		return ENODEV;
 	}
 
@@ -3168,7 +3207,7 @@
 				   "Happy Meal Global Regs",
 				   sdev->reg_addrs[0].which_io, 0);
 	if(!hp->gregs) {
-		printk("happymeal: Cannot map Happy Meal global registers.\n");
+		printk(KERN_ERR "happymeal: Cannot map Happy Meal global registers.\n");
 		return ENODEV;
 	}
 
@@ -3177,7 +3216,7 @@
 				     "Happy Meal MAC TX Regs",
 				     sdev->reg_addrs[1].which_io, 0);
 	if(!hp->etxregs) {
-		printk("happymeal: Cannot map Happy Meal MAC Transmit registers.\n");
+		printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Transmit registers.\n");
 		return ENODEV;
 	}
 
@@ -3186,7 +3225,7 @@
 				     "Happy Meal MAC RX Regs",
 				     sdev->reg_addrs[2].which_io, 0);
 	if(!hp->erxregs) {
-		printk("happymeal: Cannot map Happy Meal MAC Receive registers.\n");
+		printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Receive registers.\n");
 		return ENODEV;
 	}
 
@@ -3195,7 +3234,7 @@
 					"Happy Meal BIGMAC Regs",
 					sdev->reg_addrs[3].which_io, 0);
 	if(!hp->bigmacregs) {
-		printk("happymeal: Cannot map Happy Meal BIGMAC registers.\n");
+		printk(KERN_ERR "happymeal: Cannot map Happy Meal BIGMAC registers.\n");
 		return ENODEV;
 	}
 
@@ -3204,7 +3243,7 @@
 				     "Happy Meal Tranceiver Regs",
 				     sdev->reg_addrs[4].which_io, 0);
 	if(!hp->tcvregs) {
-		printk("happymeal: Cannot map Happy Meal Tranceiver registers.\n");
+		printk(KERN_ERR "happymeal: Cannot map Happy Meal Tranceiver registers.\n");
 		return ENODEV;
 	}
 
@@ -3299,7 +3338,7 @@
 	/* Now make sure pci_dev cookie is there. */
 	pcp = pdev->sysdata;
 	if(pcp == NULL || pcp->prom_node == -1) {
-		printk("happymeal(PCI): Some PCI device info missing\n");
+		printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n");
 		return ENODEV;
 	}
 	node = pcp->prom_node;
@@ -3323,7 +3362,7 @@
 			return -ENOMEM;
 	}
 	if(hme_version_printed++ == 0)
-		printk(version);
+		printk(KERN_INFO "%s", version);
 
 	if (!qfe_slot) {
 		prom_name[0] = 0;
@@ -3331,7 +3370,7 @@
 			int i = simple_strtoul(dev->name + 3, NULL, 10);
 			sprintf(prom_name, "-%d", i + 3);
 		}
-		printk("%s%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet ", dev->name, prom_name);
+		printk(KERN_INFO "%s%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet ", dev->name, prom_name);
 		if (qp->quattro_pci_dev->vendor == PCI_VENDOR_ID_DEC &&
 		    qp->quattro_pci_dev->device == PCI_DEVICE_ID_DEC_21153)
 			printk("DEC 21153 PCI Bridge\n");
@@ -3340,10 +3379,10 @@
 				qp->quattro_pci_dev->vendor, qp->quattro_pci_dev->device);
 	}
 	if(qfe_slot != -1)
-		printk("%s: Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet ",
+		printk(KERN_INFO "%s: Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet ",
 		       dev->name, qfe_slot);
 	else
-		printk("%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ",
+		printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ",
 		       dev->name);
 
 	dev->base_addr = (long) pdev;
@@ -3362,7 +3401,7 @@
 
 	hpreg_base = pdev->base_address[0];
 	if((hpreg_base & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
-		printk("happymeal(PCI): Cannot find proper PCI device base address.\n");
+		printk(KERN_ERR "happymeal(PCI): Cannot find proper PCI device base address.\n");
 		return ENODEV;
 	}
 	hpreg_base &= PCI_BASE_ADDRESS_MEM_MASK;
@@ -3404,7 +3443,7 @@
 
 	hp->happy_block = (struct hmeal_init_block *) get_free_page(GFP_DMA);
 	if(!hp->happy_block) {
-		printk("happymeal(PCI): Cannot get hme init block.\n");
+		printk(KERN_ERR "happymeal(PCI): Cannot get hme init block.\n");
 		return ENODEV;
 	}
 
@@ -3443,6 +3482,9 @@
 	 * PROM leaves it at zero.
 	 */
 	{
+#if 1
+		unsigned char latency_timer = 64;
+#else
 		unsigned char min_gnt, latency_timer;
 
 		pci_read_config_byte(pdev, PCI_MIN_GNT, &min_gnt);
@@ -3450,6 +3492,7 @@
 			latency_timer = 64;
 		else
 			latency_timer = ((min_gnt << 3) & 0xff);
+#endif
 		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, latency_timer);
 	}
 #ifdef __sparc_v9__
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sunlance.c linux.14p16/drivers/net/sunlance.c
--- linux.vanilla/drivers/net/sunlance.c	Sun Mar 21 15:22:00 1999
+++ linux.14p16/drivers/net/sunlance.c	Thu Dec  9 15:33:27 1999
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.85 1999/03/21 05:22:05 davem Exp $
+/* $Id: sunlance.c,v 1.85.2.1 1999/10/09 06:03:38 davem Exp $
  * lance.c: Linux/Sparc/Lance driver
  *
  *	Written 1995, 1996 by Miguel de Icaza
@@ -428,7 +428,7 @@
 	for (i = 0; (i < 100) && !(ll->rdp & (LE_C0_ERR | LE_C0_IDON)); i++)
 		barrier();
 	if ((i == 100) || (ll->rdp & LE_C0_ERR)) {
-		printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp);
+		printk (KERN_ERR "LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp);
 		if (lp->ledma)
 			printk ("dcsr=%8.8x\n",
 				(unsigned int) lp->ledma->regs->cond_reg);
@@ -489,7 +489,7 @@
 			skb = dev_alloc_skb (len+2);
 
 			if (skb == 0) {
-				printk ("%s: Memory squeeze, deferring packet.\n",
+				printk (KERN_INFO "%s: Memory squeeze, deferring packet.\n",
 					dev->name);
 				lp->stats.rx_dropped++;
 				rd->mblength = 0;
@@ -547,7 +547,7 @@
 				lp->stats.tx_carrier_errors++;
 				if (lp->auto_select) {
 					lp->tpe = 1 - lp->tpe;
-					printk("%s: Carrier Lost, trying %s\n",
+					printk(KERN_NOTICE "%s: Carrier Lost, trying %s\n",
 					       dev->name, lp->tpe?"TPE":"AUI");
 					/* Stop the lance */
 					ll->rap = LE_CSR0;
@@ -565,7 +565,7 @@
 			if (status & (LE_T3_BUF|LE_T3_UFL)) {
 				lp->stats.tx_fifo_errors++;
 
-				printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
+				printk (KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
 					dev->name);
 				/* Stop the lance */
 				ll->rap = LE_CSR0;
@@ -606,7 +606,7 @@
 	int csr0;
     
 	if (dev->interrupt)
-		printk ("%s: again", dev->name);
+		printk (KERN_ERR "%s: again", dev->name);
     
 	dev->interrupt = 1;
 
@@ -643,7 +643,7 @@
 		struct sparc_dma_registers *dregs = lp->ledma->regs;
 		unsigned long tst = (unsigned long)dregs->st_addr;
 
-		printk ("%s: Memory error, status %04x, addr %06lx\n",
+		printk (KERN_ERR "%s: Memory error, status %04x, addr %06lx\n",
 			dev->name, csr0, tst & 0xffffff);
 
 		ll->rdp = LE_C0_STOP;
@@ -674,7 +674,7 @@
 
 	if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ,
 			 lancestr, (void *) dev)) {
-		printk ("Lance: Can't get irq %s\n", __irq_itoa(dev->irq));
+		printk (KERN_ERR "Lance: Can't get irq %s\n", __irq_itoa(dev->irq));
 		return -EAGAIN;
 	}
 
@@ -775,7 +775,7 @@
 
 	/* On the 4m, reset the dma too */
 	if (lp->ledma) {
-		printk ("resetting ledma\n");
+		printk (KERN_NOTICE "resetting ledma\n");
 		lp->ledma->regs->cond_reg |= DMA_RST_ENET;
 		udelay (200);
 		lp->ledma->regs->cond_reg &= ~DMA_RST_ENET;
@@ -789,7 +789,7 @@
 	dev->tbusy = 0;
 	status = init_restart_lance (lp);
 #ifdef DEBUG_DRIVER
-	printk ("Lance restart=%d\n", status);
+	printk (KERN_DEBUG "Lance restart=%d\n", status);
 #endif
 	return status;
 }
@@ -809,7 +809,7 @@
 		if (tickssofar < 100)
 			return 1;
 
-		printk ("%s: transmit timed out, status %04x, reset\n",
+		printk (KERN_ERR "%s: transmit timed out, status %04x, reset\n",
 			dev->name, ll->rdp);
 		lp->stats.tx_errors++;
 		lance_reset (dev);
@@ -986,9 +986,9 @@
 		memset(dev->priv, 0, sizeof (struct lance_private) + 8);
 	}
 	if (sparc_lance_debug && version_printed++ == 0)
-		printk (version);
+		printk (KERN_INFO "%s", version);
 
-	printk ("%s: LANCE ", dev->name);
+	printk (KERN_INFO "%s: LANCE ", dev->name);
 	/* Fill the dev fields */
 	dev->base_addr = (long) sdev;
 
@@ -1061,7 +1061,7 @@
 		if (prop[0] == 0) {
 			int topnd, nd;
 
-			printk("%s: using auto-carrier-detection.\n",
+			printk(KERN_INFO "%s: using auto-carrier-detection.\n",
 			       dev->name);
 
 			/* Is this found at /options .attributes in all
@@ -1081,9 +1081,9 @@
 				       sizeof(prop));
 
 			if (strcmp(prop, "true")) {
-				printk("%s: warning: overriding option "
+				printk(KERN_NOTICE "%s: warning: overriding option "
 				       "'tpe-link-test?'\n", dev->name);
-				printk("%s: warning: mail any problems "
+				printk(KERN_NOTICE "%s: warning: mail any problems "
 				       "to ecd@skynet.be\n", dev->name);
 				set_auxio(AUXIO_LINK_TEST, 0);
 			}
@@ -1106,7 +1106,7 @@
 
 	/* This should never happen. */
 	if ((unsigned long)(lp->init_block->brx_ring) & 0x07) {
-		printk("%s: ERROR: Rx and Tx rings not on even boundary.\n",
+		printk(KERN_ERR "%s: ERROR: Rx and Tx rings not on even boundary.\n",
 		       dev->name);
 		return ENODEV;
 	}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sunqe.c linux.14p16/drivers/net/sunqe.c
--- linux.vanilla/drivers/net/sunqe.c	Wed Oct 20 01:12:39 1999
+++ linux.14p16/drivers/net/sunqe.c	Thu Dec  9 15:33:30 1999
@@ -67,7 +67,7 @@
 	}
 	if(tries)
 		return 0;
-	printk("QuadEther: AIEEE cannot reset the QEC!\n");
+	printk(KERN_ERR "QuadEther: AIEEE cannot reset the QEC!\n");
 	return -1;
 }
 
@@ -91,7 +91,7 @@
 		break;
 	}
 	if(!tries) {
-		printk("QuadEther: AIEEE cannot reset the MACE!\n");
+		printk(KERN_ERR "QuadEther: AIEEE cannot reset the MACE!\n");
 		return -1;
 	}
 
@@ -105,7 +105,7 @@
 		break;
 	}
 	if(!tries) {
-		printk("QuadEther: Cannot reset QE channel!\n");
+		printk(KERN_ERR "QuadEther: Cannot reset QE channel!\n");
 		return -1;
 	}
 	return 0;
@@ -216,7 +216,7 @@
 				break;
 		}
 		if (tries == 0)
-			printk("%s: Warning, link state is down.\n", qep->dev->name);
+			printk(KERN_NOTICE "%s: Warning, link state is down.\n", qep->dev->name);
 	}
 
 	/* Missed packet counter is cleared on a read. */
@@ -240,41 +240,41 @@
 	int mace_hwbug_workaround = 0;
 
 	if(qe_status & CREG_STAT_EDEFER) {
-		printk("%s: Excessive transmit defers.\n", dev->name);
+		printk(KERN_ERR "%s: Excessive transmit defers.\n", dev->name);
 		qep->net_stats.tx_errors++;
 	}
 
 	if(qe_status & CREG_STAT_CLOSS) {
-		printk("%s: Carrier lost, link down?\n", dev->name);
+		printk(KERN_ERR "%s: Carrier lost, link down?\n", dev->name);
 		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);
+		printk(KERN_ERR "%s: Excessive transmit retries (more than 16).\n", dev->name);
 		qep->net_stats.tx_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if(qe_status & CREG_STAT_LCOLL) {
-		printk("%s: Late transmit collision.\n", dev->name);
+		printk(KERN_ERR "%s: Late transmit collision.\n", dev->name);
 		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);
+		printk(KERN_ERR "%s: Transmit fifo underflow, driver bug.\n", dev->name);
 		qep->net_stats.tx_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if(qe_status & CREG_STAT_JERROR) {
-		printk("%s: Jabber error.\n", dev->name);
+		printk(KERN_ERR "%s: Jabber error.\n", dev->name);
 	}
 
 	if(qe_status & CREG_STAT_BERROR) {
-		printk("%s: Babble error.\n", dev->name);
+		printk(KERN_ERR "%s: Babble error.\n", dev->name);
 	}
 
 	if(qe_status & CREG_STAT_CCOFLOW) {
@@ -283,27 +283,27 @@
 	}
 
 	if(qe_status & CREG_STAT_TXDERROR) {
-		printk("%s: Transmit descriptor is bogus, driver bug.\n", dev->name);
+		printk(KERN_ERR "%s: Transmit descriptor is bogus, driver bug.\n", dev->name);
 		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);
+		printk(KERN_ERR "%s: Transmit late error.\n", dev->name);
 		qep->net_stats.tx_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if(qe_status & CREG_STAT_TXPERR) {
-		printk("%s: Transmit DMA parity error.\n", dev->name);
+		printk(KERN_ERR "%s: Transmit DMA parity error.\n", dev->name);
 		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);
+		printk(KERN_ERR "%s: Transmit DMA sbus error ack.\n", dev->name);
 		qep->net_stats.tx_errors++;
 		qep->net_stats.tx_aborted_errors++;
 		mace_hwbug_workaround = 1;
@@ -325,13 +325,13 @@
 	}
 
 	if(qe_status & CREG_STAT_RXFOFLOW) {
-		printk("%s: Receive fifo overflow.\n", dev->name);
+		printk(KERN_ERR "%s: Receive fifo overflow.\n", dev->name);
 		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);
+		printk(KERN_ERR "%s: Late receive collision.\n", dev->name);
 		qep->net_stats.rx_errors++;
 		qep->net_stats.collisions++;
 	}
@@ -347,33 +347,33 @@
 	}
 
 	if(qe_status & CREG_STAT_RXDROP) {
-		printk("%s: Receive packet dropped.\n", dev->name);
+		printk(KERN_INFO "%s: Receive packet dropped.\n", dev->name);
 		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);
+		printk(KERN_ERR "%s: Receive buffer too small, driver bug.\n", dev->name);
 		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);
+		printk(KERN_ERR "%s: Receive late error.\n", dev->name);
 		qep->net_stats.rx_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if(qe_status & CREG_STAT_RXPERR) {
-		printk("%s: Receive DMA parity error.\n", dev->name);
+		printk(KERN_ERR "%s: Receive DMA parity error.\n", dev->name);
 		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);
+		printk(KERN_ERR "%s: Receive DMA sbus error ack.\n", dev->name);
 		qep->net_stats.rx_errors++;
 		qep->net_stats.rx_missed_errors++;
 		mace_hwbug_workaround = 1;
@@ -437,7 +437,7 @@
 	}
 	qep->rx_new = elem;
 	if(drops)
-		printk("%s: Memory squeeze, deferring packet.\n", qep->dev->name);
+		printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", qep->dev->name);
 }
 
 /* Interrupts for all QE's get filtered out via the QEC master controller,
@@ -538,7 +538,7 @@
 		long tickssofar = jiffies - dev->trans_start;
 
 		if (tickssofar >= 40) {
-			printk("%s: transmit timed out, resetting\n", dev->name);
+			printk(KERN_NOTICE "%s: transmit timed out, resetting\n", dev->name);
 			qe_init(qep, 1);
 			dev->tbusy = 0;
 			dev->trans_start = jiffies;
@@ -711,7 +711,7 @@
 		qe_devs[0]->dev_addr[j] = idprom->id_ethaddr[j];
 
 	if(version_printed++ == 0)
-		printk(version);
+		printk(KERN_INFO "%s", version);
 
 	qe_devs[1] = qe_devs[2] = qe_devs[3] = NULL;
 	for(i = 1; i < 4; i++) {
@@ -777,7 +777,7 @@
 					   qranges[k].ot_child_space)
 						break;
 				if(k >= num_qranges)
-					printk("QuadEther: Aieee, bogus QEC range for "
+					printk(KERN_ERR "QuadEther: Aieee, bogus QEC range for "
 					       "space %08x\n",qesdevs[i]->reg_addrs[j].which_io);
 				qesdevs[i]->reg_addrs[j].which_io = qranges[k].ot_parent_space;
 				qesdevs[i]->reg_addrs[j].phys_addr += qranges[k].ot_parent_base;
@@ -796,14 +796,14 @@
 				     "QEC Global Registers",
 				     sdev->reg_addrs[0].which_io, 0);
 	if(!qecp->gregs) {
-		printk("QuadEther: Cannot map QEC global registers.\n");
+		printk(KERN_ERR "QuadEther: Cannot map QEC global registers.\n");
 		res = ENODEV;
 		goto qec_free_devs;
 	}
 
 	/* Make sure the QEC is in MACE mode. */
 	if((qecp->gregs->ctrl & 0xf0000000) != GLOB_CTRL_MMODE) {
-		printk("QuadEther: AIEEE, QEC is not in MACE mode!\n");
+		printk(KERN_ERR "QuadEther: AIEEE, QEC is not in MACE mode!\n");
 		res = ENODEV;
 		goto qec_free_devs;
 	}
@@ -841,7 +841,7 @@
 						 "QEC Per-Channel Registers",
 						 qesdevs[i]->reg_addrs[0].which_io, 0);
 		if(!qeps[i]->qcregs) {
-			printk("QuadEther: Cannot map QE %d's channel registers.\n", i);
+			printk(KERN_ERR "QuadEther: Cannot map QE %d's channel registers.\n", i);
 			res = ENODEV;
 			goto qec_free_devs;
 		}
@@ -852,7 +852,7 @@
 						"QE MACE Registers",
 						qesdevs[i]->reg_addrs[1].which_io, 0);
 		if(!qeps[i]->mregs) {
-			printk("QuadEther: Cannot map QE %d's MACE registers.\n", i);
+			printk(KERN_ERR "QuadEther: Cannot map QE %d's MACE registers.\n", i);
 			res = ENODEV;
 			goto qec_free_devs;
 		}
@@ -888,14 +888,14 @@
 	 */
 	if(request_irq(sdev->irqs[0], &qec_interrupt,
 		       SA_SHIRQ, "QuadEther", (void *) qecp)) {
-		printk("QuadEther: Can't register QEC master irq handler.\n");
+		printk(KERN_ERR "QuadEther: Can't register QEC master irq handler.\n");
 		res = EAGAIN;
 		goto qec_free_devs;
 	}
 
 	/* Report the QE channels. */
 	for(i = 0; i < 4; i++) {
-		printk("%s: QuadEthernet channel[%d] ", qe_devs[i]->name, i);
+		printk(KERN_INFO "%s: QuadEthernet channel[%d] ", qe_devs[i]->name, i);
 		for(j = 0; j < 6; j++)
 			printk ("%2.2x%c",
 				qe_devs[i]->dev_addr[j],
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/syncppp.c linux.14p16/drivers/net/syncppp.c
--- linux.vanilla/drivers/net/syncppp.c	Wed Oct 20 01:12:39 1999
+++ linux.14p16/drivers/net/syncppp.c	Thu Dec  9 15:33:32 1999
@@ -151,7 +151,9 @@
 
 static void if_down(struct device *dev)
 {
-	;
+	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
+
+	sp->pp_link_state=SPPP_LINK_DOWN;
 }
 
 /*
@@ -192,7 +194,7 @@
 	skb->dev=dev;
 	skb->mac.raw=skb->data;
 	
-	if (dev->flags & IFF_UP)
+	if (dev->flags & IFF_RUNNING)
 	{
 		/* Count received bytes, add FCS and one flag */
 		sp->ibytes+= skb->len + 3;
@@ -368,7 +370,7 @@
 
 		/* Keepalive mode disabled or channel down? */
 		if (! (sp->pp_flags & PP_KEEPALIVE) ||
-		    ! (dev->flags & IFF_RUNNING))
+		    ! (dev->flags & IFF_UP))
 			continue;
 
 		/* No keepalive in PPP mode if LCP not opened yet. */
@@ -528,10 +530,10 @@
 		if (h->ident != sp->lcp.confid)
 			break;
 		sppp_clear_timeout (sp);
-		if (! (dev->flags & IFF_UP) &&
-		    (dev->flags & IFF_RUNNING)) {
+		if ((sp->pp_link_state != SPPP_LINK_UP) &&
+		    (dev->flags & IFF_UP)) {
 			/* Coming out of loopback mode. */
-			dev->flags |= IFF_UP;
+			sp->pp_link_state=SPPP_LINK_UP;
 			printk (KERN_INFO "%s: up\n", dev->name);
 		}
 		switch (sp->lcp.state) {
@@ -696,9 +698,9 @@
 			break;
 		}
 		sp->pp_loopcnt = 0;
-		if (! (dev->flags & IFF_UP) &&
-		    (dev->flags & IFF_RUNNING)) {
-			dev->flags |= IFF_UP;
+		if (sp->pp_link_state==SPPP_LINK_DOWN &&
+		    (dev->flags & IFF_UP)) {
+			sp->pp_link_state=SPPP_LINK_UP;
 			printk (KERN_INFO "%s: up\n", dev->name);
 		}
 		break;
@@ -823,7 +825,7 @@
 int sppp_close (struct device *dev)
 {
 	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
-	dev->flags &= ~IFF_RUNNING;
+	sp->pp_link_state = SPPP_LINK_DOWN;
 	sp->lcp.state = LCP_STATE_CLOSED;
 	sp->ipcp.state = IPCP_STATE_CLOSED;
 	sppp_clear_timeout (sp);
@@ -837,9 +839,10 @@
 {
 	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
 	sppp_close(dev);
-	dev->flags |= IFF_RUNNING;
-	if (!(sp->pp_flags & PP_CISCO))
+	if (!(sp->pp_flags & PP_CISCO)) {
 		sppp_lcp_open (sp);
+	}
+	sp->pp_link_state = SPPP_LINK_DOWN;
 	return 0;
 }
 
@@ -849,7 +852,6 @@
 {
 	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
 	sppp_close(dev);
-	dev->flags |= IFF_RUNNING;
 	if (!(sp->pp_flags & PP_CISCO))
 	{
 		sp->lcp.magic = jiffies;
@@ -858,7 +860,8 @@
 		sp->ipcp.state = IPCP_STATE_CLOSED;
 		/* Give it a moment for the line to settle then go */
 		sppp_set_timeout (sp, 1);
-	}
+	} 
+	sp->pp_link_state=SPPP_LINK_DOWN;
 	return 0;
 }
 
@@ -1176,7 +1179,7 @@
 	cli();
 
 	sp->pp_flags &= ~PP_TIMO;
-	if (! (sp->pp_if->flags & IFF_RUNNING) || (sp->pp_flags & PP_CISCO)) {
+	if (! (sp->pp_if->flags & IFF_UP) || (sp->pp_flags & PP_CISCO)) {
 		restore_flags(flags);
 		return;
 	}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/syncppp.h linux.14p16/drivers/net/syncppp.h
--- linux.vanilla/drivers/net/syncppp.h	Sat Feb  6 20:46:21 1999
+++ linux.14p16/drivers/net/syncppp.h	Thu Dec  9 15:33:32 1999
@@ -47,6 +47,7 @@
 	u32		ipkts,opkts;	/* Packets in/out */
 	struct timer_list	pp_timer;
 	struct device	*pp_if;
+	char		pp_link_state;
 };
 
 struct ppp_device
@@ -71,6 +72,9 @@
 #define IPCP_STATE_ACK_RCVD     1       /* IPCP state: conf-ack received */
 #define IPCP_STATE_ACK_SENT     2       /* IPCP state: conf-ack sent */
 #define IPCP_STATE_OPENED       3       /* IPCP state: opened */
+
+#define SPPP_LINK_DOWN		0	/* link down - no keepalive */
+#define SPPP_LINK_UP		1	/* link is up - keepalive ok */
 
 void sppp_attach (struct ppp_device *pd);
 void sppp_detach (struct device *dev);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/tlan.c linux.14p16/drivers/net/tlan.c
--- linux.vanilla/drivers/net/tlan.c	Wed Oct 20 01:12:39 1999
+++ linux.14p16/drivers/net/tlan.c	Mon Dec 13 18:39:41 1999
@@ -32,6 +32,8 @@
  *	Alan Cox	<alan@redhat.com>:	Fixed the out of memory
  *						handling.
  *
+ *	Torben Mathiasen <torben.mathiasen@compaq.com> New Maintainer!
+ *
  ********************************************************************/
 
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/tlan.h linux.14p16/drivers/net/tlan.h
--- linux.vanilla/drivers/net/tlan.h	Sun Aug  9 18:42:41 1998
+++ linux.14p16/drivers/net/tlan.h	Wed Dec 15 23:26:11 1999
@@ -14,6 +14,8 @@
  *
  ** This file is best viewed/edited with tabstop=4, colums>=132
  *
+ *  Dec 10, 1999	Torben Mathiasen <torben.mathiasen@compaq.com>
+ *			New Maintainer
  ********************************************************************/
 
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/tulip.c linux.14p16/drivers/net/tulip.c
--- linux.vanilla/drivers/net/tulip.c	Sat Aug 14 02:27:30 1999
+++ linux.14p16/drivers/net/tulip.c	Tue Dec 21 00:32:36 1999
@@ -1,13 +1,13 @@
 /* tulip.c: A DEC 21040-family ethernet driver for Linux. */
 /*
-	Written 1994-1998 by Donald Becker.
+	Written/copyright 1994-1999 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
 
-	This driver is for the Digital "Tulip" ethernet adapter interface.
+	This driver is for the Digital "Tulip" Ethernet adapter interface.
 	It should work with most DEC 21*4*-based chips/ethercards, as well as
-	PNIC and MXIC chips.
+	with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX.
 
 	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
 	Center of Excellence in Space Data and Information Sciences
@@ -18,7 +18,7 @@
 */
 
 #define SMP_CHECK
-static const char version[] = "tulip.c:v0.89H 5/23/98 becker@cesdis.gsfc.nasa.gov\n";
+static const char version[] = "tulip.c:v0.91g-ppc 7/16/99 becker@cesdis.gsfc.nasa.gov\n";
 
 /* A few user-configurable values. */
 
@@ -60,80 +60,134 @@
 static int rx_copybreak = 100;
 #endif
 
+/*
+  Set the bus performance register.
+	Typical: Set 16 longword cache alignment, no burst limit.
+	Cache alignment bits 15:14	     Burst length 13:8
+		0000	No alignment  0x00000000 unlimited		0800 8 longwords
+		4000	8  longwords		0100 1 longword		1000 16 longwords
+		8000	16 longwords		0200 2 longwords	2000 32 longwords
+		C000	32  longwords		0400 4 longwords
+	Warning: many older 486 systems are broken and require setting 0x00A04800
+	   8 longword cache alignment, 8 longword burst.
+	ToDo: Non-Intel setting could be better.
+*/
+
+#if defined(__alpha__)
+static int csr0 = 0x01A00000 | 0xE000;
+#elif defined(__i386__) || defined(__powerpc__) || defined(__sparc__)
+static int csr0 = 0x01A00000 | 0x8000;
+#else
+#warning Processor architecture undefined!
+static int csr0 = 0x00A00000 | 0x4800;
+#endif
+
 /* Operational parameters that usually are not changed. */
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT  (4*HZ)
+#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
+/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
+   to support a pre-NWay full-duplex signaling mechanism using short frames.
+   No one knows what it should be, but if left at its default value some
+   10base2(!) packets trigger a full-duplex-request interrupt. */
+#define FULL_DUPLEX_MAGIC	0x6969
+
+#if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
 
+#include <linux/config.h>
+#include <linux/version.h>
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
 #include <linux/module.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/timer.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
-
-#include <asm/processor.h>		/* Processor type for cache alignment. */
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <asm/processor.h>		/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
 
-/* Kernel compatibility defines, common to David Hind's PCMCIA package.
+/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
    This is only in the support-all-kernels source code. */
-#include <linux/version.h>		/* Evil, but neccessary */
 
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10300
-#define RUN_AT(x) (x)			/* What to put in timer->expires.  */
-#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
-#define virt_to_bus(addr)  ((unsigned long)addr)
-#define bus_to_virt(addr) ((void*)addr)
+#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(reverse_probe, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(csr0, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+#endif
 
-#else  /* 1.3.0 and later */
 #define RUN_AT(x) (jiffies + (x))
-#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
-#endif
 
-#if (LINUX_VERSION_CODE >= 0x10344)
-#define NEW_MULTICAST
-#include <linux/delay.h>
-#endif
-#ifdef SA_SHIRQ
-#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
-#else
-#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
+#if (LINUX_VERSION_CODE >= 0x20100)
+static char kernel_version[] = UTS_RELEASE;
 #endif
 
-#if (LINUX_VERSION_CODE < 0x20123)
+#if LINUX_VERSION_CODE < 0x20123
 #define hard_smp_processor_id() smp_processor_id()
 #define test_and_set_bit(val, addr) set_bit(val, addr)
+#define le16_to_cpu(val) (val)
+#define le32_to_cpu(val) (val)
+#define cpu_to_le32(val) (val)
 #endif
-
-/* This my implementation of shared IRQs, now only used for 1.2.13. */
-#ifdef HAVE_SHARED_IRQ
-#define USE_SHARED_IRQ
-#include <linux/shared_irq.h>
+#if LINUX_VERSION_CODE <= 0x20139
+#define	net_device_stats enet_statistics
+#else
+#define NETSTATS_VER2
 #endif
-
-/* The total size is unusually large: The 21040 aligns each of its 16
-   longword-wide registers on a quadword boundary. */
-#define TULIP_TOTAL_SIZE 0x80
-
-#ifdef HAVE_DEVLIST
-struct netdev_entry tulip_drv =
-{"Tulip", tulip_pci_probe, TULIP_TOTAL_SIZE, NULL};
+#if LINUX_VERSION_CODE < 0x20155
+/* Grrrr, the PCI code changed, but did not consider CardBus... */
+#include <linux/bios32.h>
+#define PCI_SUPPORT_VER1
+#else
+#define PCI_SUPPORT_VER2
+#endif
+#if LINUX_VERSION_CODE < 0x20159
+#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
+#else
+#define dev_free_skb(skb) dev_kfree_skb(skb);
+#endif
+#if ! defined(CAP_NET_ADMIN)
+#define capable(CAP_XXX) (suser())
 #endif
+#if ! defined(HAS_NETIF_QUEUE)
+#define netif_wake_queue(dev)  mark_bh(NET_BH);
+#endif
+
+/* Condensed operations for readability. */
+#define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
 
+#define tulip_debug debug
 #ifdef TULIP_DEBUG
-int tulip_debug = TULIP_DEBUG;
+static int tulip_debug = TULIP_DEBUG;
 #else
-int tulip_debug = 1;
+static int tulip_debug = 1;
 #endif
 
 /*
@@ -143,17 +197,27 @@
 
 This device driver is designed for the DECchip "Tulip", Digital's
 single-chip ethernet controllers for PCI.  Supported members of the family
-are the 21040, 21041, 21140, 21140A, 21142, and 21143.  These chips are used on
-many PCI boards including the SMC EtherPower series.
-
+are the 21040, 21041, 21140, 21140A, 21142, and 21143.  Similar work-alike
+chips from Lite-On, Macronics, ASIX, Compex and other listed below are also
+supported. 
+
+These chips are used on at least 140 unique PCI board designs.  The great
+number of chips and board designs supported is the reason for the
+driver size and complexity.  Almost of the increasing complexity is in the
+board configuration and media selection code.  There is very little
+increasing in the operational critical path length.
 
 II. Board-specific settings
 
 PCI bus devices are configured by the system at boot time, so no jumpers
 need to be set on the board.  The system BIOS preferably should assign the
 PCI INTA signal to an otherwise unused system IRQ line.
-Note: Kernel versions earlier than 1.3.73 do not support shared PCI
-interrupt lines.
+
+Some boards have EEPROMs tables with default media entry.  The factory default
+is usually "autoselect".  This should only be overridden when using
+transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!)
+for forcing full-duplex when used with old link partners that do not do
+autonegotiation. 
 
 III. Driver operation
 
@@ -201,111 +265,159 @@
 
 IV. Notes
 
-Thanks to Duke Kamstra of SMC for providing an EtherPower board.
+Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board.
+Greg LaPolla at Linksys provided PNIC and other Linksys boards.
+Znyx provided a four-port card for testing.
 
 IVb. References
 
 http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
 http://www.digital.com  (search for current 21*4* datasheets and "21X4 SROM")
-http://www.national.com/pf/DP/DP83840.html
+http://www.national.com/pf/DP/DP83840A.html
+http://www.asix.com.tw/pmac.htm
+http://www.admtek.com.tw/
 
 IVc. Errata
 
-The DEC databook doesn't document which Rx filter settings accept broadcast
-packets.  Nor does it document how to configure the part to configure the
-serial subsystem for normal (vs. loopback) operation or how to have it
-autoswitch between internal 10baseT, SIA and AUI transceivers.
-
+The old DEC databooks were light on details.
 The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last
-register of the set CSR12-15 written.  Hmmm, now how is that possible?  */
-
-
-/* A few values that may be tweaked. */
-#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
+register of the set CSR12-15 written.  Hmmm, now how is that possible?
 
-/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
-   to support a pre-NWay full-duplex signaling mechanism using short frames.
-   No one knows what it should be, but if left at its default value some
-   10base2(!) packets trigger a full-duplex-request interrupt. */
-#define FULL_DUPLEX_MAGIC	0x6969
+The DEC SROM format is very badly designed not precisely defined, leading to
+part of the media selection junkheap below.  Some boards do not have EEPROM
+media tables and need to be patched up.  Worse, other boards use the DEC
+design kit media table when it isn't correct for their board.
 
-#ifndef PCI_VENDOR_ID_DEC		/* Now defined in linux/pci.h */
-#define PCI_VENDOR_ID_DEC			0x1011
-#define PCI_DEVICE_ID_TULIP			0x0002		/* 21040. */
-#define PCI_DEVICE_ID_TULIP_FAST	0x0009		/* 21140. */
-#endif
+We cannot use MII interrupts because there is no defined GPIO pin to attach
+them.  The MII transceiver status is polled using an kernel timer.
 
-#ifndef PCI_DEVICE_ID_DEC_TULIP_PLUS
-#define PCI_DEVICE_ID_DEC_TULIP_PLUS	0x0014		/* 21041. */
-#endif
-#ifndef PCI_DEVICE_ID_DEC_TULIP_21142
-#define PCI_DEVICE_ID_DEC_TULIP_21142	0x0019
-#endif
+*/
 
-#ifndef PCI_VENDOR_ID_LITEON
-#define PCI_VENDOR_ID_LITEON	0x11AD
-#endif
+static struct device *
+tulip_probe1(int pci_bus, int pci_devfn, struct device *dev, long ioaddr,
+			 int irq, int chip_idx, int board_idx);
+
+/* This table drives the PCI probe routines.  It's mostly boilerplate in all
+   of the drivers, and will likely be provided by some future kernel.
+   Note the matching code -- the first table entry matchs all 56** cards but
+   second only the 1234 card.
+*/
+enum pci_flags_bit {
+	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
+	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+};
+#define PCI_ADDR0_IO (PCI_USES_IO|PCI_ADDR0)
 
-#ifndef PCI_VENDOR_ID_MXIC
-#define	PCI_VENDOR_ID_MXIC		0x10d9
-#define PCI_DEVICE_ID_MX98713	0x0512
-#define PCI_DEVICE_ID_MX98715	0x0531
-#define PCI_DEVICE_ID_MX98725	0x0531
-#endif
+struct pci_id_info {
+	const char *name;
+	u16	vendor_id, device_id, device_id_mask, flags;
+	int io_size, min_latency;
+	struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev,
+							 long ioaddr, int irq, int chip_idx, int fnd_cnt);
+};
+#ifndef CARDBUS
+static struct pci_id_info pci_tbl[] = {
+  { "Digital DC21040 Tulip",
+	0x1011, 0x0002, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  { "Digital DC21041 Tulip",
+	0x1011, 0x0014, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  { "Digital DS21140 Tulip",
+	0x1011, 0x0009, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  { "Digital DS21143 Tulip",
+	0x1011, 0x0019, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  { "Lite-On 82c168 PNIC",
+	0x11AD, 0x0002, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
+  { "Macronix 98713 PMAC",
+	0x10d9, 0x0512, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
+  { "Macronix 98715 PMAC",
+	0x10d9, 0x0531, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
+  { "Macronix 98725 PMAC",
+	0x10d9, 0x0531, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
+  { "ASIX AX88140",
+	0x125B, 0x1400, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  { "Lite-On LC82C115 PNIC-II",
+	0x11AD, 0xc115, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
+  { "ADMtek AN981 Comet",
+	0x1317, 0x0981, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
+  { "Compex RL100-TX",
+	0x11F6, 0x9881, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  { "Intel 21145 Tulip",
+	0x8086, 0x0039, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  { "Xircom Tulip clone",
+	0x115d, 0x0003, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  {0},
+};
+#endif /* !CARD_BUS */
 
-/* The rest of these values should never change. */
+/* This table use during operation for capabilities and media timer. */
 
 static void tulip_timer(unsigned long data);
 static void t21142_timer(unsigned long data);
 static void mxic_timer(unsigned long data);
 static void pnic_timer(unsigned long data);
+static void comet_timer(unsigned long data);
 
-/* A table describing the chip types. */
-enum tbl_flag { HAS_MII=1, HAS_MEDIA_TABLE = 2, CSR12_IN_SROM = 4,};
+enum tbl_flag {
+	HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8,
+	HAS_PWRDWN=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */
+	HAS_PNICNWAY=0x80, HAS_NWAY143=0x40,	/* Uses internal NWay xcvr. */
+	HAS_8023X=0x100,
+};
 static struct tulip_chip_table {
-	int vendor_id, device_id;
 	char *chip_name;
 	int io_size;
 	int valid_intrs;			/* CSR7 interrupt enable settings */
 	int flags;
 	void (*media_timer)(unsigned long data);
 } tulip_tbl[] = {
-  { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP,
-	"Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
-  { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS,
-	"Digital DC21041 Tulip", 128, 0x0001ebef, HAS_MEDIA_TABLE, tulip_timer },
-  { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST,
-	"Digital DS21140 Tulip", 128, 0x0001ebef,
-	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM,
-	tulip_timer },
-  { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_21142,
-	"Digital DS21142/3 Tulip", 128, 0x0801fbff,
-	HAS_MII | HAS_MEDIA_TABLE, t21142_timer },
-  { PCI_VENDOR_ID_LITEON, 0x0002,
-	"Lite-On 82c168 PNIC", 256, 0x0001ebef, HAS_MII, pnic_timer },
-  { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98713,
-	"Macronix 98713 PMAC", 128, 0x0001ebef,
-	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer /* Tulip-like! */ },
-  { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98715,
-	"Macronix 98715 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer },
-  { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98725,
-	"Macronix 98725 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer },
-  { 0x125B, 0x1400, "ASIX AX88140", 128, 0x0001fbff,
+  { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
+  { "Digital DC21041 Tulip", 128, 0x0001ebff, HAS_MEDIA_TABLE, tulip_timer },
+  { "Digital DS21140 Tulip", 128, 0x0001ebef,
 	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
-  {0, 0, 0, 0},
+  { "Digital DS21143 Tulip", 128, 0x0801fbff,
+	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143,
+	t21142_timer },
+  { "Lite-On 82c168 PNIC", 256, 0x0001ebef,
+	HAS_MII | HAS_PNICNWAY, pnic_timer },
+  { "Macronix 98713 PMAC", 128, 0x0001ebef,
+	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+  { "Macronix 98715 PMAC", 256, 0x0001ebef,
+	HAS_MEDIA_TABLE, mxic_timer },
+  { "Macronix 98725 PMAC", 256, 0x0001ebef,
+	HAS_MEDIA_TABLE, mxic_timer },
+  { "ASIX AX88140", 128, 0x0001fbff,
+	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer },
+  { "Lite-On PNIC-II", 256, 0x0801fbff,
+	HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer },
+  { "ADMtek Comet", 256, 0x0001abef,
+	MC_HASH_ONLY, comet_timer },
+  { "Compex 9881 PMAC", 128, 0x0001ebef,
+	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+  { "Intel DS21145 Tulip", 128, 0x0801fbff,
+	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143,
+	t21142_timer },
+  { "Xircom tulip work-alike", 128, 0x0801fbff,
+	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143,
+	t21142_timer },
+  {0},
+};
+/* This matches the table above.  Note 21142 == 21143. */
+enum chips {
+	DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
+	LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMPEX9881,
+	I21145,
 };
-/* This matches the table above. */
-enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
-			 LC82C168, MX98713, MX98715, MX98725};
 
 /* A full-duplex map for media types. */
-enum MediaIs {MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
-		  MediaIs100=16};
+enum MediaIs {
+	MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
+	MediaIs100=16};
 static const char media_cap[] =
 {0,0,0,16,  3,19,16,24,  27,4,7,5, 0,20,23,20 };
+static u8 t21040_csr13[] = {2,0x0C,8,4,  4,0,0,0, 0,0,0,0, 4,0,0,0};
 /* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
-static u16 t21041_csr13[] = { 0xEF05, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
-static u16 t21041_csr14[] = { 0x7F3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
+static u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
+static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
 static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
 
 static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };
@@ -321,16 +433,12 @@
 
 /* The bits in the CSR5 status registers, mostly interrupt sources. */
 enum status_bits {
-	TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10,
+	TimerInt=0x800, SytemError=0x2000, TPLnkFail=0x1000, TPLnkPass=0x10,
 	NormalIntr=0x10000, AbnormalIntr=0x8000,
 	RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40,
 	TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
 };
 
-enum desc_status_bits {
-	DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300,
-};
-        
 /* The Tulip Rx and Tx buffer descriptors. */
 struct tulip_rx_desc {
 	s32 status;
@@ -344,6 +452,22 @@
 	u32 buffer1, buffer2;				/* We use only buffer 1.  */
 };
 
+enum desc_status_bits {
+	DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300,
+};
+
+/* Ring-wrap flag in length field, use for last ring entry.
+	0x01000000 means chain on buffer2 address,
+	0x02000000 means use the ring start address in CSR2/3.
+   Note: Some work-alike chips do not function correctly in chained mode.
+   The ASIX chip works only in chained mode.
+   Thus we indicates ring mode, but always write the 'next' field for
+   chained mode as well.
+*/
+#define DESC_RING_WRAP 0x02000000
+
+#define EEPROM_SIZE 128 	/* 2 << EEPROM_ADDRLEN */
+
 struct medialeaf {
 	u8 type;
 	u8 media;
@@ -353,7 +477,8 @@
 struct mediatable {
 	u16 defaultmedia;
 	u8 leafcount, csr12dir;				/* General purpose pin directions. */
-	unsigned has_mii:1, has_nonmii:1;
+	unsigned has_mii:1, has_nonmii:1, has_reset:6;
+	u32 csr15dir, csr15val;				/* 21143 NWay setting. */
 	struct medialeaf mleaf[0];
 };
 
@@ -375,19 +500,13 @@
 	/* The addresses of receive-in-place skbuffs. */
 	struct sk_buff* rx_skbuff[RX_RING_SIZE];
 	char *rx_buffs;				/* Address of temporary Rx buffers. */
-	u32 setup_frame[48];		/* Pseudo-Tx frame to init address table. */
+	u16 setup_frame[96];		/* Pseudo-Tx frame to init address table. */
 	int chip_id;
 	int revision;
-#if LINUX_VERSION_CODE > 0x20139
+	int flags;
 	struct net_device_stats stats;
-#else
-	struct enet_statistics stats;
-#endif
 	struct timer_list timer;	/* Media selection timer. */
 	int interrupt;				/* In-interrupt flag. */
-#ifdef SMP_CHECK
-	int smp_proc_id;			/* Which processor in IRQ handler. */
-#endif
 	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
 	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
 	unsigned int tx_full:1;				/* The Tx queue is full. */
@@ -398,134 +517,134 @@
 	unsigned int media2:4;				/* Secondary monitored media port. */
 	unsigned int medialock:1;			/* Don't sense media type. */
 	unsigned int mediasense:1;			/* Media sensing in progress. */
+	unsigned int nway:1, nwayset:1;		/* 21143 internal NWay. */
+	unsigned int csr0;					/* CSR0 setting. */
 	unsigned int csr6;					/* Current CSR6 control settings. */
-	unsigned char eeprom[128];			/* Serial EEPROM contents. */
+	unsigned char eeprom[EEPROM_SIZE];	/* Serial EEPROM contents. */
+	void (*link_change)(struct device *dev, int csr5);
 	u16 to_advertise;					/* NWay capabilities advertised.  */
+	u16 lpar;							/* 21143 Link partner ability. */
 	u16 advertising[4];
 	signed char phys[4], mii_cnt;		/* MII device addresses. */
 	struct mediatable *mtable;
 	int cur_index;						/* Current media index. */
-	unsigned char pci_bus, pci_dev_fn;
+	int saved_if_port;
+	unsigned char pci_bus, pci_devfn;
+	int ttimer;
+	int susp_rx;
+	unsigned long nir;
 	int pad0, pad1;						/* Used for 8-byte alignment */
 };
 
-static struct device *tulip_probe1(int pci_bus, int pci_devfn,
-								   struct device *dev,
-								   int chip_id, int options);
 static void parse_eeprom(struct device *dev);
-static int read_eeprom(long ioaddr, int location);
+static int read_eeprom(long ioaddr, int location, int addr_len);
 static int mdio_read(struct device *dev, int phy_id, int location);
 static void mdio_write(struct device *dev, int phy_id, int location, int value);
 static void select_media(struct device *dev, int startup);
 static int tulip_open(struct device *dev);
-static void tulip_timer(unsigned long data);
+/* Chip-specific media selection (timer functions prototyped above). */
+static void t21142_lnk_change(struct device *dev, int csr5);
+static void t21142_start_nway(struct device *dev);
+static void pnic_lnk_change(struct device *dev, int csr5);
+static void pnic_do_nway(struct device *dev);
+
 static void tulip_tx_timeout(struct device *dev);
 static void tulip_init_ring(struct device *dev);
 static int tulip_start_xmit(struct sk_buff *skb, struct device *dev);
+static int tulip_refill_rx(struct device *dev);
 static int tulip_rx(struct device *dev);
-static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs);
+static void tulip_interrupt(int irq, void *dev_instance, 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);
 #ifdef HAVE_PRIVATE_IOCTL
 static int private_ioctl(struct device *dev, struct ifreq *rq, int cmd);
 #endif
-#ifdef NEW_MULTICAST
 static void set_rx_mode(struct device *dev);
-#else
-static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
-#endif
 
 
 
-/* A list of all installed Tulip devices, for removing the driver module. */
+/* A list of all installed Tulip devices. */
 static struct device *root_tulip_dev = NULL;
 
-/* This 21040 probe no longer uses a large fixed contiguous Rx buffer region,
-   but now receives directly into full-sized skbuffs that are allocated
-   at open() time.
-   This allows the probe routine to use the old driver initialization
-   interface. */
-
+#ifndef CARDBUS
 int tulip_probe(struct device *dev)
 {
 	int cards_found = 0;
-	static int pci_index = 0;	/* Static, for multiple probe calls. */
+	int pci_index = 0;
 	unsigned char pci_bus, pci_device_fn;
 
-	/* Ideally we would detect all network cards in slot order.  That would
-	   be best done a central PCI probe dispatch, which wouldn't work
-	   well with the current structure.  So instead we detect just the
-	   Tulip cards in slot order. */
-
-#if LINUX_VERSION_CODE >= 0x20155
-	if (! pci_present())
-		return -ENODEV;
-#else
-	if (! pcibios_present())
+	if ( ! pcibios_present())
 		return -ENODEV;
-#endif
+
 	for (;pci_index < 0xff; pci_index++) {
 		u16 vendor, device, pci_command, new_command;
-		unsigned long pci_ioaddr = 0;
-		int chip_idx = 0;
+		int chip_idx;
+		int irq;
+		long ioaddr;
 
 		if (pcibios_find_class
 			(PCI_CLASS_NETWORK_ETHERNET << 8,
 			 reverse_probe ? 0xfe - pci_index : pci_index,
-			 &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
+			 &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) {
 			if (reverse_probe)
 				continue;
 			else
 				break;
+		}
 		pcibios_read_config_word(pci_bus, pci_device_fn,
 								 PCI_VENDOR_ID, &vendor);
 		pcibios_read_config_word(pci_bus, pci_device_fn,
 								 PCI_DEVICE_ID, &device);
 
-		for (chip_idx = 0; tulip_tbl[chip_idx].chip_name; chip_idx++)
-			if (vendor == tulip_tbl[chip_idx].vendor_id  &&
-				device == tulip_tbl[chip_idx].device_id)
+		for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
+			if (vendor == pci_tbl[chip_idx].vendor_id
+				&& (device & pci_tbl[chip_idx].device_id_mask) ==
+				pci_tbl[chip_idx].device_id)
 				break;
-		if (tulip_tbl[chip_idx].chip_name == 0) {
-			if (vendor == PCI_VENDOR_ID_DEC  ||
-				vendor == PCI_VENDOR_ID_LITEON)
-				printk(KERN_INFO "Unknown Tulip-style PCI ethernet chip type"
-					   " %4.4x %4.4x"" detected: not configured.\n",
-					   vendor, device);
+		if (pci_tbl[chip_idx].vendor_id == 0)
 			continue;
-		}
-#if LINUX_VERSION_CODE >= 0x20155
-		pci_ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0];
-#else
-		pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
-								  &pci_ioaddr);
+
+		{
+#if defined(PCI_SUPPORT_VER2)
+			struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
+			ioaddr = pdev->base_address[0] & ~3;
+			irq = pdev->irq;
+#else
+			u32 pci_ioaddr;
+			u8 pci_irq_line;
+			pcibios_read_config_dword(pci_bus, pci_device_fn,
+									  PCI_BASE_ADDRESS_0, &pci_ioaddr);
+			pcibios_read_config_byte(pci_bus, pci_device_fn,
+									 PCI_INTERRUPT_LINE, &pci_irq_line);
+			ioaddr = pci_ioaddr & ~3;
+			irq = pci_irq_line;
 #endif
-		/* Remove I/O space marker in bit 0. */
-		pci_ioaddr &= ~3;
+		}
 
-		if (tulip_debug > 2)
-			printk(KERN_DEBUG "Found %s at I/O %#lx.\n",
-				   tulip_tbl[chip_idx].chip_name, pci_ioaddr);
+		if (debug > 2)
+			printk(KERN_INFO "Found %s at PCI I/O address %#lx.\n",
+				   pci_tbl[chip_idx].name, ioaddr);
 
-		if (check_region(pci_ioaddr, tulip_tbl[chip_idx].io_size))
+		if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
 			continue;
 
 		pcibios_read_config_word(pci_bus, pci_device_fn,
 								 PCI_COMMAND, &pci_command);
 		new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
 		if (pci_command != new_command) {
-			printk(KERN_INFO "  The PCI BIOS has not enabled this"
-				   " device!  Updating PCI command %4.4x->%4.4x.\n",
-				   pci_command, new_command);
+			printk(KERN_INFO "  The PCI BIOS has not enabled the"
+				   " device at %d/%d!  Updating PCI command %4.4x->%4.4x.\n",
+				   pci_bus, pci_device_fn, pci_command, new_command);
 			pcibios_write_config_word(pci_bus, pci_device_fn,
 									  PCI_COMMAND, new_command);
 		}
 
-		dev = tulip_probe1(pci_bus, pci_device_fn, dev, chip_idx, cards_found);
+		dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, dev, ioaddr,
+									   irq, chip_idx, cards_found);
 
 		/* Get and check the bus-master and latency values. */
 		if (dev) {
-			unsigned char pci_latency;
+			u8 pci_latency;
 			pcibios_read_config_byte(pci_bus, pci_device_fn,
 									 PCI_LATENCY_TIMER, &pci_latency);
 			if (pci_latency < 10) {
@@ -534,75 +653,62 @@
 					   pci_latency);
 				pcibios_write_config_byte(pci_bus, pci_device_fn,
 										  PCI_LATENCY_TIMER, 64);
-			} else if (tulip_debug > 1)
-				printk(KERN_INFO "  PCI latency timer (CFLT) is %#x, "
-					   " PCI command is %4.4x.\n",
-					   pci_latency, new_command);
-			/* Bring the 21143 out power-down mode. */
-			if (device == PCI_DEVICE_ID_DEC_TULIP_21142)
-				pcibios_write_config_dword(pci_bus, pci_device_fn,
-										   0x40, 0x40000000);
-			dev = 0;
-			cards_found++;
+			}
 		}
+		dev = 0;
+		cards_found++;
 	}
 
 	return cards_found ? 0 : -ENODEV;
 }
+#endif  /* not CARDBUS */
 
-static struct device *tulip_probe1(int pci_bus, int pci_device_fn,
-								   struct device *dev,
-								   int chip_id, int board_idx)
+static struct device *tulip_probe1(int pci_bus, int pci_devfn,
+								   struct device *dev, long ioaddr, int irq,
+								   int chip_idx, int board_idx)
 {
 	static int did_version = 0;			/* Already printed version info. */
 	struct tulip_private *tp;
-	long ioaddr;
-	int irq;
 	/* See note below on the multiport cards. */
 	static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
 	static int last_irq = 0;
 	static int multiport_cnt = 0;		/* For four-port boards w/one EEPROM */
+	u8 chip_rev;
 	int i;
 	unsigned short sum;
+	u8 ee_data[EEPROM_SIZE];
 
 	if (tulip_debug > 0  &&  did_version++ == 0)
 		printk(KERN_INFO "%s", version);
 
 	dev = init_etherdev(dev, 0);
 
-#if LINUX_VERSION_CODE >= 0x20155
-	irq = pci_find_slot(pci_bus, pci_device_fn)->irq;
-	ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0];
-#else
-	{
-		u8 pci_irq_line;
-		u32 pci_ioaddr;
-		pcibios_read_config_byte(pci_bus, pci_device_fn,
-								 PCI_INTERRUPT_LINE, &pci_irq_line);
-		pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
-								  &pci_ioaddr);
-		irq = pci_irq_line;
-		ioaddr = pci_ioaddr;
-	}
-#endif
-	/* Remove I/O space marker in bit 0. */
-	ioaddr &= ~3;
+	/* Make certain the data structures are quadword aligned. */
+	tp = (void *)(((long)kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA) + 7) & ~7);
+	memset(tp, 0, sizeof(*tp));
+	dev->priv = tp;
+
+	tp->next_module = root_tulip_dev;
+	root_tulip_dev = dev;
+
+	pcibios_read_config_byte(pci_bus, pci_devfn, PCI_REVISION_ID, &chip_rev);
+
+	/* Bring the 21041/21143 out of sleep mode.
+	   Caution: Snooze mode does not work with some boards! */
+	if (tulip_tbl[chip_idx].flags & HAS_PWRDWN)
+		pcibios_write_config_dword(pci_bus, pci_devfn, 0x40, 0x00000000);
 
-	printk(KERN_INFO "%s: %s at %#3lx,",
-		   dev->name, tulip_tbl[chip_id].chip_name, ioaddr);
+	printk(KERN_INFO "%s: %s rev %d at %#3lx,",
+		   dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
 
 	/* Stop the chip's Tx and Rx processes. */
 	outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
 	/* Clear the missed-packet counter. */
 	(volatile int)inl(ioaddr + CSR8);
 
-	if (chip_id == DC21041) {
-		if (inl(ioaddr + CSR9) & 0x8000) {
-			printk(" 21040 compatible mode,");
-			chip_id = DC21040;
-		} else {
-			printk(" 21041 mode,");
-		}
+	if (chip_idx == DC21041  &&  inl(ioaddr + CSR9) & 0x8000) {
+		printk(" 21040 compatible mode,");
+		chip_idx = DC21040;
 	}
 
 	/* The station address ROM is read byte serially.  The register must
@@ -610,7 +716,7 @@
 	   EEPROM.
 	   */
 	sum = 0;
-	if (chip_id == DC21040) {
+	if (chip_idx == DC21040) {
 		outl(0, ioaddr + CSR9);		/* Reset the pointer with a dummy write. */
 		for (i = 0; i < 6; i++) {
 			int value, boguscnt = 100000;
@@ -620,28 +726,34 @@
 			dev->dev_addr[i] = value;
 			sum += value & 0xff;
 		}
-	} else if (chip_id == LC82C168) {
+	} else if (chip_idx == LC82C168) {
 		for (i = 0; i < 3; i++) {
 			int value, boguscnt = 100000;
 			outl(0x600 | i, ioaddr + 0x98);
 			do
 				value = inl(ioaddr + CSR9);
 			while (value < 0  && --boguscnt > 0);
-			((u16*)dev->dev_addr)[i] = value;
+			put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i);
 			sum += value & 0xffff;
 		}
-	} else {	/* Must be a new chip, with a serial EEPROM interface. */
-		/* We read the whole EEPROM, and sort it out later.  DEC has a
-		   specification _Digital Semiconductor 21X4 Serial ROM Format_
-		   but early vendor boards just put the address in the first six
-		   EEPROM locations. */
-		unsigned char ee_data[128];
+	} else if (chip_idx == COMET) {
+		/* No need to read the EEPROM. */
+		put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr);
+		put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4));
+		for (i = 0; i < 6; i ++)
+			sum += dev->dev_addr[i];
+	} else {
+		/* A serial EEPROM interface, we read now and sort it out later. */
 		int sa_offset = 0;
+		int ee_addr_size = read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
 
 		for (i = 0; i < sizeof(ee_data)/2; i++)
-			((u16 *)ee_data)[i] = read_eeprom(ioaddr, i);
+			((u16 *)ee_data)[i] =
+				le16_to_cpu(read_eeprom(ioaddr, i, ee_addr_size));
 
-		/* Detect the simple EEPROM format by the duplicated station addr. */
+		/* DEC now has a specification (see Notes) but early board makers
+		   just put the address in the first EEPROM locations. */
+		/* This does  memcmp(eedata, eedata+16, 8) */
 		for (i = 0; i < 8; i ++)
 			if (ee_data[i] != ee_data[16+i])
 				sa_offset = 20;
@@ -655,7 +767,8 @@
 		}
 	}
 	/* Lite-On boards have the address byte-swapped. */
-	if (dev->dev_addr[0] == 0xA0  &&  dev->dev_addr[1] == 0x00)
+	if ((dev->dev_addr[0] == 0xA0  ||  dev->dev_addr[0] == 0xC0)
+		&&  dev->dev_addr[1] == 0x00)
 		for (i = 0; i < 6; i+=2) {
 			char tmp = dev->dev_addr[i];
 			dev->dev_addr[i] = dev->dev_addr[i+1];
@@ -671,34 +784,37 @@
 		for (i = 0; i < 5; i++)
 			dev->dev_addr[i] = last_phys_addr[i];
 		dev->dev_addr[i] = last_phys_addr[i] + 1;
-#if defined(__i386__)		/* This BIOS bug doesn't exist on Alphas. */
-		irq = last_irq;
+#if defined(__i386__)		/* Patch up x86 BIOS bug. */
+		if (last_irq)
+			irq = last_irq;
 #endif
 	}
 
 	for (i = 0; i < 6; i++)
-		printk(" %2.2x", last_phys_addr[i] = dev->dev_addr[i]);
+		printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]);
 	printk(", IRQ %d.\n", irq);
 	last_irq = irq;
 
 	/* We do a request_region() only to register /proc/ioports info. */
-	/* Note that proper size is tulip_tbl[chip_id].chip_name, but... */
-	request_region(ioaddr, TULIP_TOTAL_SIZE, dev->name);
+	/* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */
+	request_region(ioaddr, tulip_tbl[chip_idx].io_size, dev->name);
 
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 
-	/* Make certain the data structures are quadword aligned. */
-	tp = (void *)(((long)kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA) + 7) & ~7);
-	memset(tp, 0, sizeof(*tp));
-	dev->priv = tp;
-
-	tp->next_module = root_tulip_dev;
-	root_tulip_dev = dev;
-
 	tp->pci_bus = pci_bus;
-	tp->pci_dev_fn = pci_device_fn;
-	tp->chip_id = chip_id;
+	tp->pci_devfn = pci_devfn;
+	tp->chip_id = chip_idx;
+	tp->revision = chip_rev;
+	tp->flags = tulip_tbl[chip_idx].flags;
+	tp->csr0 = csr0;
+
+	/* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles.
+	   And the ASIX must have a burst limit or horrible things happen. */
+	if (chip_idx == DC21143  &&  chip_rev == 65)
+		tp->csr0 &= ~0x01000000;
+	else if (chip_idx == AX88140)
+		tp->csr0 |= 0x2000;
 
 #ifdef TULIP_FULL_DUPLEX
 	tp->full_duplex = 1;
@@ -729,37 +845,58 @@
 	if (tp->full_duplex)
 		tp->full_duplex_lock = 1;
 
-	/* This is logically part of probe1(), but too complex to write inline. */
-	if (tulip_tbl[chip_id].flags & HAS_MEDIA_TABLE)
-		parse_eeprom(dev);
-
 	if (media_cap[tp->default_port] & MediaIsMII) {
 		u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
 		tp->to_advertise = media2advert[tp->default_port - 9];
-	} else
-		tp->to_advertise = 0x03e1;
+	} else if (tp->flags & HAS_8023X)
+		tp->to_advertise = 0x05e1;
+	else 
+		tp->to_advertise = 0x01e1;
+
+	/* This is logically part of probe1(), but too complex to write inline. */
+	if (tp->flags & HAS_MEDIA_TABLE) {
+		memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom));
+		parse_eeprom(dev);
+	}
 
-	if ((tp->mtable  &&  tp->mtable->has_mii) ||
-		( ! tp->mtable  &&  (tulip_tbl[tp->chip_id].flags & HAS_MII))) {
+	if ((tp->flags & ALWAYS_CHECK_MII) ||
+		(tp->mtable  &&  tp->mtable->has_mii) ||
+		( ! tp->mtable  &&  (tp->flags & HAS_MII))) {
 		int phy, phy_idx;
+		if (tp->mtable  &&  tp->mtable->has_mii) {
+			for (i = 0; i < tp->mtable->leafcount; i++)
+				if (tp->mtable->mleaf[i].media == 11) {
+					tp->cur_index = i;
+					tp->saved_if_port = dev->if_port;
+					select_media(dev, 1);
+					dev->if_port = tp->saved_if_port;
+					break;
+				}
+		}
 		/* Find the connected MII xcvrs.
 		   Doing this in open() would allow detecting external xcvrs later,
 		   but takes much time. */
 		for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
 			 phy++) {
 			int mii_status = mdio_read(dev, phy, 1);
-			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+			if ((mii_status & 0x8301) == 0x8001 ||
+				((mii_status & 0x8000) == 0  && (mii_status & 0x7800) != 0)) {
 				int mii_reg0 = mdio_read(dev, phy, 0);
+				int mii_advert = mdio_read(dev, phy, 4);
 				int reg4 = ((mii_status>>6) & tp->to_advertise) | 1;
 				tp->phys[phy_idx] = phy;
 				tp->advertising[phy_idx++] = reg4;
-				printk(KERN_INFO "%s:  MII transceiver found at MDIO address "
-					   "%d, config %4.4x status %4.4x.\n",
-					   dev->name, phy, mii_reg0, mii_status);
-				if (1 || (media_cap[tp->default_port] & MediaIsMII)) {
+				printk(KERN_INFO "%s:  MII transceiver #%d "
+					   "config %4.4x status %4.4x advertising %4.4x.\n",
+					   dev->name, phy, mii_reg0, mii_status, mii_advert);
+				/* Fixup for DLink with miswired PHY. */
+				if (mii_advert != reg4) {
 					printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d,"
 						   " previously advertising %4.4x.\n",
-						   dev->name, reg4, phy, mdio_read(dev, phy, 4));
+						   dev->name, reg4, phy, mii_advert);
+					printk(KERN_DEBUG "%s:  Advertising %4.4x (to advertise"
+						   " is %4.4x).\n",
+						   dev->name, reg4, tp->to_advertise);
 					mdio_write(dev, phy, 4, reg4);
 				}
 				/* Enable autonegotiation: some boards default to off. */
@@ -788,9 +925,15 @@
 	dev->set_multicast_list = &set_rx_mode;
 #endif
 
+	if ((tp->flags & HAS_NWAY143)  || tp->chip_id == DC21041)
+		tp->link_change = t21142_lnk_change;
+	else if (tp->flags & HAS_PNICNWAY)
+		tp->link_change = pnic_lnk_change;
+
 	/* Reset the xcvr interface and turn on heartbeat. */
-	switch (chip_id) {
+	switch (chip_idx) {
 	case DC21041:
+		tp->to_advertise = 0x0061;
 		outl(0x00000000, ioaddr + CSR13);
 		outl(0xFFFFFFFF, ioaddr + CSR14);
 		outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
@@ -806,28 +949,43 @@
 			outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
 		break;
 	case DC21142:
-		outl(0x82420200, ioaddr + CSR6);
-		outl(0x0001, ioaddr + CSR13);
-		outl(0x0003FFFF, ioaddr + CSR14);
-		outl(0x0008, ioaddr + CSR15);
-		outl(0x0001, ioaddr + CSR13);
-		outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+	case PNIC2:
+		if (tp->mii_cnt  ||  media_cap[dev->if_port] & MediaIsMII) {
+			outl(0x82020000, ioaddr + CSR6);
+			outl(0x0000, ioaddr + CSR13);
+			outl(0x0000, ioaddr + CSR14);
+			outl(0x820E0000, ioaddr + CSR6);
+		} else
+			t21142_start_nway(dev);
 		break;
 	case LC82C168:
 		if ( ! tp->mii_cnt) {
+			tp->nway = 1;
+			tp->nwayset = 0;
 			outl(0x00420000, ioaddr + CSR6);
 			outl(0x30, ioaddr + CSR12);
 			outl(0x0001F078, ioaddr + 0xB8);
 			outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
 		}
 		break;
-	case MX98713: case MX98715: case MX98725:
+	case MX98713: case COMPEX9881:
 		outl(0x00000000, ioaddr + CSR6);
 		outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
 		outl(0x00000001, ioaddr + CSR13);
 		break;
+	case MX98715: case MX98725:
+		outl(0x01a80000, ioaddr + CSR6);
+		outl(0xFFFFFFFF, ioaddr + CSR14);
+		outl(0x00001000, ioaddr + CSR12);
+		break;
+	case COMET:
+		/* No initialization necessary. */
+		break;
 	}
 
+	if (tulip_tbl[chip_idx].flags & HAS_PWRDWN)
+		pcibios_write_config_dword(pci_bus, pci_devfn, 0x40, 0x40000000);
+
 	return dev;
 }
 
@@ -846,29 +1004,37 @@
 } eeprom_fixups[] = {
   {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c,
 						  0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }},
-  {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x021f,
+  {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f,
 							   0x0000, 0x009E, /* 10baseT */
-							   0x0903, 0x006D, /* 100baseTx */ }},
-  {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x033f,
+							   0x0004, 0x009E, /* 10baseT-FD */
+							   0x0903, 0x006D, /* 100baseTx */
+							   0x0905, 0x006D, /* 100baseTx-FD */ }},
+  {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f,
 								 0x0107, 0x8021, /* 100baseFx */
 								 0x0108, 0x8021, /* 100baseFx-FD */
-								 0x0103, 0x006D, /* 100baseTx */ }},
-  {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0313,
+								 0x0100, 0x009E, /* 10baseT */
+								 0x0104, 0x009E, /* 10baseT-FD */
+								 0x0103, 0x006D, /* 100baseTx */
+								 0x0105, 0x006D, /* 100baseTx-FD */ }},
+  {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513,
 							   0x1001, 0x009E, /* 10base2, CSR12 0x10*/
 							   0x0000, 0x009E, /* 10baseT */
-							   0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ }},
-  {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x031F,
-							0x1B01, 0x0000, /* 10base2,   CSR12 0x1B */
-							0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ 
-							0x0B00, 0x009E, /* 10baseT,   CSR12 0x0B */
+							   0x0004, 0x009E, /* 10baseT-FD */
+							   0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */
+							   0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}},
+  {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F,
+								  0x1B01, 0x0000, /* 10base2,   CSR12 0x1B */
+								  0x0B00, 0x009E, /* 10baseT,   CSR12 0x0B */
+								  0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */
+								  0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
+								  0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */
    }},
   {0, 0, 0, 0, {}}};
 
 static const char * block_name[] = {"21140 non-MII", "21140 MII PHY",
  "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};
 
-#define EEPROM_SIZE 128
-#if defined(__i386__)
+#if defined(__i386__)			/* AKA get_unaligned() */
 #define get_u16(ptr) (*(u16 *)(ptr))
 #else
 #define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8))
@@ -881,14 +1047,10 @@
 	static unsigned char *last_ee_data = NULL;
 	static int controller_index = 0;
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
-	long ioaddr = dev->base_addr;
 	unsigned char *ee_data = tp->eeprom;
 	int i;
 
 	tp->mtable = 0;
-	for (i = 0; i < EEPROM_SIZE/2; i++)
-		((u16 *)ee_data)[i] = read_eeprom(ioaddr, i);
-
 	/* Detect an old-style (SA only) EEPROM layout:
 	   memcmp(eedata, eedata+16, 8). */
 	for (i = 0; i < 8; i ++)
@@ -925,20 +1087,13 @@
 		}
 	  }
 	  if (eeprom_fixups[i].name == NULL) { /* No fixup found. */
-		printk(KERN_INFO "%s: Old style EEPROM -- no media selection information.\n",
+		  printk(KERN_INFO "%s: Old style EEPROM with no media selection "
+				 "information.\n",
 			   dev->name);
 		return;
 	  }
 	}
-	if (tulip_debug > 1) {
-	  printk(KERN_DEBUG "read_eeprom:");
-	  for (i = 0; i < 64; i++) {
-		printk("%s%4.4x", (i & 7) == 0 ? "\n" KERN_DEBUG : " ",
-			   read_eeprom(ioaddr, i));
-	  }
-	  printk("\n");
-	}
-	
+
 	controller_index = 0;
 	if (ee_data[19] > 1) {		/* Multiport board. */
 		last_ee_data = ee_data;
@@ -948,42 +1103,29 @@
 	if (ee_data[27] == 0) {		/* No valid media table. */
 	} else if (tp->chip_id == DC21041) {
 		unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3];
-		short media;
-		int count;
-
-		media = get_u16(p);
-		p += 2;
-		count = *p++;
+		int media = get_u16(p);
+		int count = p[2];
+		p += 3;
 
-		printk(KERN_INFO "%s:21041 Media information at %d, default media "
-			   "%4.4x (%s).\n", dev->name, ee_data[27], media,
+		printk(KERN_INFO "%s: 21041 Media table, default media %4.4x (%s).\n",
+			   dev->name, media,
 			   media & 0x0800 ? "Autosense" : medianame[media & 15]);
 		for (i = 0; i < count; i++) {
 			unsigned char media_code = *p++;
-			u16 csrvals[3];
-			int idx;
-			for (idx = 0; idx < 3; idx++) {
-				csrvals[idx] = get_u16(p);
-				p += 2;
-			}
-			if (media_code & 0x40) {
-				printk(KERN_INFO "%s:  21041 media %2.2x (%s),"
-					   " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n",
-					   dev->name, media_code & 15, medianame[media_code & 15],
-					   csrvals[0], csrvals[1], csrvals[2]);
-			} else
-				printk(KERN_INFO "%s:  21041 media #%d, %s.\n",
-					   dev->name, media_code & 15, medianame[media_code & 15]);
+			if (media_code & 0x40)
+				p += 6;
+			printk(KERN_INFO "%s:  21041 media #%d, %s.\n",
+				   dev->name, media_code & 15, medianame[media_code & 15]);
 		}
 	} else {
 		unsigned char *p = (void *)ee_data + ee_data[27];
 		unsigned char csr12dir = 0;
-		int count;
+		int count, new_advertise = 0;
 		struct mediatable *mtable;
 		u16 media = get_u16(p);
 
 		p += 2;
-		if (tulip_tbl[tp->chip_id].flags & CSR12_IN_SROM)
+		if (tp->flags & CSR12_IN_SROM)
 			csr12dir = *p++;
 		count = *p++;
 		mtable = (struct mediatable *)
@@ -995,13 +1137,14 @@
 		mtable->defaultmedia = media;
 		mtable->leafcount = count;
 		mtable->csr12dir = csr12dir;
-		mtable->has_nonmii = mtable->has_mii = 0;
+		mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0;
+		mtable->csr15dir = mtable->csr15val = 0;
 
 		printk(KERN_INFO "%s:  EEPROM default media type %s.\n", dev->name,
 			   media & 0x0800 ? "Autosense" : medianame[media & 15]);
 		for (i = 0; i < count; i++) {
 			struct medialeaf *leaf = &mtable->mleaf[i];
-			
+
 			if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */
 				leaf->type = 0;
 				leaf->media = p[0] & 0x3f;
@@ -1011,12 +1154,34 @@
 				p += 4;
 			} else {
 				leaf->type = p[1];
-				if (p[1] & 1) {
+				if (p[1] == 0x05) {
+					mtable->has_reset = i;
+					leaf->media = p[2] & 0x0f;
+				} else if (p[1] & 1) {
 					mtable->has_mii = 1;
 					leaf->media = 11;
 				} else {
 					mtable->has_nonmii = 1;
 					leaf->media = p[2] & 0x0f;
+					switch (leaf->media) {
+					case 0: new_advertise |= 0x0020; break;
+					case 4: new_advertise |= 0x0040; break;
+					case 3: new_advertise |= 0x0080; break;
+					case 5: new_advertise |= 0x0100; break;
+					case 6: new_advertise |= 0x0200; break;
+					}
+					if (p[1] == 2  &&  leaf->media == 0) {
+						if (p[2] & 0x40) {
+							u32 base15 = get_unaligned((u16*)&p[7]);
+							mtable->csr15dir =
+								(get_unaligned((u16*)&p[9])<<16) + base15;
+							mtable->csr15val =
+								(get_unaligned((u16*)&p[11])<<16) + base15;
+						} else {
+							mtable->csr15dir = get_unaligned((u16*)&p[3])<<16;
+							mtable->csr15val = get_unaligned((u16*)&p[5])<<16;
+						}
+					}
 				}
 				leaf->leafdata = p + 2;
 				p += (p[0] & 0x3f) + 1;
@@ -1025,7 +1190,7 @@
 				unsigned char *bp = leaf->leafdata;
 				printk(KERN_INFO "%s:  MII interface PHY %d, setup/reset "
 					   "sequences %d/%d long, capabilities %2.2x %2.2x.\n",
-					   dev->name, bp[0], bp[1], bp[1 + bp[1]*2],
+					   dev->name, bp[0], bp[1], bp[2 + bp[1]*2],
 					   bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]);
 			}
 			printk(KERN_INFO "%s:  Index #%d - Media %s (#%d) described "
@@ -1033,6 +1198,8 @@
 				   dev->name, i, medianame[leaf->media], leaf->media,
 				   block_name[leaf->type], leaf->type);
 		}
+		if (new_advertise)
+			tp->to_advertise = new_advertise;
 	}
 }
 /* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/
@@ -1040,54 +1207,48 @@
 /*  EEPROM_Ctrl bits. */
 #define EE_SHIFT_CLK	0x02	/* EEPROM shift clock. */
 #define EE_CS			0x01	/* EEPROM chip select. */
-#define EE_DATA_WRITE	0x04	/* EEPROM chip data in. */
+#define EE_DATA_WRITE	0x04	/* Data from the Tulip to EEPROM. */
 #define EE_WRITE_0		0x01
 #define EE_WRITE_1		0x05
-#define EE_DATA_READ	0x08	/* EEPROM chip data out. */
+#define EE_DATA_READ	0x08	/* Data from the EEPROM chip. */
 #define EE_ENB			(0x4800 | EE_CS)
 
 /* Delay between EEPROM clock transitions.
-   The 1.2 code is a "nasty" timing loop, but PC compatible machines are
-   *supposed* to delay an ISA-compatible period for the SLOW_DOWN_IO macro.  */
-#ifdef _LINUX_DELAY_H
-#define eeprom_delay(nanosec)	udelay((nanosec + 999)/1000)
-#else
-#define eeprom_delay(nanosec)	do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
-#endif
+   Even at 33Mhz current PCI implementations don't overrun the EEPROM clock.
+   We add a bus turn-around to insure that this remains true. */
+#define eeprom_delay()	inl(ee_addr)
 
 /* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD	(5 << 6)
-#define EE_READ_CMD		(6 << 6)
-#define EE_ERASE_CMD	(7 << 6)
+#define EE_READ_CMD		(6)
 
-static int read_eeprom(long ioaddr, int location)
+/* Note: this routine returns extra data bits for size detection. */
+static int read_eeprom(long ioaddr, int location, int addr_len)
 {
 	int i;
-	unsigned short retval = 0;
+	unsigned retval = 0;
 	long ee_addr = ioaddr + CSR9;
-	int read_cmd = location | EE_READ_CMD;
-	
+	int read_cmd = location | (EE_READ_CMD << addr_len);
+
 	outl(EE_ENB & ~EE_CS, ee_addr);
 	outl(EE_ENB, ee_addr);
-	
+
 	/* Shift the read command bits out. */
-	for (i = 10; i >= 0; i--) {
+	for (i = 4 + addr_len; i >= 0; i--) {
 		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
 		outl(EE_ENB | dataval, ee_addr);
-		eeprom_delay(100);
+		eeprom_delay();
 		outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
-		eeprom_delay(150);
-		outl(EE_ENB | dataval, ee_addr);	/* Finish EEPROM a clock tick. */
-		eeprom_delay(250);
+		eeprom_delay();
+		retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
 	}
 	outl(EE_ENB, ee_addr);
-	
+
 	for (i = 16; i > 0; i--) {
 		outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
-		eeprom_delay(100);
+		eeprom_delay();
 		retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
 		outl(EE_ENB, ee_addr);
-		eeprom_delay(100);
+		eeprom_delay();
 	}
 
 	/* Terminate the EEPROM access. */
@@ -1121,19 +1282,33 @@
 	int i;
 	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
 	int retval = 0;
-	long mdio_addr = dev->base_addr + CSR9;
+	long ioaddr = dev->base_addr;
+	long mdio_addr = ioaddr + CSR9;
 
 	if (tp->chip_id == LC82C168) {
-		long ioaddr = dev->base_addr;
 		int i = 1000;
 		outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
+		inl(ioaddr + 0xA0);
+		inl(ioaddr + 0xA0);
 		while (--i > 0)
 			if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
 				return retval & 0xffff;
 		return 0xffff;
 	}
 
-	/* Establish sync by sending at least 32 logic ones. */ 
+	if (tp->chip_id == COMET) {
+		if (phy_id == 1) {
+			if (location < 7)
+				return inl(ioaddr + 0xB4 + (location<<2));
+			else if (location == 17)
+				return inl(ioaddr + 0xD0);
+			else if (location >= 29 && location <= 31)
+				return inl(ioaddr + 0xD4 + ((location-29)<<2));
+		}
+		return 0xffff;
+	}
+
+	/* Establish sync by sending at least 32 logic ones. */
 	for (i = 32; i >= 0; i--) {
 		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
 		mdio_delay();
@@ -1165,10 +1340,10 @@
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	int i;
 	int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
-	long mdio_addr = dev->base_addr + CSR9;
+	long ioaddr = dev->base_addr;
+	long mdio_addr = ioaddr + CSR9;
 
 	if (tp->chip_id == LC82C168) {
-		long ioaddr = dev->base_addr;
 		int i = 1000;
 		outl(cmd, ioaddr + 0xA0);
 		do
@@ -1178,7 +1353,19 @@
 		return;
 	}
 
-	/* Establish sync by sending 32 logic ones. */ 
+	if (tp->chip_id == COMET) {
+		if (phy_id != 1)
+			return;
+		if (location < 7)
+			outl(value, ioaddr + 0xB4 + (location<<2));
+		else if (location == 17)
+			outl(value, ioaddr + 0xD0);
+		else if (location >= 29 && location <= 31)
+			outl(value, ioaddr + 0xD4 + ((location-29)<<2));
+		return;
+	}
+
+	/* Establish sync by sending 32 logic ones. */
 	for (i = 32; i >= 0; i--) {
 		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
 		mdio_delay();
@@ -1209,7 +1396,12 @@
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	long ioaddr = dev->base_addr;
-	int i = 0;
+	int next_tick = 3*HZ;
+	int i;
+
+	/* Wake the chip from sleep/snooze mode. */
+	if (tp->flags & HAS_PWRDWN)
+		pcibios_write_config_dword(tp->pci_bus, tp->pci_devfn, 0x40, 0);
 
 	/* On some chip revs we must set the MII/SYM port before the reset!? */
 	if (tp->mii_cnt  ||  (tp->mtable  &&  tp->mtable->has_mii))
@@ -1217,86 +1409,61 @@
 
 	/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
 	outl(0x00000001, ioaddr + CSR0);
-#ifdef _LINUX_DELAY_H
-	udelay(2);
-#else
-	SLOW_DOWN_IO;
-#endif
+
+	if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))
+		return -EAGAIN;
+	MOD_INC_USE_COUNT;
+
 	/* Deassert reset.
-	   486: Set 8 longword cache alignment, 8 longword burst.
-	   586: Set 16 longword cache alignment, no burst limit.
-	   Cache alignment bits 15:14	     Burst length 13:8
-		0000	No alignment  0x00000000 unlimited		0800 8 longwords
-		4000	8  longwords		0100 1 longword		1000 16 longwords
-		8000	16 longwords		0200 2 longwords	2000 32 longwords
-		C000	32  longwords		0400 4 longwords
 	   Wait the specified 50 PCI cycles after a reset by initializing
 	   Tx and Rx queues and the address filter list. */
-#if defined(__alpha__)
-	/* ToDo: Alpha setting could be better. */
-	outl(0x01A00000 | 0xE000, ioaddr + CSR0);
-#elif defined(__powerpc__)
-	outl(0x01A00080 | 0x8000, ioaddr + CSR0);
-#elif defined(__i386__)
-#if defined(MODULE)
-	/* When a module we don't have 'x86' to check. */
-	outl(0x01A00000 | 0x4800, ioaddr + CSR0);
-#else
-#if (LINUX_VERSION_CODE > 0x2014c)
-#define x86 boot_cpu_data.x86
-#endif
-	outl(0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0);
-	if (x86 <= 4)
-	  printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache "
-			 "alignment to %x.\n", dev->name,
-			 0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000));
-#endif
-#else
-	outl(0x01A00000 | 0x4800, ioaddr + CSR0);
-#warning Processor architecture undefined!
-#endif
-
-#ifdef SA_SHIRQ
-	if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) {
-		return -EAGAIN;
-	}
-#else
-	if (irq2dev_map[dev->irq] != NULL
-		|| (irq2dev_map[dev->irq] = dev) == NULL
-		|| dev->irq == 0
-		|| request_irq(dev->irq, &tulip_interrupt, 0,
-					   tulip_tbl[tp->chip_id].chip_name)) {
-		return -EAGAIN;
-	}
-#endif
+	outl(tp->csr0, ioaddr + CSR0);
 
 	if (tulip_debug > 1)
 		printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq);
 
-	MOD_INC_USE_COUNT;
-
 	tulip_init_ring(dev);
 
-	/* This is set_rx_mode(), but without starting the transmitter. */
-	/* Fill the whole address filter table with our physical address. */
-	{
+#if 0
+	if (tp->chip_id == PNIC2) {
+		u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
+		u32 addr_high = cpu_to_le16(get_unaligned((u16 *)(dev->dev_addr+4)));
+		addr_high = (dev->dev_addr[4]<<8) + (dev->dev_addr[5]<<0);
+		outl((dev->dev_addr[0]<<8) + dev->dev_addr[1] +
+			 (dev->dev_addr[2]<<24) + (dev->dev_addr[3]<<16),
+			 ioaddr + 0xB0);
+		outl(addr_high + (addr_high<<16), ioaddr + 0xB8);
+	}
+#endif
+	if (tp->flags & MC_HASH_ONLY) {
+		u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
+		u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4)));
+		if (tp->chip_id == AX88140) {
+			outl(0, ioaddr + CSR13);
+			outl(addr_low,  ioaddr + CSR14);
+			outl(1, ioaddr + CSR13);
+			outl(addr_high, ioaddr + CSR14);
+		} else if (tp->chip_id == COMET) {
+			outl(addr_low,  ioaddr + 0xA4);
+			outl(addr_high, ioaddr + 0xA8);
+			outl(0, ioaddr + 0xAC);
+			outl(0, ioaddr + 0xB0);
+		}
+	} else {
+		/* This is set_rx_mode(), but without starting the transmitter. */
 		u16 *eaddrs = (u16 *)dev->dev_addr;
-		u32 *setup_frm = tp->setup_frame, i;
+		u16 *setup_frm = &tp->setup_frame[15*6];
 
-		/* You must add the broadcast address when doing perfect filtering! */
-		*setup_frm++ = 0xffff;
-		*setup_frm++ = 0xffff;
-		*setup_frm++ = 0xffff;
-		/* Fill the rest of the accept table with our physical address. */
-		for (i = 1; i < 16; i++) {
-			*setup_frm++ = eaddrs[0];
-			*setup_frm++ = eaddrs[1];
-			*setup_frm++ = eaddrs[2];
-		}
+		/* 21140 bug: you must add the broadcast address. */
+		memset(tp->setup_frame, 0xff, sizeof(tp->setup_frame));
+		/* Fill the final entry of the table with our physical address. */
+		*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+		*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+		*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
 		/* Put the setup frame on the Tx list. */
-		tp->tx_ring[0].length = 0x08000000 | 192;
-		tp->tx_ring[0].buffer1 = virt_to_bus(tp->setup_frame);
-		tp->tx_ring[0].status = 0x80000000;
+		tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192);
+		tp->tx_ring[0].buffer1 = virt_to_le32desc(tp->setup_frame);
+		tp->tx_ring[0].status = cpu_to_le32(DescOwned);
 
 		tp->cur_tx++;
 	}
@@ -1304,13 +1471,12 @@
 	outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3);
 	outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
 
+	tp->saved_if_port = dev->if_port;
 	if (dev->if_port == 0)
 		dev->if_port = tp->default_port;
-	if (tp->chip_id == DC21041  &&  dev->if_port > 4)
-		/* Invalid: Select initial TP, autosense, autonegotiate.  */
-		dev->if_port = 4;
 
 	/* Allow selecting a default media. */
+	i = 0;
 	if (tp->mtable == NULL)
 		goto media_picked;
 	if (dev->if_port) {
@@ -1323,31 +1489,80 @@
 				goto media_picked;
 			}
 	}
-	if ((tp->mtable->defaultmedia & 0x0800) == 0)
+	if ((tp->mtable->defaultmedia & 0x0800) == 0) {
+		int looking_for = tp->mtable->defaultmedia & 15;
 		for (i = 0; i < tp->mtable->leafcount; i++)
-		  if (tp->mtable->mleaf[i].media == (tp->mtable->defaultmedia & 15)) {
-			printk(KERN_INFO "%s: Using EEPROM-set media %s.\n",
-				   dev->name, medianame[tp->mtable->mleaf[i].media]);
-			goto media_picked;
-		  }
+			if (tp->mtable->mleaf[i].media == looking_for) {
+				printk(KERN_INFO "%s: Using EEPROM-set media %s.\n",
+					   dev->name, medianame[looking_for]);
+				goto media_picked;
+			}
+	}
 	/* Start sensing first non-full-duplex media. */
 	for (i = tp->mtable->leafcount - 1;
 		 (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--)
-	  ;
+		;
 media_picked:
 
 	tp->csr6 = 0;
 	tp->cur_index = i;
+	tp->nwayset = 0;
+	if (dev->if_port == 0  && tp->chip_id == DC21041) {
+		tp->nway = 1;
+	}
 	if (dev->if_port == 0  &&  tp->chip_id == DC21142) {
-		tp->csr6 = 0x82420200;
-		outl(0x0003FFFF, ioaddr + CSR14);
+		if (tp->mii_cnt) {
+			select_media(dev, 1);
+			if (tulip_debug > 1)
+				printk(KERN_INFO "%s: Using MII transceiver %d, status "
+					   "%4.4x.\n",
+					   dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1));
+			outl(0x82020000, ioaddr + CSR6);
+			tp->csr6 = 0x820E0000;
+			dev->if_port = 11;
+			outl(0x0000, ioaddr + CSR13);
+			outl(0x0000, ioaddr + CSR14);
+		} else
+			t21142_start_nway(dev);
+	} else if (tp->chip_id == PNIC2) {
+		t21142_start_nway(dev);
+	} else if (tp->chip_id == LC82C168  &&  ! tp->medialock) {
+		if (tp->mii_cnt) {
+			dev->if_port = 11;
+			tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0);
+			outl(0x0001, ioaddr + CSR15);
+		} else if (inl(ioaddr + CSR5) & TPLnkPass)
+			pnic_do_nway(dev);
+		else {
+			/* Start with 10mbps to do autonegotiation. */
+			outl(0x32, ioaddr + CSR12);
+			tp->csr6 = 0x00420000;
+			outl(0x0001B078, ioaddr + 0xB8);
+			outl(0x0201B078, ioaddr + 0xB8);
+			next_tick = 1*HZ;
+		}
+	} else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881)
+			   && ! tp->medialock) {
+		dev->if_port = 0;
+		tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0);
+		outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
+	} else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) {
+		/* Provided by BOLO, Macronix - 12/10/1998. */
+		dev->if_port = 0;
+		tp->csr6 = 0x01a80200;
+		outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
+		outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0);
+	} else if (tp->chip_id == DC21143  &&
+			   media_cap[dev->if_port] & MediaIsMII) {
+		/* We must reset the media CSRs when we force-select MII mode. */
+		outl(0x0000, ioaddr + CSR13);
+		outl(0x0000, ioaddr + CSR14);
 		outl(0x0008, ioaddr + CSR15);
-		outl(0x0001, ioaddr + CSR13);
-		outl(0x1301, ioaddr + CSR12);
-	} else if (tp->chip_id == LC82C168  &&  tp->mii_cnt && ! tp->medialock) {
-		dev->if_port = 11;
-		tp->csr6 = 0x816C0000 | (tp->full_duplex ? 0x0200 : 0);
-		outl(0x0001, ioaddr + CSR15);
+	} else if (tp->chip_id == COMET) {
+		dev->if_port = 0;
+		tp->csr6 = 0x00040000;
+	} else if (tp->chip_id == AX88140) {
+		tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100;
 	} else
 		select_media(dev, 1);
 
@@ -1373,7 +1588,7 @@
 	/* Set the timer to switch to check for link beat and perhaps switch
 	   to an alternate media type. */
 	init_timer(&tp->timer);
-	tp->timer.expires = RUN_AT(5*HZ);
+	tp->timer.expires = RUN_AT(next_tick);
 	tp->timer.data = (unsigned long)dev;
 	tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
 	add_timer(&tp->timer);
@@ -1388,7 +1603,7 @@
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	struct mediatable *mtable = tp->mtable;
 	u32 new_csr6;
-	int check_mii =0, i;
+	int i;
 
 	if (mtable) {
 		struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index];
@@ -1406,33 +1621,56 @@
 			new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
 			break;
 		case 2: case 4: {
-			u16 setup[3];
-			for (i = 0; i < 3; i++)
+			u16 setup[5];
+			u32 csr13val, csr14val, csr15dir, csr15val;
+			for (i = 0; i < 5; i++)
 				setup[i] = get_u16(&p[i*2 + 1]);
 
 			dev->if_port = p[0] & 15;
+			if (media_cap[dev->if_port] & MediaAlwaysFD)
+				tp->full_duplex = 1;
+
+			if (startup && mtable->has_reset) {
+				struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
+				unsigned char *rst = rleaf->leafdata;
+				if (tulip_debug > 1)
+					printk(KERN_DEBUG "%s: Resetting the transceiver.\n",
+						   dev->name);
+				for (i = 0; i < rst[0]; i++)
+					outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
+			}
 			if (tulip_debug > 1)
-				printk(KERN_DEBUG "%s: 21142 non-MII %s transceiver control %4.4x/%4.4x.\n",
+				printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control "
+					   "%4.4x/%4.4x.\n",
 					   dev->name, medianame[dev->if_port], setup[0], setup[1]);
 			if (p[0] & 0x40) {	/* SIA (CSR13-15) setup values are provided. */
+				csr13val = setup[0];
+				csr14val = setup[1];
+				csr15dir = (setup[3]<<16) | setup[2];
+				csr15val = (setup[4]<<16) | setup[2];
 				outl(0, ioaddr + CSR13);
-				outl(setup[1], ioaddr + CSR14);
-				outl(setup[2], ioaddr + CSR15);
-				outl(setup[0], ioaddr + CSR13);
-				for (i = 0; i < 3; i++)			/* Re-fill setup[]  */
-					setup[i] = get_u16(&p[i*2 + 7]);
-			} else if (dev->if_port <= 4) {
-				outl(0, ioaddr + CSR13);
-				outl(t21142_csr14[dev->if_port], ioaddr + CSR14);
-				outl(t21142_csr15[dev->if_port], ioaddr + CSR15);
-				outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+				outl(csr14val, ioaddr + CSR14);
+				outl(csr15dir, ioaddr + CSR15);	/* Direction */
+				outl(csr15val, ioaddr + CSR15);	/* Data */
+				outl(csr13val, ioaddr + CSR13);
 			} else {
-				outl(0, ioaddr + CSR14);
-				outl(8, ioaddr + CSR15);
-				outl(0, ioaddr + CSR13);
+				csr13val = 1;
+				csr14val = 0x0003FF7F;
+				csr15dir = (setup[0]<<16) | 0x0008;
+				csr15val = (setup[1]<<16) | 0x0008;
+				if (dev->if_port <= 4)
+					csr14val = t21142_csr14[dev->if_port];
+				if (startup) {
+					outl(0, ioaddr + CSR13);
+					outl(csr14val, ioaddr + CSR14);
+				}
+				outl(csr15dir, ioaddr + CSR15);	/* Direction */
+				outl(csr15val, ioaddr + CSR15);	/* Data */
+				if (startup) outl(csr13val, ioaddr + CSR13);
 			}
-			outl(setup[0]<<16, ioaddr + CSR15);	/* Direction */
-			outl(setup[1]<<16, ioaddr + CSR15);	/* Data */
+			if (tulip_debug > 1)
+				printk(KERN_DEBUG "%s:  Setting CSR15 to %8.8x/%8.8x.\n",
+					   dev->name, csr15dir, csr15val);
 			if (mleaf->type == 4)
 				new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
 			else
@@ -1446,7 +1684,6 @@
 			u16 to_advertise;
 
 			dev->if_port = 11;
-			check_mii = 1;
 			new_csr6 = 0x020E0000;
 			if (mleaf->type == 3) {	/* 21142 */
 				u16 *init_sequence = (u16*)(p+2);
@@ -1473,7 +1710,7 @@
 			}
 			to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1;
 			tp->advertising[phy_num] = to_advertise;
-			if (tulip_debug > 1 || 1)
+			if (tulip_debug > 1)
 				printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d (%d).\n",
 					   dev->name, to_advertise, phy_num, tp->phys[phy_num]);
 			/* Bogus: put in by a committee?  */
@@ -1481,32 +1718,33 @@
 			break;
 		}
 		default:
-		  new_csr6 = 0x020E0000;
+			printk(KERN_DEBUG "%s:  Invalid media table selection %d.\n",
+					   dev->name, mleaf->type);
+			new_csr6 = 0x020E0000;
 		}
 		if (tulip_debug > 1)
 			printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n",
 				   dev->name, medianame[dev->if_port],
 				   inl(ioaddr + CSR12) & 0xff);
 	} else if (tp->chip_id == DC21041) {
+		int port = dev->if_port <= 4 ? dev->if_port : 0;
 		if (tulip_debug > 1)
 			printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n",
-				   dev->name, medianame[dev->if_port & 15],
-				   inl(ioaddr + CSR12) & 0xffff);
+				   dev->name, medianame[port == 3 ? 12: port],
+				   inl(ioaddr + CSR12));
 		outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
-		outl(t21041_csr14[dev->if_port], ioaddr + CSR14);
-		outl(t21041_csr15[dev->if_port], ioaddr + CSR15);
-		outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
+		outl(t21041_csr14[port], ioaddr + CSR14);
+		outl(t21041_csr15[port], ioaddr + CSR15);
+		outl(t21041_csr13[port], ioaddr + CSR13);
 		new_csr6 = 0x80020000;
 	} else if (tp->chip_id == LC82C168) {
 		if (startup && ! tp->medialock)
 			dev->if_port = tp->mii_cnt ? 11 : 0;
 		if (tulip_debug > 1)
-			printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, CSR12 %4.4x,"
-				   " media %s.\n",
-				   dev->name, inl(ioaddr + 0xB8), inl(ioaddr + CSR12),
-				   medianame[dev->if_port]);
+			printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s.\n",
+				   dev->name, inl(ioaddr + 0xB8), medianame[dev->if_port]);
 		if (tp->mii_cnt) {
-			new_csr6 = 0x812C0000;
+			new_csr6 = 0x810C0000;
 			outl(0x0001, ioaddr + CSR15);
 			outl(0x0201B07A, ioaddr + 0xB8);
 		} else if (startup) {
@@ -1518,10 +1756,8 @@
 		} else if (dev->if_port == 3  ||  dev->if_port == 5) {
 			outl(0x33, ioaddr + CSR12);
 			new_csr6 = 0x01860000;
-			if (startup)
-				outl(0x0201F868, ioaddr + 0xB8); /* Trigger autonegotiation. */
-			else
-				outl(0x1F868, ioaddr + 0xB8);
+			/* Trigger autonegotiation. */
+			outl(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8);
 		} else {
 			outl(0x32, ioaddr + CSR12);
 			new_csr6 = 0x00420000;
@@ -1532,18 +1768,24 @@
 		int csr12 = inl(ioaddr + CSR12);
 		if (tulip_debug > 1)
 			printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n",
-				   dev->name, dev->if_port ? "AUI" : "10baseT", csr12);
-		new_csr6 = (dev->if_port ? 0x01860000 : 0x00420000);
+				   dev->name, medianame[dev->if_port], csr12);
+		if (media_cap[dev->if_port] & MediaAlwaysFD)
+			tp->full_duplex = 1;
+		new_csr6 = 0x20000;
 		/* Set the full duplux match frame. */
 		outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11);
 		outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
-		outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
+		if (t21040_csr13[dev->if_port] & 8) {
+			outl(0x0705, ioaddr + CSR14);
+			outl(0x0006, ioaddr + CSR15);
+		} else {
+			outl(0xffff, ioaddr + CSR14);
+			outl(0x0000, ioaddr + CSR15);
+		}
+		outl(0x8f01 | t21040_csr13[dev->if_port], ioaddr + CSR13);
 	} else {					/* Unknown chip type with no media table. */
 		if (tp->default_port == 0)
-			if (tp->mii_cnt) {
-				dev->if_port = 11;
-			} else
-				dev->if_port = 3;
+			dev->if_port = tp->mii_cnt ? 11 : 3;
 		if (media_cap[dev->if_port] & MediaIsMII) {
 			new_csr6 = 0x020E0000;
 		} else if (media_cap[dev->if_port] & MediaIsFx) {
@@ -1561,28 +1803,80 @@
 	return;
 }
 
-static void tulip_timer(unsigned long data)
+/*
+  Check the MII negotiated duplex, and change the CSR6 setting if
+  required.
+  Return 0 if everything is OK.
+  Return < 0 if the transceiver is missing or has no link beat.
+  */
+static int check_duplex(struct device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int mii_reg1, mii_reg5, negotiated, duplex;
+
+	if (tp->full_duplex_lock)
+		return 0;
+	mii_reg1 = mdio_read(dev, tp->phys[0], 1);
+	mii_reg5 = mdio_read(dev, tp->phys[0], 5);
+	if (tulip_debug > 1)
+		printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
+			   "%4.4x.\n", dev->name, mii_reg1, mii_reg5);
+	if (mii_reg1 == 0xffff)
+		return -2;
+	if ((mii_reg1 & 0x0004) == 0) {
+		int new_reg1 = mdio_read(dev, tp->phys[0], 1);
+		if ((new_reg1 & 0x0004) == 0) {
+			if (tulip_debug  > 1)
+				printk(KERN_INFO "%s: No link beat on the MII interface,"
+					   " status %4.4x.\n", dev->name, new_reg1);
+			return -1;
+		}
+	}
+	negotiated = mii_reg5 & tp->advertising[0];
+	duplex = ((negotiated & 0x0300) == 0x0100
+			  || (negotiated & 0x00C0) == 0x0040);
+	/* 100baseTx-FD  or  10T-FD, but not 100-HD */
+	if (tp->full_duplex != duplex) {
+		tp->full_duplex = duplex;
+		if (negotiated & 0x038)	/* 100mbps. */
+			tp->csr6 &= ~0x00400000;
+		if (tp->full_duplex) tp->csr6 |= 0x0200;
+		else				 tp->csr6 &= ~0x0200;
+		outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		if (tulip_debug > 0)
+			printk(KERN_INFO "%s: Setting %s-duplex based on MII"
+				   "#%d link partner capability of %4.4x.\n",
+				   dev->name, tp->full_duplex ? "full" : "half",
+				   tp->phys[0], mii_reg5);
+		return 1;
+	}
+	return 0;
+}
+
+static void tulip_timer(unsigned long data)
 {
 	struct device *dev = (struct device *)data;
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	u32 csr12 = inl(ioaddr + CSR12);
-	int next_tick = 0;
+	int next_tick = 2*HZ;
 
-	if (tulip_debug > 3) {
-		printk(KERN_DEBUG "%s: Media selection tick, status %8.8x mode %8.8x "
-			   "SIA %8.8x %8.8x %8.8x %8.8x.\n",
-			   dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR6),
-			   csr12, inl(ioaddr + CSR13),
+	if (tulip_debug > 2) {
+		printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode"
+			   " %8.8x SIA %8.8x %8.8x %8.8x %8.8x.\n",
+			   dev->name, medianame[dev->if_port], inl(ioaddr + CSR5),
+			   inl(ioaddr + CSR6), csr12, inl(ioaddr + CSR13),
 			   inl(ioaddr + CSR14), inl(ioaddr + CSR15));
 	}
 	switch (tp->chip_id) {
 	case DC21040:
-		if (csr12 & 0x0002) { /* Network error */
-			printk(KERN_INFO "%s: No 10baseT link beat found, switching to %s media.\n",
-				   dev->name, dev->if_port ? "10baseT" : "AUI");
-			dev->if_port ^= 1;
-			outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
+		if (!tp->medialock  &&  csr12 & 0x0002) { /* Network error */
+			printk(KERN_INFO "%s: No link beat found.\n",
+				   dev->name);
+			dev->if_port = (dev->if_port == 2 ? 0 : 2);
+			select_media(dev, 0);
 			dev->trans_start = jiffies;
 		}
 		break;
@@ -1590,6 +1884,7 @@
 		if (tulip_debug > 2)
 			printk(KERN_DEBUG "%s: 21041 media tick  CSR12 %8.8x.\n",
 				   dev->name, csr12);
+		if (tp->medialock) break;
 		switch (dev->if_port) {
 		case 0: case 3: case 4:
 		  if (csr12 & 0x0004) { /*LnkFail */
@@ -1611,25 +1906,26 @@
 		  break;
 		case 1:					/* 10base2 */
 		case 2:					/* AUI */
-		  if (csr12 & 0x0100) {
-			next_tick = (30*HZ);			/* 30 sec. */
-			tp->mediasense = 0;
-		  } else if ((csr12 & 0x0004) == 0) {
-			printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n", dev->name);
-			dev->if_port = 0;
-			select_media(dev, 0);
-			next_tick = (24*HZ)/10;				/* 2.4 sec. */
-		  } else if (tp->mediasense || (csr12 & 0x0002)) {
-			dev->if_port = 3 - dev->if_port; /* Swap ports. */
-			select_media(dev, 0);
-			next_tick = 20*HZ;
-		  } else {
-			next_tick = 20*HZ;
-		  }
-		  break;
+			if (csr12 & 0x0100) {
+				next_tick = (30*HZ);			/* 30 sec. */
+				tp->mediasense = 0;
+			} else if ((csr12 & 0x0004) == 0) {
+				printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n",
+					   dev->name);
+				dev->if_port = 0;
+				select_media(dev, 0);
+				next_tick = (24*HZ)/10;				/* 2.4 sec. */
+			} else if (tp->mediasense || (csr12 & 0x0002)) {
+				dev->if_port = 3 - dev->if_port; /* Swap ports. */
+				select_media(dev, 0);
+				next_tick = 20*HZ;
+			} else {
+				next_tick = 20*HZ;
+			}
+			break;
 		}
 		break;
-	case DC21140:  case DC21142: case MX98713: default: {
+	case DC21140:  case DC21142: case MX98713: case COMPEX9881: default: {
 		struct medialeaf *mleaf;
 		unsigned char *p;
 		if (tp->mtable == NULL) {	/* No EEPROM info, use generic code. */
@@ -1698,53 +1994,11 @@
 			next_tick = (24*HZ)/10;
 			break;
 		}
-		case 1:  case 3: {		/* 21140, 21142 MII */
-			int mii_reg1, mii_reg5;
+		case 1:  case 3:		/* 21140, 21142 MII */
 		actually_mii:
-			mii_reg1 = mdio_read(dev, tp->phys[0], 1);
-			mii_reg5 = mdio_read(dev, tp->phys[0], 5);
-			if (tulip_debug > 1)
-				printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
-					   "%4.4x, CSR12 %2.2x, %cD.\n",
-					   dev->name, mii_reg1, mii_reg5, csr12,
-					   tp->full_duplex ? 'F' : 'H');
-			if (mii_reg1 != 0xffff  &&  (mii_reg1 & 0x0004) == 0) {
-				int new_reg1 = mdio_read(dev, tp->phys[0], 1);
-				if ((new_reg1 & 0x0004) == 0) {
-					printk(KERN_INFO "%s: No link beat on the MII interface,"
-						   " status then %4.4x now %4.4x.\n",
-						   dev->name, mii_reg1, new_reg1);
-					if (tp->mtable  &&  tp->mtable->has_nonmii)
-						goto select_next_media;
-				}
-			}
-			if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000)
-				;				/* No MII device or no link partner report */
-			else if (tp->full_duplex_lock)
-				;
-			else {
-				int negotiated = mii_reg5 & tp->advertising[0];
-				int duplex = ((negotiated & 0x0100) != 0
-							  || (negotiated & 0x00C0) == 0x0040);
-				/* 100baseTx-FD  or  10T-FD, but not 100-HD */
-				if (tp->full_duplex != duplex) {
-					tp->full_duplex = duplex;
-					if (tp->full_duplex)
-						tp->csr6 |= 0x0200;
-					else
-						tp->csr6 &= ~0x0200;
-					outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-					outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-					if (tulip_debug > 0) /* Gurppp, should be >1 */
-						printk(KERN_INFO "%s: Setting %s-duplex based on MII"
-							   " Xcvr #%d parter capability of %4.4x.\n",
-							   dev->name, tp->full_duplex ? "full" : "half",
-							   tp->phys[0], mii_reg5);
-				}
-			}
+			check_duplex(dev);
 			next_tick = 60*HZ;
 			break;
-		}
 		case 2:					/* 21142 serial block has no link beat. */
 		default:
 			break;
@@ -1752,10 +2006,8 @@
 	}
 	break;
 	}
-	if (next_tick) {
-		tp->timer.expires = RUN_AT(next_tick);
-		add_timer(&tp->timer);
-	}
+	tp->timer.expires = RUN_AT(next_tick);
+	add_timer(&tp->timer);
 }
 
 /* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
@@ -1769,49 +2021,50 @@
 	int next_tick = 60*HZ;
 	int new_csr6 = 0;
 
-	if (tulip_debug > 1)
-		printk(KERN_INFO"%s: 21142 negotiation status %8.8x, %s.\n",
+	if (tulip_debug > 2)
+		printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n",
 			   dev->name, csr12, medianame[dev->if_port]);
-	if (dev->if_port == 3) {
-		if (csr12 & 2) {		/* No 100mbps link beat, revert to 10mbps. */
-			new_csr6 = 0x82420200;
-			outl(new_csr6, ioaddr + CSR6);
-			outl(0x0000, ioaddr + CSR13);
-			outl(0x0003FFFF, ioaddr + CSR14);
-			outl(0x0008, ioaddr + CSR15);
-			outl(0x0001, ioaddr + CSR13);
-			outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+	if (media_cap[dev->if_port] & MediaIsMII) {
+		check_duplex(dev);
+		next_tick = 60*HZ;
+	} else if (tp->nwayset) {
+		/* Don't screw up a negotiated session! */
+		if (tulip_debug > 1)
+			printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n",
+				   dev->name, medianame[dev->if_port], csr12);
+	} else if (tp->medialock) {
+			;
+	} else if (dev->if_port == 3) {
+		if (csr12 & 2) {	/* No 100mbps link beat, revert to 10mbps. */
+			if (tulip_debug > 1)
+				printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, "
+					   "trying NWay.\n", dev->name, csr12);
+			t21142_start_nway(dev);
+			next_tick = 3*HZ;
 		}
 	} else if ((csr12 & 0x7000) != 0x5000) {
 		/* Negotiation failed.  Search media types. */
 		if (tulip_debug > 1)
-			printk(KERN_INFO"%s: 21142 negotiation failed, status %8.8x.\n",
+			printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n",
 				   dev->name, csr12);
 		if (!(csr12 & 4)) {		/* 10mbps link beat good. */
 			new_csr6 = 0x82420000;
 			dev->if_port = 0;
 			outl(0, ioaddr + CSR13);
 			outl(0x0003FFFF, ioaddr + CSR14);
-			outl(t21142_csr15[dev->if_port], ioaddr + CSR15);
+			outw(t21142_csr15[dev->if_port], ioaddr + CSR15);
 			outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
-		} else if (csr12 & 0x100) {
-			new_csr6 = 0x82420200;
-			dev->if_port = 2;
-			outl(0, ioaddr + CSR13);
-			outl(0x0003FFFF, ioaddr + CSR14);
-			outl(0x0008, ioaddr + CSR15);
-			outl(0x0001, ioaddr + CSR13);
 		} else {
 			/* Select 100mbps port to check for link beat. */
 			new_csr6 = 0x83860000;
 			dev->if_port = 3;
 			outl(0, ioaddr + CSR13);
 			outl(0x0003FF7F, ioaddr + CSR14);
-			outl(8, ioaddr + CSR15);
+			outw(8, ioaddr + CSR15);
 			outl(1, ioaddr + CSR13);
 		}
 		if (tulip_debug > 1)
-			printk(KERN_INFO"%s: Testing new 21142 media %s.\n",
+			printk(KERN_INFO"%s: Testing new 21143 media %s.\n",
 				   dev->name, medianame[dev->if_port]);
 		if (new_csr6 != (tp->csr6 & ~0x00D5)) {
 			tp->csr6 &= 0x00D5;
@@ -1820,51 +2073,147 @@
 			outl(tp->csr6 | 0x0002, ioaddr + CSR6);
 			outl(tp->csr6 | 0x2002, ioaddr + CSR6);
 		}
+		next_tick = 3*HZ;
 	}
+	if (tp->cur_tx - tp->dirty_tx > 0  &&
+		jiffies - dev->trans_start > TX_TIMEOUT) {
+		printk(KERN_WARNING "%s: Tx hung, %d vs. %d.\n",
+			   dev->name, tp->cur_tx, tp->dirty_tx);
+		tulip_tx_timeout(dev);
+	}
+
 	tp->timer.expires = RUN_AT(next_tick);
 	add_timer(&tp->timer);
 }
 
-static void t21142_lnk_change( struct device *dev)
+static void t21142_start_nway(struct device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int csr14 = ((tp->to_advertise & 0x0780) << 9)  |
+		((tp->to_advertise&0x0020)<<1) | 0xffbf;
+
+	dev->if_port = 0;
+	tp->nway = tp->mediasense = 1;
+	tp->nwayset = tp->lpar = 0;
+	if (debug > 1)
+		printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n",
+			   dev->name, csr14);
+	outl(0x0001, ioaddr + CSR13);
+	outl(csr14, ioaddr + CSR14);
+	tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
+	outl(tp->csr6, ioaddr + CSR6);
+	if (tp->mtable  &&  tp->mtable->csr15dir) {
+		outl(tp->mtable->csr15dir, ioaddr + CSR15);
+		outl(tp->mtable->csr15val, ioaddr + CSR15);
+	} else
+		outw(0x0008, ioaddr + CSR15);
+	outl(0x1301, ioaddr + CSR12); 		/* Trigger NWAY. */
+}
+
+static void t21142_lnk_change(struct device *dev, int csr5)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	int csr12 = inl(ioaddr + CSR12);
 
 	if (tulip_debug > 1)
-		printk(KERN_INFO"%s: 21142 link status interrupt %8.8x, CSR5 %x.\n",
-			   dev->name, csr12, inl(ioaddr + CSR5));
+		printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, "
+			   "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14));
 
-	if ((csr12 & 0x7000) == 0x5000) {
-		if (csr12 & 0x01800000) {
-			/* Switch to 100mbps mode. */
-			outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-			if (csr12 & 0x01000000) {
-				dev->if_port = 5;
-				tp->csr6 = 0x83860200;
-			} else {
+	/* If NWay finished and we have a negotiated partner capability. */
+	if (tp->nway  &&  !tp->nwayset  &&  (csr12 & 0x7000) == 0x5000) {
+		int setup_done = 0;
+		int negotiated = tp->to_advertise & (csr12 >> 16);
+		tp->lpar = csr12 >> 16;
+		tp->nwayset = 1;
+		if (negotiated & 0x0100)		dev->if_port = 5;
+		else if (negotiated & 0x0080)	dev->if_port = 3;
+		else if (negotiated & 0x0040)	dev->if_port = 4;
+		else if (negotiated & 0x0020)	dev->if_port = 0;
+		else {
+			tp->nwayset = 0;
+			if ((csr12 & 2) == 0  &&  (tp->to_advertise & 0x0180))
 				dev->if_port = 3;
-				tp->csr6 = 0x83860000;
-			}
-			outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-		} /* Else 10baseT-FD is handled automatically. */
-	} else if (dev->if_port == 3) {
-		if (!(csr12 & 2))
-			printk(KERN_INFO"%s: 21142 100baseTx link beat good.\n",
-				   dev->name);
-		else
-			dev->if_port = 0;
-	} else if (dev->if_port == 0) {
-		if (!(csr12 & 4))
-			printk(KERN_INFO"%s: 21142 10baseT link beat good.\n",
+		}
+		tp->full_duplex = (media_cap[dev->if_port] & MediaAlwaysFD) ? 1:0;
+
+		if (tulip_debug > 1) {
+			if (tp->nwayset)
+				printk(KERN_INFO "%s: Switching to %s based on link "
+					   "negotiation %4.4x & %4.4x = %4.4x.\n",
+					   dev->name, medianame[dev->if_port], tp->to_advertise,
+					   tp->lpar, negotiated);
+			else
+				printk(KERN_INFO "%s: Autonegotiation failed, using %s,"
+					   " link beat status %4.4x.\n",
+					   dev->name, medianame[dev->if_port], csr12);
+		}
+
+		if (tp->mtable) {
+			int i;
+			for (i = 0; i < tp->mtable->leafcount; i++)
+				if (tp->mtable->mleaf[i].media == dev->if_port) {
+					tp->cur_index = i;
+					select_media(dev, 0);
+					setup_done = 1;
+					break;
+				}
+		}
+		if ( ! setup_done) {
+			tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000;
+			if (tp->full_duplex)
+				tp->csr6 |= 0x0200;
+			outl(1, ioaddr + CSR13);
+		}
+#if 0							/* Restart shouldn't be needed. */
+		outl(tp->csr6 | 0x0000, ioaddr + CSR6);
+		if (debug > 2)
+			printk(KERN_DEBUG "%s:  Restarting Tx and Rx, CSR5 is %8.8x.\n",
+				   dev->name, inl(ioaddr + CSR5));
+#endif
+		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		if (debug > 2)
+			printk(KERN_DEBUG "%s:  Setting CSR6 %8.8x/%x CSR12 %8.8x.\n",
+				   dev->name, tp->csr6, inl(ioaddr + CSR6),
+				   inl(ioaddr + CSR12));
+	} else if ((tp->nwayset  &&  (csr5 & 0x08000000)
+				&& (dev->if_port == 3  ||  dev->if_port == 5)
+				&& (csr12 & 2) == 2) ||
+			   (tp->nway && (csr5 & (TPLnkFail)))) {
+		/* Link blew? Maybe restart NWay. */
+		del_timer(&tp->timer);
+		t21142_start_nway(dev);
+		tp->timer.expires = RUN_AT(3*HZ);
+		add_timer(&tp->timer);
+	} else if (dev->if_port == 3  ||  dev->if_port == 5) {
+		if (tulip_debug > 1)
+			printk(KERN_INFO"%s: 21143 %s link beat %s.\n",
+				   dev->name, medianame[dev->if_port],
+				   (csr12 & 2) ? "failed" : "good");
+		if ((csr12 & 2)  &&  ! tp->medialock) {
+			del_timer(&tp->timer);
+			t21142_start_nway(dev);
+			tp->timer.expires = RUN_AT(3*HZ);
+			add_timer(&tp->timer);
+		}
+	} else if (dev->if_port == 0  ||  dev->if_port == 4) {
+		if ((csr12 & 4) == 0)
+			printk(KERN_INFO"%s: 21143 10baseT link beat good.\n",
 				   dev->name);
 	} else if (!(csr12 & 4)) {		/* 10mbps link beat good. */
-			printk(KERN_INFO"%s: 21142 10mpbs sensed media.\n",
+		if (tulip_debug)
+			printk(KERN_INFO"%s: 21143 10mbps sensed media.\n",
+				   dev->name);
+		dev->if_port = 0;
+	} else if (tp->nwayset) {
+		if (tulip_debug)
+			printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n",
+				   dev->name, medianame[dev->if_port], tp->csr6);
+	} else {		/* 100mbps link beat good. */
+		if (tulip_debug)
+			printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n",
 				   dev->name);
-			dev->if_port = 0;
-	} else  {		/* 100mbps link beat good. */
-		printk(KERN_INFO"%s: 21142 100baseTx sensed media.\n",
-			   dev->name);
 		dev->if_port = 3;
 		tp->csr6 = 0x83860000;
 		outl(0x0003FF7F, ioaddr + CSR14);
@@ -1873,7 +2222,6 @@
 		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
 	}
 }
-	
 
 static void mxic_timer(unsigned long data)
 {
@@ -1892,57 +2240,98 @@
 	}
 }
 
+static void pnic_do_nway(struct device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	u32 phy_reg = inl(ioaddr + 0xB8);
+	u32 new_csr6 = tp->csr6 & ~0x40C40200;
+
+	if (phy_reg & 0x78000000) { /* Ignore baseT4 */
+		if (phy_reg & 0x20000000)		dev->if_port = 5;
+		else if (phy_reg & 0x40000000)	dev->if_port = 3;
+		else if (phy_reg & 0x10000000)	dev->if_port = 4;
+		else if (phy_reg & 0x08000000)	dev->if_port = 0;
+		tp->nwayset = 1;
+		new_csr6 = (dev->if_port & 1) ? 0x01860000 : 0x00420000;
+		outl(0x32 | (dev->if_port & 1), ioaddr + CSR12);
+		if (dev->if_port & 1)
+			outl(0x1F868, ioaddr + 0xB8);
+		if (phy_reg & 0x30000000) {
+			tp->full_duplex = 1;
+			new_csr6 |= 0x00000200;
+		}
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: PNIC autonegotiated status %8.8x, %s.\n",
+				   dev->name, phy_reg, medianame[dev->if_port]);
+		if (tp->csr6 != new_csr6) {
+			tp->csr6 = new_csr6;
+			outl(tp->csr6 | 0x0002, ioaddr + CSR6);	/* Restart Tx */
+			outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+			dev->trans_start = jiffies;
+		}
+	}
+}
+static void pnic_lnk_change(struct device *dev, int csr5)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int phy_reg = inl(ioaddr + 0xB8);
+
+	if (tulip_debug > 1)
+		printk(KERN_DEBUG "%s: PNIC link changed state %8.8x, CSR5 %8.8x.\n",
+			   dev->name, phy_reg, csr5);
+	if (inl(ioaddr + CSR5) & TPLnkFail) {
+		outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7);
+		if (! tp->nwayset  ||  jiffies - dev->trans_start > 1*HZ) {
+			tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff);
+			outl(tp->csr6, ioaddr + CSR6);
+			outl(0x30, ioaddr + CSR12);
+			outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
+			dev->trans_start = jiffies;
+		}
+	} else if (inl(ioaddr + CSR5) & TPLnkPass) {
+		pnic_do_nway(dev);
+		outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7);
+	}
+}
 static void pnic_timer(unsigned long data)
 {
 	struct device *dev = (struct device *)data;
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	long ioaddr = dev->base_addr;
-	int csr12 = inl(ioaddr + CSR12);
 	int next_tick = 60*HZ;
-	int new_csr6 = tp->csr6 & ~0x40C40200;
 
 	if (media_cap[dev->if_port] & MediaIsMII) {
-		int negotiated = mdio_read(dev, tp->phys[0], 5) & tp->advertising[0];
-
-		if (tulip_debug > 1)
-			printk(KERN_DEBUG "%s: LC82C168 negotiated capability %8.8x, "
-				   "CSR5 %8.8x.\n",
-				   dev->name, negotiated, inl(ioaddr + CSR5));
-
-		if (negotiated & 0x0380) 				/* 10 vs 100mbps */
-			new_csr6 |= 0x812E0000;
-		else
-			new_csr6 |= 0x816E0000;
-		if (((negotiated & 0x0300) == 0x0100)			/* Duplex */
-			|| (negotiated & 0x00C0) == 0x0040
-			|| tp->full_duplex_lock) {
-			tp->full_duplex = 1;
-			new_csr6 |= 0x0200;
-		}
-		if (tulip_debug > 1)
-			printk(KERN_DEBUG "%s: LC82C168 MII PHY status %4.4x, Link "
-				   "partner report %4.4x, csr6 %8.8x/%8.8x.\n",
-			   dev->name, mdio_read(dev, tp->phys[0], 1), negotiated,
-				   tp->csr6, inl(ioaddr + CSR6));
+		if (check_duplex(dev) > 0)
+			next_tick = 3*HZ;
 	} else {
+		int csr12 = inl(ioaddr + CSR12);
+		int new_csr6 = tp->csr6 & ~0x40C40200;
 		int phy_reg = inl(ioaddr + 0xB8);
 		int csr5 = inl(ioaddr + CSR5);
 
 		if (tulip_debug > 1)
-			printk(KERN_DEBUG "%s: LC82C168 phy status %8.8x, CSR5 %8.8x.\n",
-				   dev->name, phy_reg, csr5);
-
+			printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s "
+				   "CSR5 %8.8x.\n",
+				   dev->name, phy_reg, medianame[dev->if_port], csr5);
 		if (phy_reg & 0x04000000) {	/* Remote link fault */
-			/*outl(0x0201F078, ioaddr + 0xB8);*/
-			next_tick = 3*HZ;
-		}
-		if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */
+			outl(0x0201F078, ioaddr + 0xB8);
+			next_tick = 1*HZ;
+			tp->nwayset = 0;
+		} else if (phy_reg & 0x78000000) { /* Ignore baseT4 */
+			pnic_do_nway(dev);
+			next_tick = 60*HZ;
+		} else if (csr5 & TPLnkFail) { /* 100baseTx link beat */
 			if (tulip_debug > 1)
 				printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
 					   "CSR5 %8.8x, PHY %3.3x.\n",
 					   dev->name, medianame[dev->if_port], csr12,
 					   inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
+			next_tick = 3*HZ;
 			if (tp->medialock) {
+			} else if (tp->nwayset  &&  (dev->if_port & 1)) {
+				next_tick = 1*HZ;
 			} else if (dev->if_port == 0) {
 				dev->if_port = 3;
 				outl(0x33, ioaddr + CSR12);
@@ -1954,121 +2343,144 @@
 				new_csr6 = 0x00420000;
 				outl(0x1F078, ioaddr + 0xB8);
 			}
-			new_csr6 |= (tp->csr6 & 0xfdff);
-			next_tick = 3*HZ;
-		} else
-			new_csr6 = tp->csr6;
-		if (tp->full_duplex_lock  ||  (phy_reg & 0x30000000) != 0) {
-			tp->full_duplex = 1;
-			new_csr6 |= 0x00000200;
+			if (tp->csr6 != new_csr6) {
+				tp->csr6 = new_csr6;
+				outl(tp->csr6 | 0x0002, ioaddr + CSR6);	/* Restart Tx */
+				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+				dev->trans_start = jiffies;
+				if (tulip_debug > 1)
+					printk(KERN_INFO "%s: Changing PNIC configuration to %s "
+						   "%s-duplex, CSR6 %8.8x.\n",
+						   dev->name, medianame[dev->if_port],
+						   tp->full_duplex ? "full" : "half", new_csr6);
+			}
 		}
 	}
-	if (tp->csr6 != new_csr6) {
-		tp->csr6 = new_csr6;
-		outl(tp->csr6 | 0x0002, ioaddr + CSR6);	/* Restart Tx */
-		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-		dev->trans_start = jiffies;
-		if (tulip_debug > 0) /* Gurppp, should be >1 */
-			printk(KERN_INFO "%s: Changing PNIC configuration to %s-duplex, "
-				   "CSR6 %8.8x.\n",
-				   dev->name, tp->full_duplex ? "full" : "half", new_csr6);
-	}
+	tp->timer.expires = RUN_AT(next_tick);
+	add_timer(&tp->timer);
+}
+
+static void comet_timer(unsigned long data)
+{
+	struct device *dev = (struct device *)data;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int next_tick = 60*HZ;
+
+	if (tulip_debug > 1)
+		printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability "
+			   "%4.4x.\n",
+			   dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8));
 	tp->timer.expires = RUN_AT(next_tick);
 	add_timer(&tp->timer);
 }
 
 static void tulip_tx_timeout(struct device *dev)
 {
-  struct tulip_private *tp = (struct tulip_private *)dev->priv;
-  long ioaddr = dev->base_addr;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
 
-  if (media_cap[dev->if_port] & MediaIsMII) {
-	  /* Do nothing -- the media monitor should handle this. */
-	  if (tulip_debug > 1)
-		  printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
-				 dev->name);
-	  dev->trans_start = jiffies;
-	  return;
-  } else if (tp->chip_id == DC21040) {
-	  if (inl(ioaddr + CSR12) & 0x0002) {
-		  printk(KERN_INFO "%s: transmit timed out, switching to %s media.\n",
-				 dev->name, dev->if_port ? "10baseT" : "AUI");
-		  dev->if_port ^= 1;
-		  outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
-	  }
-	  dev->trans_start = jiffies;
-	  return;
-  } else if (tp->chip_id == DC21041) {
-	u32 csr12 = inl(ioaddr + CSR12);
+	if (media_cap[dev->if_port] & MediaIsMII) {
+		/* Do nothing -- the media monitor should handle this. */
+		if (tulip_debug > 1)
+			printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
+				   dev->name);
+	} else if (tp->chip_id == DC21040) {
+		if ( !tp->medialock  &&  inl(ioaddr + CSR12) & 0x0002) {
+			dev->if_port = (dev->if_port == 2 ? 0 : 2);
+			printk(KERN_INFO "%s: transmit timed out, switching to "
+				   "%s.\n",
+				   dev->name, medianame[dev->if_port]);
+			select_media(dev, 0);
+		}
+		dev->trans_start = jiffies;
+		return;
+	} else if (tp->chip_id == DC21041) {
+		int csr12 = inl(ioaddr + CSR12);
+
+		printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, "
+			   "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n",
+			   dev->name, inl(ioaddr + CSR5), csr12,
+			   inl(ioaddr + CSR13), inl(ioaddr + CSR14));
+		tp->mediasense = 1;
+		if ( ! tp->medialock) {
+			if (dev->if_port == 1 || dev->if_port == 2)
+				if (csr12 & 0x0004) {
+					dev->if_port = 2 - dev->if_port;
+				} else
+					dev->if_port = 0;
+			else
+				dev->if_port = 1;
+			select_media(dev, 0);
+		}
+	} else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
+			   || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) {
+		printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
+			   "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
+			   dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
+			   inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+		if ( ! tp->medialock  &&  tp->mtable) {
+			do
+				--tp->cur_index;
+			while (tp->cur_index >= 0
+				   && (media_cap[tp->mtable->mleaf[tp->cur_index].media]
+					   & MediaIsFD));
+			if (--tp->cur_index < 0) {
+				/* We start again, but should instead look for default. */
+				tp->cur_index = tp->mtable->leafcount - 1;
+			}
+			select_media(dev, 0);
+			printk(KERN_WARNING "%s: transmit timed out, switching to %s "
+				   "media.\n", dev->name, medianame[dev->if_port]);
+		}
+	} else {
+		printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 "
+			   "%8.8x, resetting...\n",
+			   dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12));
+		dev->if_port = 0;
+	}
+
+#if defined(way_too_many_messages)
+	if (tulip_debug > 3) {
+		int i;
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			u8 *buf = (u8 *)(tp->rx_ring[i].buffer1);
+			int j;
+			printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x  "
+				   "%2.2x %2.2x %2.2x.\n",
+				   i, (unsigned int)tp->rx_ring[i].status,
+				   (unsigned int)tp->rx_ring[i].length,
+				   (unsigned int)tp->rx_ring[i].buffer1,
+				   (unsigned int)tp->rx_ring[i].buffer2,
+				   buf[0], buf[1], buf[2]);
+			for (j = 0; buf[j] != 0xee && j < 1600; j++)
+				if (j < 100) printk(" %2.2x", buf[j]);
+			printk(" j=%d.\n", j);
+		}
+		printk(KERN_DEBUG "  Rx ring %8.8x: ", (int)tp->rx_ring);
+		for (i = 0; i < RX_RING_SIZE; i++)
+			printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
+		printk("\n" KERN_DEBUG "  Tx ring %8.8x: ", (int)tp->tx_ring);
+		for (i = 0; i < TX_RING_SIZE; i++)
+			printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
+		printk("\n");
+	}
+#endif
+
+	/* Stop and restart the chip's Tx processes . */
+	outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+	outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+	/* Trigger an immediate transmit demand. */
+	outl(0, ioaddr + CSR1);
 
-	printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, CSR12 %8.8x,"
-		   " CSR13 %8.8x, CSR14 %8.8x, resetting...\n",
-		   dev->name, inl(ioaddr + CSR5), csr12,
-		   inl(ioaddr + CSR13), inl(ioaddr + CSR14));
-	tp->mediasense = 1;
-	if (dev->if_port == 1 || dev->if_port == 2)
-		if (csr12 & 0x0004) {
-			dev->if_port = 2 - dev->if_port;
-		} else
-			dev->if_port = 0;
-	else
-		dev->if_port = 1;
-	select_media(dev, 0);
-	tp->stats.tx_errors++;
 	dev->trans_start = jiffies;
+	tp->stats.tx_errors++;
 	return;
-  } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
-			 || tp->chip_id == MX98713) {
-	  /* Stop the transmit process. */
-	  outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-	  printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
-			 "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
-			 dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
-			 inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
-	  if (tp->mtable) {
-		  if (--tp->cur_index < 0) {
-			  /* We start again, but should instead look for default. */
-			  tp->cur_index = tp->mtable->leafcount - 1;
-		  }
-		  select_media(dev, 0);
-		  printk(KERN_WARNING "%s: transmit timed out, switching to %s media.\n",
-				 dev->name, dev->if_port ? "100baseTx" : "10baseT");
-	  }
-	  outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-	  tp->stats.tx_errors++;
-	  dev->trans_start = jiffies;
-	  return;
-  } else
-	printk(KERN_WARNING "%s: transmit timed out, status %8.8x, CSR12 %8.8x,"
-		   " resetting...\n",
-		   dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12));
-#ifdef way_too_many_messages
-  printk("  Rx ring %8.8x: ", (int)tp->rx_ring);
-  for (i = 0; i < RX_RING_SIZE; i++)
-	printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
-  printk("\n  Tx ring %8.8x: ", (int)tp->tx_ring);
-  for (i = 0; i < TX_RING_SIZE; i++)
-	printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
-  printk("\n");
-#endif
-
-  /* Perhaps we should reinitialize the hardware here. */
-  dev->if_port = 0;
-  /* Stop and restart the chip's Tx processes . */
-  outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-  outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-  /* Trigger an immediate transmit demand. */
-  outl(0, ioaddr + CSR1);
-
-  dev->trans_start = jiffies;
-  tp->stats.tx_errors++;
-  return;
 }
 
 
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void
-tulip_init_ring(struct device *dev)
+static void tulip_init_ring(struct device *dev)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	int i;
@@ -2076,40 +2488,42 @@
 	tp->tx_full = 0;
 	tp->cur_rx = tp->cur_tx = 0;
 	tp->dirty_rx = tp->dirty_tx = 0;
+	tp->susp_rx = 0;
+	tp->ttimer = 0;
+	tp->nir = 0;
 
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		tp->rx_ring[i].status = 0x80000000;	/* Owned by Tulip chip */
-		tp->rx_ring[i].length = PKT_BUF_SZ;
-		{
-			/* Note the receive buffer must be longword aligned.
-			   dev_alloc_skb() provides 16 byte alignment.  But do *not*
-			   use skb_reserve() to align the IP header! */
-			struct sk_buff *skb;
-			skb = DEV_ALLOC_SKB(PKT_BUF_SZ);
-			tp->rx_skbuff[i] = skb;
-			if (skb == NULL)
-				break;			/* Bad news!  */
-			skb->dev = dev;			/* Mark as being used by this device. */
-#if LINUX_VERSION_CODE > 0x10300
-			tp->rx_ring[i].buffer1 = virt_to_bus(skb->tail);
-#else
-			tp->rx_ring[i].buffer1 = virt_to_bus(skb->data);
-#endif
-		}
-		tp->rx_ring[i].buffer2 = virt_to_bus(&tp->rx_ring[i+1]);
+		tp->rx_ring[i].status = 0x00000000;
+		tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ);
+		tp->rx_ring[i].buffer2 = virt_to_le32desc(&tp->rx_ring[i+1]);
+		tp->rx_skbuff[i] = NULL;
 	}
 	/* Mark the last entry as wrapping the ring. */
-	tp->rx_ring[i-1].length = PKT_BUF_SZ | 0x02000000;
-	tp->rx_ring[i-1].buffer2 = virt_to_bus(&tp->rx_ring[0]);
+	tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | DESC_RING_WRAP);
+	tp->rx_ring[i-1].buffer2 = virt_to_le32desc(&tp->rx_ring[0]);
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		/* Note the receive buffer must be longword aligned.
+		   dev_alloc_skb() provides 16 byte alignment.  But do *not*
+		   use skb_reserve() to align the IP header! */
+		struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
+		tp->rx_skbuff[i] = skb;
+		if (skb == NULL)
+			break;
+		skb->dev = dev;			/* Mark as being used by this device. */
+		tp->rx_ring[i].status = cpu_to_le32(DescOwned);	/* Owned by Tulip chip */
+		tp->rx_ring[i].buffer1 = virt_to_le32desc(skb->tail);
+	}
+	tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 
 	/* The Tx buffer descriptor is filled in as needed, but we
 	   do need to clear the ownership bit. */
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		tp->tx_skbuff[i] = 0;
 		tp->tx_ring[i].status = 0x00000000;
-		tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]);
+		tp->tx_ring[i].buffer2 = virt_to_le32desc(&tp->tx_ring[i+1]);
 	}
-	tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]);
+	tp->tx_ring[i-1].buffer2 = virt_to_le32desc(&tp->tx_ring[0]);
 }
 
 static int
@@ -2128,80 +2542,76 @@
 		return 1;
 	}
 
-	/* Caution: the write order is important here, set the base address
-	   with the "ownership" bits last. */
+	/* Caution: the write order is important here, set the field
+	   with the ownership bits last. */
 
 	/* Calculate the next Tx descriptor entry. */
 	entry = tp->cur_tx % TX_RING_SIZE;
 
 	tp->tx_skbuff[entry] = skb;
-	tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
+	tp->tx_ring[entry].buffer1 = virt_to_le32desc(skb->data);
 
 	if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
-	  flag = 0x60000000; /* No interrupt */
-	  dev->tbusy = 0;
+		flag = 0x60000000; /* No interrupt */
 	} else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {
-	  flag = 0xe0000000; /* Tx-done intr. */
-	  dev->tbusy = 0;
+		flag = 0xe0000000; /* Tx-done intr. */
 	} else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
-	  flag = 0x60000000; /* No Tx-done intr. */
-	  dev->tbusy = 0;
-	} else {
-	  /* Leave room for set_rx_mode() to fill entries. */
-	  flag = 0xe0000000; /* Tx-done intr. */
-	  tp->tx_full = 1;
+		flag = 0x60000000; /* No Tx-done intr. */
+	} else {		/* Leave room for set_rx_mode() to fill entries. */
+		tp->tx_full = 1;
+		flag = 0xe0000000; /* Tx-done intr. */
 	}
 	if (entry == TX_RING_SIZE-1)
-		flag |= 0xe2000000;
+		flag = 0xe0000000 | DESC_RING_WRAP;
 
-	tp->tx_ring[entry].length = skb->len | flag;
-	tp->tx_ring[entry].status = 0x80000000;	/* Pass ownership to the chip. */
+	tp->tx_ring[entry].length = cpu_to_le32(skb->len | flag);
+	tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
 	tp->cur_tx++;
-	/* Trigger an immediate transmit demand. */
-	outl(0, dev->base_addr + CSR1);
+	if ( ! tp->tx_full)
+		clear_bit(0, (void*)&dev->tbusy);
 
 	dev->trans_start = jiffies;
+	/* Trigger an immediate transmit demand. */
+	outl(0, dev->base_addr + CSR1);
 
 	return 0;
 }
 
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
-static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs)
+static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 {
-#ifdef SA_SHIRQ		/* Use the now-standard shared IRQ implementation. */
 	struct device *dev = (struct device *)dev_instance;
-#else
-	struct device *dev = (struct device *)(irq2dev_map[irq]);
-#endif
-
-	struct tulip_private *tp;
-	long ioaddr;
-	int csr5, work_budget = max_interrupt_work;
-
-	if (dev == NULL) {
-		printk (KERN_ERR" tulip_interrupt(): irq %d for unknown device.\n",
-				irq);
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int csr5;
+	int entry;
+	int missed;
+	int rx = 0;
+	int tx = 0;
+	int oi = 0;
+	int maxrx = RX_RING_SIZE;
+	int maxtx = TX_RING_SIZE;
+	int maxoi = TX_RING_SIZE;
+
+#if defined(__i386__) && defined(SMP_CHECK)
+	if (test_and_set_bit(0, (void*)&dev->interrupt)) {
+		printk(KERN_ERR "%s: Duplicate entry of the interrupt handler by "
+			   "processor %d.\n",
+			   dev->name, hard_smp_processor_id());
+		dev->interrupt = 0;
 		return;
 	}
-
-	ioaddr = dev->base_addr;
-	tp = (struct tulip_private *)dev->priv;
-	if (test_and_set_bit(0, (void*)&tp->interrupt)) {
-#ifdef SMP_CHECK
-		printk(KERN_ERR "%s: Re-entering the interrupt handler with proc %d,"
-			   " proc %d already handling.\n", dev->name,
-			   tp->smp_proc_id, hard_smp_processor_id());
 #else
+	if (dev->interrupt) {
 		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
-#endif
 		return;
 	}
 	dev->interrupt = 1;
-#ifdef SMP_CHECK
-	tp->smp_proc_id = hard_smp_processor_id();
 #endif
 
+	tp->nir++;
+
 	do {
 		csr5 = inl(ioaddr + CSR5);
 		/* Acknowledge all of the current interrupt sources ASAP. */
@@ -2214,23 +2624,25 @@
 		if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
 			break;
 
-		if (csr5 & (RxIntr | RxNoBuf))
-			work_budget -= tulip_rx(dev);
+		if (csr5 & (RxIntr | RxNoBuf)) {
+			rx += tulip_rx(dev);
+			tulip_refill_rx(dev);
+		}
 
-		if (csr5 & (TxNoBuf | TxDied | TxIntr)) {
+		if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) {
 			unsigned int dirty_tx;
 
 			for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
 				 dirty_tx++) {
 				int entry = dirty_tx % TX_RING_SIZE;
-				int status = tp->tx_ring[entry].status;
+				int status = le32_to_cpu(tp->tx_ring[entry].status);
 
 				if (status < 0)
-					break;			/* It still hasn't been Txed */
+					break;			/* It still has not been Txed */
 				/* Check for Rx filter setup frames. */
 				if (tp->tx_skbuff[entry] == NULL)
 				  continue;
-
+				
 				if (status & 0x8000) {
 					/* There was an major error, log it. */
 #ifndef final_version
@@ -2253,19 +2665,16 @@
 					if (status & 0x0001) tp->stats.tx_deferred++;
 #endif
 #if LINUX_VERSION_CODE > 0x20127
-					tp->stats.tx_bytes += tp->tx_ring[entry].length & 0x7ff;
+					tp->stats.tx_bytes += tp->tx_skbuff[entry]->len;
 #endif
 					tp->stats.collisions += (status >> 3) & 15;
 					tp->stats.tx_packets++;
 				}
 
 				/* Free the original skb. */
-#if (LINUX_VERSION_CODE > 0x20155)
-				dev_kfree_skb(tp->tx_skbuff[entry]);
-#else
-				dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE);
-#endif
+				dev_free_skb(tp->tx_skbuff[entry]);
 				tp->tx_skbuff[entry] = 0;
+				tx++;
 			}
 
 #ifndef final_version
@@ -2281,15 +2690,15 @@
 				/* The ring is no longer full, clear tbusy. */
 				tp->tx_full = 0;
 				dev->tbusy = 0;
-				mark_bh(NET_BH);
+				netif_wake_queue(dev);
 			}
 
 			tp->dirty_tx = dirty_tx;
 			if (csr5 & TxDied) {
-				if (tulip_debug > 1)
-					printk(KERN_WARNING "%s: The transmitter stopped!"
-						   "  CSR5 is %x, CSR6 %x.\n",
-						   dev->name, csr5, inl(ioaddr + CSR6));
+				if (tulip_debug > 2)
+					printk(KERN_WARNING "%s: The transmitter stopped."
+						   "  CSR5 is %x, CSR6 %x, new CSR6 %x.\n",
+						   dev->name, csr5, inl(ioaddr + CSR6), tp->csr6);
 				outl(tp->csr6 | 0x0002, ioaddr + CSR6);
 				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
 			}
@@ -2297,6 +2706,8 @@
 
 		/* Log errors. */
 		if (csr5 & AbnormalIntr) {	/* Abnormal error summary bit. */
+			if (csr5 == 0xffffffff)
+				break;
 			if (csr5 & TxJabber) tp->stats.tx_errors++;
 			if (csr5 & TxFIFOUnderflow) {
 				if ((tp->csr6 & 0xC000) != 0xC000)
@@ -2306,128 +2717,186 @@
 				/* Restart the transmit process. */
 				outl(tp->csr6 | 0x0002, ioaddr + CSR6);
 				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+				outl(0, ioaddr + CSR1);
 			}
 			if (csr5 & RxDied) {		/* Missed a Rx frame. */
 				tp->stats.rx_errors++;
 				tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
 			}
-			if (csr5 & TimerInt) {
-				printk(KERN_ERR "%s: Something Wicked happened! %8.8x.\n",
-					   dev->name, csr5);
-				/* Hmmmmm, it's not clear what to do here. */
+			if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) {
+				if (tp->link_change)
+					(tp->link_change)(dev, csr5);
 			}
-			if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)
-				&& tp->chip_id == DC21142) {
-				if (tulip_debug > 1)
-					printk(KERN_INFO"%s: 21142 link change, CSR5 = %8.8x.\n",
-						   dev->name, csr5);
-				t21142_lnk_change(dev);
+			if (csr5 & SytemError) {
+				printk(KERN_ERR "%s: (%lu) System Error occured\n", dev->name, tp->nir);
 			}
 			/* Clear all error sources, included undocumented ones! */
 			outl(0x0800f7ba, ioaddr + CSR5);
+			oi++;
+		}
+		if (csr5 & TimerInt) {
+#if 0
+			if (tulip_debug > 2)
+				printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n",
+					   dev->name, csr5);
+			outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
+#endif
+			tp->ttimer = 0;
+			oi++;
 		}
-		if (--work_budget < 0) {
+		if (tx > maxtx || rx > maxrx || oi > maxoi) {
+#if 0
 			if (tulip_debug > 1)
-				printk(KERN_WARNING "%s: Too much work at interrupt, "
-					   "csr5=0x%8.8x.\n", dev->name, csr5);
+#endif
+				printk(KERN_WARNING "%s: Too much work during an interrupt, "
+					   "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi);
 			/* Acknowledge all interrupt sources. */
-			outl(0x8001ffff, ioaddr + CSR5);
-#ifdef notdef
-			/* Clear all but standard interrupt sources. */
-			outl((~csr5) & 0x0001ebef, ioaddr + CSR7);
+#if 0
+			/* Clear all interrupting sources, set timer to re-enable. */
+			outl(((~csr5) & 0x0001ebef) | NormalIntr | AbnormalIntr | TimerInt,
+				 ioaddr + CSR7);
+			outl(12, ioaddr + CSR11);
+			tp->ttimer = 1;
 #endif
 			break;
 		}
 	} while (1);
 
-	if (tulip_debug > 3)
+	tulip_refill_rx(dev);
+
+	/* check if we card is in suspend mode */
+	entry = tp->dirty_rx % RX_RING_SIZE;
+	if (tp->rx_skbuff[entry] == NULL) {
+		printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx);
+		if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) {
+			printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir);
+			outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt,
+				ioaddr + CSR7);
+			outl(TimerInt, ioaddr + CSR5);
+			outl(12, ioaddr + CSR11);
+			tp->ttimer = 1;
+		}
+	}
+
+	if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) {
+		tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed;
+	}
+
+	if (tulip_debug > 4)
 		printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
 			   dev->name, inl(ioaddr + CSR5));
 
+#if defined(__i386__)
+	clear_bit(0, (void*)&dev->interrupt);
+#else
 	dev->interrupt = 0;
-	clear_bit(0, (void*)&tp->interrupt);
+#endif
 	return;
 }
 
-static int
-tulip_rx(struct device *dev)
+static int tulip_refill_rx(struct device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int entry;
+	int refilled = 0;
+
+	/* Refill the Rx ring buffers. */
+	for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
+		entry = tp->dirty_rx % RX_RING_SIZE;
+		if (tp->rx_skbuff[entry] == NULL) {
+			struct sk_buff *skb;
+			skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ);
+			if (skb == NULL)
+				break;
+			skb->dev = dev;			/* Mark as being used by this device. */
+			tp->rx_ring[entry].buffer1 = virt_to_le32desc(skb->tail);
+			refilled++;
+		}
+		tp->rx_ring[entry].status = cpu_to_le32(DescOwned);
+	}
+	return refilled;
+}
+
+static int tulip_rx(struct device *dev)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	int entry = tp->cur_rx % RX_RING_SIZE;
 	int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
-	int work_done = 0;
+	int received = 0;
 
 	if (tulip_debug > 4)
 		printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
 			   tp->rx_ring[entry].status);
-	/* If we own the next entry, it's a new packet. Send it up. */
-	while (tp->rx_ring[entry].status >= 0) {
-		s32 status = tp->rx_ring[entry].status;
-
+	/* If we own the next entry, it is a new packet. Send it up. */
+	while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
+		s32 status = le32_to_cpu(tp->rx_ring[entry].status);
+
+		if (tulip_debug > 5)
+			printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
+				   dev->name, entry, status);
 		if (--rx_work_limit < 0)
 			break;
-		if ((status & 0x0300) != 0x0300) {
-			if ((status & 0xffff) != 0x7fff) { /* Ingore earlier buffers. */
-				if (tulip_debug > 1)
-					printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
-						   "multiple buffers, status %8.8x!\n",
+		if ((status & 0x38008300) != 0x0300) {
+			if ((status & 0x38000300) != 0x0300) {
+				/* Ingore earlier buffers. */
+				if ((status & 0xffff) != 0x7fff) {
+					if (tulip_debug > 1)
+						printk(KERN_WARNING "%s: Oversized Ethernet frame "
+							   "spanned multiple buffers, status %8.8x!\n",
+							   dev->name, status);
+					tp->stats.rx_length_errors++;
+				}
+			} else if (status & RxDescFatalErr) {
+				/* There was a fatal error. */
+				if (tulip_debug > 2)
+					printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
 						   dev->name, status);
-			  tp->stats.rx_length_errors++;
+				tp->stats.rx_errors++; /* end of a packet.*/
+				if (status & 0x0890) tp->stats.rx_length_errors++;
+				if (status & 0x0004) tp->stats.rx_frame_errors++;
+				if (status & 0x0002) tp->stats.rx_crc_errors++;
+				if (status & 0x0001) tp->stats.rx_fifo_errors++;
 			}
-		} else if (status & 0x8000) {
-			/* There was a fatal error. */
-			if (tulip_debug > 2)
-				printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
-					   dev->name, status);
-			tp->stats.rx_errors++; /* end of a packet.*/
-			if (status & 0x0890) tp->stats.rx_length_errors++;
-			if (status & 0x0004) tp->stats.rx_frame_errors++;
-			if (status & 0x0002) tp->stats.rx_crc_errors++;
-			if (status & 0x0001) tp->stats.rx_fifo_errors++;
 		} else {
 			/* Omit the four octet CRC from the length. */
-			short pkt_len = (status >> 16) - 4;
+			short pkt_len = ((status >> 16) & 0x7ff) - 4;
 			struct sk_buff *skb;
 
-			/* Check if the packet is long enough to just accept without
-			   copying to a properly sized skbuff. */
+#ifndef final_version
+			if (pkt_len > 1518) {
+				printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n",
+					   dev->name, pkt_len, pkt_len);
+				pkt_len = 1518;
+				tp->stats.rx_length_errors++;
+			}
+#endif
+			/* Check if the packet is long enough to accept without copying
+			   to a minimally-sized skbuff. */
 			if (pkt_len < rx_copybreak
-				&& (skb = DEV_ALLOC_SKB(pkt_len+2)) != NULL) {
+				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
-#if LINUX_VERSION_CODE < 0x10300
-				memcpy(skb->data, tp->rx_ring[entry].buffer1, pkt_len);
-#elif LINUX_VERSION_CODE < 0x20200  || defined(__alpha__)
-				memcpy(skb_put(skb, pkt_len),
-					   bus_to_virt(tp->rx_ring[entry].buffer1), pkt_len);
-#else
-				eth_copy_and_sum(skb, bus_to_virt(tp->rx_ring[entry].buffer1),
-								 pkt_len, 0);
+#if ! defined(__alpha__)
+				eth_copy_and_sum(skb, tp->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
+#else
+				memcpy(skb_put(skb, pkt_len), tp->rx_skbuff[entry]->tail,
+					   pkt_len);
 #endif
-				work_done++;
 			} else { 	/* Pass up the skb already on the Rx ring. */
-				skb = tp->rx_skbuff[entry];
+				char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len);
 				tp->rx_skbuff[entry] = NULL;
 #ifndef final_version
-				{
-					void *temp = skb_put(skb, pkt_len);
-					if (bus_to_virt(tp->rx_ring[entry].buffer1) != temp)
-						printk(KERN_ERR "%s: Internal consistency error! The "
-						   "skbuff addresses do not match in tulip_rx:"
-							   " %p vs. %p / %p.\n", dev->name,
-							   bus_to_virt(tp->rx_ring[entry].buffer1),
-							   skb->head, temp);
-				}
-#else
-				skb_put(skb, pkt_len);
+				if (le32desc_to_virt(tp->rx_ring[entry].buffer1) != temp)
+					printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
+						   "do not match in tulip_rx: %p vs. %p / %p.\n",
+						   dev->name,
+						   le32desc_to_virt(tp->rx_ring[entry].buffer1),
+						   skb->head, temp);
 #endif
 			}
-#if LINUX_VERSION_CODE > 0x10300
 			skb->protocol = eth_type_trans(skb, dev);
-#else
-			skb->len = pkt_len;
-#endif
 			netif_rx(skb);
 			dev->last_rx = jiffies;
 			tp->stats.rx_packets++;
@@ -2435,33 +2904,14 @@
 			tp->stats.rx_bytes += pkt_len;
 #endif
 		}
+		received++;
 		entry = (++tp->cur_rx) % RX_RING_SIZE;
 	}
 
-	/* Refill the Rx ring buffers. */
-	for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
-		entry = tp->dirty_rx % RX_RING_SIZE;
-		if (tp->rx_skbuff[entry] == NULL) {
-			struct sk_buff *skb;
-			skb = tp->rx_skbuff[entry] = DEV_ALLOC_SKB(PKT_BUF_SZ);
-			if (skb == NULL)
-				break;
-			skb->dev = dev;			/* Mark as being used by this device. */
-#if LINUX_VERSION_CODE > 0x10300
-			tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail);
-#else
-			tp->rx_ring[entry].buffer1 = virt_to_bus(skb->data);
-#endif
-			work_done++;
-		}
-		tp->rx_ring[entry].status = 0x80000000;
-	}
-
-	return work_done;
+	return received;
 }
 
-static int
-tulip_close(struct device *dev)
+static int tulip_close(struct device *dev)
 {
 	long ioaddr = dev->base_addr;
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
@@ -2476,22 +2926,20 @@
 
 	/* Disable interrupts by clearing the interrupt mask. */
 	outl(0x00000000, ioaddr + CSR7);
-	/* Stop the chip's Tx and Rx processes. */
+	/* Stop the Tx and Rx processes. */
 	outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
 	/* 21040 -- Leave the card in 10baseT state. */
 	if (tp->chip_id == DC21040)
 		outl(0x00000004, ioaddr + CSR13);
 
-	tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+	if (inl(ioaddr + CSR6) != 0xffffffff)
+		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
 
 	del_timer(&tp->timer);
 
-#ifdef SA_SHIRQ
 	free_irq(dev->irq, dev);
-#else
-	free_irq(dev->irq);
-	irq2dev_map[dev->irq] = 0;
-#endif
+
+	dev->if_port = tp->saved_if_port;
 
 	/* Free all the skbuffs in the Rx queue. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
@@ -2504,31 +2952,26 @@
 #if LINUX_VERSION_CODE < 0x20100
 			skb->free = 1;
 #endif
-#if (LINUX_VERSION_CODE > 0x20155)
-			dev_kfree_skb(skb);
-#else
-			dev_kfree_skb(skb, FREE_WRITE);
-#endif
+			dev_free_skb(skb);
 		}
 	}
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		if (tp->tx_skbuff[i])
-#if (LINUX_VERSION_CODE > 0x20155)
-			dev_kfree_skb(tp->tx_skbuff[i]);
-#else
-			dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE);
-#endif
+			dev_free_skb(tp->tx_skbuff[i]);
 		tp->tx_skbuff[i] = 0;
 	}
 
+	/* Leave the driver in snooze, not sleep, mode. */
+	if (tp->flags & HAS_PWRDWN)
+		pcibios_write_config_dword(tp->pci_bus, tp->pci_devfn, 0x40,
+								   0x40000000);
 
 	MOD_DEC_USE_COUNT;
 
 	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;
 	long ioaddr = dev->base_addr;
@@ -2551,31 +2994,32 @@
 
 	switch(cmd) {
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
-		if (tp->mtable  &&  tp->mtable->has_mii)
+		if (tp->mii_cnt)
 			data[0] = phy;
-		else if (tp->chip_id == DC21142)
+		else if (tp->flags & HAS_NWAY143)
 			data[0] = 32;
+		else if (tp->chip_id == COMET)
+			data[0] = 1;
 		else
 			return -ENODEV;
-		return 0;
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
-		if (data[0] == 32) {  /* 21142 pseudo-MII */
+		if (data[0] == 32  &&  (tp->flags & HAS_NWAY143)) {
 			int csr12 = inl(ioaddr + CSR12);
 			int csr14 = inl(ioaddr + CSR14);
 			switch (data[1]) {
 			case 0: {
-				data[3] = ((csr14<<13)&0x4000) + ((csr14<<5)&0x1000);
+				data[3] = (csr14<<5) & 0x1000;
 				break; }
 			case 1:
 				data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0)
 					+ (csr12&0x06 ? 0x04 : 0);
 				break;
 			case 4: {
-				int csr14 = inl(ioaddr + CSR14);
-				data[3] = ((csr14>>9)&0x0380) + ((csr14>>1)&0x20) + 1;
+				data[3] = ((csr14>>9)&0x07C0) +
+					((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1;
 				break;
 			}
-			case 5: data[3] = inl(ioaddr + CSR12) >> 16; break;
+			case 5: data[3] = csr12 >> 16; break;
 			default: data[3] = 0; break;
 			}
 		} else {
@@ -2586,9 +3030,11 @@
 		}
 		return 0;
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
-		if (!suser())
+		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
-		if (data[0] == 32) {  /* 21142 pseudo-MII */
+		if (data[0] == 32  &&  (tp->flags & HAS_NWAY143)) {
+			if (data[1] == 5)
+				tp->to_advertise = data[2];
 		} else {
 			save_flags(flags);
 			cli();
@@ -2613,9 +3059,9 @@
    N.B. Do not use for bulk data, use a table-based routine instead.
    This is common code and should be moved to net/core/crc.c */
 static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
+static inline u32 ether_crc_le(int length, unsigned char *data)
 {
-	unsigned int crc = 0xffffffff;	/* Initial value. */
+	u32 crc = 0xffffffff;	/* Initial value. */
 	while(--length >= 0) {
 		unsigned char current_octet = *data++;
 		int bit;
@@ -2629,80 +3075,107 @@
 	}
 	return crc;
 }
+static unsigned const ethernet_polynomial = 0x04c11db7U;
+static inline u32 ether_crc(int length, unsigned char *data)
+{
+    int crc = -1;
+
+    while(--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
+			crc = (crc << 1) ^
+				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
+    }
+    return crc;
+}
 
-#ifdef NEW_MULTICAST
 static void set_rx_mode(struct device *dev)
-#else
-static void set_rx_mode(struct device *dev, int num_addrs, void *addrs)
-#endif
 {
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	int csr6 = inl(ioaddr + CSR6) & ~0x00D5;
-	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 
 	tp->csr6 &= ~0x00D5;
 	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
-		outl(csr6 | 0x00C0, ioaddr + CSR6);
+		tp->csr6 |= 0x00C0;
+		csr6 |= 0x00C0;
 		/* Unconditionally log net taps. */
 		printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
-		tp->csr6 |= 0xC0;
 	} else if ((dev->mc_count > 1000)  ||  (dev->flags & IFF_ALLMULTI)) {
-		/* Too many to filter perfectly -- accept all multicasts. */
-		outl(csr6 | 0x0080, ioaddr + CSR6);
-		tp->csr6 |= 0x80;
+		/* Too many to filter well -- accept all multicasts. */
+		tp->csr6 |= 0x0080;
+		csr6 |= 0x0080;
+	} else	if (tp->flags & MC_HASH_ONLY) {
+		/* Some work-alikes have only a 64-entry hash filter table. */
+		/* Should verify correctness on big-endian/__powerpc__ */
+		struct dev_mc_list *mclist;
+		int i;
+		u32 mc_filter[2];		 /* Multicast hash filter */
+		if (dev->mc_count > 64) {		/* Arbitrary non-effective limit. */
+			tp->csr6 |= 0x0080;
+			csr6 |= 0x0080;
+		} else {
+			mc_filter[1] = mc_filter[0] = 0;
+			for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+				 i++, mclist = mclist->next)
+				set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter);
+			if (tp->chip_id == AX88140) {
+				outl(2, ioaddr + CSR13);
+				outl(mc_filter[0], ioaddr + CSR14);
+				outl(3, ioaddr + CSR13);
+				outl(mc_filter[1], ioaddr + CSR14);
+			} else if (tp->chip_id == COMET) { /* Has a simple hash filter. */
+				outl(mc_filter[0], ioaddr + 0xAC);
+				outl(mc_filter[1], ioaddr + 0xB0);
+			}
+		}
 	} else {
-		u32 *setup_frm = tp->setup_frame;
+		u16 *eaddrs, *setup_frm = tp->setup_frame;
 		struct dev_mc_list *mclist;
-		u16 *eaddrs;
-		u32 tx_flags;
+		u32 tx_flags = 0x08000000 | 192;
 		int i;
 
+		/* Note that only the low-address shortword of setup_frame is valid!
+		   The values are doubled for big-endian architectures. */
 		if (dev->mc_count > 14) { /* Must use a multicast hash table. */
-		  u16 hash_table[32];
-		  memset(hash_table, 0, sizeof(hash_table));
-		  /* This should work on big-endian machines as well. */
-		  for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-			   i++, mclist = mclist->next)
-			  set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
-					  hash_table);
-		  /* Copy the hash table to the setup frame.
-			 NOTE that only the LOW SHORTWORD of setup_frame[] is valid! */
-		  for (i = 0; i < 32; i++)
-			*setup_frm++ = hash_table[i];
-		  setup_frm += 7;
-		  tx_flags = 0x08400000 | 192;
-		  /* Too clever: i > 15 for fall-though. */
+			u16 hash_table[32];
+			tx_flags = 0x08400000 | 192;		/* Use hash filter. */
+			memset(hash_table, 0, sizeof(hash_table));
+			set_bit(255, hash_table); 			/* Broadcast entry */
+			/* This should work on big-endian machines as well. */
+			for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+				 i++, mclist = mclist->next)
+				set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
+						hash_table);
+			for (i = 0; i < 32; i++)
+				*setup_frm++ = *setup_frm++ = hash_table[i];
+			setup_frm = &tp->setup_frame[13*6];
 		} else {
-		  /* We have <= 15 addresses so we can use the wonderful
-			 16 address perfect filtering of the Tulip. */
-		  for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
-			   i++, mclist = mclist->next) {
-			/* Note that only the low shortword of setup_frame[] is valid!
-			   This code may require tweaking for non-x86 architectures! */
-			eaddrs = (u16 *)mclist->dmi_addr;
-			*setup_frm++ = *eaddrs++;
-			*setup_frm++ = *eaddrs++;
-			*setup_frm++ = *eaddrs++;
-		  }
-		  /* Fill the rest of the table with our physical address.
-			 Once again, only the low shortword or setup_frame[] is valid! */
-		  *setup_frm++ = 0xffff;
-		  *setup_frm++ = 0xffff;
-		  *setup_frm++ = 0xffff;
-		  tx_flags = 0x08000000 | 192;
+			/* We have <= 14 addresses so we can use the wonderful
+			   16 address perfect filtering of the Tulip. */
+			for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
+				 i++, mclist = mclist->next) {
+				eaddrs = (u16 *)mclist->dmi_addr;
+				*setup_frm++ = *setup_frm++ = *eaddrs++;
+				*setup_frm++ = *setup_frm++ = *eaddrs++;
+				*setup_frm++ = *setup_frm++ = *eaddrs++;
+			}
+			/* Fill the unused entries with the broadcast address. */
+			memset(setup_frm, 0xff, (15-i)*12);
+			setup_frm = &tp->setup_frame[15*6];
 		}
+		/* Fill the final entry with our physical address. */
 		eaddrs = (u16 *)dev->dev_addr;
-		do {
-			*setup_frm++ = eaddrs[0];
-			*setup_frm++ = eaddrs[1];
-			*setup_frm++ = eaddrs[2];
-		} while (++i < 15);
+		*setup_frm++ = *setup_frm++ = eaddrs[0];
+		*setup_frm++ = *setup_frm++ = eaddrs[1];
+		*setup_frm++ = *setup_frm++ = eaddrs[2];
 		/* Now add this frame to the Tx list. */
 		if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {
 			/* Same setup recently queued, we need not add it. */
 		} else {
 			unsigned long flags;
-			unsigned int entry, dummy = 0;
+			unsigned int entry;
 
 			save_flags(flags); cli();
 			entry = tp->cur_tx++ % TX_RING_SIZE;
@@ -2711,32 +3184,29 @@
 				/* Avoid a chip errata by prefixing a dummy entry. */
 				tp->tx_skbuff[entry] = 0;
 				tp->tx_ring[entry].length =
-					(entry == TX_RING_SIZE-1) ? 0x02000000 : 0;
+					(entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0;
 				tp->tx_ring[entry].buffer1 = 0;
-				/* race with chip, set DescOwned later */
-				dummy = entry;
+				tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
 				entry = tp->cur_tx++ % TX_RING_SIZE;
 			}
 
 			tp->tx_skbuff[entry] = 0;
 			/* Put the setup frame on the Tx list. */
 			if (entry == TX_RING_SIZE-1)
-				tx_flags |= 0x02000000;		/* Wrap ring. */
-			tp->tx_ring[entry].length = tx_flags;
-			tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);
-			tp->tx_ring[entry].status = 0x80000000;
+				tx_flags |= DESC_RING_WRAP;		/* Wrap ring. */
+			tp->tx_ring[entry].length = cpu_to_le32(tx_flags);
+			tp->tx_ring[entry].buffer1 = virt_to_le32desc(tp->setup_frame);
+			tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
 			if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {
-				dev->tbusy = 1;
+				set_bit(0, (void*)&dev->tbusy);
 				tp->tx_full = 1;
 			}
-			if (dummy >= 0)
-				tp->tx_ring[dummy].status = DescOwned;
 			restore_flags(flags);
 			/* Trigger an immediate transmit demand. */
 			outl(0, ioaddr + CSR1);
 		}
-		outl(csr6 | 0x0000, ioaddr + CSR6);
 	}
+	outl(csr6 | 0x0000, ioaddr + CSR6);
 }
 
 #ifdef CARDBUS
@@ -2745,18 +3215,18 @@
 
 static dev_node_t *tulip_attach(dev_locator_t *loc)
 {
+	struct device *dev;
 	u16 dev_id;
 	u32 io;
-	u8 bus, devfn;
-	struct device *dev;
+	u8 bus, devfn, irq;
 
 	if (loc->bus != LOC_PCI) return NULL;
 	bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
 	printk(KERN_INFO "tulip_attach(bus %d, function %d)\n", bus, devfn);
 	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
 	pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
-	io &= ~3;
-	dev = tulip_probe1(bus, devfn, NULL, DC21142, -1);
+	pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
+	dev = tulip_probe1(bus, devfn, NULL, io & ~3, irq, DC21142, 0);
 	if (dev) {
 		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
 		strcpy(node->dev_name, dev->name);
@@ -2768,6 +3238,45 @@
 	return NULL;
 }
 
+static void tulip_suspend(dev_node_t *node)
+{
+	struct device **devp, **next;
+	printk(KERN_INFO "tulip_suspend(%s)\n", node->dev_name);
+	for (devp = &root_tulip_dev; *devp; devp = next) {
+		next = &((struct tulip_private *)(*devp)->priv)->next_module;
+		if (strcmp((*devp)->name, node->dev_name) == 0) break;
+	}
+	if (*devp) {
+		long ioaddr = (*devp)->base_addr;
+		struct tulip_private *tp = (struct tulip_private *)(*devp)->priv;
+		int csr6 = inl(ioaddr + CSR6);
+		/* Disable interrupts, stop the chip, gather stats. */
+		if (csr6 != 0xffffffff) {
+			outl(0x00000000, ioaddr + CSR7);
+			outl(csr6 & ~0x2002, ioaddr + CSR6);
+			tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+		}
+		tulip_close(*devp);
+		/* Put the 21143 into sleep mode. */
+		pcibios_write_config_dword(tp->pci_bus,tp->pci_devfn, 0x40,0x80000000);
+	}
+}
+
+static void tulip_resume(dev_node_t *node)
+{
+	struct device **devp, **next;
+	printk(KERN_INFO "tulip_resume(%s)\n", node->dev_name);
+	for (devp = &root_tulip_dev; *devp; devp = next) {
+		next = &((struct tulip_private *)(*devp)->priv)->next_module;
+		if (strcmp((*devp)->name, node->dev_name) == 0) break;
+	}
+	if (*devp) {
+		struct tulip_private *tp = (struct tulip_private *)(*devp)->priv;
+		pcibios_write_config_dword(tp->pci_bus, tp->pci_devfn, 0x40, 0x0000);
+		tulip_open(*devp);
+	}
+}
+
 static void tulip_detach(dev_node_t *node)
 {
 	struct device **devp, **next;
@@ -2786,34 +3295,17 @@
 }
 
 struct driver_operations tulip_ops = {
-	"tulip_cb", tulip_attach, NULL, NULL, tulip_detach
+	"tulip_cb", tulip_attach, tulip_suspend, tulip_resume, tulip_detach
 };
 
 #endif  /* Cardbus support */
 
 
 #ifdef MODULE
-#if LINUX_VERSION_CODE > 0x20118
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(reverse_probe, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-#endif
-
-/* An additional parameter that may be passed in... */
-static int debug = -1;
-
-int
-init_module(void)
+int init_module(void)
 {
-	if (debug >= 0)
-		tulip_debug = debug;
-
 #ifdef CARDBUS
+	reverse_probe = 0;			/* Not used. */
 	register_driver(&tulip_ops);
 	return 0;
 #else
@@ -2821,8 +3313,7 @@
 #endif
 }
 
-void
-cleanup_module(void)
+void cleanup_module(void)
 {
 	struct device *next_dev;
 
@@ -2832,9 +3323,11 @@
 
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	while (root_tulip_dev) {
-		next_dev = ((struct tulip_private *)root_tulip_dev->priv)->next_module;
+		struct tulip_private *tp = (struct tulip_private *)root_tulip_dev->priv;
+		next_dev = tp->next_module;
 		unregister_netdev(root_tulip_dev);
-		release_region(root_tulip_dev->base_addr, TULIP_TOTAL_SIZE);
+		release_region(root_tulip_dev->base_addr,
+					   tulip_tbl[tp->chip_id].io_size);
 		kfree(root_tulip_dev);
 		root_tulip_dev = next_dev;
 	}
@@ -2844,8 +3337,9 @@
 
 /*
  * Local variables:
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c -o tulip_cb.o -I/usr/src/pcmcia-cs-3.0.9/include/"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/wavelan.c linux.14p16/drivers/net/wavelan.c
--- linux.vanilla/drivers/net/wavelan.c	Wed Oct 20 01:12:39 1999
+++ linux.14p16/drivers/net/wavelan.c	Thu Dec  9 15:33:27 1999
@@ -1910,18 +1910,18 @@
 
     case SIOCSIWNWID:
       /* Set NWID in WaveLAN. */
-      if(wrq->u.nwid.on)
+      if(!wrq->u.nwid.disabled)
 	{
-	  /* Set NWID in psa. */
-	  psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8;
-	  psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;
+	  /* Set NWID in psa */
+	  psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8;
+	  psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
 	  psa.psa_nwid_select = 0x01;
 	  psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
 		    (unsigned char *)psa.psa_nwid, 3);
 
 	  /* Set NWID in mmc. */
-	  m.w.mmw_netw_id_l = wrq->u.nwid.nwid & 0xFF;
-	  m.w.mmw_netw_id_h = (wrq->u.nwid.nwid & 0xFF00) >> 8;
+	  m.w.mmw_netw_id_l = psa.psa_nwid[1];
+	  m.w.mmw_netw_id_h = psa.psa_nwid[0];
 	  mmc_write(ioaddr, (char *)&m.w.mmw_netw_id_l - (char *)&m,
 		    (unsigned char *)&m.w.mmw_netw_id_l, 2);
 	  mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00);
@@ -1945,8 +1945,9 @@
       /* Read the NWID. */
       psa_read(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
 	       (unsigned char *)psa.psa_nwid, 3);
-      wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
-      wrq->u.nwid.on = psa.psa_nwid_select;
+      wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
+      wrq->u.nwid.disabled = !(psa.psa_nwid_select);
+      wrq->u.nwid.fixed = 1;	/* Superfluous */
       break;
 
     case SIOCSIWFREQ:
@@ -2006,83 +2007,96 @@
       wrq->u.sens.fixed = 1;
       break;
 
-     case SIOCSIWENCODE:
-       /* Set encryption key. */
-       if(!mmc_encr(ioaddr))
-	 {
-	   ret = -EOPNOTSUPP;
-	   break;
-	 }
-
-       if(wrq->u.encoding.method)
-	 {	/* Enable encryption. */
-	   int		i;
-	   long long	key = wrq->u.encoding.code;
-
-	   for(i = 7; i >= 0; i--)
-	     {
-	       psa.psa_encryption_key[i] = key & 0xFF;
-	       key >>= 8;
-	     }
-           psa.psa_encryption_select = 1;
-	   psa_write(ioaddr, lp->hacr,
-		     (char *) &psa.psa_encryption_select - (char *) &psa,
-		     (unsigned char *) &psa.psa_encryption_select, 8+1);
-
-           mmc_out(ioaddr, mmwoff(0, mmw_encr_enable),
-		   MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
-           mmc_write(ioaddr, mmwoff(0, mmw_encr_key),
-		     (unsigned char *) &psa.psa_encryption_key, 8);
-	 }
-       else
-	 {	/* Disable encryption. */
-	   psa.psa_encryption_select = 0;
-	   psa_write(ioaddr, lp->hacr,
-		     (char *) &psa.psa_encryption_select - (char *) &psa,
-		     (unsigned char *) &psa.psa_encryption_select, 1);
-
-	   mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0);
-	 }
-       /* update the Wavelan checksum */
-       update_psa_checksum(dev, ioaddr, lp->hacr);
-       break;
-
-     case SIOCGIWENCODE:
-       /* Read the encryption key. */
-       if(!mmc_encr(ioaddr))
-	 {
-	   ret = -EOPNOTSUPP;
-	   break;
-	 }
-
-       /* Only super-user can see encryption key. */
-       if(!suser())
-	 {
-	   ret = -EPERM;
-	   break;
-	 }
-       else
-	 {
-	   int		i;
-	   long long	key = 0;
+    case SIOCSIWENCODE:
+      /* Set encryption key */
+      if(!mmc_encr(ioaddr))
+	{
+	  ret = -EOPNOTSUPP;
+	  break;
+	}
+
+      /* Basic checking... */
+      if(wrq->u.encoding.pointer != (caddr_t) 0)
+	{
+	  /* Check the size of the key */
+	  if(wrq->u.encoding.length != 8)
+	    {
+	      ret = -EINVAL;
+	      break;
+	    }
 
-	   psa_read(ioaddr, lp->hacr,
+	  /* Copy the key in the driver */
+	  if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer,
+			    wrq->u.encoding.length))
+	    {
+	      ret = -EFAULT;
+	      break;
+	    }
+
+	  psa.psa_encryption_select = 1;
+	  psa_write(ioaddr, lp->hacr,
 		    (char *) &psa.psa_encryption_select - (char *) &psa,
-		    (unsigned char *) &psa.psa_encryption_select, 1+8);
-	   for(i = 0; i < 8; i++)
-	     {
-	       key <<= 8;
-	       key += psa.psa_encryption_key[i];
-	     }
-	   wrq->u.encoding.code = key;
-
-	   /* encryption is enabled */
-	   if(psa.psa_encryption_select)
-	     wrq->u.encoding.method = mmc_encr(ioaddr);
-	   else
-	     wrq->u.encoding.method = 0;
-	 }
-       break;
+		    (unsigned char *) &psa.psa_encryption_select, 8+1);
+
+	  mmc_out(ioaddr, mmwoff(0, mmw_encr_enable),
+		  MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
+	  mmc_write(ioaddr, mmwoff(0, mmw_encr_key),
+		    (unsigned char *) &psa.psa_encryption_key, 8);
+	}
+
+      if(wrq->u.encoding.flags & IW_ENCODE_DISABLED)
+	{	/* disable encryption */
+	  psa.psa_encryption_select = 0;
+	  psa_write(ioaddr, lp->hacr,
+		    (char *) &psa.psa_encryption_select - (char *) &psa,
+		    (unsigned char *) &psa.psa_encryption_select, 1);
+
+	  mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0);
+	}
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev, ioaddr, lp->hacr);
+      break;
+
+    case SIOCGIWENCODE:
+      /* Read the encryption key */
+      if(!mmc_encr(ioaddr))
+	{
+	  ret = -EOPNOTSUPP;
+	  break;
+	}
+
+      /* only super-user can see encryption key */
+      if(!suser())
+	{
+	  ret = -EPERM;
+	  break;
+	}
+
+      /* Basic checking... */
+      if(wrq->u.encoding.pointer != (caddr_t) 0)
+	{
+	  /* Verify the user buffer */
+	  ret = verify_area(VERIFY_WRITE, wrq->u.encoding.pointer, 8);
+	  if(ret)
+	    break;
+
+	  psa_read(ioaddr, lp->hacr,
+		   (char *) &psa.psa_encryption_select - (char *) &psa,
+		   (unsigned char *) &psa.psa_encryption_select, 1+8);
+
+	  /* encryption is enabled ? */
+	  if(psa.psa_encryption_select)
+	    wrq->u.encoding.flags = IW_ENCODE_ENABLED;
+	  else
+	    wrq->u.encoding.flags = IW_ENCODE_DISABLED;
+	  wrq->u.encoding.flags |= mmc_encr(ioaddr);
+
+	  /* Copy the key to the user buffer */
+	  wrq->u.encoding.length = 8;
+	  if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8))
+	    ret = -EFAULT;
+	}
+      break;
 
     case SIOCGIWRANGE:
       /* basic checking */
@@ -2116,6 +2130,19 @@
 
 	  range.num_bitrates = 1;
 	  range.bitrate[0] = 2000000;	/* 2 Mb/s */
+
+	  /* Encryption supported ? */
+	  if(mmc_encr(ioaddr))
+	    {
+	      range.encoding_size[0] = 8;	/* DES = 64 bits key */
+	      range.num_encoding_sizes = 1;
+	      range.max_encoding_tokens = 1;	/* Only one key possible */
+	    }
+	  else
+	    {
+	      range.num_encoding_sizes = 0;
+	      range.max_encoding_tokens = 0;
+	    }
 
 	  /* Copy structure to the user buffer. */
 	  if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range)))
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/wavelan.p.h linux.14p16/drivers/net/wavelan.p.h
--- linux.vanilla/drivers/net/wavelan.p.h	Sat Aug 14 02:27:30 1999
+++ linux.14p16/drivers/net/wavelan.p.h	Tue Dec 21 01:03:03 1999
@@ -300,6 +300,11 @@
  *	- Add the (short) list of bit-rates in range
  *	- Developp a new sensitivity... (sens.value & sens.fixed)
  *
+ * Changes made for release in 2.2.14 & 2.3.23 :
+ * -------------------------------------------
+ *	- Fix check for root permission (break instead of exit)
+ *	- New nwid & encoding setting (Wireless Extension 9)
+ *
  * Wishes & dreams:
  * ----------------
  *	- roaming (see Pcmcia driver)
@@ -390,7 +395,7 @@
 /************************ CONSTANTS & MACROS ************************/
 
 #ifdef DEBUG_VERSION_SHOW
-static const char	*version	= "wavelan.c : v20 (wireless extensions) 29/7/99\n";
+static const char	*version	= "wavelan.c : v21 (wireless extensions) 16/10/99\n";
 #endif
 
 /* Watchdog temporisation */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/z85230.c linux.14p16/drivers/net/z85230.c
--- linux.vanilla/drivers/net/z85230.c	Sat Aug 14 02:27:30 1999
+++ linux.14p16/drivers/net/z85230.c	Thu Dec  9 15:33:31 1999
@@ -14,10 +14,6 @@
  *	Asynchronous mode dropped for 2.2. For 2.3 we will attempt the
  *	unification of all the Z85x30 asynchronous drivers for real.
  *
- *	To Do:
- *	
- *	Finish DMA mode support.
- *
  *	Performance
  *
  *	Z85230:
@@ -169,7 +165,7 @@
 /*
  *	As above but for enhanced chips.
  */
-
+ 
 u8 z8530_hdlc_kilostream_85230[]=
 {
 	4,	SYNC_ENAB|SDLC|X1CLK,
@@ -354,13 +350,15 @@
 		z8530_tx_done(chan);
 	}
 		
-	if(altered&DCD)
+	if(altered&chan->dcdcheck)
 	{
-		if(status&DCD)
+		if(status&chan->dcdcheck)
 		{
 			printk(KERN_INFO "%s: DCD raised\n", chan->dev->name);
 			write_zsreg(chan, R3, chan->regs[3]|RxENABLE);
-			if(chan->netdevice)
+			if(chan->netdevice &&
+			    ((chan->netdevice->type == ARPHRD_HDLC) ||
+			    (chan->netdevice->type == ARPHRD_PPP)))
 				sppp_reopen(chan->netdevice);
 		}
 		else
@@ -440,7 +438,6 @@
 		if(status&TxEOM)
 		{
 			flags=claim_dma_lock();
-			/* Transmit underrun */
 			disable_dma(chan->txdma);
 			clear_dma_ff(chan->txdma);	
 			chan->txdma_on=0;
@@ -448,13 +445,15 @@
 			z8530_tx_done(chan);
 		}
 	}
-	if(altered&DCD)
+	if(altered&chan->dcdcheck)
 	{
-		if(status&DCD)
+		if(status&chan->dcdcheck)
 		{
 			printk(KERN_INFO "%s: DCD raised\n", chan->dev->name);
 			write_zsreg(chan, R3, chan->regs[3]|RxENABLE);
-			if(chan->netdevice)
+			if(chan->netdevice &&
+			    ((chan->netdevice->type == ARPHRD_HDLC) ||
+			    (chan->netdevice->type == ARPHRD_PPP)))
 				sppp_reopen(chan->netdevice);
 		}
 		else
@@ -1012,6 +1011,8 @@
 	   floating IRQ transition when we reset the chip */
 	dev->chanA.irqs=&z8530_nop;
 	dev->chanB.irqs=&z8530_nop;
+	dev->chanA.dcdcheck=DCD;
+	dev->chanB.dcdcheck=DCD;
 	/* Reset the chip */
 	write_zsreg(&dev->chanA, R9, 0xC0);
 	udelay(200);
@@ -1104,7 +1105,7 @@
 	c->mtu=1500;
 	c->max=0;
 	c->count=0;
-	c->status=0;	/* Fixme - check DCD now */
+	c->status=read_zsreg(c, R0);
 	c->sync=1;
 	write_zsreg(c, R3, c->regs[R3]|RxENABLE);
 	return 0;
@@ -1251,7 +1252,7 @@
 		 *	Save the ready state and the buffer currently
 		 *	being used as the DMA target
 		 */
-
+		 
 		int ready=c->dma_ready;
 		unsigned char *rxb=c->rx_buf[c->dma_num];
 		unsigned long flags;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/z85230.h linux.14p16/drivers/net/z85230.h
--- linux.vanilla/drivers/net/z85230.h	Sat Oct 17 23:33:45 1998
+++ linux.14p16/drivers/net/z85230.h	Thu Dec  9 15:33:31 1999
@@ -270,6 +270,7 @@
 	struct sk_buff	*skb;		/* Buffer dptr points into */
 	struct sk_buff	*skb2;		/* Pending buffer */
 	u8		status;		/* Current DCD */
+	u8		dcdcheck;	/* which bit to check for line */
 	u8		sync;		/* Set if in sync mode */
 
 	u8		regs[32];	/* Register map for the chip */
@@ -413,7 +414,7 @@
  *	Standard interrupt vector sets
  */
  
-struct z8530_irqhandler z8530_sync, z8530_async, z8530_nop;
+extern struct z8530_irqhandler z8530_sync, z8530_async, z8530_nop;
 
 /*
  *	Asynchronous Interfacing
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/pci/oldproc.c linux.14p16/drivers/pci/oldproc.c
--- linux.vanilla/drivers/pci/oldproc.c	Wed Oct 20 01:12:39 1999
+++ linux.14p16/drivers/pci/oldproc.c	Thu Dec  9 15:34:05 1999
@@ -396,6 +396,9 @@
 	DEVICE( ALLIANCE,	ALLIANCE_PROVIDEO, "Provideo"),
 	DEVICE( ALLIANCE,	ALLIANCE_AT24,	"AT24"),
 	DEVICE( ALLIANCE,	ALLIANCE_AT3D,	"AT3D"),
+	DEVICE( SYSKONNECT,	SYSKONNECT_FP,	"SK-FDDI-PCI"),
+	DEVICE( SYSKONNECT,	SYSKONNECT_TR,	"SK-TR-PCI"),
+	DEVICE( SYSKONNECT,	SYSKONNECT_GE,	"SK-98xx"),
 	DEVICE( VMIC,		VMIC_VME,	"VMIVME-7587"),
 	DEVICE( DIGI,		DIGI_EPC,	"AccelPort EPC"),
  	DEVICE( DIGI,		DIGI_RIGHTSWITCH, "RightSwitch SE-6"),
@@ -526,6 +529,7 @@
 	DEVICE( INTEL,		INTEL_82441,	"82441FX Natoma"),
 	DEVICE( INTEL,		INTEL_82380FB,	"82380FB Mobile"),
 	DEVICE( INTEL,		INTEL_82439,	"82439HX Triton II"),
+	DEVICE(	INTEL,		INTEL_MEGARAID,	"OEM MegaRAID Controller"),
 	DEVICE(	INTEL,		INTEL_82371SB_0,"82371SB PIIX3 ISA"),
 	DEVICE(	INTEL,		INTEL_82371SB_1,"82371SB PIIX3 IDE"),
 	DEVICE( INTEL,		INTEL_82371SB_2,"82371SB PIIX3 USB"),
@@ -536,13 +540,16 @@
 	DEVICE( INTEL,		INTEL_82371AB_2,"82371AB PIIX4 USB"),
 	DEVICE( INTEL,		INTEL_82371AB_3,"82371AB PIIX4 ACPI"),
 	DEVICE( INTEL,		INTEL_82443LX_0,"440LX - 82443LX PAC Host"),
-	DEVICE( COMPUTONE,	COMPUTONE_IP2EX, "Computone IntelliPort Plus"),
 	DEVICE( INTEL,		INTEL_82443LX_1,"440LX - 82443LX PAC AGP"),
 	DEVICE( INTEL,		INTEL_82443BX_0,"440BX - 82443BX Host"),
 	DEVICE( INTEL,		INTEL_82443BX_1,"440BX - 82443BX AGP"),
 	DEVICE( INTEL,		INTEL_82443BX_2,"440BX - 82443BX Host (no AGP)"),
 	DEVICE( INTEL,		INTEL_P6,	"Orion P6"),
- 	DEVICE( INTEL,		INTEL_82450GX,	"82450GX Orion P6"),
+ 	DEVICE( INTEL,		INTEL_82450GX,	"450KX/GX [Orion] - 82454KX/GX PCI Bridge"),
+ 	DEVICE( INTEL,		INTEL_82453GX,	"450KX/GX [Orion] - 82453KX/GX Memory Controller"),
+ 	DEVICE( INTEL,		INTEL_82451NX,	"450NX - 82451NX Memory & I/O Controller"),
+ 	DEVICE( INTEL,		INTEL_82454NX,	"450NX - 82454NX PCI Expander Bridge"),
+	DEVICE( COMPUTONE,	COMPUTONE_IP2EX, "Computone IntelliPort Plus"),
 	DEVICE(	KTI,		KTI_ET32P2,	"ET32P2"),
 	DEVICE( ADAPTEC,	ADAPTEC_7810,	"AIC-7810 RAID"),
 	DEVICE( ADAPTEC,	ADAPTEC_7821,	"AIC-7860"),
@@ -847,6 +854,7 @@
 	      case PCI_VENDOR_ID_ATRONICS:	return "Atronics";
 	      case PCI_VENDOR_ID_TIGERJET:	return "TigerJet";
 	      case PCI_VENDOR_ID_ARK:		return "ARK Logic";
+	      case PCI_VENDOR_ID_SYSKONNECT:	return "SysKonnect";
 	      default:				return "Unknown vendor";
 	}
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/Config.in linux.14p16/drivers/s390/Config.in
--- linux.vanilla/drivers/s390/Config.in	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/Config.in	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,67 @@
+mainmenu_option next_comment
+comment 'S/390 block device drivers'
+
+tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
+if [ "$CONFIG_NET" = "y" ]; then
+  tristate 'Network block device support' CONFIG_BLK_DEV_NBD
+fi
+bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
+if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
+  tristate '   Linear (append) mode' CONFIG_MD_LINEAR
+  tristate '   RAID-0 (striping) mode' CONFIG_MD_STRIPED
+  tristate '   RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING
+  tristate '   RAID-4/RAID-5 mode' CONFIG_MD_RAID5
+fi
+if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
+  bool '      Boot support (linear, striped)' CONFIG_MD_BOOT
+fi
+tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
+if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
+  bool '   Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
+fi
+
+bool 'Support for VM minidisk (VM only)' CONFIG_MDISK
+if [ "$CONFIG_MDISK" = "y" ]; then
+  bool '   Support for synchronous read-write' CONFIG_MDISK_SYNC
+fi
+
+tristate 'Support for DASD devices' CONFIG_DASD
+if [ "$CONFIG_DASD" != "n"  ]; then
+  comment 'DASD disciplines'
+  bool '   Support for ECKD Disks' CONFIG_DASD_ECKD
+fi
+
+#menu_option next_comment
+#endmenu
+
+if [ "$CONFIG_NET" = "y" ]; then
+  mainmenu_option next_comment
+  comment 'S/390 Network device support'
+
+  bool 'Network device support' CONFIG_NETDEVICES
+  if [ "$CONFIG_NETDEVICES" = "y" ]; then
+    menu_option next_comment
+    comment 'S390 Network devices'
+    bool 'CTC device support' CONFIG_CTC
+    bool 'IUCV device support (VM only)' CONFIG_IUCV
+    tristate 'Dummy net driver support' CONFIG_DUMMY
+    bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
+    bool 'Token Ring driver support' CONFIG_TR
+  fi
+  endmenu
+fi
+
+mainmenu_option next_comment
+comment 'S/390 Terminal and Console options'
+
+bool 'Support for 3215 line mode terminal' CONFIG_3215
+if [ "$CONFIG_3215" = "y" ]; then
+  bool 'Support for console on 3215 line mode terminal' CONFIG_3215_CONSOLE
+fi
+
+bool 'Support for HWC line mode terminal' CONFIG_HWC
+if [ "$CONFIG_HWC" = "y" ]; then
+  bool 'console on HWC line mode terminal' CONFIG_HWC_CONSOLE
+fi
+endmenu
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/Makefile linux.14p16/drivers/s390/Makefile
--- linux.vanilla/drivers/s390/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/Makefile	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,40 @@
+#
+# Makefile for the linux i386-specific parts of the memory manager.
+#
+# 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...
+
+all: io.o
+
+CFLAGS += 
+O_TARGET := io.o
+O_OBJS    :=         
+M_OBJS   :=
+
+SUBDIRS := $(SUBDIRS) arch/s390/drivers/block arch/s390/drivers/char \
+	arch/s390/drivers/misc  arch/s390/drivers/net
+MOD_SUB_DIRS += ./net
+
+O_OBJS := block/s390-block.o \
+  char/s390-char.o \
+  misc/s390-misc.o \
+  net/s390-net.o 
+
+io.o: $(O_OBJS)
+
+block/s390-block.o: dummy
+	$(MAKE)  -C block
+
+char/s390-char.o: dummy
+	$(MAKE)  -C char
+
+misc/s390-misc.o: dummy
+	$(MAKE) -C misc
+
+net/s390-net.o: dummy
+	$(MAKE) -C net
+
+include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/block/Makefile linux.14p16/drivers/s390/block/Makefile
--- linux.vanilla/drivers/s390/block/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/block/Makefile	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,25 @@
+all: s390-block.o
+
+CFLAGS += 
+O_TARGET := s390-block.o
+O_OBJS   :=         
+M_OBJS   :=
+
+ifeq ($(CONFIG_DASD),y)
+  O_OBJS += dasd.o dasd_ccwstuff.o 
+  ifeq ($(CONFIG_PROC_FS),y)
+   O_OBJS += dasd_proc.o dasd_profile.o
+  endif 
+  ifeq ($(CONFIG_DASD_ECKD),y)
+   O_OBJS += dasd_eckd.o
+  endif 
+endif
+
+ifeq ($(CONFIG_MDISK),y)
+  O_OBJS += mdisk.o
+endif
+
+dasd_mod.o: $(D_OBJS)
+	$(LD) $(LD_RFLAG) -r -o $@ $+
+
+include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/block/dasd.c linux.14p16/drivers/s390/block/dasd.c
--- linux.vanilla/drivers/s390/block/dasd.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/block/dasd.c	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,1490 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *                : Utz Bacher <utz.bacher@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif				/* MODULE */
+
+#include <linux/tqueue.h>
+#include <linux/timer.h>
+#include <linux/malloc.h>
+#include <linux/genhd.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/ctype.h>
+#include <asm/io.h>
+#include <asm/spinlock.h>
+#include <asm/semaphore.h>
+#include <asm/ebcdic.h>
+#include <asm/uaccess.h>
+
+#include "../../../arch/s390/kernel/irq.h"
+
+#include "dasd.h"
+#include <linux/blk.h>
+
+#include "dasd_types.h"
+#include "dasd_ccwstuff.h"
+
+#define PRINTK_HEADER DASD_NAME":"
+
+#define CCW_READ_DEVICE_CHARACTERISTICS  0x64
+
+#define DASD_SSCH_RETRIES 5
+
+/* This macro is a little tricky, but makes the code more easy to read... */
+#define MATCH(info,ct,cm,dt,dm) ( \
+( info -> sid_data.cu_type  ct ) && ( info -> sid_data.cu_model cm ) && \
+( info -> sid_data.dev_type dt ) && ( info -> sid_data.dev_model dm ) )
+
+/* Prototypes for the functions called from external */
+static ssize_t dasd_read (struct file *, char *, size_t, loff_t *);
+static ssize_t dasd_write (struct file *, const char *, size_t, loff_t *);
+static int dasd_ioctl (struct inode *, struct file *, unsigned int, unsigned long);
+static int dasd_open (struct inode *, struct file *);
+static int dasd_fsync (struct file *, struct dentry *);
+static int dasd_release (struct inode *, struct file *);
+void dasd_debug (unsigned long tag);
+void dasd_profile_add (cqr_t *cqr);
+void dasd_proc_init (void);
+
+static struct file_operations dasd_file_operations;
+
+spinlock_t dasd_lock;		/* general purpose lock for the dasd driver */
+
+/* All asynchronous I/O should waint on this wait_queue */
+struct wait_queue *dasd_waitq = NULL;
+
+static int dasd_autodetect = 1;
+static int dasd_devno[DASD_MAX_DEVICES] =
+{0,};
+static int dasd_count = 0;
+
+extern dasd_chanq_t *cq_head;
+
+static int
+dasd_get_hexdigit (char c)
+{
+	if ((c >= '0') && (c <= '9'))
+		return c - '0';
+	if ((c >= 'a') && (c <= 'f'))
+		return c + 10 - 'a';
+	if ((c >= 'A') && (c <= 'F'))
+		return c + 10 - 'A';
+	return -1;
+}
+
+/* sets the string pointer after the next comma */
+static void
+dasd_scan_for_next_comma (char **strptr)
+{
+	while (((**strptr) != ',') && ((**strptr)++))
+		(*strptr)++;
+
+	/* set the position AFTER the comma */
+	if (**strptr == ',')
+		(*strptr)++;
+}
+
+/*sets the string pointer after the next comma, if a parse error occured */
+static int
+dasd_get_next_int (char **strptr)
+{
+	int j, i = -1;		/* for cosmetic reasons first -1, then 0 */
+	if (isxdigit (**strptr)) {
+		for (i = 0; isxdigit (**strptr);) {
+			i <<= 4;
+			j = dasd_get_hexdigit (**strptr);
+			if (j == -1) {
+				PRINT_ERR ("no integer: skipping range.\n");
+				dasd_scan_for_next_comma (strptr);
+				i = -1;
+				break;
+			}
+			i += j;
+			(*strptr)++;
+			if (i > 0xffff) {
+				PRINT_ERR (" value too big, skipping range.\n");
+				dasd_scan_for_next_comma (strptr);
+				i = -1;
+				break;
+			}
+		}
+	}
+	return i;
+}
+
+static inline int
+devindex_from_devno (int devno)
+{
+	int i;
+	for (i = 0; i < dasd_count; i++) {
+		if (dasd_devno[i] == devno)
+			return i;
+	}
+	if (dasd_autodetect) {
+		if (dasd_count < DASD_MAX_DEVICES) {
+			dasd_devno[dasd_count] = devno;
+			return dasd_count++;
+		}
+		return -EOVERFLOW;
+	}
+	return -ENODEV;
+}
+
+/* returns 1, if dasd_no is in the specified ranges, otherwise 0 */
+static inline int
+dasd_is_accessible (int devno)
+{
+	return (devindex_from_devno (devno) >= 0);
+}
+
+/* dasd_insert_range skips ranges, if the start or the end is -1 */
+static void
+dasd_insert_range (int start, int end)
+{
+	int curr;
+	FUNCTION_ENTRY ("dasd_insert_range");
+	if (dasd_count >= DASD_MAX_DEVICES) {
+		PRINT_ERR (" too many devices specified, ignoring some.\n");
+		FUNCTION_EXIT ("dasd_insert_range");
+		return;
+	}
+	if ((start == -1) || (end == -1)) {
+		PRINT_ERR ("invalid format of parameter, skipping range\n");
+		FUNCTION_EXIT ("dasd_insert_range");
+		return;
+	}
+	if (end < start) {
+		PRINT_ERR (" ignoring range from %x to %x - start value " \
+			   "must be less than end value.\n", start, end);
+		FUNCTION_EXIT ("dasd_insert_range");
+		return;
+	}
+/* concurrent execution would be critical, but will not occur here */
+	for (curr = start; curr <= end; curr++) {
+		if (dasd_is_accessible (curr)) {
+			PRINT_WARN (" %x is already in list as device %d\n",
+				    curr, devindex_from_devno (curr));
+		}
+		dasd_devno[dasd_count] = curr;
+		dasd_count++;
+		if (dasd_count >= DASD_MAX_DEVICES) {
+			PRINT_ERR (" too many devices specified, ignoring some.\n");
+			break;
+		}
+	}
+	PRINT_INFO (" added dasd range from %x to %x.\n",
+		    start, dasd_devno[dasd_count - 1]);
+
+	FUNCTION_EXIT ("dasd_insert_range");
+}
+
+void
+dasd_setup (char *str, int *ints)
+{
+	int devno, devno2;
+
+	FUNCTION_ENTRY ("dasd_setup");
+	dasd_autodetect = 0;
+	while (*str && *str != 1) {
+		if (!isxdigit (*str)) {
+			str++;	/* to avoid looping on two commas */
+			PRINT_ERR (" kernel parameter in invalid format.\n");
+			continue;
+		}
+		devno = dasd_get_next_int (&str);
+
+		/* range was skipped? -> scan for comma has been done */
+		if (devno == -1)
+			continue;
+
+		if (*str == ',') {
+			str++;
+			dasd_insert_range (devno, devno);
+			continue;
+		}
+		if (*str == '-') {
+			str++;
+			devno2 = dasd_get_next_int (&str);
+			if (devno2 == -1) {
+				PRINT_ERR (" invalid character in " \
+					   "kernel parameters.");
+			} else {
+				dasd_insert_range (devno, devno2);
+			}
+			dasd_scan_for_next_comma (&str);
+			continue;
+		}
+		if (*str == 0) {
+			dasd_insert_range (devno, devno);
+			break;
+		}
+		PRINT_ERR (" unexpected character in kernel parameter, " \
+			   "skipping range.\n");
+	}
+	FUNCTION_EXIT ("dasd_setup");
+}
+
+static void
+dd_geninit (struct gendisk *ignored)
+{
+	FUNCTION_ENTRY ("dd_geninit");
+	FUNCTION_EXIT ("dd_geninit");
+}
+
+static struct hd_struct dd_hdstruct[DASD_MAX_DEVICES << PARTN_BITS];
+static int dd_blocksizes[DASD_MAX_DEVICES << PARTN_BITS];
+
+struct gendisk dd_gendisk =
+{
+	MAJOR_NR,		/* Major number */
+	"dd",			/* Major name */
+	PARTN_BITS,		/* Bits to shift to get real from partn */
+	1 << PARTN_BITS,	/* Number of partitions per real */
+	DASD_MAX_DEVICES,	/* maximum number of real */
+	dd_geninit,		/* init function */
+	dd_hdstruct,		/* hd struct */
+	dd_blocksizes,		/* block sizes */
+	0,			/* number */
+	NULL,			/* internal */
+	NULL			/* next */
+
+};
+
+void
+sleep_done (struct semaphore *sem)
+{
+	if (sem != NULL) {
+		up (sem);
+	}
+}
+
+void
+sleep (int timeout)
+{
+	struct semaphore sem = MUTEX_LOCKED;
+	struct timer_list timer;
+
+	init_timer (&timer);
+	timer.data = (unsigned long) &sem;
+	timer.expires = jiffies + timeout;
+	timer.function = (void (*)(unsigned long)) sleep_done;
+	printk (KERN_DEBUG PRINTK_HEADER
+		"Sleeping for timer tics %d\n", timeout);
+	add_timer (&timer);
+	down (&sem);
+	del_timer (&timer);
+}
+
+#ifdef CONFIG_DASD_ECKD
+extern dasd_operations_t dasd_eckd_operations;
+#endif				/* CONFIG_DASD_ECKD */
+
+dasd_operations_t *dasd_disciplines[] =
+{
+#ifdef CONFIG_DASD_ECKD
+	&dasd_eckd_operations
+#endif				/* CONFIG_DASD_ECKD */
+};
+
+char *dasd_name[] =
+{
+#ifdef CONFIG_DASD_ECKD
+	"ECKD"
+#endif				/* CONFIG_DASD_ECKD */
+};
+
+dasd_information_t *dasd_info[DASD_MAX_DEVICES] =
+{NULL,};
+
+static int dasd_blks[256] =
+{0,};
+static int dasd_secsize[256] =
+{0,};
+static int dasd_blksize[256] =
+{0,};
+static int dasd_maxsecs[256] =
+{0,};
+
+void
+fill_sizes (int di)
+{
+	int rc;
+	int minor;
+	rc = dasd_disciplines[dasd_info[di]->type]->fill_sizes (di);
+	switch (rc) {
+	case -EMEDIUMTYPE:
+		dasd_info[di]->flags |= DASD_NOT_FORMATTED;
+		break;
+	}
+	PRINT_INFO ("%ld kB <- 'soft'-block: %d, hardsect %d Bytes\n",
+		    dasd_info[di]->sizes.kbytes,
+		    dasd_info[di]->sizes.bp_block,
+		    dasd_info[di]->sizes.bp_sector);
+	switch (dasd_info[di]->type) {
+#ifdef CONFIG_DASD_ECKD
+	case dasd_eckd:
+		dasd_info[di]->sizes.first_sector =
+		    3 << dasd_info[di]->sizes.s2b_shift;
+		break;
+#endif				/* CONFIG_DASD_ECKD */
+	default:
+		INTERNAL_CHECK ("Unknown dasd type %d\n", dasd_info[di]->type);
+	}
+	minor = di << PARTN_BITS;
+	dasd_blks[minor] = dasd_info[di]->sizes.kbytes;
+	dasd_secsize[minor] = dasd_info[di]->sizes.bp_sector;
+	dasd_blksize[minor] = dasd_info[di]->sizes.bp_block;
+	dasd_maxsecs[minor] = 
+                ((PAGE_SIZE/sizeof(ccw1_t))-4)<<dasd_info[di]->sizes.s2b_shift;
+	dasd_blks[minor + 1] = dasd_info[di]->sizes.kbytes -
+	    (dasd_info[di]->sizes.first_sector >> 1);
+	dasd_secsize[minor + 1] = dasd_info[di]->sizes.bp_sector;
+	dasd_blksize[minor + 1] = dasd_info[di]->sizes.bp_block;
+	dasd_maxsecs[minor+1] = 
+                ((PAGE_SIZE/sizeof(ccw1_t))-4)<<dasd_info[di]->sizes.s2b_shift;
+}
+
+int
+dasd_format (int dev, format_data_t * fdata)
+{
+	int rc;
+	int devindex = DEVICE_NR (dev);
+	PRINT_INFO ("Format called with devno %x\n", dev);
+	if (MINOR (dev) & (0xff >> (8 - PARTN_BITS))) {
+		PRINT_WARN ("Can't format partition! minor %x %x\n",
+			    MINOR (dev), 0xff >> (8 - PARTN_BITS));
+		return -EINVAL;
+	}
+	down (&dasd_info[devindex]->sem);
+	if (dasd_info[devindex]->open_count == 1) {
+		rc = dasd_disciplines[dasd_info[devindex]->type]->
+		    dasd_format (devindex, fdata);
+		if (rc) {
+			PRINT_WARN ("Formatting failed rc=%d\n", rc);
+		}
+	} else {
+		PRINT_WARN ("device is open! %d\n", dasd_info[devindex]->open_count);
+		rc = -EINVAL;
+	}
+	if (!rc) {
+		fill_sizes (devindex);
+		dasd_info[devindex]->flags &= ~DASD_NOT_FORMATTED;
+	} else {
+		dasd_info[devindex]->flags |= DASD_NOT_FORMATTED;
+	}
+	up (&dasd_info[devindex]->sem);
+	return rc;
+}
+
+static inline int
+do_dasd_ioctl (struct inode *inp, unsigned int no, unsigned long data)
+{
+	int rc;
+	int di;
+	dasd_information_t *dev;
+
+	di = DEVICE_NR (inp->i_rdev);
+	if (!dasd_info[di]) {
+		PRINT_WARN ("No device registered as %d\n", inp->i_rdev);
+		return -EINVAL;
+	}
+	if ((_IOC_DIR (no) != _IOC_NONE) && (data == 0)) {
+		PRINT_DEBUG ("empty data ptr");
+		return -EINVAL;
+	}
+	dev = dasd_info[di];
+	if (!dev) {
+		PRINT_WARN ("No device registered as %d\n", inp->i_rdev);
+		return -EINVAL;
+	}
+	PRINT_INFO ("ioctl 0x%08x %s'0x%x'%d(%d) on dev %d/%d (%d) with data %8lx\n", no,
+		    _IOC_DIR (no) == _IOC_NONE ? "0" :
+		    _IOC_DIR (no) == _IOC_READ ? "r" :
+		    _IOC_DIR (no) == _IOC_WRITE ? "w" :
+		    _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? "rw" : "u",
+		    _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no),
+		    MAJOR (inp->i_rdev), MINOR (inp->i_rdev), di, data);
+
+	switch (no) {
+	case BLKGETSIZE:{	/* Return device size */
+			unsigned long blocks;
+			if (inp->i_rdev & 0x01) {
+				blocks = (dev->sizes.blocks - 3) <<
+				    dev->sizes.s2b_shift;
+			} else {
+				blocks = dev->sizes.kbytes << dev->sizes.s2b_shift;
+			}
+			rc = copy_to_user ((long *) data, &blocks, sizeof (long));
+			break;
+		}
+	case BLKFLSBUF:{
+			rc = fsync_dev (inp->i_rdev);
+			break;
+		}
+	case BLKRAGET:{
+			rc = copy_to_user ((long *) data,
+					read_ahead + MAJOR_NR, sizeof (long));
+			break;
+		}
+	case BLKRASET:{
+			rc = copy_from_user (read_ahead + MAJOR_NR,
+					     (long *) data, sizeof (long));
+			break;
+		}
+	case BLKRRPART:{
+			INTERNAL_CHECK ("BLKRPART not implemented%s", "");
+			rc = -EINVAL;
+			break;
+		}
+	case HDIO_GETGEO:{
+			INTERNAL_CHECK ("HDIO_GETGEO not implemented%s", "");
+			rc = -EINVAL;
+			break;
+		}
+		RO_IOCTLS (inp->i_rdev, data);
+
+	case BIODASDRSID:{
+			rc = copy_to_user ((void *) data,
+					   &(dev->info.sid_data),
+					   sizeof (senseid_t));
+			break;
+		}
+	case BIODASDRWTB:{
+			int offset = 0;
+			int xlt;
+			rc = copy_from_user (&xlt, (void *) data,
+					     sizeof (int));
+                        PRINT_INFO("Xlating %d to",xlt);
+			if (rc)
+				break;
+			if (MINOR (inp->i_rdev) & 1)
+				offset = 3;
+			xlt += offset;
+                        printk(" %d \n",xlt);
+			rc = copy_to_user ((void *) data, &xlt,
+					   sizeof (int));
+			break;
+		}
+	case BIODASDFORMAT:{
+			/* fdata == NULL is a valid arg to dasd_format ! */
+			format_data_t *fdata = NULL;
+			if (data) {
+				fdata = kmalloc (sizeof (format_data_t),
+						 GFP_ATOMIC);
+				if (!fdata) {
+					rc = -ENOMEM;
+					break;
+				}
+				rc = copy_from_user (fdata, (void *) data,
+						     sizeof (format_data_t));
+				if (rc)
+					break;
+			}
+			rc = dasd_format (inp->i_rdev, fdata);
+			if (fdata) {
+				kfree (fdata);
+			}
+			break;
+		}
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static void
+dasd_end_request (struct request *req, int uptodate)
+{
+	struct buffer_head *bh;
+	FUNCTION_ENTRY ("dasd_end_request");
+#if DASD_PARANOIA > 2
+	if (!req) {
+		INTERNAL_CHECK ("end_request called with zero arg%s\n", "");
+	}
+#endif				/* DASD_PARANOIA */
+	while ((bh = req->bh) != NULL) {
+		req->bh = bh->b_reqnext;
+		bh->b_reqnext = NULL;
+		bh->b_end_io (bh, uptodate);
+	}
+	if (!end_that_request_first (req, uptodate, DEVICE_NAME)) {
+#ifndef DEVICE_NO_RANDOM
+		add_blkdev_randomness (MAJOR (req->rq_dev));
+#endif
+		DEVICE_OFF (req->rq_dev);
+		end_that_request_last (req);
+	}
+	FUNCTION_EXIT ("dasd_end_request");
+	return;
+}
+
+void
+dasd_wakeup (void)
+{
+	wake_up (&dasd_waitq);
+}
+
+int
+dasd_unregister_dasd (int irq, dasd_type_t dt, dev_info_t * info)
+{
+	int rc = 0;
+	FUNCTION_ENTRY ("dasd_unregister_dasd");
+	INTERNAL_CHECK ("dasd_unregister_dasd not implemented%s\n", "");
+	FUNCTION_EXIT ("dasd_unregister_dasd");
+	return rc;
+}
+
+/* Below you find the functions already cleaned up */
+static dasd_type_t
+check_type (dev_info_t * info)
+{
+	dasd_type_t type = dasd_none;
+
+	FUNCTION_ENTRY ("check_type");
+#ifdef CONFIG_DASD_ECKD
+	if (MATCH (info, == 0x3990, ||1, == 0x3390, ||1) ||
+	    MATCH (info, == 0x3990, ||1, == 0x3380, ||1)) {
+		type = dasd_eckd;
+	} else
+#endif				/* CONFIG_DASD_ECKD */
+	{
+		type = dasd_none;
+	}
+	FUNCTION_EXIT ("check_type");
+	return type;
+}
+
+static int
+dasd_read_characteristics (dasd_information_t * info)
+{
+	int rc;
+	int ct = 0;
+	dev_info_t *di;
+	dasd_type_t dt;
+
+	FUNCTION_ENTRY ("read_characteristics");
+	if (info == NULL) {
+		return -ENODEV;
+	}
+	di = &(info->info);
+	if (di == NULL) {
+		return -ENODEV;
+	}
+	dt = check_type (di);
+	/* Some cross-checks, if the cu supports RDC */
+	if (MATCH (di, == 0x2835, ||1, ||1, ||1) ||
+	    MATCH (di, == 0x3830, ||1, ||1, ||1) ||
+	    MATCH (di, == 0x3830, ||1, ||1, ||1) ||
+	    MATCH (di, == 0x3990, <=0x03, == 0x3380, <=0x0d)) {
+		PRINT_WARN ("Device %d (%x/%x at %x/%x) supports no RDC\n",
+			    info->info.irq,
+			    di->sid_data.dev_type,
+			    di->sid_data.dev_model,
+			    di->sid_data.cu_type,
+			    di->sid_data.cu_model);
+		return -EINVAL;
+	}
+	switch (dt) {
+#ifdef CONFIG_DASD_ECKD
+	case dasd_eckd:
+		ct = 64;
+		break;
+#endif				/*  CONFIG_DASD_ECKD */
+	default:
+		INTERNAL_ERROR ("don't know dasd type %d\n", dt);
+	}
+	rc = read_dev_chars (info->info.irq,
+			     (void *) &(info->rdc_data), ct);
+	if (rc) {
+		PRINT_WARN ("RDC resulted in rc=%d\n", rc);
+	}
+	FUNCTION_EXIT ("read_characteristics");
+	return rc;
+}
+
+/* How many sectors must be in a request to dequeue it ? */
+#define QUEUE_BLOCKS 100
+#define QUEUE_SECTORS (QUEUE_BLOCKS << dasd_info[di]->sizes.s2b_shift)
+
+/* How often to retry an I/O before raising an error */
+#define DASD_MAX_RETRIES 5
+
+static atomic_t bh_scheduled = ATOMIC_INIT (0);
+
+static inline void
+schedule_bh (void (*func) (void))
+{
+	static struct tq_struct dasd_tq =
+	{0,};
+	/* Protect against rescheduling, when already running */
+	if (atomic_compare_and_swap (0, 1, &bh_scheduled))
+		return;
+	dasd_tq.routine = (void *) (void *) func;
+	queue_task (&dasd_tq, &tq_immediate);
+	mark_bh (IMMEDIATE_BH);
+	return;
+}
+
+static inline
+ cqr_t *
+dasd_cqr_from_req (struct request *req)
+{
+	cqr_t *cqr = NULL;
+	int di;
+	dasd_information_t *info;
+
+	if (!req) {
+		PRINT_ERR ("No request passed!");
+		return NULL;
+	}
+	di = DEVICE_NR (req->rq_dev);
+	info = dasd_info[di];
+	if (!info)
+		return NULL;
+	/* if applicable relocate block */
+	if (MINOR (req->rq_dev) & 0x1) {
+		req->sector += info->sizes.first_sector;
+	}
+	/* Now check for consistency */
+	if (!req->nr_sectors) {
+		PRINT_WARN ("req: %p dev: %08x sector: %ld nr_sectors: %ld bh: %p\n",
+		     req, req->rq_dev, req->sector, req->nr_sectors, req->bh);
+		return NULL;
+	}
+	if (((req->sector + req->nr_sectors) >> 1) > info->sizes.kbytes) {
+		printk (KERN_ERR PRINTK_HEADER
+			"Requesting I/O past end of device %d\n",
+			di);
+		return NULL;
+	}
+	cqr = dasd_disciplines[info->type]->get_req_ccw (di, req);
+	if (!cqr) {
+		PRINT_WARN ("empty CQR generated\n");
+	} else {
+		cqr->req = req;
+		cqr->int4cqr = cqr;
+		cqr->devindex = di;
+#ifdef DASD_PROFILE
+		asm volatile ("STCK %0":"=m" (cqr->buildclk));
+#endif				/* DASD_PROFILE */
+		if (atomic_compare_and_swap (CQR_STATUS_EMPTY,
+					     CQR_STATUS_FILLED,
+					     &cqr->status)) {
+			PRINT_WARN ("cqr from req stat changed %d\n",
+				    atomic_read (&cqr->status));
+		}
+	}
+	return cqr;
+}
+
+int
+dasd_start_IO (cqr_t * cqr)
+{
+	int rc = 0;
+	int retries = DASD_SSCH_RETRIES;
+	int di, irq;
+
+	if (!cqr) {
+		PRINT_WARN ("(start_IO) no cqr passed\n");
+		return -EINVAL;
+	}
+	if (cqr->magic != DASD_MAGIC) {
+		PRINT_WARN ("(start_IO) magic number mismatch\n");
+		return -EINVAL;
+	}
+	if (atomic_compare_and_swap (CQR_STATUS_QUEUED,
+				     CQR_STATUS_IN_IO,
+				     &cqr->status)) {
+		PRINT_WARN ("start_IO: status changed %d\n",
+			    atomic_read (&cqr->status));
+		atomic_set (&cqr->status, CQR_STATUS_ERROR);
+		return -EINVAL;
+	}
+        di = cqr->devindex;
+	irq = dasd_info[di]->info.irq;
+	do {
+		asm volatile ("STCK %0":"=m" (cqr->startclk));
+		rc = do_IO (irq, cqr->cpaddr, (long) cqr, 0x00, cqr->options);
+		switch (rc) {
+		case 0:
+			if (!(cqr->options & DOIO_WAIT_FOR_INTERRUPT))
+                        	atomic_set_mask (DASD_CHANQ_BUSY,
+                                	         &dasd_info[di]->queue.flags);
+			break;
+		case -ENODEV:
+			PRINT_WARN ("cqr %p: 0x%04x error, %d retries left\n",
+				    cqr, dasd_info[di]->info.devno, retries);
+			break;
+		case -EIO:
+			PRINT_WARN ("cqr %p: 0x%04x I/O, %d retries left\n",
+				    cqr, dasd_info[di]->info.devno, retries);
+			break;
+		case -EBUSY:	/* set up timer, try later */
+			PRINT_WARN ("cqr %p: 0x%04x busy, %d retries left\n",
+				    cqr, dasd_info[di]->info.devno, retries);
+			break;
+		default:
+			PRINT_WARN ("cqr %p: 0x%04x %d, %d retries left\n",
+				    cqr, rc, dasd_info[di]->info.devno,
+                                    retries);
+			break;
+		}
+	} while (rc && --retries);
+	if (rc) {
+		if (atomic_compare_and_swap (CQR_STATUS_IN_IO,
+					     CQR_STATUS_ERROR,
+					     &cqr->status)) {
+			PRINT_WARN ("start_IO:(done) status changed %d\n",
+				    atomic_read (&cqr->status));
+		        atomic_set (&cqr->status, CQR_STATUS_ERROR);
+		}
+        }
+	return rc;
+}
+
+static inline
+void
+dasd_end_cqr (cqr_t * cqr, int uptodate)
+{
+	struct request *req = cqr->req;
+	asm volatile ("STCK %0":"=m" (cqr->endclk));
+#ifdef DASD_PROFILE
+	dasd_profile_add (cqr);
+#endif				/* DASD_PROFILE */
+	dasd_chanq_deq (&dasd_info[cqr->devindex]->queue, cqr);
+        if (req) {
+                dasd_end_request (req, uptodate);
+        }
+}
+
+void
+dasd_dump_sense (devstat_t * stat)
+{
+	int sl, sct;
+	printk (KERN_INFO PRINTK_HEADER
+		"-------------------I/O Error-----------------------------\n");
+	for (sl = 0; sl < 4; sl++) {
+		printk (KERN_INFO PRINTK_HEADER "Sense:");
+		for (sct = 0; sct < 8; sct++) {
+			printk (" %2d:0x%02X", 8 * sl + sct,
+				stat->ii.sense.data[8 * sl + sct]);
+		}
+		printk ("\n");
+	}
+}
+
+void
+dasd_do_chanq (void)
+{
+	dasd_chanq_t *qp = NULL;
+	cqr_t *cqr;
+        long flags;
+        int irq,di;
+        int tasks;
+	atomic_set (&bh_scheduled, 0);
+	dasd_debug (0x44445f69);	/* DD_i */
+	while ((tasks = atomic_read(&chanq_tasks)) != 0) {
+/* initialization and wraparound */
+		if (qp == NULL) {
+			dasd_debug (0x44445f68);        /* DD_h */
+			qp = cq_head;
+			if (!qp) {
+                          dasd_debug (0x44445f45);        /* DD_E */
+                          dasd_debug (tasks);      
+                          PRINT_ERR("Mismatch of NULL queue pointer and "
+                                    "still %d chanq_tasks to do!!\n"
+                                    "Please send output of /proc/dasd/debug "
+                                    "to Linux390@de.ibm.com\n", tasks);
+                          atomic_set(&chanq_tasks,0);
+                          break;
+			}
+		}
+/* Get the irq number: Ouch, FIXME!!!!! */
+#if 0
+                di =(((unsigned long)qp)-
+                     ((unsigned long)&(dasd_info[0]->queue)))
+                        / sizeof(dasd_information_t);
+                dasd_debug(di);
+                irq = dasd_info[di]->info.irq;
+                dasd_debug(irq);
+#endif
+/* Get first request */
+		cqr = (cqr_t *) (qp->head);
+		dasd_debug ((unsigned long) cqr);	/* cqr */
+/* empty queue -> dequeue and proceed */
+		if (!cqr) {
+			dasd_chanq_t *nqp = qp->next_q;
+			cql_deq (qp);
+			qp = nqp;
+			continue;
+		}
+/* process all requests on that queue */
+		do {
+			cqr_t *next;
+			dasd_debug (0x44445f64);	/* DD_d */
+			dasd_debug ((unsigned long) cqr);	/* cqr */
+			if (cqr->magic != DASD_MAGIC) {
+				dasd_debug (0x44445f65);	/* DD_e */
+				PRINT_WARN ("do_cq:magic mismatch %p\n", cqr);
+                                break;
+			}
+                        irq = dasd_info[cqr->devindex]->info.irq;
+                        s390irq_spin_lock_irqsave (irq, flags);
+			switch (atomic_read (&cqr->status)) {
+			case CQR_STATUS_IN_IO:
+                                dasd_debug (0x44445f48);	/* DD_I */
+                                cqr = NULL;
+                                break;
+			case CQR_STATUS_QUEUED:
+                                dasd_debug (0x44445f53);	/* DD_S */
+                                if (dasd_start_IO (cqr) == 0) {
+                                        atomic_dec (&chanq_tasks);
+                                        cqr = NULL;
+                                }
+                                break;
+			case CQR_STATUS_ERROR:
+                                dasd_debug (0x44445f54);	/* DD_E */
+                                dasd_dump_sense (cqr->dstat);
+                                if (cqr->retries++ < 5) {
+                                        atomic_set (&cqr->status,
+                                                    CQR_STATUS_QUEUED);
+                                        if (dasd_start_IO (cqr) == 0) {
+                                                atomic_dec (&chanq_tasks);
+                                                cqr = NULL;
+                                        }
+                                } else {
+                                        atomic_set (&cqr->status,
+                                                    CQR_STATUS_FAILED);
+                                }
+                                break;
+			case CQR_STATUS_DONE:
+                                next = cqr->next;
+                                dasd_debug (0x44445f44);	/* DD_D */
+                                dasd_end_cqr (cqr, 1);
+                                atomic_dec (&chanq_tasks);
+                                cqr = next;
+                                break;
+			case CQR_STATUS_FAILED:
+                                next = cqr->next;
+                                dasd_debug (0x44445f45);	/* DD_F */
+                                dasd_end_cqr (cqr, 0);
+                                atomic_dec (&chanq_tasks);
+                                cqr = next;
+                                break;
+			default:
+                                PRINT_WARN ("unknown cqrstatus\n");
+                                cqr = NULL;
+			}
+                        s390irq_spin_unlock_irqrestore (irq, flags);
+		} while (cqr);
+		qp = qp->next_q;
+	}
+	spin_lock (&io_request_lock);
+	do_dasd_request ();
+	spin_unlock (&io_request_lock);
+	dasd_debug (0x44445f6f);	/* DD_o */
+}
+
+/* 
+   The request_fn is called from ll_rw_blk for any new request.
+   We use it to feed the chanqs.
+   This implementation assumes we are serialized by the io_request_lock.
+ */
+void
+do_dasd_request (void)
+{
+	struct request *req;
+	struct request *prev;
+	struct request *next;
+	char broken[DASD_MAX_DEVICES] =	{0,};
+	char busy[DASD_MAX_DEVICES] = {0,};
+	int di;
+	cqr_t *cqr;
+	long caller;
+	dasd_chanq_t *q;
+	long flags;
+        int irq;
+        
+	__asm__ ("lr %0,14":"=d" (caller)); 
+	dasd_debug (0x44525f69);	/* DR_i */
+	dasd_debug ((unsigned long) caller);	/* calleraddres */
+	prev = NULL;
+	for (req = CURRENT; req != NULL; req = next) {
+		next = req->next;
+		di = DEVICE_NR (req->rq_dev);
+		dasd_debug ((unsigned long) req);	/* req */
+		dasd_debug (0x44520000 +	/* DR## */
+                            ((((di/16)<9?(di/16)+'0':(di/16)+'a'))<<8) +
+                            (((di%16)<9?(di%16)+'0':(di%16)+'a')));
+                irq = dasd_info[di]->info.irq;
+                s390irq_spin_lock_irqsave (irq, flags);
+                q = &dasd_info[di]->queue;
+                busy[di] = busy[di]||(atomic_read(&q->flags)&DASD_CHANQ_BUSY);
+                if ( !busy[di] ||
+                     ((!broken[di]) && (req->nr_sectors >= QUEUE_SECTORS))) {
+                        if (prev) {
+                                prev->next = next;
+                        } else {
+                                CURRENT = next;
+                        }
+			req->next = NULL;
+			if (req == &blk_dev[MAJOR_NR].plug) {
+				dasd_debug (0x44525f75);	/* DR_u */
+				goto cont;
+			}
+			cqr = dasd_cqr_from_req (req);
+			if (!cqr) {
+				dasd_debug (0x44525f65);	/* DR_e */
+				dasd_end_request (req, 0);
+				goto cont;
+                        }
+                        dasd_debug (0x44525f71);	/* DR_q */
+                        dasd_debug ((unsigned long) cqr);	/* cqr */
+                        dasd_chanq_enq (q, cqr);
+                        if (!(atomic_read (&q->flags) & DASD_CHANQ_ACTIVE)) {
+                                cql_enq_head (q);
+                        }
+                        if (!busy[di]) {
+                                if (dasd_start_IO (cqr) == 0)
+                                        dasd_debug (0x44525f73); /* DR_s */
+                                else {
+                                        atomic_inc (&chanq_tasks);
+					schedule_bh (dasd_do_chanq);
+                                        busy[di] = 1;
+                                }
+                        }
+                } else {
+                        dasd_debug (0x44525f62);	/* DR_b */
+                        broken[di] = 1;
+			prev = req;
+		}
+        cont:
+                s390irq_spin_unlock_irqrestore (irq, flags);
+	}
+	dasd_debug (0x44525f6f);	/* DR_o */
+}
+
+void
+dasd_handler (int irq, void *ds, struct pt_regs *regs)
+{
+	devstat_t *stat = (devstat_t *) ds;
+	int ip;
+	cqr_t *cqr;
+	int done_fast_io = 0;
+
+	dasd_debug (0x44485f69);	/* DH_i */
+	if (!stat)
+		PRINT_ERR ("handler called without devstat");
+	ip = stat->intparm;
+	dasd_debug (ip);	/* intparm */
+	switch (ip) {		/* filter special intparms... */
+	case 0x00000000:	/* no intparm: unsolicited interrupt */
+		dasd_debug (0x44485f30);	/* DH_0 */
+		PRINT_INFO ("Unsolicited interrupt on device %04X\n",
+			    stat->devno);
+		dasd_dump_sense (stat);
+		return;
+	default:
+		if (ip & 0x80000001) {
+			PRINT_INFO ("Spurious interrupt %08x on device %04X\n",
+				    ip, stat->devno);
+			return;
+		}
+		cqr = (cqr_t *) ip;
+		if (cqr->magic != DASD_MAGIC) {
+			dasd_debug (0x44485f65);	/* DH_e */
+			PRINT_WARN ("handler:magic mismatch on %p %08x\n",
+				    cqr, cqr->magic);
+			return;
+		}
+		asm volatile ("STCK %0":"=m" (cqr->stopclk));
+		if (stat->cstat == 0x00 && stat->dstat == 0x0c) {
+			dasd_debug (0x44486f6b);	/* DHok */
+			if (atomic_compare_and_swap (CQR_STATUS_IN_IO,
+						     CQR_STATUS_DONE,
+						     &cqr->status)) {
+				PRINT_WARN ("handler: cqrstat changed%d\n",
+					    atomic_read (&cqr->status));
+			}
+			if (cqr->next) {
+				dasd_debug (0x44485f6e);	/* DH_n */
+				if (dasd_start_IO (cqr->next) == 0)
+					done_fast_io = 1;
+			}
+ 			break;
+		}
+		dasd_debug (0x44482121);	/* DH!! */
+		if (!cqr->dstat)
+			cqr->dstat = kmalloc (sizeof (devstat_t),
+					      GFP_ATOMIC);
+		if (cqr->dstat) {
+			memcpy (cqr->dstat, stat, sizeof (devstat_t));
+			dasd_dump_sense (cqr->dstat);
+		} else {
+			PRINT_ERR ("no memory for dtstat\n");
+		}
+		/* errorprocessing */
+		if (cqr->retries < DASD_MAX_RETRIES) {
+			dasd_debug (0x44485f72);	/* DH_r */
+			atomic_set (&cqr->status, CQR_STATUS_ERROR);
+		} else {
+			dasd_debug (0x44485f6e);	/* DH_f */
+			atomic_set (&cqr->status, CQR_STATUS_FAILED);
+		}
+
+	}
+	if (done_fast_io == 0)
+		atomic_clear_mask (DASD_CHANQ_BUSY,
+				   &dasd_info[cqr->devindex]->
+				   queue.flags);
+        
+	if (cqr->flags & DASD_DO_IO_SLEEP) {
+		dasd_debug (0x44485f77);	/* DH_w */
+		dasd_wakeup ();
+	} else if (! (cqr->options & DOIO_WAIT_FOR_INTERRUPT) ){
+                dasd_debug (0x44485f73);	/* DH_s */
+                atomic_inc (&chanq_tasks);
+                schedule_bh (dasd_do_chanq);
+	} else {
+                dasd_debug (cqr->flags);	/* DH_g */
+                dasd_debug (0x44485f6f);	/* DH_g */
+        }
+}
+
+static int
+register_dasd (int irq, dasd_type_t dt, dev_info_t * info)
+{
+	int rc = 0;
+	int di;
+	static spinlock_t register_lock = SPIN_LOCK_UNLOCKED;
+	spin_lock (&register_lock);
+	FUNCTION_ENTRY ("register_dasd");
+	di = devindex_from_devno (info->devno);
+	if (di < 0) {
+		INTERNAL_CHECK ("Can't get index for devno %d\n", info->devno);
+		return -ENODEV;
+	}
+	if (dasd_info[di]) {	/* devindex is not free */
+		INTERNAL_CHECK ("reusing allocated deviceindex %d\n", di);
+		return -ENODEV;
+	}
+	dasd_info[di] = (dasd_information_t *)
+	    kmalloc (sizeof (dasd_information_t), GFP_ATOMIC);
+	if (dasd_info[di] == NULL) {
+		PRINT_WARN ("No memory for dasd_info_t on irq %d\n", irq);
+		return -ENOMEM;
+	}
+	memset (dasd_info[di], 0, sizeof (dasd_information_t));
+	memcpy (&(dasd_info[di]->info), info, sizeof (dev_info_t));
+	spin_lock_init (&dasd_info[di]->queue.f_lock);
+	spin_lock_init (&dasd_info[di]->queue.q_lock);
+	atomic_set (&dasd_info[di]->queue.flags, 0);
+	dasd_info[di]->type = dt;
+	dasd_info[di]->irq = irq;
+	dasd_info[di]->sem = MUTEX;
+	rc = dasd_read_characteristics (dasd_info[di]);
+	if (rc) {
+		PRINT_WARN ("RDC returned error %d\n", rc);
+		rc = -ENODEV;
+		goto unalloc;
+	}
+#if DASD_PARANOIA > 1
+	if (dasd_disciplines[dt]->ck_characteristics)
+#endif				/* DASD_PARANOIA */
+		rc = dasd_disciplines[dt]->
+		    ck_characteristics (dasd_info[di]->rdc_data);
+
+	if (rc) {
+		INTERNAL_CHECK ("Discipline returned non-zero when"
+				"checking device characteristics%s\n", "");
+		rc = -ENODEV;
+		goto unalloc;
+	}
+	rc = request_irq (irq, dasd_handler, 0, "dasd",
+			  &(dasd_info[di]->dev_status));
+	if (rc) {
+#if DASD_PARANOIA > 0
+		printk (KERN_WARNING PRINTK_HEADER
+			"Cannot register irq %d, rc=%d\n",
+			irq, rc);
+#endif				/* DASD_DEBUG */
+		rc = -ENODEV;
+		goto unalloc;
+	}
+#if DASD_PARANOIA > 1
+	if (!dasd_disciplines[dt]->fill_sizes) {
+		INTERNAL_CHECK ("No fill_sizes for dt=%d\n", dt);
+		goto unregister;
+	}
+#endif				/* DASD_PARANOIA */
+	fill_sizes (di);
+	goto exit;
+
+      unregister:
+	free_irq (irq, &(dasd_info[di]->dev_status));
+      unalloc:
+	kfree (dasd_info[di]);
+      exit:
+	spin_unlock (&register_lock);
+	FUNCTION_EXIT ("register_dasd");
+	return rc;
+}
+
+static int
+probe_for_dasd (int irq)
+{
+	int rc;
+	dev_info_t info;
+	dasd_type_t dt;
+
+	FUNCTION_ENTRY ("probe_for_dasd");
+
+	rc = get_dev_info_by_irq (irq, &info);
+	if (rc == -ENODEV) {	/* end of device list */
+		return rc;
+	}
+#if DASD_PARANOIA > 2
+	if (rc) {
+		INTERNAL_CHECK ("unknown rc %d of get_dev_info", rc);
+		return rc;
+	}
+#endif				/* DASD_PARANOIA */
+	if ((info.status & DEVSTAT_NOT_OPER)) {
+		return -ENODEV;
+	}
+	dt = check_type (&info);
+	switch (dt) {
+#ifdef CONFIG_DASD_ECKD
+	case dasd_eckd:
+#endif				/* CONFIG_DASD_ECKD */
+		FUNCTION_CONTROL ("Probing devno %d...\n", info.devno);
+		if (!dasd_is_accessible (info.devno)) {
+			FUNCTION_CONTROL ("out of range...skip%s\n", "");
+			return -ENODEV;
+		}
+		if (dasd_disciplines[dt]->ck_devinfo) {
+			rc = dasd_disciplines[dt]->ck_devinfo (&info);
+		}
+#if DASD_PARANOIA > 1
+		else {
+			INTERNAL_ERROR ("no ck_devinfo function%s\n", "");
+			return -ENODEV;
+		}
+#endif				/* DASD_PARANOIA */
+		if (rc == -ENODEV) {
+			return rc;
+		}
+#if DASD_PARANOIA > 2
+		if (rc) {
+			INTERNAL_CHECK ("unknown error rc=%d\n", rc);
+			return -ENODEV;
+		}
+#endif				/* DASD_PARANOIA */
+		rc = register_dasd (irq, dt, &info);
+		if (rc) {
+			PRINT_INFO ("devno %x not enabled as minor %d  due to errors\n",
+				    info.devno,
+				    devindex_from_devno (info.devno) <<
+				    PARTN_BITS);
+		} else {
+			PRINT_INFO ("devno %x added as minor %d (%s)\n",
+				    info.devno,
+			       devindex_from_devno (info.devno) << PARTN_BITS,
+				    dasd_name[dt]);
+		}
+	case dasd_none:
+		break;
+	default:
+		PRINT_DEBUG ("unknown device type\n");
+		break;
+	}
+	FUNCTION_EXIT ("probe_for_dasd");
+	return rc;
+}
+
+static int
+register_major (int major)
+{
+	int rc = 0;
+
+	FUNCTION_ENTRY ("register_major");
+	rc = register_blkdev (major, DASD_NAME, &dasd_file_operations);
+#if DASD_PARANOIA > 1
+	if (rc) {
+		PRINT_WARN ("registering major -> rc=%d aborting... \n", rc);
+		return rc;
+	}
+#endif				/* DASD_PARANOIA */
+	blk_dev[major].request_fn = do_dasd_request;
+	FUNCTION_CONTROL ("successfully registered major: %d\n", major);
+	FUNCTION_EXIT ("register_major");
+	return rc;
+}
+
+/* 
+   Below you find functions which are called from outside. Some of them may be
+   static, because they are called by their function pointers only. Thus static
+   modifier is to make sure, that they are only called via the kernel's methods
+ */
+
+static ssize_t
+dasd_read (struct file *filp, char *b, size_t s, loff_t * o)
+{
+	ssize_t rc;
+	FUNCTION_ENTRY ("dasd_read");
+	rc = block_read (filp, b, s, o);
+	FUNCTION_EXIT ("dasd_read");
+	return rc;
+}
+static ssize_t
+dasd_write (struct file *filp, const char *b, size_t s, loff_t * o)
+{
+	ssize_t rc;
+	FUNCTION_ENTRY ("dasd_write");
+	rc = block_write (filp, b, s, o);
+	FUNCTION_EXIT ("dasd_write");
+	return rc;
+}
+static int
+dasd_ioctl (struct inode *inp, struct file *filp,
+	    unsigned int no, unsigned long data)
+{
+	int rc = 0;
+	FUNCTION_ENTRY ("dasd_ioctl");
+	if ((!inp) || !(inp->i_rdev)) {
+		return -EINVAL;
+	}
+	rc = do_dasd_ioctl (inp, no, data);
+	FUNCTION_EXIT ("dasd_ioctl");
+	return rc;
+}
+
+static int
+dasd_open (struct inode *inp, struct file *filp)
+{
+	int rc = 0;
+	dasd_information_t *dev;
+	FUNCTION_ENTRY ("dasd_open");
+	if ((!inp) || !(inp->i_rdev)) {
+		return -EINVAL;
+	}
+	dev = dasd_info[DEVICE_NR (inp->i_rdev)];
+	if (!dev) {
+		PRINT_DEBUG ("No device registered as %d (%d)\n",
+			    inp->i_rdev, DEVICE_NR (inp->i_rdev));
+		return -EINVAL;
+	}
+	down (&dev->sem);
+	up (&dev->sem);
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif				/* MODULE */
+#if DASD_PARANOIA > 2
+	if (dev->open_count < 0) {
+		INTERNAL_ERROR ("open count cannot be less than 0: %d",
+				dev->open_count);
+		return -EINVAL;
+	}
+#endif				/* DASD_PARANOIA */
+	dev->open_count++;
+	FUNCTION_EXIT ("dasd_open");
+	return rc;
+}
+
+static int
+dasd_fsync (struct file *filp, struct dentry *d)
+{
+	int rc = 0;
+	FUNCTION_ENTRY ("dasd_fsync");
+	if (!filp) {
+		return -EINVAL;
+	}
+	rc = block_fsync (filp, d);
+	FUNCTION_EXIT ("dasd_fsync");
+	return rc;
+}
+
+static int
+dasd_release (struct inode *inp, struct file *filp)
+{
+	int rc = 0;
+	dasd_information_t *dev;
+	FUNCTION_ENTRY ("dasd_release");
+	if ((!inp) || !(inp->i_rdev)) {
+		return -EINVAL;
+	}
+	dev = dasd_info[DEVICE_NR (inp->i_rdev)];
+	if (!dev) {
+		PRINT_WARN ("No device registered as %d\n", inp->i_rdev);
+		return -EINVAL;
+	}
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif				/* MODULE */
+#if DASD_PARANOIA > 2
+	if (!dev->open_count) {
+		PRINT_WARN ("device %d has not been opened before:\n",
+			    inp->i_rdev);
+	}
+#endif				/* DASD_PARANOIA */
+	dev->open_count--;
+#if DASD_PARANOIA > 2
+	if (dev->open_count < 0) {
+		INTERNAL_ERROR ("open count cannot be less than 0: %d",
+				dev->open_count);
+		return -EINVAL;
+	}
+#endif				/* DASD_PARANOIA */
+	FUNCTION_EXIT ("dasd_release");
+	return rc;
+}
+
+static struct
+file_operations dasd_file_operations =
+{
+	NULL,			/* loff_t(*llseek)(struct file *,loff_t,int); */
+	dasd_read,
+	dasd_write,
+	NULL,			/* int(*readdir)(struct file *,void *,filldir_t); */
+	NULL,			/* u int(*poll)(struct file *,struct poll_table_struct *); */
+	dasd_ioctl,
+	NULL,			/* int (*mmap) (struct file *, struct vm_area_struct *); */
+	dasd_open,
+	NULL,			/* int (*flush) (struct file *) */
+	dasd_release,
+	dasd_fsync,
+	NULL,			/* int (*fasync) (int, struct file *, int);
+				   int (*check_media_change) (kdev_t dev);
+				   int (*revalidate) (kdev_t dev);
+				   int (*lock) (struct file *, int, struct file_lock *); */
+};
+
+int
+dasd_init (void)
+{
+	int rc = 0;
+	int i;
+
+	FUNCTION_ENTRY ("dasd_init");
+	PRINT_INFO ("initializing...\n");
+	atomic_set (&chanq_tasks, 0);
+	atomic_set (&bh_scheduled, 0);
+	spin_lock_init (&dasd_lock);
+	/* First register to the major number */
+	rc = register_major (MAJOR_NR);
+#if DASD_PARANOIA > 1
+	if (rc) {
+		PRINT_WARN ("registering major_nr returned rc=%d\n", rc);
+		return rc;
+	}
+#endif	/* DASD_PARANOIA */ 
+        read_ahead[MAJOR_NR] = 8;
+        blk_size[MAJOR_NR] = dasd_blks;
+	hardsect_size[MAJOR_NR] = dasd_secsize;
+	blksize_size[MAJOR_NR] = dasd_blksize;
+	max_sectors[MAJOR_NR] = dasd_maxsecs;
+#ifdef CONFIG_PROC_FS
+	dasd_proc_init ();
+#endif				/* CONFIG_PROC_FS */
+	/* Now scan the device list for DASDs */
+	FUNCTION_CONTROL ("entering detection loop%s\n", "");
+	for (i = 0; i < NR_IRQS; i++) {
+		int irc;	/* Internal return code */
+		LOOP_CONTROL ("Probing irq %d...\n", i);
+		irc = probe_for_dasd (i);
+		switch (irc) {
+		case 0:
+			LOOP_CONTROL ("Added DASD%s\n", "");
+			break;
+		case -ENODEV:
+			LOOP_CONTROL ("No DASD%s\n", "");
+			break;
+		case -EMEDIUMTYPE:
+			PRINT_WARN ("DASD not formatted%s\n", "");
+			break;
+		default:
+			INTERNAL_CHECK ("probe_for_dasd: unknown rc=%d", irc);
+			break;
+		}
+	}
+	FUNCTION_CONTROL ("detection loop completed%s\n", "");
+/* Finally do the genhd stuff */
+#if 0				/* 2 b done */
+	dd_gendisk.next = gendisk_head;
+	gendisk_head = &dd_gendisk;
+	for (i = 0; i < DASD_MAXDEVICES; i++) {
+		LOOP_CONTROL ("Setting partitions of DASD %d\n", i);
+		resetup_one_dev (&dd_gendisk, i);
+	}
+#endif				/* 0 */
+	FUNCTION_EXIT ("dasd_init");
+	return rc;
+}
+
+#ifdef MODULE
+int
+init_module (void)
+{
+	int rc = 0;
+
+	FUNCTION_ENTRY ("init_module");
+	PRINT_INFO ("trying to load module\n");
+	rc = dasd_init ();
+	if (rc == 0) {
+		PRINT_INFO ("module loaded successfully\n");
+	} else {
+		PRINT_WARN ("warning: Module load returned rc=%d\n", rc);
+	}
+	FUNCTION_EXIT ("init_module");
+	return rc;
+}
+
+void
+cleanup_module (void)
+{
+	int rc = 0;
+
+	FUNCTION_ENTRY ("cleanup_module");
+	PRINT_INFO ("trying to unload module \n");
+
+	/* FIXME: replace by proper unload functionality */
+	INTERNAL_ERROR ("Modules not yet implemented %s", "");
+
+	if (rc == 0) {
+		PRINT_INFO ("module unloaded successfully\n");
+	} else {
+		PRINT_WARN ("module unloaded with errors\n");
+	}
+	FUNCTION_EXIT ("cleanup_module");
+}
+#endif				/* MODULE */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/block/dasd.h linux.14p16/drivers/s390/block/dasd.h
--- linux.vanilla/drivers/s390/block/dasd.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/block/dasd.h	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,226 @@
+
+#ifndef DASD_H
+#define DASD_H
+
+/* First of all the external stuff */
+#include <linux/ioctl.h>
+#include <linux/major.h>
+
+#define IOCTL_LETTER 'D'
+#define BIODASDFORMAT  _IO(IOCTL_LETTER,0) /* Format the volume or an extent */
+#define BIODASDDISABLE _IO(IOCTL_LETTER,1) /* Disable the volume (for Linux) */
+#define BIODASDENABLE  _IO(IOCTL_LETTER,2) /* Enable the volume (for Linux) */
+/* Stuff for reading and writing the Label-Area to/from user space */
+#define BIODASDGTVLBL  _IOR(IOCTL_LETTER,3,dasd_volume_label_t)
+#define BIODASDSTVLBL  _IOW(IOCTL_LETTER,4,dasd_volume_label_t)
+#define BIODASDRWTB    _IOWR(IOCTL_LETTER,5,int)
+#define BIODASDRSID    _IOR(IOCTL_LETTER,6,senseid_t)
+
+typedef
+union {
+	char bytes[512];
+	struct {
+		/* 80 Bytes of Label data */
+		char identifier[4];	/* e.g. "LNX1", "VOL1" or "CMS1" */
+		char label[6];	/* Given by user */
+		char security;
+		char vtoc[5];	/* Null in "LNX1"-labelled partitions */
+		char reserved0[5];
+		long ci_size;
+		long blk_per_ci;
+		long lab_per_ci;
+		char reserved1[4];
+		char owner[0xe];
+		char no_part;
+		char reserved2[0x1c];
+		/* 16 Byte of some information on the dasd */
+		short blocksize;
+		char nopart;
+		char unused;
+		long unused2[3];
+		/* 7*10 = 70 Bytes of partition data */
+		struct {
+			char type;
+			long start;
+			long size;
+			char unused;
+		} part[7];
+	} __attribute__ ((packed)) label;
+} dasd_volume_label_t;
+
+typedef union {
+	struct {
+		unsigned long no;
+		unsigned int ct;
+	} __attribute__ ((packed)) input;
+	struct {
+		unsigned long noct;
+	} __attribute__ ((packed)) output;
+} __attribute__ ((packed)) dasd_xlate_t;
+
+void dasd_setup (char *, int *);
+int dasd_init (void);
+#ifdef MODULE
+int init_module (void);
+void cleanup_module (void);
+#endif				/* MODULE */
+
+/* Definitions for blk.h */
+/* #define DASD_MAGIC 0x44415344  is ascii-"DASD" */
+/* #define dasd_MAGIC 0x64617364;  is ascii-"DASD" */
+#define DASD_MAGIC 0xC4C1E2C4 /* is ebcdic-"DASD" */
+#define dasd_MAGIC 0x8481A284 /* is ebcdic-"DASD" */
+#define DASD_NAME "dasd"
+#define DASD_PARTN_BITS 2
+#define DASD_MAX_DEVICES (256>>DASD_PARTN_BITS)
+
+#define MAJOR_NR DASD_MAJOR
+#define PARTN_BITS DASD_PARTN_BITS
+
+#ifdef __KERNEL__
+/* Now lets turn to the internal sbtuff */
+
+/*
+   define the debug levels:
+   - 0 No debugging output to console or syslog
+   - 1 Log internal errors to syslog, ignore check conditions 
+   - 2 Log internal errors and check conditions to syslog
+   - 3 Log internal errors to console, log check conditions to syslog
+   - 4 Log internal errors and check conditions to console
+   - 5 panic on internal errors, log check conditions to console
+   - 6 panic on both, internal errors and check conditions
+ */
+#define DASD_DEBUG 4
+
+#define DASD_PROFILE
+/*
+   define the level of paranoia
+   - 0 quite sure, that things are going right
+   - 1 sanity checking, only to avoid panics
+   - 2 normal sanity checking
+   - 3 extensive sanity checks
+   - 4 exhaustive debug messages
+ */
+#define DASD_PARANOIA 2
+
+/*
+   define the depth of flow control, which is logged as a check condition
+   - 0 No flow control messages
+   - 1 Entry of functions logged like check condition
+   - 2 Entry and exit of functions logged like check conditions
+   - 3 Internal structure broken down
+   - 4 unrolling of loops,...
+ */
+#define DASD_FLOW_CONTROL 0
+
+#if DASD_DEBUG > 0
+#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#define PRINT_INFO(x...) printk ( KERN_INFO PRINTK_HEADER x )
+#define PRINT_WARN(x...) printk ( KERN_WARNING PRINTK_HEADER x )
+#define PRINT_ERR(x...) printk ( KERN_ERR PRINTK_HEADER x )
+#define PRINT_FATAL(x...) panic ( PRINTK_HEADER x )
+#else
+#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#define PRINT_INFO(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#define PRINT_WARN(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#define PRINT_ERR(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#define PRINT_FATAL(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#endif				/* DASD_DEBUG */
+
+#define INTERNAL_ERRMSG(x,y...) \
+"Internal error: in file " __FILE__ " line: %d: " x, __LINE__, y
+#define INTERNAL_CHKMSG(x,y...) \
+"Inconsistency: in file " __FILE__ " line: %d: " x, __LINE__, y
+#define INTERNAL_FLWMSG(x,y...) \
+"Flow control: file " __FILE__ " line: %d: " x, __LINE__, y
+
+#if DASD_DEBUG > 4
+#define INTERNAL_ERROR(x...) PRINT_FATAL ( INTERNAL_ERRMSG ( x ) )
+#elif DASD_DEBUG > 2
+#define INTERNAL_ERROR(x...) PRINT_ERR ( INTERNAL_ERRMSG ( x ) )
+#elif DASD_DEBUG > 0
+#define INTERNAL_ERROR(x...) PRINT_WARN ( INTERNAL_ERRMSG ( x ) )
+#else
+#define INTERNAL_ERROR(x...)
+#endif				/* DASD_DEBUG */
+
+#if DASD_DEBUG > 5
+#define INTERNAL_CHECK(x...) PRINT_FATAL ( INTERNAL_CHKMSG ( x ) )
+#elif DASD_DEBUG > 3
+#define INTERNAL_CHECK(x...) PRINT_ERR ( INTERNAL_CHKMSG ( x ) )
+#elif DASD_DEBUG > 1
+#define INTERNAL_CHECK(x...) PRINT_WARN ( INTERNAL_CHKMSG ( x ) )
+#else
+#define INTERNAL_CHECK(x...)
+#endif				/* DASD_DEBUG */
+
+#if DASD_DEBUG > 3
+#define INTERNAL_FLOW(x...) PRINT_ERR ( INTERNAL_FLWMSG ( x ) )
+#elif DASD_DEBUG > 2
+#define INTERNAL_FLOW(x...) PRINT_WARN ( INTERNAL_FLWMSG ( x ) )
+#else
+#define INTERNAL_FLOW(x...)
+#endif				/* DASD_DEBUG */
+
+#if DASD_FLOW_CONTROL > 0
+#define FUNCTION_ENTRY(x) INTERNAL_FLOW( x "entered %s\n","" );
+#else
+#define FUNCTION_ENTRY(x)
+#endif				/* DASD_FLOW_CONTROL */
+
+#if DASD_FLOW_CONTROL > 1
+#define FUNCTION_EXIT(x) INTERNAL_FLOW( x "exited %s\n","" );
+#else
+#define FUNCTION_EXIT(x)
+#endif				/* DASD_FLOW_CONTROL */
+
+#if DASD_FLOW_CONTROL > 2
+#define FUNCTION_CONTROL(x...) INTERNAL_FLOW( x );
+#else
+#define FUNCTION_CONTROL(x...)
+#endif				/* DASD_FLOW_CONTROL */
+
+#if DASD_FLOW_CONTROL > 3
+#define LOOP_CONTROL(x...) INTERNAL_FLOW( x );
+#else
+#define LOOP_CONTROL(x...)
+#endif				/* DASD_FLOW_CONTROL */
+
+#define DASD_DO_IO_SLEEP 0x01
+#define DASD_DO_IO_NOLOCK 0x02
+#define DASD_DO_IO_NODEC 0x04
+
+#define DASD_NOT_FORMATTED 0x01
+
+extern struct wait_queue *dasd_waitq;
+
+#undef DEBUG_DASD_MALLOC
+#ifdef DEBUG_DASD_MALLOC
+void *b;
+#define kmalloc(x...) (PRINT_INFO(" kmalloc %p\n",b=kmalloc(x)),b)
+#define kfree(x) PRINT_INFO(" kfree %p\n",x);kfree(x)
+#define get_free_page(x...) (PRINT_INFO(" gfp %p\n",b=get_free_page(x)),b)
+#define __get_free_pages(x...) (PRINT_INFO(" gfps %p\n",b=__get_free_pages(x)),b)
+#endif				/* DEBUG_DASD_MALLOC */
+
+#endif				/* __KERNEL__ */
+#endif				/* DASD_H */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/block/dasd_ccwstuff.c linux.14p16/drivers/s390/block/dasd_ccwstuff.c
--- linux.vanilla/drivers/s390/block/dasd_ccwstuff.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/block/dasd_ccwstuff.c	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,424 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_ccwstuff.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <asm/spinlock.h>
+#include <asm/atomic.h>
+
+#include "dasd.h"
+#include "dasd_types.h"
+
+#define PRINTK_HEADER "dasd_ccw:"
+#define MAX_CP_POWER 9		/* Maximum allowed index */
+#define CP_PER_PAGE_POWER 9	/* Maximum index, fitting on page */
+
+#define get_free_pages __get_free_pages
+
+/* Stuff for the handling task_list */
+dasd_chanq_t *cq_head = NULL;	/* head of task_list */
+atomic_t chanq_tasks;
+
+/* Array of freelists for the channel programs' -space */
+static ccw1_t *ccwarea[CP_PER_PAGE_POWER + 1] =
+{NULL,};
+
+/* array of pages retrieved for internal use */
+#define MAX_DASD_PAGES 64
+static int dasd_page_count = 0;
+static long dasd_page[MAX_DASD_PAGES];
+
+#ifdef __SMP__
+static spinlock_t ccw_lock=SPIN_LOCK_UNLOCKED;	/* spinlock for ccwareas */
+static spinlock_t cq_lock=SPIN_LOCK_UNLOCKED;	/* spinlock for cq_head */
+#endif				/* __SMP__ */
+
+void
+ccwarea_enq (int index, ccw1_t * area)
+{
+	FUNCTION_ENTRY ("ccwarea_enq");
+#if DASD_PARANOIA > 2
+	if (!area) {
+		INTERNAL_CHECK ("zero area %s\n", "");
+	}
+	if (index > CP_PER_PAGE_POWER) {
+		INTERNAL_CHECK ("index too large %d\n", index);
+	}
+#endif
+	*(ccw1_t **) area = ccwarea[index];
+	ccwarea[index] = area;
+	FUNCTION_EXIT ("ccwarea_enq");
+	return;
+}
+
+ccw1_t *
+ccwarea_deq (int index)
+{
+	ccw1_t *cp;
+	FUNCTION_ENTRY ("ccwarea_deq");
+#if DASD_PARANOIA > 2
+	if (index > CP_PER_PAGE_POWER) {
+		INTERNAL_CHECK ("index too large %d\n", index);
+	}
+#endif
+	cp = ccwarea[index];
+	ccwarea[index] = *(ccw1_t **) ccwarea[index];
+#if DASD_PARANOIA > 2
+	if (!cp) {
+		INTERNAL_CHECK ("returning NULL %s\n", "");
+	}
+#endif
+	FUNCTION_EXIT ("ccwarea_deq");
+	return cp;
+}
+
+ccw1_t *
+request_cpa (int index)
+{
+	ccw1_t *freeblk;
+	FUNCTION_ENTRY ("request_cpa");
+	if (index > MAX_CP_POWER) {
+		INTERNAL_ERROR ("index too large %d\n", index);
+		freeblk = NULL;
+		goto exit;
+	}
+	if (index > CP_PER_PAGE_POWER) {
+		int pc = 1 << (index - CP_PER_PAGE_POWER);
+		do {
+			freeblk = (ccw1_t *) get_free_pages (GFP_ATOMIC, index - CP_PER_PAGE_POWER);
+			if (dasd_page_count + pc >= MAX_DASD_PAGES) {
+				PRINT_WARN ("Requesting too many pages...");
+			} else {
+				int i;
+				for (i = 0; i < pc; i++)
+					dasd_page[dasd_page_count++] =
+						(long) freeblk + i * PAGE_SIZE;
+			}
+			FUNCTION_CONTROL ("requesting index %d", index);
+			if ( ! freeblk ) {
+				panic ("No memory received\n");
+			}
+		} while (!freeblk);
+		memset(freeblk,0,PAGE_SIZE<<(index-CP_PER_PAGE_POWER));
+		goto exit;
+	}
+	while (ccwarea[index] == NULL) {
+		ccw1_t *blk;
+		if (index == CP_PER_PAGE_POWER) {
+			do {
+				blk = (ccw1_t *) get_free_page (GFP_ATOMIC);
+				if (dasd_page_count + 1 >= MAX_DASD_PAGES) {
+					PRINT_WARN ("Requesting too many pages...");
+				} else {
+					dasd_page[dasd_page_count++] =
+						(long) blk;
+				}
+				if (blk == NULL) {
+					PRINT_WARN ("Can't allocate page!\n");
+				}
+			} while ( ! blk );
+			memset(blk,0,PAGE_SIZE);
+			ccwarea_enq (CP_PER_PAGE_POWER, blk);
+			continue;
+		}
+		blk = request_cpa (index + 1);
+#if DASD_PARANOIA > 1
+		if (!blk) {
+			PRINT_WARN ("retrieved NULL");
+		}
+#endif				/* DASD_PARANOIA */
+		ccwarea_enq (index, blk);
+		ccwarea_enq (index, blk + (1 << index));
+	}
+#if DASD_PARANOIA > 2
+	if (!ccwarea[index]) {
+		INTERNAL_ERROR ("ccwarea is NULL\n%s", "");
+	}
+#endif				/* DASD_PARANOIA */
+
+	freeblk = ccwarea_deq (index);
+#if DASD_PARANOIA > 1
+	if (!freeblk) {
+		INTERNAL_ERROR ("freeblk is NULL\n%s", "");
+	}
+#endif				/* DASD_PARANOIA */
+      exit:
+	FUNCTION_EXIT ("request_cpa");
+	return freeblk;
+}
+
+ccw1_t *
+request_cp (int size)
+{
+	ccw1_t *freeblk;
+	int index;
+	int blksize;
+	/* Determine the index of ccwarea to look at */
+	for (index = 0, blksize = 1;
+	     size > blksize;
+	     index++, blksize = blksize << 1) {
+	}
+	if (index > MAX_CP_POWER) {
+		INTERNAL_ERROR ("index too large %d\n", index);
+	}
+	spin_lock (&ccw_lock);
+	freeblk = request_cpa (index);
+	spin_unlock (&ccw_lock);
+	if (freeblk == NULL) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"No way to deliver free ccw space\n");
+	}
+	return freeblk;
+}
+
+void
+release_cp (int size, ccw1_t * area)
+{
+	int index;
+	int blksize;
+	/* Determine the index of ccwarea to look at */
+	for (index = 0, blksize = 1;
+	     size > blksize;
+	     index++, blksize = blksize << 1) {
+	}
+	if (index > MAX_CP_POWER) {
+		INTERNAL_ERROR ("index too large %d\n", index);
+	} else if (index > CP_PER_PAGE_POWER) {
+		free_pages ((unsigned long) area,
+			    index - CP_PER_PAGE_POWER);
+		INTERNAL_CHECK ("large index used: %d\n", index);
+	} else {
+		spin_lock (&ccw_lock);
+		ccwarea_enq (index, area);
+		spin_unlock (&ccw_lock);
+	}
+	return;
+}
+
+/* ---------------------------------------------------------- */
+
+static cqr_t *cqrp = NULL;
+#ifdef __SMP__
+static spinlock_t cqr_lock=SPIN_LOCK_UNLOCKED;
+#endif				/* __SMP__ */
+
+void
+cqf_enq (cqr_t * cqf)
+{
+	*(cqr_t **) cqf = cqrp;
+	cqrp = cqf;
+}
+
+cqr_t *
+cqf_deq (void)
+{
+	cqr_t *cqr = cqrp;
+	cqrp = *(cqr_t **) cqrp;
+	return cqr;
+}
+
+cqr_t *
+request_cq (void)
+{
+	cqr_t *cqr = NULL;
+	int i;
+	cqr_t *area;
+
+	spin_lock (&cqr_lock);
+	while (cqrp == NULL) {
+		do {
+			area = (cqr_t *) get_free_page (GFP_ATOMIC);
+			if (area == NULL) {
+				printk (KERN_WARNING PRINTK_HEADER
+					"No memory for chanq area\n");
+			}
+		} while ( ! area );
+		memset(area,0,PAGE_SIZE);
+		if (dasd_page_count + 1 >= MAX_DASD_PAGES) {
+			PRINT_WARN ("Requesting too many pages...");
+		} else {
+			dasd_page[dasd_page_count++] =
+				(long) area;
+		}
+		for (i = 0; i < 4096 / sizeof (cqr_t); i++) {
+				cqf_enq (area + i);
+		}
+	}
+	cqr = cqf_deq ();
+	spin_unlock (&cqr_lock);
+	return cqr;
+}
+
+void
+release_cq (cqr_t * cqr)
+{
+	spin_lock (&cqr_lock);
+	cqf_enq (cqr);
+	spin_unlock (&cqr_lock);
+	return;
+}
+
+/* ----------------------------------------------------------- */
+cqr_t *
+request_cqr (int cpsize, int datasize)
+{
+	cqr_t *cqr = NULL;
+	cqr = request_cq ();
+	if (cqr == NULL) {
+		printk (KERN_WARNING PRINTK_HEADER __FILE__
+			"No memory for chanq request\n");
+		goto exit;
+	}
+	memset (cqr, 0, sizeof (cqr_t));
+	cqr -> magic = DASD_MAGIC;
+	if (cpsize) {
+		cqr->cpaddr = request_cp (cpsize);
+		if (cqr->cpaddr == NULL) {
+			printk (KERN_WARNING PRINTK_HEADER __FILE__
+				"No memory for channel program\n");
+			goto nocp;
+		}
+		cqr->cplength = cpsize;
+	}
+	if (datasize) {
+		do {
+			cqr->data = (char *) kmalloc (datasize, GFP_ATOMIC);
+			if (cqr->data == NULL) {
+				printk (KERN_WARNING PRINTK_HEADER __FILE__
+					"No memory for cqr data area\n");
+			}
+		} while (!cqr->data);
+		memset (cqr->data,0,datasize);
+	}
+	goto exit;
+ nodata:
+	release_cp (cqr->cplength, cqr->cpaddr);
+      nocp:
+	release_cq (cqr);
+	cqr = NULL;
+      exit:
+	return cqr;
+}
+
+int
+release_cqr (cqr_t * cqr)
+{
+	int rc = 0;
+	if (cqr == NULL) {
+		rc = -ENOENT;
+		return rc;
+	}
+	if (cqr->data) {
+		kfree (cqr->data);
+	}
+	if (cqr->dstat) {
+		kfree (cqr->dstat);
+	}
+	if (cqr->cpaddr) {
+		release_cp (cqr->cplength, cqr->cpaddr);
+	}
+	cqr -> magic = dasd_MAGIC;
+	release_cq (cqr);
+	return rc;
+}
+
+/* -------------------------------------------------------------- */
+void
+dasd_chanq_enq (dasd_chanq_t * q, cqr_t * cqr)
+{
+	if (q->head != NULL) {
+		q->tail->next = cqr;
+	} else
+		q->head = cqr;
+	cqr->next = NULL;
+	q->tail = cqr;
+	if (atomic_compare_and_swap(CQR_STATUS_FILLED,
+				    CQR_STATUS_QUEUED,
+				    &cqr->status)) {
+		PRINT_WARN ("q_cqr: %p status changed %d\n", 
+			    cqr,atomic_read(&cqr->status));
+		atomic_set(&cqr->status,CQR_STATUS_QUEUED);
+	}
+}
+
+int
+dasd_chanq_deq (dasd_chanq_t * q, cqr_t * cqr)
+{
+	cqr_t *prev;
+
+	if (cqr == NULL)
+		return -ENOENT;
+	if (cqr == (cqr_t *) q->head) {
+		q->head = cqr->next;
+		if (q->head == NULL)
+			q->tail = NULL;
+	} else {
+		prev = (cqr_t *) q->head; 
+		while (prev && prev->next != cqr)
+			prev = prev->next;
+		if (prev == NULL)
+			return -ENOENT;
+		prev->next = cqr->next;
+		if (prev->next == NULL)
+			q->tail = prev;
+	}
+	cqr->next = NULL;
+	return release_cqr(cqr);
+}
+
+/* -------------------------------------------------------------------------- */
+void
+cql_enq_head (dasd_chanq_t * q)
+{
+	if (q == NULL) {
+		INTERNAL_ERROR ("NULL queue passed%s\n", "");
+		return;
+	}
+	if (atomic_read(&q->flags) & DASD_CHANQ_ACTIVE) {
+		PRINT_WARN("Queue already active");
+		return;
+	}
+	spin_lock(&cq_lock);
+	atomic_set_mask(DASD_CHANQ_ACTIVE,&q->flags);
+	q->next_q = cq_head;
+	cq_head = q;
+	spin_unlock(&cq_lock);
+}
+
+void
+cql_deq (dasd_chanq_t * q)
+{
+	dasd_chanq_t *c;
+
+        if (cq_head == NULL) {
+                INTERNAL_ERROR ("Channel queue is empty%s\n", "");
+		return;
+	}
+	if (q == NULL) {
+		INTERNAL_ERROR ("NULL queue passed%s\n", "");
+		return;
+	}
+	spin_lock(&cq_lock);
+	if (! (atomic_read(&q->flags) & DASD_CHANQ_ACTIVE)) {
+		PRINT_WARN("Queue not active\n");
+	}
+	else if (cq_head == q) {
+		cq_head = q->next_q;
+	} else {
+		c = cq_head;
+		while (c->next_q && c->next_q != q)
+			c = c->next_q;
+		if (c->next_q != q)
+			INTERNAL_ERROR ("Entry not in queue%s\n", "");
+		else
+			c->next_q = q->next_q;
+	}
+	q->next_q = NULL;
+	atomic_clear_mask(DASD_CHANQ_ACTIVE,&q->flags);
+	spin_unlock(&cq_lock);
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/block/dasd_ccwstuff.h linux.14p16/drivers/s390/block/dasd_ccwstuff.h
--- linux.vanilla/drivers/s390/block/dasd_ccwstuff.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/block/dasd_ccwstuff.h	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,9 @@
+extern atomic_t chanq_tasks;
+extern dasd_chanq_t *cq_head;
+
+cqr_t *request_cqr (int, int);
+int release_cqr (cqr_t *);
+int dasd_chanq_enq (dasd_chanq_t *, cqr_t *);
+int dasd_chanq_deq (dasd_chanq_t *, cqr_t *);
+void cql_enq_head (dasd_chanq_t * q);
+void cql_deq (dasd_chanq_t * q);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/block/dasd_eckd.c linux.14p16/drivers/s390/block/dasd_eckd.c
--- linux.vanilla/drivers/s390/block/dasd_eckd.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/block/dasd_eckd.c	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,1000 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_eckd.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif				/* MODULE */
+
+#include <linux/malloc.h>
+#include <asm/io.h>
+
+#include "../../../arch/s390/kernel/irq.h"
+
+#include "dasd_types.h"
+#include "dasd_ccwstuff.h"
+
+#include "dasd.h"
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#endif				/* PRINTK_HEADER */
+#define PRINTK_HEADER "dasd(eckd):"
+
+#define ECKD_C0(i) (i->home_bytes)
+#define ECKD_F(i) (i -> formula)
+#define ECKD_F1(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f1):(i->factors.f_0x02.f1))
+#define ECKD_F2(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f2):(i->factors.f_0x02.f2))
+#define ECKD_F3(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f3):(i->factors.f_0x02.f3))
+#define ECKD_F4(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f4):0)
+#define ECKD_F5(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f5):0)
+#define ECKD_F6(i) (i -> factor6)
+#define ECKD_F7(i) (i -> factor7)
+#define ECKD_F8(i) (i -> factor8)
+
+#define DASD_ECKD_CCW_LOCATE_RECORD 0x47
+
+#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a
+#define DASD_ECKD_CCW_WRITE_HOME_ADDRESS 0x09
+
+#define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16
+#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15
+
+#define DASD_ECKD_CCW_READ_COUNT 0x12
+#define DASD_ECKD_CCW_READ 0x06
+#define DASD_ECKD_CCW_READ_MT 0x86
+#define DASD_ECKD_CCW_WRITE 0x05
+#define DASD_ECKD_CCW_WRITE_MT 0x85
+#define DASD_ECKD_CCW_READ_CKD 0x1e
+#define DASD_ECKD_CCW_READ_CKD_MT 0x9e
+#define DASD_ECKD_CCW_WRITE_CKD 0x1d
+#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d
+
+typedef
+struct {
+	__u16 cyl;
+	__u16 head;
+} __attribute__ ((packed))
+
+ch_t;
+
+typedef
+struct {
+	__u16 cyl;
+	__u16 head;
+	__u32 sector;
+} __attribute__ ((packed))
+
+chs_t;
+
+typedef
+struct {
+	__u16 cyl;
+	__u16 head;
+	__u8 record;
+} __attribute__ ((packed))
+
+chr_t;
+
+typedef
+struct {
+	__u16 cyl;
+	__u16 head;
+	__u32 sector;
+} geom_t;
+
+typedef struct {
+	struct {
+		struct {
+			unsigned char identifier:2;
+			unsigned char token_id:1;
+			unsigned char sno_valid:1;
+			unsigned char subst_sno:1;
+			unsigned char recNED:1;
+			unsigned char emuNED:1;
+			unsigned char reserved:1;
+		} __attribute__ ((packed)) flags;
+		__u8 descriptor;
+		__u8 dev_class;
+		__u8 reserved;
+		unsigned char dev_type[6];
+		unsigned char dev_model[3];
+		unsigned char HDA_manufacturer[3];
+		unsigned char HDA_location[2];
+		unsigned char HDA_seqno[12];
+		__u16 ID;
+	} __attribute__ ((packed)) ned1;
+	struct {
+		struct {
+			unsigned char identifier:2;
+			unsigned char token_id:1;
+			unsigned char sno_valid:1;
+			unsigned char subst_sno:1;
+			unsigned char recNED:1;
+			unsigned char emuNED:1;
+			unsigned char reserved:1;
+		} __attribute__ ((packed)) flags;
+		__u8 descriptor;
+		__u8 reserved[2];
+		unsigned char dev_type[6];
+		unsigned char dev_model[3];
+		unsigned char DASD_manufacturer[3];
+		unsigned char DASD_location[2];
+		unsigned char DASD_seqno[12];
+		__u16 ID;
+	} __attribute__ ((packed)) ned2;
+	struct {
+		struct {
+			unsigned char identifier:2;
+			unsigned char token_id:1;
+			unsigned char sno_valid:1;
+			unsigned char subst_sno:1;
+			unsigned char recNED:1;
+			unsigned char emuNED:1;
+			unsigned char reserved:1;
+		} __attribute__ ((packed)) flags;
+		__u8 descriptor;
+		__u8 reserved[2];
+		unsigned char cont_type[6];
+		unsigned char cont_model[3];
+		unsigned char cont_manufacturer[3];
+		unsigned char cont_location[2];
+		unsigned char cont_seqno[12];
+		__u16 ID;
+	} __attribute__ ((packed)) ned3;
+	struct {
+		struct {
+			unsigned char identifier:2;
+			unsigned char token_id:1;
+			unsigned char sno_valid:1;
+			unsigned char subst_sno:1;
+			unsigned char recNED:1;
+			unsigned char emuNED:1;
+			unsigned char reserved:1;
+		} __attribute__ ((packed)) flags;
+		__u8 descriptor;
+		__u8 reserved[2];
+		unsigned char cont_type[6];
+		unsigned char empty[3];
+		unsigned char cont_manufacturer[3];
+		unsigned char cont_location[2];
+		unsigned char cont_seqno[12];
+		__u16 ID;
+	} __attribute__ ((packed)) ned4;
+	unsigned char ned5[32];
+	unsigned char ned6[32];
+	unsigned char ned7[32];
+	struct {
+		struct {
+			unsigned char identifier:2;
+			unsigned char reserved:6;
+		} __attribute__ ((packed)) flags;
+		__u8 selector;
+		__u16 interfaceID;
+		__u32 reserved;
+		__u16 subsystemID;
+		struct {
+			unsigned char sp0:1;
+			unsigned char sp1:1;
+			unsigned char reserved:5;
+			unsigned char scluster:1;
+		} __attribute__ ((packed)) spathID;
+		__u8 unit_address;
+		__u8 dev_ID;
+		__u8 dev_address;
+		__u8 adapterID;
+		__u16 link_address;
+		struct {
+			unsigned char parallel:1;
+			unsigned char escon:1;
+			unsigned char reserved:1;
+			unsigned char ficon:1;
+			unsigned char reserved2:4;
+		} __attribute__ ((packed)) protocol_type;
+		struct {
+			unsigned char PID_in_236:1;
+			unsigned char reserved:7;
+		} __attribute__ ((packed)) format_flags;
+		__u8 log_dev_address;
+		unsigned char reserved2[12];
+	} __attribute__ ((packed)) neq;
+
+} __attribute__ ((packed))
+
+eckd_confdata_t;
+
+typedef
+struct {
+	struct {
+		unsigned char perm:2;	/* Permissions on this extent */
+		unsigned char reserved:1;
+		unsigned char seek:2;	/* Seek control */
+		unsigned char auth:2;	/* Access authorization */
+		unsigned char pci:1;	/* PCI Fetch mode */
+	} __attribute__ ((packed)) mask;
+	struct {
+		unsigned char mode:2;	/* Architecture mode */
+		unsigned char ckd:1;	/* CKD Conversion */
+		unsigned char operation:3;	/* Operation mode */
+		unsigned char cfw:1;	/* Cache fast write */
+		unsigned char dfw:1;	/* DASD fast write */
+	} __attribute__ ((packed)) attributes;
+	__u16 short blk_size;	/* Blocksize */
+	__u16 fast_write_id;
+	__u8 unused;
+	__u8 reserved;
+	ch_t beg_ext;
+	ch_t end_ext;
+} __attribute__ ((packed, aligned (32)))
+
+DE_eckd_data_t;
+
+typedef
+struct {
+	struct {
+		unsigned char orientation:2;
+		unsigned char operation:6;
+	} __attribute__ ((packed)) operation;
+	struct {
+		unsigned char last_bytes_used:1;
+		unsigned char reserved:6;
+		unsigned char read_count_suffix:1;
+	} __attribute__ ((packed)) auxiliary;
+	__u8 unused;
+	__u8 count;
+	ch_t seek_addr;
+	chr_t search_arg;
+	__u8 sector;
+	__u16 length;
+} __attribute__ ((packed, aligned (32)))
+
+LO_eckd_data_t;
+
+/* Stuff for handling home addresses */
+typedef struct {
+	__u8 skip_control[14];
+	__u16 cell_number;
+	__u8 physical_addr[3];
+	__u8 flag;
+	ch_t track_addr;
+	__u8 reserved;
+	__u8 key_length;
+	__u8 reserved2[2];
+} __attribute__ ((packed, aligned (32)))
+
+eckd_home_t;
+
+/* eckd count area */
+typedef struct {
+	__u16 cyl;
+	__u16 head;
+	__u8 record;
+	__u8 kl;
+	__u16 dl;
+} __attribute__ ((packed))
+
+eckd_count_t;
+
+static unsigned int
+round_up_multiple (unsigned int no, unsigned int mult)
+{
+	int rem = no % mult;
+	return (rem ? no - rem + mult : no);
+/*      return (no % mult ? no - (no % mult) + mult : no); */
+}
+
+static unsigned int
+ceil_quot (unsigned int d1, unsigned int d2)
+{
+	return (d1 + (d2 - 1)) / d2;
+}
+
+static int
+bytes_per_record (dasd_eckd_characteristics_t * rdc,
+		  int kl,	/* key length */
+		  int dl /* data length */ )
+{
+	int bpr = 0;
+	switch (rdc->formula) {
+	case 0x01:{
+			unsigned int fl1, fl2;
+			fl1 = round_up_multiple (ECKD_F2 (rdc) + dl,
+						 ECKD_F1 (rdc));
+			fl2 = round_up_multiple (kl ? ECKD_F2 (rdc) + kl : 0,
+						 ECKD_F1 (rdc));
+			bpr = fl1 + fl2;
+			break;
+		}
+	case 0x02:{
+			unsigned int fl1, fl2, int1, int2;
+			int1 = ceil_quot (dl + ECKD_F6 (rdc),
+					  ECKD_F5 (rdc) << 1);
+			int2 = ceil_quot (kl + ECKD_F6 (rdc),
+					  ECKD_F5 (rdc) << 1);
+			fl1 = round_up_multiple (ECKD_F1 (rdc) *
+						 ECKD_F2 (rdc) +
+						 (dl + ECKD_F6 (rdc) +
+						  ECKD_F4 (rdc) * int1),
+						 ECKD_F1 (rdc));
+			fl2 = round_up_multiple (ECKD_F1 (rdc) *
+						 ECKD_F3 (rdc) +
+						 (kl + ECKD_F6 (rdc) +
+						  ECKD_F4 (rdc) * int2),
+						 ECKD_F1 (rdc));
+			bpr = fl1 + fl2;
+			break;
+		}
+	default:
+		INTERNAL_ERROR ("unknown formula%d\n", rdc->formula);
+	}
+	return bpr;
+}
+
+static inline unsigned int
+bytes_per_track (dasd_eckd_characteristics_t * rdc)
+{
+	return *(unsigned int *) (rdc->byte_per_track) >> 8;
+}
+
+static unsigned int
+recs_per_track (dasd_eckd_characteristics_t * rdc,
+		unsigned int kl, unsigned int dl)
+{
+	int rpt = 0;
+	if (rdc->formula == 0x01) {
+		if (kl)
+			return 1499 / (15 +
+				       7 + ceil_quot (kl + 12, 32) +
+				       ceil_quot (dl + 12, 32));
+		else
+			return 1499 / (15 + ceil_quot (dl + 12, 32));
+
+	}
+	if (rdc->formula == 0x02) {
+		int dn = ceil_quot (dl + 6, 232) + 1;
+		if (kl) {
+			int kn = ceil_quot (kl + 6, 232) + 1;
+			return 1729 / (10 +
+				       9 + ceil_quot (kl + 6 * kn, 34) +
+				       9 + ceil_quot (dl + 6 * dn, 34));
+		} else
+			return 1729 / (10 +
+				       9 + ceil_quot (dl + 6 * dn, 34));
+	}
+	return rpt;
+}
+
+static
+void
+define_extent (ccw1_t * de_ccw,
+	       DE_eckd_data_t * data,
+	       int trk,
+	       int totrk,
+	       int cmd,
+	       dasd_information_t * info)
+{
+	ch_t geo, beg, end;
+
+	geo.cyl = info->rdc_data->eckd.no_cyl;
+	geo.head = info->rdc_data->eckd.trk_per_cyl;
+	beg.cyl = trk / geo.head;
+	beg.head = trk % geo.head;
+	end.cyl = totrk / geo.head;
+	end.head = totrk % geo.head;
+
+	memset (de_ccw, 0, sizeof (ccw1_t));
+	de_ccw->cmd_code = CCW_DEFINE_EXTENT;
+	de_ccw->count = 16;
+	de_ccw->cda = (void *) virt_to_phys (data);
+
+	memset (data, 0, sizeof (DE_eckd_data_t));
+	switch (cmd) {
+	case DASD_ECKD_CCW_READ_HOME_ADDRESS:
+	case DASD_ECKD_CCW_READ_RECORD_ZERO:
+	case DASD_ECKD_CCW_READ:
+	case DASD_ECKD_CCW_READ_MT:
+	case DASD_ECKD_CCW_READ_CKD:	/* Fallthrough */
+	case DASD_ECKD_CCW_READ_CKD_MT:
+	case DASD_ECKD_CCW_READ_COUNT:
+		data->mask.perm = 0x1;
+		break;
+	case DASD_ECKD_CCW_WRITE:
+	case DASD_ECKD_CCW_WRITE_MT:
+		break;
+	case DASD_ECKD_CCW_WRITE_CKD:
+	case DASD_ECKD_CCW_WRITE_CKD_MT:
+		data->attributes.operation = 0x1;	/* format through cache */
+		break;
+	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
+	case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
+		data->mask.perm = 0x3;
+		data->mask.auth = 0x1;
+		data->attributes.operation = 0x1;	/* format through cache */
+		break;
+	default:
+		INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd);
+		break;
+	}
+	data->attributes.mode = 0x3;
+	data->beg_ext.cyl = beg.cyl;
+	data->beg_ext.head = beg.head;
+	data->end_ext.cyl = end.cyl;
+	data->end_ext.head = end.head;
+}
+
+static inline void
+locate_record (ccw1_t * lo_ccw,
+	       LO_eckd_data_t * data,
+	       int trk,
+	       int rec_on_trk,
+	       int no_rec,
+	       int cmd,
+	       dasd_information_t * info)
+{
+	ch_t geo =
+	{info->rdc_data->eckd.no_cyl,
+	 info->rdc_data->eckd.trk_per_cyl};
+	ch_t seek =
+	{trk / (geo.head), trk % (geo.head)};
+	int reclen = info->sizes.bp_block;
+	memset (lo_ccw, 0, sizeof (ccw1_t));
+	lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
+	lo_ccw->count = 16;
+	lo_ccw->cda = (void *) virt_to_phys (data);
+
+	memset (data, 0, sizeof (LO_eckd_data_t));
+	switch (cmd) {
+	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
+		data->operation.orientation = 0x3;
+		data->operation.operation = 0x03;
+		break;
+	case DASD_ECKD_CCW_READ_HOME_ADDRESS:
+		data->operation.orientation = 0x3;
+		data->operation.operation = 0x16;
+		break;
+	case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
+		data->operation.orientation = 0x3;
+		data->operation.operation = 0x03;
+		data->count++;
+		break;
+	case DASD_ECKD_CCW_READ_RECORD_ZERO:
+		data->operation.orientation = 0x3;
+		data->operation.operation = 0x16;
+		data->count++;
+		break;
+	case DASD_ECKD_CCW_WRITE:
+	case DASD_ECKD_CCW_WRITE_MT:
+		data->auxiliary.last_bytes_used = 0x1;
+		data->length = reclen;
+		data->operation.operation = 0x01;
+		break;
+	case DASD_ECKD_CCW_WRITE_CKD:
+	case DASD_ECKD_CCW_WRITE_CKD_MT:
+		data->auxiliary.last_bytes_used = 0x1;
+		data->length = reclen;
+		data->operation.operation = 0x03;
+		break;
+	case DASD_ECKD_CCW_READ:
+	case DASD_ECKD_CCW_READ_MT:
+		data->auxiliary.last_bytes_used = 0x1;
+		data->length = reclen;
+		data->operation.operation = 0x06;
+		break;
+	case DASD_ECKD_CCW_READ_CKD:
+	case DASD_ECKD_CCW_READ_CKD_MT:
+		data->auxiliary.last_bytes_used = 0x1;
+		data->length = reclen;
+		data->operation.operation = 0x16;
+		break;
+	case DASD_ECKD_CCW_READ_COUNT:
+		data->operation.operation = 0x06;
+                break;
+	default:
+		INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd);
+	}
+	memcpy (&(data->seek_addr), &seek, sizeof (ch_t));
+	memcpy (&(data->search_arg), &seek, sizeof (ch_t));
+	data->search_arg.record = rec_on_trk;
+	data->count += no_rec;
+}
+
+void
+dasd_eckd_print_error (devstat_t * stat)
+{
+	int sct, sl;
+	char *sense = stat->ii.sense.data;
+	PRINT_WARN ("IRQ on devno %x: with intparm:%x DS:0x%02x CS:0x%02x\n",
+		    stat->devno, stat->intparm, stat->dstat, stat->cstat);
+	PRINT_WARN ("Failing CCW: %p\n", (ccw1_t *) stat->cpa);
+	for (sl = 0; sl < 4; sl++) {
+		PRINT_DEBUG ("Sense:");
+		for (sct = 0; sct < 8; sct++) {
+			printk (" %2d:0x%02x",
+				8 * sl + sct, sense[8 * sl + sct]);
+		}
+		printk ("\n");
+	}
+	if (sense[27] & 0x80) {	/* 32 Byte Sense Data */
+		PRINT_INFO ("Sense Data is 32 Byte information\n");
+		PRINT_INFO ("Format: %x Exception class %x\n",
+			    sense[6] & 0x0f, sense[22] >> 4);
+	} else {		/* 24 Byte Sense Data */
+		PRINT_INFO ("Sense Data is 24 Byte information\n");
+		PRINT_INFO ("FMT: %x MSG %x, %s MSGb to SYSOP\n",
+			    sense[7] >> 4, sense[7] & 0x0f,
+			    sense[1] & 0x10 ? "" : "no");
+	}
+}
+
+int
+dasd_eckd_format_track (int di, int trk, int bs)
+{
+	int rc = 0;
+	int i;
+	int flags = 0x00;	/* FORMAT_R0 = 0x01, FORMAT_HA = 0x03 */
+        dasd_information_t * info=dasd_info[di];
+	cqr_t *fcp;
+	DE_eckd_data_t *DE_data;
+	LO_eckd_data_t *LO_data;
+	eckd_count_t *ct_data;
+	eckd_count_t *r0_data;
+	ccw1_t *last_ccw;
+        int retries = 5;
+
+	int rpt = recs_per_track (&(info->rdc_data->eckd), 0, bs);
+	int cyl = trk / info->rdc_data->eckd.trk_per_cyl;
+	int head = trk % info->rdc_data->eckd.trk_per_cyl;
+
+	fcp = request_cqr (2 + 1 + rpt,
+			   sizeof (DE_eckd_data_t) +
+			   sizeof (LO_eckd_data_t) +
+			   (rpt + 1) * sizeof (eckd_count_t));
+        fcp -> devindex=di;
+	DE_data = (DE_eckd_data_t *) fcp->data;
+	LO_data = (LO_eckd_data_t *) (((long) DE_data) +
+				      sizeof (DE_eckd_data_t));
+	r0_data = (eckd_count_t *) (((long) LO_data) +
+				    sizeof (LO_eckd_data_t));
+	ct_data = (eckd_count_t *) (((long) r0_data) +
+				    sizeof (eckd_count_t));
+	last_ccw = fcp->cpaddr;
+	switch (flags) {
+	case 0x03:
+		define_extent (last_ccw, DE_data, trk, trk,
+			       DASD_ECKD_CCW_WRITE_HOME_ADDRESS, info);
+		last_ccw->flags = CCW_FLAG_CC;
+		last_ccw++;
+		locate_record (last_ccw, LO_data, trk, 0, rpt,
+			       DASD_ECKD_CCW_WRITE_HOME_ADDRESS, info);
+		last_ccw->flags = CCW_FLAG_CC;
+		last_ccw++;
+		break;
+	case 0x01:
+		define_extent (last_ccw, DE_data, trk, trk,
+			       DASD_ECKD_CCW_WRITE_RECORD_ZERO, info);
+		last_ccw->flags = CCW_FLAG_CC;
+		last_ccw++;
+		locate_record (last_ccw, LO_data, trk, 0, rpt,
+			       DASD_ECKD_CCW_WRITE_RECORD_ZERO, info);
+		last_ccw->flags = CCW_FLAG_CC;
+		last_ccw++;
+		break;
+	case 0x00:
+		define_extent (last_ccw, DE_data, trk, trk,
+			       DASD_ECKD_CCW_WRITE_CKD, info);
+		last_ccw->flags = CCW_FLAG_CC;
+		last_ccw++;
+		locate_record (last_ccw, LO_data, trk, 0, rpt,
+			       DASD_ECKD_CCW_WRITE_CKD, info);
+                LO_data->length = bs;
+		last_ccw->flags = CCW_FLAG_CC;
+		last_ccw++;
+		break;
+	default:
+		PRINT_WARN ("Unknown format flags...%d\n", flags);
+		return -EINVAL;
+	}
+	if (flags & 0x02) {
+		PRINT_WARN ("Unsupported format flag...%d\n", flags);
+		return -EINVAL;
+	}
+	if (flags & 0x01) {	/* write record zero */
+		memset (r0_data, 0, sizeof (eckd_count_t));
+		r0_data->cyl = cyl;
+		r0_data->head = head;
+		r0_data->record = 0;
+		r0_data->kl = 0;
+		r0_data->dl = 8;
+		last_ccw->cmd_code = 0x03;
+		last_ccw->count = 8;
+		last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI;
+		last_ccw->cda = (void *) virt_to_phys (r0_data);
+		last_ccw++;
+	}
+	/* write remaining records */
+	for (i = 0; i < rpt; i++, last_ccw++) {
+		memset (ct_data + i, 0, sizeof (eckd_count_t));
+		(ct_data + i)->cyl = cyl;
+		(ct_data + i)->head = head;
+		(ct_data + i)->record = i + 1;
+		(ct_data + i)->kl = 0;
+		(ct_data + i)->dl = bs;
+		last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
+		last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI;
+		last_ccw->count = 8;
+		last_ccw->cda = (void *)
+                        virt_to_phys (ct_data + i);
+	}
+	(last_ccw - 1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC);
+        fcp -> devindex = di;
+        fcp -> flags = DASD_DO_IO_SLEEP;
+        do {
+                struct wait_queue wait = {current, NULL};
+                unsigned long flags;
+                int irq;
+                int cs;
+
+                irq = dasd_info[fcp->devindex]->info.irq;
+                s390irq_spin_lock_irqsave (irq, flags);
+                atomic_set(&fcp->status,CQR_STATUS_QUEUED);
+                rc = dasd_start_IO ( fcp );
+                add_wait_queue (&dasd_waitq, &wait);
+                do {
+                        current->state = TASK_UNINTERRUPTIBLE;
+                        s390irq_spin_unlock_irqrestore (irq, flags);
+                        schedule ();
+                        s390irq_spin_lock_irqsave (irq, flags);
+                } while (((cs = atomic_read (&fcp->status)) !=
+                          CQR_STATUS_DONE) &&
+                         (cs != CQR_STATUS_ERROR));
+                remove_wait_queue (&dasd_waitq, &wait);
+		s390irq_spin_unlock_irqrestore (irq, flags);
+
+                retries --;
+	} while ( (rc || (atomic_read(&fcp->status) != CQR_STATUS_DONE)) &&
+                  retries);
+        if ((rc || (atomic_read(&fcp->status) != CQR_STATUS_DONE)))
+                rc = -EIO;
+	release_cqr (fcp);
+	return rc;
+}
+
+int
+dasd_eckd_ck_devinfo (dev_info_t * info)
+{
+	return 0;
+}
+
+cqr_t *
+dasd_eckd_build_req (int devindex,
+		     struct request * req)
+{
+	cqr_t *rw_cp = NULL;
+	ccw1_t *ccw;
+
+	DE_eckd_data_t *DE_data;
+	LO_eckd_data_t *LO_data;
+	struct buffer_head *bh;
+	int rw_cmd;
+	dasd_information_t *info = dasd_info[devindex];
+	int blk_per_trk = recs_per_track (&(info->rdc_data->eckd),
+					  0, info->sizes.bp_block);
+	int byt_per_blk = info->sizes.bp_block;
+	int noblk = req-> nr_sectors >> info->sizes.s2b_shift;
+	int btrk = (req->sector >> info->sizes.s2b_shift) / blk_per_trk;
+	int etrk = ((req->sector + req->nr_sectors - 1) >>
+		    info->sizes.s2b_shift) / blk_per_trk;
+
+        if ( ! noblk ) {
+                PRINT_ERR("No blocks to write...returning\n");
+                return NULL;
+        }
+
+	if (req->cmd == READ) {
+		rw_cmd = DASD_ECKD_CCW_READ_MT;
+	} else
+#if DASD_PARANOIA > 2
+	if (req->cmd == WRITE)
+#endif				/* DASD_PARANOIA */
+	{
+		rw_cmd = DASD_ECKD_CCW_WRITE_MT;
+	}
+#if DASD_PARANOIA > 2
+	else {
+		PRINT_ERR ("Unknown command %d\n", req->cmd);
+		return NULL;
+	}
+#endif				/* DASD_PARANOIA */
+	/* Build the request */
+	rw_cp = request_cqr (2 + noblk,
+			     sizeof (DE_eckd_data_t) +
+			     sizeof (LO_eckd_data_t));
+        if ( ! rw_cp ) {
+          return NULL;
+        }
+	DE_data = rw_cp->data;
+	LO_data = rw_cp->data + sizeof (DE_eckd_data_t);
+	ccw = rw_cp->cpaddr;
+
+	define_extent (ccw, DE_data, btrk, etrk, rw_cmd, info);
+	ccw->flags = CCW_FLAG_CC;
+	ccw++;
+	locate_record (ccw, LO_data, btrk,
+		       (req->sector >> info->sizes.s2b_shift) %
+		       blk_per_trk + 1,
+		       req->nr_sectors >> info->sizes.s2b_shift,
+		       rw_cmd, info);
+	ccw->flags = CCW_FLAG_CC;
+	for (bh = req->bh; bh; bh = bh->b_reqnext) {
+                long size;
+		for (size = 0; size < bh->b_size; size += byt_per_blk) {
+                        ccw++;
+                        ccw->flags = CCW_FLAG_CC;
+                        ccw->cmd_code = rw_cmd;
+                        ccw->count = byt_per_blk;
+                        ccw->cda = (void *) virt_to_phys (bh->b_data + size);
+		}
+	}
+	ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
+	return rw_cp;
+}
+
+cqr_t *
+dasd_eckd_rw_label (int devindex, int rw, char *buffer)
+{
+	int cmd_code = 0x03;
+	dasd_information_t *info = dasd_info[devindex];
+	cqr_t *cqr;
+	ccw1_t *ccw;
+
+	switch (rw) {
+	case READ:
+		cmd_code = DASD_ECKD_CCW_READ;
+		break;
+	case WRITE:
+		cmd_code = DASD_ECKD_CCW_WRITE;
+		break;
+#if DASD_PARANOIA > 2
+	default:
+		INTERNAL_ERROR ("unknown cmd %d", rw);
+		return NULL;
+#endif				/* DASD_PARANOIA */
+	}
+	cqr = request_cqr (3, sizeof (DE_eckd_data_t) +
+			   sizeof (LO_eckd_data_t));
+	ccw = cqr->cpaddr;
+	define_extent (ccw, cqr->data, 0, 0, cmd_code, info);
+	ccw->flags |= CCW_FLAG_CC;
+	ccw++;
+	locate_record (ccw, cqr->data + 1, 0, 2, 1, cmd_code, info);
+	ccw->flags |= CCW_FLAG_CC;
+	ccw++;
+	ccw->cmd_code = cmd_code;
+	ccw->flags |= CCW_FLAG_SLI;
+	ccw->count = sizeof (dasd_volume_label_t);
+	ccw->cda = (void *) virt_to_phys ((void *) buffer);
+	return cqr;
+
+}
+
+void
+dasd_eckd_print_char (dasd_characteristics_t * i)
+{
+        dasd_eckd_characteristics_t * c = 
+                (dasd_eckd_characteristics_t *)i;
+	PRINT_INFO ("%x/%x (%x/%x) Cyl: %d Head: %d Sec: %d \n",
+		    c->dev_type, c->dev_model,
+		    c->cu_type, c->cu_model.model,
+		    c->no_cyl, c->trk_per_cyl,
+		    c->sec_per_trk);
+	PRINT_INFO ("Estimate: %d Byte/trk %d byte/kByte %d kByte/trk \n",
+		    bytes_per_track (c),
+		    bytes_per_record (c, 0, 1024),
+		    recs_per_track (c, 0, 1024));
+};
+
+int
+dasd_eckd_ck_char (dasd_characteristics_t * i)
+{
+	int rc = 0;
+	dasd_eckd_print_char (i);
+	return rc;
+}
+
+int
+dasd_eckd_format (int devindex, format_data_t * fdata)
+{
+	int rc = 0;
+	int i;
+	dasd_information_t *info = dasd_info[devindex];
+	format_data_t fd;
+
+	if (!fdata) {
+		fd.start_unit = 0;
+		fd.stop_unit = info->rdc_data->eckd.no_cyl *
+                        info->rdc_data->eckd.trk_per_cyl - 1;
+		fd.blksize = 4096;
+	} else {
+		memcpy (&fd, fdata, sizeof (format_data_t));
+		if ( fd.stop_unit == -1 ) {
+                        fd.stop_unit = info->rdc_data->eckd.no_cyl *
+                                info->rdc_data->eckd.trk_per_cyl - 1;
+		}
+                if ( fd.blksize == 0 ) {
+                        fd.blksize = 4096;
+                }
+	}
+        PRINT_INFO("Formatting device %d from %d to %d with bs %d\n",
+                   devindex,fd.start_unit,fd.stop_unit,fd.blksize);
+        if ( fd.start_unit > fd.stop_unit ) {
+                PRINT_WARN ("start unit .gt. stop unit\n");
+                return -EINVAL;
+        }
+        if ( (fd.start_unit > info->rdc_data->eckd.no_cyl *
+              info->rdc_data->eckd.trk_per_cyl - 1) ) {
+                PRINT_WARN ("start unit beyond end of disk\n");
+                return -EINVAL;
+        }
+        if ( (fd.stop_unit > info->rdc_data->eckd.no_cyl *
+              info->rdc_data->eckd.trk_per_cyl - 1) ) {
+                PRINT_WARN ("stop unit beyond end of disk\n");
+                return -EINVAL;
+        }
+        switch (fd.blksize) {
+        case 512:
+        case 1024:
+        case 2048:
+        case 4096:
+                break;
+        default:
+                PRINT_WARN ("invalid blocksize\n");
+                return -EINVAL;
+        }
+	for (i = fd.start_unit; i <= fd.stop_unit; i++) {
+                /* print 20 messages per disk at all */
+                if ( ! ( i % (info->rdc_data->eckd.trk_per_cyl  *
+                                (info->rdc_data->eckd.no_cyl / 20 ) )))  {
+                        PRINT_INFO ("Format %d Cylinder: %d\n",devindex,
+                                    i/info->rdc_data->eckd.trk_per_cyl);
+                }
+		rc = dasd_eckd_format_track (devindex, i, fd.blksize);
+		if (rc) {
+			PRINT_WARN ("Formatting of Track %d failed...exiting\n", i);
+			break;
+		}
+	}
+        PRINT_INFO("Formated device %d from %d to %d with bs %d\n",
+                   devindex,fd.start_unit,fd.stop_unit,fd.blksize);
+	return rc;
+}
+
+int
+dasd_eckd_read_count (int di)
+{
+	int rc;
+	cqr_t *rw_cp = NULL;
+	ccw1_t *ccw;
+	DE_eckd_data_t *DE_data;
+	LO_eckd_data_t *LO_data;
+	eckd_count_t *count_data;
+        int retries = 5;
+        unsigned long flags;
+        int irq;
+        int cs;
+	dasd_information_t *info = dasd_info[di];
+	rw_cp = request_cqr (3,
+			     sizeof (DE_eckd_data_t) +
+			     sizeof (LO_eckd_data_t) +
+			     sizeof (eckd_count_t));
+	DE_data = rw_cp->data;
+	LO_data = rw_cp->data + sizeof (DE_eckd_data_t);
+	count_data = (eckd_count_t*)((long)LO_data + sizeof (LO_eckd_data_t));
+	ccw = rw_cp->cpaddr;
+	define_extent (ccw, DE_data, 0, 0, DASD_ECKD_CCW_READ_COUNT, info);
+	ccw->flags = CCW_FLAG_CC;
+	ccw++;
+	locate_record (ccw, LO_data, 0, 1, 1, DASD_ECKD_CCW_READ_COUNT, info);
+	ccw->flags = CCW_FLAG_CC;
+	ccw++;
+	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+	ccw->count = 8;
+	ccw->cda = (void *) virt_to_phys (count_data);
+	rw_cp->devindex = di;
+        rw_cp -> options = DOIO_WAIT_FOR_INTERRUPT;
+        do {
+                irq = dasd_info[di]->info.irq;
+                s390irq_spin_lock_irqsave (irq, flags);
+                atomic_set(&rw_cp -> status, CQR_STATUS_QUEUED);
+                rc = dasd_start_IO ( rw_cp );
+                s390irq_spin_unlock_irqrestore (irq, flags);
+                retries --;
+	} while ( ( ( (cs=atomic_read(&rw_cp->status)) != CQR_STATUS_DONE) || 
+                    rc ) &&  retries );
+        if ( ( rc || cs != CQR_STATUS_DONE) ) {
+                if ( ( cs == CQR_STATUS_ERROR ) &&
+                     ( rw_cp -> dstat -> ii.sense.data[1] == 0x08 ) ) {
+                        rc = -EMEDIUMTYPE;
+                } else {
+                        dasd_eckd_print_error (rw_cp->dstat);
+                        rc = -EIO;
+                }
+        } else {
+                rc = count_data->dl;
+        }
+	release_cqr (rw_cp);
+	return rc;
+}
+
+int
+dasd_eckd_fill_sizes (int devindex)
+{
+	int bs = 0;
+	int sb;
+	dasd_information_t *in = dasd_info[devindex];
+	bs = dasd_eckd_read_count (devindex);
+	if (bs <= 0) {
+                PRINT_INFO("Cannot figure out blocksize. did you format the disk?\n");
+                memset (&(in -> sizes), 0, sizeof(dasd_sizes_t ));
+                return -EMEDIUMTYPE;
+	} else {
+		in->sizes.bp_block = bs;
+	}
+	in->sizes.bp_sector = in->sizes.bp_block;
+        
+	in->sizes.b2k_shift = 0; /* bits to shift a block to get 1k */
+	for (sb = 1024; sb < bs; sb = sb << 1)
+                in->sizes.b2k_shift++;
+        
+	in->sizes.s2b_shift = 0; /* bits to shift 512 to get a block */
+	for (sb = 512; sb < bs; sb = sb << 1)
+                in->sizes.s2b_shift++;
+        
+	in->sizes.blocks = in->rdc_data->eckd.no_cyl *
+                in->rdc_data->eckd.trk_per_cyl *
+                recs_per_track (&(in->rdc_data->eckd), 0, bs);
+	in->sizes.kbytes = in->sizes.blocks << in->sizes.b2k_shift;
+        
+	PRINT_INFO ("Verified: %d B/trk %d B/Blk(%d B) %d Blks/trk %d kB/trk \n",
+		    bytes_per_track (&(in->rdc_data->eckd)),
+		    bytes_per_record (&(in->rdc_data->eckd), 0, in->sizes.bp_block),
+                    in->sizes.bp_block,
+		    recs_per_track (&(in->rdc_data->eckd), 0, in->sizes.bp_block),
+		    (recs_per_track (&(in->rdc_data->eckd), 0, in->sizes.bp_block) <<
+                     in->sizes.b2k_shift ));
+                    return 0;
+}
+
+dasd_operations_t dasd_eckd_operations =
+{
+	dasd_eckd_ck_devinfo,
+	dasd_eckd_build_req,
+	dasd_eckd_rw_label,
+	dasd_eckd_ck_char,
+	dasd_eckd_fill_sizes,
+	dasd_eckd_format,
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/block/dasd_proc.c linux.14p16/drivers/s390/block/dasd_proc.c
--- linux.vanilla/drivers/s390/block/dasd_proc.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/block/dasd_proc.c	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,115 @@
+/*
+  Structure of the proc filesystem:
+  /proc/dasd/
+  /proc/dasd/devices                  # List of devices
+  /proc/dasd/ddabcd                   # Device node for devno abcd            
+  /proc/dasd/ddabcd1                  # Device node for partition abcd  
+  /proc/dasd/abcd                     # Device information for devno abcd
+*/
+
+#include <linux/proc_fs.h>
+
+#include "dasd.h"
+#include "dasd_types.h"
+
+int dasd_proc_read_devices ( char *, char **, off_t, int, int);
+#ifdef DASD_PROFILE
+extern int dasd_proc_read_statistics ( char *, char **, off_t, int, int);
+extern int dasd_proc_read_debug ( char *, char **, off_t, int, int);
+#endif /* DASD_PROFILE */
+
+struct proc_dir_entry dasd_proc_root_entry = {
+	0,
+	4,"dasd",
+	S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
+	1,0,0,
+	0,
+	NULL,
+};
+
+struct proc_dir_entry dasd_proc_devices_entry = {
+	0,
+	7,"devices",
+	S_IFREG | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
+	1,0,0,
+	0,
+	NULL,
+	&dasd_proc_read_devices,
+};
+
+#ifdef DASD_PROFILE
+struct proc_dir_entry dasd_proc_stats_entry = {
+	0,
+	10,"statistics",
+	S_IFREG | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
+	1,0,0,
+	0,
+	NULL,
+	&dasd_proc_read_statistics,
+};
+
+struct proc_dir_entry dasd_proc_debug_entry = {
+	0,
+	5,"debug",
+	S_IFREG | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
+	1,0,0,
+	0,
+	NULL,
+	&dasd_proc_read_debug,
+};
+#endif /* DASD_PROFILE */
+
+struct proc_dir_entry dasd_proc_device_template = {
+	0,
+	6,"dd????",
+	S_IFBLK | S_IRUGO | S_IWUSR | S_IWGRP,
+	1,0,0,
+	0,
+	NULL,
+};
+
+void
+dasd_proc_init ( void )
+{
+	proc_register( & proc_root, & dasd_proc_root_entry);
+	proc_register( & dasd_proc_root_entry, & dasd_proc_devices_entry);
+#ifdef DASD_PROFILE
+ 	proc_register( & dasd_proc_root_entry, & dasd_proc_stats_entry); 
+ 	proc_register( & dasd_proc_root_entry, & dasd_proc_debug_entry); 
+#endif /* DASD_PROFILE */
+}
+
+
+int 
+dasd_proc_read_devices ( char * buf, char **start, off_t off, int len, int d)
+{
+	int i;
+	len = sprintf ( buf, "dev# MAJ minor node        Format\n");
+	for ( i = 0; i < DASD_MAX_DEVICES; i++ ) {
+		dasd_information_t *info = dasd_info[i];
+		if ( ! info ) 
+			continue;
+		if ( len >= PAGE_SIZE - 80 )
+			len += sprintf ( buf + len, "terminated...\n");
+		len += sprintf ( buf + len,
+				 "%04X %3d %5d /dev/dd%04X",
+				 dasd_info[i]->info.devno,
+				 DASD_MAJOR,
+				 i << PARTN_BITS,
+				 i );
+                if (info->flags == DASD_NOT_FORMATTED) {
+			len += sprintf ( buf + len, "    n/a");
+		} else {
+			len += sprintf ( buf + len, " %6d", 
+					 info->sizes.bp_block);
+		}
+		len += sprintf ( buf + len, "\n");
+	} 
+	return len;
+}
+
+
+void 
+dasd_proc_add_node (int di) 
+{
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/block/dasd_profile.c linux.14p16/drivers/s390/block/dasd_profile.c
--- linux.vanilla/drivers/s390/block/dasd_profile.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/block/dasd_profile.c	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,209 @@
+#include <linux/mm.h>
+#include <asm/spinlock.h>
+
+#include "dasd.h"
+#include "dasd_types.h"
+
+#define PRINTK_HEADER "dasd_profile:"
+
+static long dasd_io_reqs=0; /* number of requests processed at all */
+static long dasd_io_secs[16]; /* histogram of request's sizes */
+static long dasd_io_times[16]; /* histogram of requests's times */
+static long dasd_io_timps[16]; /* histogram of requests's times per sector */
+static long dasd_io_time1[16]; /* histogram of time from build to start */
+static long dasd_io_time2[16]; /* histogram of time from start to irq */
+static long dasd_io_time2ps[16]; /* histogram of time from start to irq */
+static long dasd_io_time3[16]; /* histogram of time from irq to end */
+
+void
+dasd_profile_add ( cqr_t *cqr )
+{
+	int ind;
+	long strtime,irqtime,endtime,tottime;
+	long tottimeps,sectors;
+	long help;
+	if ( ! cqr -> req ) 
+	  return;
+	sectors = cqr -> req -> nr_sectors;
+	strtime = ((cqr->startclk - cqr->buildclk) >> 12);
+	irqtime = ((cqr->stopclk - cqr->startclk) >> 12);
+	endtime = ((cqr->endclk - cqr->stopclk) >> 12);
+	tottime = ((cqr->endclk - cqr->buildclk) >> 12);
+	tottimeps = tottime / sectors;
+
+	if (! dasd_io_reqs ++){
+	  for ( ind = 0; ind < 16; ind ++) {
+		dasd_io_secs[ind] = 0;
+		dasd_io_times[ind]=0;
+		dasd_io_timps[ind]=0;
+		dasd_io_time1[ind]=0;
+		dasd_io_time2[ind]=0;
+		dasd_io_time2ps[ind]=0;
+		dasd_io_time3[ind]=0;
+	  }
+	};
+	
+	for ( ind = 0, help = sectors >> 3; 
+	      ind < 15 && help; 
+	      help = help >> 1,ind ++);
+	dasd_io_secs[ind] ++;
+
+	for ( ind = 0, help = tottime >> 3; 
+	      ind < 15 && help; 
+	      help = help >> 1,ind ++);
+	dasd_io_times[ind] ++;
+
+	for ( ind = 0, help = tottimeps >> 3; 
+	      ind < 15 && help; 
+	      help = help >> 1,ind ++);
+	dasd_io_timps[ind] ++;
+
+	for ( ind = 0, help = strtime >> 3; 
+	      ind < 15 && help; 
+	      help = help >> 1,ind ++);
+	dasd_io_time1[ind] ++;
+
+	for ( ind = 0, help = irqtime >> 3; 
+	      ind < 15 && help; 
+	      help = help >> 1,ind ++);
+	dasd_io_time2[ind] ++;
+
+	for ( ind = 0, help = (irqtime/sectors) >> 3; 
+	      ind < 15 && help; 
+	      help = help >> 1,ind ++);
+	dasd_io_time2ps[ind] ++;
+
+	for ( ind = 0, help = endtime >> 3; 
+	      ind < 15 && help; 
+	      help = help >> 1,ind ++);
+	dasd_io_time3[ind] ++;
+}
+
+int 
+dasd_proc_read_statistics ( char * buf, char **start, 
+			    off_t off, int len, int d)
+{
+	int i;
+	int shift, help;
+	
+	for ( shift = 0, help = dasd_io_reqs; 
+	      help > 8192; 
+	      help = help >> 1,shift ++);
+	len = sprintf ( buf, "%ld dasd I/O requests\n", dasd_io_reqs); 
+	len += sprintf ( buf+len, "__<4 ___8 __16 __32 __64 _128 _256 _512 __1k __2k __4k __8k _16k _32k _64k >64k\n");
+	len += sprintf ( buf+len, "Histogram of sizes (512B secs)\n");
+	for ( i = 0; i < 16; i ++) {
+		len += sprintf ( buf+len, "%4ld ",dasd_io_secs[i] >> shift );
+	}
+	len += sprintf ( buf+len, "\n");
+	len += sprintf ( buf+len, "Histogram of I/O times\n");
+	for ( i = 0; i < 16; i ++) {
+		len += sprintf ( buf+len, "%4ld ",dasd_io_times[i] >> shift );
+	}
+	len += sprintf ( buf+len, "\n");
+	len += sprintf ( buf+len, "Histogram of I/O times per sector\n");
+	for ( i = 0; i < 16; i ++) {
+		len += sprintf ( buf+len, "%4ld ",dasd_io_timps[i] >> shift );
+	}
+	len += sprintf ( buf+len, "\n");
+	len += sprintf ( buf+len, "Histogram of I/O time till ssch\n");
+	for ( i = 0; i < 16; i ++) {
+		len += sprintf ( buf+len, "%4ld ",dasd_io_time1[i] >> shift );
+	}
+	len += sprintf ( buf+len, "\n");
+	len += sprintf ( buf+len, "Histogram of I/O time between ssch and irq\n");
+	for ( i = 0; i < 16; i ++) {
+		len += sprintf ( buf+len, "%4ld ",dasd_io_time2[i] >> shift );
+	}
+	len += sprintf ( buf+len, "\n");
+	len += sprintf ( buf+len, "Histogram of I/O time between ssch and irq per sector\n");
+	for ( i = 0; i < 16; i ++) {
+		len += sprintf ( buf+len, "%4ld ",dasd_io_time2ps[i] >> shift );
+	}
+	len += sprintf ( buf+len, "\n");
+	len += sprintf ( buf+len, "Histogram of I/O time between irq and end\n");
+	for ( i = 0; i < 16; i ++) {
+		len += sprintf ( buf+len, "%4ld ",dasd_io_time3[i] >> shift );
+	}
+	len += sprintf ( buf+len, "\n");
+	return len;
+}
+typedef
+struct {
+	union {
+		unsigned long long  clock;
+		struct {
+			unsigned int ts1;
+			unsigned int ts2 : 20;
+			unsigned int unused : 8;
+			unsigned int cpu : 4;
+		} __attribute__ ((packed)) s;
+	} __attribute__ ((packed)) u;
+	unsigned long caller_address;
+	unsigned long tag;
+} __attribute__ ((packed)) dasd_debug_entry;
+
+static dasd_debug_entry *dasd_debug_area = NULL;
+static dasd_debug_entry *dasd_debug_actual;
+static spinlock_t debug_lock = SPIN_LOCK_UNLOCKED;
+
+void 
+dasd_debug ( unsigned long tag )
+{
+	long flags;
+	dasd_debug_entry *d;
+	/* initialize in first call ... */
+	if ( ! dasd_debug_area ) {
+		dasd_debug_actual = dasd_debug_area = 
+			get_free_page (GFP_ATOMIC);
+		if ( ! dasd_debug_area ) {
+			PRINT_WARN("No debug area allocated\n");
+			return;
+		}
+		memset (dasd_debug_area,0,PAGE_SIZE);
+	}
+	/* renormalize to page */
+	spin_lock_irqsave(&debug_lock,flags);
+	dasd_debug_actual = (dasd_debug_entry *)
+		( (unsigned long) dasd_debug_area +
+		  ( ( (unsigned long)dasd_debug_actual -
+		      (unsigned long)dasd_debug_area ) % 1808 ) );
+	d = dasd_debug_actual ++;
+	spin_unlock_irqrestore(&debug_lock,flags);
+	/* write CPUID to lowest 12 bits of clock... */
+	__asm__ __volatile__ ( "STCK  %0\n"
+			       "ST    14,%1\n"
+			       :"=m" (d->u.clock),
+			       "=m" (d->caller_address));
+	d->tag = tag;
+	d->u.s.cpu = smp_processor_id();
+}
+
+int 
+dasd_proc_read_debug ( char * buf, char **start, 
+		       off_t off, int len, int dd)
+{
+	dasd_debug_entry *d;
+	char tag[9] = { 0, };
+	long flags;
+	spin_lock_irqsave(&debug_lock,flags);
+	len = 0;
+       	for( d = dasd_debug_area; 
+	     len < 4068 ;
+	     d ++ ) {
+		if ( *(char*)(&d->tag) == 'D' ) {
+			memcpy(tag,&(d->tag),4);
+			tag[4]=0;
+		}
+		else {
+			sprintf(tag,"%08x",d->tag);
+			tag[8]=0;
+		}
+		len += sprintf ( buf+len,
+				 "%lx %08x%05x %08lx (%8s)\n",
+				 d->u.s.cpu, d->u.s.ts1, d->u.s.ts2,
+				 d->caller_address,tag);
+	}
+	spin_unlock_irqrestore(&debug_lock,flags);
+	return len;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/block/dasd_types.h linux.14p16/drivers/s390/block/dasd_types.h
--- linux.vanilla/drivers/s390/block/dasd_types.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/block/dasd_types.h	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,303 @@
+/* 456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.
+ * IBM CONFIDENTIAL
+ * File...........: linux/drivers/s390/block/dasd_types.h
+ * Author.........: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Created........: 08/31/1999
+ * Last Modified..: 09/29/1999
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999
+
+ * List of Changes:
+ - Initial Release as of 09/29/1999
+
+ * Description
+
+ * Restrictions
+
+ * Known Bugs
+
+ * Todo-List
+
+ */
+
+#ifndef DASD_TYPES_H
+#define DASD_TYPES_H
+
+#include "dasd.h"
+
+#include <linux/blkdev.h>
+
+#include "../../../arch/s390/kernel/irq.h"
+
+#define CCW_DEFINE_EXTENT 0x63
+#define CCW_LOCATE_RECORD 0x43
+#define CCW_READ_DEVICE_CHARACTERISTICS 0x64
+
+typedef
+enum {
+	dasd_none = -1,
+#ifdef CONFIG_DASD_FBA
+	dasd_fba,
+#endif				/* CONFIG_DASD_FBA */
+#ifdef CONFIG_DASD_CKD
+	dasd_ckd,
+#endif				/* CONFIG_DASD_CKD */
+#ifdef CONFIG_DASD_ECKD
+	dasd_eckd
+#endif				/* CONFIG_DASD_ECKD */
+} dasd_type_t;
+
+typedef
+struct {
+	union {
+		__u8 c;
+		struct {
+			unsigned char reserved:1;
+			unsigned char overrunnable:1;
+			unsigned char burst_byte:1;
+			unsigned char data_chain:1;
+			unsigned char zeros:4;
+		} __attribute__ ((packed)) bits;
+	} __attribute__ ((packed)) mode;
+	union {
+		__u8 c;
+		struct {
+			unsigned char zero0:1;
+			unsigned char removable:1;
+			unsigned char shared:1;
+			unsigned char zero1:1;
+			unsigned char bam:1;
+			unsigned char hpsa:1;
+			unsigned char zeros:2;
+		} __attribute__ ((packed)) bits;
+	} __attribute__ ((packed)) features;
+	__u8 dev_class;
+	__u8 unit_type;
+	__u16 blk_size;
+	__u32 blk_per_cycl;
+	__u32 blk_per_bound;
+	__u32 blk_bdsa;
+	__u32 blk_hpsa;
+	__u16 reserved1;
+	__u16 blk_ce;
+	__u32 reserved2;
+	__u16 reserved3;
+} __attribute__ ((packed, aligned (32))) 
+
+dasd_fba_characteristics_t;
+
+typedef
+struct {
+	__u16 cu_type;
+	struct {
+		unsigned char support:2;
+		unsigned char async:1;
+		unsigned char reserved:1;
+		unsigned char cache_info:1;
+		unsigned char model:3;
+	} __attribute__ ((packed)) cu_model;
+	__u16 dev_type;
+	__u8 dev_model;
+	struct {
+		unsigned char mult_burst:1;
+		unsigned char RT_in_LR:1;
+		unsigned char reserved1:1;
+		unsigned char RD_IN_LR:1;
+		unsigned char reserved2:4;
+		unsigned char reserved3:8;
+		unsigned char defect_wr:1;
+		unsigned char reserved4:2;
+		unsigned char striping:1;
+		unsigned char reserved5:4;
+		unsigned char cfw:1;
+		unsigned char reserved6:2;
+		unsigned char cache:1;
+		unsigned char dual_copy:1;
+		unsigned char dfw:1;
+		unsigned char reset_alleg:1;
+		unsigned char sense_down:1;
+	} __attribute__ ((packed)) facilities;
+	__u8 dev_class;
+	__u8 unit_type;
+	__u16 no_cyl;
+	__u16 trk_per_cyl;
+	__u8 sec_per_trk;
+	__u8 byte_per_track[3];
+	__u16 home_bytes;
+	__u8 formula;
+	union {
+		struct {
+			__u8 f1;
+			__u16 f2;
+			__u16 f3;
+		} __attribute__ ((packed)) f_0x01;
+		struct {
+			__u8 f1;
+			__u8 f2;
+			__u8 f3;
+			__u8 f4;
+			__u8 f5;
+		} __attribute__ ((packed)) f_0x02;
+	} __attribute__ ((packed)) factors;
+	__u16 first_alt_trk;
+	__u16 no_alt_trk;
+	__u16 first_dia_trk;
+	__u16 no_dia_trk;
+	__u16 first_sup_trk;
+	__u16 no_sup_trk;
+	__u8 MDR_ID;
+	__u8 OBR_ID;
+	__u8 director;
+	__u8 rd_trk_set;
+	__u16 max_rec_zero;
+	__u8 reserved1;
+	__u8 RWANY_in_LR;
+	__u8 factor6;
+	__u8 factor7;
+	__u8 factor8;
+	__u8 reserved2[3];
+	__u8 reserved3[10];
+} __attribute__ ((packed, aligned (32))) 
+
+dasd_eckd_characteristics_t;
+
+#ifdef CONFIG_DASD_CKD
+struct dasd_ckd_characteristics {
+	char info[64];
+};
+
+#endif				/* CONFIG_DASD_CKD */
+
+#ifdef CONFIG_DASD_ECKD
+struct dasd_eckd_characteristics {
+	char info[64];
+};
+
+#endif				/* CONFIG_DASD_ECKD */
+
+typedef
+union {
+	char __attribute__ ((aligned (32))) bytes[64];
+#ifdef CONFIG_DASD_FBA
+	dasd_fba_characteristics_t fba;
+#endif				/* CONFIG_DASD_FBA */
+#ifdef CONFIG_DASD_CKD
+	struct dasd_ckd_characteristics ckd;
+#endif				/* CONFIG_DASD_CKD */
+#ifdef CONFIG_DASD_ECKD
+	dasd_eckd_characteristics_t eckd;
+#endif				/* CONFIG_DASD_ECKD */
+} __attribute__ ((aligned (32))) 
+
+dasd_characteristics_t;
+
+#define CQR_STATUS_EMPTY  0x00
+#define CQR_STATUS_FILLED 0x01
+#define CQR_STATUS_QUEUED 0x02
+#define CQR_STATUS_IN_IO  0x04
+#define CQR_STATUS_DONE   0x08
+#define CQR_STATUS_RETRY  0x10
+#define CQR_STATUS_ERROR  0x20
+#define CQR_STATUS_FAILED 0x40
+#define CQR_STATUS_SLEEP  0x80
+
+#define CQR_FLAGS_SLEEP   0x01
+#define CQR_FLAGS_WAIT    0x02
+#define CQR_FLAGS_NOLOCK  0x04
+#define CQR_FLAGS_NORETRY 0x08
+
+typedef
+struct cqr_t {
+	unsigned int    magic;    /* magic number should be "DASD" */
+	atomic_t status;	/* current status of request */
+	unsigned short retries; /* counter for retry in error case */
+	unsigned short cplength;/* Length of channel program  (CP) */
+	unsigned short devindex;/* device number */
+	unsigned short flags;    /* Flags for execution */
+	
+	void * data;		/* additional data area for CP */
+	ccw1_t *cpaddr;		/* Address of CP */
+	struct request *req;	/* backpointer to struct request */
+	struct cqr_t *next;     /* forward chain in chanq */
+	struct cqr_t *int4cqr;  /* which cqr ist the nect PCI for? */
+	unsigned long long buildclk;
+	unsigned long long startclk;
+	unsigned long long stopclk;
+	unsigned long long endclk;
+	devstat_t *dstat;	/* savearea for devstat */
+	spinlock_t lock;
+	int options;
+} __attribute__ ((packed)) 
+cqr_t;
+
+typedef
+struct {
+	unsigned long int kbytes;
+	unsigned int bp_sector;
+	unsigned int bp_block;
+	unsigned int blocks;
+	unsigned int s2b_shift;
+	unsigned int b2k_shift;
+	unsigned int first_sector;
+} dasd_sizes_t;
+
+#define DASD_CHANQ_ACTIVE 0x01
+#define DASD_CHANQ_BUSY 0x02
+typedef
+struct dasd_chanq_t {
+	volatile cqr_t *head;
+	volatile cqr_t *tail;
+	spinlock_t q_lock;	/* lock for queue operations */
+	spinlock_t f_lock;	/* lock for flag operations */
+	long lockflags;
+	atomic_t flags;
+	struct dasd_chanq_t *next_q;	/* pointer to next queue */
+} __attribute__ ((packed, aligned (16))) 
+dasd_chanq_t;
+
+typedef
+struct dasd_information_t {
+	devstat_t dev_status;
+	dasd_characteristics_t *rdc_data;
+	dasd_volume_label_t *label;
+	dasd_type_t type;
+	dev_info_t info;
+	dasd_sizes_t sizes;
+	dasd_chanq_t queue;
+	int open_count;
+	spinlock_t lock;
+	struct semaphore sem;
+	unsigned long flags;
+	int irq;
+	struct proc_dir_entry *proc_device;
+	union {
+		struct {
+			char dummy;
+		} fba;
+		struct {
+			char dummy;
+		} ckd;
+		struct {
+			int blk_per_trk;
+		} eckd;
+	} private;
+} dasd_information_t;
+
+typedef struct {
+	int start_unit;
+	int stop_unit;
+	int blksize;
+} format_data_t;
+
+typedef
+struct {
+	int (*ck_devinfo) (dev_info_t *);
+	cqr_t *(*get_req_ccw) (int, struct request *);
+	cqr_t *(*rw_label) (int, int, char *);
+	int (*ck_characteristics) (dasd_characteristics_t *);
+	int (*fill_sizes) (int);
+	int (*dasd_format) (int, format_data_t *);
+} dasd_operations_t;
+
+extern dasd_information_t *dasd_info[];
+
+#endif				/* DASD_TYPES_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/block/mdisk.c linux.14p16/drivers/s390/block/mdisk.c
--- linux.vanilla/drivers/s390/block/mdisk.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/block/mdisk.c	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,697 @@
+/*
+ *  drivers/s390/block/mdisk.c
+ *    VM minidisk device driver.
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Hartmut Penner (hp@de.ibm.com)
+ */
+
+
+#ifndef __KERNEL__
+#  define __KERNEL__
+#endif
+
+#define __NO_VERSION__
+#include <linux/version.h>
+
+char kernel_version [] = UTS_RELEASE;
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>              /* printk()                         */
+#include <linux/malloc.h>              /* kmalloc()                        */
+#include <linux/vmalloc.h>             /* vmalloc()                        */
+#include <linux/fs.h>                  /* everything...                    */
+#include <linux/errno.h>               /* error codes                      */
+#include <linux/timer.h>
+#include <linux/types.h>               /* size_t                           */
+#include <linux/fcntl.h>               /* O_ACCMODE                        */
+#include <linux/hdreg.h>               /* HDIO_GETGEO                      */
+#include <linux/init.h>                /* initfunc                         */
+#include <linux/interrupt.h>
+#include <linux/ctype.h>
+
+#include <asm/system.h>                /* cli(), *_flags                   */
+#include <asm/uaccess.h>               /* access_ok                        */
+#include <asm/io.h>                    /* virt_to_phys                     */
+
+	 /* Added statement HSM 12/03/99 */
+#include "../../../arch/s390/kernel/irq.h"
+
+#define MAJOR_NR MDISK_MAJOR /* force definitions on in blk.h */
+
+#include <linux/blk.h>
+
+
+#include "mdisk.h"        /* local definitions */
+
+/*
+ * structure for all device specific information
+ */
+
+typedef struct mdisk_Dev {
+	u32 vdev;   /* vdev of mindisk */
+	u32 size;   /* size in blocks */
+	u32 status; /* status of last io operation */
+	u32 nr_bhs; /* number of buffer of last io operation */
+        u32 blksize; /* blksize from minidisk */
+        u32 blkmult; /* multiplier between blksize and 512 HARDSECT */
+        u32 blkshift; /* loe2 of multiplier above */
+	/*
+	 * each device has own iob and bio,
+	 * it's possible to run io in parallel
+	 * not used yet due to only one CURRENT per MAJOR
+	 */
+	
+	mdisk_rw_io_t* iob;      /* each device has it own iob and bio */
+	mdisk_bio_t*   bio;
+	 /* Added statement HSM 12/03/99 */
+	devstat_t dev_status;    /* Here we hold the I/O status */
+
+	int usage;               /* usage counter */
+
+	struct tq_struct tqueue; /* per device task queue */
+} mdisk_Dev;
+
+
+/*
+ * appended to global structures in mdisk_init;
+ */
+
+static int mdisk_blksizes[MDISK_DEVS];
+static int mdisk_sizes[MDISK_DEVS] = { 0 };
+static int mdisk_hardsects[MDISK_DEVS];
+static int mdisk_maxsectors[MDISK_DEVS];
+
+/*
+ *  structure hold device specific information
+ */
+
+static mdisk_Dev mdisk_devices[MDISK_DEVS];
+static mdisk_rw_io_t mdisk_iob[MDISK_DEVS] __attribute__ ((aligned(8)));
+static mdisk_bio_t mdisk_bio[MDISK_DEVS][256]__attribute__ ((aligned(8)));
+
+
+/*
+ * Parameter parsing
+ */
+struct {
+        long vdev[MDISK_DEVS];
+	long size[MDISK_DEVS];
+	long offset[MDISK_DEVS];
+        long blksize[MDISK_DEVS];
+} mdisk_setup_data;
+
+/*
+ * Parameter parsing function, called from init/main.c
+ * vdev    : virtual device number
+ * size    : size in kbyte
+ * offset  : offset after which minidisk is available
+ * blksize : blocksize minidisk is formated
+ * Format is: mdisk=<vdev>:<size>:<offset>:<blksize>,<vdev>:<size>:<offset>...
+ * <vdev>:<size>:<offset>:<blksize> can be shortened to <vdev>:<size> with offset=0,blksize=512
+ */
+__initfunc(void mdisk_setup(char *str,int *ints))
+{
+	char *cur = str;
+	int vdev, size, offset=0,blksize;
+	static i = 0;
+	if (!i)
+	  memset(&mdisk_setup_data,0,sizeof(mdisk_setup_data));
+
+        while (*cur != 0) {
+	        blksize=MDISK_HARDSECT;
+		vdev = size = offset = 0;
+		if (!isxdigit(*cur)) goto syntax_error;
+		vdev = simple_strtoul(cur,&cur,16);
+		if (*cur++ != ':') goto syntax_error;
+		if (!isxdigit(*cur)) goto syntax_error;
+		size = simple_strtoul(cur,&cur,16);
+		if (*cur == ':') { /* another colon -> offset specified */
+			cur++;
+			if (!isxdigit(*cur)) goto syntax_error;
+			offset = simple_strtoul(cur,&cur,16);
+			if (*cur == ':') { /* another colon -> blksize */
+			  cur++;
+			  if (!isxdigit(*cur)) goto syntax_error;
+			  blksize = simple_strtoul(cur,&cur,16);
+			}
+		}
+		if (*cur != ',' && *cur != 0) goto syntax_error;
+		if (*cur == ',') cur++;
+		if (i >= MDISK_DEVS) {
+			printk(KERN_WARNING "mnd: too many devices\n");
+			return;
+		}
+		mdisk_setup_data.vdev[i] = vdev;
+		mdisk_setup_data.size[i] = size;
+		mdisk_setup_data.offset[i] = offset;
+		mdisk_setup_data.blksize[i] = blksize;
+
+		i++;
+	}
+	
+	return;
+
+syntax_error:
+        printk(KERN_WARNING "mnd: syntax error in parameter string: %s\n", str);
+	return;
+}
+
+/*
+ * Open and close
+ */
+
+static int mdisk_open (struct inode *inode, struct file *filp)
+{
+	mdisk_Dev *dev; /* device information */
+	int num = MINOR(inode->i_rdev);
+	
+	/* 
+	 * size 0 means device not installed
+	 */
+	if ((num >= MDISK_DEVS) || (mdisk_sizes[num] == 0))
+		return -ENODEV;
+	MOD_INC_USE_COUNT;
+	dev = &mdisk_devices[num];
+	dev->usage++;
+	return 0;          /* success */
+}
+
+static int mdisk_release (struct inode *inode, struct file *filp)
+{
+	mdisk_Dev *dev = &mdisk_devices[MINOR(inode->i_rdev)];
+	
+	/*
+	 * flush device
+	 */
+	
+	fsync_dev(inode->i_rdev);
+	dev->usage--;
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+
+/*
+ * The mdisk() implementation
+ */
+
+static int mdisk_ioctl (struct inode *inode, struct file *filp,
+                 unsigned int cmd, unsigned long arg)
+{
+	int err,rc, size=0;
+	struct hd_geometry *geo = (struct hd_geometry *)arg;
+	mdisk_Dev *dev = mdisk_devices + MINOR(inode->i_rdev);
+	
+	switch(cmd) {
+		
+	case BLKGETSIZE:
+	        rc = copy_to_user ((long *) arg, &dev->size, sizeof (long));
+		printk(KERN_WARNING "mnd: ioctl BLKGETSIZE %d\n",dev->size);
+		return rc;
+	case BLKFLSBUF: /* flush */
+		if (!suser()) return -EACCES; /* only root */
+		fsync_dev(inode->i_rdev);
+		invalidate_buffers(inode->i_rdev);
+		return 0;
+		
+	case BLKRAGET: /* return the readahead value */
+		if (!arg)  return -EINVAL;
+		err = access_ok(VERIFY_WRITE, (long *) arg, sizeof(long));
+		if (err) return err;
+		put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
+		return 0;
+		
+	case BLKRASET: /* set the readahead value */
+		if (!suser()) return -EACCES;
+		if (arg > 0xff) return -EINVAL; /* limit it */
+		read_ahead[MAJOR(inode->i_rdev)] = arg;
+		return 0;
+		
+	case BLKRRPART: /* re-read partition table: can't do it */
+		return -EINVAL;
+		
+		RO_IOCTLS(inode->i_rdev, arg); /* the default RO operations */
+		
+	case HDIO_GETGEO:
+		/*
+		 * get geometry of device -> linear
+		 */
+		size = dev->size;
+		if (geo==NULL) return -EINVAL;
+		err = access_ok(VERIFY_WRITE, geo, sizeof(*geo));
+		if (err) return err;
+		put_user(1,    &geo->cylinders);
+		put_user(1,    &geo->heads);
+		put_user(size, &geo->sectors);
+		put_user(0,    &geo->start);
+		return 0;
+	}
+	
+	return -EINVAL; /* unknown command */
+}
+
+/*
+ * The file operations
+ */
+
+static struct file_operations mdisk_fops = {
+	NULL,          /* lseek: default */
+	block_read,
+	block_write,
+	NULL,          /* mdisk_readdir */
+	NULL,          /* mdisk_select */
+	mdisk_ioctl,
+	NULL,          /* mdisk_mmap */
+	mdisk_open,
+	NULL,          /* mdisk_flush */
+	mdisk_release,
+	block_fsync,
+	NULL,          /* mdisk_fasync */
+	NULL,          /* mdisk_check_change */
+	NULL,          /* mdisk_revalidate */
+	NULL,          /* mdisk_lock */
+};
+
+/*
+ * The 'low level' IO function
+ */
+
+
+static __inline__ int
+dia250(void* iob,int cmd)
+{
+	int rc;
+	
+	iob = (void*) virt_to_phys(iob);
+
+	asm volatile ("    lr    2,%1\n"
+		      "    lr    3,%2\n"
+		      "    .long 0x83230250\n"
+		      "    lr    %0,3"
+		      : "=d" (rc)
+		      : "d" (iob) , "d" (cmd)
+		      : "2", "3" );
+	return rc;
+}
+
+/*
+ * Init of minidisk device
+ */
+
+static __inline__ int
+mdisk_init_io(mdisk_Dev *dev,int blocksize,int offset,int size)
+{
+	mdisk_init_io_t *iob = (mdisk_init_io_t*) dev->iob;
+	int rc;
+
+	memset(iob,0,sizeof(mdisk_init_io_t));
+	
+	iob->dev_nr = dev->vdev;
+	iob->block_size = blocksize;
+	iob->offset     = offset;
+	iob->start_block= 0;
+	iob->end_block  = size;
+	
+	rc = dia250(iob,INIT_BIO);
+	
+	/*
+	 * clear for following io once
+	 */
+	
+	memset(iob,0,sizeof(mdisk_rw_io_t));
+	
+	return rc;
+}
+
+/*
+ * release of minidisk device
+ */
+
+static __inline__ int
+mdisk_term_io(mdisk_Dev *dev)
+{
+	mdisk_init_io_t *iob = (mdisk_init_io_t*) dev->iob;
+	
+	memset(iob,0,sizeof(mdisk_init_io_t));
+	
+	iob->dev_nr = dev->vdev;
+	
+	return dia250(iob,TERM_BIO);
+}
+
+/*
+ * setup and start of minidisk io request
+ */
+
+static __inline__ int
+mdisk_rw_io_clustered (mdisk_Dev *dev,
+                       mdisk_bio_t* bio_array,
+                       int length,
+                       int req,
+                       int sync)
+{
+	int rc;
+	mdisk_rw_io_t *iob = dev->iob;
+	
+	iob->dev_nr      = dev->vdev;
+	iob->key         = 0;
+	iob->flags       = sync;
+	
+	iob->block_count = length;
+	iob->interrupt_params = req;
+	iob->bio_list     = virt_to_phys(bio_array);
+	
+	rc = dia250(iob,RW_BIO);
+	rc = (rc == 8) ? 0 : rc;
+	return rc;
+}
+
+
+/*
+ * this handles a clustered request in success case
+ * all buffers are detach and marked uptodate to the kernel
+ * then CURRENT->bh is set to the last processed but not
+ * update buffer
+ */
+
+static __inline__ void
+mdisk_end_request(int nr_bhs)
+{
+	int i;
+	struct buffer_head *bh;
+	struct request *req;
+
+	if (nr_bhs != 1) {
+		req = CURRENT;
+		bh  = req->bh;
+		
+		for (i=0;i<nr_bhs-1;i++) {
+			req->bh = bh->b_reqnext;
+			bh->b_reqnext = NULL;
+			bh->b_end_io(bh,1);
+			bh = req->bh;			
+		}
+		
+		/*
+		 * set CURRENT to last processed, not marked buffer
+		 */
+		req->buffer = bh->b_data;
+		req->current_nr_sectors = bh->b_size >> 9;
+		CURRENT = req;
+	}
+	end_request(1);
+}
+
+
+
+/*
+ * Block-driver specific functions
+ */
+
+void mdisk_request(void)
+{
+	mdisk_Dev *dev;
+	mdisk_bio_t *bio;
+	struct buffer_head *bh;
+	unsigned int sector, nr, offset;
+	int rc,rw,i;
+
+	i = 0;
+	while(CURRENT) {
+		INIT_REQUEST;
+		
+		/* Check if the minor number is in range */
+		if (DEVICE_NR(CURRENT_DEV) > MDISK_DEVS) {
+			static int count = 0;
+			if (count++ < 5) /* print the message at most five times */
+				printk(KERN_WARNING "mnd: request for minor %d out of range\n",
+				       DEVICE_NR(CURRENT_DEV)  )       ;
+			end_request(0);
+			continue;
+		}
+		
+		/*
+		 * Pointer to device structure, from the static array
+		 */
+		dev = mdisk_devices + DEVICE_NR(CURRENT_DEV);
+		
+		/*
+		 * check, if operation is past end of devices
+		 */
+		if (CURRENT->nr_sectors + CURRENT->sector > dev->size) {
+			static int count = 0;
+			if (count++ < 5)
+				printk(KERN_WARNING "mnd%c: request past end of device\n",
+				       DEVICE_NR(CURRENT_DEV));
+			end_request(0);
+			continue;
+		}
+		
+		/*
+		 * do command (read or write)
+		 */
+		switch(CURRENT->cmd) {
+		case READ:
+			rw = MDISK_READ_REQ;
+			break;
+		case WRITE:
+			rw = MDISK_WRITE_REQ;
+			break;
+		default:
+			/* can't happen */
+			end_request(0);
+			continue;
+		}
+		
+		/*
+		 * put the clustered requests in mdisk_bio array
+		 * nr_sectors is checked against max_sectors in make_request
+		 * nr_sectors and sector are always blocks of 512 
+		 * but bh_size depends on the filesystems size
+		 */
+		sector = CURRENT->sector>>dev->blkshift;
+		bh     = CURRENT->bh;
+		bio    = dev->bio;
+		dev->nr_bhs = 0;
+		
+		/*
+		 * sector is translated to block in minidisk context
+		 * 
+		 */
+		offset = 0;
+
+
+		
+		for (nr = 0,i = 0; 
+		     nr < CURRENT->nr_sectors && bh;
+		     nr+=dev->blkmult, sector++,i++) {
+			memset(&bio[i], 0, sizeof(mdisk_bio_t));
+			bio[i].type   = rw;
+			bio[i].block_number = sector;
+			bio[i].buffer  = virt_to_phys(bh->b_data+offset);
+			offset += dev->blksize;
+			if (bh->b_size <= offset) {
+				offset = 0;
+				bh = bh->b_reqnext;
+				dev->nr_bhs++;
+			}
+		}
+
+		if (( rc = mdisk_rw_io_clustered(dev, &bio[0], i,
+						 (unsigned long) dev,
+#ifdef CONFIG_MDISK_SYNC
+						 MDISK_SYNC
+#else
+						 MDISK_ASYNC
+#endif
+			)) != 0 ) {
+			printk(KERN_WARNING "mnd%c: %s request failed rc %d"
+			       " sector %ld nr_sectors %ld \n",
+			       DEVICE_NR(CURRENT_DEV),
+			       rw == MDISK_READ_REQ ? "read" : "write",
+			       rc, CURRENT->sector, CURRENT->nr_sectors);
+			end_request(0);
+			continue;
+		}
+		i = 0;		
+		/*
+		 * Synchron: looping to end of request (INIT_REQUEST has return)
+		 * Asynchron: end_request done in bottom half
+		 */
+#ifdef CONFIG_MDISK_SYNC
+		mdisk_end_request(dev->nr_bhs);
+#else
+		return;
+#endif	
+	}
+}
+
+
+/*
+ * mdisk interrupt handler called when read/write request finished
+ * queues and marks a bottom half.
+ *
+ */
+void do_mdisk_interrupt(void)
+{
+        u16 code;
+	mdisk_Dev *dev;
+	
+	code = S390_lowcore.cpu_addr;
+
+	if ((code >> 8) != 0x03) {
+	  printk("mnd: wrong sub-interruption code %d",code>>8);
+	  return;
+	}
+
+	/*
+	 * pointer to devives structure given as external interruption
+	 * parameter
+	 */
+	dev = (mdisk_Dev*) S390_lowcore.ext_params;
+	dev->status = code & 0x00ff;
+
+	queue_task(&dev->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+/*
+ * the bottom half checks the status of request
+ * on success it calls end_request and calls mdisk_request
+ * if more transfer to do
+ */
+
+static void
+do_mdisk_bh(void *data)
+{
+	mdisk_Dev *dev = (mdisk_Dev*) data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	/*
+	 * check for status of asynchronous rw
+	 */
+	if (dev->status != 0x00) {
+		printk("mnd: status of async rw %d",dev->status);
+		end_request(0);
+	} else {
+		/*
+		 * end request for clustered requests
+		 */
+		mdisk_end_request(dev->nr_bhs);
+	}
+
+	/*
+	 * if more to do, call mdisk_request
+	 */
+	if (CURRENT)
+		mdisk_request();
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+void /* Added fuction HSM 12/03/99 */
+mdisk_handler (int cpu, void *ds, struct pt_regs *regs)
+{
+	printk (KERN_ERR "mnd: received I/O interrupt... shouldn't happen\n");
+}
+
+__initfunc(int mdisk_init(void))
+{
+        int rc,i;
+        mdisk_Dev *dev;
+	
+	/*
+	 * register block device
+	 */
+	if (register_blkdev(MAJOR_NR,"mnd",&mdisk_fops) < 0) {
+		printk("mnd: unable to get major %d for mini disk\n"
+		       ,MAJOR_NR);
+		return MAJOR_NR;
+	}
+	
+	/*
+	 * setup global major dependend structures
+	 */
+	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+
+	/*
+	 * setup sizes for available devices
+	 */
+	read_ahead[MAJOR_NR] = MDISK_RAHEAD;	/* 8 sector (4kB) read-ahead */
+	blk_size[MAJOR_NR] = mdisk_sizes;       /* size of reserved mdisk    */
+	blksize_size[MAJOR_NR] = mdisk_blksizes;   /* blksize of device      */
+	hardsect_size[MAJOR_NR] = mdisk_hardsects;
+	max_sectors[MAJOR_NR]   = mdisk_maxsectors;
+	
+	for (i=0;i<MDISK_DEVS;i++) {
+		mdisk_sizes[i] = mdisk_setup_data.size[i];
+		if (mdisk_sizes[i] == 0) {
+			continue;
+		}
+		/* Added block HSM 12/03/99 */
+		if ( request_irq(get_irq_by_devno(mdisk_setup_data.vdev[i]),
+				 mdisk_handler, 0, "mnd",
+				 &(mdisk_devices[i].dev_status)) ){
+			printk ( KERN_WARNING "mnd: Cannot acquire I/O irq of"
+				 " %4X for paranoia reasons, skipping\n",
+				 mdisk_setup_data.vdev[i]);
+			continue;
+		}
+		/*
+		 * open VM minidisk low level device
+		 */
+		dev = &mdisk_devices[i];
+		dev->bio=mdisk_bio[i];
+		dev->iob=&mdisk_iob[i];
+		dev->vdev = mdisk_setup_data.vdev[i];
+		dev->size = mdisk_setup_data.size[i] * 2; /* buffer 512 b */
+		dev->blksize = mdisk_setup_data.blksize[i]; 
+		dev->tqueue.routine = do_mdisk_bh;
+		dev->tqueue.data = dev;
+		dev->blkmult = dev->blksize/512;
+		dev->blkshift = 
+		  dev->blkmult==1?0:
+		  dev->blkmult==2?1:
+		  dev->blkmult==4?2:
+		  dev->blkmult==8?3:-1;
+
+		mdisk_blksizes[i]  = mdisk_setup_data.blksize[i];
+		mdisk_hardsects[i] = mdisk_setup_data.blksize[i];
+
+		/*
+		 * max sectors for one clustered req  
+		 */
+		mdisk_maxsectors[i] = MDISK_MAXSECTORS*dev->blkmult;
+
+		rc = mdisk_init_io(dev,
+				   mdisk_setup_data.blksize[i],
+				   mdisk_setup_data.offset[i],/* offset in vdev*/
+				   dev->size>>dev->blkshift  /* size in blocks */
+			);
+		if (rc > 4) {
+			printk("mnd%c: init failed (rc: %d)\n",'a'+i,rc);
+			mdisk_sizes[i] = 0;
+			continue;
+		}
+		
+		/*
+		 * set vdev in device structure for further rw access
+		 * vdev and size given by linload
+		 */
+		printk("mnd%c: register device at major %X with %d blocks %d blksize \n",
+		       'a' + i, MAJOR_NR, dev->size>>dev->blkshift,dev->blkmult*512);
+	}
+	
+	/*
+	 * enable service-signal external interruptions,
+	 * Control Register 0 bit 22 := 1
+	 * (besides PSW bit 7 must be set to 1 somewhere for external
+	 * interruptions)
+	 */
+        ctl_set_bit(0, 9);
+	
+        return 0;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/block/mdisk.h linux.14p16/drivers/s390/block/mdisk.h
--- linux.vanilla/drivers/s390/block/mdisk.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/block/mdisk.h	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,71 @@
+/*
+ *  drivers/s390/block/mdisk.h
+ *    VM minidisk device driver.
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Hartmut Penner (hp@de.ibm.com)
+ */
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define MDISK_DEVS 4                   /* for disks                        */
+#define MDISK_RAHEAD 8                 /* read ahead                       */
+#define MDISK_BLKSIZE 1024             /* 1k blocks                        */
+#define MDISK_HARDSECT 512             /* FIXME -- 512 byte blocks         */
+#define MDISK_MAXSECTORS 256           /* max sectors for one request      */
+
+
+
+/* 
+ * low level io defines for diagnose 250
+ */
+
+#define MDISK_WRITE_REQ 0x01                                                 
+#define MDISK_READ_REQ  0x02                                                   
+
+#define MDISK_SYNC      0x01
+#define MDISK_ASYNC     0x03
+#define INIT_BIO        0x00
+#define RW_BIO          0x01
+#define TERM_BIO        0x02
+
+/*
+ * This stucture is used for clustered request
+ * up to 256 different request can be handled with one invocation
+ */
+
+typedef struct {
+        u8      type;
+        u8      status;
+        u16     spare1;
+        u32     block_number;
+        u32     alet;
+        u32     buffer;
+} mdisk_bio_t;
+
+typedef struct {
+        u16     dev_nr;
+        u16     spare1[11];
+        u32     block_size;
+        u32     offset;
+        u32     start_block;
+        u32     end_block;
+        u32     spare2[6];
+} mdisk_init_io_t;
+ 
+typedef struct {
+        u16     dev_nr;
+        u16     spare1[11];
+        u8      key;
+        u8      flags;
+        u16     spare2;
+        u32     block_count;
+        u32     alet;
+        u32     bio_list;
+        u32     interrupt_params;
+        u32     spare3[5];
+} mdisk_rw_io_t;
+
+                                                                               
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/char/Makefile linux.14p16/drivers/s390/char/Makefile
--- linux.vanilla/drivers/s390/char/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/char/Makefile	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,16 @@
+all: s390-char.o
+
+CFLAFS += 
+O_TARGET := s390-char.o
+O_OBJS    :=         
+M_OBJS   :=
+
+ifeq ($(CONFIG_3215_CONSOLE),y)
+  O_OBJS += con3215.o
+endif
+
+ifeq ($(CONFIG_HWC),y)
+  O_OBJS += hwc_con.o hwc_rw.o hwc_tty.o
+endif
+
+include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/char/con3215.c linux.14p16/drivers/s390/char/con3215.c
--- linux.vanilla/drivers/s390/char/con3215.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/char/con3215.c	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,1106 @@
+/*
+ *  drivers/s390/char/con3215.c
+ *    3215 line mode terminal driver.
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+#include <linux/tty.h>
+#include <linux/vt_kern.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/interrupt.h>
+
+#include <linux/malloc.h>
+#include <asm/io.h>
+#include <asm/ebcdic.h>
+#include <asm/uaccess.h>
+
+#include "../../../arch/s390/kernel/cpcmd.h"
+#include "../../../arch/s390/kernel/irq.h"
+
+#define NR_3215		    1
+#define NR_3215_REQ	    (4*NR_3215)
+#define RAW3215_BUFFER_SIZE 65536     /* output buffer size */
+#define RAW3215_INBUF_SIZE  256	      /* input buffer size */
+#define RAW3215_MIN_SPACE   128	      /* minimum free space for wakeup */
+#define RAW3215_MIN_WRITE   1024      /* min. length for immediate output */
+#define RAW3215_MAX_CCWLEN  3968      /* max. bytes to write with one ccw */
+#define RAW3215_NR_CCWS	    ((RAW3215_BUFFER_SIZE/RAW3215_MAX_CCWLEN)+2)
+#define RAW3215_TIMEOUT	    HZ/10     /* time for delayed output */
+
+#define RAW3215_FIXED	    1	      /* 3215 console device is not be freed */
+#define RAW3215_ACTIVE	    2	      /* set if the device is in use */
+#define RAW3215_WORKING	    4	      /* set if a request is being worked on */
+#define RAW3215_THROTTLED   8	      /* set if reading is disabled */
+#define RAW3215_STOPPED	    16	      /* set if writing is disabled */
+#define RAW3215_CLOSING	    32	      /* set while in close process */
+#define RAW3215_TIMER_RUNS  64	      /* set if the output delay timer is on */
+#define RAW3215_FLUSHING    128	      /* set to flush buffer (no delay) */
+
+struct _raw3215_info;		      /* forward declaration ... */
+
+/*
+ * Request types for a 3215 device
+ */
+typedef enum {
+	RAW3215_READ, RAW3215_WRITE
+} raw3215_type;
+
+/*
+ * Request structure for a 3215 device
+ */
+typedef struct _raw3215_req {
+	raw3215_type type;	      /* type of the request */
+	int start, end;		      /* start/end index into output buffer */
+	int residual;		      /* residual count for read request */
+	ccw1_t ccws[RAW3215_NR_CCWS]; /* space for the channel program */
+	struct _raw3215_info *info;   /* pointer to main structure */
+	struct _raw3215_req *next;    /* pointer to next request */
+} raw3215_req  __attribute__ ((aligned(8)));
+
+typedef struct _raw3215_info {
+	int flags;		      /* state flags */
+	int irq;		      /* interrupt number to do_IO */
+	char *buffer;		      /* pointer to output buffer */
+	char *inbuf;		      /* pointer to input buffer */
+	int head;		      /* first free byte in output buffer */
+	int count;		      /* number of bytes in output buffer */
+	devstat_t devstat;	      /* device status structure for do_IO */
+	struct tty_struct *tty;	      /* pointer to tty structure if present */
+	struct tq_struct tqueue;      /* task queue to bottom half */
+	raw3215_req *queued_read;     /* pointer to queued read requests */
+	raw3215_req *queued_write;    /* pointer to queued write requests */
+	struct wait_queue *empty_wait;/* wait queue for flushing */
+	struct timer_list timer;      /* timer for delayed output */
+	char *message;                /* pending message from raw3215_irq */
+	int msg_dstat;                /* dstat for pending message */
+	int msg_cstat;                /* cstat for pending message */
+} raw3215_info;
+
+static raw3215_info *raw3215[NR_3215];	/* array of 3215 devices structures */
+static raw3215_req *raw3215_freelist;	/* list of free request structures */
+static spinlock_t raw3215_freelist_lock;/* spinlock to protect free list */
+
+static struct tty_driver tty3215_driver;
+static struct tty_struct *tty3215_table[NR_3215];
+static struct termios *tty3215_termios[NR_3215];
+static struct termios *tty3215_termios_locked[NR_3215];
+static int tty3215_refcount;
+
+#ifndef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * Get a request structure from the free list
+ */
+extern inline raw3215_req *raw3215_alloc_req(void) {
+	raw3215_req *req;
+	unsigned long flags;
+
+	spin_lock_irqsave(&raw3215_freelist_lock, flags);
+	req = raw3215_freelist;
+	raw3215_freelist = req->next;
+	spin_unlock_irqrestore(&raw3215_freelist_lock, flags);
+	return req;
+}
+
+/*
+ * Put a request structure back to the free list
+ */
+extern inline void raw3215_free_req(raw3215_req *req) {
+	unsigned long flags;
+
+	spin_lock_irqsave(&raw3215_freelist_lock, flags);
+	req->next = raw3215_freelist;
+	raw3215_freelist = req;
+	spin_unlock_irqrestore(&raw3215_freelist_lock, flags);
+}
+
+/*
+ * Get a write request structure. That is either a new or the last
+ * queued write request. The request structure is set up in 
+ * raw3215_mk_write_ccw.
+ */
+static raw3215_req *raw3215_mk_write_req(raw3215_info *raw)
+{
+	raw3215_req *req;
+
+	/* check if there is a queued write request */
+	req = raw->queued_write;
+	if (req == NULL) {
+		/* no queued write request, use new req structure */
+		req = raw3215_alloc_req();
+		req->type = RAW3215_WRITE;
+		req->info = raw;
+		req->start = raw->head;
+	} else
+		raw->queued_write = NULL;
+	return req;
+}
+
+/*
+ * Get a read request structure. If there is a queued read request
+ * it is used, but that shouldn't happen because a 3215 terminal
+ * won't accept a new read before the old one is completed.
+ */
+static raw3215_req *raw3215_mk_read_req(raw3215_info *raw)
+{
+	raw3215_req *req;
+
+	/* there can only be ONE read request at a time */
+	req = raw->queued_read;
+	if (req == NULL) {
+		/* no queued read request, use new req structure */
+		req = raw3215_alloc_req();
+		req->type = RAW3215_READ;
+		req->info = raw;
+	} else
+		raw->queued_read = NULL;
+	return req;
+}
+
+/*
+ * Set up a write request with the information from the main structure.
+ * A ccw chain is created that writes everything in the output buffer
+ * to the 3215 device.
+ */
+static int raw3215_mk_write_ccw(raw3215_info *raw, raw3215_req *req)
+{
+	ccw1_t *ccw;
+	int len, count, ix;
+
+	ccw = req->ccws;
+	req->end = (raw->head - 1) & (RAW3215_BUFFER_SIZE - 1);
+	len = ((req->end - req->start) & (RAW3215_BUFFER_SIZE - 1)) + 1;
+	ix = req->start;
+	while (len > 0) {
+		if (ccw > req->ccws)
+			ccw[-1].flags |= 0x40; /* use command chaining */
+		ccw->cmd_code = 0x01; /* write, auto carrier return */
+		ccw->flags = 0x20;    /* ignore incorrect length ind.  */
+		ccw->cda =
+			(void *) virt_to_phys(raw->buffer + ix);
+		count = (len > RAW3215_MAX_CCWLEN) ? 
+			RAW3215_MAX_CCWLEN : len;
+		if (ix + count > RAW3215_BUFFER_SIZE)
+			count = RAW3215_BUFFER_SIZE-ix;
+		ccw->count = count;
+		len -= count;
+		ix = (ix + count) & (RAW3215_BUFFER_SIZE - 1);
+		ccw++;
+	}
+	if (ccw > req->ccws)
+		ccw[-1].flags |= 0x40;	/* use command chaining */
+	ccw->cmd_code = 0x03; /* nop at the end */
+	ccw->flags = 0x20;    /* ignore incorrect length */
+	ccw->cda = NULL;      /* no data address for nop */
+	ccw->count = 0;	      /* no count for nop */
+	return len;
+}
+
+/*
+ * Set up a read request that reads up to 160 byte from the 3215 device.
+ */
+static void raw3215_mk_read_ccw(raw3215_info *raw, raw3215_req *req)
+{
+	ccw1_t *ccw;
+
+	ccw = req->ccws;
+	ccw->cmd_code = 0x0A; /* read inquiry */
+	ccw->flags = 0x60;    /* ignore incorrect length & command chaining */
+	ccw->count = 160;
+	ccw->cda = (void *) virt_to_phys(raw->inbuf);
+	ccw++;
+	ccw->cmd_code = 0x03; /* nop at the end */
+	ccw->flags = 0x20;    /* ignore incorrect length ind. */
+	ccw->cda = NULL;      /* no data address for nop */
+	ccw->count = 0;	      /* no count for nop */
+}
+
+/*
+ * Start a read or a write request
+ */
+static void raw3215_start_io(raw3215_info *raw)
+{
+	raw3215_req *req;
+	int res;
+
+	req = raw->queued_read;
+	if (req != NULL &&
+	    !(raw->flags & (RAW3215_WORKING | RAW3215_THROTTLED))) {
+		/* dequeue request */
+		raw->queued_read = NULL;
+		res = do_IO(raw->irq, req->ccws, (__u32) req, 0, 0);
+		if (res != 0) {
+			/* do_IO failed, put request back to queue */
+			raw->queued_read = req;
+		} else {
+			raw->flags |= RAW3215_WORKING;
+		} 
+	}
+	req = raw->queued_write;
+	if (req != NULL &&
+	    !(raw->flags & (RAW3215_WORKING | RAW3215_STOPPED))) {
+		/* dequeue request */
+		raw->queued_write = NULL;
+		res = do_IO(raw->irq, req->ccws, (__u32) req, 0, 0);
+		if (res != 0) {
+			/* do_IO failed, put request back to queue */
+			raw->queued_write = req;
+		} else {
+			raw->flags |= RAW3215_WORKING;
+		}
+	}
+}
+
+/*
+ * Function to start a delayed output after RAW3215_TIMEOUT seconds
+ */
+static void raw3215_timeout(unsigned long __data)
+{
+	raw3215_info *raw = (raw3215_info *) __data;
+	unsigned long flags;
+
+	s390irq_spin_lock_irqsave(raw->irq, flags);
+	if (raw->flags & RAW3215_TIMER_RUNS) {
+		del_timer(&raw->timer);
+		raw->flags &= ~RAW3215_TIMER_RUNS;
+		raw3215_start_io(raw);
+	}
+	s390irq_spin_unlock_irqrestore(raw->irq, flags);
+}
+
+/*
+ * Function to conditionally start an IO. A read is started immediatly,
+ * a write is only started immediatly if the flush flag is on or the
+ * amount of data is bigger than RAW3215_MIN_WRITE. If a write is not
+ * done immediatly a timer is started with a delay of RAW3215_TIMEOUT.
+ */
+extern inline void raw3215_try_io(raw3215_info *raw)
+{
+	if (!(raw->flags & RAW3215_ACTIVE))
+		return;
+	if (raw->queued_read != NULL)
+		raw3215_start_io(raw);
+	else if (raw->queued_write != NULL) {
+		if (raw->count >= RAW3215_MIN_WRITE ||
+		    (raw->flags & RAW3215_FLUSHING)) {
+			/* execute write requests bigger than minimum size */
+			raw3215_start_io(raw);
+			if (raw->flags & RAW3215_TIMER_RUNS) {
+				del_timer(&raw->timer);
+				raw->flags &= ~RAW3215_TIMER_RUNS;
+			}
+		} else if (!(raw->flags & RAW3215_TIMER_RUNS)) {
+			/* delay small writes */
+			init_timer(&raw->timer);
+			raw->timer.expires = RAW3215_TIMEOUT + jiffies;
+			raw->timer.data = (unsigned long) raw;
+			raw->timer.function = raw3215_timeout;
+			add_timer(&raw->timer);
+			raw->flags |= RAW3215_TIMER_RUNS;
+		}
+	}
+}
+
+/*
+ * The bottom half handler routine for 3215 devices. It tries to start
+ * the next IO and wakes up processes waiting on the tty.
+ */
+static void raw3215_softint(void *data)
+{
+	raw3215_info *raw;
+	struct tty_struct *tty;
+	unsigned long flags;
+
+	raw = (raw3215_info *) data;
+	s390irq_spin_lock_irqsave(raw->irq, flags);
+	raw3215_try_io((raw3215_info *) data);
+	s390irq_spin_unlock_irqrestore(raw->irq, flags);
+	/* Check for pending message from raw3215_irq */
+	if (raw->message != NULL) {
+		printk(raw->message, raw->irq, raw->msg_dstat, raw->msg_cstat);
+		raw->message = NULL;
+	}
+	tty = raw->tty;
+	if (tty != NULL &&
+	    RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+/*
+ * Find the raw3215_info structure associated with irq
+ */
+static inline raw3215_info *raw3215_find_info(int irq) {
+	raw3215_info *raw;
+	int i;
+
+	for (i = 0; i < NR_3215; i++) {
+		raw = raw3215[i];
+		if (raw != NULL && raw->irq == irq &&
+		    (raw->flags & RAW3215_ACTIVE))
+			break;
+	}
+	return (i >= NR_3215) ? NULL : raw;
+}
+
+/*
+ * Interrupt routine, called from Ingo's I/O layer
+ */
+static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs)
+{
+	raw3215_info *raw;
+	raw3215_req *req;
+	struct tty_struct *tty;
+	devstat_t *stat;
+        int cstat, dstat;
+	int count;
+
+	stat = (devstat_t *) int_parm;
+	req = (raw3215_req *) stat->intparm;
+	cstat = stat->cstat;
+	dstat = stat->dstat;
+	if (cstat != 0) {
+		raw = raw3215_find_info(irq);
+		if (raw != NULL) {
+			raw->message = KERN_WARNING
+				"Got nonzero channel status in raw3215_irq "
+				"(dev %i, dev sts 0x%2x, sch sts 0x%2x)";
+			raw->msg_dstat = dstat;
+			raw->msg_cstat = cstat;
+			queue_task(&raw->tqueue, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
+		}
+	}
+        if (dstat & 0x01) { /* we got a unit exception */
+		raw = raw3215_find_info(irq);
+		if (raw != NULL) {
+                        raw->message = KERN_WARNING
+                                "Got a unit exception in raw3215_irq "
+                                "(dev %i, dev sts 0x%2x, sch sts 0x%2x)";
+                        raw->msg_dstat = dstat;
+                        raw->msg_cstat = cstat;
+                        queue_task(&raw->tqueue, &tq_immediate);
+                        mark_bh(IMMEDIATE_BH);
+		}
+		dstat &= ~0x01;
+        }
+	switch (dstat) {
+	case 0x80:
+		if (cstat != 0)
+			break;
+		/* Attention interrupt, someone hit the enter key */
+		if ((raw = raw3215_find_info(irq)) == NULL)
+			return;              /* That shouldn't happen ... */
+		/* Setup a read request */
+		req = raw3215_mk_read_req(raw);
+		raw3215_mk_read_ccw(raw, req);
+		raw->queued_read = req;
+		queue_task(&raw->tqueue, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+		break;
+	case 0x08:
+	case 0x0C:
+		/* Channel end interrupt. */
+		raw = req->info;
+		if (req->type == RAW3215_READ) {
+			/* store residual count, then wait for device end */
+			req->residual = stat->rescnt;
+		}
+		if (dstat == 0x08)
+			break;
+	case 0x04:
+		/* Device end interrupt. */
+		raw = req->info;
+		if (req->type == RAW3215_READ && raw->tty != NULL) {
+			tty = raw->tty;
+			count = 160 - req->residual;
+			if (count >= TTY_FLIPBUF_SIZE - tty->flip.count)
+				count = TTY_FLIPBUF_SIZE - tty->flip.count - 1;
+			EBCASC(raw->inbuf, count);
+			if (count == 2 &&
+			    strncmp(raw->inbuf, "^c", 2) == 0) {
+				/* emulate a control C = break */
+				tty->flip.count++;
+				*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+				*tty->flip.char_buf_ptr++ = INTR_CHAR(tty);
+				tty_flip_buffer_push(raw->tty);
+			} else if (count == 2 &&
+				   strncmp(raw->inbuf, "^d", 2) == 0) {
+				/* emulate a control D = end of file */
+				tty->flip.count++;
+				*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+				*tty->flip.char_buf_ptr++ = EOF_CHAR(tty);
+				tty_flip_buffer_push(raw->tty);
+			} else if (count == 2 &&
+				   strncmp(raw->inbuf, "^z", 2) == 0) {
+				/* emulate a control Z = suspend */
+				tty->flip.count++;
+				*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+				*tty->flip.char_buf_ptr++ = SUSP_CHAR(tty);
+				tty_flip_buffer_push(raw->tty);
+			} else {
+				memcpy(tty->flip.char_buf_ptr,
+				       raw->inbuf, count);
+				if (count < 2 ||
+				    strncmp(raw->inbuf+count-2, "^n", 2)) {
+					/* don't add the auto \n */
+					tty->flip.char_buf_ptr[count] = '\n';
+					memset(tty->flip.flag_buf_ptr,
+					       TTY_NORMAL, count + 1);
+					count++;
+				} else
+					count-=2;
+				tty->flip.char_buf_ptr += count;
+				tty->flip.flag_buf_ptr += count;
+				tty->flip.count += count;
+				tty_flip_buffer_push(raw->tty);
+			}
+		} else if (req->type == RAW3215_WRITE) {
+			raw->count -= ((req->end - req->start) &
+				       (RAW3215_BUFFER_SIZE - 1)) + 1;
+		}
+		raw->flags &= ~RAW3215_WORKING;
+		raw3215_free_req(req);
+		/* check for empty wait */
+		if (raw->empty_wait != NULL &&
+		    raw->queued_write == NULL &&
+		    raw->queued_read == NULL) {
+			wake_up_interruptible(&raw->empty_wait);
+			raw->empty_wait = NULL;
+		}
+		queue_task(&raw->tqueue, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+		break;
+	default:
+		if (dstat & 0x04) {
+			/* Strange interrupt, I'll do my best to clean up */
+			if (req != NULL && req->info != NULL &&
+			    req->type == RAW3215_WRITE) {
+				req->info->count -= ((req->end - req->start) &
+					            (RAW3215_BUFFER_SIZE-1))+1;
+			}
+		}
+		raw = raw3215_find_info(irq);
+		if (raw != NULL) {
+			raw->message = KERN_WARNING
+				"Spurious interrupt in in raw3215_irq "
+				"(dev %i, dev sts 0x%2x, sch sts 0x%2x)";
+			raw->msg_dstat = dstat;
+			raw->msg_cstat = cstat;
+			queue_task(&raw->tqueue, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
+		}
+	}
+	return;
+}
+
+/*
+ * String write routine for 3215 devices
+ */
+static int
+raw3215_write(raw3215_info *raw, const char *str,
+	      int from_user, unsigned int length)
+{
+	raw3215_req *req;
+	unsigned long flags;
+	int ret, c;
+	int count;
+	
+	ret = 0;
+	while (length > 0) {
+		s390irq_spin_lock_irqsave(raw->irq, flags);
+		count = (length > RAW3215_BUFFER_SIZE) ?
+					     RAW3215_BUFFER_SIZE : length;
+		length -= count;
+
+		while (RAW3215_BUFFER_SIZE - raw->count < count) {
+			/* there might be a request pending */
+			raw3215_try_io(raw);
+			if (wait_cons_dev(raw->irq) != 0) {
+				/* that shouldn't happen */
+				raw->count = 0;
+			} 
+		}
+
+		req = raw3215_mk_write_req(raw);
+		/* copy string to output buffer and convert it to EBCDIC */
+		if (from_user) {
+			while (1) {
+				c = MIN(count,
+					MIN(RAW3215_BUFFER_SIZE - raw->count,
+					    RAW3215_BUFFER_SIZE - raw->head));
+				if (c <= 0)
+					break;
+				c -= copy_from_user(raw->buffer + raw->head,
+						    str, c);
+				if (c == 0) {
+					if (!ret)
+						ret = -EFAULT;
+					break;
+				}
+				ASCEBC(raw->buffer + raw->head, c);
+				raw->head = (raw->head + c) &
+					    (RAW3215_BUFFER_SIZE - 1);
+				raw->count += c;
+				str += c;
+				count -= c;
+				ret += c;
+			}
+		} else {
+			while (1) {
+				c = MIN(count,
+					MIN(RAW3215_BUFFER_SIZE - raw->count,
+					    RAW3215_BUFFER_SIZE - raw->head));
+				if (c <= 0)
+					break;
+				memcpy(raw->buffer + raw->head, str, c);
+				ASCEBC(raw->buffer + raw->head, c);
+				raw->head = (raw->head + c) &
+					    (RAW3215_BUFFER_SIZE - 1);
+				raw->count += c;
+				str += c;
+				count -= c;
+				ret += c;
+			}
+		}
+		raw3215_mk_write_ccw(raw, req);
+		raw->queued_write = req;
+		/* start or queue request */
+		raw3215_try_io(raw);
+		s390irq_spin_unlock_irqrestore(raw->irq, flags);
+
+	}
+
+	return ret;
+}
+
+/*
+ * Put character routine for 3215 devices
+ */
+static void raw3215_putchar(raw3215_info *raw, unsigned char ch)
+{
+	raw3215_req *req;
+	unsigned long flags;
+
+	s390irq_spin_lock_irqsave(raw->irq, flags);
+	while (RAW3215_BUFFER_SIZE - raw->count < 1) {
+		/* there might be a request pending */
+		raw3215_try_io(raw);
+		if (wait_cons_dev(raw->irq) != 0) {
+			/* that shouldn't happen */
+			raw->count = 0;
+		}
+	}
+
+	req = raw3215_mk_write_req(raw);
+	raw->buffer[raw->head] = (char) _ascebc[(int) ch];
+	raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1);
+	raw->count++;
+	raw3215_mk_write_ccw(raw, req);
+	raw->queued_write = req;
+	/* start or queue request */
+	raw3215_try_io(raw);
+	s390irq_spin_unlock_irqrestore(raw->irq, flags);
+}
+
+/*
+ * Flush routine, it simply sets the flush flag and tries to start 
+ * pending IO.
+ */
+static void raw3215_flush_buffer(raw3215_info *raw)
+{
+	unsigned long flags;
+
+	s390irq_spin_lock_irqsave(raw->irq, flags);
+	if (raw->count > 0) {
+		raw->flags |= RAW3215_FLUSHING;
+		raw3215_try_io(raw);
+		raw->flags &= ~RAW3215_FLUSHING;
+	}
+	s390irq_spin_unlock_irqrestore(raw->irq, flags);
+}
+
+/*
+ * Fire up a 3215 device.
+ */
+static int raw3215_startup(raw3215_info *raw)
+{
+	unsigned long flags;
+
+	if (raw->flags & RAW3215_ACTIVE)
+		return 0;
+	if (request_irq(raw->irq, raw3215_irq, SA_INTERRUPT,
+			"3215 terminal driver", &raw->devstat) != 0)
+		return -1;
+	raw->flags |= RAW3215_ACTIVE;
+	s390irq_spin_lock_irqsave(raw->irq, flags);
+	raw3215_try_io(raw);
+	s390irq_spin_unlock_irqrestore(raw->irq, flags);
+
+	return 0;	
+}
+
+/*
+ * Shutdown a 3215 device.
+ */
+static void raw3215_shutdown(raw3215_info *raw)
+{
+	struct wait_queue wait = { current, NULL };
+	unsigned long flags;
+
+	if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FIXED))
+		return;
+	/* Wait for outstanding requests, then free irq */
+	s390irq_spin_lock_irqsave(raw->irq, flags);
+	if ((raw->flags & RAW3215_WORKING) ||
+	    raw->queued_write != NULL ||
+	    raw->queued_read != NULL) {
+		raw->flags |= RAW3215_CLOSING;
+		add_wait_queue(&raw->empty_wait, &wait);
+		current->state = TASK_INTERRUPTIBLE;
+                s390irq_spin_unlock_irqrestore(raw->irq, flags);
+		schedule();
+		s390irq_spin_lock_irqsave(raw->irq, flags);
+                current->state = TASK_RUNNING;
+		raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING);
+	}
+	free_irq(raw->irq, NULL);
+	s390irq_spin_unlock_irqrestore(raw->irq, flags);
+}
+
+static int
+raw3215_find_dev(int number)
+{
+	dev_info_t dinfo;
+	int irq;
+	int count;
+
+	irq = 0;
+	count = 0;
+	while (count <= number && get_dev_info(irq, &dinfo) != -ENODEV) {
+		if (dinfo.sid_data.cu_type == 0x3215)
+			count++;
+		irq++;
+	}
+	if (count <= number)
+		irq = -1;     /* console not found */
+	else
+		irq--;
+	return irq;
+}
+
+#ifdef CONFIG_3215_CONSOLE
+
+/*
+ * Try to request the console IRQ. Called from init/main.c
+ */
+int con3215_activate(void)
+{
+	raw3215_info *raw;
+
+        if (!MACHINE_IS_VM)
+                return 0;
+	raw = raw3215[0];  /* 3215 console is the first one */
+	if (raw->irq == -1) /* now console device found in con3215_init */
+		return -1;
+	return raw3215_startup(raw);
+}
+
+/*
+ * Write a string to the 3215 console
+ */
+static void
+con3215_write(struct console *co, const char *str, unsigned int count)
+{
+	raw3215_info *raw;
+
+	if (count <= 0)
+		return;
+	raw = raw3215[0];  /* console 3215 is the first one */
+	raw3215_write(raw, str, 0, count);
+}
+
+kdev_t con3215_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, c->index);
+}
+
+/*
+ * panic() calls console_unblank before the system enters a
+ * disabled, endless loop.
+ */
+void con3215_unblank(void)
+{
+	raw3215_info *raw;
+	unsigned long flags;
+
+	raw = raw3215[0];  /* console 3215 is the first one */
+	s390irq_spin_lock_irqsave(raw->irq, flags);
+	while (RAW3215_BUFFER_SIZE > raw->count) {
+		/* there might be a request pending */
+		raw->flags |= RAW3215_FLUSHING;
+		raw3215_try_io(raw);
+		if (wait_cons_dev(raw->irq) != 0) {
+			/* that shouldn't happen */
+			raw->count = 0;
+		}
+		raw->flags &= ~RAW3215_FLUSHING;
+	}
+	s390irq_spin_unlock_irqrestore(raw->irq, flags);
+}
+
+__initfunc(static int con3215_setup(struct console *co, char *options))
+{
+	return 0;
+}
+
+/*
+ *  The console structure for the 3215 console
+ */
+static struct console con3215 = {
+	"tty3215",
+	con3215_write,
+	NULL,
+	con3215_device,
+	NULL,
+	con3215_unblank,
+	con3215_setup,
+	CON_PRINTBUFFER,
+	0,
+	0,
+	NULL
+};
+
+#endif
+
+/*
+ * tty3215_open
+ *
+ * This routine is called whenever a 3215 tty is opened.
+ */
+static int tty3215_open(struct tty_struct *tty, struct file * filp)
+{
+	raw3215_info *raw;
+	int retval, line;
+
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_3215))
+		return -ENODEV;
+
+	raw = raw3215[line];
+	if (raw == NULL) {
+		raw = kmalloc(sizeof(raw3215_info) +
+			      RAW3215_INBUF_SIZE, GFP_KERNEL);
+		if (raw == NULL)
+			return -ENOMEM;
+		raw->irq = raw3215_find_dev(line);
+		if (raw->irq == -1) {
+			kfree(raw);
+			return -ENODEV;
+		}
+		raw->inbuf = (char *) raw + sizeof(raw3215_info);
+		memset(raw, 0, sizeof(raw3215_info));
+		raw->buffer = (char *) kmalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL);
+		if (raw->buffer == NULL) {
+			kfree_s(raw, sizeof(raw3215_info));
+			return -ENOMEM;
+		}
+		raw->tqueue.routine = raw3215_softint;
+		raw->tqueue.data = raw;
+		raw3215[line] = raw;
+	}
+
+	tty->driver_data = raw;
+	raw->tty = tty;
+
+	tty->low_latency = 0;  /* don't use bottom half for pushing chars */
+	/*
+	 * Start up 3215 device
+	 */
+	retval = raw3215_startup(raw);
+	if (retval)
+		return retval;
+
+	return 0;
+}
+
+/*
+ * tty3215_close()
+ *
+ * This routine is called when the 3215 tty is closed. We wait
+ * for the remaining request to be completed. Then we clean up.
+ */
+static void tty3215_close(struct tty_struct *tty, struct file * filp)
+{
+	raw3215_info *raw;
+
+	raw = (raw3215_info *) tty->driver_data;
+	if (raw == NULL || tty->count > 1)
+		return;
+	tty->closing = 1;
+	/* Shutdown the terminal */
+	raw3215_shutdown(raw);
+	tty->closing = 0;
+	raw->tty = NULL;
+}
+
+/*
+ * Returns the amount of free space in the output buffer.
+ */
+static int tty3215_write_room(struct tty_struct *tty)
+{
+	raw3215_info *raw;
+				
+	raw = (raw3215_info *) tty->driver_data;
+	return RAW3215_BUFFER_SIZE - raw->count;
+}
+
+/*
+ * String write routine for 3215 ttys
+ */
+static int tty3215_write(struct tty_struct * tty, int from_user,
+		    const unsigned char *buf, int count)
+{
+	raw3215_info *raw;
+	int ret;
+				
+	if (!tty)
+		return 0;
+	raw = (raw3215_info *) tty->driver_data;
+	ret = raw3215_write(raw, buf, from_user, count);
+	return ret;
+}
+
+/*
+ * Put character routine for 3215 ttys
+ */
+static void tty3215_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	raw3215_info *raw;
+
+	if (!tty)
+		return;
+	raw = (raw3215_info *) tty->driver_data;
+	raw3215_putchar(raw, ch);
+}
+
+static void tty3215_flush_chars(struct tty_struct *tty)
+{
+}
+
+/*
+ * Returns the number of characters in the output buffer
+ */
+static int tty3215_chars_in_buffer(struct tty_struct *tty)
+{
+	raw3215_info *raw;
+
+	raw = (raw3215_info *) tty->driver_data;
+	return raw->count;
+}
+
+static void tty3215_flush_buffer(struct tty_struct *tty)
+{
+	raw3215_info *raw;
+
+	raw = (raw3215_info *) tty->driver_data;
+	raw3215_flush_buffer(raw);
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * Currently we don't have any io controls for 3215 ttys
+ */
+static int tty3215_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
+
+	switch (cmd) {
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+/*
+ * Disable reading from a 3215 tty
+ */
+static void tty3215_throttle(struct tty_struct * tty)
+{
+	raw3215_info *raw;
+
+	raw = (raw3215_info *) tty->driver_data;
+	raw->flags |= RAW3215_THROTTLED;
+}
+
+/*
+ * Enable reading from a 3215 tty
+ */
+static void tty3215_unthrottle(struct tty_struct * tty)
+{
+	raw3215_info *raw;
+	unsigned long flags;
+
+	raw = (raw3215_info *) tty->driver_data;
+	if (raw->flags & RAW3215_THROTTLED) {
+		s390irq_spin_lock_irqsave(raw->irq, flags);
+		raw->flags &= ~RAW3215_THROTTLED;
+		raw3215_try_io(raw);
+		s390irq_spin_unlock_irqrestore(raw->irq, flags);
+	}
+}
+
+/*
+ * Disable writing to a 3215 tty
+ */
+static void tty3215_stop(struct tty_struct *tty)
+{
+	raw3215_info *raw;
+
+	raw = (raw3215_info *) tty->driver_data;
+	raw->flags |= RAW3215_STOPPED;
+}
+
+/*
+ * Enable writing to a 3215 tty
+ */
+static void tty3215_start(struct tty_struct *tty)
+{
+	raw3215_info *raw;
+	unsigned long flags;
+
+	raw = (raw3215_info *) tty->driver_data;
+	if (raw->flags & RAW3215_STOPPED) {
+		s390irq_spin_lock_irqsave(raw->irq, flags);
+		raw->flags &= ~RAW3215_STOPPED;
+		raw3215_try_io(raw);
+		s390irq_spin_unlock_irqrestore(raw->irq, flags);
+	}
+}
+
+/*
+ * 3215 console driver boottime initialization code.
+ * Register console. We can't request the IRQ here, because
+ * it's too early (kmalloc isn't working yet). We'll have to
+ * buffer all the console requests until we can request the
+ * irq. For this purpose we use some pages of fixed memory.
+ */
+__initfunc (long con3215_init(long kmem_start, long kmem_end))
+{
+	raw3215_info *raw;
+	raw3215_req *req;
+	int i;
+
+	if (!MACHINE_IS_VM)
+                return kmem_start;
+	cpcmd("TERM CONMODE 3215", NULL, 0);
+	cpcmd("TERM AUTOCR OFF", NULL, 0);
+	cpcmd("TERM HOLD OFF", NULL, 0);
+	cpcmd("TERM MORE 5 5", NULL, 0);
+
+	kmem_start = (kmem_start + 7) & -8L;
+
+	/* allocate 3215 request structures */
+	raw3215_freelist = NULL;
+	spin_lock_init(&raw3215_freelist_lock);
+	for (i = 0; i < NR_3215_REQ; i++) {
+		req = (raw3215_req *) kmem_start;
+		kmem_start += sizeof(raw3215_req);
+		req->next = raw3215_freelist;
+		raw3215_freelist = req;
+	}
+
+#ifdef CONFIG_3215_CONSOLE
+	raw3215[0] = raw = (raw3215_info *) kmem_start;
+	kmem_start += sizeof(raw3215_info);
+	memset(raw, 0, sizeof(raw3215_info));
+	raw->buffer = (char *) kmem_start;
+	kmem_start += RAW3215_BUFFER_SIZE;
+	raw->inbuf = (char *) kmem_start;
+	kmem_start += RAW3215_INBUF_SIZE;
+	/* Find the first console */
+	raw->irq = raw3215_find_dev(0);
+	raw->flags |= RAW3215_FIXED;
+	raw->tqueue.routine = raw3215_softint;
+	raw->tqueue.data = raw;
+
+	if (raw->irq != -1) {
+		register_console(&con3215);
+		s390irq_spin_lock(raw->irq);
+		set_cons_dev(raw->irq);
+		s390irq_spin_unlock(raw->irq);
+	} else {
+		kmem_start = (long) raw;
+		raw3215[0] = NULL;
+		printk("Couldn't find a 3215 console device\n");
+	}
+#endif
+
+	/*
+	 * Initialize the tty_driver structure
+	 * Entries in tty3215_driver that are NOT initialized:
+	 * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
+	 */
+
+	memset(&tty3215_driver, 0, sizeof(struct tty_driver));
+	tty3215_driver.magic = TTY_DRIVER_MAGIC;
+	tty3215_driver.driver_name = "tty3215";
+	tty3215_driver.name = "ttyS";
+	tty3215_driver.name_base = 0;
+	tty3215_driver.major = TTY_MAJOR;
+	tty3215_driver.minor_start = 64;
+	tty3215_driver.num = NR_3215;
+	tty3215_driver.type = TTY_DRIVER_TYPE_SYSTEM;
+	tty3215_driver.subtype = SYSTEM_TYPE_TTY;
+	tty3215_driver.init_termios = tty_std_termios;
+	tty3215_driver.init_termios.c_iflag = IGNBRK | IGNPAR;
+	tty3215_driver.init_termios.c_oflag = ONLCR;
+	tty3215_driver.init_termios.c_lflag = ISIG;
+	tty3215_driver.flags = TTY_DRIVER_REAL_RAW;
+	tty3215_driver.refcount = &tty3215_refcount;
+	tty3215_driver.table = tty3215_table;
+	tty3215_driver.termios = tty3215_termios;
+	tty3215_driver.termios_locked = tty3215_termios_locked;
+
+	tty3215_driver.open = tty3215_open;
+	tty3215_driver.close = tty3215_close;
+	tty3215_driver.write = tty3215_write;
+	tty3215_driver.put_char = tty3215_put_char;
+	tty3215_driver.flush_chars = tty3215_flush_chars;
+	tty3215_driver.write_room = tty3215_write_room;
+	tty3215_driver.chars_in_buffer = tty3215_chars_in_buffer;
+	tty3215_driver.flush_buffer = tty3215_flush_buffer;
+	tty3215_driver.ioctl = tty3215_ioctl;
+	tty3215_driver.throttle = tty3215_throttle;
+	tty3215_driver.unthrottle = tty3215_unthrottle;
+	tty3215_driver.send_xchar = NULL;
+	tty3215_driver.set_termios = NULL;
+	tty3215_driver.stop = tty3215_stop;
+	tty3215_driver.start = tty3215_start;
+	tty3215_driver.hangup = NULL;
+	tty3215_driver.break_ctl = NULL;
+	tty3215_driver.wait_until_sent = NULL;
+	tty3215_driver.read_proc = NULL;
+
+	if (tty_register_driver(&tty3215_driver))
+		panic("Couldn't register tty3215 driver\n");
+
+	return kmem_start;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/char/hwc.h linux.14p16/drivers/s390/char/hwc.h
--- linux.vanilla/drivers/s390/char/hwc.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/char/hwc.h	Wed Dec 15 22:49:15 1999
@@ -0,0 +1,228 @@
+/*
+ *  drivers/s390/char/hwc.h
+ *
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ *
+ *
+ *
+ */
+
+#ifndef __HWC_H__
+#define __HWC_H__
+
+
+#define ET_OpCmd		0x01
+#define ET_Msg		0x02
+#define ET_StateChange	0x08
+#define ET_PMsgCmd		0x09
+#define ET_CntlProgOpCmd	0x20
+
+
+#define ET_OpCmd_Mask	0x80000000
+#define ET_Msg_Mask		0x40000000
+#define ET_StateChange_Mask	0x01000000
+#define ET_PMsgCmd_Mask	0x00800000
+#define ET_CtlProgOpCmd_Mask	0x00000001
+
+
+#define GMF_DOM		0x8000
+#define GMF_SndAlrm	0x4000
+#define GMF_HoldMsg	0x2000
+
+
+#define LTF_CntlText	0x8000
+#define LTF_LabelText	0x4000
+#define LTF_DataText	0x2000
+#define LTF_EndText	0x1000
+#define LTF_PromptText	0x0800
+
+
+#define HWC_COMMAND_INITIATED	0
+#define HWC_BUSY		2
+#define HWC_NOT_OPERATIONAL	3
+
+
+#define HWC_CMDW_READDATA 0x00770005
+
+#define HWC_CMDW_WRITEDATA 0x00760005
+
+#define HWC_CMDW_WRITEMASK 0x00780005
+
+
+#define GDS_ID_MDSMU		0x1310
+#define GDS_ID_MDSRouteInfo	0x1311
+#define GDS_ID_AgUnWrkCorr	0x1549
+#define GDS_ID_SNACondReport	0x1532
+#define GDS_ID_CPMSU		0x1212
+#define GDS_ID_RoutTargInstr	0x154D
+#define GDS_ID_OpReq		0x8070
+#define GDS_ID_TextCmd		0x1320
+
+
+#define GDS_KEY_SelfDefTextMsg	0x31
+
+#define _HWCB_HEADER	u16	length; \
+			u8	function_code; \
+			u8	control_mask[3]; \
+			u16	response_code;
+
+#define _EBUF_HEADER 	u16	length; \
+			u8	type; \
+			u8	flags; \
+			u16	_reserved;
+
+typedef struct {
+	_EBUF_HEADER
+} __attribute__((packed))	evbuf_t;
+
+
+
+#define _MDB_HEADER	u16	length; \
+			u16	type; \
+			u32	tag; \
+			u32	revision_code;
+
+#define _GO_HEADER	u16	length; \
+			u16	type; \
+			u32	domid; \
+			u8	hhmmss_time[8]; \
+			u8	th_time[3]; \
+			u8	_reserved_0; \
+			u8	dddyyyy_date[7]; \
+			u8	_reserved_1; \
+			u16	general_msg_flags; \
+			u8	_reserved_2[10]; \
+			u8	originating_system_name[8]; \
+			u8	job_guest_name[8];
+
+#define _MTO_HEADER	u16	length; \
+			u16	type; \
+			u16	line_type_flags; \
+			u8	alarm_control; \
+			u8	_reserved[3];
+
+typedef struct {
+	_GO_HEADER
+} __attribute__((packed))	go_t;
+
+typedef	struct {
+	go_t	go;
+} __attribute__((packed))	mdb_body_t;
+
+typedef struct {
+	_MDB_HEADER
+	mdb_body_t	mdb_body;
+} __attribute__((packed))	mdb_t;
+
+typedef struct {
+	_EBUF_HEADER
+	mdb_t		mdb;
+} __attribute__((packed))	msgbuf_t;
+
+typedef struct {
+	_HWCB_HEADER
+	msgbuf_t	msgbuf;
+} __attribute__((packed))	write_hwcb_t;
+
+typedef struct {
+	_MTO_HEADER
+} __attribute__((packed))	mto_t;
+
+static write_hwcb_t write_hwcb_template = {
+	sizeof(write_hwcb_t),				
+	0x00,						
+	{
+		0x00,
+		0x00,					
+		0x00					
+	},
+	0x0000,						
+	{ 	
+		sizeof(msgbuf_t),			
+		ET_Msg,				
+		0x00,					
+		0x0000,					
+		{ 	
+			sizeof(mdb_t),			
+			0x0001,
+			0xD4C4C240,
+			0x00000001,
+			{ 	
+				{ 	
+					sizeof(go_t),	
+					0x0001
+				}
+			}
+		}
+	}
+};
+
+static mto_t mto_template = {
+	sizeof(mto_t),
+	0x0004,
+	LTF_EndText,	
+	0x00			
+};
+
+ 
+typedef u32 _hwcb_mask_t;
+
+typedef struct {
+	_HWCB_HEADER
+	u16		_reserved;
+	u16		mask_length;
+	_hwcb_mask_t	cp_receive_mask;
+	_hwcb_mask_t	cp_send_mask;
+	_hwcb_mask_t	hwc_receive_mask;
+	_hwcb_mask_t	hwc_send_mask;
+} __attribute__((packed))	init_hwcb_t;
+
+static init_hwcb_t init_hwcb_template = {
+	sizeof(init_hwcb_t),
+	0x00,
+	{
+		0x00,
+		0x00,				
+		0x00				
+	},
+	0x0000,					
+	0x0000,					
+	sizeof(_hwcb_mask_t),
+	ET_OpCmd_Mask | ET_PMsgCmd_Mask,
+	ET_Msg_Mask
+};
+
+
+#define _GDS_VECTOR_HEADER	u16	length; \
+				u16	gds_id;
+
+#define _GDS_SUBVECTOR_HEADER	u8	length; \
+				u8	key;
+
+typedef struct {
+	_GDS_VECTOR_HEADER
+} __attribute__((packed))	gds_vector_t;
+
+typedef struct {
+	_GDS_SUBVECTOR_HEADER
+} __attribute__((packed))	gds_subvector_t;
+
+typedef struct {
+	_HWCB_HEADER
+} __attribute__((packed))	read_hwcb_t;
+
+static read_hwcb_t read_hwcb_template = {
+	PAGE_SIZE,
+	0x00,		
+	{
+		0x00,	
+		0x00,	
+		0x80	
+	}
+};
+
+#endif   /* __HWC_H__ */ 
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/char/hwc_con.c linux.14p16/drivers/s390/char/hwc_con.c
--- linux.vanilla/drivers/s390/char/hwc_con.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/char/hwc_con.c	Wed Dec 15 22:49:58 1999
@@ -0,0 +1,87 @@
+/*
+ *  drivers/s390/char/hwc_con.c
+ *    HWC line mode console driver
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ */
+
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/kdev_t.h>
+#include <linux/string.h>
+#include <linux/console.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+
+#include "hwc_rw.h"
+
+extern void hwc_tty_init(void);
+
+
+#ifdef CONFIG_HWC_CONSOLE
+
+#define  hwc_console_major 4 
+#define  hwc_console_minor 0
+#define  hwc_console_name  "console" 
+
+void hwc_console_write(struct console *, const char *, unsigned int);
+kdev_t hwc_console_device(struct console *);
+
+#define  HWC_CON_PRINT_HEADER "hwc console driver: "
+
+struct console hwc_console = {
+	hwc_console_name,
+	hwc_console_write,
+	NULL,
+	hwc_console_device,
+	NULL,			
+	NULL,			
+	NULL,			
+	CON_PRINTBUFFER,
+	0,
+	0,
+	NULL
+};
+ 
+void hwc_console_write(
+	struct console *console,
+	const char *message,
+	unsigned int count)
+{
+	if (console->device(console) != hwc_console.device(&hwc_console)) 
+	{
+		hwc_printk(KERN_WARNING HWC_CON_PRINT_HEADER
+				"hwc_console_write() called with wrong "
+				"device number");
+		return;
+	}
+	hwc_write(0, message, count);
+}
+
+
+kdev_t hwc_console_device(struct console *c)
+{
+	return  MKDEV(hwc_console_major, hwc_console_minor);
+}
+
+#endif	
+
+__initfunc(unsigned long hwc_console_init(unsigned long kmem_start))
+{
+
+#ifdef CONFIG_3215
+        if (MACHINE_IS_VM)
+                return kmem_start;
+#endif
+	if (hwc_init(&kmem_start) == 0) {
+#ifdef CONFIG_HWC_CONSOLE
+		register_console(&hwc_console);
+#endif	
+		hwc_tty_init();
+	}
+	else panic(HWC_CON_PRINT_HEADER "hwc initialisation failed !");
+	return kmem_start;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/char/hwc_rw.c linux.14p16/drivers/s390/char/hwc_rw.c
--- linux.vanilla/drivers/s390/char/hwc_rw.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/char/hwc_rw.c	Wed Dec 15 23:03:10 1999
@@ -0,0 +1,1821 @@
+/*
+ *  drivers/s390/char/hwc_rw.c
+ *     driver: reading from and writing to system console on S/390 via HWC
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+
+#include <asm/ebcdic.h>
+#include <asm/uaccess.h>
+#include <asm/types.h>
+#include <asm/bitops.h>
+#include <asm/setup.h>
+#include <asm/page.h>
+
+#ifndef MIN
+#define MIN(a,b) ((a<b) ? a : b)
+#endif
+
+#define HWC_RW_PRINT_HEADER "hwc low level driver: "
+#define  USE_VM_DETECTION
+#define  DEFAULT_CASE_DELIMITER '%'
+
+#define DUMP_HWC_INIT_ERROR
+#define DUMP_HWC_WRITE_ERROR
+#define DUMP_HWC_WRITE_LIST_ERROR
+#define DUMP_HWC_READ_ERROR
+#undef DUMP_HWCB_INPUT
+#undef BUFFER_STRESS_TEST
+
+typedef struct {
+	unsigned char *next;
+	unsigned short int mto_char_sum;
+	unsigned char mto_number;
+	unsigned char times_lost;
+	unsigned short int mto_number_lost;
+	unsigned long int mto_char_sum_lost;
+} __attribute__((packed))	hwcb_list_t;
+
+#define MAX_HWCB_ROOM (PAGE_SIZE - sizeof(hwcb_list_t))
+#define MAX_MESSAGE_SIZE (MAX_HWCB_ROOM - sizeof(write_hwcb_t))
+
+#define BUF_HWCB hwc_data.hwcb_list_tail
+#define OUT_HWCB hwc_data.hwcb_list_head
+#define ALL_HWCB_MTO hwc_data.mto_number
+#define ALL_HWCB_CHAR hwc_data.mto_char_sum
+
+#define _LIST(hwcb) ((hwcb_list_t*)(&(hwcb)[PAGE_SIZE-sizeof(hwcb_list_t)]))
+#define _HWCB_CHAR(hwcb) (_LIST(hwcb)->mto_char_sum)
+#define _HWCB_MTO(hwcb) (_LIST(hwcb)->mto_number)
+#define _HWCB_CHAR_LOST(hwcb) (_LIST(hwcb)->mto_char_sum_lost)
+#define _HWCB_MTO_LOST(hwcb) (_LIST(hwcb)->mto_number_lost)
+#define _HWCB_TIMES_LOST(hwcb) (_LIST(hwcb)->times_lost)
+#define _HWCB_NEXT(hwcb) (_LIST(hwcb)->next)
+#define BUF_HWCB_CHAR _HWCB_CHAR(BUF_HWCB)
+#define BUF_HWCB_MTO _HWCB_MTO(BUF_HWCB)
+#define BUF_HWCB_NEXT _HWCB_NEXT(BUF_HWCB)
+#define OUT_HWCB_CHAR _HWCB_CHAR(OUT_HWCB)
+#define OUT_HWCB_MTO _HWCB_MTO(OUT_HWCB)
+#define OUT_HWCB_NEXT _HWCB_NEXT(OUT_HWCB)
+#define BUF_HWCB_CHAR_LOST _HWCB_CHAR_LOST(BUF_HWCB)
+#define BUF_HWCB_MTO_LOST _HWCB_MTO_LOST(BUF_HWCB)
+#define OUT_HWCB_CHAR_LOST _HWCB_CHAR_LOST(OUT_HWCB)
+#define OUT_HWCB_MTO_LOST _HWCB_MTO_LOST(OUT_HWCB)
+#define BUF_HWCB_TIMES_LOST _HWCB_TIMES_LOST(BUF_HWCB)
+
+
+#include  "hwc.h"
+
+#define __HWC_RW_C__
+#include "hwc_rw.h"
+#undef __HWC_RW_C__
+
+static unsigned char _obuf[MAX_HWCB_ROOM];
+
+static unsigned char
+	_page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
+
+typedef u32 kmem_pages_t;
+
+#define MAX_KMEM_PAGES (sizeof(kmem_pages_t) << 3)
+#define HWC_TIMER_RUNS	1
+#define FLUSH_HWCBS	2
+
+static struct {
+	hwc_ioctls_t ioctls;
+	hwc_ioctls_t init_ioctls;
+	unsigned char *hwcb_list_head;
+	unsigned char *hwcb_list_tail;
+	unsigned short int mto_number;
+	unsigned int mto_char_sum;
+	unsigned char hwcb_count;
+	unsigned long kmem_start;
+	unsigned long kmem_end;
+	kmem_pages_t kmem_pages;
+	unsigned char *obuf;
+	unsigned short int obuf_cursor;
+	unsigned short int obuf_count;
+	unsigned short int obuf_start;
+	unsigned char *page;
+	u32 current_servc;
+	unsigned char *current_hwcb;
+	unsigned char write_nonprio:1;
+	unsigned char write_prio:1;
+	unsigned char read_nonprio:1;
+	unsigned char read_prio:1;
+	unsigned char flags;
+	spinlock_t lock;
+	struct timer_list write_timer;
+} hwc_data = {
+	{ },		
+	{		
+		8,		
+		0,		
+		80,		
+		CODE_ASCII,	
+		1,		
+		50,		
+		MAX_KMEM_PAGES,	
+		0,		
+		0x6c		
+	},
+	NULL,		
+	NULL,		
+	0,		
+	0,		
+	0,		
+	0,		
+	0,		
+	0,		
+	_obuf,		
+	0,		
+	0,		
+	0,		
+	_page,		
+	0,		
+	NULL,		
+	0,		
+	0,		
+	0,		
+	0,		
+	0		
+};
+
+#define DELAYED_WRITE 0
+#define IMMEDIATE_WRITE 1
+
+static signed int do_hwc_write(int from_user, const unsigned char *,
+					unsigned int,
+					unsigned char,
+					unsigned char);
+
+
+static asmlinkage int internal_print(char write_time, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+	unsigned char buf[512];
+
+	va_start(args, fmt);
+	i = vsprintf(buf, fmt, args);
+	va_end(args);
+	return do_hwc_write(0, buf, i, CODE_ASCII, write_time);
+}
+
+
+int hwc_printk(const char *fmt, ...)
+{
+	va_list args;
+	int i;
+	unsigned char buf[512];
+	unsigned long flags;
+	int retval;
+	
+	spin_lock_irqsave(&hwc_data.lock, flags);
+
+        i = vsprintf(buf, fmt, args);
+	va_end(args);
+	retval = do_hwc_write(0, buf, i, CODE_ASCII, IMMEDIATE_WRITE);
+	
+	spin_unlock_irqrestore(&hwc_data.lock, flags);
+
+	return retval;
+}
+	
+#ifdef DUMP_HWCB_INPUT
+
+static void dump_storage_area(unsigned char *area, unsigned short int count)
+{
+	unsigned short int index;
+	ioctl_nl_t old_final_nl;
+
+	if (!area || !count)
+		return;
+
+	old_final_nl = hwc_data.ioctls.final_nl;
+	hwc_data.ioctls.final_nl = 1;
+	
+	internal_print(DELAYED_WRITE, "\n%8x   ", area);
+
+	
+	for (index = 0; index < count; index++) {
+		
+		if (area[index] <= 0xF)
+			internal_print(DELAYED_WRITE, "0%x", area[index]);
+		else	internal_print(DELAYED_WRITE, "%x", area[index]);
+		
+		if ((index & 0xF) == 0xF)
+			internal_print(DELAYED_WRITE, "\n%8x   ",
+						 &area[index + 1]);
+		else	if ((index & 3) == 3)
+				
+				internal_print(DELAYED_WRITE, " ");
+	}
+	
+	internal_print(IMMEDIATE_WRITE, "\n"); 
+	hwc_data.ioctls.final_nl = old_final_nl;
+}
+#endif	
+
+static inline u32 service_call(
+	u32 hwc_command_word,
+	unsigned char hwcb[])
+{
+	unsigned int condition_code = 1;
+
+	__asm__ __volatile__("L 1, 0(0,%0) \n\t"
+			     "LRA 2, 0(0,%1) \n\t"
+			     ".long 0xB2200012 \n\t"
+			     :
+			     :"a"(&hwc_command_word), "a"(hwcb)
+			     :"1", "2", "memory");
+
+	__asm__ __volatile__("IPM %0 \n\t"
+			     "SRL %0, 28 \n\t"
+			     :"=r"(condition_code));
+	return condition_code;
+}
+
+
+
+static inline unsigned char * ext_int_param(void)
+{
+	u32 param;
+
+	__asm__ __volatile__("L %0,128(0,0)\n\t"
+			     :"=r"(param));
+
+	return ((unsigned char *) param);
+}
+
+static int prepare_write_hwcb(void)
+{
+	write_hwcb_t *hwcb;
+
+	if (!BUF_HWCB)
+		return -ENOMEM;
+	
+	BUF_HWCB_MTO = 0;
+	BUF_HWCB_CHAR = 0;
+	hwcb = (write_hwcb_t *) BUF_HWCB;
+	memcpy(hwcb, &write_hwcb_template, sizeof(write_hwcb_t));
+	
+	if (!hwc_data.write_nonprio && hwc_data.write_prio)
+		hwcb->msgbuf.type = ET_PMsgCmd;
+
+	return 0;
+}
+
+static int sane_write_hwcb(void)
+{
+	unsigned short int lost_msg;
+	unsigned int lost_char;
+	unsigned char lost_hwcb;
+	unsigned char *bad_addr;
+	unsigned long page;
+	int page_nr;
+
+	if (!OUT_HWCB)
+		return -ENOMEM;
+	
+	if ((unsigned long)OUT_HWCB & 0xFFF) {
+		bad_addr = OUT_HWCB;
+#ifdef DUMP_HWC_WRITE_LIST_ERROR
+		__asm__("LHI 1,0xe30\n\t"
+			"LRA 2,0(0,%0) \n\t"
+			"J .+0 \n\t"
+			:
+			:"a"(bad_addr)
+			:"1", "2");
+#endif	
+		
+		hwc_data.kmem_pages = 0;
+		if ((unsigned long)BUF_HWCB & 0xFFF) {
+			lost_hwcb = hwc_data.hwcb_count;
+			lost_msg = ALL_HWCB_MTO;
+			lost_char = ALL_HWCB_CHAR;
+			
+			OUT_HWCB = NULL;
+			BUF_HWCB = NULL;
+			ALL_HWCB_MTO = 0;
+			ALL_HWCB_CHAR = 0;
+			hwc_data.hwcb_count = 0;
+		} else {
+			lost_hwcb = hwc_data.hwcb_count - 1;
+			lost_msg = ALL_HWCB_MTO - BUF_HWCB_MTO;
+			lost_char = ALL_HWCB_CHAR - BUF_HWCB_CHAR;
+			OUT_HWCB = BUF_HWCB;
+			ALL_HWCB_MTO = BUF_HWCB_MTO;
+			ALL_HWCB_CHAR = BUF_HWCB_CHAR;
+			hwc_data.hwcb_count = 1;
+			page = (unsigned long) BUF_HWCB;
+			
+			
+			if (page >= hwc_data.kmem_start &&
+			    page < hwc_data.kmem_end) {
+				
+				page_nr = (int)
+					  ((page - hwc_data.kmem_start) >> 12);
+				set_bit(page_nr, &hwc_data.kmem_pages);
+			}
+		}
+		
+		internal_print(
+			DELAYED_WRITE,
+			HWC_RW_PRINT_HEADER
+			"found invalid HWCB at address 0x%x. List corrupted. "
+			"Lost %i HWCBs with %i characters within up to %i "
+			"messages. Saved %i HWCB with last %i characters i"
+			"within up to %i messages.\n",
+			(unsigned int)bad_addr,
+			lost_hwcb, lost_char, lost_msg,
+			hwc_data.hwcb_count,
+			ALL_HWCB_CHAR, ALL_HWCB_MTO);
+	}
+	return 0;
+}
+
+static int reuse_write_hwcb(void)
+{
+	int retval;
+
+	if (hwc_data.hwcb_count < 2)
+#ifdef DUMP_HWC_WRITE_LIST_ERROR 
+		__asm__("LHI 1,0xe31\n\t"
+			"LRA 2,0(0,%0)\n\t"
+			"LRA 3,0(0,%1)\n\t"
+			"J .+0 \n\t"
+			:
+			:"a"(BUF_HWCB), "a"(OUT_HWCB)
+			:"1", "2", "3");
+#else
+		return -EPERM;
+#endif	
+	
+	if (hwc_data.current_hwcb == OUT_HWCB) {
+		if (hwc_data.hwcb_count > 2) {
+			BUF_HWCB_NEXT = OUT_HWCB_NEXT;
+			BUF_HWCB = OUT_HWCB_NEXT;
+			OUT_HWCB_NEXT = BUF_HWCB_NEXT;
+			BUF_HWCB_NEXT = NULL;
+		}
+	} else {
+		BUF_HWCB_NEXT = OUT_HWCB;
+		BUF_HWCB = OUT_HWCB;
+		OUT_HWCB = OUT_HWCB_NEXT;
+		BUF_HWCB_NEXT = NULL;
+	}
+	BUF_HWCB_TIMES_LOST += 1;
+	BUF_HWCB_CHAR_LOST += BUF_HWCB_CHAR;
+	BUF_HWCB_MTO_LOST += BUF_HWCB_MTO;
+	ALL_HWCB_MTO -= BUF_HWCB_MTO;
+	ALL_HWCB_CHAR -= BUF_HWCB_CHAR;
+
+	retval = prepare_write_hwcb();
+
+	if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb)
+		internal_print(
+			DELAYED_WRITE,
+			HWC_RW_PRINT_HEADER
+			"reached my own limit of "
+			"allowed buffer space for output (%i HWCBs = %li "
+			"bytes), skipped content of oldest HWCB %i time(s) "
+			"(%i lines = %i characters)\n",
+			hwc_data.ioctls.max_hwcb,
+			hwc_data.ioctls.max_hwcb * PAGE_SIZE,
+			BUF_HWCB_TIMES_LOST,
+			BUF_HWCB_MTO_LOST,
+			BUF_HWCB_CHAR_LOST);
+	else	internal_print(
+			DELAYED_WRITE,
+			HWC_RW_PRINT_HEADER
+			"page allocation failed, "
+			"could not expand buffer for output (currently in "
+			"use: %i HWCBs = %li bytes), skipped content of "
+			"oldest HWCB %i time(s) (%i lines = %i characters)\n",
+			hwc_data.hwcb_count,
+			hwc_data.hwcb_count * PAGE_SIZE,
+			BUF_HWCB_TIMES_LOST,
+			BUF_HWCB_MTO_LOST,
+			BUF_HWCB_CHAR_LOST);
+
+	return retval;
+}
+
+static int allocate_write_hwcb(void)
+{
+	unsigned char *page;
+	int page_nr;
+	
+	if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb)
+		return -ENOMEM;
+	
+	page_nr = find_first_zero_bit(&hwc_data.kmem_pages, MAX_KMEM_PAGES);
+	if (page_nr < hwc_data.ioctls.kmem_hwcb) {
+		page = (unsigned char *)
+				(hwc_data.kmem_start + (page_nr << 12));
+		set_bit(page_nr, &hwc_data.kmem_pages);
+	} else	page = (unsigned char *) __get_free_page(GFP_ATOMIC);
+	if (!page)
+		return -ENOMEM;
+
+	if (!OUT_HWCB)
+		OUT_HWCB = page;
+	else	
+		BUF_HWCB_NEXT = page;
+
+	BUF_HWCB = page;
+	BUF_HWCB_NEXT = NULL;
+	hwc_data.hwcb_count++;
+	prepare_write_hwcb();
+	BUF_HWCB_TIMES_LOST = 0;
+	BUF_HWCB_MTO_LOST = 0;
+	BUF_HWCB_CHAR_LOST = 0;
+
+#ifdef BUFFER_STRESS_TEST
+	internal_print(
+		DELAYED_WRITE,
+		"*** " HWC_RW_PRINT_HEADER
+		"page #%i at 0x%x for buffering allocated. ***\n",
+		hwc_data.hwcb_count, page);
+
+#endif	
+	return 0;
+}
+
+static int release_write_hwcb(void)
+{
+	unsigned long page;
+	int page_nr;
+        
+        if (!hwc_data.hwcb_count)
+                return -ENODATA;
+        
+        if (hwc_data.hwcb_count == 1) {
+                prepare_write_hwcb();
+                
+                ALL_HWCB_CHAR = 0;
+                ALL_HWCB_MTO = 0;
+                BUF_HWCB_TIMES_LOST = 0;
+                BUF_HWCB_MTO_LOST = 0;
+                BUF_HWCB_CHAR_LOST = 0;
+        }
+        else {  
+                page = (unsigned long) OUT_HWCB;
+                
+                ALL_HWCB_MTO -= OUT_HWCB_MTO;
+                ALL_HWCB_CHAR -= OUT_HWCB_CHAR;
+                hwc_data.hwcb_count--;
+                
+                OUT_HWCB = OUT_HWCB_NEXT;
+                
+                if (page >= hwc_data.kmem_start &&
+                    page < hwc_data.kmem_end) {
+			memset((void *) page, 0, PAGE_SIZE);
+                        page_nr = (int) ((page - hwc_data.kmem_start) >> 12);
+                        clear_bit(page_nr, &hwc_data.kmem_pages);
+                }
+                else 
+                	free_page(page);
+#ifdef BUFFER_STRESS_TEST
+	        internal_print(
+			DELAYED_WRITE,
+			"*** " HWC_RW_PRINT_HEADER
+			"page at 0x%x released, %i pages still in use ***\n",
+			page, hwc_data.hwcb_count);
+
+#endif  
+        }
+	return 0;
+}
+
+static int add_mto(
+	unsigned char *message,
+	unsigned short int count)
+{
+	unsigned short int mto_size;
+	write_hwcb_t *hwcb;
+	mto_t *mto;
+	void *dest;
+
+	if (!BUF_HWCB)
+		return -ENOMEM;
+
+	if (BUF_HWCB == hwc_data.current_hwcb)
+		return -ENOMEM;
+
+	mto_size = sizeof(mto_t) + count;
+	hwcb = (write_hwcb_t *) BUF_HWCB;
+	
+	if ((MAX_HWCB_ROOM - hwcb->length) < mto_size)
+		return -ENOMEM;
+
+	mto = (mto_t *) (((unsigned long) hwcb) + hwcb->length);
+	memcpy(mto, &mto_template, sizeof(mto_t));
+	dest = (void *) (((unsigned long) mto) + sizeof(mto_t));
+	memcpy(dest, message, count);
+	mto->length += count;
+	
+	hwcb->length		+= mto_size;
+	hwcb->msgbuf.length	+= mto_size;
+	hwcb->msgbuf.mdb.length	+= mto_size;
+
+	BUF_HWCB_MTO++;
+	ALL_HWCB_MTO++;
+	BUF_HWCB_CHAR += count;
+	ALL_HWCB_CHAR += count;
+
+	return count;
+}
+
+static int write_event_data_1(void)
+{
+	unsigned short int condition_code;
+	int retval;
+
+	if ((!hwc_data.write_prio) && (!hwc_data.write_nonprio))
+		return -EPERM;
+
+	if (hwc_data.current_servc)
+		return -EBUSY;
+	
+	retval = sane_write_hwcb();
+	if (retval < 0)
+		return retval;
+	if (!OUT_HWCB_MTO)
+		return -ENODATA;
+	condition_code = service_call(HWC_CMDW_WRITEDATA, OUT_HWCB);
+#ifdef DUMP_HWC_WRITE_ERROR 
+	if (condition_code != HWC_COMMAND_INITIATED)
+		__asm__("LHI 1,0xe20\n\t"
+			"L 2,0(0,%0)\n\t"
+			"LRA 3,0(0,%1)\n\t"
+			"J .+0 \n\t"
+			:
+			:"a"(&condition_code), "a"(OUT_HWCB)
+			:"1", "2", "3");
+#endif	
+	switch (condition_code) {
+		case HWC_COMMAND_INITIATED :
+			hwc_data.current_servc = HWC_CMDW_WRITEDATA;
+			hwc_data.current_hwcb = OUT_HWCB;
+			retval = condition_code;
+			break;
+		case HWC_BUSY :
+			retval = -EBUSY;
+			break;
+		default :
+			retval = -EIO;
+	}
+	return retval;
+}
+
+static void flush_hwcbs(void)
+{
+	while (hwc_data.hwcb_count > 1)
+		release_write_hwcb();
+	release_write_hwcb();
+	hwc_data.flags &= ~FLUSH_HWCBS;
+}
+
+static int write_event_data_2(void)
+{
+	write_hwcb_t *hwcb;
+	int retval;
+	unsigned char *param;
+
+	param = ext_int_param();
+	if (param != hwc_data.current_hwcb)
+		return -EINVAL;
+
+	hwcb = (write_hwcb_t *) OUT_HWCB;
+
+#ifdef DUMP_HWC_WRITE_ERROR 
+#if 0
+	if (((unsigned char *) hwcb) != param)
+		__asm__("LHI 1,0xe22\n\t"
+			"LRA 2,0(0,%0)\n\t"
+			"LRA 3,0(0,%1)\n\t"
+			"LRA 4,0(0,%2)\n\t"
+			"LRA 5,0(0,%3)\n\t"
+			"J .+0 \n\t"
+			:
+			:"a"(OUT_HWCB),
+			 "a"(hwc_data.current_hwcb),
+			 "a"(BUF_HWCB),
+			 "a"(param)
+			:"1", "2", "3", "4", "5");
+#endif
+	if (hwcb->response_code != 0x0020)
+#if 0
+		internal_print(DELAYED_WRITE, HWC_RW_PRINT_HEADER
+		"\n************************ error in write_event_data_2()\n"
+		"OUT_HWCB:                    0x%x\n"
+		"BUF_HWCB:                    0x%x\n"
+		"response_code:               0x%x\n"
+		"hwc_data.hwcb_count:        %d\n"
+		"hwc_data.kmem_pages:        0x%x\n"
+		"hwc_data.ioctls.kmem_hwcb:   %d\n"
+		"hwc_data.ioctls.max_hwcb:    %d\n"
+		"hwc_data.kmem_start:        0x%x\n"
+		"hwc_data.kmem_end:          0x%x\n"
+		"*****************************************************\n",
+		OUT_HWCB,
+		BUF_HWCB,
+		hwcb->response_code,
+		hwc_data.hwcb_count,
+		hwc_data.kmem_pages,
+		hwc_data.ioctls.kmem_hwcb,
+		hwc_data.ioctls.max_hwcb,
+		hwc_data.kmem_start,
+		hwc_data.kmem_end);
+#endif
+		__asm__("LHI 1,0xe21\n\t"
+			"LRA 2,0(0,%0)\n\t"
+			"LRA 3,0(0,%1)\n\t"
+			"LRA 4,0(0,%2)\n\t"
+			"LH 5,0(0,%3)\n\t"
+			"SRL 5,8(0)\n\t"
+			"J .+0 \n\t"
+			:
+			:"a"(OUT_HWCB), "a"(hwc_data.current_hwcb),
+			 "a"(BUF_HWCB),
+			 "a"(&(hwc_data.hwcb_count))
+			:"1", "2", "3", "4", "5");
+#endif	
+
+	
+	if (hwcb->response_code == 0x0020) {
+		retval = OUT_HWCB_CHAR;
+		release_write_hwcb();
+	} else retval = -EIO;	
+
+	hwc_data.current_servc = 0;
+	hwc_data.current_hwcb = NULL;
+
+	if (hwc_data.flags & FLUSH_HWCBS)
+		flush_hwcbs();
+
+	return retval;
+}
+
+static void do_put_line(
+	unsigned char * message,
+	unsigned short count)
+{
+	if (add_mto(message, count) != count) {
+		if (allocate_write_hwcb() < 0)
+			reuse_write_hwcb();
+		
+#ifdef DUMP_HWC_WRITE_LIST_ERROR 
+		if (add_mto(message, count) != count)
+			__asm__("LHI 1,0xe32\n\t"
+				"LRA 2,0(0,%0)\n\t"
+				"L 3,0(0,%1)\n\t"
+				"LRA 4,0(0,%2)\n\t"
+				"LRA 5,0(0,%3)\n\t"
+				"J .+0 \n\t"
+				:
+				:"a"(message), "a"(&hwc_data.kmem_pages),
+				 "a"(BUF_HWCB), "a"(OUT_HWCB)
+				:"1", "2", "3", "4", "5");
+#else
+		add_mto(message, count);
+#endif	
+	}
+}
+
+static void put_line(
+	unsigned char * message,
+	unsigned short count)
+{
+	
+	if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_TIMER_RUNS)) {
+		del_timer(&hwc_data.write_timer);
+		hwc_data.flags &= ~HWC_TIMER_RUNS;
+	}
+
+	hwc_data.obuf_start += count;
+	do_put_line(message, count);
+	hwc_data.obuf_start -= count;
+}
+
+static void set_alarm(void)
+{
+	write_hwcb_t *hwcb;
+	if ((!BUF_HWCB) || (BUF_HWCB == hwc_data.current_hwcb))
+		allocate_write_hwcb();
+
+	hwcb = (write_hwcb_t *) BUF_HWCB;
+	hwcb->msgbuf.mdb.mdb_body.go.general_msg_flags |= GMF_SndAlrm;
+} 
+
+static void hwc_write_timeout(unsigned long data)
+{
+	unsigned long flags;
+	
+	spin_lock_irqsave(&hwc_data.lock, flags);
+	
+	hwc_data.obuf_start = hwc_data.obuf_count;
+	if (hwc_data.obuf_count)
+		put_line(hwc_data.obuf, hwc_data.obuf_count);
+	hwc_data.obuf_start = 0;
+	hwc_data.obuf_cursor = 0;
+	hwc_data.obuf_count = 0;
+	
+	write_event_data_1(); 
+	spin_unlock_irqrestore(&hwc_data.lock, flags);
+}
+
+static int do_hwc_write(
+	int from_user,
+	const unsigned char *msg,
+	unsigned int count,
+	unsigned char code,
+	unsigned char write_time)
+{
+	unsigned int i_msg = 0;
+	unsigned short int spaces = 0;
+	unsigned int processed_characters = 0;
+	unsigned char ch, orig_ch;
+	unsigned short int obuf_count;
+	unsigned short int obuf_cursor;
+	unsigned short int obuf_columns;
+
+	if (hwc_data.obuf_start) {
+		obuf_cursor = 0;
+		obuf_count = 0;
+		obuf_columns = MIN(hwc_data.ioctls.columns,
+				   MAX_MESSAGE_SIZE - hwc_data.obuf_start);
+	} else {
+		obuf_cursor = hwc_data.obuf_cursor;
+		obuf_count = hwc_data.obuf_count;
+		obuf_columns = hwc_data.ioctls.columns;
+	}
+	
+	for (i_msg = 0; i_msg < count; i_msg++) {
+		if (from_user)
+			get_user(orig_ch, msg + i_msg);
+		else
+			orig_ch = msg[i_msg];
+		if (code == CODE_EBCDIC)
+			ch = _ebcasc[orig_ch];
+		else	ch = orig_ch;
+
+		processed_characters++;
+		
+		if ((obuf_cursor == obuf_columns) &&
+		    (ch != '\n') &&
+		    (ch != '\t')) {
+			put_line(&hwc_data.obuf[hwc_data.obuf_start],
+				 obuf_columns);
+			obuf_cursor = 0;
+			obuf_count = 0;
+		}
+		
+		switch (ch) {
+		   case '\n' :  
+			put_line(&hwc_data.obuf[hwc_data.obuf_start],
+				 obuf_count);
+			obuf_cursor = 0;
+			obuf_count = 0;
+			break;
+
+		   case '\a' :  
+			hwc_data.obuf_start += obuf_count;
+			set_alarm();
+			hwc_data.obuf_start -= obuf_count;
+			break;
+
+		   case '\t' :  
+			do
+			{			
+				if (obuf_cursor < obuf_columns) {
+					hwc_data.obuf[hwc_data.obuf_start +
+								obuf_cursor]
+						= 0x20;  
+					obuf_cursor++;
+				}
+				else break;
+			} while (obuf_cursor % hwc_data.ioctls.width_htab);
+			break;
+
+		   case '\f' :  
+		   case '\v' :  
+			spaces = obuf_cursor;
+			put_line(&hwc_data.obuf[hwc_data.obuf_start],
+				 obuf_count);
+			obuf_count = obuf_cursor;
+			while (spaces) {
+				hwc_data.obuf[hwc_data.obuf_start +
+						obuf_cursor - spaces]
+					= 0x20;  
+				spaces--;
+			}
+			break;
+
+		   case '\b' :  
+			if (obuf_cursor)
+				obuf_cursor--;
+			break;
+
+		   case '\r' :  
+			obuf_cursor = 0;
+			break;
+
+		   case 0x00 :  
+			put_line(&hwc_data.obuf[hwc_data.obuf_start],
+				 obuf_count);
+			obuf_cursor = 0;
+			obuf_count = 0;
+			goto out;
+
+		   default:  
+			if (isprint(ch))
+				hwc_data.obuf[hwc_data.obuf_start +
+						obuf_cursor++]
+					 = (code == CODE_ASCII) ?
+					   _ascebc[orig_ch]:orig_ch;
+		}
+		if (obuf_cursor > obuf_count)
+			obuf_count = obuf_cursor;
+	}
+
+	
+	if (obuf_cursor) {
+		if (hwc_data.obuf_start ||
+		    (hwc_data.ioctls.final_nl == 0)) {
+			
+			put_line(&hwc_data.obuf[hwc_data.obuf_start],
+				 obuf_count);
+			obuf_cursor = 0;
+			obuf_count = 0;
+		}
+		else {
+			if (hwc_data.ioctls.final_nl > 0) {
+				if (hwc_data.flags & HWC_TIMER_RUNS) {
+					hwc_data.write_timer.expires =
+						jiffies +
+						hwc_data.ioctls.final_nl*HZ/10;
+				}
+				else {
+					init_timer(&hwc_data.write_timer);
+					hwc_data.write_timer.function =
+						hwc_write_timeout;
+					hwc_data.write_timer.data =
+						(unsigned long)NULL;
+					hwc_data.write_timer.expires =
+						jiffies +
+						hwc_data.ioctls.final_nl*HZ/10;
+					add_timer(&hwc_data.write_timer);
+					hwc_data.flags |= HWC_TIMER_RUNS;
+				}
+			}
+			else ;	
+		}
+	}
+	else ;	
+out :
+	if (!hwc_data.obuf_start) {
+		hwc_data.obuf_cursor = obuf_cursor;
+		hwc_data.obuf_count = obuf_count;
+	}
+
+	if (write_time == IMMEDIATE_WRITE)
+		write_event_data_1();
+
+	return processed_characters;
+}
+
+
+
+
+
+signed int hwc_write(int from_user, const unsigned char *msg, unsigned int count)
+{
+	unsigned long flags;
+	int retval;
+	
+	spin_lock_irqsave(&hwc_data.lock, flags);
+	retval = do_hwc_write(from_user, msg, count, hwc_data.ioctls.code,
+							 IMMEDIATE_WRITE);
+	spin_unlock_irqrestore(&hwc_data.lock, flags);
+	return retval;
+}
+
+
+
+
+
+unsigned int hwc_chars_in_buffer(unsigned char flag)
+{
+	unsigned short int number = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&hwc_data.lock, flags);
+	if (flag & IN_HWCB)
+		number += ALL_HWCB_CHAR;
+	
+	if (flag & IN_WRITE_BUF)
+		number += hwc_data.obuf_cursor;
+	
+	spin_unlock_irqrestore(&hwc_data.lock, flags);
+	return number;
+}
+
+static inline int nr_setbits(kmem_pages_t arg)
+{
+	int i;
+	int nr = 0;
+
+	for (i = 0; i < (sizeof(arg) << 3); i++) {
+		if (arg & 1)
+			nr++;
+		arg >>= 1;
+	}
+	return nr;
+}
+
+unsigned int hwc_write_room(unsigned char flag)
+{
+	unsigned int number = 0;
+	unsigned long flags;
+	write_hwcb_t *hwcb;
+	
+	spin_lock_irqsave(&hwc_data.lock, flags);
+        if (flag & IN_HWCB) {
+		if (BUF_HWCB) {
+			hwcb = (write_hwcb_t *) BUF_HWCB;
+                	number += MAX_HWCB_ROOM - hwcb->length;
+		}
+		number += (hwc_data.ioctls.kmem_hwcb -
+			   nr_setbits(hwc_data.kmem_pages)) *
+			  (MAX_HWCB_ROOM -
+				(sizeof(write_hwcb_t) + sizeof(mto_t)));
+	}
+        if (flag & IN_WRITE_BUF)
+                number += MAX_HWCB_ROOM - hwc_data.obuf_cursor;
+	spin_unlock_irqrestore(&hwc_data.lock, flags);
+	return number;
+}
+
+void hwc_flush_buffer(unsigned char flag)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&hwc_data.lock, flags);
+	if (flag & IN_HWCB) {
+		if (hwc_data.current_servc != HWC_CMDW_WRITEDATA)
+			flush_hwcbs();
+		else	hwc_data.flags |= FLUSH_HWCBS;
+	}
+	if (flag & IN_WRITE_BUF) {
+		hwc_data.obuf_cursor = 0;	
+		hwc_data.obuf_count = 0;
+	}
+	spin_unlock_irqrestore(&hwc_data.lock, flags);
+}
+
+unsigned short int seperate_cases(unsigned char *buf, unsigned short int count)
+{
+	unsigned short int i_in;
+	unsigned short int i_out = 0;
+	unsigned char _case = 0;
+
+	for (i_in = 0; i_in < count; i_in++) {
+		if (buf[i_in] == hwc_data.ioctls.delim) {
+			if ((i_in + 1 < count) &&
+			    (buf[i_in + 1] == hwc_data.ioctls.delim)) {
+				buf[i_out] = hwc_data.ioctls.delim;
+				i_out++;
+				i_in++; 
+			} else	_case = ~_case;
+		} else {
+			if (_case) {
+				if (hwc_data.ioctls.tolower) 
+					buf[i_out] = _ebc_toupper[buf[i_in]];
+				else	buf[i_out] = _ebc_tolower[buf[i_in]];
+			} else	buf[i_out] = buf[i_in];
+			i_out++;
+		}
+	}
+	return i_out;
+}
+
+
+
+#ifdef DUMP_HWCB_INPUT
+
+static int gds_vector_name(u16 id, unsigned char name[])
+{
+	int retval = 0;
+
+	switch (id) {
+		case GDS_ID_MDSMU :
+			name = "Multiple Domain Support Message Unit";
+			break;
+		case GDS_ID_MDSRouteInfo :
+			name = "MDS Routing Information";
+			break;
+		case GDS_ID_AgUnWrkCorr :
+			name = "Agent Unit of Work Correlator";
+			break;
+		case GDS_ID_SNACondReport :
+			name = "SNA Condition Report";
+			break;
+		case GDS_ID_CPMSU :
+			name = "CP Management Services Unit";
+			break;
+		case GDS_ID_RoutTargInstr :
+			name = "Routing and Targeting Instructions";
+			break;
+		case GDS_ID_OpReq :
+			name = "Operate Request";
+			break;
+		case GDS_ID_TextCmd :
+			name = "Text Command";
+			break;
+
+		default :
+			name = "unknown GDS variable";
+			retval = -EINVAL;
+	}
+
+	return retval;
+}
+#endif	
+
+
+
+inline static gds_vector_t * find_gds_vector(
+	gds_vector_t *start, void *end, u16 id)
+{
+	gds_vector_t *vec;
+	gds_vector_t *retval = NULL;
+
+	vec = start;
+
+	while (((void *) vec) < end) {
+	 	if (vec->gds_id == id) {
+
+#ifdef DUMP_HWCB_INPUT
+			int retval_name;
+			unsigned char name[64];
+
+			retval_name = gds_vector_name(id, name);
+			internal_print(
+				DELAYED_WRITE,
+				HWC_RW_PRINT_HEADER
+				"%s at 0x%x up to 0x%x, length: %d",
+				name,
+				(unsigned long) vec,
+				((unsigned long) vec) + vec->length - 1,
+				vec->length);
+			if (retval_name < 0)
+				internal_print(
+					IMMEDIATE_WRITE,
+					", id: 0x%x\n",
+					vec->gds_id);
+			else	internal_print(
+					IMMEDIATE_WRITE,
+					"\n");
+#endif	
+			retval = vec;
+			break;
+		}
+
+		vec = (gds_vector_t *) (((unsigned long) vec) + vec->length);
+	}
+
+	return retval;
+}
+
+
+inline static gds_subvector_t * find_gds_subvector(
+	gds_subvector_t *start, void *end, u8 key)
+{
+	gds_subvector_t *subvec;
+	gds_subvector_t *retval = NULL;
+
+	subvec = start;
+
+	while (((void *) subvec) < end) {
+	 	if (subvec->key == key) {
+			retval = subvec;
+			break;
+		}
+		subvec = (gds_subvector_t *)
+				(((unsigned long) subvec) + subvec->length);
+	}
+	return retval;
+}
+
+
+inline static int get_input(void *start, void *end)
+{
+	int count;
+
+	count = ((unsigned long) end) - ((unsigned long) start);
+
+	if (hwc_data.ioctls.tolower)
+		EBC_TOLOWER(start, count);
+	if (hwc_data.ioctls.delim)
+		count = seperate_cases(start, count);
+	if (hwc_data.ioctls.echo)
+		do_hwc_write(0, start, count, CODE_EBCDIC, IMMEDIATE_WRITE);
+	if (hwc_data.ioctls.code == CODE_ASCII)
+		EBCASC(start, count);
+	store_hwc_input(start, count);
+	return count;
+}
+
+
+inline static int eval_selfdeftextmsg(gds_subvector_t *start, void *end)
+{
+	gds_subvector_t *subvec;
+	void *subvec_data;
+	void *subvec_end;
+	int retval = 0;
+
+	subvec = start;
+
+	while (((void *) subvec) < end) {
+		subvec = find_gds_subvector(subvec, end, 0x30);
+		if (!subvec)
+			break;
+		subvec_data = (void *)
+				(((unsigned long) subvec) + 
+						sizeof(gds_subvector_t));
+		subvec_end = (void *)
+				(((unsigned long) subvec) + subvec->length);
+		retval += get_input(subvec_data, subvec_end);
+		subvec = (gds_subvector_t *) subvec_end;
+	}
+	return retval;
+}
+
+
+inline static int eval_textcmd(gds_subvector_t *start, void *end)
+{
+	gds_subvector_t *subvec;
+	gds_subvector_t *subvec_data;
+	void *subvec_end;
+	int retval = 0;
+
+	subvec = start;
+
+	while (((void *) subvec) < end) {
+		subvec = find_gds_subvector(
+					subvec, end, GDS_KEY_SelfDefTextMsg);
+		if (!subvec)
+			break;
+		subvec_data = (gds_subvector_t *)
+				(((unsigned long) subvec) + 
+						sizeof(gds_subvector_t));
+		subvec_end = (void *)
+				(((unsigned long) subvec) + subvec->length);
+		retval += eval_selfdeftextmsg(subvec_data, subvec_end);
+		subvec = (gds_subvector_t *) subvec_end;
+	}
+
+	return retval;
+}
+
+
+inline static int eval_cpmsu(gds_vector_t *start, void *end)
+{
+	gds_vector_t *vec;
+	gds_subvector_t *vec_data;
+	void *vec_end;
+	int retval = 0;
+
+	vec = start;
+
+	while (((void *) vec) < end) {
+		vec = find_gds_vector(vec, end, GDS_ID_TextCmd);
+		if (!vec)
+			break;
+		vec_data = (gds_subvector_t *)
+				(((unsigned long) vec) + sizeof(gds_vector_t));
+		vec_end = (void *) (((unsigned long) vec) + vec->length);
+		retval += eval_textcmd(vec_data, vec_end);
+		vec = (gds_vector_t *) vec_end;
+	}
+
+	return retval;
+}
+
+
+inline static int eval_mdsmu(gds_vector_t *start, void *end)
+{
+	gds_vector_t *vec;
+	gds_vector_t *vec_data;
+	void *vec_end;
+	int retval = 0;
+
+	vec = find_gds_vector(start, end, GDS_ID_CPMSU);
+	if (vec) {
+		vec_data = (gds_vector_t *)
+				(((unsigned long) vec) + sizeof(gds_vector_t));
+		vec_end = (void *) (((unsigned long) vec) + vec->length);
+		retval = eval_cpmsu(vec_data, vec_end);
+	}
+
+	return retval;
+}
+
+
+inline static int eval_evbuf(gds_vector_t *start, void *end)
+{
+	gds_vector_t *vec;
+	gds_vector_t *vec_data;
+	void *vec_end;
+	int retval = 0;
+
+	vec = find_gds_vector(start, end, GDS_ID_MDSMU);
+	if (vec) {
+		vec_data = (gds_vector_t *)
+				(((unsigned long) vec) + sizeof(gds_vector_t));
+		vec_end = (void *) (((unsigned long) vec) + vec->length);
+		retval = eval_mdsmu(vec_data, vec_end);
+	}
+
+	return retval;
+}
+
+
+static int process_evbufs(void *start, void *end)
+{
+	int retval = 0;
+	evbuf_t *evbuf;
+	void *evbuf_end;
+	gds_vector_t *evbuf_data;
+
+	evbuf = (evbuf_t *) start;
+	while (((void *) evbuf) < end) {
+		evbuf_data = (gds_vector_t *)
+				(((unsigned long) evbuf) + sizeof(evbuf_t));
+		evbuf_end = (void *) (((unsigned long) evbuf) + evbuf->length);
+		switch (evbuf->type) {
+			case ET_OpCmd :
+			case ET_CntlProgOpCmd :
+			case ET_PMsgCmd :
+#ifdef DUMP_HWCB_INPUT
+				
+				internal_print(
+					DELAYED_WRITE,
+					HWC_RW_PRINT_HEADER
+					"event buffer "
+					"at 0x%x up to 0x%x, length: %d\n",
+					(unsigned long) evbuf,
+					(unsigned long) (evbuf_end - 1),
+					evbuf->length);
+				dump_storage_area((void *)evbuf, evbuf->length);
+#endif
+				retval += eval_evbuf(evbuf_data, evbuf_end);
+				break;
+			case ET_StateChange :
+				
+				retval = -ENOSYS;
+				break;
+			default :
+				printk(
+					KERN_WARNING
+					HWC_RW_PRINT_HEADER
+					"unconditional read: "
+					"unknown event buffer found, "
+					"type 0x%x",
+					evbuf->type);
+				retval = -ENOSYS;
+		}
+		evbuf = (evbuf_t *) evbuf_end;
+	}
+	return retval;
+}
+
+static int unconditional_read_1(void)
+{
+	unsigned short int condition_code;
+	read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
+	int retval;
+	
+	if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio))
+		return -EOPNOTSUPP;
+	if (hwc_data.current_servc)
+		return -EBUSY;
+	
+	memset(hwcb, 0x00, PAGE_SIZE); 
+	memcpy(hwcb, &read_hwcb_template, sizeof(read_hwcb_t));
+
+	condition_code = service_call(HWC_CMDW_READDATA, hwc_data.page);
+
+#ifdef DUMP_HWC_READ_ERROR 
+	if (condition_code == HWC_NOT_OPERATIONAL)
+		__asm__("LHI 1,0xe40\n\t"
+			"L 2,0(0,%0)\n\t"
+			"LRA 3,0(0,%1)\n\t"
+			"J .+0 \n\t"
+			:
+			:"a"(&condition_code), "a"(hwc_data.page)
+			:"1", "2", "3");
+#endif	
+
+	switch (condition_code) {
+		case HWC_COMMAND_INITIATED :
+			hwc_data.current_servc = HWC_CMDW_READDATA;
+			hwc_data.current_hwcb = hwc_data.page;
+			retval = condition_code;
+			break;
+		case HWC_BUSY :
+			retval = -EBUSY;
+			break;
+		default :
+			retval = -EIO;
+	}
+
+	return retval;
+}
+
+static int unconditional_read_2(void)
+{
+	read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
+
+#ifdef DUMP_HWC_READ_ERROR 
+	if ((hwcb->response_code != 0x0020) &&
+	    (hwcb->response_code != 0x0220) &&
+	    (hwcb->response_code != 0x60F0) &&
+	    (hwcb->response_code != 0x62F0))
+		__asm__("LHI 1,0xe41\n\t"
+			"LRA 2,0(0,%0)\n\t"
+			"L 3,0(0,%1)\n\t"
+			"J .+0\n\t"
+			:
+			:"a"(hwc_data.page), "a"(&(hwcb->response_code))
+			:"1", "2", "3");
+#endif	
+
+	hwc_data.current_servc = 0;
+	hwc_data.current_hwcb = NULL;
+
+	switch (hwcb->response_code) {
+	   case 0x0020 :
+	   case 0x0220 : 
+		return process_evbufs(
+			(void *) (((unsigned long) hwcb) + sizeof(read_hwcb_t)),
+			(void *) (((unsigned long) hwcb) + hwcb->length));
+	   case 0x60F0 :
+	   case 0x62F0 : 
+		return 0;
+	   case 0x0100 :
+		internal_print(
+			IMMEDIATE_WRITE,
+			HWC_RW_PRINT_HEADER
+			"unconditional read: HWCB boundary violation - this "
+			"must not occur in a correct driver, please contact "
+			"author\n");
+		return -EIO;
+
+	   case 0x0300 :
+		internal_print(
+			IMMEDIATE_WRITE,
+			HWC_RW_PRINT_HEADER
+			"unconditional read: "
+			"insufficient HWCB length - this must not occur in a "
+			"correct driver, please contact author\n");
+		return -EIO;
+
+	   case 0x01F0 :
+		internal_print(
+			IMMEDIATE_WRITE, 
+			HWC_RW_PRINT_HEADER
+			"unconditional read: "
+			"invalid command - this must not occur in a correct "
+			"driver, please contact author\n");
+		return -EIO;
+
+	   case 0x40F0 :
+		internal_print(
+			IMMEDIATE_WRITE,
+			HWC_RW_PRINT_HEADER
+			"unconditional read: invalid function code - this "
+			"must not occur in a correct driver, please contact "
+			"author\n");
+		return -EIO;
+
+	   case 0x70F0 :
+		internal_print(
+			IMMEDIATE_WRITE,
+			HWC_RW_PRINT_HEADER
+			"unconditional read: invalid selection mask - this "
+			"must not occur in a correct driver, please contact "
+			"author\n");
+		return -EIO;
+
+	   case 0x0040 :
+		internal_print(
+			IMMEDIATE_WRITE,
+			HWC_RW_PRINT_HEADER
+			"unconditional read: HWC equipment check - don't "
+			"know how to handle this case\n");
+		return -EIO;
+	   
+	   default :
+		internal_print(
+			IMMEDIATE_WRITE,
+			HWC_RW_PRINT_HEADER
+			"unconditional read: invalid response code %x - this "
+			"must not occur in a correct driver, please contact "
+			"author\n",
+			hwcb->response_code);
+		return -EIO;
+	}
+}
+
+static int write_event_mask_1(void)
+{
+	unsigned int condition_code;
+	int retval;
+	
+	memcpy(hwc_data.page, &init_hwcb_template, sizeof(init_hwcb_t));
+	condition_code = service_call(HWC_CMDW_WRITEMASK, hwc_data.page);
+#ifdef DUMP_HWC_INIT_ERROR
+	if (condition_code != HWC_COMMAND_INITIATED)
+		__asm__("LHI 1,0xe10\n\t"
+			"L 2,0(0,%0)\n\t"
+			"LRA 3,0(0,%1)\n\t"
+			"J .+0\n\t"
+			:
+			:"a"(&condition_code), "a"(hwc_data.page)
+			:"1", "2", "3");
+#endif	
+
+	switch (condition_code) {
+		case HWC_COMMAND_INITIATED :
+			hwc_data.current_servc = HWC_CMDW_WRITEMASK;
+			hwc_data.current_hwcb = hwc_data.page;
+			retval = condition_code;
+			break;
+		case HWC_BUSY :
+			retval = -EBUSY;
+			break;
+		default :
+			retval = -EIO;
+	}
+	return retval;
+}
+
+
+
+
+
+static int write_event_mask_2(void)
+{
+	init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page;
+	int retval = 0;
+
+	
+	if (hwcb->hwc_receive_mask & ET_Msg_Mask)
+		hwc_data.write_nonprio = 1;
+	
+	if (hwcb->hwc_receive_mask & ET_PMsgCmd_Mask)
+		hwc_data.write_prio = 1;
+	
+	if (hwcb->hwc_send_mask & ET_OpCmd_Mask)
+		hwc_data.read_nonprio = 1;
+	
+	if (hwcb->hwc_send_mask & ET_PMsgCmd_Mask)
+		hwc_data.read_nonprio = 1;
+
+	if ((hwcb->response_code != 0x0020) ||
+	    (!hwc_data.write_nonprio) ||
+	    ((!hwc_data.read_nonprio) && (!hwc_data.read_prio)))
+#ifdef DUMP_HWC_INIT_ERROR
+		__asm__("LHI 1,0xe11\n\t"
+			"LRA 2,0(0,%0)\n\t"
+			"L 3,0(0,%1)\n\t"
+			"J .+0\n\t"
+			:
+			:"a"(hwcb), "a"(&(hwcb->response_code))
+			:"1", "2", "3");
+#else
+		retval = -EIO
+#endif	
+
+	hwc_data.current_servc = 0;
+	hwc_data.current_hwcb = NULL;
+
+	return retval;
+}
+
+static int set_hwc_ioctls(hwc_ioctls_t *ioctls, char correct)
+{
+	int retval = 0;
+	hwc_ioctls_t tmp;
+	
+	if (ioctls->width_htab > MAX_MESSAGE_SIZE) {
+		if (correct)
+			tmp.width_htab = MAX_MESSAGE_SIZE;
+		else	retval = -EINVAL;
+	} else	tmp.width_htab = ioctls->width_htab;
+
+	tmp.echo = ioctls->echo;
+	
+	if (ioctls->columns > MAX_MESSAGE_SIZE) {
+		if (correct)
+			tmp.columns = MAX_MESSAGE_SIZE;
+		else	retval = -EINVAL;
+	} else	tmp.columns = ioctls->columns;
+
+	
+	switch (ioctls->code) {
+		case CODE_EBCDIC :
+		case CODE_ASCII :
+			tmp.code = ioctls->code;
+			break;
+		default :
+			if (correct)
+				tmp.code = CODE_ASCII;
+			else	retval = -EINVAL;
+	}
+				
+	tmp.final_nl = ioctls->final_nl;
+	
+	if (ioctls->max_hwcb < 2) {
+		if (correct)
+			tmp.max_hwcb = 2;
+		else	retval = -EINVAL;
+	} else	tmp.max_hwcb = ioctls->max_hwcb;
+	
+	tmp.tolower = ioctls->tolower;
+	
+	if (ioctls->kmem_hwcb > ioctls->max_hwcb) {
+		if (correct)
+			tmp.kmem_hwcb = ioctls->max_hwcb;
+		else	retval = -EINVAL;
+	} else	tmp.kmem_hwcb = ioctls->kmem_hwcb;
+	
+	
+	if (ioctls->kmem_hwcb > MAX_KMEM_PAGES) {
+		if (correct)
+			ioctls->kmem_hwcb = MAX_KMEM_PAGES;
+		else	retval = -EINVAL;
+	}
+	
+	if (ioctls->kmem_hwcb < 2) {
+		if (correct)
+			ioctls->kmem_hwcb = 2;
+		else	retval = -EINVAL;
+	}
+	
+	tmp.delim = ioctls->delim;
+
+	
+	if (!(retval < 0))
+		hwc_data.ioctls = tmp;
+
+	return retval;
+}
+
+int hwc_init(unsigned long *kmem_start)
+{
+	int retval;
+#ifdef BUFFER_STRESS_TEST
+
+	init_hwcb_t *hwcb;
+	int i;
+
+#endif
+#ifdef CONFIG_3215
+        if (MACHINE_IS_VM)
+                return kmem_start;
+#endif
+	spin_lock_init(&hwc_data.lock);
+	retval = write_event_mask_1();
+	if (retval < 0)
+		return retval;
+#ifdef USE_VM_DETECTION
+	if (MACHINE_IS_VM) {
+		if (hwc_data.init_ioctls.columns > 76)
+			hwc_data.init_ioctls.columns = 76;
+		hwc_data.init_ioctls.tolower = 1;
+		if (!hwc_data.init_ioctls.delim)
+			hwc_data.init_ioctls.delim = DEFAULT_CASE_DELIMITER;
+	} else {
+		hwc_data.init_ioctls.tolower = 0;
+		hwc_data.init_ioctls.delim = 0;
+	}
+#endif
+	retval = set_hwc_ioctls(&hwc_data.init_ioctls, 1);
+
+	*kmem_start = (*kmem_start + PAGE_SIZE - 1) & -4096L;
+	hwc_data.kmem_start = *kmem_start;
+	*kmem_start += hwc_data.ioctls.kmem_hwcb * PAGE_SIZE;
+	hwc_data.kmem_end = *kmem_start - 1;
+
+        ctl_set_bit(0, 9);
+#ifdef BUFFER_STRESS_TEST 
+	internal_print(
+		DELAYED_WRITE,
+		HWC_RW_PRINT_HEADER 
+		"use %i bytes for buffering.\n", 
+		hwc_data.ioctls.kmem_hwcb * PAGE_SIZE);
+	for (i = 0; i < 500; i++) {
+		hwcb = (init_hwcb_t *) BUF_HWCB;
+		internal_print(
+			DELAYED_WRITE, 
+			HWC_RW_PRINT_HEADER
+			"This is stress test message #%i, free: %i bytes\n", 
+			i, 
+			MAX_HWCB_ROOM - (hwcb->length + sizeof(mto_t)));
+	}
+
+#endif	
+	return retval;
+}
+
+void do_hwc_interrupt(void)
+{
+	spin_lock(&hwc_data.lock);
+	if (!hwc_data.current_servc) {
+		unconditional_read_1();
+	} else {
+		switch (hwc_data.current_servc) {
+			case HWC_CMDW_WRITEMASK :
+				write_event_mask_2();
+				break;
+			
+			case HWC_CMDW_WRITEDATA :
+				write_event_data_2();
+				break;
+
+			case HWC_CMDW_READDATA :
+				unconditional_read_2();
+				break;
+		}		
+		write_event_data_1();
+	}
+	wake_up_hwc_tty();
+	spin_unlock(&hwc_data.lock);
+}
+
+
+int hwc_ioctl(unsigned int cmd, unsigned long arg)
+{
+	hwc_ioctls_t tmp = hwc_data.ioctls;
+	int retval = 0;
+	unsigned long flags;
+	unsigned int obuf;
+	
+	spin_lock_irqsave(&hwc_data.lock, flags);
+	
+	switch (cmd) {
+	   case TIOCHWCSHTAB :
+		if (get_user(tmp.width_htab, (ioctl_htab_t *) arg))
+			goto fault;
+		break;
+	   
+	   case TIOCHWCSECHO :
+                if (get_user(tmp.echo, (ioctl_echo_t *) arg))
+			goto fault;
+		break;
+	   
+	   case TIOCHWCSCOLS :
+                if (get_user(tmp.columns, (ioctl_cols_t *) arg))
+			goto fault;
+		break;
+	   
+	   case TIOCHWCSCODE :
+                if (get_user(tmp.code, (ioctl_code_t *) arg))
+			goto fault;
+
+		break;
+	   
+	   case TIOCHWCSNL :
+                if (get_user(tmp.final_nl, (ioctl_nl_t *) arg))
+			goto fault;
+		break;
+
+	   case TIOCHWCSOBUF :
+                if (get_user(obuf, (unsigned int *) arg))
+			goto fault;
+		if (obuf & 0xFFF)
+			tmp.max_hwcb = (((obuf | 0xFFF) + 1) >> 12);
+		else	tmp.max_hwcb = (obuf >> 12);
+		break;
+
+	   
+	   case TIOCHWCSCASE :
+                if (get_user(tmp.tolower, (ioctl_case_t *) arg))
+			goto fault;
+		break;
+	   
+	   case TIOCHWCSDELIM :
+		if (get_user(tmp.delim, (ioctl_delim_t *) arg))
+			goto fault;
+		break;
+
+	   
+	   case TIOCHWCSINIT :
+		retval = set_hwc_ioctls(&hwc_data.init_ioctls, 1);
+		break;
+
+	   
+	   case TIOCHWCGHTAB :
+		if (put_user(tmp.width_htab, (ioctl_htab_t *) arg))
+			goto fault;
+		break;
+
+	   
+	   case TIOCHWCGECHO :
+                if (put_user(tmp.echo, (ioctl_echo_t *) arg))
+			goto fault;
+		break;
+
+	   
+	   case TIOCHWCGCOLS :
+                if (put_user(tmp.columns, (ioctl_cols_t *) arg))
+			goto fault;
+		break;
+
+	   
+	   case TIOCHWCGCODE :
+                if (put_user(tmp.code, (ioctl_code_t *) arg))
+			goto fault;
+
+		break;
+
+	   
+	   case TIOCHWCGNL :
+                if (put_user(tmp.final_nl, (ioctl_nl_t *) arg))
+			goto fault;
+		break;
+
+	   
+	   case TIOCHWCGOBUF :
+                if (put_user(tmp.max_hwcb, (ioctl_obuf_t *) arg))
+			goto fault;
+		break;
+
+	   
+	   case TIOCHWCGKBUF :
+                if (put_user(tmp.kmem_hwcb, (ioctl_obuf_t *) arg))
+			goto fault;
+		break;
+
+	   
+	   case TIOCHWCGCASE :
+                if (put_user(tmp.tolower, (ioctl_case_t *) arg))
+			goto fault;
+		break;
+	   
+	   case TIOCHWCGDELIM :
+		if (put_user(tmp.delim, (ioctl_delim_t *) arg))
+			goto fault;
+		break;
+#if 0 
+	   
+	   case TIOCHWCGINIT :
+		if (put_user(&hwc_data.init_ioctls, (hwc_ioctls_t *) arg))
+			goto fault;
+		break;
+
+	   
+	   case TIOCHWCGCURR :
+		if (put_user(&hwc_data.ioctls, (hwc_ioctls_t *) arg))
+			goto fault;
+		break;
+#endif
+	   
+	   default :
+		goto noioctlcmd;
+	}
+
+	
+	if (_IOC_DIR(cmd) == _IOC_WRITE)
+		retval = set_hwc_ioctls(&tmp, 0);
+
+	goto out;
+
+	fault:
+		retval = -EFAULT;
+		goto out;
+	noioctlcmd:
+		retval = -ENOIOCTLCMD;
+	out:
+		spin_unlock_irqrestore(&hwc_data.lock, flags);
+		return retval;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/char/hwc_rw.h linux.14p16/drivers/s390/char/hwc_rw.h
--- linux.vanilla/drivers/s390/char/hwc_rw.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/char/hwc_rw.h	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,210 @@
+/*
+ *  drivers/s390/char/hwc_rw.h
+ *    interface to the HWC-read/write driver 
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ */
+
+#ifndef __HWC_RW_H__
+#define __HWC_RW_H__
+
+
+#include <linux/ioctl.h>
+
+
+
+
+
+
+
+#ifndef __HWC_RW_C__
+
+
+
+
+
+
+
+extern int hwc_init(unsigned long *);
+
+
+
+
+
+
+extern int hwc_write(int from_user, const unsigned char *, unsigned int);
+
+
+
+
+
+
+
+extern unsigned int hwc_chars_in_buffer(unsigned char);
+
+
+
+
+
+
+
+extern unsigned int hwc_write_room(unsigned char);
+
+
+
+
+
+
+
+extern void hwc_flush_buffer(unsigned char);
+
+
+
+
+
+
+extern signed int hwc_ioctl(unsigned int, unsigned long);
+
+
+
+
+
+
+
+
+
+extern void do_hwc_interrupt(void);
+
+
+
+
+
+
+extern int hwc_printk(const char *, ...);
+
+#else	
+
+
+
+
+
+extern void store_hwc_input(unsigned char*, unsigned int);
+
+
+
+
+extern void wake_up_hwc_tty(void);
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#define IN_HWCB      1
+#define IN_WRITE_BUF 2
+#define IN_BUFS_TOTAL        (IN_HWCB | IN_WRITE_BUF)
+
+
+
+typedef unsigned short int ioctl_htab_t;
+typedef unsigned char ioctl_echo_t;
+typedef unsigned short int ioctl_cols_t;
+typedef unsigned char ioctl_code_t;
+typedef signed char ioctl_nl_t;
+typedef unsigned short int ioctl_obuf_t;
+typedef unsigned char ioctl_case_t;
+typedef unsigned char ioctl_delim_t;
+
+
+typedef struct {
+	ioctl_htab_t width_htab;
+	ioctl_echo_t echo;
+	ioctl_cols_t columns;
+	ioctl_code_t code;
+	ioctl_nl_t final_nl;
+	ioctl_obuf_t max_hwcb;
+	ioctl_obuf_t kmem_hwcb;		
+	ioctl_case_t tolower;
+	ioctl_delim_t delim;
+} hwc_ioctls_t;
+
+
+
+
+
+
+static hwc_ioctls_t _hwc_ioctls;
+
+
+
+
+
+
+
+#define HWC_IOCTL_LETTER 'B'
+
+
+#define TIOCHWCSHTAB	_IOW(HWC_IOCTL_LETTER, 0, _hwc_ioctls.width_htab)
+
+#define TIOCHWCSECHO	_IOW(HWC_IOCTL_LETTER, 1, _hwc_ioctls.echo)
+
+#define TIOCHWCSCOLS	_IOW(HWC_IOCTL_LETTER, 2, _hwc_ioctls.columns)
+
+#define TIOCHWCSCODE	_IOW(HWC_IOCTL_LETTER, 3, _hwc_ioctls.code)
+
+#define TIOCHWCSNL	_IOW(HWC_IOCTL_LETTER, 4, _hwc_ioctls.final_nl)
+
+#define TIOCHWCSOBUF	_IOW(HWC_IOCTL_LETTER, 5, _hwc_ioctls.max_hwcb)
+
+#define TIOCHWCSINIT	_IO(HWC_IOCTL_LETTER, 6)
+
+#define TIOCHWCSCASE	_IOW(HWC_IOCTL_LETTER, 7, _hwc_ioctls.tolower)
+
+
+#define TIOCHWCSDELIM	_IOW(HWC_IOCTL_LETTER, 9, _hwc_ioctls.delim)
+
+
+#define TIOCHWCGHTAB	_IOR(HWC_IOCTL_LETTER, 10, _hwc_ioctls.width_htab)
+
+#define TIOCHWCGECHO	_IOR(HWC_IOCTL_LETTER, 11, _hwc_ioctls.echo)
+
+#define TIOCHWCGCOLS	_IOR(HWC_IOCTL_LETTER, 12, _hwc_ioctls.columns)
+
+#define TIOCHWCGCODE	_IOR(HWC_IOCTL_LETTER, 13, _hwc_ioctls.code)
+
+#define TIOCHWCGNL	_IOR(HWC_IOCTL_LETTER, 14, _hwc_ioctls.final_nl)
+
+#define TIOCHWCGOBUF	_IOR(HWC_IOCTL_LETTER, 15, _hwc_ioctls.max_hwcb)
+
+#define TIOCHWCGINIT	_IOR(HWC_IOCTL_LETTER, 16, _hwc_ioctls)
+
+#define TIOCHWCGCASE	_IOR(HWC_IOCTL_LETTER, 17, _hwc_ioctls.tolower)
+
+
+#define TIOCHWCGDELIM	_IOR(HWC_IOCTL_LETTER, 19, _hwc_ioctls.delim)
+
+#define TIOCHWCGKBUF	_IOR(HWC_IOCTL_LETTER, 20, _hwc_ioctls.max_hwcb)
+
+#define TIOCHWCGCURR	_IOR(HWC_IOCTL_LETTER, 21, _hwc_ioctls)
+
+
+
+
+#define CODE_ASCII              0x0
+#define CODE_EBCDIC             0x1
+
+
+#endif   
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/char/hwc_tty.c linux.14p16/drivers/s390/char/hwc_tty.c
--- linux.vanilla/drivers/s390/char/hwc_tty.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/char/hwc_tty.c	Wed Dec 15 23:04:36 1999
@@ -0,0 +1,234 @@
+/*
+ *  drivers/s390/char/hwc_tty.c
+ *    HWC line mode terminal driver.
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ *
+ *  Thanks to Martin Schwidefsky.
+ */
+
+#include <linux/major.h>
+#include <linux/termios.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/uaccess.h>
+
+#include "hwc_rw.h"
+
+#define HWC_TTY_PRINT_HEADER "hwc tty driver: "
+#define HWC_TTY_BUF_SIZE 512
+
+typedef struct {
+	struct tty_struct *tty;
+	unsigned char buf[HWC_TTY_BUF_SIZE];
+	unsigned short int buf_count;
+	spinlock_t lock;
+} hwc_tty_data_struct;
+
+static hwc_tty_data_struct hwc_tty_data;
+static struct tty_driver hwc_tty_driver;
+static struct tty_struct * hwc_tty_table[1];
+static struct termios * hwc_tty_termios[1];
+static struct termios * hwc_tty_termios_locked[1];
+static int hwc_tty_refcount = 0;
+
+extern struct termios  tty_std_termios;
+
+static int hwc_tty_open(struct tty_struct *tty,
+                         struct file       *filp)
+{
+	if (MINOR(tty->device) - tty->driver.minor_start)
+		return -ENODEV;
+
+	tty->driver_data = &hwc_tty_data;
+	hwc_tty_data.buf_count = 0;
+	hwc_tty_data.tty = tty;
+	tty->low_latency = 0;
+
+	return 0;
+}
+
+void wake_up_hwc_tty(void)
+{
+	if ((hwc_tty_data.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+			hwc_tty_data.tty->ldisc.write_wakeup)
+		(hwc_tty_data.tty->ldisc.write_wakeup)(hwc_tty_data.tty);
+	wake_up_interruptible(&hwc_tty_data.tty->write_wait);
+}
+
+static void hwc_tty_close(struct tty_struct *tty,
+                           struct file *filp)
+{
+	if (MINOR(tty->device) != tty->driver.minor_start) {
+		printk(KERN_WARNING HWC_TTY_PRINT_HEADER
+			"do not close hwc tty because of wrong device number");
+		return;
+	}
+
+	hwc_tty_data.tty = NULL;
+}
+
+static int hwc_tty_write_room (struct tty_struct *tty)
+{
+	int retval;
+
+	retval = hwc_write_room(IN_BUFS_TOTAL);
+	return retval;
+}
+
+static int hwc_tty_write(struct tty_struct   *tty,
+			  int                  from_user,
+	                  const unsigned char *buf,
+       		          int                  count)
+{
+	int retval;
+
+	if (hwc_tty_data.buf_count > 0)
+	{
+		hwc_write(0, hwc_tty_data.buf, hwc_tty_data.buf_count);
+		hwc_tty_data.buf_count = 0;
+	}
+	retval = hwc_write(from_user, buf, count);
+	return retval;
+}
+
+static void hwc_tty_put_char(struct tty_struct *tty,
+                              unsigned char ch)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hwc_tty_data.lock, flags);
+	if (hwc_tty_data.buf_count >= HWC_TTY_BUF_SIZE)
+	{
+		hwc_write(0, hwc_tty_data.buf, hwc_tty_data.buf_count);
+		hwc_tty_data.buf_count = 0;
+	}
+	hwc_tty_data.buf[hwc_tty_data.buf_count] = ch;
+	hwc_tty_data.buf_count++;
+	spin_unlock_irqrestore(&hwc_tty_data.lock, flags);
+}
+
+static void hwc_tty_flush_chars(struct tty_struct *tty)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hwc_tty_data.lock, flags);
+	hwc_write(0, hwc_tty_data.buf, hwc_tty_data.buf_count);
+	hwc_tty_data.buf_count = 0;
+	spin_unlock_irqrestore(&hwc_tty_data.lock, flags);
+}
+
+
+static int hwc_tty_chars_in_buffer(struct tty_struct *tty)
+{
+	int retval;
+
+	retval = hwc_chars_in_buffer(IN_BUFS_TOTAL);
+	return retval;
+}
+
+static void hwc_tty_flush_buffer(struct tty_struct *tty)
+{
+	wake_up_hwc_tty();
+}
+
+static int hwc_tty_ioctl(
+	struct tty_struct *tty,
+	struct file * file,
+	unsigned int cmd,
+	unsigned long arg)
+{
+        if (tty->flags & (1 << TTY_IO_ERROR))
+                return -EIO;
+
+	return hwc_ioctl(cmd, arg);
+}
+
+void store_hwc_input(unsigned char* buf, unsigned int count)
+{
+	struct tty_struct *tty = hwc_tty_data.tty;
+
+	if (tty != NULL) {
+		if (count == 2 && strncmp(buf, "^c", 2) == 0) {
+			tty->flip.count++;
+			*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+			*tty->flip.char_buf_ptr++ = INTR_CHAR(tty);
+		} else if (count == 2 && strncmp(buf, "^d", 2) == 0) {
+			tty->flip.count++;
+			*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+			*tty->flip.char_buf_ptr++ = EOF_CHAR(tty);
+		} else if (count == 2 && strncmp(buf, "^z", 2) == 0) {
+			tty->flip.count++;
+			*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+			*tty->flip.char_buf_ptr++ = SUSP_CHAR(tty);
+		} else {
+			memcpy(tty->flip.char_buf_ptr, buf, count);
+			if (count < 2 ||
+			    strncmp(buf + count - 2, "^n", 2)) {
+				tty->flip.char_buf_ptr[count] = '\n';
+				count++;
+			} else	count -= 2;
+			memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count);
+			tty->flip.char_buf_ptr += count;
+			tty->flip.flag_buf_ptr += count;
+			tty->flip.count += count;
+		}
+		tty_flip_buffer_push(tty);
+		wake_up_hwc_tty();
+	}
+}
+
+void hwc_tty_init(void)
+{
+	memset (&hwc_tty_driver, 0, sizeof(struct tty_driver));
+	hwc_tty_driver.magic = TTY_DRIVER_MAGIC;
+	hwc_tty_driver.driver_name = "tty_hwc";
+	hwc_tty_driver.name = "ttyS";
+	hwc_tty_driver.name_base = 0;
+	hwc_tty_driver.major = TTY_MAJOR;
+	hwc_tty_driver.minor_start = 64;
+	hwc_tty_driver.num = 1;
+	hwc_tty_driver.type = TTY_DRIVER_TYPE_SYSTEM;
+	hwc_tty_driver.subtype = SYSTEM_TYPE_TTY;
+	hwc_tty_driver.init_termios = tty_std_termios;
+	hwc_tty_driver.init_termios.c_iflag = IGNBRK | IGNPAR;
+	hwc_tty_driver.init_termios.c_oflag = ONLCR;
+	hwc_tty_driver.init_termios.c_lflag = ISIG | ECHO;
+	hwc_tty_driver.flags = TTY_DRIVER_REAL_RAW;
+	hwc_tty_driver.refcount = &hwc_tty_refcount;
+	
+	hwc_tty_driver.table = hwc_tty_table;
+	hwc_tty_driver.termios = hwc_tty_termios;
+	hwc_tty_driver.termios_locked = hwc_tty_termios_locked;
+
+	hwc_tty_driver.open = hwc_tty_open;
+	hwc_tty_driver.close = NULL /* hwc_tty_close */;
+	hwc_tty_driver.write = hwc_tty_write;
+	hwc_tty_driver.put_char = hwc_tty_put_char;
+	hwc_tty_driver.flush_chars = hwc_tty_flush_chars;
+	hwc_tty_driver.write_room = hwc_tty_write_room;
+	hwc_tty_driver.chars_in_buffer = hwc_tty_chars_in_buffer;
+	hwc_tty_driver.flush_buffer = hwc_tty_flush_buffer;
+	hwc_tty_driver.ioctl = hwc_tty_ioctl;
+	
+	hwc_tty_driver.throttle = NULL;
+	hwc_tty_driver.unthrottle = NULL;
+	hwc_tty_driver.send_xchar = NULL;
+	hwc_tty_driver.set_termios = NULL;
+	hwc_tty_driver.set_ldisc = NULL;
+	hwc_tty_driver.stop = NULL; 
+	hwc_tty_driver.start = NULL; 
+	hwc_tty_driver.hangup = NULL;
+	hwc_tty_driver.break_ctl = NULL;
+	hwc_tty_driver.wait_until_sent = NULL;
+	hwc_tty_driver.read_proc = NULL;
+	hwc_tty_driver.write_proc = NULL;
+
+	if (tty_register_driver(&hwc_tty_driver))
+		panic("Couldn't register hwc_tty driver\n");
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/ebcdic.c linux.14p16/drivers/s390/ebcdic.c
--- linux.vanilla/drivers/s390/ebcdic.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/ebcdic.c	Wed Dec 15 22:18:14 1999
@@ -0,0 +1,246 @@
+/*
+ *  arch/s390/kernel/ebcdic.c
+ *    ECBDIC -> ASCII, ASCII -> ECBDIC conversion tables.
+ *
+ *  S390 version
+ *    Copyright (C) 1998 IBM Corporation
+ *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#include <asm/types.h>
+
+/*
+ * ASCII -> EBCDIC
+ */
+__u8 _ascebc[256] =
+{
+ /*00  NL    SH    SX    EX    ET    NQ    AK    BL */
+     0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+ /*08  BS    HT    LF    VT    FF    CR    SO    SI */
+     0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /*10  DL    D1    D2    D3    D4    NK    SN    EB */
+     0x10, 0x11, 0x12, 0x13, 0x3C, 0x15, 0x32, 0x26,
+ /*18  CN    EM    SB    EC    FS    GS    RS    US */
+     0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,
+ /*20  SP     !     "     #     $     %     &     ' */
+     0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+ /*28   (     )     *     +     ,     -    .      / */
+     0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+ /*30   0     1     2     3     4     5     6     7 */
+     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ /*38   8     9     :     ;     <     =     >     ? */
+     0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+ /*40   @     A     B     C     D     E     F     G */
+     0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ /*48   H     I     J     K     L     M     N     O */
+     0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ /*50   P     Q     R     S     T     U     V     W */
+     0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ /*58   X     Y     Z     [     \     ]     ^     _ */
+     0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
+ /*60   `     a     b     c     d     e     f     g */
+     0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ /*68   h     i     j     k     l     m     n     o */
+     0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ /*70   p     q     r     s     t     u     v     w */
+     0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ /*78   x     y     z     {     |     }     ~    DL */
+     0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF
+};
+
+/*
+ * EBCDIC -> ASCII
+ */
+__u8 _ebcasc[256] =
+{
+ /* 0x00   NUL   SOH   STX   ETX  *SEL    HT  *RNL   DEL */
+          0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+ /* 0x08   -GE  -SPS  -RPT    VT    FF    CR    SO    SI */
+          0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /* 0x10   DLE   DC1   DC2   DC3  -RES   -NL    BS  -POC
+                                  -ENP  ->LF             */
+          0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+ /* 0x18   CAN    EM  -UBS  -CU1  -IFS  -IGS  -IRS  -ITB
+                                                    -IUS */
+          0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x20   -DS  -SOS    FS  -WUS  -BYP    LF   ETB   ESC
+                                  -INP                   */
+          0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+ /* 0x28   -SA  -SFE   -SM  -CSP  -MFA   ENQ   ACK   BEL
+                       -SW                               */ 
+          0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+ /* 0x30  ----  ----   SYN   -IR   -PP  -TRN  -NBS   EOT */
+          0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+ /* 0x38  -SBS   -IT  -RFF  -CU3   DC4   NAK  ----   SUB */
+          0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+ /* 0x40    SP   RSP           �ä              ----       */
+          0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+ /* 0x48                       .     <     (     +     | */
+          0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+ /* 0x50     &                                      ---- */
+          0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+ /* 0x58           �ß     !     $     *     )     ;       */
+          0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
+ /* 0x60     -     /  ----     �Ä  ----  ----  ----       */
+          0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+ /* 0x68              ----     ,     %     _     >     ? */ 
+          0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+ /* 0x70  ----        ----  ----  ----  ----  ----  ---- */
+          0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x78     *     `     :     #     @     '     =     " */
+          0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+ /* 0x80     *     a     b     c     d     e     f     g */
+          0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ /* 0x88     h     i              ----  ----  ----       */
+          0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+ /* 0x90     �°     j     k     l     m     n     o     p */
+          0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+ /* 0x98     q     r                    ----        ---- */
+          0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+ /* 0xA0           ~     s     t     u     v     w     x */
+          0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ /* 0xA8     y     z              ----  ----  ----  ---- */
+          0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+ /* 0xB0     ^                    ----     �§  ----       */
+          0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+ /* 0xB8        ----     [     ]  ----  ----  ----  ---- */
+          0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
+ /* 0xC0     {     A     B     C     D     E     F     G */
+          0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ /* 0xC8     H     I  ----           �ö              ---- */
+          0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+ /* 0xD0     }     J     K     L     M     N     O     P */
+          0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ /* 0xD8     Q     R  ----           �ü                   */
+          0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+ /* 0xE0     \           S     T     U     V     W     X */
+          0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ /* 0xE8     Y     Z        ----     �Ö  ----  ----  ---- */
+          0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+ /* 0xF0     0     1     2     3     4     5     6     7 */
+          0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ /* 0xF8     8     9  ----  ----     �Ü  ----  ----  ---- */
+          0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+/*
+ * EBCDIC (capitals) -> ASCII (small case)
+ */
+__u8 _ebcasc_reduce_case[256] =
+{
+ /* 0x00   NUL   SOH   STX   ETX  *SEL    HT  *RNL   DEL */
+          0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+
+ /* 0x08   -GE  -SPS  -RPT    VT    FF    CR    SO    SI */
+          0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+
+ /* 0x10   DLE   DC1   DC2   DC3  -RES   -NL    BS  -POC
+                                  -ENP  ->LF             */
+          0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+
+ /* 0x18   CAN    EM  -UBS  -CU1  -IFS  -IGS  -IRS  -ITB
+                                                    -IUS */
+          0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+
+ /* 0x20   -DS  -SOS    FS  -WUS  -BYP    LF   ETB   ESC
+                                  -INP                   */
+          0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+
+ /* 0x28   -SA  -SFE   -SM  -CSP  -MFA   ENQ   ACK   BEL
+                       -SW                               */ 
+          0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+
+ /* 0x30  ----  ----   SYN   -IR   -PP  -TRN  -NBS   EOT */
+          0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+
+ /* 0x38  -SBS   -IT  -RFF  -CU3   DC4   NAK  ----   SUB */
+          0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+
+ /* 0x40    SP   RSP           �ä              ----       */
+          0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+
+ /* 0x48                       .     <     (     +     | */
+          0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+
+ /* 0x50     &                                      ---- */
+          0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+
+ /* 0x58           �ß     !     $     *     )     ;       */
+          0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
+
+ /* 0x60     -     /  ----     �Ä  ----  ----  ----       */
+          0x2D, 0x2F, 0x07, 0x84, 0x07, 0x07, 0x07, 0x8F,
+
+ /* 0x68              ----     ,     %     _     >     ? */ 
+          0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+
+ /* 0x70  ----        ----  ----  ----  ----  ----  ---- */
+          0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+
+ /* 0x78     *     `     :     #     @     '     =     " */
+          0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+
+ /* 0x80     *     a     b     c     d     e     f     g */
+          0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+
+ /* 0x88     h     i              ----  ----  ----       */
+          0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+
+ /* 0x90     �°     j     k     l     m     n     o     p */
+          0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+
+ /* 0x98     q     r                    ----        ---- */
+          0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+
+ /* 0xA0           ~     s     t     u     v     w     x */
+          0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+
+ /* 0xA8     y     z              ----  ----  ----  ---- */
+          0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+
+ /* 0xB0     ^                    ----     �§  ----       */
+          0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+
+ /* 0xB8        ----     [     ]  ----  ----  ----  ---- */
+          0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
+
+ /* 0xC0     {     A     B     C     D     E     F     G */
+          0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+
+ /* 0xC8     H     I  ----           �ö              ---- */
+          0x68, 0x69, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+
+ /* 0xD0     }     J     K     L     M     N     O     P */
+          0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+
+ /* 0xD8     Q     R  ----           �ü                   */
+          0x71, 0x72, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+
+ /* 0xE0     \           S     T     U     V     W     X */
+          0x5C, 0xF6, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+
+ /* 0xE8     Y     Z        ----     �Ö  ----  ----  ---- */
+          0x79, 0x7A, 0xFD, 0x07, 0x94, 0x07, 0x07, 0x07,
+
+ /* 0xF0     0     1     2     3     4     5     6     7 */
+          0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+
+ /* 0xF8     8     9  ----  ----     �Ü  ----  ----  ---- */
+          0x38, 0x39, 0x07, 0x07, 0x81, 0x07, 0x07, 0x07
+};
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/misc/Makefile linux.14p16/drivers/s390/misc/Makefile
--- linux.vanilla/drivers/s390/misc/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/misc/Makefile	Wed Dec 15 22:18:22 1999
@@ -0,0 +1,8 @@
+all: s390-misc.o
+
+CFLAFS += 
+O_TARGET := s390-misc.o
+O_OBJS    :=         
+M_OBJS   := 
+
+include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/net/Makefile linux.14p16/drivers/s390/net/Makefile
--- linux.vanilla/drivers/s390/net/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/net/Makefile	Wed Dec 15 22:18:22 1999
@@ -0,0 +1,16 @@
+all: s390-net.o
+
+CFLAFS += 
+O_TARGET := s390-net.o
+O_OBJS    :=         
+M_OBJS   :=
+
+ifeq ($(CONFIG_CTC),y)
+  O_OBJS += ctc.o
+endif
+
+ifeq ($(CONFIG_IUCV),y)
+  O_OBJS += iucv.o
+endif
+
+include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/net/ctc.c linux.14p16/drivers/s390/net/ctc.c
--- linux.vanilla/drivers/s390/net/ctc.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/net/ctc.c	Wed Dec 15 22:19:15 1999
@@ -0,0 +1,1408 @@
+/*
+ *  drivers/s390/net/ctc.c 
+ *    CTC / ESCON network driver
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Dieter Wellerdiek (wel@de.ibm.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+
+#include <linux/signal.h>
+#include <linux/string.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/if_arp.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+
+#include <asm/io.h>
+#include <asm/bitops.h>
+ 
+#include "../../../arch/s390/kernel/irq.h"
+
+
+//#define DEBUG 
+
+/* Redefine message level, so that all messages occure on 3215 console in DEBUG mode */
+#ifdef DEBUG                
+        #undef  KERN_INFO
+        #undef  KERN_WARNING
+        #undef  KERN_DEBUG
+        #define KERN_INFO    KERN_EMERG
+        #define KERN_WARNING KERN_EMERG
+        #define KERN_DEBUG   KERN_EMERG
+#endif  
+//#undef DEBUG
+
+#define CCW_CMD_WRITE           0x01
+#define CCW_CMD_READ            0x02
+#define CCW_CMD_SET_EXTENDED    0xc3
+#define CCW_CMD_PREPARE         0xe3
+
+#define MAX_DEVICES             16 
+#define MAX_ADAPTERS            MAX_DEVICES / 2
+#define CTC_DEFAULT_MTU_SIZE    1500
+#define READ                    0
+#define WRITE                   1
+#define CTC                     0
+#define ESCON                   1
+#define CHANNEL_MEDIA           2
+#define CTC_BLOCKS              8          /* 8 blocks * 2 times * 64k = 1M */
+
+#define TB_TX                   0          /* sk buffer handling in process */
+#define TB_STOP                 1          /* network device stop in process */
+#define TB_RETRY                2          /* retry in process */
+#define TB_NOBUFFER             3          /* no buffer on free queue */ 
+
+/* state machine codes used in ctc_irq_handler */
+#define CTC_STOP                0
+#define CTC_START_HALT_IO       1
+#define CTC_START_SET_X_MODE    2
+#define CTC_START_SELECT        4 
+#define CTC_START_READ_TEST     32
+#define CTC_START_READ          33
+#define CTC_START_WRITE_TEST    64
+#define CTC_START_WRITE         65
+
+
+typedef enum { 
+        channel_type_none,           /* Device is not a channel */
+        channel_type_undefined,      /* Device is a channel but we dont know anything about it */
+        channel_type_ctca,           /* Device is a CTC/A and we can deal with it */
+        channel_type_escon,          /* Device is a ESCON channel and we can deal with it */
+        channel_type_unsupported     /* Device is a unsupported model */
+} channel_type_t; 
+  
+
+
+/* 
+ *   Structures needed in the initial phase 
+ *
+ */  
+
+static int channel_tab_initialized = 0;     /* channel[] structure initialized */
+
+struct devicelist {  
+        unsigned int  devno;
+        __u8          flag;
+#define CHANNEL_IN_USE   0x08               /* - Show that channel is in use */
+}; 
+
+static struct {
+        struct devicelist  list[MAX_DEVICES]; 
+        int                count;
+        int                left;
+} channel[CHANNEL_MEDIA];
+
+
+
+static int ctc_no_auto = 0;
+
+struct adapterlist{ 
+        unsigned int       devno[2];
+        __u16              protocol;
+};
+
+static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS];
+
+
+/* 
+ *   Structure used after the initial phase 
+ *
+ */
+    
+struct buffer {
+        struct buffer       *next;
+        int                 packets;
+        struct block        *block;
+};
+
+
+struct channel {
+        unsigned int        devno;
+        int                 irq;
+        int                 IO_active;
+        ccw1_t              ccw[3];
+        __u32               state; 
+        int                 buffer_count;
+        struct buffer       *free_anchor;
+        struct buffer       *proc_anchor;
+        devstat_t           *devstat;
+        struct device       *dev;      /* backward pointer to the network device */ 
+        struct wait_queue   *wait;
+        struct tq_struct    tq;
+        struct timer_list   timer;
+        unsigned long       flag_a;    /* atomic flags */
+#define CTC_BH_ACTIVE       0   
+        __u8                last_dstat;
+        __u8                flag;
+#define CTC_WRITE            0x01      /* - Set if this is a write channel */
+#define CTC_TIMER            0x80      /* - Set if timer made the wake_up  */ 
+};
+
+
+struct ctc_priv {                                                                    
+        struct net_device_stats  stats;
+        struct channel           channel[2]; 
+        __u16                    protocol;
+};  
+
+/*
+ *   This structure works as shuttle between two systems 
+ *    - A block can contain one or more packets 
+ */
+
+#define PACKET_HEADER_LENGTH  6
+struct packet {
+        __u16         length;
+        __u16         type;
+        __u16         unused;
+        __u8          data;
+}; 
+
+#define BLOCK_HEADER_LENGTH   2
+struct block {
+        __u16         length;
+        struct packet data;
+};
+
+
+/* Interrupt handler */
+static void ctc_irq_handler(int irq, void *initparm, struct pt_regs *regs);
+static void ctc_irq_bh(struct channel *ctc); 
+static void ctc_read_retry (struct channel *ctc);
+static void ctc_write_retry (struct channel *ctc);
+
+
+/* Functions for the DEV methods */
+void ctc_setup(char *dev_name, int *ints);
+int ctc_probe(struct device *dev);
+ 
+
+static int ctc_open(struct device *dev); 
+static void ctc_timer (struct channel *ctc);
+static int ctc_release(struct device *dev);
+static int ctc_tx(struct sk_buff *skb, struct device *dev);
+static int ctc_change_mtu(struct device *dev, int new_mtu);
+struct net_device_stats* ctc_stats(struct device *dev); 
+
+
+/*
+ *   Channel Routines 
+ *
+ */ 
+
+static void channel_init(void);
+static void channel_scan(void);
+static int channel_get(int media, int devno);
+static int channel_get_next(int media); 
+static int channel_free(int media, int devno);
+static channel_type_t channel_check_for_type (senseid_t *id);
+static void channel_sort(struct devicelist list[], int n);
+
+
+/*
+ * initialize the channel[].list 
+ */   
+static void channel_init(void) 
+{
+        int     m;
+#ifdef DEBUG
+        int     c;
+#endif
+
+        if (!test_and_set_bit(0, (void *)& channel_tab_initialized)){
+                channel_scan(); 
+                for (m = 0; m < CHANNEL_MEDIA; m++) { 
+                        channel_sort (channel[m].list, MAX_DEVICES); 
+                        channel[m].left = channel[m].count;   
+                }
+                if (channel[CTC].count == 0 && channel[ESCON].count == 0) 
+                        printk(KERN_INFO "channel: no Channel devices recognized\n");
+                else
+                        printk(KERN_INFO "channel: %d Parallel channel found - %d ESCON channel found\n",
+                            channel[CTC].count, channel[ESCON].count);  
+#ifdef DEBUG 
+                for (m = 0; m < CHANNEL_MEDIA;  m++) { 
+                        for (c = 0; c < MAX_DEVICES; c++){
+                                printk(KERN_DEBUG "channel: Adapter=%x Entry=%x devno=%04x\n", 
+                                     m, c, channel[m].list[c].devno);
+                        }
+                }
+#endif
+         }
+}
+
+
+/*
+* scan for all channels and put the device numbers into the channel[].list 
+*/  
+static void channel_scan(void)
+{
+        int        m;
+        int        c;
+        int        irq;
+        dev_info_t temp;
+        
+        for (m = 0; m < CHANNEL_MEDIA;  m++) { 
+                for (c = 0; c < MAX_DEVICES; c++){
+                        channel[m].list[c].devno = -ENODEV;
+                }
+        }
+        
+        for (irq = 0; irq < NR_IRQS; irq++) {
+                /* CTC/A */
+                if (channel[CTC].count < MAX_DEVICES ) {
+                        if (get_dev_info(irq, &temp) == 0 && 
+                            channel_check_for_type(&temp.sid_data) == channel_type_ctca) {
+                                channel[CTC].list[channel[CTC].count].devno = temp.devno; 
+                                channel[CTC].count++; 
+                        }
+                }
+
+                /* ESCON */
+                if (channel[ESCON].count < MAX_DEVICES ) {
+                        if (get_dev_info(irq, &temp) == 0 && 
+                            channel_check_for_type(&temp.sid_data) == channel_type_escon) {
+                                channel[ESCON].list[channel[ESCON].count].devno = temp.devno; 
+                                channel[ESCON].count++; 
+
+                        }
+                }
+        }
+} 
+ 
+
+/*
+ * free specific channel from the channel[].list 
+ */  
+static int channel_free(int media, int devno)
+{
+        int     i;
+
+        for (i = 0; i < channel[media].count; i++) {       
+                if ((devno == channel[media].list[i].devno) &&
+                    ((channel[media].list[i].flag & CHANNEL_IN_USE) != 0x00)) {
+                        channel[media].list[i].flag &= ~CHANNEL_IN_USE;
+                        return 0;
+                }
+        }
+        printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno);
+        return -ENODEV; 
+}
+
+
+/*
+ * get specific channel from the channel[].list 
+ */  
+static int channel_get(int media, int devno)
+{
+        int     i;
+
+        for (i = 0; i < channel[media].count; i++) {       
+                if ((devno == channel[media].list[i].devno) &&
+                    ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00)) {
+                        channel[media].list[i].flag |= CHANNEL_IN_USE;
+                        return channel[media].list[i].devno;             
+                }
+        }
+        printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno);
+        return -ENODEV; 
+
+}
+
+
+/*
+ * get the next free channel from the channel[].list 
+ */  
+static int channel_get_next(int media)
+{
+        int     i;
+
+        for (i = 0; i < channel[media].count; i++) {
+                if ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00) {
+#ifdef DEBUG
+                        printk(KERN_DEBUG "channel: picked=%04x\n", channel[media].list[i].devno);
+#endif
+                        channel[media].list[i].flag |= CHANNEL_IN_USE;
+                        return channel[media].list[i].devno;        
+                }
+        }
+        return -ENODEV; 
+}
+ 
+
+/*
+ * picks the next free channel from the channel[].list 
+ */  
+static int channel_left(int media)
+{
+        return channel[media].left; 
+}
+
+
+/*
+ * defines all devices which are channels
+ */
+static channel_type_t channel_check_for_type (senseid_t *id)
+ {
+        channel_type_t type;
+
+        switch (id->cu_type) {
+                case 0x3088: 
+
+                        switch (id->cu_model) {
+                                case 0x08:    
+                                        type = channel_type_ctca;  /* 3088/08  ==> CTCA */
+                                        break; 
+
+                                case 0x1F:   
+                                        type = channel_type_escon; /* 3088/1F  ==> ESCON channel */
+                                        break;
+ 
+                                case 0x01:                         /* 3088/01  ==> P390 OSA emulation */
+                                case 0x60:                         /* 3088/60  ==> OSA/2 Adapter */
+                                        type = channel_type_unsupported;
+                                         break; 
+
+                                default:
+                                        type = channel_type_undefined;
+                                        printk(KERN_INFO "channel: Unknown model found 3088/%02x\n",id->cu_model);
+                        }
+                        break;
+
+                default:
+                        type = channel_type_none;
+
+        }
+        return type;
+}
+
+
+/*
+ *  sort the channel[].list
+ */
+static void channel_sort(struct devicelist list[], int n)
+{
+        int               i;
+        int               sorted = 0;
+        struct devicelist tmp;
+
+        while (!sorted) { 
+                sorted = 1;
+
+                for (i = 0; i < n-1; i++) {  
+                        if (list[i].devno > list[i+1].devno) {  
+                                tmp = list[i];
+                                list[i] = list[i+1];
+                                list[i+1] = tmp;
+                                sorted = 0;
+                        }
+                }
+        }
+} 
+
+
+/*
+ *   General routines 
+ *
+ */
+
+static int inline extract_channel_id(char *name)
+{
+        if (name[0] == 'c') 
+                return (name[3]-'0');
+        else
+                return (name[5]-'0');
+}
+
+
+static int inline extract_channel_media(char *name)
+{
+        if (name[0] == 'c') 
+                return CTC;
+        else
+                return ESCON;
+}
+
+
+static void ctc_tab_init(void)
+{                                    
+        int          m;
+        int          i;
+        static int   t;
+
+        if (t == 0){
+                for (m = 0; m < CHANNEL_MEDIA;  m++) {
+                        for (i = 0; i < MAX_ADAPTERS;  i++) {
+                                ctc_adapter[m][i].devno[WRITE] = -ENODEV;
+                                ctc_adapter[m][i].devno[READ] = -ENODEV;
+                        }
+                }
+                t = 1; 
+        }
+} 
+
+
+static int ctc_buffer_alloc(struct channel *ctc) {
+        
+        struct buffer    *p;
+        struct buffer    *q;
+
+        p = kmalloc(sizeof(p), GFP_KERNEL);
+        if (p == NULL) 
+                return -ENOMEM;
+        else {  
+                p->next = NULL;  
+                p->packets = 0;
+                p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4);
+                if (p->block == NULL) {
+                        kfree(p);
+                        return -ENOMEM;
+                }
+        }
+   
+        if (ctc->free_anchor == NULL) 
+                ctc->free_anchor = p;  
+        else {  
+                 q = ctc->free_anchor;
+                 while (q->next != NULL) 
+                        q = q->next;
+                 q->next = p;
+        }
+        ctc->buffer_count++;   
+   return 0;
+}
+
+
+static int ctc_buffer_free(struct channel *ctc) {
+        
+        struct buffer    *p;
+
+           
+        if (ctc->free_anchor == NULL)
+                return -ENOMEM;
+        
+        p = ctc->free_anchor; 
+        ctc->free_anchor = p->next;
+        free_pages((__u32)p->block, 4);
+        kfree(p);
+
+        return 0;
+}
+
+
+static int inline ctc_buffer_swap(struct buffer **from, struct buffer **to) {
+        
+        struct buffer    *p = NULL;
+        struct buffer    *q = NULL;
+ 
+        if (*from == NULL)
+                return -ENOMEM; 
+
+        p = *from;
+        *from = p->next;
+        p->next = NULL;
+
+        if (*to == NULL)
+                *to = p;
+        else {
+                q = *to;
+                while (q->next != NULL)
+                        q = q->next;
+                q->next = p;
+
+        }
+        return 0;
+}
+
+
+/*
+ *   ctc_setup function 
+ *     this function is called for each ctc= keyword passed into the kernel 
+ *
+ *     valid parameter are: ctc=n,0xnnnn,0xnnnn,ctcx 
+ *     where n      is the channel protocol always 0 
+ *           0xnnnn is the cu number  read 
+ *           0xnnnn is the cu number  write 
+ *           ctcx can be ctc0 to ctc7 or escon0 to escon7 
+ */
+void ctc_setup(char *dev_name, int *ints)
+{
+        struct adapterlist tmp;
+
+        ctc_tab_init();
+        
+        ctc_no_auto = 1;
+
+        tmp.devno[WRITE] = -ENODEV;
+        tmp.devno[READ] = -ENODEV; 
+
+        switch (ints[0]) {
+              
+                case 3: /* write channel passed */
+                        tmp.devno[WRITE] = ints[3]; 
+                        
+                case 2: /* read channel passed */
+                        tmp.devno[READ] = ints[2];
+                        if (tmp.devno[WRITE] == -ENODEV)
+                                tmp.devno[WRITE] = tmp.devno[READ]++; 
+
+                case 1: /* protocol type passed */
+                        tmp.protocol    = ints[1];
+                        if (tmp.protocol == 0) {
+                                break;    
+                        } else {
+                                printk(KERN_WARNING "%s: wrong Channel protocol type passed\n", dev_name);
+                                return;
+                        }
+
+                default: 
+                        printk(KERN_WARNING "%s: wrong number of parameter passed\n", dev_name);
+                        return;
+        }
+        ctc_adapter[extract_channel_media(dev_name)][extract_channel_id(dev_name)] = tmp; 
+#ifdef DEBUG
+        printk(DEBUG "%s: protocol=%x read=%04x write=%04x\n",
+             dev_name, tmp.protocol, tmp.devno[READ], tmp.devno[WRITE]);
+#endif  
+        return;
+        
+}
+
+
+/*
+ *   ctc_probe 
+ *      this function is called for each channel network device, 
+ *      which is defined in the /init/main.c 
+ */
+int ctc_probe(struct device *dev)
+{       
+        int                rc;
+        int                c;
+        int                i;
+        int                m;
+
+        struct ctc_priv    *privptr;
+
+        /* Only the first time the ctc_probe gets control */
+        if (channel_tab_initialized == 0) {  
+                channel_init();  
+
+
+        }
+        
+        ctc_tab_init();
+
+        m = extract_channel_media(dev->name);
+        i = extract_channel_id(dev->name);
+        
+        if (channel_left(m) <=1) 
+                return -ENODEV;
+
+        dev->priv = kmalloc(sizeof(struct ctc_priv), GFP_KERNEL);
+        if (dev->priv == NULL)
+                return -ENOMEM;
+        memset(dev->priv, 0, sizeof(struct ctc_priv));  
+        privptr = (struct ctc_priv *) (dev->priv);
+
+        
+        for (c = 0; c < 2; c++) {
+                privptr->channel[c].devstat = kmalloc(sizeof(devstat_t), GFP_KERNEL);
+                if (privptr->channel[c].devstat == NULL){
+                        if (i == WRITE)
+                                kfree(privptr->channel[READ].devstat);
+                        return -ENOMEM;  
+                }
+                memset(privptr->channel[c].devstat, 0, sizeof(devstat_t));
+
+                if (ctc_no_auto == 0) 
+                         ctc_adapter[m][i].devno[c] = channel_get_next(m);
+                else 
+                         ctc_adapter[m][i].devno[c] = channel_get(m, ctc_adapter[m][i].devno[c]);
+
+                if ( ctc_adapter[m][i].devno[c] != -ENODEV){
+                         rc = request_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]),
+                              (void *)ctc_irq_handler, SA_INTERRUPT, dev->name, 
+                              privptr->channel[c].devstat);
+                         if (rc) { 
+                                 printk(KERN_WARNING "%s: requested device busy %02x\n", dev->name, rc);
+                                 return -EBUSY;
+                         }
+                } else {        
+                        if (i == WRITE) {
+                                free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]), privptr->channel[i].devstat);
+                                channel_free(m, ctc_adapter[m][i].devno[READ]);
+                                kfree(privptr->channel[READ].devstat);
+                        } 
+                        kfree(privptr->channel[i].devstat);
+                        return -ENODEV;
+                }
+        }
+
+        privptr->channel[READ].devno = ctc_adapter[m][i].devno[READ];
+        privptr->channel[READ].irq = get_irq_by_devno(ctc_adapter[m][i].devno[READ]);
+        privptr->channel[WRITE].devno = ctc_adapter[m][i].devno[WRITE];
+        privptr->channel[WRITE].irq = get_irq_by_devno(ctc_adapter[m][i].devno[WRITE]);
+        privptr->protocol = ctc_adapter[m][i].protocol;
+        channel[m].left = channel[m].left - 2;
+
+        printk(KERN_INFO "%s: read dev: %04x irq: %04x - write dev: %04x irq: %04x \n",
+            dev->name, privptr->channel[READ].devno,   privptr->channel[READ].irq,
+            privptr->channel[WRITE].devno,  privptr->channel[WRITE].irq); 
+
+        dev->mtu             = CTC_DEFAULT_MTU_SIZE;
+        dev->hard_start_xmit = ctc_tx;
+        dev->open            = ctc_open;
+        dev->stop            = ctc_release;
+        dev->get_stats       = ctc_stats;
+        dev->change_mtu      = ctc_change_mtu;
+        dev->hard_header_len = 0;
+        dev->addr_len        = 0;
+        dev->type            = ARPHRD_SLIP;
+        dev->tx_queue_len    = 100;
+        dev_init_buffers(dev);
+        dev->flags           = IFF_POINTOPOINT | IFF_NOARP;   
+
+        return 0;
+} 
+
+
+/*
+ *   Interrupt processing 
+ *
+ */
+
+static void inline ccw_check_return_code (struct device *dev, int return_code)
+{
+        if (return_code != 0) {
+                switch (return_code) {
+                        case -EBUSY:  
+                                printk(KERN_INFO "%s: Busy !\n", dev->name);
+                                break;
+                        case -ENODEV:
+                                printk(KERN_EMERG "%s: Invalid device called for IO\n", dev->name);
+                                break;
+                        case -EIO:
+                                printk(KERN_EMERG "%s: Status pending... \n", dev->name);
+                                break;
+                        default:
+                                printk(KERN_EMERG "%s: Unknown error in Do_IO %04x\n", 
+                                    dev->name, return_code);
+                }
+        }
+} 
+
+
+static void inline ccw_check_unit_check (struct device *dev, char sense)
+{
+#ifdef DEBUG
+        printk(KERN_INFO "%s: Unit Check with sense code: %02x\n",
+            dev->name, sense);
+#endif
+
+        if (sense & 0x40) {
+#ifdef DEBUG
+                if (sense & 0x01) 
+                        printk(KERN_DEBUG "%s: Interface disconnect or Selective reset occurred (remote side)\n", dev->name);
+                else 
+                        printk(KERN_DEBUG "%s: System reset occured (remote side)\n", dev->name);
+#endif
+        } else if (sense & 0x20) {
+                if (sense & 0x04)
+                        printk(KERN_WARNING "%s: Data-streaming timeout)\n", dev->name);
+                else 
+                        printk(KERN_WARNING "%s: Data-transfer parity error\n", dev->name);
+        } else if (sense & 0x10) {
+                if (sense & 0x20)
+                        printk(KERN_WARNING "%s: Hardware malfunction (remote side)\n", dev->name);
+                else 
+                        printk(KERN_WARNING "%s: Read-data parity error (remote side)\n", dev->name);
+        }
+
+} 
+
+
+static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs)
+{
+        int               rc = 0;
+        __u32             parm;
+        __u8              flags = 0x00;
+        struct  channel   *ctc = NULL;
+        struct  ctc_priv  *privptr = NULL;
+        struct  device    *dev = NULL;    
+        
+        ccw1_t            ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL},
+                                               {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; 
+
+        devstat_t *devstat = ((devstat_t *)initparm);
+
+        /* Bypass all 'unsolited interrupts' */
+        if (devstat->intparm == 0) {
+#ifdef DEBUG
+                printk(KERN_DEBUG "ctc: unsolited interrupt for device: %04x received c-%02x d-%02x f-%02x\n",
+                    devstat->devno, devstat->cstat, devstat->dstat, devstat->flag);
+#endif 
+                /* FIXME - find the related intparm!!! No IO outstanding!!!! */
+                return;
+        }
+
+        ctc = (struct channel *) (devstat->intparm);
+        dev = (struct device *) ctc->dev;
+        privptr = dev->priv;
+
+#ifdef DEBUG
+        printk(KERN_DEBUG "%s: interrupt for device: %04x received c-%02x d-%02x f-%02x state-%02x\n",
+            dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag, ctc->state);
+#endif 
+
+        /* Check for good subchannel return code, otherwise error message */
+        if (devstat->cstat) {
+                printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x\n", 
+                    dev->name, ctc->devno, devstat->cstat);
+                return;
+        }
+
+
+        /* Check the reason-code of a unit check */
+        if (devstat->dstat & DEV_STAT_UNIT_CHECK)
+                ccw_check_unit_check(dev, devstat->ii.sense.data[0]);
+
+
+        /* State machine to bring the connection up / down and to restart */ 
+
+        ctc->last_dstat = devstat->dstat;
+
+        switch (ctc->state) {   
+
+                case CTC_STOP:           /* HALT_IO issued by ctc_release (halt sequence) */
+                        if (!devstat->flag & DEVSTAT_FINAL_STATUS)
+                                return;
+                        wake_up(&ctc->wait);   /* wake up ctc_release */
+                        return;
+ 
+
+                case CTC_START_HALT_IO:  /* HALT_IO issued by ctc_open (start sequence) */
+                        if (!devstat->flag & DEVSTAT_FINAL_STATUS)
+                                return;
+
+                        ctc->state = CTC_START_SET_X_MODE;
+                        parm = (__u32) ctc;
+                        rc = do_IO (ctc->irq, &ccw_set_x_mode[0], parm, 0xff, flags);
+                        if (rc != 0)
+                                ccw_check_return_code(dev, rc);
+                        return;
+ 
+        
+                case CTC_START_SET_X_MODE:
+                        if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+                                if ((devstat->ii.sense.data[0] & 0x41) != 0x41 ||
+                                    (devstat->ii.sense.data[0] & 0x40) != 0x40) {
+                                        wake_up(&ctc->wait);  /* wake up ctc_open (READ or WRITE) */
+                                        return; 
+                                }        
+                        }
+                        if (!devstat->flag & DEVSTAT_FINAL_STATUS)
+                                return;
+                        ctc->state =  CTC_START_SELECT;
+ 
+
+                case CTC_START_SELECT:
+                        if (!ctc->flag & CTC_WRITE) {
+                                ctc->state = CTC_START_READ_TEST;
+                                ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
+                                parm = (__u32) ctc;
+                                rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+                                if (rc != 0) 
+                                        ccw_check_return_code(dev, rc);
+                                wake_up(&ctc->wait);  /* wake up ctc_open (READ) */
+
+                        } else {
+                                ctc->state = CTC_START_WRITE_TEST;
+                                /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */
+                                ctc->ccw[1].count = 0;
+                                ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
+                                parm = (__u32) ctc; 
+                                rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags);
+                                if (rc != 0)
+                                        ccw_check_return_code(dev, rc);
+                        }
+                        return;
+
+
+                case CTC_START_READ_TEST:
+                        if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+                                if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
+                                    (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
+                                    devstat->ii.sense.data[0] == 0                ) {
+                                        init_timer(&ctc->timer);
+                                        ctc->timer.function = (void *)ctc_read_retry; 
+                                        ctc->timer.data = (__u32)ctc;
+                                        ctc->timer.expires = jiffies + 10*HZ;
+                                        add_timer(&ctc->timer);
+#ifdef DEBUG 
+                                        printk(KERN_DEBUG "%s: read connection restarted\n",dev->name); 
+#endif
+                                }
+                                return;
+                        }
+
+                        if ((devstat->dstat &  ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
+                                if ((devstat->dstat & DEV_STAT_ATTENTION) && 
+                                    (devstat->dstat & DEV_STAT_BUSY)) {
+                                        printk(KERN_WARNING "%s: read channel is connected with the remote side read channel\n", dev->name);
+                                } 
+                                wake_up(&privptr->channel[WRITE].wait);  /* wake up ctc_open (WRITE) */
+                                return;
+                        }
+
+                        ctc->state = CTC_START_READ;
+                        set_bit(0, (void *)&ctc->IO_active);
+
+                        /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */
+                        /* wake_up(&privptr->channel[WRITE].wait);*/  /* wake up ctc_open (WRITE) */
+
+
+                case CTC_START_READ: 
+                        if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+                                if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
+                                    (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
+                                    devstat->ii.sense.data[0] == 0               ) {
+                                        privptr->stats.rx_errors++;
+                                        set_bit(TB_RETRY, (void *)&dev->tbusy);
+                                        init_timer(&ctc->timer);
+                                        ctc->timer.function = (void *)ctc_read_retry; 
+                                        ctc->timer.data = (__u32)ctc;
+                                        ctc->timer.expires = jiffies + 30*HZ;
+                                        add_timer(&ctc->timer); 
+                                        printk(KERN_INFO "%s: connection restarted!! problem on remote side\n",dev->name);
+                                }
+                                return;
+                        }
+
+                        if(!devstat->flag & DEVSTAT_FINAL_STATUS)
+                                return; 
+
+                        clear_bit(TB_RETRY, (void *)&dev->tbusy);
+                        
+                        ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
+
+                        if (ctc->free_anchor != NULL) {  
+                                ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
+                                parm = (__u32) ctc;
+                                rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+                                if (rc != 0) 
+                                        ccw_check_return_code(dev, rc);
+                        } else {
+                                clear_bit(0, (void *)&ctc->IO_active);    
+#ifdef DEBUG
+                                printk(KERN_DEBUG "%s: No HOT READ started in IRQ\n",dev->name);
+#endif
+                        }
+                        
+                        if (test_and_set_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a) == 0) {
+                                queue_task(&ctc->tq, &tq_immediate);
+                                mark_bh(IMMEDIATE_BH);
+                        }
+                        return;
+
+
+                case CTC_START_WRITE_TEST:
+                        if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+                                if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
+                                    (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
+                                    devstat->ii.sense.data[0] == 0                ) {
+                                        init_timer(&ctc->timer);
+                                        ctc->timer.function = (void *)ctc_write_retry; 
+                                        ctc->timer.data = (__u32)ctc;
+                                        ctc->timer.expires = jiffies + 10*HZ;
+                                        add_timer(&ctc->timer);
+#ifdef DEBUG
+                                        printk(KERN_DEBUG "%s: write connection restarted\n",dev->name);
+#endif
+                                }
+                                return;
+                        }
+
+                        ctc->state = CTC_START_WRITE;
+                        wake_up(&ctc->wait);  /* wake up ctc_open (WRITE) */
+                        return;
+ 
+
+                case CTC_START_WRITE:
+                        if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+                                privptr->stats.tx_errors += ctc->proc_anchor->packets;
+#ifdef DEBUG
+                                printk(KERN_DEBUG "%s: Unit Check on write channel\n",dev->name);
+#endif
+                        } else { 
+                                if (!devstat->flag & DEVSTAT_FINAL_STATUS)
+                                        return; 
+                                privptr->stats.tx_packets += ctc->proc_anchor->packets;
+                        } 
+
+                        ctc->proc_anchor->block->length = 0;
+                        ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
+                        clear_bit(TB_NOBUFFER, (void *)&dev->tbusy);      
+
+                        if (ctc->proc_anchor != NULL) {  
+#ifdef DEBUG
+                                printk(KERN_DEBUG "%s: IRQ early swap buffer\n",dev->name); 
+#endif
+                                ctc->ccw[1].count = ctc->proc_anchor->block->length;
+                                ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->proc_anchor->block);
+                                parm = (__u32) ctc;
+                                rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+                                if (rc != 0) 
+                                        ccw_check_return_code(dev, rc);
+                                dev->trans_start = jiffies;
+                                return;
+
+                        }
+
+                        if (ctc->free_anchor->block->length != 0) {
+                                if (test_and_set_bit(TB_TX, (void *)&dev->tbusy) == 0) {     /* set transmission to busy */
+                                        ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
+                                        clear_bit(TB_TX, (void *)&dev->tbusy);
+#ifdef DEBUG
+                                        printk(KERN_DEBUG "%s: last buffer move in IRQ\n",dev->name); 
+#endif
+                                        ctc->ccw[1].count = ctc->proc_anchor->block->length;
+                                        ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->proc_anchor->block);
+                                        parm = (__u32) ctc;
+                                        rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+                                        if (rc != 0) 
+                                                ccw_check_return_code(dev, rc);
+                                        dev->trans_start = jiffies;
+                                        return;
+                                }
+                        } 
+
+                        clear_bit(0, (void *)&ctc->IO_active);              /* set by ctc_tx or ctc_bh */
+                        return;
+
+ 
+                default: 
+                        printk(KERN_WARNING "%s: wrong selection code - irq\n",dev->name);
+                        return;  
+        }
+} 
+
+
+static void ctc_irq_bh (struct channel *ctc)
+{
+        int                rc = 0;
+        __u16              data_len;
+        __u32              parm;
+
+        __u8               flags = 0x00;
+        __u32              saveflags;
+        struct device      *dev;
+        struct ctc_priv    *privptr;             
+        struct packet      *lp;
+        struct sk_buff     *skb;
+
+        dev = (struct device *) ctc->dev; 
+        privptr = (struct ctc_priv *) dev->priv; 
+   
+#ifdef DEBUG
+        printk(KERN_DEBUG "%s: bh routine - state-%02x\n" ,dev->name, ctc->state);
+#endif 
+
+        while (ctc->proc_anchor != NULL) { 
+
+                lp = &ctc->proc_anchor->block->data;
+
+                while ((__u8 *) lp < (__u8 *) &ctc->proc_anchor->block->length + ctc->proc_anchor->block->length) {
+                        data_len = lp->length - PACKET_HEADER_LENGTH;
+                        skb = dev_alloc_skb(data_len); 
+                        if (skb) { 
+                                memcpy(skb_put(skb, data_len),&lp->data, data_len);
+                                skb->mac.raw = skb->data;
+                                skb->dev = dev;
+                                skb->protocol = htons(ETH_P_IP);
+                                skb->ip_summed = CHECKSUM_UNNECESSARY; /* no UC happend!!! */
+                                netif_rx(skb);
+                                privptr->stats.rx_packets++;
+                        } else {
+                                privptr->stats.rx_dropped++; 
+                                printk(KERN_WARNING "%s: is low on memory\n",dev->name);
+                        }
+                        (__u8 *)lp += lp->length;
+                }
+
+                s390irq_spin_lock_irqsave(ctc->irq, saveflags);
+                ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
+
+                if (test_and_set_bit(0, (void *)&ctc->IO_active) == 0) {
+#ifdef DEBUG
+                        printk(KERN_DEBUG "%s: HOT READ started in bh routine\n" ,dev->name);
+#endif 
+                        ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
+                        parm = (__u32) ctc; 
+                        rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+                        if (rc != 0) 
+                                 ccw_check_return_code(dev, rc);
+                } 
+                s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); 
+        }
+        clear_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a);
+        return;
+}  
+
+
+static void ctc_read_retry (struct channel *ctc)
+{
+        int                rc = 0;
+        __u32              parm;
+        __u8               flags = 0x00;
+        __u32              saveflags;
+        struct device      *dev;
+
+        dev = (struct device *) ctc->dev; 
+   
+#ifdef DEBUG
+        printk(KERN_DEBUG "%s: read retry - state-%02x\n" ,dev->name, ctc->state);
+#endif 
+        s390irq_spin_lock_irqsave(ctc->irq, saveflags);
+        ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
+        parm = (__u32) ctc; 
+        rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+        s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
+        if (rc != 0) 
+                ccw_check_return_code(dev, rc);
+        return;
+}  
+ 
+
+static void ctc_write_retry (struct channel *ctc)
+{
+        int                rc = 0;
+        __u32              parm;
+        __u8               flags = 0x00;
+        __u32              saveflags;
+        struct device      *dev;
+
+        dev = (struct device *) ctc->dev; 
+   
+#ifdef DEBUG
+        printk(KERN_DEBUG "%s: write retry - state-%02x\n" ,dev->name, ctc->state);
+#endif 
+        s390irq_spin_lock_irqsave(ctc->irq, saveflags);
+        ctc->ccw[1].count = 0;
+        ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->proc_anchor->block);
+        parm = (__u32) ctc; 
+        rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+        s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
+        if (rc != 0) 
+                ccw_check_return_code(dev, rc);
+        return;
+}  
+
+
+
+/*
+ *   ctc_open
+ *
+ */
+static int ctc_open(struct device *dev)
+{
+        int                rc;
+        int                i;
+        int                j;
+        __u8               flags = 0x00;
+        __u32              saveflags;
+        __u32              parm;
+        struct ctc_priv    *privptr;
+        struct wait_queue  wait = { current, NULL };
+        struct timer_list  timer;
+
+
+        dev->tbusy = 1;
+        dev->start = 0;
+
+        privptr = (struct ctc_priv *) (dev->priv);
+        
+        privptr->channel[READ].flag  = 0x00;
+        privptr->channel[WRITE].flag = CTC_WRITE;
+
+        for (i = 0; i < 2;  i++) { 
+                for (j = 0; j < CTC_BLOCKS;  j++) { 
+                        rc = ctc_buffer_alloc(&privptr->channel[i]);
+                        if (rc != 0)
+                                return -ENOMEM;
+                }
+                privptr->channel[i].tq.next = NULL;
+                privptr->channel[i].tq.sync = 0;
+                privptr->channel[i].tq.routine = (void *)(void *)ctc_irq_bh;
+                privptr->channel[i].tq.data = &privptr->channel[i]; 
+
+                privptr->channel[i].dev = dev;
+                
+                privptr->channel[i].flag_a = 0;
+
+                privptr->channel[i].ccw[0].cmd_code  = CCW_CMD_PREPARE;
+                privptr->channel[i].ccw[0].flags     = CCW_FLAG_SLI | CCW_FLAG_CC;
+                privptr->channel[i].ccw[0].count     = 0;
+                privptr->channel[i].ccw[0].cda       = NULL;
+                if (i == READ) {  
+                        privptr->channel[i].ccw[1].cmd_code  = CCW_CMD_READ;
+                        privptr->channel[i].ccw[1].flags     = CCW_FLAG_SLI;
+                        privptr->channel[i].ccw[1].count     = 0xffff;   /* MAX size */
+                        privptr->channel[i].ccw[1].cda       = NULL;
+                } else {
+                        privptr->channel[i].ccw[1].cmd_code = CCW_CMD_WRITE;
+                        privptr->channel[i].ccw[1].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
+                        privptr->channel[i].ccw[1].count    = 0;
+                        privptr->channel[i].ccw[1].cda      = NULL;
+                }
+                privptr->channel[i].ccw[2].cmd_code = CCW_CMD_NOOP;      /* jointed CE+DE */
+                privptr->channel[i].ccw[2].flags    = CCW_FLAG_SLI;
+                privptr->channel[i].ccw[2].count    = 0;
+                privptr->channel[i].ccw[2].cda      = NULL;
+                
+                privptr->channel[i].flag  &= ~CTC_TIMER;
+                init_timer(&timer);
+                timer.function = (void *)ctc_timer; 
+                timer.data = (__u32)&privptr->channel[i];
+                timer.expires = jiffies + 150*HZ;                        /* time to connect with the remote side */
+                add_timer(&timer);
+
+                s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
+                parm = (unsigned long) &privptr->channel[i]; 
+                privptr->channel[i].state = CTC_START_HALT_IO;
+                rc = halt_IO(privptr->channel[i].irq, parm, flags);
+                add_wait_queue(&privptr->channel[i].wait, &wait);
+                current->state = TASK_INTERRUPTIBLE;
+                s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
+                schedule();
+                remove_wait_queue(&privptr->channel[i].wait, &wait);
+                if(rc != 0)
+                        ccw_check_return_code(dev, rc);
+                if((privptr->channel[i].flag & CTC_TIMER) == 0x00)
+                        del_timer(&timer);
+        }
+
+        if ((((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & 
+               ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) ||
+            (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CTC_TIMER) != 0x00)) {
+#ifdef DEBUG
+                printk(KERN_DEBUG "%s: channel problems during open - read: %02x -  write: %02x\n",
+                    dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat);
+#endif 
+                printk(KERN_INFO "%s: remote side is currently not ready\n", dev->name);
+                
+                for (i = 0; i < 2;  i++) {
+                        s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
+                        parm = (unsigned long) &privptr->channel[i];
+                        privptr->channel[i].state = CTC_STOP;
+                        rc = halt_IO(privptr->channel[i].irq, parm, flags);
+                        s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
+                        if (rc != 0)
+                                ccw_check_return_code(dev, rc);
+                        for (j = 0; j < CTC_BLOCKS;  j++) 
+                                ctc_buffer_free(&privptr->channel[i]);
+                }
+                return -EIO;
+        }
+
+        printk(KERN_INFO "%s: connected with remote side\n",dev->name);
+        dev->start = 1;
+        dev->tbusy = 0;
+        return 0;
+}
+
+
+static void ctc_timer (struct channel *ctc)
+{
+#ifdef DEBUG
+        struct device      *dev;
+
+        dev = (struct device *) ctc->dev; 
+        printk(KERN_DEBUG "%s: timer return\n" ,dev->name);
+#endif
+        ctc->flag |= CTC_TIMER;
+        wake_up(&ctc->wait);  
+        return;
+}  
+
+/*
+ *   ctc_release 
+ *
+ */
+static int ctc_release(struct device *dev)
+{   
+        int                rc;
+        int                i;
+        int                j;
+        __u8               flags = 0x00;
+        __u32              saveflags;
+        __u32              parm;
+        struct ctc_priv    *privptr;
+        struct wait_queue  wait = { current, NULL }; 
+
+        privptr = (struct ctc_priv *) dev->priv;  
+   
+        dev->start = 0;
+        set_bit(TB_STOP, (void *)&dev->tbusy);    
+        
+        for (i = 0; i < 2;  i++) {
+                s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
+                privptr->channel[i].state = CTC_STOP;
+                parm = (__u32) &privptr->channel[i]; 
+                rc = halt_IO (privptr->channel[i].irq, parm, flags );
+                add_wait_queue(&privptr->channel[i].wait, &wait);
+                current->state = TASK_INTERRUPTIBLE;
+                s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); 
+                schedule();
+                remove_wait_queue(&privptr->channel[i].wait, &wait);
+                if (rc != 0) {
+                        ccw_check_return_code(dev, rc);
+                }
+                 
+                for (j = 0; j < CTC_BLOCKS;  j++) {  
+                        ctc_buffer_swap(&privptr->channel[i].proc_anchor, &privptr->channel[i].free_anchor);
+                        ctc_buffer_free(&privptr->channel[i]); 
+                }
+        }
+
+        if (((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) &
+            ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
+                printk(KERN_WARNING "%s: channel problems during close - read: %02x -  write: %02x\n",
+                    dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat);
+                return -EIO;
+        }
+
+        return 0;
+}  
+
+
+/*
+ *   ctc_tx 
+ *
+ *
+ */
+static int ctc_tx(struct sk_buff *skb, struct device *dev)
+{
+        int                rc;
+        __u32              parm;
+        __u8               flags = 0x00;
+        __u32              saveflags;
+        struct ctc_priv    *privptr;
+        struct packet      *lp;
+   
+        privptr = (struct ctc_priv *) (dev->priv);
+
+        if (skb == NULL) { 
+                printk(KERN_WARNING "%s: NULL pointer as sk_buffer passed\n", dev->name);
+                privptr->stats.tx_dropped++;
+                return -EIO;
+        }
+        
+        if (dev->tbusy != 0) {
+                return -EBUSY;
+        } 
+
+        if (test_and_set_bit(TB_TX, (void *)&dev->tbusy) != 0) {                /* set transmission to busy */
+                return -EBUSY;
+        } 
+
+        if (65535 - privptr->channel[WRITE].free_anchor->block->length - PACKET_HEADER_LENGTH <= skb->len + PACKET_HEADER_LENGTH + 2) {
+#ifdef DEBUG
+                printk(KERN_DEBUG "%s: early swap\n", dev->name);
+#endif
+                s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags);
+                ctc_buffer_swap(&privptr->channel[WRITE].free_anchor, &privptr->channel[WRITE].proc_anchor);
+                s390irq_spin_unlock_irqrestore(privptr->channel[WRITE].irq, saveflags);
+                if (privptr->channel[WRITE].free_anchor == NULL){
+                        set_bit(TB_NOBUFFER, (void *)&dev->tbusy);
+                        clear_bit(TB_TX, (void *)&dev->tbusy);
+                        return -EBUSY;
+                }
+        }
+        
+        if (privptr->channel[WRITE].free_anchor->block->length == 0) {
+                privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH; 
+                privptr->channel[WRITE].free_anchor->packets = 0;
+        } 
+
+
+        (__u8 *)lp = (__u8 *) &privptr->channel[WRITE].free_anchor->block->length + privptr->channel[WRITE].free_anchor->block->length;
+        privptr->channel[WRITE].free_anchor->block->length += skb->len + PACKET_HEADER_LENGTH;
+        lp->length = skb->len + PACKET_HEADER_LENGTH; 
+        lp->type = 0x0800; 
+        lp->unused = 0;
+        memcpy(&lp->data, skb->data, skb->len); 
+        (__u8 *) lp += lp->length; 
+        lp->length = 0;
+        dev_kfree_skb(skb);
+        privptr->channel[WRITE].free_anchor->packets++;
+
+        if (test_and_set_bit(0, (void *)&privptr->channel[WRITE].IO_active) == 0) {
+                s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags);
+                ctc_buffer_swap(&privptr->channel[WRITE].free_anchor,&privptr->channel[WRITE].proc_anchor); 
+                privptr->channel[WRITE].ccw[1].count = privptr->channel[WRITE].proc_anchor->block->length;
+                privptr->channel[WRITE].ccw[1].cda   = (char *)virt_to_phys(privptr->channel[WRITE].proc_anchor->block);
+                parm = (__u32) &privptr->channel[WRITE];  
+                rc = do_IO (privptr->channel[WRITE].irq, &privptr->channel[WRITE].ccw[0], parm, 0xff, flags );
+                if (rc != 0) 
+                        ccw_check_return_code(dev, rc);
+                dev->trans_start = jiffies;
+                s390irq_spin_unlock_irqrestore(privptr->channel[WRITE].irq, saveflags);
+        }
+
+        if (privptr->channel[WRITE].free_anchor == NULL)
+                set_bit(TB_NOBUFFER, (void *)&dev->tbusy);
+
+        clear_bit(TB_TX, (void *)&dev->tbusy);
+        return 0;
+} 
+
+
+/*
+ *   ctc_change_mtu 
+ *
+ *   S/390 can handle MTU sizes from 576 to 32760 for VM, VSE
+ *                                   576 to 65527 for OS/390
+ *
+ */
+static int ctc_change_mtu(struct device *dev, int new_mtu)
+{
+        if ((new_mtu < 576) || (new_mtu > 65528))
+                return -EINVAL;
+        dev->mtu = new_mtu;
+        return 0;
+}
+
+
+/*
+ *   ctc_stats
+ *
+ */
+struct net_device_stats *ctc_stats(struct device *dev)
+{
+         struct ctc_priv *privptr;
+   
+         privptr = dev->priv;
+         return &privptr->stats;
+}  
+
+
+/* Module code goes here */
+
+/*
+                free_irq(privptr->channel[i].irq, privptr->channel[i].devstat);
+                kfree(privptr->channel[i].devstat); 
+
+*/
+/* --- This is the END my friend --- */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/net/iucv.c linux.14p16/drivers/s390/net/iucv.c
--- linux.vanilla/drivers/s390/net/iucv.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/net/iucv.c	Wed Dec 15 22:19:54 1999
@@ -0,0 +1,1110 @@
+/*
+ *  drivers/s390/net/iucv.c
+ *    Network driver for VM using iucv
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Stefan Hegewald <hegewald@de.ibm.com>
+ *               Hartmut Penner <hpenner@de.ibm.com> 
+ */
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>              /* printk()                         */
+#include <linux/malloc.h>              /* kmalloc()                        */
+#include <linux/errno.h>               /* error codes                      */
+#include <linux/types.h>               /* size_t                           */
+#include <linux/interrupt.h>           /* mark_bh                          */
+#include <linux/netdevice.h>           /* struct device, and other headers */
+#include <linux/inetdevice.h>          /* struct device, and other headers */
+#include <linux/if_arp.h>
+#include <linux/rtnetlink.h>
+#include <linux/ip.h>                  /* struct iphdr                     */
+#include <linux/tcp.h>                 /* struct tcphdr                    */
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <asm/checksum.h>
+#include <asm/io.h>
+#include <asm/string.h>
+
+#include "iucv.h"
+
+#define DEBUG123
+#define MAX_DEVICES  10
+
+extern char _ascebc[];
+
+/* 
+ *  global structures 
+ */
+static char iucv_userid[MAX_DEVICES][8];
+static char iucv_ascii_userid[MAX_DEVICES][8];
+static int  iucv_pathid[MAX_DEVICES] = {0};
+static unsigned char iucv_ext_int_buffer[40] __attribute__((aligned (8))) ={0};
+static unsigned char glob_command_buffer[40] __attribute__((aligned (8)));
+struct device iucv_devs[];
+
+
+/* This structure is private to each device. It is used to pass */
+/* packets in and out, so there is place for a packet           */
+struct iucv_priv {
+    struct net_device_stats stats;
+    int packetlen;
+    int status;
+    u8 *packetdata;
+    int pathid;                    /* used device */
+    unsigned char command_buffer[40] __attribute__((aligned (8)));
+    unsigned char ext_int_buffer[40] __attribute__((aligned (8)));
+    u8* receive_buffer;
+    int receive_buffer_len;
+    u8* send_buffer;
+    int send_buffer_len;    
+    char * new_send_buf;       /* send buffer ptr */
+    unsigned char recv_buf[2048];  /* size is just a guess */
+    unsigned char userid[8];
+};
+
+struct iucv_header {
+  short len;
+};
+
+/*
+ * Following the iucv primitives 
+ */
+
+
+extern inline void b2f0(int code,void* parm)
+{
+  asm volatile ("LR    1,%1\n\tLR    0,%0\n\t.long 0xb2f01000" ::
+                "d" (code) ,"a" (parm) :"0", "1");
+}
+
+int iucv_enable(void *parms)
+{
+  MASK_T *parm = parms;
+  memset(parms,0,sizeof(parm));
+  parm->ipmask = 0xF8;
+  b2f0(SETMASK,parm);
+  memset(parms,0,sizeof(parm));
+  parm->ipmask = 0xF8;
+  b2f0(SETCMASK,parm);
+  return parm->iprcode;
+}
+
+
+int iucv_declare_buffer(void *parms, DCLBFR_T *buffer)
+{
+  DCLBFR_T *parm = parms;
+  memset(parms,0,sizeof(parm));
+  parm->ipflags1= 0x00;
+  parm->ipbfadr1 = virt_to_phys(buffer);
+  b2f0(DECLARE_BUFFER, parm);
+  return parm->iprcode;
+}
+
+
+int iucv_retrieve_buffer(void *parms)
+{
+  DCLBFR_T *parm = parms;
+  memset(parms,0x0,sizeof(parm));
+  parm->iprcode = 0x0;
+  b2f0(RETRIEVE_BUFFER, parm);
+  return parm->iprcode;
+}
+
+
+int iucv_connect(void *parms,
+                 const char *userid,
+                 const char *host,
+                 const char *ipusr,
+                 unsigned short * used_pathid)
+{
+  CONNECT_T *parm = parms;                              /* ipflags was 0x60*/
+  memset(parms,0x0,sizeof(parm));
+  parm->ipflags1 = 0x80;
+  parm->ipmsglim = 0x0a;
+  memcpy(parm->ipvmid,userid,8);
+  if (ipusr)
+    memcpy(parm->ipuser,ipusr,16);
+  memcpy(parm->iptarget,host,8);
+  b2f0(CONNECT, parm);
+  *used_pathid = parm->ippathid;
+  return parm->iprcode;
+}
+
+
+
+int iucv_accept(void *parms,int pathid)
+{
+#ifdef DEBUG
+  int i=0;
+#endif
+  ACCEPT_T *parm = parms;
+  memset(parms,0,sizeof(parm));
+  parm->ippathid = pathid;
+  parm->ipflags1 = 0x80;
+  parm->ipmsglim = 0x0a;
+#ifdef DEBUG
+  printk("iucv: iucv_accept input.\n");
+  for (i=0;i<40; i++)
+  {
+    printk("%02x ",((char *)parms)[i]);
+  }
+  printk("\n");
+#endif
+  b2f0(ACCEPT, parm);
+  return parm->iprcode;
+}
+
+
+
+int iucv_receive(void *parms,void *bufferarray,int len)
+{
+#ifdef DEBUG
+  int i=0;
+#endif
+  RECEIVE_T *parm = parms;
+  memset(parms,0x0,sizeof(parm));
+  /*parm->ipflags1 = 0x42;*/
+  parm->ipflags1 = 0x0;
+  parm->ipmsgid  = 0x0;
+  parm->iptrgcls = 0x0;
+  parm->ipbfadr1 = (ULONG) virt_to_phys(bufferarray);
+  parm->ipbfln1f  = len;
+  parm->ipbfln2f  = 0x0;
+  b2f0(RECEIVE, parm);
+  if (parm->iprcode == 0)
+    len = parm->ipbfln1f;
+//  len = len-parm->ipbfln1f;
+#ifdef DEBUG
+  printk("iucv: iucv_receive command input:\n");
+   for (i=0;i<40;i++)  /* show iucv buffer before send */
+    {
+      printk("%02x ",((char *)parms)[i]);
+    }
+  printk("\n");
+
+  printk("iucv: iucv_receive data buffer:\n");
+  for (i=0;i<len;i++)  /* show data received */
+   {
+     printk("%02x ",((char *)bufferarray)[i]);
+   }
+  printk("\n");
+  printk("received length: %02x ",len);
+
+#endif
+  return parm->iprcode;
+}
+
+
+int iucv_send(void *parms,int pathid,void *bufferarray,int len,
+              void *recv_buf, int recv_len)
+{
+#ifdef DEBUG
+  int i=0;
+#endif
+  SEND_T *parm = parms;
+  memset(parms,0x0,sizeof(parm));
+  /*  parm->ipflags1 = 0x48; ??*/
+  parm->ippathid = pathid;
+  parm->ipflags1 = 0x14;                       /* any options ?? */
+  parm->ipmsgid  = 0x0;
+  parm->iptrgcls = 0x0;
+  parm->ipbfadr1 = virt_to_phys(bufferarray);
+  parm->ipbfln1f = len;
+  parm->ipsrccls = 0x0;
+  parm->ipmsgtag = 0x0;
+  parm->ipbfadr2 = virt_to_phys(recv_buf);
+  parm->ipbfln2f = recv_len;
+
+
+#ifdef DEBUG
+  printk("iucv: iucv_send command input:\n");
+  for (i=0;i<40;i++)  /* show iucv buffer before send */
+   {
+     printk("%02x ",((char *)parms)[i]);
+   }
+  printk("\n");
+
+  printk("iucv: iucv_send data buffer:\n");
+  for (i=0;i<len;i++)  /* show send data before send */
+   {
+     printk("%02x ",((char *)bufferarray)[i]);
+   }
+  printk("\n");
+#endif
+
+  b2f0(SEND, parm);
+
+#ifdef DEBUGXX
+ printk("iucv: iucv_send buffer after send:\n");
+ for (i=0;i<len;i++) /* show send buffer after send */
+   {
+     printk("%1x",((char *)bufferarray)[i]);
+   }
+   printk("\n");
+#endif
+
+  return parm->iprcode;
+}
+
+
+
+int iucv_sever(void *parms)
+{
+  SEVER_T *parm = parms;
+  memset(parms,0x0,sizeof(parm));
+  parm->ippathid = 0x0;
+  parm->ipflags1 = 0x0;
+  parm->iprcode  = 0xF;
+  memset(parm->ipuser,0,16);
+  b2f0(SEVER, parm);
+  return parm->iprcode;
+}
+
+
+#ifdef DEBUG
+/*--------------------------*/
+/* Dump buffer formatted    */
+/*--------------------------*/
+static void dumpit(char* buf, int len)
+{
+  int i;
+  for (i=0;i<len;i++) {
+    if (!(i%16)&&i!=0)
+      printk("\n");
+    else if (!(i%4)&&i!=0)
+      printk(" ");
+    printk(  "%02X",buf[i]);
+  }
+  if (len%16)
+    printk(  "\n");
+}
+#endif
+
+
+
+/*--------------------------*/
+/* Get device from pathid   */
+/*--------------------------*/
+struct device * get_device_from_pathid(int pathid)
+{
+   int i;
+    for (i=0;i<=MAX_DEVICES;i++)
+    {
+      if (iucv_pathid[i] == pathid)
+        return &iucv_devs[i];
+    }
+    printk("iucv: get_device_from_pathid: no device for pathid %X\n",pathid);
+ return 0;
+}
+
+
+
+/*--------------------------*/
+/* Get device from userid   */
+/*--------------------------*/
+struct device * get_device_from_userid(char * userid)
+{
+   int i;
+   struct device * dev;
+   struct iucv_priv *privptr;
+      for (i=0;i<=MAX_DEVICES;i++)
+      {
+        dev = &iucv_devs[i];
+        privptr = (struct iucv_priv *)(dev->priv);
+        if (memcmp(privptr->userid,userid,8)==0)
+          return &iucv_devs[i];
+      }
+      printk("iucv: get_device_from_uid: no device for userid %s\n",userid);
+   return 0;
+}
+
+
+/*--------------------------*/
+/* Open iucv Device Driver */
+/*--------------------------*/
+int iucv_open(struct device *dev)
+{
+    int rc;
+    unsigned short iucv_used_pathid;
+    struct iucv_priv *privptr;
+    char iucv_host[8]   ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; 
+    char vmident[16]    ={0xf0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+                          0xf0,0x40,0x40,0x40,0x40,0x40,0x40,0x40};
+
+#ifdef DEBUG
+    printk(  "iucv: iucv_open, device: %s\n",dev->name);
+#endif
+
+    privptr = (struct iucv_priv *)(dev->priv);
+    if(privptr->pathid != -1) {
+       dev->start = 1;
+       dev->tbusy = 0;
+       return 0;
+    }
+    if ((rc = iucv_connect(privptr->command_buffer,
+                           privptr->userid,
+                           iucv_host,
+                           vmident,
+                           &iucv_used_pathid))!=0) {
+      printk(  "iucv: iucv connect failed with rc %X\n",rc);
+      iucv_retrieve_buffer(privptr->command_buffer);
+      return -ENODEV;
+    }
+
+    privptr->pathid = iucv_used_pathid;
+    iucv_pathid[dev-iucv_devs]=privptr->pathid;
+
+#ifdef DEBUG
+    printk(  "iucv: iucv_connect ended with rc: %X\n",rc);
+    printk(  "iucv[%d] pathid %X \n",(int)(dev-iucv_devs),privptr->pathid);
+#endif
+    dev->start = 1;
+    dev->tbusy = 0;
+    return 0;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Receive a packet: retrieve, encapsulate and pass over to upper levels */
+/*-----------------------------------------------------------------------*/
+void iucv_rx(struct device *dev, int len, unsigned char *buf)
+{
+
+  struct sk_buff *skb;
+  struct iucv_priv *privptr = (struct iucv_priv *)dev->priv;
+
+#ifdef DEBUG
+  printk(  "iucv: iucv_rx len: %X, device %s\n",len,dev->name);
+  printk(  "iucv rx: received orig:\n");
+  dumpit(buf,len);
+#endif
+
+  /* strip iucv header now */
+  len = len - 2;   /* short header */
+  buf = buf + 2;   /* short header */
+
+  skb = dev_alloc_skb(len+2); /* why +2 ? alignment ? */
+  if (!skb) {
+    printk(  "iucv rx: low on mem, returning...\n");
+    return;
+  }
+  skb_reserve(skb, 2);                        /* align IP on 16B boundary*/
+  memcpy(skb_put(skb, len), buf, len);
+#ifdef DEBUG
+  printk(  "iucv rx: data before netif_rx()\n");
+  dumpit(buf,len);
+#endif
+
+  /* Write metadata, and then pass to the receive level */
+  skb->mac.raw = skb->data;
+  skb->pkt_type = PACKET_HOST;
+  skb->dev = dev;
+  skb->protocol = htons(ETH_P_IP);
+  skb->ip_summed = CHECKSUM_UNNECESSARY;                /* don't check it*/
+  privptr->stats.rx_packets++;
+  netif_rx(skb);
+
+  return;
+} /* end  iucv_rx() */
+
+
+
+
+/*----------------------------*/
+/* handle interrupts          */
+/*----------------------------*/
+void do_iucv_interrupt(void)
+{
+  int rc;
+  struct in_device *indev;
+  struct in_ifaddr *inaddr;
+  unsigned long len=0;
+  struct device *dev=0;
+  struct iucv_priv *privptr;
+  INTERRUPT_T * extern_int_buffer;
+  unsigned short iucv_data_len=0;
+  unsigned short iucv_next=0;
+  unsigned char * rcvptr;
+  
+  /* get own buffer: */
+  extern_int_buffer = (INTERRUPT_T*) iucv_ext_int_buffer;
+  
+  dev->interrupt = 1;        /* lock ! */
+  
+#ifdef DEBUG
+  printk(  "iucv: do_iucv_interrupt %x received; pathid: %02X\n",
+	   extern_int_buffer->iptype,extern_int_buffer->ippathid);
+  printk(   "iucv: extern_int_buffer:\n");
+  dumpit((char *)&extern_int_buffer[0],40);
+#endif
+  
+  switch (extern_int_buffer->iptype)
+    {
+    case 0x01: /* connection pending ext interrrupt */
+#ifdef DEBUG
+      printk(  "iucv: connection pending IRQ.\n");
+#endif
+      
+      rc = iucv_accept(glob_command_buffer,
+		       extern_int_buffer->ippathid);
+      if (rc != 0) {
+	printk(  "iucv: iucv_accept failed with rc: %X\n",rc);
+	iucv_retrieve_buffer(glob_command_buffer);
+	break;
+      }
+#ifdef DEBUG
+      dumpit(&((char *)extern_int_buffer)[8],8);
+#endif
+      dev = get_device_from_userid(&((char*)extern_int_buffer)[8]);
+      privptr = (struct iucv_priv *)(dev->priv);
+      privptr->pathid =  extern_int_buffer->ippathid;
+      
+#ifdef DEBUG
+      printk(  "iucv: iucv_accept ended with rc: %X\n",rc);
+      printk(  "iucv: device %s found.\n",dev->name);
+#endif
+      break;
+      
+    case 0x02: /* connection completed ext interrrupt */
+      /* set own global IP address */
+      /* & set global routing addr */
+#ifdef DEBUG
+      printk(  "connection completed.\n");
+#endif
+      
+      if( extern_int_buffer->ipmsgtag !=0)
+	{
+	  /* get ptr's to kernel struct with local & broadcast address */
+	  dev = get_device_from_pathid(extern_int_buffer->ippathid);
+	  privptr = (struct iucv_priv *)(dev->priv);
+	  indev = dev->ip_ptr;
+	  inaddr = (struct in_ifaddr*) indev->ifa_list;
+	}
+      break;
+      
+      
+    case 0x03: /* connection severed ext interrrupt */
+      /* we do not handle this one at this time */
+#ifdef DEBUG
+      printk(  "connection severed.\n");
+#endif
+      break;
+      
+      
+    case 0x04: /* connection quiesced ext interrrupt */
+      /* we do not handle this one at this time */
+#ifdef DEBUG
+      printk(  "connection quiesced.\n");
+#endif
+      break;
+      
+      
+    case 0x05: /* connection resumed ext interrrupt */
+      /* we do not handle this one at this time */
+#ifdef DEBUG
+      printk(  "connection resumed.\n");
+#endif
+      break;
+      
+      
+    case 0x06: /* priority message complete ext interrupt */
+    case 0x07: /* non priority message complete ext interrupt */
+      /* send it to iucv_rx for handling */
+#ifdef DEBUG
+      printk(  "message completed.\n");
+#endif
+      
+      if (extern_int_buffer->ipaudit ==0)  /* ok case */
+	{
+#ifdef DEBUG
+	  printk(  "iucv: msg complete interrupt successful, rc: %X\n",
+		   (unsigned int)extern_int_buffer->ipaudit);
+#endif
+	  ;
+	}
+      else
+	{
+	  printk(  "iucv: msg complete interrupt error, rc: %X\n",
+		   (unsigned int)extern_int_buffer->ipaudit);
+	}
+      /* a transmission is over: tell we are no more busy */
+      dev = get_device_from_pathid(extern_int_buffer->ippathid);
+      privptr = (struct iucv_priv *)(dev->priv);
+      privptr->stats.tx_packets++;
+      mark_bh(NET_BH);
+      dev->tbusy = 0;                 /* transmission is no longer busy*/
+      break;
+      
+      
+    case 0x08: /* priority message pending */
+    case 0x09: /* non priority message pending */
+#ifdef DEBUG
+      printk(  "message pending.\n");
+#endif
+      dev = get_device_from_pathid(extern_int_buffer->ippathid);
+      privptr = (struct iucv_priv *)(dev->priv);
+      rcvptr = &privptr->receive_buffer[0];
+      
+      /* re-set receive buffer */
+      memset(privptr->receive_buffer,0,privptr->receive_buffer_len);
+      len = privptr->receive_buffer_len;
+      
+        /* get data now */
+        if (extern_int_buffer->ipflags1 & 0x80)
+	  {  /* data is in the message */
+#ifdef DEBUG
+	    printk(  "iucv: iucv_receive data is in header!\n");
+#endif
+	    memcpy(privptr->receive_buffer,
+		   (char *)extern_int_buffer->iprmmsg1,
+		   (unsigned long)(extern_int_buffer->iprmmsg2));
+	  }
+        else /* data is in buffer, do a receive */
+	  {
+	    rc = iucv_receive(privptr->command_buffer,rcvptr,len);
+	    if (rc != 0  || len == 0)
+	      {
+		printk(  "iucv: iucv_receive failed with rc: %X, length: %lX\n",rc,len);
+		iucv_retrieve_buffer(privptr->command_buffer);
+		break;
+	      }
+	  } /* end else */
+	
+      iucv_next = 0; 
+      /* get next packet offset */  
+      iucv_data_len= *((unsigned short*)rcvptr); 
+        do{ /* until receive buffer is empty, i.e. iucv_next == 0 ! */
+
+        /* get data length:    */
+        iucv_data_len= iucv_data_len - iucv_next;
+	
+#ifdef DEBUG
+        printk(  "iucv: iucv_receive: len is %02X, last: %02X\n",
+		 iucv_data_len,iucv_next);
+#endif
+        /* transmit upstairs */
+        iucv_rx(dev,(iucv_data_len),rcvptr);
+	
+#ifdef DEBUG
+        printk(  "iucv: transaction complete now.\n");
+#endif
+        rcvptr = rcvptr + iucv_data_len;
+        iucv_next = iucv_data_len; 
+        /* get next packet offset */  
+        iucv_data_len= *((unsigned short*)rcvptr);
+	
+      } while (iucv_data_len != 0);
+      dev->tbusy = 0;                 /* transmission is no longer busy*/
+      break;
+      
+    default:
+      printk(  "unknown iucv interrupt \n");
+      break;
+      
+    } /* end switch */
+  dev->interrupt = 0;                                       /* release lock*/
+  
+#ifdef DEBUG
+  printk(  "iucv: leaving do_iucv_interrupt.\n");
+#endif
+  
+}  /* end    do_iucv_interrupt()  */
+
+
+
+/*-------------------------------------------*/
+/*   Transmit a packet (low level interface) */
+/*-------------------------------------------*/
+int iucv_hw_tx(char *send_buf, int len,struct device *dev)
+{
+  /* This function deals with hw details.                         */
+  /* This interface strips off the ethernet header details.       */
+  /* In other words, this function implements the iucv behaviour,*/
+  /* while all other procedures are rather device-independent     */
+  struct iucv_priv *privptr;
+  int rc, recv_len=2000;
+  
+  privptr = (struct iucv_priv *)(dev->priv);
+  
+#ifdef DEBUG
+  printk(  "iucv: iucv_hw_tx, device %s\n",dev->name);
+  printk(  "iucv: hw_TX_data len: %X\n",len);
+  dumpit(send_buf,len);
+#endif
+  
+  /* I am paranoid. Ain't I? */
+  if (len < sizeof(struct iphdr))
+    {
+      printk(  "iucv: Hmm... packet too short (%i octets)\n",len);
+      return -EINVAL;
+    }
+  
+  /*
+   * build IUCV header (preceeding halfword offset)   
+   * works as follows: Each packet is preceded by the 
+   * halfword offset to the next one. 
+   * The last packet is followed by an offset of zero.
+   * E.g., AL2(12),10-byte packet, AL2(34), 32-byte packet, AL2(0)
+   */
+  
+  memcpy(&privptr->send_buffer[2],send_buf,len+2);
+  privptr->send_buffer[len+2] = 0;
+  privptr->send_buffer[len+3] = 0;
+  *((unsigned short*) &privptr->send_buffer[0]) = len + 2;
+  
+#ifdef DEBUG
+  printk(  "iucv: iucv_hw_tx, device %s\n",dev->name);
+  printk(  "iucv: send len: %X\n",len+4);
+  dumpit(privptr->send_buffer,len+4);
+#endif
+  *((unsigned short*) &privptr->send_buffer[0]) = len + 2;
+  
+  /* Ok, now the packet is ready for transmission: send it. */
+  if ((rc = iucv_send(privptr->command_buffer,
+		      privptr->pathid,
+		      &privptr->send_buffer[0],len+4,
+		      privptr->recv_buf,recv_len))!=0) {
+    printk(  "iucv: send_iucv failed, rc: %X\n",rc);
+    iucv_retrieve_buffer(privptr->command_buffer);
+  }
+#ifdef DEBUG
+  printk(  "iucv: send_iucv ended, rc: %X\n",rc);
+#endif
+  return rc;
+} /* end   iucv_hw_tx()  */
+
+
+
+
+
+
+/*------------------------------------------*/
+/* Transmit a packet (called by the kernel) */
+/*------------------------------------------*/
+int iucv_tx(struct sk_buff *skb, struct device *dev)
+{
+    int retval=0;
+
+    struct iucv_priv *privptr;
+
+    if (dev == NULL)
+    {
+      printk("iucv: NULL dev passed\n");
+      return 0;
+    }
+
+    privptr = (struct iucv_priv *) (dev->priv);
+
+    if (skb == NULL)
+    {
+      printk("iucv: %s: NULL buffer passed\n", dev->name);
+      privptr->stats.tx_errors++;
+      return 0;
+    }
+
+#ifdef DEBUG
+    printk(  "iucv: enter iucv_tx, using %s\n",dev->name);
+#endif
+
+    if (dev->tbusy)                                   /* shouldn't happen*/
+    {
+      privptr->stats.tx_errors++;
+      dev_kfree_skb(skb);
+      printk("iucv: %s: transmit access conflict ! leaving iucv_tx.\n", dev->name);
+    }
+
+    dev->tbusy = 1;                                   /* transmission is busy*/
+    dev->trans_start = jiffies;                       /* save the timestamp*/
+
+    /* actual deliver of data is device-specific, and not shown here */
+    retval = iucv_hw_tx(skb->data, skb->len, dev);
+
+    dev_kfree_skb(skb);                               /* release it*/
+
+#ifdef DEBUG
+    printk(  "iucv:leaving iucv_tx, device %s\n",dev->name);
+#endif
+
+    return retval;              /* zero == done; nonzero == fail*/
+}   /* end  iucv_tx( struct sk_buff *skb, struct device *dev)  */
+
+
+
+
+
+
+/*---------------*/
+/* iucv_release */
+/*---------------*/
+int iucv_release(struct device *dev)
+{
+    int rc =0;
+    struct iucv_priv *privptr;
+    privptr = (struct iucv_priv *) (dev->priv);
+
+    dev->start = 0;
+    dev->tbusy = 1;                              /* can't transmit any more*/
+    rc = iucv_sever(privptr->command_buffer);
+    if (rc!=0)
+    {
+       printk("iucv: %s: iucv_release pending...rc:%02x\n",dev->name,rc);
+    }
+
+#ifdef DEBUG
+      printk("iucv: iucv_sever ended with rc: %X\n",rc);
+#endif
+
+    return rc;
+} /* end  iucv_release() */
+
+
+
+
+
+/*-----------------------------------------------*/
+/* Configuration changes (passed on by ifconfig) */
+/*-----------------------------------------------*/
+int iucv_config(struct device *dev, struct ifmap *map)
+{
+   if (dev->flags & IFF_UP)        /* can't act on a running interface*/
+        return -EBUSY;
+
+   /* ignore other fields */
+   return 0;
+}
+/*  end  iucv_config()  */
+
+
+
+
+
+/*----------------*/
+/* Ioctl commands */
+/*----------------*/
+int iucv_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+    printk(  "iucv: device %s; iucv_ioctl\n",dev->name);
+    return 0;
+}
+
+/*---------------------------------*/
+/* Return statistics to the caller */
+/*---------------------------------*/
+struct net_device_stats *iucv_stats(struct device *dev)
+{
+    struct iucv_priv *priv = (struct iucv_priv *)dev->priv;
+#ifdef DEBUG
+    printk(  "iucv: device %s; iucv_stats\n",dev->name);
+#endif
+    return &priv->stats;
+}
+
+
+/*
+ * iucv_change_mtu     
+ * IUCV can handle MTU sizes from 576 to approx. 32000    
+ */
+
+static int iucv_change_mtu(struct device *dev, int new_mtu)
+{
+#ifdef DEBUG
+    printk(  "iucv: device %s; iucv_change_mtu\n",dev->name);
+#endif
+       if ((new_mtu < 64) || (new_mtu > 32000))
+	 return -EINVAL;
+       dev->mtu = new_mtu;
+       return 0;
+}
+
+
+
+
+/*--------------------------------------------*/
+/* The init function (sometimes called probe).*/
+/* It is invoked by register_netdev()         */
+/*--------------------------------------------*/
+int iucv_init(struct device *dev)
+{
+    int rc;
+    struct iucv_priv *privptr;
+
+#ifdef DEBUG
+    printk(  "iucv: iucv_init, device: %s\n",dev->name);
+#endif
+
+    dev->open            = iucv_open;
+    dev->stop            = iucv_release;
+    dev->set_config      = iucv_config;
+    dev->hard_start_xmit = iucv_tx;
+    dev->do_ioctl        = iucv_ioctl;
+    dev->get_stats       = iucv_stats;
+    dev->change_mtu      = iucv_change_mtu;
+
+    /* keep the default flags, just add NOARP */
+
+    dev->hard_header_len = 0;
+    dev->addr_len        = 0;
+    dev->type            = ARPHRD_SLIP;
+    dev->tx_queue_len    = 100;
+    dev->flags           = IFF_NOARP|IFF_POINTOPOINT;
+    dev->mtu    = 4092;
+
+    dev_init_buffers(dev);
+
+    /* Then, allocate the priv field. This encloses the statistics */
+    /* and a few private fields.*/
+    dev->priv = kmalloc(sizeof(struct iucv_priv), GFP_KERNEL);
+    if (dev->priv == NULL){
+       printk(  "iucv: no memory for dev->priv.\n");
+       return -ENOMEM;
+    }
+    memset(dev->priv, 0, sizeof(struct iucv_priv));
+    privptr = (struct iucv_priv *)(dev->priv);
+
+
+    privptr->send_buffer = (u8*) __get_free_pages(GFP_KERNEL+GFP_DMA,8);
+    if (privptr->send_buffer == NULL) {
+      printk(KERN_INFO "%s: could not get pages for send buffer\n",
+	     dev->name);
+      return -ENOMEM;
+    }
+    memset(privptr->send_buffer, 0, 8*PAGE_SIZE);
+    privptr->send_buffer_len=8*PAGE_SIZE;
+    
+    privptr->receive_buffer = (u8*) __get_free_pages(GFP_KERNEL+GFP_DMA,8);
+    if (privptr->receive_buffer == NULL) {
+      printk(KERN_INFO "%s: could not get pages for receive buffer\n",
+	     dev->name);
+      return -ENOMEM;
+    }
+    memset(privptr->receive_buffer, 0, 8*PAGE_SIZE);
+    privptr->receive_buffer_len=8*PAGE_SIZE;
+
+    /* now use the private fields ... */
+    /* init pathid                    */
+    privptr->pathid = -1;
+
+    /* init private userid from global userid */
+    memcpy(privptr->userid,iucv_userid[dev-iucv_devs],8);
+
+
+    /* we can use only ONE buffer for external interrupt ! */
+    rc=iucv_declare_buffer(privptr->command_buffer,
+                           (DCLBFR_T *)iucv_ext_int_buffer);
+    if (rc!=0 && rc!=19)   /* ignore existing buffer */
+      {
+         printk(  "iucv:iucv_declare failed, rc: %X\n",rc);
+         return -ENODEV;
+      }
+
+    rc = iucv_enable(privptr->command_buffer);
+    if (rc!=0)
+    {
+            printk(  "iucv:iucv_enable failed, rc: %x\n",rc);
+            iucv_retrieve_buffer(privptr->command_buffer);
+            return -ENODEV;
+    }
+#ifdef DEBUG
+    printk(  "iucv: iucv_init endend OK for device %s.\n",dev->name);
+#endif
+    return 0;
+}
+
+
+/*
+ * setup iucv devices
+ * 
+ * string passed: iucv=userid1,...,useridn 
+ */
+
+__initfunc(int iucv_setup(char* str, int *ints))
+{
+    int result=0, i=0,j=0, k=0, device_present=0;
+    char *s = str;
+    struct device * dev ={0};
+
+#ifdef DEBUG
+    printk(  "iucv: start registering device(s)... \n");
+#endif
+
+    /*
+     * scan device userids
+     */
+
+    while(*s != 0x20 && *s != '\0'){
+       if(*s == ','){
+          /* fill userid up to 8 chars */
+          for(k=i;k<8;k++){
+             iucv_userid[j][k] = 0x40;
+          } /* end for */
+          /* new device  */
+          j++;
+          s++; /* ignore current char */
+          i=0;
+          if (j>MAX_DEVICES) {
+             printk("iucv: setup devices: max devices %d reached.\n",
+		    MAX_DEVICES);
+             break;
+          } /* end if */
+          continue;
+       } /* end if */
+       iucv_ascii_userid[j][i] = (int)*s;
+       iucv_userid[j][i] = _ascebc[(int)*s++];
+       i++;
+    } /* end while */
+
+    /* 
+     * fill last userid up to 8 chars
+     */
+    for(k=i;k<8;k++) {
+      iucv_userid[j][k] = 0x40;
+    }
+
+    /*
+     * set device name and register
+     */
+
+    for (k=0;k<=j;k++) {
+      memcpy(iucv_devs[k].name, "iucv0", 4);
+      dev = &iucv_devs[k];
+      dev->name[4] = k + '0';
+
+#ifdef DEBUGX
+      printk("iucv: (ASCII- )Userid:%s\n",&iucv_ascii_userid[k][0]);
+      printk("iucv: (ASCII-)Userid: ");
+      for (i=0;i<8;i++) {
+        printk(  "%02X ",(int)iucv_ascii_userid[k][i]);
+      }
+      printk("\n");
+      printk("iucv: (EBCDIC-)Userid: ");
+      for (i=0;i<8;i++) {
+         printk(  "%02X ",(int)iucv_userid[k][i]);
+      }
+      printk("\n");
+      printk("iucv: device name :%s\n",iucv_devs[k].name);
+#endif
+
+      if ( (result = register_netdev(iucv_devs + k)) )
+          printk("iucv: error %i registering device \"%s\"\n",
+                 result, iucv_devs[k].name);
+      else
+      {
+              device_present++;
+      }
+    } /* end for */
+
+#ifdef DEBUG
+    printk(  "iucv: end register devices, %d devices present\n",device_present);
+#endif
+    return device_present ? 0 : -ENODEV;
+}
+
+
+
+
+
+/*-------------*/
+/* The devices */
+/*-------------*/
+char iucv_names[MAX_DEVICES*8]; /* MAX_DEVICES eight-byte buffers */
+struct device iucv_devs[MAX_DEVICES] = {
+    {
+        iucv_names, /* name -- set at load time */
+        0, 0, 0, 0,  /* shmem addresses */
+        0x000,       /* ioport */
+        0,           /* irq line */
+        0, 0, 0,     /* various flags: init to 0 */
+        NULL,        /* next ptr */
+        iucv_init,  /* init function, fill other fields with NULL's */
+    },
+    {
+        iucv_names+8,/* name -- set at load time */
+        0, 0, 0, 0,  /* shmem addresses */
+        0x000,       /* ioport */
+        0,           /* irq line */
+        0, 0, 0,     /* various flags: init to 0 */
+        NULL,        /* next ptr */
+        iucv_init,  /* init function, fill other fields with NULL's */
+    },
+    {
+        iucv_names+16,/* name -- set at load time */
+        0, 0, 0, 0,  /* shmem addresses */
+        0x000,       /* ioport */
+        0,           /* irq line */
+        0, 0, 0,     /* various flags: init to 0 */
+        NULL,        /* next ptr */
+        iucv_init,  /* init function, fill other fields with NULL's */
+    },
+    {
+        iucv_names+24,/* name -- set at load time */
+        0, 0, 0, 0,  /* shmem addresses */
+        0x000,       /* ioport */
+        0,           /* irq line */
+        0, 0, 0,     /* various flags: init to 0 */
+        NULL,        /* next ptr */
+        iucv_init,  /* init function, fill other fields with NULL's */
+    },
+    {
+        iucv_names+32,/* name -- set at load time */
+        0, 0, 0, 0,  /* shmem addresses */
+        0x000,       /* ioport */
+        0,           /* irq line */
+        0, 0, 0,     /* various flags: init to 0 */
+        NULL,        /* next ptr */
+        iucv_init,  /* init function, fill other fields with NULL's */
+    },
+    {
+        iucv_names+40,/* name -- set at load time */
+        0, 0, 0, 0,  /* shmem addresses */
+        0x000,       /* ioport */
+        0,           /* irq line */
+        0, 0, 0,     /* various flags: init to 0 */
+        NULL,        /* next ptr */
+        iucv_init,  /* init function, fill other fields with NULL's */
+    },
+    {
+        iucv_names+48,/* name -- set at load time */
+        0, 0, 0, 0,  /* shmem addresses */
+        0x000,       /* ioport */
+        0,           /* irq line */
+        0, 0, 0,     /* various flags: init to 0 */
+        NULL,        /* next ptr */
+        iucv_init,  /* init function, fill other fields with NULL's */
+    },
+    {
+        iucv_names+56,/* name -- set at load time */
+        0, 0, 0, 0,  /* shmem addresses */
+        0x000,       /* ioport */
+        0,           /* irq line */
+        0, 0, 0,     /* various flags: init to 0 */
+        NULL,        /* next ptr */
+        iucv_init,  /* init function, fill other fields with NULL's */
+    },
+    {
+        iucv_names+64,/* name -- set at load time */
+        0, 0, 0, 0,  /* shmem addresses */
+        0x000,       /* ioport */
+        0,           /* irq line */
+        0, 0, 0,     /* various flags: init to 0 */
+        NULL,        /* next ptr */
+        iucv_init,  /* init function, fill other fields with NULL's */
+    },
+    {
+        iucv_names+72,/* name -- set at load time */
+        0, 0, 0, 0,  /* shmem addresses */
+        0x000,       /* ioport */
+        0,           /* irq line */
+        0, 0, 0,     /* various flags: init to 0 */
+        NULL,        /* next ptr */
+        iucv_init,  /* init function, fill other fields with NULL's */
+    }
+};
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/s390/net/iucv.h linux.14p16/drivers/s390/net/iucv.h
--- linux.vanilla/drivers/s390/net/iucv.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/s390/net/iucv.h	Wed Dec 15 22:20:07 1999
@@ -0,0 +1,146 @@
+/*
+ *  drivers/s390/net/iucv.h
+ *    Network driver for VM using iucv
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Stefan Hegewald <hegewald@de.ibm.com>
+ *               Hartmut Penner <hpenner@de.ibm.com> 
+ */
+
+#ifndef _IUCV_H
+#define _IUCV_H
+
+
+#define UCHAR  unsigned char
+#define USHORT unsigned short
+#define ULONG  unsigned long
+
+#define DEFAULT_BUFFERSIZE  2048
+#define DEFAULT_FN_LENGTH   27
+#define TRANSFERLENGTH      10
+
+
+
+/* function ID's */
+#define RETRIEVE_BUFFER 2
+#define REPLY           3
+#define SEND            4
+#define RECEIVE         5
+#define ACCEPT          10
+#define CONNECT         11
+#define DECLARE_BUFFER  12
+#define SEVER           15
+#define SETMASK         16
+#define SETCMASK        17
+#define PURGE           9999
+
+/* structures */
+typedef struct {
+  USHORT res0;
+  UCHAR  ipflags1;
+  UCHAR  iprcode;
+  ULONG  res1;
+  ULONG  res2;
+  ULONG  ipbfadr1;
+  ULONG  res[6];
+} DCLBFR_T;
+
+typedef struct {
+  USHORT ippathid;
+  UCHAR  ipflags1;
+  UCHAR  iprcode;
+  USHORT ipmsglim;
+  USHORT res1;
+  UCHAR  ipvmid[8];
+  UCHAR  ipuser[16];
+  UCHAR  iptarget[8];
+} CONNECT_T;
+
+typedef struct {
+  USHORT ippathid;
+  UCHAR  ipflags1;
+  UCHAR  iprcode;
+  USHORT ipmsglim;
+  USHORT res1;
+  UCHAR  res2[8];
+  UCHAR  ipuser[16];
+  UCHAR  res3[8];
+} ACCEPT_T;
+
+typedef struct {
+  USHORT ippathid;
+  UCHAR  ipflags1;
+  UCHAR  iprcode;
+  ULONG  ipmsgid;
+  ULONG  iptrgcls;
+  ULONG  ipbfadr1;
+  ULONG  ipbfln1f;
+  ULONG  ipsrccls;
+  ULONG  ipmsgtag;
+  ULONG  ipbfadr2;
+  ULONG  ipbfln2f;
+  ULONG  res;
+} SEND_T;
+
+typedef struct {
+  USHORT ippathid;
+  UCHAR  ipflags1;
+  UCHAR  iprcode;
+  ULONG  ipmsgid;
+  ULONG  iptrgcls;
+  ULONG  iprmmsg1;
+  ULONG  iprmmsg2;
+  ULONG  res1[2];
+  ULONG  ipbfadr2;
+  ULONG  ipbfln2f;
+  ULONG  res2;
+} REPLY_T;
+
+typedef struct {
+  USHORT ippathid;
+  UCHAR  ipflags1;
+  UCHAR  iprcode;
+  ULONG  ipmsgid;
+  ULONG  iptrgcls;
+  ULONG  ipbfadr1;
+  ULONG  ipbfln1f;
+  ULONG  res1[3];
+  ULONG  ipbfln2f;
+  ULONG  res2;
+} RECEIVE_T;
+
+typedef struct {
+  USHORT ippathid;
+  UCHAR  ipflags1;
+  UCHAR  iprcode;
+  ULONG  res1[3];
+  UCHAR  ipuser[16];
+  ULONG  res2[2];
+} SEVER_T;
+
+typedef struct {
+  UCHAR  ipmask;
+  UCHAR  res1[2];
+  UCHAR  iprcode;
+  ULONG  res2[9];
+} MASK_T;
+
+typedef struct {
+  USHORT ippathid;
+  UCHAR  ipflags1;
+  UCHAR  iptype;
+  ULONG  ipmsgid;
+  ULONG  ipaudit;
+  ULONG  iprmmsg1;
+  ULONG  iprmmsg2;
+  ULONG  ipsrccls;
+  ULONG  ipmsgtag;
+  ULONG  ipbfadr2;
+  ULONG  ipbfln2f;
+  UCHAR  ippollfg;
+  UCHAR  res2[3];
+} INTERRUPT_T;
+
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/audio/amd7930.c linux.14p16/drivers/sbus/audio/amd7930.c
--- linux.vanilla/drivers/sbus/audio/amd7930.c	Wed Oct 20 01:12:39 1999
+++ linux.14p16/drivers/sbus/audio/amd7930.c	Thu Dec  9 15:34:12 1999
@@ -135,7 +135,7 @@
 	unsigned char xmit_idle_char;
 
 	/* Callback routine (and argument) when output is done on */
-	void (*output_callback)();
+	void (*output_callback)(void *, unsigned char);
 	void * output_callback_arg;
 
 	/* Current buffer that the driver is recording on channel */
@@ -144,7 +144,7 @@
 	volatile unsigned long input_limit;
 
 	/* Callback routine (and argument) when input is done on */
-	void (*input_callback)();
+	void (*input_callback)(void *, unsigned char, unsigned long);
 	void * input_callback_arg;
 };
 
@@ -520,7 +520,7 @@
 			channel->input_count = 0;
 			if (channel->input_callback)
 				(*channel->input_callback)
-					(channel->input_callback_arg, 1);
+					(channel->input_callback_arg, 1, 0);
 		}
 	}
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/audio/cs4215.h linux.14p16/drivers/sbus/audio/cs4215.h
--- linux.vanilla/drivers/sbus/audio/cs4215.h	Tue Mar 16 00:11:30 1999
+++ linux.14p16/drivers/sbus/audio/cs4215.h	Thu Dec  9 15:34:12 1999
@@ -11,11 +11,12 @@
 struct cs4215 {
 	__u8	data[4];	/* Data mode: Time slots 5-8 */
 	__u8	ctrl[4];	/* Ctrl mode: Time slots 1-4 */
-	__volatile__ struct dbri_mem td;
-	__volatile__ struct dbri_mem rd;
 	__u8	onboard;
-	__u32	status;
-        __u32	version;
+	__volatile__ __u32	status;
+        __volatile__ __u32	version;
+        int offset;
+        int ctrlmode;
+        int datamode;
 };
 
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/audio/cs4231.c linux.14p16/drivers/sbus/audio/cs4231.c
--- linux.vanilla/drivers/sbus/audio/cs4231.c	Wed Oct 20 01:12:40 1999
+++ linux.14p16/drivers/sbus/audio/cs4231.c	Thu Dec  9 15:34:12 1999
@@ -904,8 +904,9 @@
     if (l < 0) l = 0;
   }
 
-  l_adj = l * (CS4231_MAX_GAIN + 1) / (AUDIO_MAX_GAIN + 1);
-  r_adj = r * (CS4231_MAX_GAIN + 1) / (AUDIO_MAX_GAIN + 1);
+  /* See cs4231_play_gain for why we do things this way. -DaveM */
+  l_adj = ((l * (CS4231_MAX_GAIN + 1)) + AUDIO_MAX_GAIN) / (AUDIO_MAX_GAIN + 1);
+  r_adj = ((r * (CS4231_MAX_GAIN + 1)) + AUDIO_MAX_GAIN) / (AUDIO_MAX_GAIN + 1);
   
   CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x0);
   old_gain = CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr));
@@ -932,7 +933,7 @@
   int tmp = 0, r, l, r_adj, l_adj;
   unsigned char old_gain;
 
-  tprintk(("in play_gain: %d %c\n", value, balance));
+  tprintk(("in play_gain: %d %x, ", value, balance));
   r = l = value;
   if (balance < AUDIO_MID_BALANCE) {
     r = (int)(value - ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT));
@@ -942,11 +943,15 @@
     if (l < 0) l = 0;
   }
 
+  /* We have to round up else several OSS programs
+   * get confused because for small increments we
+   * would otherwise not increase the volume ever. -DaveM
+   */
   (l == 0) ? (l_adj = CS4231_MAX_DEV_ATEN) : (l_adj = CS4231_MAX_ATEN - 
-                                              (l * (CS4231_MAX_ATEN + 1) / 
+                              (((l * (CS4231_MAX_ATEN + 1)) + AUDIO_MAX_GAIN) / 
                                                (AUDIO_MAX_GAIN + 1)));
   (r == 0) ? (r_adj = CS4231_MAX_DEV_ATEN) : (r_adj = CS4231_MAX_ATEN -
-                                              (r * (CS4231_MAX_ATEN + 1) /
+                              (((r * (CS4231_MAX_ATEN + 1)) + AUDIO_MAX_GAIN) /
                                                (AUDIO_MAX_GAIN + 1)));
   
   CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x6);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/audio/dbri.c linux.14p16/drivers/sbus/audio/dbri.c
--- linux.vanilla/drivers/sbus/audio/dbri.c	Wed Oct 20 01:12:40 1999
+++ linux.14p16/drivers/sbus/audio/dbri.c	Thu Dec  9 15:34:12 1999
@@ -64,6 +64,7 @@
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/malloc.h>
+#include <linux/ioport.h>
 #include <linux/version.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
@@ -229,7 +230,7 @@
                         dbri->regs->reg8, dbri->regs->reg9)); 
 
 	dbri->regs->reg0 = D_R; /* Soft Reset */
-	for(i = 0; (dbri->regs->reg0 & D_R) && i < 10; i++)
+	for(i = 0; (dbri->regs->reg0 & D_R) && i < 64; i++)
 		udelay(10);
 }
 
@@ -370,9 +371,9 @@
         int rd;
         int status;
         void *buffer;
-        int count;
+        int count = 0;
         void (*callback)(void *, int, unsigned int) = NULL;
-        void *callback_arg;
+        void *callback_arg = NULL;
 
         if ((pipe < 0) || (pipe > 15)) {
                 printk("DBRI: invalid pipe in reception_complete_intr\n");
@@ -804,6 +805,7 @@
         dbri_cmdsend(dbri, cmd);
 }
 
+#if 0
 /* unlink_time_slot()
  *
  * I don't use this function, so it's basically untested.
@@ -865,6 +867,7 @@
 
         dbri_cmdsend(dbri, cmd);
 }
+#endif
 
 /* xmit_fixed() / recv_fixed()
  *
@@ -1475,7 +1478,7 @@
          * codec at this location on the CHI, so return false.
          */
 
-        i = 10;
+        i = 64;
         while (((dbri->mm.status & 0xe4) != 0x20) && --i) udelay(125);
         if (i == 0) {
 		return 0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/char/openprom.c linux.14p16/drivers/sbus/char/openprom.c
--- linux.vanilla/drivers/sbus/char/openprom.c	Wed Oct 20 01:12:40 1999
+++ linux.14p16/drivers/sbus/char/openprom.c	Thu Dec  9 15:34:12 1999
@@ -209,7 +209,7 @@
 				     buf, len);
 		restore_flags(flags);
 
-		if (error <= 0)
+		if (error < 0)
 			error = -EINVAL;
 		break;
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/char/pcikbd.c linux.14p16/drivers/sbus/char/pcikbd.c
--- linux.vanilla/drivers/sbus/char/pcikbd.c	Sat Aug 14 02:26:16 1999
+++ linux.14p16/drivers/sbus/char/pcikbd.c	Thu Dec  9 15:34:12 1999
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.27 1999/05/09 06:40:47 ecd Exp $
+/* $Id: pcikbd.c,v 1.27.2.1 1999/10/01 05:09:36 davem Exp $
  * pcikbd.c: Ultra/AX PC keyboard support.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -934,10 +934,34 @@
 	aux_fasync,
 };
 
+static int aux_no_open(struct inode *inode, struct file *file)
+{
+	return -ENODEV;
+}
+
+struct file_operations psaux_no_fops = {
+	NULL,		/* seek */
+	NULL,
+	NULL,
+	NULL, 		/* readdir */
+	NULL,
+	NULL, 		/* ioctl */
+	NULL,		/* mmap */
+	aux_no_open,
+	NULL,		/* flush */
+	NULL,
+	NULL,
+	NULL,
+};
+
 static struct miscdevice psaux_mouse = {
 	PSMOUSE_MINOR, "ps2aux", &psaux_fops
 };
 
+static struct miscdevice psaux_no_mouse = {
+	PSMOUSE_MINOR, "ps2aux", &psaux_no_fops
+};
+
 __initfunc(int pcimouse_init(void))
 {
 	struct linux_ebus *ebus;
@@ -947,7 +971,7 @@
 	if (pcikbd_mrcoffee) {
 		if ((pcimouse_iobase = pcikbd_iobase) == 0) {
 			printk("pcimouse_init: no 8042 given\n");
-			return -ENODEV;
+			goto do_enodev;
 		}
 		pcimouse_irq = pcikbd_irq;
 	} else {
@@ -962,7 +986,7 @@
 			}
 		}
 		printk("pcimouse_init: no 8042 found\n");
-		return -ENODEV;
+		goto do_enodev;
 
 found:
 		pcimouse_iobase = child->base_address[0];
@@ -987,7 +1011,7 @@
 		        SA_SHIRQ, "mouse", (void *)pcimouse_iobase)) {
 		printk("8042: Cannot register IRQ %s\n",
 		       __irq_itoa(pcimouse_irq));
-		return -ENODEV;
+		goto do_enodev;
 	}
 
 	printk("8042(mouse) at %lx (irq %s)\n", pcimouse_iobase,
@@ -1016,8 +1040,17 @@
 	aux_end_atomic();
 
 	return 0;
+
+do_enodev:
+	misc_register(&psaux_no_mouse);
+	return -ENODEV;
 }
 
+__initfunc(int pcimouse_no_init(void))
+{
+	misc_register(&psaux_no_mouse);
+	return -ENODEV;
+}
 
 __initfunc(int ps2kbd_probe(unsigned long *memory_start))
 {
@@ -1034,7 +1067,7 @@
 	len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
 	if (len < 0) {
 		printk("ps2kbd_probe: no name of root node\n");
-		return -ENODEV;
+		goto do_enodev;
 	}
 	if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) {
 		pcikbd_mrcoffee = 1;	/* Brain damage detected */
@@ -1047,7 +1080,7 @@
         node = prom_getchild(prom_root_node);
 	node = prom_searchsiblings(node, "aliases");
 	if (!node)
-		return -ENODEV;
+		goto do_enodev;
 
 	len = prom_getproperty(node, "keyboard", prop, sizeof(prop));
 	if (len > 0) {
@@ -1055,7 +1088,7 @@
 		kbnode = prom_finddevice(prop);
 	}
 	if (!kbnode)
-		return -ENODEV;
+		goto do_enodev;
 
 	len = prom_getproperty(node, "mouse", prop, sizeof(prop));
 	if (len > 0) {
@@ -1063,7 +1096,7 @@
 		msnode = prom_finddevice(prop);
 	}
 	if (!msnode)
-		return -ENODEV;
+		goto do_enodev;
 
 	/*
 	 * Find matching EBus nodes...
@@ -1131,6 +1164,8 @@
 		pnode = prom_getsibling(pnode);
 		pnode = prom_searchsiblings(pnode, "pci");
 	}
+do_enodev:
+	sunkbd_setinitfunc(memory_start, pcimouse_no_init);
 	return -ENODEV;
 
 found:
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/char/sab82532.c linux.14p16/drivers/sbus/char/sab82532.c
--- linux.vanilla/drivers/sbus/char/sab82532.c	Thu Mar 25 17:23:34 1999
+++ linux.14p16/drivers/sbus/char/sab82532.c	Thu Dec  9 15:34:12 1999
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.30 1999/03/24 11:34:52 davem Exp $
+/* $Id: sab82532.c,v 1.30.2.2 1999/10/12 14:11:20 davem Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -36,6 +36,12 @@
 
 static DECLARE_TASK_QUEUE(tq_serial);
 
+/* This is (one of many) a special gross hack to allow SU and
+ * SAB serials to co-exist on the same machine. -DaveM
+ */
+#undef SERIAL_BH
+#define SERIAL_BH	AURORA_BH
+
 static struct tty_driver serial_driver, callout_driver;
 static int sab82532_refcount;
 
@@ -250,6 +256,8 @@
 static void batten_down_hatches(struct sab82532 *info)
 {
 	unsigned char saved_rfc;
+	
+	if (!stop_a_enabled) return;
 
 	/* If we are doing kadb, we call the debugger
 	 * else we just drop into the boot monitor.
@@ -2136,7 +2144,7 @@
 
 __initfunc(static inline void show_serial_version(void))
 {
-	char *revision = "$Revision: 1.30 $";
+	char *revision = "$Revision: 1.30.2.2 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -2146,6 +2154,8 @@
 	printk("SAB82532 serial driver version %s\n", serial_version);
 }
 
+extern int su_num_ports;
+
 /*
  * The serial driver boot-time initialization code!
  */
@@ -2169,7 +2179,7 @@
 	serial_driver.driver_name = "serial";
 	serial_driver.name = "ttyS";
 	serial_driver.major = TTY_MAJOR;
-	serial_driver.minor_start = 64;
+	serial_driver.minor_start = 64 + su_num_ports;
 	serial_driver.num = NR_PORTS;
 	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
 	serial_driver.subtype = SERIAL_TYPE_NORMAL;
@@ -2267,7 +2277,7 @@
 	
 		printk(KERN_INFO
 		       "ttyS%02d at 0x%lx (irq = %s) is a SAB82532 %s\n",
-		       info->line, (unsigned long)info->regs,
+		       info->line + su_num_ports, (unsigned long)info->regs,
 		       __irq_itoa(info->irq), sab82532_version[info->type]);
 	}
 
@@ -2565,8 +2575,9 @@
 __initfunc(int sab82532_console_init(void))
 {
 	extern int con_is_present(void);
+	extern int su_console_registered;
 
-	if (con_is_present())
+	if (con_is_present() || su_console_registered)
 		return 0;
 
 	if (!sab82532_chain) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/char/su.c linux.14p16/drivers/sbus/char/su.c
--- linux.vanilla/drivers/sbus/char/su.c	Tue Mar 16 00:11:30 1999
+++ linux.14p16/drivers/sbus/char/su.c	Thu Dec  9 15:34:12 1999
@@ -1,8 +1,8 @@
-/* $Id: su.c,v 1.18 1999/01/02 16:47:37 davem Exp $
+/* $Id: su.c,v 1.18.2.5 1999/10/14 08:44:35 davem Exp $
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- * Coypright (C) 1998  Pete Zaitcev   (zaitcev@metabyte.com)
+ * Copyright (C) 1998-1999  Pete Zaitcev   (zaitcev@metabyte.com)
  *
  * This is mainly a variation of drivers/char/serial.c,
  * credits go to authors mentioned therein.
@@ -92,6 +92,11 @@
 int su_serial_console_init(void);
 #endif
 
+enum su_type { SU_PORT_NONE, SU_PORT_MS, SU_PORT_KBD, SU_PORT_PORT };
+static char *su_typev[] = { "???", "mouse", "kbd", "serial" };
+
+#define SU_PROPSIZE	128
+
 /*
  * serial.c saves memory when it allocates async_info upon first open.
  * We have parts of state structure together because we do call startup
@@ -107,8 +112,8 @@
 	int		 line;
 	int		 cflag;
 
-	int		 kbd_node;
-	int		 ms_node;
+	enum su_type	 port_type;	/* Hookup type: e.g. mouse */
+	int		 is_console;
 	int		 port_node;
 
 	char		 name[16];
@@ -145,6 +150,18 @@
 	unsigned long		last_active;	/* For async_struct, to be */
 };
 
+/*
+ * Scan status structure.
+ * "prop" is a local variable but it eats stack to keep it in each
+ * stack frame of a recursive procedure.
+ */
+struct su_probe_scan {
+	int msnode, kbnode;	/* PROM nodes for mouse and keyboard */
+	int msx, kbx;		/* minors for mouse and keyboard */
+	int devices;		/* scan index */
+	char prop[SU_PROPSIZE];
+};
+
 static char *serial_name = "PCIO serial driver";
 static char serial_version[16];
 
@@ -223,8 +240,6 @@
 	return 0;
 }
 
-#ifdef __sparc_v9__
-
 static inline
 unsigned int su_inb(struct su_struct *info, unsigned long offset)
 {
@@ -234,20 +249,7 @@
 static inline void
 su_outb(struct su_struct *info, unsigned long offset, int value)
 {
-	outb(value, info->port + offset);
-}
-
-#else
-
-static inline
-unsigned int su_inb(struct su_struct *info, unsigned long offset)
-{
-	return (unsigned int)(*(volatile unsigned char *)(info->port + offset));
-}
-
-static inline void
-su_outb(struct su_struct *info, unsigned long offset, int value)
-{
+#ifndef __sparc_v9__
 	/*
 	 * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are
 	 * connected with a gate then go to SlavIO. When IRQ4 goes tristated
@@ -257,10 +259,9 @@
 	 * This problem is similar to what Alpha people suffer, see serial.c.
 	 */
 	if (offset == UART_MCR) value |= UART_MCR_OUT2;
-	*(volatile unsigned char *)(info->port + offset) = value;
-}
-
 #endif
+	outb(value, info->port + offset);
+}
 
 #define serial_in(info, off)		su_inb(info, off)
 #define serial_inp(info, off)		su_inb(info, off)
@@ -341,14 +342,14 @@
 }
 
 static __inline__ void
-receive_kbd_ms_chars(struct su_struct *info, struct pt_regs *regs)
+receive_kbd_ms_chars(struct su_struct *info, struct pt_regs *regs, int is_brk)
 {
 	unsigned char status = 0;
 	unsigned char ch;
 
 	do {
 		ch = serial_inp(info, UART_RX);
-		if (info->kbd_node) {
+		if (info->port_type == SU_PORT_KBD) {
 			if(ch == SUNKBD_RESET) {
                         	l1a_state.kbd_id = 1;
                         	l1a_state.l1_down = 0;
@@ -368,7 +369,7 @@
                 	}
                 	sunkbd_inchar(ch, regs);
 		} else {
-			sun_mouse_inbyte(ch);
+			sun_mouse_inbyte(ch, is_brk);
 		}
 
 		status = su_inb(info, UART_LSR);
@@ -380,12 +381,15 @@
 {
 	struct tty_struct *tty = info->tty;
 	unsigned char ch;
-	int ignored = 0;
+	int ignored = 0, saw_console_brk = 0;
 	struct	async_icount *icount;
 
 	icount = &info->icount;
 	do {
 		ch = serial_inp(info, UART_RX);
+		if (info->is_console &&
+		    (ch == 0 || (*status &UART_LSR_BI)))
+			saw_console_brk = 1;
 		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
 			break;
 		*tty->flip.char_buf_ptr = ch;
@@ -461,6 +465,8 @@
 	printk("E%02x.R%d", *status, tty->flip.count);
 #endif
 	tty_flip_buffer_push(tty);
+	if (saw_console_brk != 0)
+		batten_down_hatches();
 }
 
 static __inline__ void
@@ -529,7 +535,7 @@
 			    (status & UART_MSR_DCD))
 				hardpps();
 #endif
-	}
+		}
 		if (status & UART_MSR_DCTS)
 			icount->cts++;
 		wake_up_interruptible(&info->delta_msr_wait);
@@ -598,8 +604,9 @@
 #ifdef SERIAL_DEBUG_INTR
 	printk("status = %x...", status);
 #endif
-	if (status & UART_LSR_DR)
-		receive_kbd_ms_chars(info, regs);
+	if ((status & UART_LSR_DR) || (status & UART_LSR_BI))
+		receive_kbd_ms_chars(info, regs,
+				     (status & UART_LSR_BI) != 0);
 
 #ifdef SERIAL_DEBUG_INTR
 	printk("end.\n");
@@ -775,7 +782,7 @@
 	/*
 	 * Allocate the IRQ if necessary
 	 */
-	if (info->kbd_node || info->ms_node) {
+	if (info->port_type != SU_PORT_PORT) {
 		retval = request_irq(info->irq, su_kbd_ms_interrupt,
 				     SA_SHIRQ, info->name, info);
 	} else {
@@ -956,7 +963,7 @@
 	int		bits;
 	unsigned long	flags;
 
-	if (!info->kbd_node && !info->ms_node) {
+	if (info->port_type == SU_PORT_PORT) {
 		if (!info->tty || !info->tty->termios)
 			return;
 		if (!info->port)
@@ -1133,9 +1140,9 @@
 	struct su_struct *info = su_table;
 	int lsr;
 
-	if (!info->kbd_node)
+	if (info->port_type != SU_PORT_KBD)
 		++info;
-	if (!info)
+	if (info->port_type != SU_PORT_KBD)
 		return;
 
 	do {
@@ -1151,9 +1158,9 @@
 {
 	struct su_struct *info = su_table;
 
-	if (!info->ms_node)
+	if (info->port_type != SU_PORT_MS)
 		++info;
-	if (!info)
+	if (info->port_type != SU_PORT_MS)
 		return;
 
 	info->cflag &= ~(CBAUDEX | CBAUD);
@@ -2026,6 +2033,8 @@
 	if ((line < 0) || (line >= NR_PORTS))
 		return -ENODEV;
 	info = su_table + line;
+	if (info->type == PORT_UNKNOWN)
+		return -ENODEV;
 	info->count++;
 	tty->driver_data = info;
 	info->tty = tty;
@@ -2202,9 +2211,9 @@
 
 /*
  * ---------------------------------------------------------------------
- * su_init() and friends
+ * su_XXX_init() and friends
  *
- * su_init() is called at boot-time to initialize the serial driver.
+ * su_XXX_init() is called at boot-time to initialize the serial driver.
  * ---------------------------------------------------------------------
  */
 
@@ -2215,7 +2224,7 @@
  */
 __initfunc(static __inline__ void show_su_version(void))
 {
-	char *revision = "$Revision: 1.18 $";
+	char *revision = "$Revision: 1.18.2.5 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -2226,8 +2235,8 @@
 }
 
 /*
- * This routine is called by su_init() to initialize a specific serial
- * port.  It determines what type of UART chip this serial port is
+ * This routine is called by su_{serial|kbd_ms}_init() to initialize a specific
+ * serial port.  It determines what type of UART chip this serial port is
  * using: 8250, 16450, 16550, 16550A.  The important question is
  * whether or not this UART is a 16550A, since this will determine
  * whether or not we can use its FIFO features.
@@ -2236,38 +2245,38 @@
 autoconfig(struct su_struct *info)
 {
 	unsigned char status1, status2, scratch, scratch2;
-#ifdef __sparc_v9__
 	struct linux_ebus_device *dev = 0;
 	struct linux_ebus *ebus;
-#else
+#ifndef __sparc_v9__
 	struct linux_prom_registers reg0;
 #endif
 	unsigned long flags;
 
-#ifdef __sparc_v9__
+	if (!info->port_node || !info->port_type)
+		return;
+
+	/*
+	 * First we look for Ebus-bases su's
+	 */
 	for_each_ebus(ebus) {
 		for_each_ebusdev(dev, ebus) {
-			if (!strncmp(dev->prom_name, "su", 2)) {
-				if (dev->prom_node == info->kbd_node)
-					goto ebus_done;
-				if (dev->prom_node == info->ms_node)
-					goto ebus_done;
+			if (dev->prom_node == info->port_node) {
+				info->port = dev->base_address[0];
+				info->irq = dev->irqs[0];
+				goto ebus_done;
 			}
 		}
 	}
-ebus_done:
-	if (!dev)
-		return;
-
-	info->port = dev->base_address[0];
-	if (check_region(info->port, 8))
-		return;
 
-	info->irq = dev->irqs[0];
+#ifdef __sparc_v9__
+	/*
+	 * Not on Ebus, bailing.
+	 */
+	return;
 #else
-	if (!info->port_node)
-		return;
-
+	/*
+	 * Not on Ebus, must be OBIO.
+	 */
 	if (prom_getproperty(info->port_node, "reg",
 	    (char *)&reg0, sizeof(reg0)) == -1) {
 		prom_printf("su: no \"reg\" property\n");
@@ -2279,21 +2288,24 @@
 		prom_printf("su: cannot map\n");
 		return;
 	}
+
 	/*
-	 * There is no intr property on MrCoffee, so hardwire it. Krups?
+	 * There is no intr property on MrCoffee, so hardwire it.
 	 */
 	info->irq = IRQ_4M(13);
 #endif
 
-#ifdef DEBUG_SERIAL_OPEN
-	printk("Found 'su' at %016lx IRQ %s\n", dev->base_address[0],
-	       __irq_itoa(dev->irqs[0]));
+ebus_done:
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("Found 'su' at %016lx IRQ %s\n", info->port,
+		__irq_itoa(info->irq));
 #endif
 
 	info->magic = SERIAL_MAGIC;
 
 	save_flags(flags); cli();
-	
+
 	/*
 	 * Do a simple existence test first; if we fail this, there's
 	 * no point trying anything else.
@@ -2312,17 +2324,20 @@
 		return;		/* We failed; there's nothing here */
 	}
 
-#if 0 /* P3: This does not work on MrCoffee. OUT2 is 0x80 - should work... */
 	scratch = serial_inp(info, UART_MCR);
 	serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch);
 	serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
 	status1 = serial_inp(info, UART_MSR) & 0xF0;
 	serial_outp(info, UART_MCR, scratch);
 	if (status1 != 0x90) {
+		/*
+		 * This code fragment used to fail, now it fixed itself.
+		 * We keep the printout for a case.
+		 */
+		printk("su: loopback returned status 0x%02x\n", status1);
 		restore_flags(flags);
 		return;
 	} 
-#endif
 
 	scratch2 = serial_in(info, UART_LCR);
 	serial_outp(info, UART_LCR, 0xBF);	/* set up for StarTech test */
@@ -2389,11 +2404,7 @@
 		return;
 	}
 
-	if (info->kbd_node || info->ms_node)
-		sprintf(info->name, "su(%s)", info->ms_node ? "mouse" : "kbd");
-	else
-		strcpy(info->name, "su(serial)");
-
+	sprintf(info->name, "su(%s)", su_typev[info->port_type]);
 #ifdef __sparc_v9__
 	request_region(info->port, 8, info->name);
 #endif
@@ -2409,6 +2420,11 @@
 	restore_flags(flags);
 }
 
+/* This is used by the SAB driver to adjust where its minor
+ * numbers start, we always are probed for first.
+ */
+int su_num_ports = 0;
+
 /*
  * The serial driver boot-time initialization code!
  */
@@ -2499,11 +2515,18 @@
 		if (info->type == PORT_UNKNOWN)
 			continue;
 
-		printk(KERN_INFO "%s at %16lx (irq = %s) is a %s\n",
-		       info->name, info->port, __irq_itoa(info->irq),
+		printk(KERN_INFO "%s at 0x%lx (tty %d irq %s) is a %s\n",
+		       info->name, (long)info->port, i, __irq_itoa(info->irq),
 		       uart_config[info->type].name);
 	}
 
+	for (i = 0, info = su_table; i < NR_PORTS; i++, info++)
+		if (info->type == PORT_UNKNOWN)
+			break;
+
+	su_num_ports = i;
+	serial_driver.num = callout_driver.num = i;
+
 	return 0;
 }
 
@@ -2519,7 +2542,7 @@
 		info->type = PORT_UNKNOWN;
 		info->baud_base = BAUD_BASE;
 
-		if (info->kbd_node)
+		if (info->port_type == SU_PORT_KBD)
 			info->cflag = B1200 | CS8 | CLOCAL | CREAD;
 		else
 			info->cflag = B4800 | CS8 | CLOCAL | CREAD;
@@ -2528,12 +2551,12 @@
 		if (info->type == PORT_UNKNOWN)
 			continue;
 
-		printk(KERN_INFO "%s at %16lx (irq = %s) is a %s\n",
+		printk(KERN_INFO "%s at 0x%lx (irq = %s) is a %s\n",
 		       info->name, info->port, __irq_itoa(info->irq),
 		       uart_config[info->type].name);
 
 		startup(info);
-		if (info->kbd_node)
+		if (info->port_type == SU_PORT_KBD)
 			keyboard_zsinit(su_put_char_kbd);
 		else
 			sun_mouse_zsinit();
@@ -2541,154 +2564,131 @@
 	return 0;
 }
 
-__initfunc(int su_probe (unsigned long *memory_start))
+/*
+ * We got several platforms which present 'su' in different parts
+ * of device tree. 'su' may be found under obio, ebus, isa and pci.
+ * We walk over the tree and find them wherever PROM hides them.
+ */
+__initfunc(void su_probe_any(struct su_probe_scan *t, int sunode))
 {
-	struct su_struct *info = su_table;
-        int node, enode, tnode, sunode;
-	int kbnode = 0, msnode = 0;
-	int devices = 0;
-	char prop[128];
+	struct su_struct *info;
 	int len;
 
-	/*
-	 * Find su on MrCoffee. We return OK code if find any.
-	 * Then su_init finds every one and initializes them.
-	 * We do this early because MrCoffee got no aliases.
-	 */
-	node = prom_getchild(prom_root_node);
-	if ((node = prom_searchsiblings(node, "obio")) != 0) {
-		if ((sunode = prom_getchild(node)) != 0) {
-			if ((sunode = prom_searchsiblings(sunode, "su")) != 0) {
-				info->port_node = sunode;
-#ifdef CONFIG_SERIAL_CONSOLE
-				/*
-				 * Console must be initiated after the generic
-				 * initialization.
-				 * sunserial_setinitfunc inverts order, so
-				 * call this before next one.
-				 */
-				sunserial_setinitfunc(memory_start,
-						      su_serial_console_init);
-#endif
-        			sunserial_setinitfunc(memory_start,
-						      su_serial_init);
-				return 0;
+	if (t->devices >= NR_PORTS)
+		return;
+
+	for (; sunode != 0; sunode = prom_getsibling(sunode)) {
+		len = prom_getproperty(sunode, "name", t->prop, SU_PROPSIZE);
+		if (len <= 1)
+			continue;		/* Broken PROM node */
+		if (strncmp(t->prop, "su", len) == 0 ||
+		    strncmp(t->prop, "serial", len) == 0 ||
+		    strncmp(t->prop, "su_pnp", len) == 0) {
+			info = &su_table[t->devices];
+			if (t->kbnode != 0 && sunode == t->kbnode) {
+				t->kbx = t->devices;
+				info->port_type = SU_PORT_KBD;
+			} else if (t->msnode != 0 && sunode == t->msnode) {
+				t->msx = t->devices;
+				info->port_type = SU_PORT_MS;
+			} else {
+				info->port_type = SU_PORT_PORT;
 			}
+			info->is_console = 0;
+			info->port_node = sunode;
+			++t->devices;
+		} else {
+			su_probe_any(t, prom_getchild(sunode));
 		}
 	}
+}
+
+__initfunc(int su_probe (unsigned long *memory_start))
+{
+	int node;
+	int len;
+	struct su_probe_scan scan;
+
+	/*
+	 * First, we scan the tree.
+	 */
+	scan.devices = 0;
+	scan.msx = -1;
+	scan.kbx = -1;
+	scan.kbnode = 0;
+	scan.msnode = 0;
 
 	/*
 	 * Get the nodes for keyboard and mouse from 'aliases'...
 	 */
         node = prom_getchild(prom_root_node);
 	node = prom_searchsiblings(node, "aliases");
-	if (!node)
-		return -ENODEV;
+	if (node != 0) {
 
-	len = prom_getproperty(node, "keyboard", prop, sizeof(prop));
-	if (len > 0) {
-		prop[len] = 0;
-		kbnode = prom_finddevice(prop);
-	}
-	if (!kbnode)
-		return -ENODEV;
+		len = prom_getproperty(node, "keyboard", scan.prop,SU_PROPSIZE);
+		if (len > 0) {
+			scan.prop[len] = 0;
+			scan.kbnode = prom_finddevice(scan.prop);
+		}
 
-	len = prom_getproperty(node, "mouse", prop, sizeof(prop));
-	if (len > 0) {
-		prop[len] = 0;
-		msnode = prom_finddevice(prop);
+		len = prom_getproperty(node, "mouse", scan.prop, SU_PROPSIZE);
+		if (len > 0) {
+			scan.prop[len] = 0;
+			scan.msnode = prom_finddevice(scan.prop);
+		}
 	}
-	if (!msnode)
-		return -ENODEV;
 
-	/*
-	 * Find matching EBus nodes...
-	 */
-        node = prom_getchild(prom_root_node);
-	if ((node = prom_searchsiblings(node, "pci")) == 0) {
-		return -ENODEV;		/* Plain sparc */
-	}
+	su_probe_any(&scan, prom_getchild(prom_root_node));
 
 	/*
-	 * Check for SUNW,sabre on Ultra 5/10/AXi.
-	 */
-	len = prom_getproperty(node, "model", prop, sizeof(prop));
-	if ((len > 0) && !strncmp(prop, "SUNW,sabre", len)) {
-        	node = prom_getchild(node);
-		node = prom_searchsiblings(node, "pci");
+	 * Second, we process the special case of keyboard and mouse.
+	 *
+	 * Currently if we got keyboard and mouse hooked to "su" ports
+	 * we do not use any possible remaining "su" as a serial port.
+	 * Thus, we ignore values of .msx and .kbx, then compact ports.
+	 * Those who want to address this issue need to merge
+	 * su_serial_init() and su_ms_kbd_init().
+	 */
+	if (scan.msx != -1 && scan.kbx != -1) {
+		su_table[0].port_type = SU_PORT_MS;
+		su_table[0].is_console = 0;
+		su_table[0].port_node = scan.msnode;
+		su_table[1].port_type = SU_PORT_KBD;
+		su_table[1].is_console = 0;
+		su_table[1].port_node = scan.kbnode;
+
+        	sunserial_setinitfunc(memory_start, su_kbd_ms_init);
+        	rs_ops.rs_change_mouse_baud = su_change_mouse_baud;
+		sunkbd_setinitfunc(memory_start, sun_kbd_init);
+		kbd_ops.compute_shiftstate = sun_compute_shiftstate;
+		kbd_ops.setledstate = sun_setledstate;
+		kbd_ops.getledstate = sun_getledstate;
+		kbd_ops.setkeycode = sun_setkeycode;
+		kbd_ops.getkeycode = sun_getkeycode;
+#ifdef CONFIG_PCI
+		sunkbd_install_keymaps(memory_start, sun_key_maps,
+		    sun_keymap_count, sun_func_buf, sun_func_table,
+		    sun_funcbufsize, sun_funcbufleft,
+		    sun_accent_table, sun_accent_table_size);
+#endif
+		return 0;
+	}
+	if (scan.msx != -1 || scan.kbx != -1) {
+		printk("su_probe: cannot match keyboard and mouse, confused\n");
+		return -ENODEV;
 	}
 
+	if (scan.devices == 0)
+		return -ENODEV;
+
+#ifdef CONFIG_SERIAL_CONSOLE
 	/*
-	 * For each PCI bus...
+	 * Console must be initiated after the generic initialization.
+	 * sunserial_setinitfunc inverts order, so call this before next one.
 	 */
-	while (node) {
-		enode = prom_getchild(node);
-		enode = prom_searchsiblings(enode, "ebus");
-
-		/*
-		 * For each EBus on this PCI...
-		 */
-		while (enode) {
-			sunode = prom_getchild(enode);
-			tnode = prom_searchsiblings(sunode, "su");
-			if (!tnode)
-				tnode = prom_searchsiblings(sunode, "su_pnp");
-			sunode = tnode;
-
-			/*
-			 * For each 'su' on this EBus...
-			 */
-			while (sunode) {
-				/*
-				 * Does it match?
-				 */
-				if (sunode == kbnode) {
-					info->kbd_node = sunode;
-					++info;
-					++devices;
-				}
-				if (sunode == msnode) {
-					info->ms_node = sunode;
-					++info;
-					++devices;
-				}
-
-				/*
-				 * Found everything we need?
-				 */
-				if (devices == 2)
-					goto found;
-
-				sunode = prom_getsibling(sunode);
-				tnode = prom_searchsiblings(sunode, "su");
-				if (!tnode)
-					tnode = prom_searchsiblings(sunode,
-								    "su_pnp");
-				sunode = tnode;
-			}
-			enode = prom_getsibling(enode);
-			enode = prom_searchsiblings(enode, "ebus");
-		}
-		node = prom_getsibling(node);
-		node = prom_searchsiblings(node, "pci");
-	}
-	return -ENODEV;
-
-found:
-        sunserial_setinitfunc(memory_start, su_kbd_ms_init);
-        rs_ops.rs_change_mouse_baud = su_change_mouse_baud;
-	sunkbd_setinitfunc(memory_start, sun_kbd_init);
-	kbd_ops.compute_shiftstate = sun_compute_shiftstate;
-	kbd_ops.setledstate = sun_setledstate;
-	kbd_ops.getledstate = sun_getledstate;
-	kbd_ops.setkeycode = sun_setkeycode;
-	kbd_ops.getkeycode = sun_getkeycode;
-#ifdef CONFIG_PCI
-	sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count,
-			       sun_func_buf, sun_func_table,
-			       sun_funcbufsize, sun_funcbufleft,
-			       sun_accent_table, sun_accent_table_size);
+	sunserial_setinitfunc(memory_start, su_serial_console_init);
 #endif
+	sunserial_setinitfunc(memory_start, su_serial_init);
 	return 0;
 }
 
@@ -2910,6 +2910,8 @@
 	if (su_inb(info, UART_LSR) == 0xff)
 		return -1;
 
+	info->is_console = 1;
+
 	return 0;
 }
 
@@ -2927,6 +2929,8 @@
 	NULL
 };
 
+int su_console_registered = 0;
+
 /*
  *	Register console.
  */
@@ -2942,6 +2946,7 @@
 		return 0;
 	sercons.index = 0;
 	register_console(&sercons);
+	su_console_registered = 1;
 	return 0;
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/char/sunkeymap.c linux.14p16/drivers/sbus/char/sunkeymap.c
--- linux.vanilla/drivers/sbus/char/sunkeymap.c	Mon Jan 27 08:42:54 1997
+++ linux.14p16/drivers/sbus/char/sunkeymap.c	Thu Dec  9 15:34:12 1999
@@ -1,3 +1,4 @@
+
 /* Do not edit this file! It was automatically generated by   */
 /*    loadkeys --mktable defkeymap.map > defkeymap.c          */
 
@@ -30,7 +31,7 @@
 	0xf110,	0xf111,	0xf112,	0xf703,	0xf603,	0xf11d,	0xf200,	0xf203,
 	0xf601,	0xf200,	0xf200,	0xf600,	0xf602,	0xf01b,	0xf021,	0xf040,
 	0xf023,	0xf024,	0xf025,	0xf05e,	0xf026,	0xf02a,	0xf028,	0xf029,
-	0xf05f,	0xf02b,	0xf07e,	0xf07f,	0xf115,	0xf200,	0xf30d,	0xf30c,
+	0xf05f,	0xf02b,	0xf07e,	0xf07f,	0xf115,	0xf03d,	0xf30d,	0xf30c,
 	0xf200,	0xf200,	0xf310,	0xf200,	0xf114,	0xf009,	0xfb51,	0xfb57,
 	0xfb45,	0xfb52,	0xfb54,	0xfb59,	0xfb55,	0xfb49,	0xfb4f,	0xfb50,
 	0xf07b,	0xf07d,	0xf07f,	0xf20e,	0xf307,	0xf308,	0xf309,	0xf30b,
@@ -38,7 +39,7 @@
 	0xfb46,	0xfb47,	0xfb48,	0xfb4a,	0xfb4b,	0xfb4c,	0xf03a,	0xf022,
 	0xf07c,	0xf201,	0xf30e,	0xf304,	0xf305,	0xf306,	0xf300,	0xf200,
 	0xf20b,	0xf200,	0xf208,	0xf700,	0xfb5a,	0xfb58,	0xfb43,	0xfb56,
-	0xfb42,	0xfb4e,	0xfb4d,	0xf03c,	0xf03e,	0xf03f,	0xf700,	0xf200,
+	0xfb42,	0xfb4e,	0xfb4d,	0xf03c,	0xf03e,	0xf03f,	0xf700,	0xf00a,
 	0xf301,	0xf302,	0xf303,	0xf200,	0xf200,	0xf200,	0xf11b,	0xf207,
 	0xf200,	0xf020,	0xf200,	0xf20a,	0xf200,	0xf30a,	0xf200,	0xf200,
 };
@@ -49,7 +50,7 @@
 	0xf512,	0xf513,	0xf514,	0xf703,	0xf603,	0xf11d,	0xf200,	0xf202,
 	0xf601,	0xf200,	0xf200,	0xf600,	0xf602,	0xf200,	0xf200,	0xf040,
 	0xf200,	0xf024,	0xf200,	0xf200,	0xf07b,	0xf05b,	0xf05d,	0xf07d,
-	0xf05c,	0xf200,	0xf200,	0xf200,	0xf115,	0xf200,	0xf30d,	0xf30c,
+	0xf05c,	0xf200,	0xf200,	0xf200,	0xf115,	0xf03d,	0xf30d,	0xf30c,
 	0xf200,	0xf200,	0xf310,	0xf200,	0xf114,	0xf200,	0xfb71,	0xfb77,
 	0xf918,	0xfb72,	0xfb74,	0xfb79,	0xfb75,	0xfb69,	0xfb6f,	0xfb70,
 	0xf200,	0xf07e,	0xf200,	0xf20e,	0xf911,	0xf912,	0xf913,	0xf30b,
@@ -57,7 +58,7 @@
 	0xf919,	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,	0xf200,	0xf200,
 	0xf200,	0xf201,	0xf30e,	0xf90e,	0xf90f,	0xf910,	0xf90a,	0xf200,
 	0xf118,	0xf200,	0xf208,	0xf700,	0xfb7a,	0xfb78,	0xf916,	0xfb76,
-	0xf915,	0xfb6e,	0xfb6d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf200,
+	0xf915,	0xfb6e,	0xfb6d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf00a,
 	0xf90b,	0xf90c,	0xf90d,	0xf200,	0xf200,	0xf200,	0xf11b,	0xf207,
 	0xf200,	0xf200,	0xf200,	0xf119,	0xf200,	0xf30a,	0xf200,	0xf200,
 };
@@ -68,7 +69,7 @@
 	0xf106,	0xf107,	0xf108,	0xf703,	0xf603,	0xf11d,	0xf200,	0xf204,
 	0xf601,	0xf200,	0xf200,	0xf600,	0xf602,	0xf200,	0xf200,	0xf000,
 	0xf01b,	0xf01c,	0xf01d,	0xf01e,	0xf01f,	0xf07f,	0xf200,	0xf200,
-	0xf01f,	0xf200,	0xf000,	0xf008,	0xf115,	0xf200,	0xf30d,	0xf30c,
+	0xf01f,	0xf200,	0xf000,	0xf008,	0xf115,	0xf03d,	0xf30d,	0xf30c,
 	0xf200,	0xf200,	0xf310,	0xf200,	0xf114,	0xf200,	0xf011,	0xf017,
 	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,	0xf009,	0xf00f,	0xf010,
 	0xf01b,	0xf01d,	0xf008,	0xf20e,	0xf307,	0xf308,	0xf309,	0xf30b,
@@ -76,7 +77,7 @@
 	0xf006,	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,	0xf200,	0xf007,
 	0xf01c,	0xf201,	0xf30e,	0xf304,	0xf305,	0xf306,	0xf300,	0xf200,
 	0xf118,	0xf200,	0xf208,	0xf700,	0xf01a,	0xf018,	0xf003,	0xf016,
-	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf20e,	0xf07f,	0xf700,	0xf200,
+	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf20e,	0xf07f,	0xf700,	0xf00a,
 	0xf301,	0xf302,	0xf303,	0xf200,	0xf200,	0xf200,	0xf11b,	0xf207,
 	0xf200,	0xf000,	0xf200,	0xf119,	0xf200,	0xf30a,	0xf200,	0xf200,
 };
@@ -87,7 +88,7 @@
 	0xf200,	0xf200,	0xf200,	0xf703,	0xf603,	0xf11d,	0xf200,	0xf200,
 	0xf601,	0xf200,	0xf200,	0xf600,	0xf602,	0xf200,	0xf200,	0xf000,
 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf01f,	0xf200,	0xf200,	0xf200,	0xf115,	0xf200,	0xf30d,	0xf30c,
+	0xf01f,	0xf200,	0xf200,	0xf200,	0xf115,	0xf03d,	0xf30d,	0xf30c,
 	0xf200,	0xf200,	0xf310,	0xf200,	0xf114,	0xf200,	0xf011,	0xf017,
 	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,	0xf009,	0xf00f,	0xf010,
 	0xf200,	0xf200,	0xf200,	0xf20e,	0xf307,	0xf308,	0xf309,	0xf30b,
@@ -95,7 +96,7 @@
 	0xf006,	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,	0xf200,	0xf200,
 	0xf200,	0xf201,	0xf30e,	0xf304,	0xf305,	0xf306,	0xf300,	0xf200,
 	0xf118,	0xf200,	0xf208,	0xf700,	0xf01a,	0xf018,	0xf003,	0xf016,
-	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf200,
+	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf00a,
 	0xf301,	0xf302,	0xf303,	0xf200,	0xf200,	0xf200,	0xf11b,	0xf207,
 	0xf200,	0xf200,	0xf200,	0xf119,	0xf200,	0xf30a,	0xf200,	0xf200,
 };
@@ -106,15 +107,15 @@
 	0xf506,	0xf507,	0xf508,	0xf703,	0xf603,	0xf11d,	0xf200,	0xf209,
 	0xf210,	0xf200,	0xf200,	0xf600,	0xf211,	0xf81b,	0xf831,	0xf832,
 	0xf833,	0xf834,	0xf835,	0xf836,	0xf837,	0xf838,	0xf839,	0xf830,
-	0xf82d,	0xf83d,	0xf860,	0xf87f,	0xf115,	0xf200,	0xf30d,	0xf30c,
+	0xf82d,	0xf83d,	0xf860,	0xf87f,	0xf115,	0xf03d,	0xf30d,	0xf30c,
 	0xf200,	0xf200,	0xf310,	0xf200,	0xf114,	0xf809,	0xf871,	0xf877,
 	0xf865,	0xf872,	0xf874,	0xf879,	0xf875,	0xf869,	0xf86f,	0xf870,
-	0xf85b,	0xf85d,	0xf200,	0xf87f,	0xf907,	0xf908,	0xf909,	0xf30b,
+	0xf85b,	0xf85d,	0xf87f,	0xf20e,	0xf907,	0xf908,	0xf909,	0xf30b,
 	0xf200,	0xf200,	0xf117,	0xf200,	0xf702,	0xf861,	0xf873,	0xf864,
 	0xf866,	0xf867,	0xf868,	0xf86a,	0xf86b,	0xf86c,	0xf83b,	0xf827,
 	0xf85c,	0xf80d,	0xf30e,	0xf904,	0xf905,	0xf906,	0xf900,	0xf200,
 	0xf118,	0xf200,	0xf208,	0xf700,	0xf87a,	0xf878,	0xf863,	0xf876,
-	0xf862,	0xf86e,	0xf86d,	0xf82c,	0xf82e,	0xf82f,	0xf700,	0xf200,
+	0xf862,	0xf86e,	0xf86d,	0xf82c,	0xf82e,	0xf82f,	0xf700,	0xf00a,
 	0xf901,	0xf902,	0xf903,	0xf200,	0xf200,	0xf200,	0xf11b,	0xf207,
 	0xf200,	0xf820,	0xf200,	0xf119,	0xf200,	0xf30a,	0xf200,	0xf200,
 };
@@ -125,7 +126,7 @@
 	0xf506,	0xf507,	0xf508,	0xf703,	0xf603,	0xf11d,	0xf200,	0xf200,
 	0xf601,	0xf200,	0xf200,	0xf600,	0xf602,	0xf200,	0xf200,	0xf200,
 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf115,	0xf200,	0xf30d,	0xf30c,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf115,	0xf03d,	0xf30d,	0xf30c,
 	0xf200,	0xf200,	0xf20c,	0xf200,	0xf114,	0xf200,	0xf811,	0xf817,
 	0xf805,	0xf812,	0xf814,	0xf819,	0xf815,	0xf809,	0xf80f,	0xf810,
 	0xf200,	0xf200,	0xf20c,	0xf20e,	0xf307,	0xf308,	0xf309,	0xf30b,
@@ -133,7 +134,7 @@
 	0xf806,	0xf807,	0xf808,	0xf80a,	0xf80b,	0xf80c,	0xf200,	0xf200,
 	0xf200,	0xf201,	0xf30e,	0xf304,	0xf305,	0xf306,	0xf300,	0xf200,
 	0xf118,	0xf200,	0xf208,	0xf700,	0xf81a,	0xf818,	0xf803,	0xf816,
-	0xf802,	0xf80e,	0xf80d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf200,
+	0xf802,	0xf80e,	0xf80d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf00a,
 	0xf301,	0xf302,	0xf303,	0xf200,	0xf200,	0xf200,	0xf11b,	0xf207,
 	0xf200,	0xf200,	0xf200,	0xf119,	0xf200,	0xf30a,	0xf200,	0xf200,
 };
@@ -147,6 +148,7 @@
 
 unsigned int keymap_count = 7;
 
+
 /*
  * Philosophy: most people do not define more strings, but they who do
  * often want quite a lot of string space. So, we statically allocate
@@ -183,6 +185,7 @@
 	'\033', '[', 'M', 0, 
 	'\033', '[', 'P', 0, 
 };
+
 
 char *funcbufptr = func_buf;
 int funcbufsize = sizeof(func_buf);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/char/sunkeymap.map linux.14p16/drivers/sbus/char/sunkeymap.map
--- linux.vanilla/drivers/sbus/char/sunkeymap.map	Mon Jan 27 08:42:54 1997
+++ linux.14p16/drivers/sbus/char/sunkeymap.map	Thu Dec  9 15:34:12 1999
@@ -160,7 +160,7 @@
 	alt	keycode				0x41 = Meta_bracketright
 keycode 0x42 = Delete		Delete
 	control	keycode				0x42 = BackSpace
-	alt	keycode				0x43 = Meta_Delete
+	alt	keycode				0x42 = Meta_Delete
 	control	alt	keycode			0x42 = Boot
 keycode 0x43 = Compose
 keycode 0x44 = KP_7
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/char/sunmouse.c linux.14p16/drivers/sbus/char/sunmouse.c
--- linux.vanilla/drivers/sbus/char/sunmouse.c	Sat Aug 14 02:25:56 1999
+++ linux.14p16/drivers/sbus/char/sunmouse.c	Thu Dec  9 15:34:12 1999
@@ -81,7 +81,7 @@
 	unsigned int tail;
 	union {
 		char stream [STREAM_SIZE];
-		Firm_event ev [0];
+		Firm_event ev [EV_SIZE];
 	} queue;
 };
 
@@ -142,8 +142,6 @@
 }
 
 /* Auto baud rate "detection".  ;-) */
-static int mouse_bogon_bytes = 0;
-static int mouse_baud_changing = 0;	/* For reporting things to the user. */
 static int mouse_baud = 4800;		/* Initial rate set by zilog driver. */
 
 /* Change the baud rate after receiving too many "bogon bytes". */
@@ -161,71 +159,112 @@
 		mouse_baud = 1200;
 
 	rs_change_mouse_baud(mouse_baud);
-	mouse_baud_changing = 1;
 }
 
-void mouse_baud_detection(unsigned char c)
+/* This tries to monitor the mouse state so that it
+ * can automatically adjust to the correct baud rate.
+ * The mouse spits out BRKs when the baud rate is
+ * incorrect.
+ *
+ * It returns non-zero if we should ignore this byte.
+ */
+int mouse_baud_detection(unsigned char c, int is_break)
 {
-	static int wait_for_synchron = 1;
+	static int mouse_got_break = 0;
 	static int ctr = 0;
 
-	if(wait_for_synchron) {
-		if((c < 0x80) || (c > 0x87))
-			mouse_bogon_bytes++;
-		else {
-			ctr = 0;
-			wait_for_synchron = 0;
-		}
-	} else {
+	if (is_break) {
+		/* Let a few normal bytes go by before
+		 * we jump the gun and say we need to
+		 * try another baud rate.
+		 */
+		if (mouse_got_break && ctr < 8)
+			return 1;
+
+		/* OK, we need to try another baud rate. */
+		sun_mouse_change_baud();
+		ctr = 0;
+		mouse_got_break = 1;
+		return 1;
+	}
+	if (mouse_got_break) {
 		ctr++;
-		if(ctr >= 4) {
-			ctr = 0;
-			wait_for_synchron = 1;
-			if(mouse_baud_changing == 1) {
-				printk(KERN_DEBUG "sunmouse: Successfully adjusted to %d baud.\n",
-				       mouse_baud);
-				mouse_baud_changing = 0;
-			}
+		if (c == 0x87) {
+			printk(KERN_INFO "sunmouse: Successfully "
+			       "adjusted to %d baud.\n", mouse_baud);
+			mouse_got_break = 0;
 		}
+		return 1;
 	}
-	if(mouse_bogon_bytes > 12) {
-		sun_mouse_change_baud();
-		mouse_bogon_bytes = 0;
-		wait_for_synchron = 1;
-	}
+
+	return 0;
 }
 
-/* The following is called from the zs driver when bytes are received on
- * the Mouse zs8530 channel.
+/* You ask me, why does this cap the lower bound at -127 and not
+ * -128?  Because the xf86 mouse code is crap and treats -128
+ * as an illegal value and resets it's protocol state machine
+ * when it sees this value.
+ */
+#define CLIP(__X)	(((__X) > 127) ? 127 : (((__X) < -127) ? -127 : (__X)))
+
+/* The following is called from the serial driver when bytes/breaks
+ * are received on the Mouse line.
  */
 void
-sun_mouse_inbyte(unsigned char byte)
+sun_mouse_inbyte(unsigned char byte, int is_break)
 {
 	signed char mvalue;
 	int d, pushed = 0;
 	Firm_event ev;
 
 	add_mouse_randomness (byte);
+#if 0
+	{
+		static int xxx = 0;
+		printk("mouse(%02x:%d) ",
+		       byte, is_break);
+		if (byte == 0x87) {
+			xxx = 0;
+			printk("\n");
+		}
+	}
+#endif
+	if (mouse_baud_detection(byte, is_break))
+		return;
+
 	if(!sunmouse.active)
 		return;
 
-	mouse_baud_detection(byte);
+	/* Ignore this if it is garbage. */
+	if (sunmouse.byte == 69) {
+		if (byte != 0x87)
+			return;
 
-	if (!gen_events){
-		push_char (byte);
-		return;
+		/* Ok, we've begun the state machine. */
+		sunmouse.byte = 0;
 	}
-
+#if 0
 	/* If the mouse sends us a byte from 0x80 to 0x87
 	 * we are starting at byte zero in the transaction
 	 * protocol.
 	 */
 	if(byte >= 0x80 && byte <= 0x87)
 		sunmouse.byte = 0;
+#endif
 
 	mvalue = (signed char) byte;
 	switch(sunmouse.byte) {
 	case 0:
+		/* If we get a bogus button byte, just skip it.
+		 * When we get here the baud detection code has
+		 * passed, so the only other things which can
+		 * cause this are dropped serial characters and
+		 * confused mouse.  We check this because otherwise
+		 * begin posting erroneous mouse events.
+		 */
+		if ((byte & 0xf0) != 0x80)
+			return;
+
 		/* Button state */
 		sunmouse.button_state = (~byte) & 0x7;
 #ifdef SMOUSE_DEBUG
@@ -258,6 +297,7 @@
 		printk("DX2<%d>", mvalue);
 #endif
 		sunmouse.delta_x += mvalue;
+		sunmouse.delta_x = CLIP(sunmouse.delta_x);
 		sunmouse.byte++;
 		return;
 	case 4:
@@ -266,7 +306,8 @@
 		printk("DY2<%d>", mvalue);
 #endif
 		sunmouse.delta_y += mvalue;
-		sunmouse.byte = 69;  /* Some ridiculous value */
+		sunmouse.delta_y = CLIP(sunmouse.delta_y);
+		sunmouse.byte = 0;  /* Back to button state */
 		break;
 	case 69:
 		/* Until we get the (0x80 -> 0x87) value we aren't
@@ -279,6 +320,12 @@
 		sunmouse.byte = 69;  /* What could cause this? */
 		return;
 	};
+	if (!gen_events){
+		push_char (~sunmouse.button_state & 0x87);
+		push_char (sunmouse.delta_x);
+		push_char (sunmouse.delta_y);
+		return;
+	}
 	d = bstate ^ pstate;
 	pstate = bstate;
 	if (d){
@@ -389,6 +436,10 @@
 			if (current->tss.flags & SPARC_FLAG_32BIT) {
 				Firm_event *q = get_from_queue();
 				
+				if ((end - p) <
+				    ((sizeof(Firm_event) - sizeof(struct timeval) +
+				      (sizeof(u32) * 2))))
+					break;
 				copy_to_user_ret((Firm_event *)p, q, 
 						 sizeof(Firm_event)-sizeof(struct timeval),
 						 -EFAULT);
@@ -400,6 +451,8 @@
 			} else
 #endif	
 			{	
+				if ((end - p) < sizeof(Firm_event))
+					break;
 				copy_to_user_ret((Firm_event *)p, get_from_queue(),
 				     		 sizeof(Firm_event), -EFAULT);
 				p += sizeof (Firm_event);
@@ -409,16 +462,25 @@
 		file->f_dentry->d_inode->i_atime = CURRENT_TIME;
 		return p-buffer;
 	} else {
-		int c;
-		
-		for (c = count; !queue_empty() && c; c--){
-			put_user_ret(sunmouse.queue.stream[sunmouse.tail], buffer, -EFAULT);
+		int c, limit = 3;
+
+		if (count < limit)
+			limit = count;
+		for (c = 0; c < limit; c++) {
+			put_user(sunmouse.queue.stream[sunmouse.tail], buffer);
 			buffer++;
 			sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE;
 		}
+		while (c < count) {
+			if (c >= 5)
+				break;
+			put_user(0, buffer);
+			buffer++;
+			c++;
+		}
 		sunmouse.ready = !queue_empty();
 		file->f_dentry->d_inode->i_atime = CURRENT_TIME;
-		return count-c;
+		return c;
 	}
 	/* Only called if nothing was sent */
 	if (signal_pending(current))
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/char/sunmouse.h linux.14p16/drivers/sbus/char/sunmouse.h
--- linux.vanilla/drivers/sbus/char/sunmouse.h	Thu Sep  4 20:54:49 1997
+++ linux.14p16/drivers/sbus/char/sunmouse.h	Thu Dec  9 15:34:12 1999
@@ -1,4 +1,4 @@
-/* $Id: sunmouse.h,v 1.1 1997/08/28 02:23:38 ecd Exp $
+/* $Id: sunmouse.h,v 1.1.6.1 1999/10/14 08:44:33 davem Exp $
  * sunmouse.h: Interface to the SUN mouse driver.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -8,6 +8,6 @@
 #define _SPARC_SUNMOUSE_H 1
 
 extern void sun_mouse_zsinit(void);
-extern void sun_mouse_inbyte(unsigned char);
+extern void sun_mouse_inbyte(unsigned char, int);
 
 #endif /* !(_SPARC_SUNMOUSE_H) */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/char/sunserial.c linux.14p16/drivers/sbus/char/sunserial.c
--- linux.vanilla/drivers/sbus/char/sunserial.c	Tue Mar 16 00:11:30 1999
+++ linux.14p16/drivers/sbus/char/sunserial.c	Thu Dec  9 15:34:12 1999
@@ -1,4 +1,4 @@
-/* $Id: sunserial.c,v 1.68 1998/12/09 18:53:51 davem Exp $
+/* $Id: sunserial.c,v 1.68.2.2 1999/10/04 14:57:02 jj Exp $
  * serial.c: Serial port driver infrastructure for the Sparc.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -19,6 +19,7 @@
 #include "sunserial.h"
 
 int serial_console;
+int stop_a_enabled = 1;
 
 __initfunc(int con_is_present(void))
 {
@@ -389,12 +390,10 @@
 	 * So be very careful not to probe for keyboards if we are on a
 	 * serial console.
 	 */
-	if (!serial_console) {
-		if (ps2kbd_probe(&memory_start) == 0)
-			return memory_start;
-		if (su_probe(&memory_start) == 0)
-			return memory_start;
-	}
+	if (!serial_console)
+		ps2kbd_probe(&memory_start);
+	if (su_probe(&memory_start) == 0)
+		return memory_start;
 #endif
 
 	if (!ret)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/char/sunserial.h linux.14p16/drivers/sbus/char/sunserial.h
--- linux.vanilla/drivers/sbus/char/sunserial.h	Mon Jan 12 23:15:45 1998
+++ linux.14p16/drivers/sbus/char/sunserial.h	Thu Dec  9 15:34:12 1999
@@ -1,4 +1,4 @@
-/* $Id: sunserial.h,v 1.17 1997/12/19 07:33:12 ecd Exp $
+/* $Id: sunserial.h,v 1.17.4.1 1999/10/04 14:57:08 jj Exp $
  * sunserial.h: SUN serial driver infrastructure (including keyboards).
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -41,6 +41,7 @@
 extern void sunkbd_setinitfunc(unsigned long *, int (*) (void));
 
 extern int serial_console;
+extern int stop_a_enabled;
 extern void sunserial_console_termios(struct console *);
 
 #ifdef CONFIG_PCI
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/char/zs.c linux.14p16/drivers/sbus/char/zs.c
--- linux.vanilla/drivers/sbus/char/zs.c	Wed Oct 20 01:12:40 1999
+++ linux.14p16/drivers/sbus/char/zs.c	Thu Dec  9 15:34:12 1999
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.41.2.2 1999/09/21 15:50:45 davem Exp $
+/* $Id: zs.c,v 1.41.2.4 1999/10/14 08:44:40 davem Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -374,6 +374,8 @@
  */
 void batten_down_hatches(void)
 {
+	if (!stop_a_enabled)
+		return;
 	/* If we are doing kadb, we call the debugger
 	 * else we just drop into the boot monitor.
 	 * Note that we must flush the user windows
@@ -471,7 +473,7 @@
 			goto next_char;
 		}
 		if(info->cons_mouse) {
-			sun_mouse_inbyte(ch);
+			sun_mouse_inbyte(ch, 0);
 			do_queue_task = 0;
 			goto next_char;
 		}
@@ -584,8 +586,12 @@
 	 * 'break asserted' status change interrupt, call
 	 * the boot prom.
 	 */
-	if((status & BRK_ABRT) && info->break_abort)
-		batten_down_hatches();
+	if(status & BRK_ABRT) {
+		if (info->break_abort)
+			batten_down_hatches();
+		if (info->cons_mouse)
+			sun_mouse_inbyte(0, 1);
+	}
 
 	/* XXX Whee, put in a buffer somewhere, the status information
 	 * XXX whee whee whee... Where does the information go...
@@ -1849,7 +1855,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.41.2.2 $";
+	char *revision = "$Revision: 1.41.2.4 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/advansys.c linux.14p16/drivers/scsi/advansys.c
--- linux.vanilla/drivers/scsi/advansys.c	Wed Oct 20 01:12:40 1999
+++ linux.14p16/drivers/scsi/advansys.c	Thu Dec  9 15:33:50 1999
@@ -1,5 +1,5 @@
-/* $Id: advansys.c,v 1.58 1999/09/03 23:02:16 bobf Exp bobf $ */
-#define ASC_VERSION "3.2F"    /* AdvanSys Driver Version */
+/* $Id: advansys.c,v 1.69 1999/11/29 18:37:53 bobf Exp bobf $ */
+#define ASC_VERSION "3.2M"    /* AdvanSys Driver Version */
 
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
@@ -19,7 +19,7 @@
  *  ftp://ftp.advansys.com/pub/linux/linux.tgz
  *
  * Please send questions, comments, bug reports to:
- *  bobf@advansys.com (Bob Frey)
+ *  linux@advansys.com
  */
 
 /*
@@ -42,13 +42,13 @@
   A. Linux Kernel Testing
 
      This driver has been tested in the following Linux kernels: v1.2.13,
-     v1.3.57, v2.0.38, v2.2.12, and v2.3.16. These kernel versions are major
+     v1.3.57, v2.0.38, v2.2.13, and v2.3.28. These kernel versions are major
      releases of Linux or the latest Linux kernel versions available when
      this version of the driver was released. The driver should also work
      in earlier versions of the Linux kernel. Beginning with v1.3.58 the
      AdvanSys driver is included with all Linux kernels. Please refer to
      sections C, D, and E for instructions on adding or upgrading the
-     AdvanSys driver.
+     AdvanSys driver. The driver is supported for x86 and alpha systems.
 
   B. Adapters Supported by this Driver
  
@@ -103,6 +103,7 @@
         ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
         ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
         ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
+        ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide and Ultra-Wide (253 CDB)
      
   C. Linux v1.2.X - Directions for Adding the AdvanSys Driver
 
@@ -634,7 +635,48 @@
      3.2F (9/3/99):
          1. Handle new initial function code added in v2.3.16 for all
             driver versions.
-            
+
+     3.2G (9/8/99):
+         1. Fix PCI board detection in v2.3.13 and greater kernels.
+         2. Fix comiple errors in v2.3.X with debugging enabled.
+
+     3.2H (9/13/99):
+         1. Add 64-bit address, long support for Alpha and UltraSPARC.
+            The driver has been verified to work on an Alpha system.
+         2. Add partial byte order handling support for Power PC and
+            other big-endian platforms. This support has not yet been
+            completed or verified.
+         3. For wide boards replace block zeroing of request and
+            scatter-gather structures with individual field initialization
+            to improve performance.
+         4. Correct and clarify ROM BIOS version detection.
+
+     3.2I (10/8/99):
+         1. Update to Adv Library 5.4.
+         2. Add v2.3.19 underrun reporting to asc_isr_callback() and
+            adv_isr_callback().  Remove DID_UNDERRUN constant and other
+            no longer needed code that previously documented the lack
+            of underrun handling.
+
+     3.2J (10/14/99):
+         1. Eliminate compile errors for v2.0 and earlier kernels.
+
+     3.2K (11/15/99):
+         1. Correct debug compile error in asc_prt_adv_scsi_req_q().
+         2. Update Adv Library to 5.5.
+         3. Add ifdef handling for /proc changes added in v2.3.28.
+         4. Increase Wide board scatter-gather list maximum length to
+            255 when the driver is compiled into the kernel.
+
+     3.2L (11/18/99):
+         1. Fix bug in adv_get_sglist() that caused an assertion failure
+            at line 7475. The reqp->sgblkp pointer must be initialized
+            to NULL in adv_get_sglist().
+
+     3.2M (11/29/99):
+         1. Really fix bug in adv_get_sglist().
+         2. Incorporate v2.3.29 changes into driver.
+
   J. Known Problems/Fix List (XXX)
 
      1. Need to add memory mapping workaround. Test the memory mapping.
@@ -649,7 +691,6 @@
      6. Need to fix sti/cli code in Asc Library.
      7. Need to fix abort code in Adv Library.
      8. Reduce io_request_lock hold time.
-     9. Add big-endian support for Alpha.
 
   K. Credits
 
@@ -673,6 +714,9 @@
      Doug Gilbert <dgilbert@interlog.com> has made changes and
      suggestions to improve the driver and done testing.
 
+     Ken Mort <ken@mort.net> reported a DEBUG compile bug fixed
+     in 3.2K.
+
   L. AdvanSys Contact Information
  
      Mail:                   Advanced System Products, Inc.
@@ -736,7 +780,9 @@
 #include <linux/blk.h>
 #include <linux/stat.h>
 #endif /* version >= v1.3.0 */
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,95)
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,18)
+#include <linux/spinlock.h>
+#elif LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,95)
 #include <asm/spinlock.h>
 #endif /* version >= 2.1.95 */
 #include "scsi.h"
@@ -756,12 +802,12 @@
 #define ASC_CONFIG_PCI
 #endif /* version < v2.1.93 */
 
-/*
- * If Linux eventually defines a DID_UNDERRUN, the constant here can be
- * removed. The current value of zero for DID_UNDERRUN results in underrun
- * conditions being ignored.
- */
-#define DID_UNDERRUN 0
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+#define cpu_to_le16(word)       (word)
+#define le16_to_cpu(word)       (word)
+#define cpu_to_le32(dword)      (dword)
+#define le32_to_cpu(dword)      (dword)
+#endif /* version < v2.1.0 */
 
 
 /*
@@ -804,6 +850,31 @@
 #define ASC_LIB_VERSION_MINOR  24
 #define ASC_LIB_SERIAL_NUMBER  121
 
+/*
+ * Portable Data Types
+ *
+ * Any instance where a 32-bit long or pointer type is assumed
+ * for precision or HW defined structures, the following define
+ * types must be used. In Linux the char, short, and int types
+ * are all consistent at 8, 16, and 32 bits respectively. Pointers
+ * and long types are 64 bits on Alpha and UltraSPARC.
+ */ 
+#define ASC_PADDR __u32         /* Physical/Bus address data type. */
+#define ASC_VADDR __u32         /* Virtual address data type. */
+#define ASC_DCNT  __u32         /* Unsigned Data count type. */
+#define ASC_SDCNT __s32         /* Signed Data count type. */
+
+/*
+ * These macros are used to convert a virtual address to a
+ * 32-bit value. This currently can be used on Linux Alpha
+ * which uses 64-bit virtual address but a 32-bit bus address.
+ * This is likely to break in the future, but doing this now
+ * will give us time to change the HW and FW to handle 64-bit
+ * addresses.
+ */
+#define ASC_VADDR_TO_U32   virt_to_bus
+#define ASC_U32_TO_VADDR   bus_to_virt
+
 typedef unsigned char uchar;
 
 #ifndef NULL
@@ -815,55 +886,11 @@
 #ifndef FALSE
 #define FALSE    (0)
 #endif
-#define  REG     register
-#define rchar    REG __s8
-#define rshort   REG __s16
-#define rint     REG __s32
-#define rlong    REG __s32
-#define ruchar   REG __u8
-#define rushort  REG __u16
-#define ruint    REG __u32
-#define rulong   REG __u32
-#define NULLPTR  (void *)0
-#define FNULLPTR (void *)0UL
+
 #define EOF      (-1)
-#define EOS      '\0'
 #define ERR      (-1)
-#define UB_ERR   (uchar)(0xFF)
 #define UW_ERR   (uint)(0xFFFF)
-#define UL_ERR   (ulong)(0xFFFFFFFFUL)
-#define iseven_word(val)  ((((uint)val) & (uint)0x0001) == 0)
 #define isodd_word(val)   ((((uint)val) & (uint)0x0001) != 0)
-#define toeven_word(val)  (((uint)val) & (uint)0xFFFE)
-#define biton(val, bits)   (((uint)(val >> bits) & (uint)0x0001) != 0)
-#define bitoff(val, bits)  (((uint)(val >> bits) & (uint)0x0001) == 0)
-#define lbiton(val, bits)  (((ulong)(val >> bits) & (ulong)0x00000001UL) != 0)
-#define lbitoff(val, bits) (((ulong)(val >> bits) & (ulong)0x00000001UL) == 0)
-#define  absh(val)    ((val) < 0 ? -(val) : (val))
-#define  swapbyte(ch)  ((((ch) << 4) | ((ch) >> 4)))
-#ifndef GBYTE
-#define GBYTE       (0x40000000UL)
-#endif
-#ifndef MBYTE
-#define MBYTE       (0x100000UL)
-#endif
-#ifndef KBYTE
-#define KBYTE       (0x400)
-#endif
-#define HI_BYTE(x) (*((__u8 *)(&x)+1))
-#define LO_BYTE(x) (*((__u8 *)&x))
-#define HI_WORD(x) (*((__u16 *)(&x)+1))
-#define LO_WORD(x) (*((__u16 *)&x))
-#ifndef MAKEWORD
-#define MAKEWORD(lo, hi)    ((__u16) (((__u16) lo) | ((__u16) hi << 8)))
-#endif
-#ifndef MAKELONG
-#define MAKELONG(lo, hi)    ((__u32) (((__u32) lo) | ((__u32) hi << 16)))
-#endif
-#define SwapWords(dWord)        ((__u32) ((dWord >> 16) | (dWord << 16)))
-#define SwapBytes(word)         ((__u16) ((word >> 8) | (word << 8)))
-#define BigToLittle(dWord) ((__u32) (SwapWords(MAKELONG(SwapBytes(LO_WORD(dWord)), SwapBytes(HI_WORD(dWord))))))
-#define LittleToBig(dWord)      BigToLittle(dWord)
 #define AscPCIConfigVendorIDRegister      0x0000
 #define AscPCIConfigDeviceIDRegister      0x0002
 #define AscPCIConfigCommandRegister       0x0004
@@ -898,25 +925,17 @@
 #define ASC_SRB2SCSIQ(srb_ptr)  (srb_ptr)
 
 #define PortAddr            unsigned short    /* port address size  */
-#define Ptr2Func            ulong
 #define inp(port)           inb(port)
 #define inpw(port)          inw(port)
 #define inpl(port)          inl(port)
 #define outp(port, byte)    outb((byte), (port))
 #define outpw(port, word)   outw((word), (port))
-#define outpl(port, long)   outl((long), (port))
+#define outpl(port, dword) outl((dword), (port))
 #define ASC_MAX_SG_QUEUE    7
-#define ASC_MAX_SG_LIST     SG_ALL
+#define ASC_MAX_SG_LIST     255
 
 #define ASC_CS_TYPE  unsigned short
-#ifndef asc_ptr_type
-#define asc_ptr_type
-#endif
 
-#ifndef ASC_GET_PTR2FUNC
-#define ASC_GET_PTR2FUNC(fun)  (Ptr2Func)(fun)
-#endif
-#define FLIP_BYTE_NIBBLE(x)    (((x<<4)& 0xFF) | (x>>4))
 #define ASC_IS_ISA          (0x0001)
 #define ASC_IS_ISAPNP       (0x0081)
 #define ASC_IS_EISA         (0x0002)
@@ -967,34 +986,10 @@
 #define ASC_SCSI_ID_BITS  3
 #define ASC_SCSI_TIX_TYPE     uchar
 #define ASC_ALL_DEVICE_BIT_SET  0xFF
-#ifdef ASC_WIDESCSI_16
-#undef  ASC_SCSI_ID_BITS
-#define ASC_SCSI_ID_BITS  4
-#define ASC_ALL_DEVICE_BIT_SET  0xFFFF
-#endif
-#ifdef ASC_WIDESCSI_32
-#undef  ASC_SCSI_ID_BITS
-#define ASC_SCSI_ID_BITS  5
-#define ASC_ALL_DEVICE_BIT_SET  0xFFFFFFFFL
-#endif
-#if ASC_SCSI_ID_BITS == 3
 #define ASC_SCSI_BIT_ID_TYPE  uchar
 #define ASC_MAX_TID       7
 #define ASC_MAX_LUN       7
 #define ASC_SCSI_WIDTH_BIT_SET  0xFF
-#elif ASC_SCSI_ID_BITS == 4
-#define ASC_SCSI_BIT_ID_TYPE   ushort
-#define ASC_MAX_TID         15
-#define ASC_MAX_LUN         7
-#define ASC_SCSI_WIDTH_BIT_SET  0xFFFF
-#elif ASC_SCSI_ID_BITS == 5
-#define ASC_SCSI_BIT_ID_TYPE    ulong
-#define ASC_MAX_TID         31
-#define ASC_MAX_LUN         7
-#define ASC_SCSI_WIDTH_BIT_SET  0xFFFFFFFF
-#else
-#error  ASC_SCSI_ID_BITS definition is wrong
-#endif
 #define ASC_MAX_SENSE_LEN   32
 #define ASC_MIN_SENSE_LEN   14
 #define ASC_MAX_CDB_LEN     12
@@ -1298,15 +1293,15 @@
     uchar               sg_queue_cnt;
     uchar               target_id;
     uchar               target_lun;
-    ulong               data_addr;
-    ulong               data_cnt;
-    ulong               sense_addr;
+    ASC_PADDR           data_addr;
+    ASC_DCNT            data_cnt;
+    ASC_PADDR           sense_addr;
     uchar               sense_len;
     uchar               extra_bytes;
 } ASC_SCSIQ_1;
 
 typedef struct asc_scisq_2 {
-    ulong               srb_ptr;
+    ASC_VADDR           srb_ptr;
     uchar               target_ix;
     uchar               flag;
     uchar               cdb_len;
@@ -1329,8 +1324,8 @@
     uchar               y_res;
     ushort              x_req_count;
     ushort              x_reconnect_rtn;
-    ulong               x_saved_data_addr;
-    ulong               x_saved_data_cnt;
+    ASC_PADDR           x_saved_data_addr;
+    ASC_DCNT            x_saved_data_cnt;
 } ASC_SCSIQ_4;
 
 typedef struct asc_q_done_info {
@@ -1342,12 +1337,12 @@
     uchar               sense_len;
     uchar               extra_bytes;
     uchar               res;
-    ulong               remain_bytes;
+    ASC_DCNT            remain_bytes;
 } ASC_QDONE_INFO;
 
 typedef struct asc_sg_list {
-    ulong               addr;
-    ulong               bytes;
+    ASC_PADDR           addr;
+    ASC_DCNT            bytes;
 } ASC_SG_LIST;
 
 typedef struct asc_sg_head {
@@ -1621,14 +1616,19 @@
 #define ASC_MIN_TAGGED_CMD  7
 #define ASC_MAX_SCSI_RESET_WAIT      30
 
+struct asc_dvc_var;     /* Forward Declaration. */
+
+typedef void (* ASC_ISR_CALLBACK)(struct asc_dvc_var *, ASC_QDONE_INFO *);
+typedef int (* ASC_EXE_CALLBACK)(struct asc_dvc_var *, ASC_SCSI_Q *);
+
 typedef struct asc_dvc_var {
     PortAddr            iop_base;
     ushort              err_code;
     ushort              dvc_cntl;
     ushort              bug_fix_cntl;
     ushort              bus_type;
-    Ptr2Func            isr_callback;
-    Ptr2Func            exe_callback;
+    ASC_ISR_CALLBACK    isr_callback;
+    ASC_EXE_CALLBACK    exe_callback;
     ASC_SCSI_BIT_ID_TYPE init_sdtr;
     ASC_SCSI_BIT_ID_TYPE sdtr_done;
     ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
@@ -1650,32 +1650,26 @@
     ASC_SCSI_Q  *scsiq_busy_tail[ASC_MAX_TID + 1];
     uchar               sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
     ASC_DVC_CFG *cfg;
-    Ptr2Func            saved_ptr2func;
     ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
     char                redo_scam;
     ushort              res2;
     uchar               dos_int13_table[ASC_MAX_TID + 1];
-    ulong               max_dma_count;
+    ASC_DCNT            max_dma_count;
     ASC_SCSI_BIT_ID_TYPE no_scam;
     ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
     uchar               max_sdtr_index;
     uchar               host_init_sdtr_index;
-    ulong               drv_ptr;
-    ulong               uc_break;
-    ulong               res7;
-    ulong               res8;
+    struct asc_board    *drv_ptr;
+    ASC_DCNT            uc_break;
 } ASC_DVC_VAR;
 
-typedef int (* ASC_ISR_CALLBACK) (ASC_DVC_VAR asc_ptr_type *, ASC_QDONE_INFO *);
-typedef int (* ASC_EXE_CALLBACK) (ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q *);
-
 typedef struct asc_dvc_inq_info {
     uchar               type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
 } ASC_DVC_INQ_INFO;
 
 typedef struct asc_cap_info {
-    ulong               lba;
-    ulong               blk_size;
+    ASC_DCNT            lba;
+    ASC_DCNT            blk_size;
 } ASC_CAP_INFO;
 
 typedef struct asc_cap_info_array {
@@ -2033,29 +2027,29 @@
 STATIC uchar     AscGetIsaDmaSpeed(PortAddr);
 STATIC uchar     AscReadLramByte(PortAddr, ushort);
 STATIC ushort    AscReadLramWord(PortAddr, ushort);
-STATIC ulong     AscReadLramDWord(PortAddr, ushort);
+STATIC ASC_DCNT  AscReadLramDWord(PortAddr, ushort);
 STATIC void      AscWriteLramWord(PortAddr, ushort, ushort);
-STATIC void      AscWriteLramDWord(PortAddr, ushort, ulong);
+STATIC void      AscWriteLramDWord(PortAddr, ushort, ASC_DCNT);
 STATIC void      AscWriteLramByte(PortAddr, ushort, uchar);
-STATIC ulong     AscMemSumLramWord(PortAddr, ushort, rint);
-STATIC void      AscMemWordSetLram(PortAddr, ushort, ushort, rint);
+STATIC ASC_DCNT  AscMemSumLramWord(PortAddr, ushort, int);
+STATIC void      AscMemWordSetLram(PortAddr, ushort, ushort, int);
 STATIC void      AscMemWordCopyToLram(PortAddr, ushort, ushort *, int);
-STATIC void      AscMemDWordCopyToLram(PortAddr, ushort, ulong *, int);
+STATIC void      AscMemDWordCopyToLram(PortAddr, ushort, ASC_DCNT *, int);
 STATIC void      AscMemWordCopyFromLram(PortAddr, ushort, ushort *, int);
-STATIC ushort    AscInitAscDvcVar(ASC_DVC_VAR asc_ptr_type *);
-STATIC ushort    AscInitFromEEP(ASC_DVC_VAR asc_ptr_type *);
-STATIC ushort    AscInitFromAscDvcVar(ASC_DVC_VAR asc_ptr_type *);
-STATIC ushort    AscInitMicroCodeVar(ASC_DVC_VAR asc_ptr_type * asc_dvc);
-STATIC int       AscTestExternalLram(ASC_DVC_VAR asc_ptr_type *);
-STATIC uchar     AscMsgOutSDTR(ASC_DVC_VAR asc_ptr_type *, uchar, uchar);
-STATIC uchar     AscCalSDTRData(ASC_DVC_VAR asc_ptr_type *, uchar, uchar);
+STATIC ushort    AscInitAscDvcVar(ASC_DVC_VAR *);
+STATIC ushort    AscInitFromEEP(ASC_DVC_VAR *);
+STATIC ushort    AscInitFromAscDvcVar(ASC_DVC_VAR *);
+STATIC ushort    AscInitMicroCodeVar(ASC_DVC_VAR *);
+STATIC int       AscTestExternalLram(ASC_DVC_VAR *);
+STATIC uchar     AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
+STATIC uchar     AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
 STATIC void      AscSetChipSDTR(PortAddr, uchar, uchar);
-STATIC uchar     AscGetSynPeriodIndex(ASC_DVC_VAR asc_ptr_type *, ruchar);
+STATIC uchar     AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
 STATIC uchar     AscAllocFreeQueue(PortAddr, uchar);
 STATIC uchar     AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
-STATIC int       AscRiscHaltedAbortSRB(ASC_DVC_VAR asc_ptr_type *, ulong);
+STATIC int       AscRiscHaltedAbortSRB(ASC_DVC_VAR *, ASC_DCNT);
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-STATIC int       AscRiscHaltedAbortTIX(ASC_DVC_VAR asc_ptr_type *, uchar);
+STATIC int       AscRiscHaltedAbortTIX(ASC_DVC_VAR *, uchar);
 #endif /* version >= v1.3.89 */
 STATIC int       AscHostReqRiscHalt(PortAddr);
 STATIC int       AscStopQueueExe(PortAddr);
@@ -2064,39 +2058,39 @@
 STATIC int       AscCleanUpDiscQueue(PortAddr);
 #endif /* version >= v1.3.89 */
 STATIC int       AscCleanUpBusyQueue(PortAddr);
-STATIC int       AscWaitTixISRDone(ASC_DVC_VAR asc_ptr_type *, uchar);
-STATIC int       AscWaitISRDone(ASC_DVC_VAR asc_ptr_type *);
-STATIC ulong     AscGetOnePhyAddr(ASC_DVC_VAR asc_ptr_type *, uchar *,
-                    ulong);
-STATIC int       AscSendScsiQueue(ASC_DVC_VAR asc_ptr_type * asc_dvc,
+STATIC int       AscWaitTixISRDone(ASC_DVC_VAR *, uchar);
+STATIC int       AscWaitISRDone(ASC_DVC_VAR *);
+STATIC ASC_PADDR AscGetOnePhyAddr(ASC_DVC_VAR *, uchar *,
+                    ASC_DCNT);
+STATIC int       AscSendScsiQueue(ASC_DVC_VAR *,
                     ASC_SCSI_Q * scsiq,
                     uchar n_q_required);
-STATIC int       AscPutReadyQueue(ASC_DVC_VAR asc_ptr_type *,
+STATIC int       AscPutReadyQueue(ASC_DVC_VAR *,
                     ASC_SCSI_Q *, uchar);
-STATIC int       AscPutReadySgListQueue(ASC_DVC_VAR asc_ptr_type *,
+STATIC int       AscPutReadySgListQueue(ASC_DVC_VAR *,
                     ASC_SCSI_Q *, uchar);
 STATIC int       AscSetChipSynRegAtID(PortAddr, uchar, uchar);
 STATIC int       AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
-STATIC ushort    AscInitLram(ASC_DVC_VAR asc_ptr_type *);
-STATIC int       AscReInitLram(ASC_DVC_VAR asc_ptr_type *);
-STATIC ushort    AscInitQLinkVar(ASC_DVC_VAR asc_ptr_type *);
-STATIC int       AscSetLibErrorCode(ASC_DVC_VAR asc_ptr_type *, ushort);
+STATIC ushort    AscInitLram(ASC_DVC_VAR *);
+STATIC int       AscReInitLram(ASC_DVC_VAR *);
+STATIC ushort    AscInitQLinkVar(ASC_DVC_VAR *);
+STATIC int       AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 STATIC int       _AscWaitQDone(PortAddr, ASC_SCSI_Q *);
 #endif /* version >= v1.3.89 */
-STATIC int       AscIsrChipHalted(ASC_DVC_VAR asc_ptr_type *);
+STATIC int       AscIsrChipHalted(ASC_DVC_VAR *);
 STATIC uchar     _AscCopyLramScsiDoneQ(PortAddr, ushort,
-                    ASC_QDONE_INFO *, ulong);
-STATIC int       AscIsrQDone(ASC_DVC_VAR asc_ptr_type *);
+                    ASC_QDONE_INFO *, ASC_DCNT);
+STATIC int       AscIsrQDone(ASC_DVC_VAR *);
 STATIC int       AscCompareString(uchar *, uchar *, int);
 STATIC ushort    AscGetEisaChipCfg(PortAddr);
-STATIC ulong     AscGetEisaProductID(PortAddr);
+STATIC ASC_DCNT  AscGetEisaProductID(PortAddr);
 STATIC PortAddr  AscSearchIOPortAddrEISA(PortAddr);
 STATIC uchar     AscGetChipScsiCtrl(PortAddr);
 STATIC uchar     AscSetChipScsiID(PortAddr, uchar);
 STATIC uchar     AscGetChipVersion(PortAddr, ushort);
 STATIC ushort    AscGetChipBusType(PortAddr);
-STATIC ulong     AscLoadMicroCode(PortAddr, ushort, ushort *, ushort);
+STATIC ASC_DCNT  AscLoadMicroCode(PortAddr, ushort, ushort *, ushort);
 STATIC int       AscFindSignature(PortAddr);
 STATIC PortAddr  AscSearchIOPortAddr11(PortAddr);
 STATIC void      AscToggleIRQAct(PortAddr);
@@ -2108,38 +2102,38 @@
 STATIC void      DvcLeaveCritical(int);
 STATIC void      DvcInPortWords(PortAddr, ushort *, int);
 STATIC void      DvcOutPortWords(PortAddr, ushort *, int);
-STATIC void      DvcOutPortDWords(PortAddr, ulong *, int);
-STATIC uchar     DvcReadPCIConfigByte(ASC_DVC_VAR asc_ptr_type *, ushort);
-STATIC void      DvcWritePCIConfigByte(ASC_DVC_VAR asc_ptr_type *,
+STATIC void      DvcOutPortDWords(PortAddr, ASC_DCNT *, int);
+STATIC uchar     DvcReadPCIConfigByte(ASC_DVC_VAR *, ushort);
+STATIC void      DvcWritePCIConfigByte(ASC_DVC_VAR *,
                     ushort, uchar);
 STATIC ushort      AscGetChipBiosAddress(PortAddr, ushort);
-STATIC void      DvcSleepMilliSecond(ulong);
-STATIC void      DvcDelayNanoSecond(ASC_DVC_VAR asc_ptr_type *, ulong);
-STATIC ulong     DvcGetSGList(ASC_DVC_VAR asc_ptr_type *, uchar *,
-                    ulong, ASC_SG_HEAD *);
+STATIC void      DvcSleepMilliSecond(ASC_DCNT);
+STATIC void      DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
+STATIC ASC_DCNT  DvcGetSGList(ASC_DVC_VAR *, uchar *,
+                    ASC_DCNT, ASC_SG_HEAD *);
 STATIC void      DvcPutScsiQ(PortAddr, ushort, ushort *, int);
 STATIC void      DvcGetQinfo(PortAddr, ushort, ushort *, int);
 STATIC PortAddr  AscSearchIOPortAddr(PortAddr, ushort);
-STATIC ushort    AscInitGetConfig(ASC_DVC_VAR asc_ptr_type *);
-STATIC ushort    AscInitSetConfig(ASC_DVC_VAR asc_ptr_type *);
-STATIC ushort    AscInitAsc1000Driver(ASC_DVC_VAR asc_ptr_type *);
-STATIC void      AscAsyncFix(ASC_DVC_VAR asc_ptr_type *, uchar,
+STATIC ushort    AscInitGetConfig(ASC_DVC_VAR *);
+STATIC ushort    AscInitSetConfig(ASC_DVC_VAR *);
+STATIC ushort    AscInitAsc1000Driver(ASC_DVC_VAR *);
+STATIC void      AscAsyncFix(ASC_DVC_VAR *, uchar,
                     ASC_SCSI_INQUIRY *);
 STATIC int       AscTagQueuingSafe(ASC_SCSI_INQUIRY *);
-STATIC void      AscInquiryHandling(ASC_DVC_VAR asc_ptr_type *,
+STATIC void      AscInquiryHandling(ASC_DVC_VAR *,
                     uchar, ASC_SCSI_INQUIRY *);
-STATIC int       AscExeScsiQueue(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q *);
-STATIC int       AscISR(ASC_DVC_VAR asc_ptr_type *);
-STATIC uint      AscGetNumOfFreeQueue(ASC_DVC_VAR asc_ptr_type *, uchar,
+STATIC int       AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
+STATIC int       AscISR(ASC_DVC_VAR *);
+STATIC uint      AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar,
                     uchar);
 STATIC int       AscSgListToQueue(int);
-STATIC int       AscAbortSRB(ASC_DVC_VAR asc_ptr_type *, ulong);
+STATIC int       AscAbortSRB(ASC_DVC_VAR *, ASC_VADDR);
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
-STATIC int       AscResetDevice(ASC_DVC_VAR asc_ptr_type *, uchar);
+STATIC int       AscResetDevice(ASC_DVC_VAR *, uchar);
 #endif /* version >= v1.3.89 */
-STATIC int       AscResetSB(ASC_DVC_VAR asc_ptr_type *);
+STATIC int       AscResetSB(ASC_DVC_VAR *);
 STATIC void      AscEnableIsaDma(uchar);
-STATIC ulong     AscGetMaxDmaCount(ushort);
+STATIC ASC_DCNT  AscGetMaxDmaCount(ushort);
 
 
 /*
@@ -2147,7 +2141,7 @@
  */
 
 #define ADV_LIB_VERSION_MAJOR  5
-#define ADV_LIB_VERSION_MINOR  2
+#define ADV_LIB_VERSION_MINOR  5
 
 /* d_os_dep.h */
 #define ADV_OS_LINUX
@@ -2155,10 +2149,36 @@
 /*
  * Define Adv Library required special types.
  */
+
+/*
+ * Portable Data Types
+ *
+ * Any instance where a 32-bit long or pointer type is assumed
+ * for precision or HW defined structures, the following define
+ * types must be used. In Linux the char, short, and int types
+ * are all consistent at 8, 16, and 32 bits respectively. Pointers
+ * and long types are 64 bits on Alpha and UltraSPARC.
+ */ 
+#define ADV_PADDR __u32         /* Physical address data type. */
+#define ADV_VADDR __u32         /* Virtual address data type. */
+#define ADV_DCNT  __u32         /* Unsigned Data count type. */
+#define ADV_SDCNT __s32         /* Signed Data count type. */
+
+/*
+ * These macros are used to convert a virtual address to a
+ * 32-bit value. This currently can be used on Linux Alpha
+ * which uses 64-bit virtual address but a 32-bit bus address.
+ * This is likely to break in the future, but doing this now
+ * will give us time to change the HW and FW to handle 64-bit
+ * addresses.
+ */
+#define ADV_VADDR_TO_U32   virt_to_bus
+#define ADV_U32_TO_VADDR   bus_to_virt
+
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
 #define AdvPortAddr  unsigned short     /* I/O Port address size */
 #else /* version >= v1,3,0 */
-#define AdvPortAddr  unsigned long      /* Virtual memory address size */
+#define AdvPortAddr  ulong              /* Virtual memory address size */
 #endif /* version >= v1,3,0 */
 
 /*
@@ -2181,15 +2201,21 @@
 
 /*
  * Define total number of simultaneous maximum element scatter-gather
- * requests, i.e. ADV_TOT_SG_LIST * ADV_MAX_SG_LIST is the total number
- * of simultaneous scatter-gather elements supported per wide adapter.
+ * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
+ * maximum number of outstanding commands per wide host adapter. Each
+ * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather
+ * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
+ * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
+ * structures or 255 scatter-gather elements.
+ * 
  */
-#define ADV_TOT_SG_LIST         64
+#define ADV_TOT_SG_BLOCK        ASC_DEF_MAX_HOST_QNG
 
 /*
- * Define Adv Library required per request scatter-gather element limit.
+ * Define Adv Library required maximum number of scatter-gather
+ * elements per request.
  */
-#define ADV_MAX_SG_LIST         64
+#define ADV_MAX_SG_LIST         255
 
 /* Number of SG blocks needed. */
 #define ADV_NUM_SG_BLOCK \
@@ -2204,8 +2230,6 @@
 #define ADV_NUM_PAGE_CROSSING \
     ((ADV_SG_TOTAL_MEM_SIZE + (ASC_PAGE_SIZE - 1))/ASC_PAGE_SIZE)
 
-#define ADV_ASSERT(a) ASC_ASSERT(a)
-
 /* a_condor.h */
 #define ADV_PCI_VENDOR_ID               0x10CD
 #define ADV_PCI_DEVICE_ID_REV_A         0x2300
@@ -2221,8 +2245,13 @@
 
 #define ADV_EEPROM_BIG_ENDIAN          0x8000   /* EEPROM Bit 15 */
 #define ADV_EEPROM_BIOS_ENABLE         0x4000   /* EEPROM Bit 14 */
+/*
+ * For the ASC3550 Bit 13 is Termination Polarity control bit.
+ * For later ICs Bit 13 controls whether the CIS (Card Information
+ * Service Section) is loaded from EEPROM.
+ */
 #define ADV_EEPROM_TERM_POL            0x2000   /* EEPROM Bit 13 */
-#define ADV_EEPROM_CIS_LD              0x1000   /* EEPROM Bit 12 */
+#define ADV_EEPROM_CIS_LD              0x2000   /* EEPROM Bit 13 */
 
 typedef struct adveep_3550_config
 {
@@ -2299,8 +2328,7 @@
                                 /* Word Offset, Description */
 
   ushort cfg_lsw;               /* 00 power up initialization */
-                                /*  bit 12 set - CIS Load */
-                                /*  bit 13 set - Term Polarity Control */
+                                /*  bit 13 set - Load CIS */
                                 /*  bit 14 set - BIOS Enable */
                                 /*  bit 15 set - Big Endian Mode */
   ushort cfg_msw;               /* 01 unused      */
@@ -2448,12 +2476,12 @@
 #define IOPB_SOFT_OVER_WR       0x0E
 #define IOPB_RES_ADDR_F         0x0F
 #define IOPB_MEM_CFG            0x10
-#define IOPB_GPIO_CNTL          0x11
+#define IOPB_RES_ADDR_11        0x11
 #define IOPB_GPIO_DATA          0x12
 #define IOPB_RES_ADDR_13        0x13
 #define IOPB_FLASH_PAGE         0x14
 #define IOPB_RES_ADDR_15        0x15
-#define IOPB_RES_ADDR_16        0x16
+#define IOPB_GPIO_CNTL          0x16
 #define IOPB_RES_ADDR_17        0x17
 #define IOPB_FLASH_DATA         0x18
 #define IOPB_RES_ADDR_19        0x19
@@ -2489,7 +2517,7 @@
 #define IOPB_RES_ADDR_37        0x37
 #define IOPB_RAM_BIST           0x38
 #define IOPB_PLL_TEST           0x39
-#define IOPB_RES_ADDR_3A        0x3A
+#define IOPB_PCI_INT_CFG        0x3A
 #define IOPB_RES_ADDR_3B        0x3B
 #define IOPB_RFIFO_CNT          0x3C
 #define IOPB_RES_ADDR_3D        0x3D
@@ -2850,16 +2878,16 @@
 
 typedef struct adv_carr_t
 {
-    ulong       carr_va;       /* Carrier Virtual Address */
-    ulong       carr_pa;       /* Carrier Physical Address */
-    ulong       areq_vpa;      /* ASC_SCSI_REQ_Q Virtual or Physical Address */
+    ADV_VADDR   carr_va;       /* Carrier Virtual Address */
+    ADV_PADDR   carr_pa;       /* Carrier Physical Address */
+    ADV_VADDR   areq_vpa;      /* ASC_SCSI_REQ_Q Virtual or Physical Address */
     /*
      * next_vpa [31:4]            Carrier Virtual or Physical Next Pointer
      *
      * next_vpa [3:1]             Reserved Bits
      * next_vpa [0]               Done Flag set in Response Queue.
      */
-    ulong       next_vpa;
+    ADV_VADDR   next_vpa;
 } ADV_CARR_T;
 
 /*
@@ -2870,7 +2898,7 @@
 #define ASC_RQ_DONE             0x00000001
 #define ASC_CQ_STOPPER          0x00000000
 
-#define ASC_GET_CARRP(carrp) ((ADV_CARR_T *) ((carrp) & ASC_NEXT_VPA_MASK))
+#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
 
 #define ADV_PAGE_SIZE   4096    /* Assume 4KB page size. */
 
@@ -2965,7 +2993,7 @@
   uchar  max_host_qng;    /* maximum number of Q'ed command allowed */
   uchar  irq_no;          /* IRQ number */
   ushort no_scam;         /* scam_tolerant of EEPROM */
-  ulong  drv_ptr;         /* driver pointer to private structure */
+  struct asc_board *drv_ptr; /* driver pointer to private structure */
   uchar  chip_scsi_id;    /* chip SCSI target ID */
   uchar  chip_type;
   uchar  bist_err_code;
@@ -2988,10 +3016,10 @@
     uchar reserved2; 
     uchar reserved3;
     uchar sg_cnt;                     /* Valid entries in block. */
-    struct asc_sg_block *sg_ptr; /* links to the next sg block */
+    ADV_PADDR sg_ptr;                 /* Pointer to next sg block. */
     struct  {
-        ulong sg_addr;                /* SG element address. */
-        ulong sg_count;               /* SG element count. */
+        ADV_PADDR sg_addr;                  /* SG element address. */
+        ADV_DCNT  sg_count;                 /* SG element count. */
     } sg_list[NO_OF_SG_PER_BLOCK];
 } ADV_SG_BLOCK;
 
@@ -3005,13 +3033,13 @@
  */
 typedef struct adv_scsi_req_q {
     uchar       cntl;           /* Ucode flags and state (ASC_MC_QC_*). */
-    uchar       reserved;
+    uchar       target_cmd;
     uchar       target_id;      /* Device target identifier. */
     uchar       target_lun;     /* Device target logical unit number. */
-    ulong       data_addr;      /* Data buffer physical address. */
-    ulong       data_cnt;       /* Data count. Ucode sets to residual. */
-    ulong       sense_addr;
-    ulong       carr_pa;
+    ADV_PADDR   data_addr;      /* Data buffer physical address. */
+    ADV_DCNT    data_cnt;       /* Data count. Ucode sets to residual. */
+    ADV_PADDR   sense_addr;
+    ADV_PADDR   carr_pa;
     uchar       mflag;
     uchar       sense_len;
     uchar       cdb_len;        /* SCSI CDB length. */
@@ -3021,18 +3049,18 @@
     uchar       host_status;    /* Ucode host status. */
     uchar       sg_working_ix;
     uchar       cdb[12];        /* SCSI command block. */
-    ulong       sg_real_addr;   /* SG list physical address. */
-    ulong       scsiq_rptr;
-    ulong       sg_working_data_cnt;
-    struct adv_scsi_req_q *scsiq_ptr;
-    ulong       carr_va;
+    ADV_PADDR   sg_real_addr;   /* SG list physical address. */
+    ADV_PADDR   scsiq_rptr;
+    ADV_DCNT    sg_working_data_cnt;
+    ADV_VADDR   scsiq_ptr;
+    ADV_VADDR   carr_va;
     /*
      * End of microcode structure - 60 bytes. The rest of the structure
      * is used by the Adv Library and ignored by the microcode.
      */
-    ulong       srb_ptr;
+    ADV_VADDR   srb_ptr;
     ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
-    ulong       vdata_addr;     /* Data buffer virtual address. */
+    char        *vdata_addr;   /* Data buffer virtual address. */
     uchar       a_flag;
 } ADV_SCSI_REQ_Q;
 
@@ -3077,18 +3105,17 @@
  */
 STATIC int   DvcEnterCritical(void);
 STATIC void  DvcLeaveCritical(int);
-STATIC void  DvcSleepMilliSecond(ulong);
+STATIC void  DvcSleepMilliSecond(ADV_DCNT);
 STATIC uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort);
 STATIC void  DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar);
-STATIC ulong DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
-                uchar *, long *, int);
+STATIC ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
+                uchar *, ASC_SDCNT *, int);
 STATIC void  DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
 
 /*
  * Adv Library functions available to drivers.
  */
-STATIC int     AdvExeScsiQueue(ADV_DVC_VAR *,
-                         ADV_SCSI_REQ_Q *);
+STATIC int     AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
 STATIC int     AdvISR(ADV_DVC_VAR *);
 STATIC int     AdvInitGetConfig(ADV_DVC_VAR *);
 STATIC int     AdvInitAsc3550Driver(ADV_DVC_VAR *);
@@ -3099,7 +3126,7 @@
 /*
  * Internal Adv Library functions.
  */
-STATIC int    AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ulong);
+STATIC int    AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
 STATIC void   AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
 STATIC int    AdvInitFrom3550EEP(ADV_DVC_VAR *);
 STATIC int    AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
@@ -3119,16 +3146,20 @@
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
 
 /* Read byte from a register. */
-#define AdvReadByteRegister(iop_base, reg_off) (inp((iop_base) + (reg_off)))
+#define AdvReadByteRegister(iop_base, reg_off) \
+    (inp((iop_base) + (reg_off)))
 
 /* Write byte to a register. */
-#define AdvWriteByteRegister(iop_base, reg_off, byte) (outp((iop_base) + (reg_off), (byte)))
+#define AdvWriteByteRegister(iop_base, reg_off, byte) \
+    (outp((iop_base) + (reg_off), (byte)))
 
 /* Read word (2 bytes) from a register. */
-#define AdvReadWordRegister(iop_base, reg_off) (inpw((iop_base) + (reg_off)))
+#define AdvReadWordRegister(iop_base, reg_off) \
+    (le16_to_cpu(inpw((iop_base) + (reg_off))))
 
 /* Write word (2 bytes) to a register. */
-#define AdvWriteWordRegister(iop_base, reg_off, word) (outpw((iop_base) + (reg_off), (word)))
+#define AdvWriteWordRegister(iop_base, reg_off, word) \
+    (outpw((iop_base) + (reg_off), cpu_to_le16(word)))
 
 /* Read byte from LRAM. */
 #define AdvReadByteLram(iop_base, addr, byte) \
@@ -3146,29 +3177,31 @@
 #define AdvReadWordLram(iop_base, addr, word) \
 do { \
     outpw((iop_base) + IOPW_RAM_ADDR, (addr));  \
-    (word) = inpw((iop_base) + IOPW_RAM_DATA); \
+    (word) = le16_to_cpu(inpw((iop_base) + IOPW_RAM_DATA)); \
 } while (0)
 
 /* Write word (2 bytes) to LRAM. */
 #define AdvWriteWordLram(iop_base, addr, word) \
     (outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \
-     outpw((iop_base) + IOPW_RAM_DATA, (word)))
+     outpw((iop_base) + IOPW_RAM_DATA, cpu_to_le16(word)))
 
 /* Write double word (4 bytes) to LRAM */
 /* Because of unspecified C language ordering don't use auto-increment. */
 #define AdvWriteDWordLram(iop_base, addr, dword) \
     ((outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \
-      outpw((iop_base) + IOPW_RAM_DATA, (ushort) ((dword) & 0xFFFF))), \
+      outpw((iop_base) + IOPW_RAM_DATA, \
+        cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
      (outpw((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
-      outpw((iop_base) + IOPW_RAM_DATA, (ushort) ((dword >> 16) & 0xFFFF))))
+      outpw((iop_base) + IOPW_RAM_DATA, \
+        cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
 
 /* Read word (2 bytes) from LRAM assuming that the address is already set. */
 #define AdvReadWordAutoIncLram(iop_base) \
-     (inpw((iop_base) + IOPW_RAM_DATA))
+     (le16_to_cpu(inpw((iop_base) + IOPW_RAM_DATA)))
 
 /* Write word (2 bytes) to LRAM assuming that the address is already set. */
 #define AdvWriteWordAutoIncLram(iop_base, word) \
-     (outpw((iop_base) + IOPW_RAM_DATA, (word)))
+     (outpw((iop_base) + IOPW_RAM_DATA, cpu_to_le16(word)))
 
 #else /* version >= v1,3,0 */
 
@@ -3182,11 +3215,11 @@
 
 /* Read word (2 bytes) from a register. */
 #define AdvReadWordRegister(iop_base, reg_off) \
-     (ADV_MEM_READW((iop_base) + (reg_off)))
+     le16_to_cpu(ADV_MEM_READW((iop_base) + (reg_off)))
 
 /* Write word (2 bytes) to a register. */
 #define AdvWriteWordRegister(iop_base, reg_off, word) \
-     (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
+     (ADV_MEM_WRITEW((iop_base) + (reg_off), cpu_to_le16(word)))
 
 /* Read byte from LRAM. */
 #define AdvReadByteLram(iop_base, addr, byte) \
@@ -3204,31 +3237,31 @@
 #define AdvReadWordLram(iop_base, addr, word) \
 do { \
     ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
-    (word) = ADV_MEM_READW((iop_base) + IOPW_RAM_DATA); \
+    (word) = le16_to_cpu(ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
 } while (0)
 
 /* Write word (2 bytes) to LRAM. */
 #define AdvWriteWordLram(iop_base, addr, word) \
     (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
-     ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
+     ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, cpu_to_le16(word)))
 
 /* Write double word (4 bytes) to LRAM */
 /* Because of unspecified C language ordering don't use auto-increment. */
 #define AdvWriteDWordLram(iop_base, addr, dword) \
     ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
       ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
-                     (ushort) ((dword) & 0xFFFF))), \
+                     cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
      (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
       ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
-                     (ushort) ((dword >> 16) & 0xFFFF))))
+                     cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
 
 /* Read word (2 bytes) from LRAM assuming that the address is already set. */
 #define AdvReadWordAutoIncLram(iop_base) \
-     (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
+     le16_to_cpu(ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
 
 /* Write word (2 bytes) to LRAM assuming that the address is already set. */
 #define AdvWriteWordAutoIncLram(iop_base, word) \
-     (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
+     (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, cpu_to_le16(word)))
 
 #endif /* version >= v1,3,0 */
 
@@ -3266,7 +3299,7 @@
  */
 #define AdvAbortQueue(asc_dvc, scsiq) \
         AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
-                       (ulong) (scsiq))
+                       (ADV_DCNT) (scsiq))
 
 /*
  * Send a Bus Device Reset Message to the specified target ID.
@@ -3281,7 +3314,7 @@
  */
 #define AdvResetDevice(asc_dvc, target_id) \
         AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
-                    (ulong) (target_id))
+                    (ADV_DCNT) (target_id))
 
 /*
  * SCSI Wide Type definition.
@@ -3374,15 +3407,6 @@
          (sizeof(ADV_SG_BLOCK) * \
           ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
 
-/*
- * A driver may optionally define the assertion macro ADV_ASSERT() in
- * its d_os_dep.h file. If the macro has not already been defined,
- * then define the macro to a no-op.
- */
-#ifndef ADV_ASSERT
-#define ADV_ASSERT(a)
-#endif /* ADV_ASSERT */
-
 typedef struct {
   uchar peri_dvc_type   : 5;    /* peripheral device type */
   uchar peri_qualifier  : 3;    /* peripheral qualifier */
@@ -3819,28 +3843,28 @@
 /* Per board statistics structure */
 struct asc_stats {
     /* Driver Entrypoint Statistics */
-    ulong     command;         /* # calls to advansys_command() */
-    ulong     queuecommand;    /* # calls to advansys_queuecommand() */
-    ulong     abort;           /* # calls to advansys_abort() */
-    ulong     reset;           /* # calls to advansys_reset() */
-    ulong     biosparam;       /* # calls to advansys_biosparam() */
-    ulong     interrupt;       /* # advansys_interrupt() calls */
-    ulong     callback;        /* # calls to asc/adv_isr_callback() */
-    ulong     done;            /* # calls to request's scsi_done function */
-    ulong     build_error;     /* # asc/adv_build_req() ASC_ERROR returns. */
-    ulong     adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
-    ulong     adv_build_nosg;  /* # adv_build_req() adv_sgblk_t alloc. fail. */
+    ADV_DCNT command;         /* # calls to advansys_command() */
+    ADV_DCNT queuecommand;    /* # calls to advansys_queuecommand() */
+    ADV_DCNT abort;           /* # calls to advansys_abort() */
+    ADV_DCNT reset;           /* # calls to advansys_reset() */
+    ADV_DCNT biosparam;       /* # calls to advansys_biosparam() */
+    ADV_DCNT interrupt;       /* # advansys_interrupt() calls */
+    ADV_DCNT callback;        /* # calls to asc/adv_isr_callback() */
+    ADV_DCNT done;            /* # calls to request's scsi_done function */
+    ADV_DCNT build_error;     /* # asc/adv_build_req() ASC_ERROR returns. */
+    ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
+    ADV_DCNT adv_build_nosg;  /* # adv_build_req() adv_sgblk_t alloc. fail. */
     /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
-    ulong     exe_noerror;     /* # ASC_NOERROR returns. */
-    ulong     exe_busy;        /* # ASC_BUSY returns. */
-    ulong     exe_error;       /* # ASC_ERROR returns. */
-    ulong     exe_unknown;     /* # unknown returns. */
+    ADV_DCNT exe_noerror;     /* # ASC_NOERROR returns. */
+    ADV_DCNT exe_busy;        /* # ASC_BUSY returns. */
+    ADV_DCNT exe_error;       /* # ASC_ERROR returns. */
+    ADV_DCNT exe_unknown;     /* # unknown returns. */
     /* Data Transfer Statistics */
-    ulong     cont_cnt;        /* # non-scatter-gather I/O requests received */
-    ulong     cont_xfer;       /* # contiguous transfer 512-bytes */
-    ulong     sg_cnt;          /* # scatter-gather I/O requests received */
-    ulong     sg_elem;         /* # scatter-gather elements */
-    ulong     sg_xfer;         /* # scatter-gather transfer 512-bytes */
+    ADV_DCNT cont_cnt;        /* # non-scatter-gather I/O requests received */
+    ADV_DCNT cont_xfer;       /* # contiguous transfer 512-bytes */
+    ADV_DCNT sg_cnt;          /* # scatter-gather I/O requests received */
+    ADV_DCNT sg_elem;         /* # scatter-gather elements */
+    ADV_DCNT sg_xfer;         /* # scatter-gather transfer 512-bytes */
 };
 #endif /* ADVANSYS_STATS */
 
@@ -3854,8 +3878,8 @@
 #ifdef ADVANSYS_STATS
     short                 q_cur_cnt[ADV_MAX_TID+1]; /* current queue count */
     short                 q_max_cnt[ADV_MAX_TID+1]; /* maximum queue count */
-    ulong                 q_tot_cnt[ADV_MAX_TID+1]; /* total enqueue count */
-    ulong                 q_tot_tim[ADV_MAX_TID+1]; /* total time queued */
+    ADV_DCNT              q_tot_cnt[ADV_MAX_TID+1]; /* total enqueue count */
+    ADV_DCNT              q_tot_tim[ADV_MAX_TID+1]; /* total time queued */
     ushort                q_max_tim[ADV_MAX_TID+1]; /* maximum time queued */
     ushort                q_min_tim[ADV_MAX_TID+1]; /* minimum time queued */
 #endif /* ADVANSYS_STATS */
@@ -3864,20 +3888,20 @@
 /*
  * Adv Library Request Structures
  *
- * The following two se structures are used to process Wide Board requests.
- * One structure is needed for each command received from the Mid-Level SCSI
- * driver.
+ * The following two structures are used to process Wide Board requests.
  *
  * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
  * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
  * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
  * Mid-Level SCSI request structure.
  *
- * The adv_sgblk_t structure is used to handle requests that include
- * scatter-gather elements.
+ * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
+ * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
+ * up to 255 scatter-gather elements may be used per request or
+ * ADV_SCSI_REQ_Q.
  */
 typedef struct adv_sgblk {
-    ADV_SG_BLOCK        sg_block[ADV_NUM_SG_BLOCK + ADV_NUM_PAGE_CROSSING];
+    ADV_SG_BLOCK        sg_block;        /* Sgblock structure. */
     uchar               align2[4];       /* Sgblock structure padding. */
     struct adv_sgblk    *next_sgblkp;    /* Next scatter-gather structure. */
 } adv_sgblk_t;
@@ -3945,7 +3969,6 @@
     ADV_CARR_T           *orig_carrp;           /* ADV_CARR_T memory block. */
     adv_req_t            *orig_reqp;            /* adv_req_t memory block. */
     adv_req_t            *adv_reqp;             /* Request structures. */
-    adv_sgblk_t          *orig_sgblkp;          /* adv_sgblk_t memory block. */
     adv_sgblk_t          *adv_sgblkp;           /* Scatter-gather structures. */
     ushort               bios_signature;        /* BIOS Signature. */
     ushort               bios_version;          /* BIOS Version. */
@@ -3992,9 +4015,9 @@
     uchar    latencyTimer;
     uchar    headerType;
     uchar    bist;
-    ulong    baseAddress[6];
+    ADV_PADDR baseAddress[6];
     ushort   reserved[4];
-    ulong    optionRomAddr;
+    ADV_PADDR optionRomAddr;
     ushort   reserved2[4];
     uchar    irqLine;
     uchar    irqPin;
@@ -4009,7 +4032,8 @@
 
 /* Note: All driver global data should be initialized. */
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28) && \
+    LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
 struct proc_dir_entry proc_scsi_advansys =
 {
     PROC_SCSI_ADVANSYS,              /* unsigned short low_ino */
@@ -4018,7 +4042,7 @@
     S_IFDIR | S_IRUGO | S_IXUGO,     /* mode_t mode */
     2                                /* nlink_t nlink */
 };
-#endif /* version >= v1.3.0 */
+#endif /* v2.3.28 > version >= v1.3.0 */
 
 /* Number of boards detected in system. */
 STATIC int asc_board_count = 0;
@@ -4063,7 +4087,8 @@
  */
 uchar adv_carr_buf[20 * sizeof(ADV_CARR_T)] = { 0 };
 uchar adv_req_buf[16 * sizeof(adv_req_t)] = { 0 };
-uchar adv_sgblk_buf[16 * sizeof(adv_sgblk_t)] = { 0 };
+#define ADV_SGBLK_BUF_CNT       32
+uchar adv_sgblk_buf[ADV_SGBLK_BUF_CNT * sizeof(adv_sgblk_t)] = { 0 };
 #endif /* version >= v1,3,0 */
 
 #ifdef ADVANSYS_DEBUG
@@ -4075,7 +4100,7 @@
     "ASC_IS_PCI",
 };
 
-STATIC int          asc_dbglvl = 0;
+STATIC int          asc_dbglvl = 2;
 #endif /* ADVANSYS_DEBUG */
 
 /* Declaration for Asc Library internal data referenced by driver. */
@@ -4105,7 +4130,7 @@
 STATIC int        asc_execute_scsi_cmnd(Scsi_Cmnd *);
 STATIC int        asc_build_req(asc_board_t *, Scsi_Cmnd *);
 STATIC int        adv_build_req(asc_board_t *, Scsi_Cmnd *, ADV_SCSI_REQ_Q **);
-STATIC int        adv_get_sglist(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *, Scsi_Cmnd *);
+STATIC int        adv_get_sglist(asc_board_t *, adv_req_t *, Scsi_Cmnd *);
 STATIC void       asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
 STATIC void       adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
 STATIC void       adv_async_callback(ADV_DVC_VAR *, uchar);
@@ -4432,6 +4457,7 @@
     asc_board_t         *boardp = NULL;
     ASC_DVC_VAR         *asc_dvc_varp = NULL;
     ADV_DVC_VAR         *adv_dvc_varp = NULL;
+    adv_sgblk_t         *sgp = NULL;
     int                 ioport = 0;
     int                 share_irq = FALSE;
     int                 iolen = 0;
@@ -4444,7 +4470,7 @@
     PCI_DEVICE          pciDevice;
     PCI_CONFIG_SPACE    pciConfig;
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
-    unsigned long       pci_memory_address;
+    ADV_PADDR           pci_memory_address;
 #endif /* version >= v1,3,0 */
 #endif /* ASC_CONFIG_PCI */
 #else /* version >= v2.1.93 */ 
@@ -4462,7 +4488,7 @@
                                     ASC_PCI_DEVICE_ID_2300,
                                     ASC_PCI_DEVICE_ID_2500
                         };
-    unsigned long       pci_memory_address;
+    ADV_PADDR           pci_memory_address;
 #endif /* CONFIG_PCI */
 #endif /* version >= v2.1.93 */ 
     int                 warn_code, err_code;
@@ -4477,7 +4503,9 @@
 
     ASC_DBG(1, "advansys_detect: begin\n");
 
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,28)
+    tpnt->proc_name = "advansys";
+#elif LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
     tpnt->proc_dir = &proc_scsi_advansys;
 #endif /* version >= v1.3.0 */
 
@@ -4711,7 +4739,7 @@
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13)
                     iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK;
 #else /* version >= v2.3.13 */ 
-                    iop = pci_devp->resource[1].start & PCI_IOADDRESS_MASK;
+                    iop = pci_devp->resource[0].start & PCI_IOADDRESS_MASK;
 #endif /* version >= v2.3.13 */ 
                     ASC_DBG2(1,
                         "advansys_detect: vendorID %X, deviceID %X\n",
@@ -4785,15 +4813,15 @@
                 ASC_DBG(1, "advansys_detect: narrow board\n");
                 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
                 asc_dvc_varp->bus_type = asc_bus[bus];
-                asc_dvc_varp->drv_ptr = (ulong) boardp;
+                asc_dvc_varp->drv_ptr = boardp;
                 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
                 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
                 asc_dvc_varp->iop_base = iop;
-                asc_dvc_varp->isr_callback = (Ptr2Func) asc_isr_callback;
+                asc_dvc_varp->isr_callback = asc_isr_callback;
             } else {
                 ASC_DBG(1, "advansys_detect: wide board\n");
                 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
-                adv_dvc_varp->drv_ptr = (ulong) boardp;
+                adv_dvc_varp->drv_ptr = boardp;
                 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
                 adv_dvc_varp->isr_callback = adv_isr_callback;
                 adv_dvc_varp->async_callback = adv_async_callback;
@@ -4848,13 +4876,13 @@
 #ifdef ASC_CONFIG_PCI
                 pci_memory_address = pciConfig.baseAddress[1];
                 ASC_DBG1(1, "advansys_detect: pci_memory_address: %lu\n",
-                    pci_memory_address);
+                    (ulong) pci_memory_address);
                 if ((boardp->ioremap_addr =
                     ioremap(pci_memory_address & PAGE_MASK,
                          PAGE_SIZE)) == 0) {
                    ASC_PRINT3(
-"advansys_detect: board %d: ioremap(%lx, %d) returned NULL\n",
-                   boardp->id, pci_memory_address, iolen);
+"advansys_detect: board %d: ioremap(%lu, %x) returned NULL\n",
+                   boardp->id, (ulong) pci_memory_address, iolen);
                    scsi_unregister(shp);
                    asc_board_count--;
                    continue;
@@ -4874,13 +4902,13 @@
 #else /* version >= v2.3.13 */ 
                 pci_memory_address = pci_devp->resource[1].start;
 #endif /* version >= v2.3.13 */ 
-                ASC_DBG1(1, "advansys_detect: pci_memory_address: %lu\n",
+                ASC_DBG1(1, "advansys_detect: pci_memory_address: %x\n",
                     pci_memory_address);
                 if ((boardp->ioremap_addr =
                     ioremap(pci_memory_address & PAGE_MASK,
                          PAGE_SIZE)) == 0) {
                    ASC_PRINT3(
-"advansys_detect: board %d: ioremap(%lx, %d) returned NULL\n",
+"advansys_detect: board %d: ioremap(%x, %d) returned NULL\n",
                    boardp->id, pci_memory_address, iolen);
                    scsi_unregister(shp);
                    asc_board_count--;
@@ -4905,7 +4933,8 @@
                  */
                 boardp->ioport = iop;
 
-                ASC_DBG2(1, "iopb_chip_id_1 %x, iopw_chip_id_0 %x\n",
+                ASC_DBG2(1,
+                    "advansys_detect: iopb_chip_id_1 %x, iopw_chip_id_0 %x\n",
                     (ushort) inp(iop + 1), (ushort) inpw(iop));
             }
 
@@ -5335,6 +5364,7 @@
                 shp->sg_tablesize = ADV_MAX_SG_LIST;
             }
 
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
 #ifdef MODULE
             /*
              * If the driver is compiled as a module, set a limit on the
@@ -5346,6 +5376,7 @@
                 shp->sg_tablesize = 64;
             }
 #endif /* MODULE */
+#endif /* version < v2.0.0 */
 
             /*
              * The value of 'sg_tablesize' can not exceed the SCSI
@@ -5362,9 +5393,14 @@
 
             /* BIOS start address. */
             if (ASC_NARROW_BOARD(boardp)) {
-                shp->base = (char *) ((ulong) AscGetChipBiosAddress(
-                                                asc_dvc_varp->iop_base,
-                                                asc_dvc_varp->bus_type));
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,29)
+                shp->base =
+#else /* version >= v2.3.29 */
+                shp->base = (char *)
+#endif /* version < v2.3.29 */
+                        ((ulong) AscGetChipBiosAddress(
+                            asc_dvc_varp->iop_base,
+                            asc_dvc_varp->bus_type));
             } else {
                 /*
                  * Fill-in BIOS board variables. The Wide BIOS saves
@@ -5396,7 +5432,12 @@
                      * Convert x86 realmode code segment to a linear
                      * address by shifting left 4.
                      */
-                    shp->base = (uchar *) (boardp->bios_codeseg << 4);
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,29)
+                    shp->base =
+#else /* version >= v2.3.29 */
+                    shp->base = (char *)
+#endif /* version < v2.3.29 */
+                        ((ulong) boardp->bios_codeseg << 4);
                 } else {
                     shp->base = 0;
                 }
@@ -5503,21 +5544,26 @@
                 int             req_cnt;
                 adv_req_t       *reqp = NULL;
                 int             sg_cnt = 0;
-                adv_sgblk_t     *sgp = NULL;
 
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
                 carrp = (ADV_CARR_T *) &adv_carr_buf[0];
                 req_cnt = sizeof(adv_req_buf)/sizeof(adv_req_t);
                 sg_cnt = sizeof(adv_sgblk_buf)/sizeof(adv_sgblk_t);
                 reqp = (adv_req_t *) &adv_req_buf[0];
-                sgp = (adv_sgblk_t *) &adv_sgblk_buf[0];
+                boardp->adv_sgblkp = NULL;
+                for (sg_cnt = 0; sg_cnt < ADV_SGBLK_BUF_CNT; sg_cnt++) {
+                    sgp = (adv_sgblk_t *) &adv_sgblk_buf[sg_cnt];
+                    sgp->next_sgblkp = boardp->adv_sgblkp;
+                    boardp->adv_sgblkp = sgp;
+                }
 #else /* version >= v1.3.0 */
                 /*
-                 * Allocate buffer carrier structures.
+                 * Allocate buffer carrier structures. The total size
+                 * is about 4 KB, so allocate all at once.
                  */
                 carrp =
                     (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC);
-                ASC_DBG1(1, "advansys_detect: carrp %x\n", (unsigned) carrp);
+                ASC_DBG1(1, "advansys_detect: carrp %lx\n", (ulong) carrp);
 
                 if (carrp == NULL) {
                     goto kmalloc_error;
@@ -5525,7 +5571,9 @@
 
                 /*
                  * Allocate up to 'max_host_qng' request structures for
-                 * the Wide board.
+                 * the Wide board. The total size is about 16 KB, so
+                 * allocate all at once. If the allocation fails decrement
+                 * and try again.
                  */
                 for (req_cnt = adv_dvc_varp->max_host_qng;
                     req_cnt > 0; req_cnt--) {
@@ -5534,8 +5582,9 @@
                         kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC);
 
                     ASC_DBG3(1,
-                        "advansys_detect: reqp %x, req_cnt %d, bytes %d\n",
-                        (unsigned) reqp, req_cnt, sizeof(adv_req_t) * req_cnt);
+                        "advansys_detect: reqp %lx, req_cnt %d, bytes %lu\n",
+                        (ulong) reqp, req_cnt,
+                        (ulong) sizeof(adv_req_t) * req_cnt);
 
                     if (reqp != NULL) {
                         break;
@@ -5547,22 +5596,27 @@
                 }
 
                 /*
-                 * Allocate up to ADV_TOT_SG_LIST request structures for
-                 * the Wide board.
+                 * Allocate up to ADV_TOT_SG_BLOCK request structures for
+                 * the Wide board. Each structure is about 136 bytes.
                  */
-                for (sg_cnt = ADV_TOT_SG_LIST; sg_cnt > 0; sg_cnt--) {
+                boardp->adv_sgblkp = NULL;
+                for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
 
                     sgp = (adv_sgblk_t *)
-                        kmalloc(sizeof(adv_sgblk_t) * sg_cnt, GFP_ATOMIC);
+                        kmalloc(sizeof(adv_sgblk_t), GFP_ATOMIC);
 
-                    ASC_DBG3(1,
-                        "advansys_detect: sgp %x, sg_cnt %d, bytes %d\n",
-                        (unsigned) sgp, sg_cnt, sizeof(adv_sgblk_t) * sg_cnt);
-
-                    if (sgp != NULL) {
+                    if (sgp == NULL) {
                         break;
                     }
+
+                    sgp->next_sgblkp = boardp->adv_sgblkp;
+                    boardp->adv_sgblkp = sgp;
+
                 }
+                ASC_DBG3(1,
+                    "advansys_detect: sg_cnt %d * %u = %u bytes\n",
+                    sg_cnt, sizeof(adv_sgblk_t),
+                    (unsigned) (sizeof(adv_sgblk_t) * sg_cnt));
 
                 /*
                  * If no request structures or scatter-gather structures could
@@ -5582,11 +5636,11 @@
 "advansys_detect: board %d: error: failed to kmalloc() adv_req_t buffer.\n",
                         boardp->id);
                     err_code = ADV_ERROR;
-                } else if (sgp == NULL) {
+                } else if (boardp->adv_sgblkp == NULL) {
                     kfree(carrp);
                     kfree(reqp);
                     ASC_PRINT1(
-"advansys_detect: board %d: error: failed to kmalloc() adv_sgblk_t buffer.\n",
+"advansys_detect: board %d: error: failed to kmalloc() adv_sgblk_t buffers.\n",
                         boardp->id);
                     err_code = ADV_ERROR;
                 } else {
@@ -5599,12 +5653,6 @@
                      * driver is built as a module and can be unloaded.
                      */
                     boardp->orig_reqp = reqp;
-
-                    /*
-                     * Save original pointer for kfree() in case the
-                     * driver is built as a module and can be unloaded.
-                     */
-                    boardp->orig_sgblkp = sgp;
 #endif /* version >= v1.3.0 */
 
                     adv_dvc_varp->carrier_buf = carrp;
@@ -5620,17 +5668,6 @@
                     }
                     boardp->adv_reqp = &reqp[0];
 
-                    /*
-                     * Point 'adv_sgblkp' to the request structures and
-                     * link them together.
-                     */
-                    sg_cnt--;
-                    sgp[sg_cnt].next_sgblkp = NULL;
-                    for (; sg_cnt > 0; sg_cnt--) {
-                        sgp[sg_cnt - 1].next_sgblkp = &sgp[sg_cnt];
-                    }
-                    boardp->adv_sgblkp = &sgp[0];
-
                     if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
                     {
                         ASC_DBG(2,
@@ -5646,7 +5683,7 @@
                     if (warn_code || err_code) {
                         ASC_PRINT3(
 "AdvInitAsc3550/38C0800Driver: board %d: error: warn %x, error %x\n",
-                            boardp->id, warn_code, adv_dvc_varp->err_code);
+                            boardp->id, warn_code, err_code);
                     }
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
                 }
@@ -5666,9 +5703,10 @@
                         kfree(boardp->orig_reqp);
                         boardp->orig_reqp = boardp->adv_reqp = NULL;
                     }
-                    if (boardp->orig_sgblkp) {
-                        kfree(boardp->orig_sgblkp);
-                        boardp->orig_sgblkp = boardp->adv_sgblkp = NULL;
+                    while ((sgp = boardp->adv_sgblkp) != NULL)
+                    {
+                        boardp->adv_sgblkp = sgp->next_sgblkp;
+                        kfree(sgp);
                     }
                 }
 #endif /* version >= v1,3,0 */
@@ -5718,6 +5756,8 @@
     release_region(shp->io_port, shp->n_io_port);
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
     if (ASC_WIDE_BOARD(boardp)) {
+        adv_sgblk_t    *sgp = NULL;
+
         iounmap(boardp->ioremap_addr);
         if (boardp->orig_carrp) {
             kfree(boardp->orig_carrp);
@@ -5727,9 +5767,10 @@
             kfree(boardp->orig_reqp);
             boardp->orig_reqp = boardp->adv_reqp = NULL;
         }
-        if (boardp->orig_sgblkp) {
-            kfree(boardp->orig_sgblkp);
-            boardp->orig_sgblkp = boardp->adv_sgblkp = NULL;
+        while ((sgp = boardp->adv_sgblkp) != NULL)
+        {
+            boardp->adv_sgblkp = sgp->next_sgblkp;
+            kfree(sgp);
         }
     }
     ASC_ASSERT(boardp->prtbuf != NULL);
@@ -5772,13 +5813,13 @@
             }
             sprintf(info,
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,92)
-"AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X/%X, IRQ %u, DMA %u",
+"AdvanSys SCSI %s: %s %u CDB: BIOS %lX, IO %lX/%X, IRQ %u, DMA %u",
 #else /* version >= v2.1.92 */ 
-"AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %lX/%X, IRQ %u, DMA %u",
+"AdvanSys SCSI %s: %s %u CDB: BIOS %lX, IO %lX/%X, IRQ %u, DMA %u",
 #endif /* version >= v2.1.92 */ 
                 ASC_VERSION, busname, asc_dvc_varp->max_total_qng,
-                (unsigned) shp->base,
-                shp->io_port, shp->n_io_port - 1,
+                (ulong) shp->base,
+                (ulong) shp->io_port, shp->n_io_port - 1,
                 shp->irq, shp->dma_channel);
         } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
             if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
@@ -5808,12 +5849,12 @@
             }
             sprintf(info,
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,92)
-                "AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X/%X, IRQ %u",
+                "AdvanSys SCSI %s: %s %u CDB: BIOS %lX, IO %X/%X, IRQ %u",
 #else /* version >= v2.1.92 */ 
-                "AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %lX/%X, IRQ %u",
+                "AdvanSys SCSI %s: %s %u CDB: BIOS %lX, IO %lX/%X, IRQ %u",
 #endif /* version >= v2.1.92 */ 
                 ASC_VERSION, busname, asc_dvc_varp->max_total_qng,
-                (unsigned) shp->base, shp->io_port - 1,
+                (ulong) shp->base, shp->io_port - 1,
                 shp->n_io_port, shp->irq);
         }
     } else {
@@ -5871,7 +5912,7 @@
 int
 advansys_command(Scsi_Cmnd *scp)
 {
-    ASC_DBG1(1, "advansys_command: scp %x\n", (unsigned) scp);
+    ASC_DBG1(1, "advansys_command: scp %lx\n", (ulong) scp);
     ASC_STATS(scp->host, command);
     scp->SCp.Status = 0; /* Set to a known state */
     advansys_queuecommand(scp, advansys_command_done);
@@ -5914,13 +5955,13 @@
     if (boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) {
         if (boardp->flags & ASC_HOST_IN_RESET) {
             ASC_DBG1(1,
-                "advansys_queuecommand: scp %x blocked for reset request\n",
-                (unsigned) scp);
+                "advansys_queuecommand: scp %lx blocked for reset request\n",
+                (ulong) scp);
             scp->result = HOST_BYTE(DID_RESET);
         } else {
             ASC_DBG1(1,
-                "advansys_queuecommand: scp %x blocked for abort request\n",
-                (unsigned) scp);
+                "advansys_queuecommand: scp %lx blocked for abort request\n",
+                (ulong) scp);
             scp->result = HOST_BYTE(DID_ABORT);
         }
 
@@ -5998,7 +6039,7 @@
     save_flags(flags);
     cli();
 
-    ASC_DBG1(1, "advansys_abort: scp %x\n", (unsigned) scp);
+    ASC_DBG1(1, "advansys_abort: scp %lx\n", (ulong) scp);
 
 #ifdef ADVANSYS_STATS
     if (scp->host != NULL) {
@@ -6015,8 +6056,8 @@
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
     if (scp->serial_number != scp->serial_number_at_timeout) {
         ASC_PRINT1(
-"advansys_abort: timeout serial number changed for request %x\n",
-            (unsigned) scp);
+"advansys_abort: timeout serial number changed for request %lx\n",
+            (ulong) scp);
         do_scsi_done = ASC_FALSE;
         scp_found = ASC_FALSE;
         ret = SCSI_ABORT_NOT_RUNNING;
@@ -6052,8 +6093,8 @@
              * queue, it had not been sent to the device. After
              * the queue is removed, no other handling is required.
              */
-            ASC_DBG1(1, "advansys_abort: scp %x found on waiting queue\n",
-                (unsigned) scp);
+            ASC_DBG1(1, "advansys_abort: scp %lx found on waiting queue\n",
+                (ulong) scp);
             scp_found = ASC_TRUE;
             scp->result = HOST_BYTE(DID_ABORT);
             ret = SCSI_ABORT_SUCCESS;
@@ -6073,9 +6114,10 @@
                 scp->result = HOST_BYTE(DID_ABORT);
 
                 /* sti(); XXX */ /* Enable interrupts for AscAbortSRB(). */
-                ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n",
-                    (unsigned) scp);
-                switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
+                ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %lx\n",
+                    (ulong) scp);
+                /* XXX */
+                switch (AscAbortSRB(asc_dvc_varp, ASC_VADDR_TO_U32(scp))) {
                 case ASC_TRUE:
                     /* asc_isr_callback() will be called */
                     ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n");
@@ -6100,10 +6142,11 @@
                 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
                 scp->result = HOST_BYTE(DID_ABORT);
 
-                ASC_DBG1(1, "advansys_abort: before AdvAbortQueue(), scp %x\n",
-                    (unsigned) scp);
+                ASC_DBG1(1,
+                    "advansys_abort: before AdvAbortQueue(), scp %lx\n",
+                    (ulong) scp);
 #if 0 /* XXX */
-                switch (AdvAbortQueue(adv_dvc_varp, (ulong) XXX)) {
+                switch (AdvAbortQueue(adv_dvc_varp, (ADV_VADDR) XXX)) {
                 case ASC_TRUE:
                     /* asc_isr_callback() will be called */
                     ASC_DBG(1, "advansys_abort: AdvAbortQueue() TRUE\n");
@@ -6184,13 +6227,13 @@
     if (do_scsi_done == ASC_TRUE) {
         if (scp->scsi_done == NULL) {
             ASC_PRINT1(
-"advansys_abort: aborted request scsi_done() is NULL, %x\n",
-                (unsigned) scp);
+"advansys_abort: aborted request scsi_done() is NULL, %lx\n",
+                (ulong) scp);
         } else {
             if (scp_found == ASC_FALSE) {
                 ASC_PRINT1(
-"advansys_abort: abort request not active or waiting, completing anyway %x\n",
-                    (unsigned) scp);
+"advansys_abort: abort request not active or waiting, completing anyway %lx\n",
+                    (ulong) scp);
             }
             ASC_STATS(scp->host, done);
             scp->scsi_done(scp);
@@ -6245,7 +6288,7 @@
     save_flags(flags);
     cli();
 
-    ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp);
+    ASC_DBG1(1, "advansys_reset: %lx\n", (ulong) scp);
 
 #ifdef ADVANSYS_STATS
     if (scp->host != NULL) {
@@ -6257,8 +6300,8 @@
     if ((reset_flags & SCSI_RESET_ASYNCHRONOUS) &&
         (scp->serial_number != scp->serial_number_at_timeout)) {
         ASC_PRINT1(
-"advansys_reset: timeout serial number changed for request %x\n",
-            (unsigned) scp);
+"advansys_reset: timeout serial number changed for request %lx\n",
+            (ulong) scp);
         do_scsi_done = ASC_FALSE;
         scp_found = ASC_FALSE;
         ret = SCSI_RESET_NOT_RUNNING;
@@ -6581,13 +6624,13 @@
     if (do_scsi_done == ASC_TRUE) {
         if (scp->scsi_done == NULL) {
             ASC_PRINT1(
-"advansys_reset: reset request scsi_done() is NULL, %x\n",
-                (unsigned) scp);
+"advansys_reset: reset request scsi_done() is NULL, %lx\n",
+                (ulong) scp);
         } else {
             if (scp_found == ASC_FALSE) {
                 ASC_PRINT1(
-"advansys_reset: reset request not active or waiting, completing anyway %x\n",
-                    (unsigned) scp);
+"advansys_reset: reset request not active or waiting, completing anyway %lx\n",
+                    (ulong) scp);
             }
             ASC_STATS(scp->host, done);
             scp->scsi_done(scp);
@@ -6915,8 +6958,8 @@
             device->queue_depth =
                 boardp->dvc_var.adv_dvc_var.max_dvc_qng;
         }
-        ASC_DBG3(1, "advansys_select_queue_depths: shp %x, id %d, depth %d\n",
-            (unsigned) shp, device->id, device->queue_depth);
+        ASC_DBG3(1, "advansys_select_queue_depths: shp %lx, id %d, depth %d\n",
+            (ulong) shp, device->id, device->queue_depth);
     }
 }
 #endif /* version >= v1.3.89 */
@@ -6928,7 +6971,7 @@
 STATIC void
 advansys_command_done(Scsi_Cmnd *scp)
 {
-    ASC_DBG1(1, "advansys_command_done: scp %x\n", (unsigned) scp);
+    ASC_DBG1(1, "advansys_command_done: scp %lx\n", (ulong) scp);
     scp->SCp.Status = 1;
 }
 
@@ -6945,7 +6988,7 @@
 
     ASC_DBG(2, "asc_scsi_done_list: begin\n");
     while (scp != NULL) {
-        ASC_DBG1(3, "asc_scsi_done_list: scp %x\n", (unsigned) scp);
+        ASC_DBG1(3, "asc_scsi_done_list: scp %lx\n", (ulong) scp);
         tscp = REQPNEXT(scp);
         REQPNEXT(scp) = NULL;
         ASC_STATS(scp->host, done);
@@ -7011,8 +7054,8 @@
     int                ret;
 
     ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-    ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %x, done %x\n",
-        (unsigned) scp, (unsigned) scp->scsi_done);
+    ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %lx, done %lx\n",
+        (ulong) scp, (ulong) scp->scsi_done);
 
     boardp = ASC_BOARDP(scp->host);
     device = boardp->device[scp->target];
@@ -7163,7 +7206,7 @@
     /*
      * Point the ASC_SCSI_Q to the 'Scsi_Cmnd'.
      */
-    asc_scsi_q.q2.srb_ptr = (ulong) scp;
+    asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
 
     /*
      * Build the ASC_SCSI_Q request.
@@ -7178,9 +7221,9 @@
     asc_scsi_q.q1.target_lun = scp->lun;
     asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun);
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-    asc_scsi_q.q1.sense_addr = (ulong) &scp->sense_buffer[0];
+    asc_scsi_q.q1.sense_addr = (ADV_PADDR) &scp->sense_buffer[0];
 #else /* version >= v2.0.0 */
-    asc_scsi_q.q1.sense_addr = virt_to_bus(&scp->sense_buffer[0]);
+    asc_scsi_q.q1.sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
 #endif /* version >= v2.0.0 */
     asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
 
@@ -7212,9 +7255,10 @@
          */
         ASC_STATS(scp->host, cont_cnt);
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-        asc_scsi_q.q1.data_addr = (ulong) scp->request_buffer;
+        asc_scsi_q.q1.data_addr = (ADV_PADDR) scp->request_buffer;
 #else /* version >= v2.0.0 */
-        asc_scsi_q.q1.data_addr = virt_to_bus(scp->request_buffer);
+        asc_scsi_q.q1.data_addr =
+            cpu_to_le32(virt_to_bus(scp->request_buffer));
 #endif /* version >= v2.0.0 */
         asc_scsi_q.q1.data_cnt = scp->request_bufflen;
         ASC_STATS_ADD(scp->host, cont_xfer,
@@ -7258,11 +7302,12 @@
         slp = (struct scatterlist *) scp->request_buffer;
         for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-            asc_sg_head.sg_list[sgcnt].addr = (ulong) slp->address;
+            asc_sg_head.sg_list[sgcnt].addr = (ADV_PADDR) slp->address;
 #else /* version >= v2.0.0 */
-            asc_sg_head.sg_list[sgcnt].addr = virt_to_bus(slp->address);
+            asc_sg_head.sg_list[sgcnt].addr =
+                cpu_to_le32(virt_to_bus(slp->address));
 #endif /* version >= v2.0.0 */
-            asc_sg_head.sg_list[sgcnt].bytes = slp->length;
+            asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(slp->length);
             ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
         }
     }
@@ -7278,6 +7323,10 @@
  *
  * If an adv_req_t can not be allocated to issue the request,
  * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
+ *
+ * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
+ * microcode for DMA addresses or math operations are byte swapped
+ * to little-endian order.
  */
 STATIC int
 adv_build_req(asc_board_t *boardp, Scsi_Cmnd *scp,
@@ -7286,6 +7335,7 @@
     adv_req_t           *reqp;
     ADV_SCSI_REQ_Q      *scsiqp;
     int                 i;
+    int                 ret;
 
     /*
      * Allocate an adv_req_t structure from the board to execute
@@ -7305,12 +7355,16 @@
      * Get 4-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
      */
     scsiqp = (ADV_SCSI_REQ_Q *) ADV_DWALIGN(&reqp->scsi_req_q);
-    memset(scsiqp, 0, sizeof(ADV_SCSI_REQ_Q));
+
+    /*
+     * Initialize the structure.
+     */
+    scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
 
     /*
      * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
      */
-    scsiqp->srb_ptr = (ulong) reqp;
+    scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
 
     /*
      * Set the adv_req_t 'cmndp' to point to the Scsi_Cmnd structure.
@@ -7337,9 +7391,9 @@
     scsiqp->target_lun = scp->lun;
 
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-    scsiqp->sense_addr = (ulong) &scp->sense_buffer[0];
+    scsiqp->sense_addr = (ADV_PADDR) &scp->sense_buffer[0];
 #else /* version >= v2.0.0 */
-    scsiqp->sense_addr = virt_to_bus(&scp->sense_buffer[0]);
+    scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
 #endif /* version >= v2.0.0 */
     scsiqp->sense_len = sizeof(scp->sense_buffer);
 
@@ -7347,12 +7401,12 @@
      * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
      * buffer command.
      */
-    scsiqp->data_cnt = scp->request_bufflen;
-    scsiqp->vdata_addr = (ulong) scp->request_buffer;
+    scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
+    scsiqp->vdata_addr = scp->request_buffer;
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-    scsiqp->data_addr = (ulong) scp->request_buffer;
+    scsiqp->data_addr = (ADV_PADDR) scp->request_buffer;
 #else /* version >= v2.0.0 */
-    scsiqp->data_addr = virt_to_bus(scp->request_buffer);
+    scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
 #endif /* version >= v2.0.0 */
 
     if (scp->use_sg == 0) {
@@ -7361,6 +7415,7 @@
          */
         reqp->sgblkp = NULL;
         scsiqp->sg_list_ptr = NULL;
+        scsiqp->sg_real_addr = 0;
         ASC_STATS(scp->host, cont_cnt);
         ASC_STATS_ADD(scp->host, cont_xfer,
                       ASC_CEILING(scp->request_bufflen, 512));
@@ -7385,46 +7440,7 @@
             return ASC_ERROR;
         }
 
-        /*
-         * Allocate an 'adv_sgblk_t' structure from the board to
-         * execute the command.
-         */
-        if (boardp->adv_sgblkp == NULL) {
-            ASC_DBG(1, "adv_build_req: no free adv_sgblk_t\n");
-            ASC_STATS(scp->host, adv_build_nosg);
-            /*
-             * Free the 'adv_req_t' structure by adding it back to the
-             * board free list.
-             */
-            reqp->next_reqp = boardp->adv_reqp;
-            boardp->adv_reqp = reqp;
-            return ASC_BUSY;
-        } else {
-            reqp->sgblkp = boardp->adv_sgblkp;
-            boardp->adv_sgblkp = reqp->sgblkp->next_sgblkp;
-            reqp->sgblkp->next_sgblkp = NULL;
-        }
-
-        /*
-         * Build scatter-gather list.
-         */
-        scsiqp->sg_list_ptr = (ADV_SG_BLOCK *)
-            ADV_DWALIGN(&reqp->sgblkp->sg_block[0]);
-
-        memset(scsiqp->sg_list_ptr, 0, sizeof(ADV_SG_BLOCK) *
-            (ADV_NUM_SG_BLOCK + ADV_NUM_PAGE_CROSSING));
-         
-        if (adv_get_sglist(&boardp->dvc_var.adv_dvc_var, scsiqp, scp) ==
-            ADV_ERROR) {
-
-            /*
-             * Free the adv_sgblk_t structure, if any, by adding it back
-             * to the board free list.
-             */
-            ASC_ASSERT(reqp->sgblkp != NULL);
-            reqp->sgblkp->next_sgblkp = boardp->adv_sgblkp;
-            boardp->adv_sgblkp = reqp->sgblkp;
-
+        if ((ret = adv_get_sglist(boardp, reqp, scp)) != ADV_SUCCESS) {
             /*
              * Free the adv_req_t structure by adding it back to the
              * board free list.
@@ -7432,7 +7448,7 @@
             reqp->next_reqp = boardp->adv_reqp;
             boardp->adv_reqp = reqp;
 
-            return ADV_ERROR;
+            return ret;
         }
 
         ASC_STATS(scp->host, sg_cnt);
@@ -7450,65 +7466,124 @@
 /*
  * Build scatter-gather list for Adv Library (Wide Board).
  *
+ * Additional ADV_SG_BLOCK structures will need to be allocated
+ * if the total number of scatter-gather elements exceeds
+ * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
+ * assumed to be physically contiguous.
+ *
  * Return:
  *      ADV_SUCCESS(1) - SG List successfully created
  *      ADV_ERROR(-1) - SG List creation failed
  */
 STATIC int
-adv_get_sglist(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp,
-    Scsi_Cmnd *scp)
+adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, Scsi_Cmnd *scp)
 {
-    ADV_SG_BLOCK        *sg_block;              /* virtual address of a SG */
-    ulong               sg_block_next_addr;     /* block and its next */
-    ulong               sg_block_physical_addr;
-    int                 i;
+    adv_sgblk_t         *sgblkp;
+    ADV_SCSI_REQ_Q      *scsiqp;
     struct scatterlist  *slp;
     int                 sg_elem_cnt;
+    ADV_SG_BLOCK        *sg_block, *prev_sg_block;
+    ADV_PADDR           sg_block_paddr;
+    int                 i;
 
+    scsiqp = (ADV_SCSI_REQ_Q *) ADV_DWALIGN(&reqp->scsi_req_q);
     slp = (struct scatterlist *) scp->request_buffer;
     sg_elem_cnt = scp->use_sg;
+    prev_sg_block = NULL;
+    reqp->sgblkp = NULL;
+
+    do
+    {
+        /*
+         * Allocate a 'adv_sgblk_t' structure from the board free
+         * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
+         * (15) scatter-gather elements.
+         */
+        if ((sgblkp = boardp->adv_sgblkp) == NULL) {
+            ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
+            ASC_STATS(scp->host, adv_build_nosg);
+
+            /*
+             * Allocation failed. Free 'adv_sgblk_t' structures already
+             * allocated for the request.
+             */
+            while ((sgblkp = reqp->sgblkp) != NULL)
+            {
+                /* Remove 'sgblkp' from the request list. */
+                reqp->sgblkp = sgblkp->next_sgblkp;
+
+                /* Add 'sgblkp' to the board free list. */
+                sgblkp->next_sgblkp = boardp->adv_sgblkp;
+                boardp->adv_sgblkp = sgblkp;
+            }
+            return ASC_BUSY;
+        } else {
+            /* Complete 'adv_sgblk_t' board allocation. */
+            boardp->adv_sgblkp = sgblkp->next_sgblkp;
+            sgblkp->next_sgblkp = NULL;
 
-    sg_block = scsiqp->sg_list_ptr;
-    sg_block_next_addr = (ulong) sg_block;    /* allow math operation */
-    sg_block_physical_addr =
+            /*
+             * Get 4 byte aligned virtual and physical addresses for
+             * the allocated ADV_SG_BLOCK structure.
+             */
+            sg_block = (ADV_SG_BLOCK *) ADV_DWALIGN(&sgblkp->sg_block);
+            sg_block_paddr =
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-        (ulong) scsiqp->sg_list_ptr;
+                (ADV_PADDR) sg_block;
 #else /* version >= v2.0.0 */
-        virt_to_bus(scsiqp->sg_list_ptr);
+                virt_to_bus(sg_block);
 #endif /* version >= v2.0.0 */
-    ADV_ASSERT(ADV_DWALIGN(sg_block_physical_addr) ==
-                   sg_block_physical_addr);
-    scsiqp->sg_real_addr = sg_block_physical_addr;
 
-    do
-    {
+            /*
+             * Check if this is the first 'adv_sgblk_t' for the request.
+             */
+            if (reqp->sgblkp == NULL)
+            {
+                /* Request's first scatter-gather block. */
+                reqp->sgblkp = sgblkp;
+
+                /*
+                 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
+                 * address pointers.
+                 */
+                scsiqp->sg_list_ptr = sg_block;
+                scsiqp->sg_real_addr = cpu_to_le32(sg_block_paddr);
+            } else
+            {
+                /* Request's second or later scatter-gather block. */
+                sgblkp->next_sgblkp = reqp->sgblkp;
+                reqp->sgblkp = sgblkp;
+
+                /*
+                 * Point the previous ADV_SG_BLOCK structure to
+                 * the newly allocated ADV_SG_BLOCK structure.
+                 */
+                ASC_ASSERT(prev_sg_block != NULL);
+                prev_sg_block->sg_ptr = cpu_to_le32(sg_block_paddr);
+            }
+        }
+
         for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
         {
             sg_block->sg_list[i].sg_addr =
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-                (ulong) slp->address;
+                (ADV_PADDR) slp->address;
 #else /* version >= v2.0.0 */
-                virt_to_bus(slp->address);
+                cpu_to_le32(virt_to_bus(slp->address));
 #endif /* version >= v2.0.0 */
-            sg_block->sg_list[i].sg_count = slp->length;
+            sg_block->sg_list[i].sg_count = cpu_to_le32(slp->length);
             ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
 
             if (--sg_elem_cnt == 0)
-            {   /* last entry, get out */
+            {   /* Last ADV_SG_BLOCK and scatter-gather entry. */
                 sg_block->sg_cnt = i + 1;
-                sg_block->sg_ptr = 0L;    /* next link = NULL */
+                sg_block->sg_ptr = 0L;    /* Last ADV_SG_BLOCK in list. */
                 return ADV_SUCCESS;
             }
             slp++;
-        } 
+        }
         sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
-        sg_block_next_addr += sizeof(ADV_SG_BLOCK);
-        sg_block_physical_addr += sizeof(ADV_SG_BLOCK);
-        ADV_ASSERT(ADV_DWALIGN(sg_block_physical_addr) ==
-                       sg_block_physical_addr);
-
-        sg_block->sg_ptr = (ADV_SG_BLOCK *) sg_block_physical_addr;
-        sg_block = (ADV_SG_BLOCK *) sg_block_next_addr; /* virtual addr */
+        prev_sg_block = sg_block;
     }
     while (1);
     /* NOTREACHED */
@@ -7525,20 +7600,19 @@
     asc_board_t         *boardp;
     Scsi_Cmnd           *scp;
     struct Scsi_Host    *shp;
-    int                 underrun = ASC_FALSE;
     int                 i;
 
     ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-    ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %x, qdonep %x\n",
-        (unsigned) asc_dvc_varp, (unsigned) qdonep);
+    ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %lx, qdonep %lx\n",
+        (ulong) asc_dvc_varp, (ulong) qdonep);
     ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
 
     /*
      * Get the Scsi_Cmnd structure and Scsi_Host structure for the
      * command that has been completed.
      */
-    scp = (Scsi_Cmnd *) qdonep->d2.srb_ptr;
-    ASC_DBG1(1, "asc_isr_callback: scp %x\n", (unsigned) scp);
+    scp = (Scsi_Cmnd *) ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
+    ASC_DBG1(1, "asc_isr_callback: scp %lx\n", (ulong) scp);
 
     if (scp == NULL) {
         ASC_PRINT("asc_isr_callback: scp is NULL\n");
@@ -7557,13 +7631,14 @@
         }
     }
     if (i == asc_board_count) {
-        ASC_PRINT2("asc_isr_callback: scp %x has bad host pointer, host %x\n",
-            (unsigned) scp, (unsigned) shp);
+        ASC_PRINT2(
+            "asc_isr_callback: scp %lx has bad host pointer, host %lx\n",
+            (ulong) scp, (ulong) shp);
         return;
     }
 
     ASC_STATS(shp, callback);
-    ASC_DBG1(1, "asc_isr_callback: shp %x\n", (unsigned) shp);
+    ASC_DBG1(1, "asc_isr_callback: shp %lx\n", (ulong) shp);
 
     /*
      * If the request isn't found on the active queue, it may
@@ -7573,36 +7648,19 @@
     boardp = ASC_BOARDP(shp);
     ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
     if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
-        ASC_PRINT2("asc_isr_callback: board %d: scp %x not on active queue\n",
-            boardp->id, (unsigned) scp);
+        ASC_PRINT2(
+            "asc_isr_callback: board %d: scp %lx not on active queue\n",
+            boardp->id, (ulong) scp);
         return;
     }
 
     /*
-     * Check for an underrun condition.
-     */
-    if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 && 
-        qdonep->remain_bytes <= scp->request_bufflen != 0) {
-        ASC_DBG1(1, "asc_isr_callback: underrun condition %u bytes\n",
-        (unsigned) qdonep->remain_bytes);
-        underrun = ASC_TRUE;
-    }
-
-    /*
      * 'qdonep' contains the command's ending status.
      */
     switch (qdonep->d3.done_stat) {
     case QD_NO_ERROR:
         ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
-        switch (qdonep->d3.host_stat) {
-        case QHSTA_NO_ERROR:
-            scp->result = 0;
-            break;
-        default:
-            /* QHSTA error occurred */
-            scp->result = HOST_BYTE(DID_ERROR);
-            break;
-        }
+        scp->result = 0;
 
         /*
          * If an INQUIRY command completed successfully, then call
@@ -7615,16 +7673,20 @@
                 (ASC_SCSI_INQUIRY *) scp->request_buffer);
         }
 
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,19)
         /*
-         * If there was an underrun without any other error,
-         * set DID_ERROR to indicate the underrun error.
+         * Check for an underrun condition.
          *
-         * Note: There is no way yet to indicate the number
-         * of underrun bytes.
+         * If there was no error and an underrun condition, then
+         * then return the number of underrun bytes.
          */
-        if (scp->result == 0 && underrun == ASC_TRUE) {
-            scp->result = HOST_BYTE(DID_UNDERRUN);
+        if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 && 
+            qdonep->remain_bytes <= scp->request_bufflen != 0) {
+            ASC_DBG1(1, "asc_isr_callback: underrun condition %u bytes\n",
+            (unsigned) qdonep->remain_bytes);
+            scp->resid = qdonep->remain_bytes;
         }
+#endif /* version >= v2.3.19 */
         break;
 
     case QD_WITH_ERROR:
@@ -7706,14 +7768,14 @@
 {
     asc_board_t         *boardp;
     adv_req_t           *reqp;
+    adv_sgblk_t         *sgblkp;
     Scsi_Cmnd           *scp;
     struct Scsi_Host    *shp;
-    int                 underrun = ASC_FALSE;
     int                 i;
 
     ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
-    ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp %x, scsiqp %x\n",
-        (unsigned) adv_dvc_varp, (unsigned) scsiqp);
+    ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp %lx, scsiqp %lx\n",
+        (ulong) adv_dvc_varp, (ulong) scsiqp);
     ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
 
     /*
@@ -7721,8 +7783,8 @@
      * completed. The adv_req_t structure actually contains the
      * completed ADV_SCSI_REQ_Q structure.
      */
-    reqp = (adv_req_t *) scsiqp->srb_ptr;
-    ASC_DBG1(1, "adv_isr_callback: reqp %x\n", (unsigned) reqp);
+    reqp = (adv_req_t *) ADV_U32_TO_VADDR(scsiqp->srb_ptr);
+    ASC_DBG1(1, "adv_isr_callback: reqp %lx\n", (ulong) reqp);
     if (reqp == NULL) {
         ASC_PRINT("adv_isr_callback: reqp is NULL\n");
         return;
@@ -7737,7 +7799,7 @@
      * determined.
      */
     scp = reqp->cmndp;
-    ASC_DBG1(1, "adv_isr_callback: scp %x\n", (unsigned) scp);
+    ASC_DBG1(1, "adv_isr_callback: scp %lx\n", (ulong) scp);
     if (scp == NULL) {
         ASC_PRINT("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
         return;
@@ -7759,13 +7821,14 @@
      * structure and adv_sgblk_t structure, if any, is dropped.
      */
     if (i == asc_board_count) {
-        ASC_PRINT2("adv_isr_callback: scp %x has bad host pointer, host %x\n",
-            (unsigned) scp, (unsigned) shp);
+        ASC_PRINT2(
+            "adv_isr_callback: scp %lx has bad host pointer, host %lx\n",
+            (ulong) scp, (ulong) shp);
         return;
     }
 
     ASC_STATS(shp, callback);
-    ASC_DBG1(1, "adv_isr_callback: shp %x\n", (unsigned) shp);
+    ASC_DBG1(1, "adv_isr_callback: shp %lx\n", (ulong) shp);
 
     /*
      * If the request isn't found on the active queue, it may have been
@@ -7778,47 +7841,34 @@
     boardp = ASC_BOARDP(shp);
     ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
     if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
-        ASC_PRINT2("adv_isr_callback: board %d: scp %x not on active queue\n",
-            boardp->id, (unsigned) scp);
+        ASC_PRINT2(
+            "adv_isr_callback: board %d: scp %lx not on active queue\n",
+            boardp->id, (ulong) scp);
         return;
     }
 
     /*
-     * Check for an underrun condition.
-     */
-    if (scp->request_bufflen != 0 && scsiqp->data_cnt != 0) {
-        ASC_DBG1(1, "adv_isr_callback: underrun condition %lu bytes\n",
-        scsiqp->data_cnt);
-        underrun = ASC_TRUE;
-    }
-
-    /*
      * 'done_status' contains the command's ending status.
      */
     switch (scsiqp->done_status) {
     case QD_NO_ERROR:
         ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
-        switch (scsiqp->host_status) {
-        case QHSTA_NO_ERROR:
-            scp->result = 0;
-            break;
-        default:
-            /* QHSTA error occurred. */
-            ASC_DBG1(2, "adv_isr_callback: host_status %x\n",
-                scsiqp->host_status);
-            scp->result = HOST_BYTE(DID_ERROR);
-            break;
-        }
+        scp->result = 0;
+
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,19)
         /*
-         * If there was an underrun without any other error,
-         * set DID_ERROR to indicate the underrun error.
+         * Check for an underrun condition.
          *
-         * Note: There is no way yet to indicate the number
-         * of underrun bytes.
+         * If there was no error and an underrun condition, then
+         * then return the number of underrun bytes.
          */
-        if (scp->result == 0 && underrun == ASC_TRUE) {
-                scp->result = HOST_BYTE(DID_UNDERRUN);
+        if (scp->request_bufflen != 0 && scsiqp->data_cnt != 0 &&
+            scsiqp->data_cnt <= scp->request_bufflen) {
+            ASC_DBG1(1, "adv_isr_callback: underrun condition %lu bytes\n",
+            (ulong) scsiqp->data_cnt);
+            scp->resid = scsiqp->data_cnt;
         }
+#endif /* version >= v2.3.19 */
         break;
 
     case QD_WITH_ERROR:
@@ -7886,12 +7936,16 @@
     asc_enqueue(&boardp->done, scp, ASC_BACK);
 
     /*
-     * Free the adv_sgblk_t structure, if any, by adding it back
-     * to the board free list.
+     * Free all 'adv_sgblk_t' structures allocated for the request.
      */
-    if (reqp->sgblkp != NULL) {
-        reqp->sgblkp->next_sgblkp = boardp->adv_sgblkp;
-        boardp->adv_sgblkp = reqp->sgblkp;
+    while ((sgblkp = reqp->sgblkp) != NULL)
+    {
+        /* Remove 'sgblkp' from the request list. */
+        reqp->sgblkp = sgblkp->next_sgblkp;
+
+        /* Add 'sgblkp' to the board free list. */
+        sgblkp->next_sgblkp = boardp->adv_sgblkp;
+        boardp->adv_sgblkp = sgblkp;
     }
 
     /*
@@ -8112,15 +8166,15 @@
 )
 {
     ushort   tmp;
-    ulong    address;
-    ulong    lbus = pciData->bus;
-    ulong    lslot = pciData->slot;
-    ulong    lfunc = pciData->func;
+    ADV_DCNT address;
+    ADV_DCNT lbus = pciData->bus;
+    ADV_DCNT lslot = pciData->slot;
+    ADV_DCNT lfunc = pciData->func;
     uchar    t2CFA, t2CF8;
-    ulong    t1CF8, t1CFC;
+    ADV_DCNT t1CF8, t1CFC;
 
-    ASC_DBG4(4, "asc_get_cfg_word: type %d, bus %lu, slot %lu, func %lu\n",
-        pciData->type, lbus, lslot, lfunc);
+    ASC_DBG4(4, "asc_get_cfg_word: type %d, bus %u, slot %u, func %u\n",
+        pciData->type, (unsigned) lbus, (unsigned) lslot, (unsigned) lfunc);
 
     /*
      * Check type of configuration mechanism.
@@ -8160,7 +8214,7 @@
          * enable <31>, bus = <23:16>, slot = <15:11>,
          * func = <10:8>, reg = <7:2>
          */
-        address = (ulong) ((lbus << 16) | (lslot << 11) |
+        address = (ADV_DCNT) ((lbus << 16) | (lslot << 11) |
             (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L);
 
         /*
@@ -8194,11 +8248,11 @@
 asc_get_cfg_byte(PCI_DATA *pciData)
 )
 {
-    uchar tmp;
-    ulong address;
-    ulong lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func;
-    uchar t2CFA, t2CF8;
-    ulong t1CF8, t1CFC;
+    uchar    tmp;
+    ADV_DCNT address;
+    ADV_DCNT lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func;
+    ADV_DCNT t2CFA, t2CF8;
+    ADV_DCNT t1CF8, t1CFC;
 
     ASC_DBG1(4, "asc_get_cfg_byte: type: %d\n", pciData->type);
 
@@ -8243,7 +8297,7 @@
          * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>,
          * reg = <7:2>
          */
-        address = (ulong) ((lbus << 16) | (lslot << 11) |
+        address = (ADV_DCNT) ((lbus << 16) | (lslot << 11) |
             (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L);
 
         /*
@@ -8274,11 +8328,11 @@
 asc_put_cfg_byte(PCI_DATA *pciData, uchar byte_data)
 )
 {
-    ulong tmpl;
-    ulong address;
-    ulong lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func;
-    uchar t2CFA, t2CF8;
-    ulong t1CF8, t1CFC;
+    ADV_DCNT tmpl;
+    ADV_DCNT address;
+    ADV_DCNT lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func;
+    uchar    t2CFA, t2CF8;
+    ADV_DCNT t1CF8, t1CFC;
 
     ASC_DBG2(4, "asc_put_cfg_byte: type: %d, byte_data %x\n",
         pciData->type, byte_data);
@@ -8328,7 +8382,7 @@
          * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>,
          * reg = <7:2>
          */
-        address = (ulong) ((lbus << 16) | (lslot << 11) | (lfunc << 8) |
+        address = (ADV_DCNT) ((lbus << 16) | (lslot << 11) | (lfunc << 8) |
                 (pciData->offset & 0xFC) | 0x80000000L);
         /*
          * Write out address to CONFIG_ADDRESS.
@@ -8366,8 +8420,8 @@
 {
     int        tid;
 
-    ASC_DBG3(3, "asc_enqueue: ascq %x, reqp %x, flag %d\n",
-        (unsigned) ascq, (unsigned) reqp, flag);
+    ASC_DBG3(3, "asc_enqueue: ascq %lx, reqp %lx, flag %d\n",
+        (ulong) ascq, (ulong) reqp, flag);
     ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
     ASC_ASSERT(reqp != NULL);
     ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
@@ -8404,7 +8458,7 @@
     }
     REQPTIME(reqp) = REQTIMESTAMP();
 #endif /* ADVANSYS_STATS */
-    ASC_DBG1(3, "asc_enqueue: reqp %x\n", (unsigned) reqp);
+    ASC_DBG1(3, "asc_enqueue: reqp %lx\n", (ulong) reqp);
     return;
 }
 
@@ -8420,7 +8474,7 @@
 {
     REQP    reqp;
 
-    ASC_DBG2(3, "asc_dequeue: ascq %x, tid %d\n", (unsigned) ascq, tid);
+    ASC_DBG2(3, "asc_dequeue: ascq %lx, tid %d\n", (ulong) ascq, tid);
     ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
     ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
     if ((reqp = ascq->q_first[tid]) != NULL) {
@@ -8439,7 +8493,7 @@
         REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
 #endif /* ADVANSYS_STATS */
     }
-    ASC_DBG1(3, "asc_dequeue: reqp %x\n", (unsigned) reqp);
+    ASC_DBG1(3, "asc_dequeue: reqp %lx\n", (ulong) reqp);
     return reqp;
 }
 
@@ -8469,7 +8523,7 @@
     REQP    firstp, lastp;
     int     i;
 
-    ASC_DBG2(3, "asc_dequeue_list: ascq %x, tid %d\n", (unsigned) ascq, tid);
+    ASC_DBG2(3, "asc_dequeue_list: ascq %lx, tid %d\n", (ulong) ascq, tid);
     ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
     ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
 
@@ -8530,7 +8584,7 @@
     if (lastpp) {
         *lastpp = lastp;
     }
-    ASC_DBG1(3, "asc_dequeue_list: firstp %x\n", (unsigned) firstp);
+    ASC_DBG1(3, "asc_dequeue_list: firstp %lx\n", (ulong) firstp);
     return firstp;
 }
 
@@ -8551,8 +8605,8 @@
     int         tid;
     int         ret = ASC_FALSE;
 
-    ASC_DBG2(3, "asc_rmqueue: ascq %x, reqp %x\n",
-        (unsigned) ascq, (unsigned) reqp);
+    ASC_DBG2(3, "asc_rmqueue: ascq %lx, reqp %lx\n",
+        (ulong) ascq, (ulong) reqp);
     ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
     ASC_ASSERT(reqp != NULL);
 
@@ -8604,7 +8658,7 @@
     }
     ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
 #endif /* ADVANSYS_STATS */
-    ASC_DBG2(3, "asc_rmqueue: reqp %x, ret %d\n", (unsigned) reqp, ret);
+    ASC_DBG2(3, "asc_rmqueue: reqp %lx, ret %d\n", (ulong) reqp, ret);
     return ret;
 }
 
@@ -8619,8 +8673,8 @@
     int            tid;
     int            ret = ASC_FALSE;
 
-    ASC_DBG2(3, "asc_isqueued: ascq %x, reqp %x\n",
-        (unsigned) ascq, (unsigned) reqp);
+    ASC_DBG2(3, "asc_isqueued: ascq %lx, reqp %lx\n",
+        (ulong) ascq, (ulong) reqp);
     ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
     ASC_ASSERT(reqp != NULL);
 
@@ -8650,7 +8704,7 @@
     REQP                    reqp;
     int                     i;
 
-    ASC_DBG1(1, "asc_execute_queue: ascq %x\n", (unsigned) ascq);
+    ASC_DBG1(1, "asc_execute_queue: ascq %lx\n", (ulong) ascq);
     ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
     /*
      * Execute queued commands for devices attached to
@@ -8734,7 +8788,6 @@
     int                leftlen;
     int                totlen;
     int                len;
-    int                upgrade = ASC_FALSE;
     ushort             major, minor, letter;
 
     boardp = ASC_BOARDP(shp);
@@ -8749,9 +8802,14 @@
      * the BIOS code segment base address.
      */
     if (boardp->bios_signature != 0x55AA) {
-        len = asc_prt_line(cp, leftlen, "Pre-3.1\n");
+        len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
+        ASC_PRT_NEXT();
+        len = asc_prt_line(cp, leftlen,
+"BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
+        ASC_PRT_NEXT();
+        len = asc_prt_line(cp, leftlen,
+"can be found at the AdvanSys FTP site: ftp://ftp.advansys.com/pub\n");
         ASC_PRT_NEXT();
-        upgrade = ASC_TRUE;
     } else {
         major = (boardp->bios_version >> 12) & 0xF;
         minor = (boardp->bios_version >> 8) & 0xF;
@@ -8761,16 +8819,20 @@
             major, minor, letter >= 26 ? '?' : letter + 'A');
         ASC_PRT_NEXT();
 
-        /* Current available ROM BIOS release is 3.1C. */
+        /*
+         * Current available ROM BIOS release is 3.1I for UW
+         * and 3.2I for U2W. This code doesn't differentiate
+         * UW and U2W boards.
+         */
         if (major < 3 || (major <= 3 && minor < 1) ||
-            (major <= 3 && minor <= 1 && letter < ('C'- 'A'))) {
-            upgrade = ASC_TRUE;
-        }
-    }
-    if (upgrade == ASC_TRUE) {
-        len = asc_prt_line(cp, leftlen,
-"Newer version of ROM BIOS available: ftp://ftp.advansys.com/pub\n");
+            (major <= 3 && minor <= 1 && letter < ('I'- 'A'))) {
+            len = asc_prt_line(cp, leftlen,
+"Newer version of ROM BIOS is available at the AdvanSys FTP site:\n");
+            ASC_PRT_NEXT();
+            len = asc_prt_line(cp, leftlen,
+"ftp://ftp.advansys.com/pub\n");
             ASC_PRT_NEXT();
+        }
     }
 
     return totlen;
@@ -9814,16 +9876,16 @@
     if (offset <= advoffset) {
         /* Read offset below current offset, copy everything. */
         cnt = ASC_MIN(cplen, leftlen);
-        ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n",
-                (unsigned) curbuf, (unsigned) cp, cnt);
+        ASC_DBG3(2, "asc_proc_copy: curbuf %lx, cp %lx, cnt %d\n",
+                (ulong) curbuf, (ulong) cp, cnt);
         memcpy(curbuf, cp, cnt);
     } else if (offset < advoffset + cplen) {
         /* Read offset within current range, partial copy. */
         cnt = (advoffset + cplen) - offset;
         cp = (cp + cplen) - cnt;
         cnt = ASC_MIN(cnt, leftlen);
-        ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n",
-                (unsigned) curbuf, (unsigned) cp, cnt);
+        ASC_DBG3(2, "asc_proc_copy: curbuf %lx, cp %lx, cnt %d\n",
+                (ulong) curbuf, (ulong) cp, cnt);
         memcpy(curbuf, cp, cnt);
     }
     return cnt;
@@ -9874,13 +9936,13 @@
  * called when interrupts are disabled.
  */
 STATIC void
-DvcSleepMilliSecond(ulong n)
+DvcSleepMilliSecond(ADV_DCNT n)
 {
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
-    ulong i;
+    ADV_DCNT i;
 #endif /* version < v2.1.0 */ 
 
-    ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", n);
+    ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong) n);
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
     mdelay(n);
 #else /* version < v2.1.0 */ 
@@ -9906,16 +9968,16 @@
     restore_flags(flags);
 }
 
-STATIC ulong
-DvcGetSGList(ASC_DVC_VAR *asc_dvc_sg, uchar *buf_addr, ulong buf_len,
+STATIC ADV_DCNT
+DvcGetSGList(ASC_DVC_VAR *asc_dvc_sg, uchar *buf_addr, ADV_DCNT buf_len,
              ASC_SG_HEAD *asc_sg_head_ptr)
 {
-    ulong buf_size;
+    ADV_DCNT buf_size;
 
     buf_size = buf_len;
     asc_sg_head_ptr->entry_cnt = 1;
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-    asc_sg_head_ptr->sg_list[0].addr = (ulong) buf_addr;
+    asc_sg_head_ptr->sg_list[0].addr = (ADV_PADDR) buf_addr;
 #else /* version >= v2.0.0 */
     asc_sg_head_ptr->sg_list[0].addr = virt_to_bus(buf_addr);
 #endif /* version >= v2.0.0 */
@@ -10010,7 +10072,7 @@
 }
 
 /*
- * void DvcOutPortDWords(PortAddr port, ulong *pdw, int dwords)
+ * void DvcOutPortDWords(PortAddr port, ADV_DCNT *pdw, int dwords)
  *
  * Calling/Exit State:
  *    none
@@ -10020,10 +10082,10 @@
  *  16 bit integer units
  */
 STATIC void  
-DvcOutPortDWords(PortAddr port, ulong *pdw, int dwords)
+DvcOutPortDWords(PortAddr port, ADV_DCNT *pdw, int dwords)
 {
-    int        i;
-    int        words;
+    int       i;
+    int       words;
     ushort    *pw;
 
     pw = (ushort *) pdw;
@@ -10040,7 +10102,7 @@
 ASC_INITFUNC(
 STATIC uchar,
 DvcReadPCIConfigByte(
-        ASC_DVC_VAR asc_ptr_type *asc_dvc, 
+        ASC_DVC_VAR *asc_dvc, 
         ushort offset)
 )
 {
@@ -10077,7 +10139,7 @@
 ASC_INITFUNC(
 STATIC void,
 DvcWritePCIConfigByte(
-        ASC_DVC_VAR asc_ptr_type *asc_dvc, 
+        ASC_DVC_VAR *asc_dvc, 
         ushort offset, 
         uchar  byte_data)
 )
@@ -10168,21 +10230,21 @@
  * Note: Because Linux currently doesn't page the kernel and all
  * kernel buffers are physically contiguous, leave '*lenp' unchanged.
  */
-ulong
+ADV_PADDR
 DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
-        uchar *vaddr, long *lenp, int flag)
+        uchar *vaddr, ADV_SDCNT *lenp, int flag)
 {
-    ulong                paddr;
+    ADV_PADDR           paddr;
 
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-    paddr = (ulong) vaddr;
+    paddr = (ADV_PADDR) vaddr;
 #else /* version >= v2.0.0 */
     paddr = virt_to_bus(vaddr);
 #endif /* version >= v2.0.0 */
 
     ASC_DBG4(4,
         "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n", 
-        (ulong) vaddr, (ulong) lenp, (ulong) *((ulong *) lenp), paddr);
+        (ulong) vaddr, (ulong) lenp, (ulong) *((ulong *) lenp), (ulong) paddr);
 
     return paddr;
 }
@@ -10432,16 +10494,15 @@
 
     boardp = ASC_BOARDP(s);
 
-    printk("Scsi_Host at addr %x\n", (unsigned) s);
+    printk("Scsi_Host at addr %lx\n", (ulong) s);
     printk(
-" next %x, extra_bytes %u, host_busy %u, host_no %d, last_reset %d,\n",
-        (unsigned) s->next, s->extra_bytes, s->host_busy, s->host_no,
+" next %lx, extra_bytes %u, host_busy %u, host_no %d, last_reset %d,\n",
+        (ulong) s->next, s->extra_bytes, s->host_busy, s->host_no,
         (unsigned) s->last_reset);
 
     printk(
-" host_wait %x, host_queue %x, hostt %x, block %x,\n",
-        (unsigned) s->host_wait, (unsigned) s->host_queue,
-        (unsigned) s->hostt, (unsigned) s->block);
+" host_queue %lx, hostt %lx, block %lx,\n",
+        (ulong) s->host_queue, (ulong) s->hostt, (ulong) s->block);
 
     printk(
 " wish_block %d, base %lu, io_port %lu, n_io_port %u, irq %d,\n",
@@ -10472,7 +10533,7 @@
 STATIC void 
 asc_prt_scsi_cmnd(Scsi_Cmnd *s)
 {
-    printk("Scsi_Cmnd at addr %x\n", (unsigned) s);
+    printk("Scsi_Cmnd at addr %lx\n", (ulong) s);
 
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
     printk(
@@ -10480,8 +10541,8 @@
         (unsigned) s->host, (unsigned) s->device, s->target, s->lun);
 #else /* version >= v1.3.0 */
     printk(
-" host %x, device %x, target %u, lun %u, channel %u,\n",
-        (unsigned) s->host, (unsigned) s->device, s->target, s->lun,
+" host %lx, device %lx, target %u, lun %u, channel %u,\n",
+        (ulong) s->host, (ulong) s->device, s->target, s->lun,
         s->channel);
 #endif /* version >= v1.3.0 */
 
@@ -10511,9 +10572,9 @@
         s->internal_timeout, s->flags, s->this_count);
 
     printk(
-" scsi_done %x, done %x, host_scribble %x, result %x\n",
-        (unsigned) s->scsi_done, (unsigned) s->done,
-        (unsigned) s->host_scribble, s->result);
+" scsi_done %lx, done %lx, host_scribble %lx, result %x\n",
+        (ulong) s->scsi_done, (ulong) s->done,
+        (ulong) s->host_scribble, s->result);
 
     printk(
 " tag %u, pid %u\n",
@@ -10526,15 +10587,15 @@
 STATIC void 
 asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
 {
-    printk("ASC_DVC_VAR at addr %x\n", (unsigned) h);
+    printk("ASC_DVC_VAR at addr %lx\n", (ulong) h);
 
     printk(
 " iop_base %x, err_code %x, dvc_cntl %x, bug_fix_cntl %d,\n",
         h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
 
     printk(
-" bus_type %d, isr_callback %x, exe_callback %x, init_sdtr %x,\n",
-        h->bus_type, (unsigned) h->isr_callback, (unsigned) h->exe_callback,
+" bus_type %d, isr_callback %lx, exe_callback %lx, init_sdtr %x,\n",
+        h->bus_type, (ulong) h->isr_callback, (ulong) h->exe_callback,
         (unsigned) h->init_sdtr);
 
     printk(
@@ -10558,8 +10619,8 @@
         (unsigned) h->no_scam, (unsigned) h->pci_fix_asyn_xfer);
 
     printk(
-" cfg %x, saved_ptr2func %x\n",
-        (unsigned) h->cfg, (unsigned) h->saved_ptr2func);
+" cfg %lx\n",
+        (ulong) h->cfg);
 }
 
 /*
@@ -10568,7 +10629,7 @@
 STATIC void 
 asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
 {
-    printk("ASC_DVC_CFG at addr %x\n", (unsigned) h);
+    printk("ASC_DVC_CFG at addr %lx\n", (ulong) h);
 
     printk(
 " can_tagged_qng %x, cmd_qng_enabled %x, disc_enable %x, sdtr_enable %x,\n",
@@ -10585,8 +10646,8 @@
           h->pci_device_id, h->lib_serial_no, h->lib_version, h->mcode_date);
 
     printk(
-" mcode_version %d, overrun_buf %x\n",
-            h->mcode_version, (unsigned) h->overrun_buf);
+" mcode_version %d, overrun_buf %lx\n",
+            h->mcode_version, (ulong) h->overrun_buf);
 }
 
 /*
@@ -10598,7 +10659,7 @@
     ASC_SG_HEAD    *sgp;
     int i;
 
-    printk("ASC_SCSI_Q at addr %x\n", (unsigned) q);
+    printk("ASC_SCSI_Q at addr %lx\n", (ulong) q);
 
     printk(
 " target_ix %u, target_lun %u, srb_ptr %x, tag_code %u,\n",
@@ -10606,22 +10667,23 @@
             (unsigned) q->q2.srb_ptr, q->q2.tag_code);
 
     printk(
-" data_addr %x, data_cnt %lu, sense_addr %x, sense_len %u,\n",
-            (unsigned) q->q1.data_addr, q->q1.data_cnt,
-            (unsigned) q->q1.sense_addr, q->q1.sense_len);
+" data_addr %lx, data_cnt %lu, sense_addr %lx, sense_len %u,\n",
+            (ulong) q->q1.data_addr, (ulong) q->q1.data_cnt,
+            (ulong) q->q1.sense_addr, q->q1.sense_len);
 
     printk(
-" cdbptr %x, cdb_len %u, sg_head %x, sg_queue_cnt %u\n",
-            (unsigned) q->cdbptr, q->q2.cdb_len,
-            (unsigned) q->sg_head, q->q1.sg_queue_cnt);
+" cdbptr %lx, cdb_len %u, sg_head %lx, sg_queue_cnt %u\n",
+            (ulong) q->cdbptr, q->q2.cdb_len,
+            (ulong) q->sg_head, q->q1.sg_queue_cnt);
 
     if (q->sg_head) {
         sgp = q->sg_head;
-        printk("ASC_SG_HEAD at addr %x\n", (unsigned) sgp);
+        printk("ASC_SG_HEAD at addr %lx\n", (ulong) sgp);
         printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt, sgp->queue_cnt);
         for (i = 0; i < sgp->entry_cnt; i++) {
-            printk(" [%u]: addr %x, bytes %lu\n",
-                i, (unsigned) sgp->sg_list[i].addr, sgp->sg_list[i].bytes);
+            printk(" [%u]: addr %lx, bytes %lu\n",
+                i, (ulong) sgp->sg_list[i].addr,
+                (ulong) sgp->sg_list[i].bytes);
         }
 
     }
@@ -10633,7 +10695,7 @@
 STATIC void 
 asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
 {
-    printk("ASC_QDONE_INFO at addr %x\n", (unsigned) q);
+    printk("ASC_QDONE_INFO at addr %lx\n", (ulong) q);
     printk(
 " srb_ptr %x, target_ix %u, cdb_len %u, tag_code %u, done_stat %x\n",
             (unsigned) q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
@@ -10658,8 +10720,8 @@
         (ulong) h->iop_base, h->err_code, (unsigned) h->ultra_able);
 
     printk(
-"  isr_callback 0x%x, sdtr_able 0x%x, wdtr_able 0x%x\n",
-        (unsigned) h->isr_callback, (unsigned) h->wdtr_able,
+"  isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
+        (ulong) h->isr_callback, (unsigned) h->wdtr_able,
         (unsigned) h->sdtr_able);
 
     printk(
@@ -10672,11 +10734,9 @@
         (unsigned) h->max_host_qng, (unsigned) h->max_dvc_qng,
         (ulong) h->carr_freelist);
 
-
     printk(
 "  icq_sp %lx, irq_sp %lx\n",
-        (ulong) h->icq_sp,
-        (ulong) h->irq_sp);
+        (ulong) h->icq_sp, (ulong) h->irq_sp);
 
     printk(
 "  no_scam 0x%x, tagqng_able 0x%x\n",
@@ -10725,34 +10785,31 @@
     int                 sg_blk_cnt;
     struct asc_sg_block *sg_ptr;
 
-    printk("ADV_SCSI_REQ_Q at addr %x\n", (unsigned) q);
+    printk("ADV_SCSI_REQ_Q at addr %lx\n", (ulong) q);
 
     printk(
 "  target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
-            q->target_id, q->target_lun, q->srb_ptr, q->a_flag);
+            q->target_id, q->target_lun, (ulong) q->srb_ptr, q->a_flag);
 
     printk("  cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
-            q->cntl, q->data_addr, q->vdata_addr);
-
-    printk(
-"  cntl 0x%x, data_addr %lx, vdata_addr %lx\n",
-            q->cntl, q->data_addr, q->vdata_addr);
+            q->cntl, (ulong) q->data_addr, (ulong) q->vdata_addr);
 
     printk(
 "  data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
-            q->data_cnt, q->sense_addr, q->sense_len);
+            (ulong) q->data_cnt, (ulong) q->sense_addr, q->sense_len);
 
     printk(
 "  cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
             q->cdb_len, q->done_status, q->host_status, q->scsi_status);
 
     printk(
-"  sg_working_ix %x, sg_working_data_cnt %lx, reserved %u\n",
-            q->sg_working_ix, q->sg_working_data_cnt, q->reserved);
+"  sg_working_ix %x, sg_working_data_cnt %lx, target_cmd %u\n",
+            q->sg_working_ix, (ulong) q->sg_working_data_cnt, q->target_cmd);
 
     printk(
 "  scsiq_rptr %lx, sg_real_addr %lx, sg_list_ptr %lx\n",
-            q->scsiq_rptr, q->sg_real_addr, (ulong) q->sg_list_ptr);
+            (ulong) q->scsiq_rptr, (ulong) q->sg_real_addr,
+            (ulong) q->sg_list_ptr);
 
     /* Display the request's ADV_SG_BLOCK structures. */
     if (q->sg_list_ptr != NULL)
@@ -10768,7 +10825,7 @@
              */
             sg_ptr = &(((ADV_SG_BLOCK *) (q->sg_list_ptr))[sg_blk_cnt]);
             asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
-            if (sg_ptr->sg_ptr == NULL)
+            if (sg_ptr->sg_ptr == 0)
             {
                 break;
             }
@@ -10792,13 +10849,13 @@
     printk("  sg_cnt %u, sg_ptr %lx\n",
         b->sg_cnt, (ulong) b->sg_ptr);
     ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
-    if (b->sg_ptr != NULL)
+    if (b->sg_ptr != 0)
     {
         ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
     }
     for (i = 0; i < b->sg_cnt; i++) {
         printk("  [%u]: sg_addr %lx, sg_count %lx\n",
-            i, b->sg_list[i].sg_addr, b->sg_list[i].sg_count);
+            i, (ulong) b->sg_list[i].sg_addr, (ulong) b->sg_list[i].sg_count);
     }
 }
 
@@ -10989,7 +11046,7 @@
 }
 
 ASC_INITFUNC(
-STATIC ulong,
+STATIC ASC_DCNT,
 AscLoadMicroCode(
                     PortAddr iop_base,
                     ushort s_addr,
@@ -10998,7 +11055,7 @@
 )
 )
 {
-    ulong               chksum;
+    ASC_DCNT            chksum;
     ushort              mcode_word_size;
     ushort              mcode_chksum;
 
@@ -11227,7 +11284,7 @@
 
 STATIC int 
 AscIsrChipHalted(
-                    REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+                    ASC_DVC_VAR *asc_dvc
 )
 {
     EXT_MSG             ext_msg;
@@ -11247,10 +11304,10 @@
     uchar               cur_dvc_qng;
     uchar               asyn_sdtr;
     uchar               scsi_status;
-    asc_board_t            *boardp;
+    asc_board_t         *boardp;
 
-    ASC_ASSERT(asc_dvc->drv_ptr != 0);
-    boardp = (asc_board_t *) asc_dvc->drv_ptr;
+    ASC_ASSERT(asc_dvc->drv_ptr != NULL);
+    boardp = asc_dvc->drv_ptr;
 
     iop_base = asc_dvc->iop_base;
     int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
@@ -11497,162 +11554,162 @@
         return (0);
     } else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC)
     {
-         uchar              q_no;
-         ushort             q_addr;
-         ulong              srb_ptr;
-         uchar              sg_wk_q_no;
-         uchar              first_sg_wk_q_no;
-         ASC_SCSI_Q         *scsiq; /* Ptr to driver request. */
-         ASC_SG_HEAD        *sg_head; /* Ptr to driver SG request. */
-         ASC_SG_LIST_Q      scsi_sg_q; /* Structure written to queue. */
-         ushort             sg_list_dwords;
-         ushort             sg_entry_cnt;
-         uchar              next_qp;
-         int                i;
-
-         q_no = AscReadLramByte(iop_base, (ushort) ASCV_REQ_SG_LIST_QP);
-         if (q_no == ASC_QLINK_END)
-         {
-             return(0);
-         }
-
-         q_addr = ASC_QNO_TO_QADDR(q_no);
-
-         /* Read request's SRB pointer. */
-         srb_ptr = AscReadLramDWord(iop_base,
-                           (ushort) (q_addr + ASC_SCSIQ_D_SRBPTR));
+        uchar              q_no;
+        ushort             q_addr;
+        uchar              sg_wk_q_no;
+        uchar              first_sg_wk_q_no;
+        ASC_SCSI_Q         *scsiq; /* Ptr to driver request. */
+        ASC_SG_HEAD        *sg_head; /* Ptr to driver SG request. */
+        ASC_SG_LIST_Q      scsi_sg_q; /* Structure written to queue. */
+        ushort             sg_list_dwords;
+        ushort             sg_entry_cnt;
+        uchar              next_qp;
+        int                i;
 
-         /*
-          * Get request's first and working SG queue.
-          */
-         sg_wk_q_no = AscReadLramByte(iop_base,
-             (ushort) (q_addr + ASC_SCSIQ_B_SG_WK_QP));
+        q_no = AscReadLramByte(iop_base, (ushort) ASCV_REQ_SG_LIST_QP);
+        if (q_no == ASC_QLINK_END)
+        {
+            return(0);
+        }
 
-         first_sg_wk_q_no = AscReadLramByte(iop_base,
-             (ushort) (q_addr + ASC_SCSIQ_B_FIRST_SG_WK_QP));
+        q_addr = ASC_QNO_TO_QADDR(q_no);
 
-         /*
-          * Reset request's working SG queue back to the
-          * first SG queue.
-          */
-         AscWriteLramByte(iop_base,
-             (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SG_WK_QP),
-             first_sg_wk_q_no);
+        /*
+         * Convert the request's SRB pointer to a host ASC_SCSI_REQ
+         * structure pointer using a macro provided by the driver.
+         * The ASC_SCSI_REQ pointer provides a pointer to the
+         * host ASC_SG_HEAD structure.
+         */
+        /* Read request's SRB pointer. */
+        scsiq = (ASC_SCSI_Q *)
+           ASC_SRB2SCSIQ(
+               ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
+               (ushort) (q_addr + ASC_SCSIQ_D_SRBPTR))));
 
-         /*
-          * Convert the request's SRB pointer to a host ASC_SCSI_REQ
-          * structure pointer using a macro provided by the driver.
-          * The ASC_SCSI_REQ pointer provides a pointer to the
-          * host ASC_SG_HEAD structure.
-          */
-         scsiq = (ASC_SCSI_Q *) ASC_SRB2SCSIQ(srb_ptr);
+        /*
+         * Get request's first and working SG queue.
+         */
+        sg_wk_q_no = AscReadLramByte(iop_base,
+            (ushort) (q_addr + ASC_SCSIQ_B_SG_WK_QP));
 
-         sg_head = scsiq->sg_head;
+        first_sg_wk_q_no = AscReadLramByte(iop_base,
+            (ushort) (q_addr + ASC_SCSIQ_B_FIRST_SG_WK_QP));
 
-         /*
-          * Set sg_entry_cnt to the number of SG elements
-          * that will be completed on this interrupt.
-          *
-          * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
-          * SG elements. The data_cnt and data_addr fields which
-          * add 1 to the SG element capacity are not used when
-          * restarting SG handling after a halt.
-          */
-         if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1))
-         {
-              sg_entry_cnt = ASC_MAX_SG_LIST - 1;
-
-              /*
-               * Keep track of remaining number of SG elements that will
-               * need to be handled on the next interrupt.
-               */
-              scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
-         } else
-         {
-              sg_entry_cnt = scsiq->remain_sg_entry_cnt;
-              scsiq->remain_sg_entry_cnt = 0;
-         }
+        /*
+         * Reset request's working SG queue back to the
+         * first SG queue.
+         */
+        AscWriteLramByte(iop_base,
+            (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SG_WK_QP),
+            first_sg_wk_q_no);
 
-         /*
-          * Copy SG elements into the list of allocated SG queues.
-          *
-          * Last index completed is saved in scsiq->next_sg_index.
-          */
-         next_qp = first_sg_wk_q_no;
-         q_addr = ASC_QNO_TO_QADDR(next_qp);
-         scsi_sg_q.sg_head_qp = q_no;
-         scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
-         for( i = 0; i < sg_head->queue_cnt; i++)
-         {
-              scsi_sg_q.seq_no = i + 1;
-              if (sg_entry_cnt > ASC_SG_LIST_PER_Q)
-              {
-                  sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2);
-                  sg_entry_cnt -= ASC_SG_LIST_PER_Q;
-                  /*
-                   * After very first SG queue RISC FW uses next
-                   * SG queue first element then checks sg_list_cnt
-                   * against zero and then decrements, so set
-                   * sg_list_cnt 1 less than number of SG elements
-                   * in each SG queue.
-                   */
-                  scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
-                  scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
-              } else {
-                  /*
-                   * This is the last SG queue in the list of
-                   * allocated SG queues. If there are more
-                   * SG elements than will fit in the allocated
-                   * queues, then set the QCSG_SG_XFER_MORE flag.
-                   */
-                  if (scsiq->remain_sg_entry_cnt != 0)
-                  {
-                      scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
-                  } else
-                  {
-                      scsi_sg_q.cntl |= QCSG_SG_XFER_END;
-                  }
-                  /* equals sg_entry_cnt * 2 */
-                  sg_list_dwords = sg_entry_cnt << 1;
-                  scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
-                  scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
-                  sg_entry_cnt = 0;
-              }
-
-              scsi_sg_q.q_no = next_qp;
-              AscMemWordCopyToLram(iop_base,
-                           (ushort) (q_addr+ASC_SCSIQ_SGHD_CPY_BEG),
-                           (ushort *) &scsi_sg_q,
-                           (ushort) (sizeof(ASC_SG_LIST_Q) >> 1));
-
-              AscMemDWordCopyToLram( iop_base,
-                           (ushort) (q_addr+ASC_SGQ_LIST_BEG ),
-                           (ulong *) &sg_head->sg_list[scsiq->next_sg_index],
-                           (ushort) sg_list_dwords);
-
-              scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
-
-              /*
-               * If the just completed SG queue contained the
-               * last SG element, then no more SG queues need
-               * to be written.
-               */
-              if (scsi_sg_q.cntl & QCSG_SG_XFER_END)
-              {
-                  break;
-              }
-
-              next_qp = AscReadLramByte( iop_base,
-                           ( ushort )( q_addr+ASC_SCSIQ_B_FWD ) );
-              q_addr = ASC_QNO_TO_QADDR( next_qp );
-         }
+        sg_head = scsiq->sg_head;
 
-         /*
-          * Clear the halt condition so the RISC will be restarted
-          * after the return.
-          */
-         AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-         return(0);
+        /*
+         * Set sg_entry_cnt to the number of SG elements
+         * that will be completed on this interrupt.
+         *
+         * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
+         * SG elements. The data_cnt and data_addr fields which
+         * add 1 to the SG element capacity are not used when
+         * restarting SG handling after a halt.
+         */
+        if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1))
+        {
+             sg_entry_cnt = ASC_MAX_SG_LIST - 1;
+
+             /*
+              * Keep track of remaining number of SG elements that will
+              * need to be handled on the next interrupt.
+              */
+             scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
+        } else
+        {
+             sg_entry_cnt = scsiq->remain_sg_entry_cnt;
+             scsiq->remain_sg_entry_cnt = 0;
+        }
+
+        /*
+         * Copy SG elements into the list of allocated SG queues.
+         *
+         * Last index completed is saved in scsiq->next_sg_index.
+         */
+        next_qp = first_sg_wk_q_no;
+        q_addr = ASC_QNO_TO_QADDR(next_qp);
+        scsi_sg_q.sg_head_qp = q_no;
+        scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
+        for( i = 0; i < sg_head->queue_cnt; i++)
+        {
+             scsi_sg_q.seq_no = i + 1;
+             if (sg_entry_cnt > ASC_SG_LIST_PER_Q)
+             {
+                 sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2);
+                 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
+                 /*
+                  * After very first SG queue RISC FW uses next
+                  * SG queue first element then checks sg_list_cnt
+                  * against zero and then decrements, so set
+                  * sg_list_cnt 1 less than number of SG elements
+                  * in each SG queue.
+                  */
+                 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
+                 scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
+             } else {
+                 /*
+                  * This is the last SG queue in the list of
+                  * allocated SG queues. If there are more
+                  * SG elements than will fit in the allocated
+                  * queues, then set the QCSG_SG_XFER_MORE flag.
+                  */
+                 if (scsiq->remain_sg_entry_cnt != 0)
+                 {
+                     scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
+                 } else
+                 {
+                     scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+                 }
+                 /* equals sg_entry_cnt * 2 */
+                 sg_list_dwords = sg_entry_cnt << 1;
+                 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
+                 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
+                 sg_entry_cnt = 0;
+             }
+
+             scsi_sg_q.q_no = next_qp;
+             AscMemWordCopyToLram(iop_base,
+                          (ushort) (q_addr+ASC_SCSIQ_SGHD_CPY_BEG),
+                          (ushort *) &scsi_sg_q,
+                          (ushort) (sizeof(ASC_SG_LIST_Q) >> 1));
+
+             AscMemDWordCopyToLram( iop_base,
+                          (ushort) (q_addr+ASC_SGQ_LIST_BEG ),
+                          (ADV_PADDR *)
+                               &sg_head->sg_list[scsiq->next_sg_index],
+                          (ushort) sg_list_dwords);
+
+             scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
+
+             /*
+              * If the just completed SG queue contained the
+              * last SG element, then no more SG queues need
+              * to be written.
+              */
+             if (scsi_sg_q.cntl & QCSG_SG_XFER_END)
+             {
+                 break;
+             }
+
+             next_qp = AscReadLramByte( iop_base,
+                          ( ushort )( q_addr+ASC_SCSIQ_B_FWD ) );
+             q_addr = ASC_QNO_TO_QADDR( next_qp );
+        }
+
+        /*
+         * Clear the halt condition so the RISC will be restarted
+         * after the return.
+         */
+        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+        return(0);
     }
     return (0);
 }
@@ -11661,8 +11718,8 @@
 _AscCopyLramScsiDoneQ(
                          PortAddr iop_base,
                          ushort q_addr,
-                         REG ASC_QDONE_INFO * scsiq,
-                         ulong max_dma_count
+                         ASC_QDONE_INFO * scsiq,
+                         ASC_DCNT max_dma_count
 )
 {
     ushort              _val;
@@ -11688,7 +11745,7 @@
     /*
      * Read high word of remain bytes from alternate location.
      */
-    scsiq->remain_bytes = (((ulong) AscReadLramWord( iop_base,
+    scsiq->remain_bytes = (((ADV_DCNT) AscReadLramWord( iop_base,
                       (ushort) (q_addr+ (ushort) ASC_SCSIQ_W_ALT_DC1))) << 16);
     /*
      * Read low word of remain bytes from original location.
@@ -11702,7 +11759,7 @@
 
 STATIC int
 AscIsrQDone(
-               REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+               ASC_DVC_VAR *asc_dvc
 )
 {
     uchar               next_qp;
@@ -11719,12 +11776,12 @@
     ushort              sg_q_addr;
     uchar               cur_target_qng;
     ASC_QDONE_INFO      scsiq_buf;
-    REG ASC_QDONE_INFO *scsiq;
+    ASC_QDONE_INFO *scsiq;
     int                 false_overrun;
     ASC_ISR_CALLBACK    asc_isr_callback;
 
     iop_base = asc_dvc->iop_base;
-    asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
+    asc_isr_callback = asc_dvc->isr_callback;
     n_q_used = 1;
     scsiq = (ASC_QDONE_INFO *) & scsiq_buf;
     done_q_tail = (uchar) AscGetVarDoneQTail(iop_base);
@@ -11789,7 +11846,7 @@
         } else if (scsiq->q_status == QS_DONE) {
             false_overrun = FALSE;
             if (scsiq->extra_bytes != 0) {
-                scsiq->remain_bytes += (ulong) scsiq->extra_bytes;
+                scsiq->remain_bytes += (ADV_DCNT) scsiq->extra_bytes;
             }
             if (scsiq->d3.done_stat == QD_WITH_ERROR) {
                 if (scsiq->d3.host_stat == QHSTA_M_DATA_OVER_RUN) {
@@ -11839,7 +11896,7 @@
 
 STATIC int
 AscISR(
-          REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+          ASC_DVC_VAR *asc_dvc
 )
 {
     ASC_CS_TYPE         chipstat;
@@ -12084,7 +12141,7 @@
 };
 
 STATIC ushort _asc_mcode_size ASC_INITDATA = sizeof(_asc_mcode_buf);
-STATIC ulong  _asc_mcode_chksum ASC_INITDATA = 0x012C453FUL;
+STATIC ADV_DCNT _asc_mcode_chksum ASC_INITDATA = 0x012C453FUL;
 
 #define ASC_SYN_OFFSET_ONE_DISABLE_LIST  16
 STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] =
@@ -12109,8 +12166,8 @@
 
 STATIC int
 AscExeScsiQueue(
-                   REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-                   REG ASC_SCSI_Q * scsiq
+                   ASC_DVC_VAR *asc_dvc,
+                   ASC_SCSI_Q *scsiq
 )
 {
     PortAddr            iop_base;
@@ -12119,7 +12176,7 @@
     int                 n_q_required;
     int                 disable_syn_offset_one_fix;
     int                 i;
-    ulong               addr;
+    ASC_PADDR           addr;
     ASC_EXE_CALLBACK    asc_exe_callback;
     ushort              sg_entry_cnt = 0;
     ushort              sg_entry_cnt_minus_one = 0;
@@ -12129,12 +12186,12 @@
     uchar               extra_bytes;
     uchar               scsi_cmd;
     uchar               disable_cmd;
-    ASC_SG_HEAD *sg_head;
-    ulong               data_cnt;
+    ASC_SG_HEAD         *sg_head;
+    ASC_DCNT            data_cnt;
 
     iop_base = asc_dvc->iop_base;
     sg_head = scsiq->sg_head;
-    asc_exe_callback = (ASC_EXE_CALLBACK) asc_dvc->exe_callback;
+    asc_exe_callback = asc_dvc->exe_callback;
     if (asc_dvc->err_code != 0)
         return (ERR);
     if (scsiq == (ASC_SCSI_Q *) 0L) {
@@ -12180,8 +12237,8 @@
         }
 #endif /* !CC_VERY_LONG_SG_LIST */
         if (sg_entry_cnt == 1) {
-            scsiq->q1.data_addr = (ulong) sg_head->sg_list[0].addr;
-            scsiq->q1.data_cnt = (ulong) sg_head->sg_list[0].bytes;
+            scsiq->q1.data_addr = (ADV_PADDR) sg_head->sg_list[0].addr;
+            scsiq->q1.data_cnt = (ADV_DCNT) sg_head->sg_list[0].bytes;
             scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
         }
         sg_entry_cnt_minus_one = sg_entry_cnt - 1;
@@ -12193,7 +12250,7 @@
         if (scsiq->q1.cntl & QC_SG_HEAD) {
             data_cnt = 0;
             for (i = 0; i < sg_entry_cnt; i++) {
-                data_cnt += (ulong) sg_head->sg_list[i].bytes;
+                data_cnt += (ADV_DCNT) sg_head->sg_list[i].bytes;
             }
         } else {
             data_cnt = scsiq->q1.data_cnt;
@@ -12228,8 +12285,10 @@
                 if ((scsi_cmd == SCSICMD_Read6) ||
                     (scsi_cmd == SCSICMD_Read10)) {
                     addr =
-                        (ulong) sg_head->sg_list[sg_entry_cnt_minus_one].addr +
-                        (ulong) sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
+                        (ADV_PADDR)
+                            sg_head->sg_list[sg_entry_cnt_minus_one].addr +
+                        (ADV_DCNT)
+                            sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
                     extra_bytes = (uchar) ((ushort) addr & 0x0003);
                     if ((extra_bytes != 0) &&
                         ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES)
@@ -12237,7 +12296,7 @@
                         scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
                         scsiq->q1.extra_bytes = extra_bytes;
                         sg_head->sg_list[sg_entry_cnt_minus_one].bytes -=
-                            (ulong) extra_bytes;
+                            (ASC_DCNT) extra_bytes;
                     }
                 }
             }
@@ -12277,7 +12336,7 @@
                           == 0)) {
                         if (((ushort) scsiq->q1.data_cnt & 0x01FF) == 0) {
                             scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
-                            scsiq->q1.data_cnt -= (ulong) extra_bytes;
+                            scsiq->q1.data_cnt -= (ASC_DCNT) extra_bytes;
                             scsiq->q1.extra_bytes = extra_bytes;
                         }
                     }
@@ -12305,8 +12364,8 @@
 
 STATIC int
 AscSendScsiQueue(
-                    REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-                    REG ASC_SCSI_Q * scsiq,
+                    ASC_DVC_VAR *asc_dvc,
+                    ASC_SCSI_Q *scsiq,
                     uchar n_q_required
 )
 {
@@ -12369,7 +12428,7 @@
 
 STATIC uint
 AscGetNumOfFreeQueue(
-                        REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                        ASC_DVC_VAR *asc_dvc,
                         uchar target_ix,
                         uchar n_qs
 )
@@ -12411,8 +12470,8 @@
 
 STATIC int
 AscPutReadyQueue(
-                    REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-                    REG ASC_SCSI_Q * scsiq,
+                    ASC_DVC_VAR *asc_dvc,
+                    ASC_SCSI_Q *scsiq,
                     uchar q_no
 )
 {
@@ -12456,8 +12515,8 @@
 
 STATIC int
 AscPutReadySgListQueue(
-                          REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-                          REG ASC_SCSI_Q * scsiq,
+                          ASC_DVC_VAR *asc_dvc,
+                          ASC_SCSI_Q *scsiq,
                           uchar q_no
 )
 {
@@ -12465,8 +12524,8 @@
     int                 i;
     ASC_SG_HEAD *sg_head;
     ASC_SG_LIST_Q       scsi_sg_q;
-    ulong               saved_data_addr;
-    ulong               saved_data_cnt;
+    ASC_DCNT            saved_data_addr;
+    ASC_DCNT            saved_data_cnt;
     PortAddr            iop_base;
     ushort              sg_list_dwords;
     ushort              sg_index;
@@ -12478,8 +12537,8 @@
     sg_head = scsiq->sg_head;
     saved_data_addr = scsiq->q1.data_addr;
     saved_data_cnt = scsiq->q1.data_cnt;
-    scsiq->q1.data_addr = (ulong) sg_head->sg_list[0].addr;
-    scsiq->q1.data_cnt = (ulong) sg_head->sg_list[0].bytes;
+    scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
+    scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
     /*
      * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
      * then not all SG elements will fit in the allocated queues.
@@ -12564,7 +12623,7 @@
                                  (ushort) (sizeof (ASC_SG_LIST_Q) >> 1));
             AscMemDWordCopyToLram(iop_base,
                                   (ushort) (q_addr + ASC_SGQ_LIST_BEG),
-                              (ulong *) & sg_head->sg_list[sg_index],
+                                  (ADV_PADDR *) &sg_head->sg_list[sg_index],
                                   (ushort) sg_list_dwords);
             sg_index += ASC_SG_LIST_PER_Q;
             scsiq->next_sg_index = sg_index;
@@ -12580,8 +12639,8 @@
 
 STATIC int
 AscAbortSRB(
-               REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-               ulong srb_ptr
+               ASC_DVC_VAR *asc_dvc,
+               ADV_VADDR srb_ptr
 )
 {
     int                 sta;
@@ -12610,7 +12669,7 @@
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 STATIC int
 AscResetDevice(
-                  REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                  ASC_DVC_VAR *asc_dvc,
                   uchar target_ix
 )
 {
@@ -12683,7 +12742,7 @@
 
 STATIC int
 AscResetSB(
-              REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+              ASC_DVC_VAR *asc_dvc
 )
 {
     int                 sta;
@@ -12697,7 +12756,7 @@
     AscStopQueueExe(iop_base);
     asc_dvc->sdtr_done = 0;
     AscResetChipAndScsiBus(asc_dvc);
-    DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000));
+    DvcSleepMilliSecond((ASC_DCNT) ((ushort) asc_dvc->scsi_reset_wait * 1000));
     AscReInitLram(asc_dvc);
     for (i = 0; i <= ASC_MAX_TID; i++) {
         asc_dvc->cur_dvc_qng[i] = 0;
@@ -12772,7 +12831,7 @@
 
 STATIC int
 AscReInitLram(
-                 REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+                 ASC_DVC_VAR *asc_dvc
 )
 {
     AscInitLram(asc_dvc);
@@ -12782,7 +12841,7 @@
 
 STATIC ushort
 AscInitLram(
-               REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+               ASC_DVC_VAR *asc_dvc
 )
 {
     uchar               i;
@@ -12835,7 +12894,7 @@
 
 STATIC ushort
 AscInitQLinkVar(
-                   REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+                   ASC_DVC_VAR *asc_dvc
 )
 {
     PortAddr            iop_base;
@@ -12868,7 +12927,7 @@
 
 STATIC int
 AscSetLibErrorCode(
-                      REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                      ASC_DVC_VAR *asc_dvc,
                       ushort err_code
 )
 {
@@ -12885,7 +12944,7 @@
 STATIC int
 _AscWaitQDone(
                  PortAddr iop_base,
-                 REG ASC_SCSI_Q * scsiq
+                 ASC_SCSI_Q * scsiq
 )
 {
     ushort              q_addr;
@@ -12907,7 +12966,7 @@
 
 STATIC uchar 
 AscMsgOutSDTR(
-                 REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                 ASC_DVC_VAR *asc_dvc,
                  uchar sdtr_period,
                  uchar sdtr_offset
 )
@@ -12944,7 +13003,7 @@
 
 STATIC uchar
 AscCalSDTRData(
-                  REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                  ASC_DVC_VAR *asc_dvc,
                   uchar sdtr_period,
                   uchar syn_offset
 )
@@ -12976,11 +13035,11 @@
 
 STATIC uchar
 AscGetSynPeriodIndex(
-                        ASC_DVC_VAR asc_ptr_type * asc_dvc,
-                        ruchar syn_time
+                        ASC_DVC_VAR *asc_dvc,
+                        uchar syn_time
 )
 {
-    ruchar             *period_table;
+    uchar             *period_table;
     int                 max_index;
     int                 min_index;
     int                 i;
@@ -13041,8 +13100,8 @@
 
 STATIC int
 AscRiscHaltedAbortSRB(
-                         REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
-                         ulong srb_ptr
+                         ASC_DVC_VAR *asc_dvc,
+                         ASC_VADDR srb_ptr
 )
 {
     PortAddr            iop_base;
@@ -13054,7 +13113,7 @@
     int                 last_int_level;
 
     iop_base = asc_dvc->iop_base;
-    asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
+    asc_isr_callback = asc_dvc->isr_callback;
     last_int_level = DvcEnterCritical();
     scsiq = (ASC_QDONE_INFO *) & scsiq_buf;
     for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng;
@@ -13087,7 +13146,7 @@
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 STATIC int
 AscRiscHaltedAbortTIX(
-                         REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                         ASC_DVC_VAR *asc_dvc,
                          uchar target_ix
 )
 {
@@ -13100,7 +13159,7 @@
     int                 last_int_level;
 
     iop_base = asc_dvc->iop_base;
-    asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
+    asc_isr_callback = asc_dvc->isr_callback;
     last_int_level = DvcEnterCritical();
     scsiq = (ASC_QDONE_INFO *) & scsiq_buf;
     for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng;
@@ -13235,7 +13294,7 @@
 
 STATIC int
 AscWaitTixISRDone(
-                     ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                     ASC_DVC_VAR *asc_dvc,
                      uchar target_ix
 )
 {
@@ -13258,7 +13317,7 @@
 
 STATIC int
 AscWaitISRDone(
-                  REG ASC_DVC_VAR asc_ptr_type * asc_dvc
+                  ASC_DVC_VAR *asc_dvc
 )
 {
     int                 tid;
@@ -13269,24 +13328,24 @@
     return (1);
 }
 
-STATIC ulong
+STATIC ASC_PADDR
 AscGetOnePhyAddr(
-                    REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
+                    ASC_DVC_VAR *asc_dvc,
                     uchar * buf_addr,
-                    ulong buf_size
+                    ASC_DCNT buf_size
 )
 {
     ASC_MIN_SG_HEAD     sg_head;
 
     sg_head.entry_cnt = ASC_MIN_SG_LIST;
     if (DvcGetSGList(asc_dvc, (uchar *) buf_addr,
-                  buf_size, (ASC_SG_HEAD *) & sg_head) != buf_size) {
+                  buf_size, (ASC_SG_HEAD *) &sg_head) != buf_size) {
         return (0L);
     }
     if (sg_head.entry_cnt > 1) {
         return (0L);
     }
-    return ((ulong) sg_head.sg_list[0].addr);
+    return ((ASC_PADDR) sg_head.sg_list[0].addr);
 }
 
 STATIC void
@@ -13296,13 +13355,13 @@
 }
 
 STATIC void
-DvcDelayNanoSecond(ASC_DVC_VAR asc_ptr_type * asc_dvc, ulong nano_sec)
+DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
 {
     udelay((nano_sec + 999)/1000);
 }
 
 ASC_INITFUNC(
-STATIC ulong,
+STATIC ASC_DCNT,
 AscGetEisaProductID(
                        PortAddr iop_base
 )
@@ -13310,12 +13369,13 @@
 {
     PortAddr            eisa_iop;
     ushort              product_id_high, product_id_low;
-    ulong               product_id;
+    ASC_DCNT            product_id;
 
     eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
     product_id_low = inpw(eisa_iop);
     product_id_high = inpw(eisa_iop + 2);
-    product_id = ((ulong) product_id_high << 16) | (ulong) product_id_low;
+    product_id = ((ASC_DCNT) product_id_high << 16) |
+        (ASC_DCNT) product_id_low;
     return (product_id);
 }
 
@@ -13326,7 +13386,7 @@
 )
 )
 {
-    ulong               eisa_product_id;
+    ASC_DCNT            eisa_product_id;
 
     if (iop_base == 0) {
         iop_base = ASC_EISA_MIN_IOP_ADDR;
@@ -13518,7 +13578,7 @@
 }
 
 ASC_INITFUNC(
-STATIC ulong,
+STATIC ASC_DCNT,
 AscGetMaxDmaCount(
                      ushort bus_type
 )
@@ -13606,7 +13666,7 @@
 ASC_INITFUNC(
 STATIC ushort,
 AscReadPCIConfigWord(
-    ASC_DVC_VAR asc_ptr_type *asc_dvc,
+    ASC_DVC_VAR *asc_dvc,
     ushort pci_config_offset)
 )
 {
@@ -13620,7 +13680,7 @@
 ASC_INITFUNC(
 STATIC ushort,
 AscInitGetConfig(
-        ASC_DVC_VAR asc_ptr_type * asc_dvc
+        ASC_DVC_VAR *asc_dvc
 )
 )
 {
@@ -13705,7 +13765,7 @@
 ASC_INITFUNC(
 STATIC ushort,
 AscInitSetConfig(
-                    ASC_DVC_VAR asc_ptr_type * asc_dvc
+                    ASC_DVC_VAR *asc_dvc
 )
 )
 {
@@ -13726,7 +13786,7 @@
 ASC_INITFUNC(
 STATIC ushort,
 AscInitFromAscDvcVar(
-                        ASC_DVC_VAR asc_ptr_type * asc_dvc
+                        ASC_DVC_VAR *asc_dvc
 )
 )
 {
@@ -13789,7 +13849,7 @@
 ASC_INITFUNC(
 STATIC ushort,
 AscInitAsc1000Driver(
-                        ASC_DVC_VAR asc_ptr_type * asc_dvc
+                        ASC_DVC_VAR *asc_dvc
 )
 )
 {
@@ -13801,7 +13861,8 @@
     if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
         !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
         AscResetChipAndScsiBus(asc_dvc);
-        DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000));
+        DvcSleepMilliSecond((ASC_DCNT)
+            ((ushort) asc_dvc->scsi_reset_wait * 1000));
     }
     asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
     if (asc_dvc->err_code != 0)
@@ -13828,7 +13889,7 @@
 ASC_INITFUNC(
 STATIC ushort,
 AscInitAscDvcVar(
-                    ASC_DVC_VAR asc_ptr_type * asc_dvc
+                    ASC_DVC_VAR *asc_dvc
 )
 )
 {
@@ -13862,8 +13923,6 @@
     asc_dvc->redo_scam = 0;
     asc_dvc->res2 = 0;
     asc_dvc->host_init_sdtr_index = 0;
-    asc_dvc->res7 = 0;
-    asc_dvc->res8 = 0;
     asc_dvc->cfg->can_tagged_qng = 0;
     asc_dvc->cfg->cmd_qng_enabled = 0;
     asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
@@ -13943,7 +14002,7 @@
 ASC_INITFUNC(
 STATIC ushort,
 AscInitFromEEP(
-                  ASC_DVC_VAR asc_ptr_type * asc_dvc
+                  ASC_DVC_VAR *asc_dvc
 )
 )
 {
@@ -13964,7 +14023,8 @@
         (AscGetChipScsiCtrl(iop_base) != 0)) {
         asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
         AscResetChipAndScsiBus(asc_dvc);
-        DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000));
+        DvcSleepMilliSecond((ASC_DCNT)
+            ((ushort) asc_dvc->scsi_reset_wait * 1000));
     }
     if (AscIsChipHalted(iop_base) == FALSE) {
         asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
@@ -14098,14 +14158,14 @@
 ASC_INITFUNC(
 STATIC ushort,
 AscInitMicroCodeVar(
-                       ASC_DVC_VAR asc_ptr_type * asc_dvc
+                       ASC_DVC_VAR *asc_dvc
 )
 )
 {
     int                 i;
     ushort              warn_code;
     PortAddr            iop_base;
-    ulong               phy_addr;
+    ASC_PADDR           phy_addr;
 
     iop_base = asc_dvc->iop_base;
     warn_code = 0;
@@ -14124,7 +14184,8 @@
                                      ASC_OVERRUN_BSIZE)) == 0L) {
         asc_dvc->err_code |= ASC_IERR_GET_PHY_ADDR;
     } else {
-        phy_addr = (phy_addr & 0xFFFFFFF8UL) + 8;
+        /* Align on an 8 byte boundary. */
+        phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
         AscWriteLramDWord(iop_base, ASCV_OVERRUN_PADDR_D, phy_addr);
         AscWriteLramDWord(iop_base, ASCV_OVERRUN_BSIZE_D,
                           ASC_OVERRUN_BSIZE - 8);
@@ -14148,7 +14209,7 @@
 ASC_INITFUNC(
 STATIC int,
 AscTestExternalLram(
-                       ASC_DVC_VAR asc_ptr_type * asc_dvc
+                       ASC_DVC_VAR *asc_dvc
 )
 )
 {
@@ -14302,7 +14363,7 @@
 {
     ushort              wval;
     ushort              sum;
-    ushort      *wbuf;
+    ushort              *wbuf;
     int                 cfg_beg;
     int                 cfg_end;
     int                 s_addr;
@@ -14416,7 +14477,7 @@
 
 STATIC void
 AscAsyncFix(
-               ASC_DVC_VAR asc_ptr_type *asc_dvc,
+               ASC_DVC_VAR *asc_dvc,
                uchar tid_no,
                ASC_SCSI_INQUIRY *inq)
 {
@@ -14470,7 +14531,7 @@
 }
 
 STATIC void
-AscInquiryHandling(ASC_DVC_VAR asc_ptr_type *asc_dvc,
+AscInquiryHandling(ASC_DVC_VAR *asc_dvc,
                    uchar tid_no, ASC_SCSI_INQUIRY *inq)
 {
     ASC_SCSI_BIT_ID_TYPE tid_bit = ASC_TIX_TO_TARGET_ID(tid_no);
@@ -14516,8 +14577,8 @@
 
 STATIC int
 AscCompareString(
-                    ruchar * str1,
-                    ruchar * str2,
+                    uchar *str1,
+                    uchar *str2,
                     int len
 )
 {
@@ -14566,19 +14627,19 @@
     return (word_data);
 }
 
-STATIC ulong
+STATIC ASC_DCNT
 AscReadLramDWord(
                     PortAddr iop_base,
                     ushort addr
 )
 {
     ushort              val_low, val_high;
-    ulong               dword_data;
+    ASC_DCNT            dword_data;
 
     AscSetChipLramAddr(iop_base, addr);
     val_low = AscGetChipLramData(iop_base);
     val_high = AscGetChipLramData(iop_base);
-    dword_data = ((ulong) val_high << 16) | (ulong) val_low;
+    dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
     return (dword_data);
 }
 
@@ -14598,7 +14659,7 @@
 AscWriteLramDWord(
                      PortAddr iop_base,
                      ushort addr,
-                     ulong dword_val
+                     ASC_DCNT dword_val
 )
 {
     ushort              word_val;
@@ -14651,7 +14712,7 @@
 AscMemDWordCopyToLram(
                          PortAddr iop_base,
                          ushort s_addr,
-                         ulong * s_buffer,
+                         ASC_DCNT *s_buffer,
                          int dwords
 )
 {
@@ -14673,15 +14734,15 @@
     return;
 }
 
-STATIC ulong
+STATIC ASC_DCNT
 AscMemSumLramWord(
                      PortAddr iop_base,
                      ushort s_addr,
-                     rint words
+                     int words
 )
 {
-    ulong               sum;
-    int                 i;
+    ASC_DCNT         sum;
+    int              i;
 
     sum = 0L;
     for (i = 0; i < words; i++, s_addr += 2) {
@@ -14695,10 +14756,10 @@
                      PortAddr iop_base,
                      ushort s_addr,
                      ushort set_wval,
-                     rint words
+                     int words
 )
 {
-    rint             i;
+    int             i;
 
     AscSetChipLramAddr(iop_base, s_addr);
     for (i = 0; i < words; i++) {
@@ -14714,664 +14775,675 @@
 
 /* a_mcode.h */
 STATIC unsigned char _adv_asc3550_buf[] = {
-  0x00,  0x00,  0x00,  0xf2,  0x00,  0xf0,  0x00,  0x16,  0x00,  0xfc,  0x48,  0xe4,  0x01,  0x00,  0x01,  0xf6,
-  0x00,  0xf6,  0x18,  0xe4,  0x0a,  0x19,  0x18,  0x80,  0x02,  0x00,  0xff,  0xff,  0x03,  0xf6,  0x00,  0xfa,
-  0xff,  0x00,  0x82,  0xe7,  0x9e,  0xe7,  0x01,  0xfa,  0x06,  0x0e,  0x09,  0xe7,  0x00,  0xea,  0x01,  0xe6,
-  0x03,  0x00,  0x08,  0x00,  0x18,  0xf4,  0x55,  0xf0,  0x3e,  0x01,  0x3e,  0x57,  0x04,  0x00,  0x1e,  0xf0,
-  0x85,  0xf0,  0x00,  0xe6,  0x00,  0xec,  0x32,  0xf0,  0x86,  0xf0,  0xa4,  0x0c,  0xd0,  0x01,  0xd5,  0xf0,
-  0xf6,  0x18,  0x38,  0x54,  0x98,  0x57,  0xbc,  0x00,  0xb1,  0xf0,  0xb4,  0x00,  0x01,  0xfc,  0x02,  0x13,
-  0x03,  0xfc,  0x9e,  0x0c,  0x00,  0x57,  0x01,  0xf0,  0x03,  0xe6,  0x0c,  0x1c,  0x10,  0x00,  0x18,  0x40,
-  0x30,  0x12,  0x3e,  0x1c,  0xbd,  0x00,  0xe0,  0x00,  0x02,  0x48,  0x02,  0x80,  0x3c,  0x00,  0x4e,  0x01,
-  0x66,  0x15,  0x6c,  0x01,  0x6e,  0x01,  0xbb,  0x00,  0xda,  0x12,  0x00,  0x4e,  0x01,  0x01,  0x01,  0xea,
-  0x08,  0x12,  0x30,  0xe4,  0x6a,  0x0f,  0xa8,  0x0c,  0xae,  0x0f,  0xb6,  0x00,  0xb9,  0x54,  0x00,  0x80,
-  0x04,  0x12,  0x06,  0xf7,  0x24,  0x01,  0x28,  0x01,  0x32,  0x00,  0x3c,  0x01,  0x3c,  0x56,  0x3e,  0x00,
-  0x4b,  0xe4,  0x4c,  0x1c,  0x68,  0x01,  0x6a,  0x01,  0x70,  0x01,  0x72,  0x01,  0x74,  0x01,  0x76,  0x01,
-  0x78,  0x01,  0x00,  0x01,  0x02,  0xee,  0x02,  0xfc,  0x03,  0x58,  0x03,  0xf7,  0x04,  0x80,  0x05,  0xfc,
-  0x08,  0x44,  0x09,  0xf0,  0x0a,  0x15,  0x10,  0x44,  0x1b,  0x80,  0x20,  0x01,  0x38,  0x1c,  0x40,  0x00,
-  0x4b,  0xf4,  0x4e,  0x1c,  0x5b,  0xf0,  0x5d,  0xf0,  0x80,  0x00,  0xaa,  0x00,  0xaa,  0x14,  0xb6,  0x08,
-  0xb8,  0x0f,  0xbb,  0x55,  0xbd,  0x56,  0xbe,  0x00,  0xc0,  0x00,  0x00,  0x4c,  0x00,  0xdc,  0x02,  0x4a,
-  0x05,  0xf0,  0x05,  0xf8,  0x06,  0x13,  0x08,  0x13,  0x0c,  0x00,  0x0e,  0x47,  0x0e,  0xf7,  0x0f,  0x00,
-  0x19,  0x00,  0x20,  0x00,  0x2a,  0x01,  0x32,  0x1c,  0x36,  0x00,  0x38,  0x12,  0x3c,  0x0b,  0x45,  0x5a,
-  0x56,  0x14,  0x59,  0xf0,  0x62,  0x0a,  0x69,  0x08,  0x83,  0x59,  0xae,  0x17,  0xb8,  0xf0,  0xba,  0x0f,
-  0xba,  0x17,  0xf0,  0x00,  0xf6,  0x0d,  0x02,  0xfa,  0x03,  0xfa,  0x04,  0x10,  0x04,  0xea,  0x04,  0xf6,
-  0x04,  0xfc,  0x05,  0x00,  0x06,  0x00,  0x06,  0x12,  0x0a,  0x10,  0x0b,  0xf0,  0x0c,  0xf0,  0x12,  0x10,
-  0x30,  0x1c,  0x33,  0x00,  0x34,  0x00,  0x38,  0x44,  0x40,  0x5c,  0x4a,  0xe4,  0x5a,  0x14,  0x62,  0x1a,
-  0x64,  0x0a,  0x68,  0x08,  0x68,  0x54,  0x83,  0x55,  0x83,  0x5a,  0x91,  0x44,  0x98,  0x12,  0x9a,  0x16,
-  0xa4,  0x00,  0xb0,  0x57,  0xb5,  0x00,  0xba,  0x00,  0xce,  0x45,  0xd0,  0x00,  0xe1,  0x00,  0xe7,  0x00,
-  0xec,  0x0d,  0x00,  0x54,  0x01,  0x48,  0x01,  0x58,  0x02,  0x10,  0x02,  0xe6,  0x03,  0xa1,  0x04,  0x13,
-  0x05,  0xe6,  0x06,  0x0b,  0x06,  0x83,  0x06,  0xf0,  0x07,  0x00,  0x0a,  0x00,  0x0a,  0x12,  0x0a,  0xf0,
-  0x0c,  0x04,  0x0c,  0x10,  0x0c,  0x12,  0x0e,  0x13,  0x10,  0x10,  0x12,  0x1c,  0x17,  0x00,  0x18,  0x0e,
-  0x19,  0xe4,  0x1a,  0x10,  0x1c,  0x00,  0x1c,  0x12,  0x1c,  0x14,  0x1d,  0xf7,  0x1e,  0x13,  0x20,  0x1c,
-  0x20,  0xe7,  0x22,  0x01,  0x26,  0x01,  0x2a,  0x12,  0x30,  0xe7,  0x41,  0x58,  0x43,  0x48,  0x44,  0x55,
-  0x46,  0x1c,  0x4e,  0xe4,  0x5c,  0xf0,  0x72,  0x02,  0x74,  0x03,  0x77,  0x57,  0x88,  0x12,  0x89,  0x48,
-  0x92,  0x13,  0x99,  0x00,  0x9b,  0x00,  0x9c,  0x32,  0x9e,  0x00,  0xa8,  0x00,  0xaa,  0x12,  0xb9,  0x00,
-  0xba,  0x06,  0xbf,  0x57,  0xc0,  0x01,  0xc0,  0x08,  0xc2,  0x01,  0xfe,  0x9c,  0xf0,  0x26,  0x02,  0xfe,
-  0xc6,  0x0c,  0xff,  0x10,  0x00,  0x00,  0xfc,  0xfe,  0x18,  0x19,  0x00,  0xfa,  0xfe,  0x80,  0x01,  0xff,
-  0x03,  0x00,  0x00,  0x2f,  0xfe,  0x01,  0x05,  0xff,  0x40,  0x00,  0x00,  0x0d,  0xff,  0x09,  0x00,  0x00,
-  0xff,  0x08,  0x01,  0x01,  0xff,  0x10,  0xff,  0xff,  0xff,  0x1f,  0x00,  0x00,  0xff,  0x10,  0xff,  0xff,
-  0xff,  0x0f,  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,  0x00,  0x00,  0xfe,  0x04,
-  0xf7,  0xfa,  0x35,  0x51,  0x0c,  0x01,  0xfe,  0xb6,  0x0e,  0xfe,  0x04,  0xf7,  0xfa,  0x51,  0x0c,  0x1d,
-  0x35,  0xfe,  0x3d,  0xf0,  0xfe,  0xf8,  0x01,  0xfe,  0x20,  0xf0,  0xd0,  0x04,  0x55,  0x50,  0x02,  0xfe,
-  0xe2,  0x0c,  0x01,  0xfe,  0x42,  0x0d,  0xfe,  0xe9,  0x12,  0x02,  0xfe,  0x04,  0x03,  0xfe,  0x28,  0x1c,
-  0x04,  0xfe,  0xa6,  0x00,  0xfe,  0xdd,  0x12,  0x4e,  0x13,  0xfe,  0xa6,  0x00,  0xc3,  0xfe,  0x48,  0xf0,
-  0xfe,  0x7c,  0x02,  0xfe,  0x49,  0xf0,  0xfe,  0x96,  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xb4,  0x02,  0xfe,
-  0x46,  0xf0,  0xfe,  0x46,  0x02,  0xfe,  0x47,  0xf0,  0xfe,  0x4c,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x3a,
-  0x02,  0xfe,  0x44,  0xf0,  0xfe,  0x3e,  0x02,  0xfe,  0x45,  0xf0,  0xfe,  0x42,  0x02,  0x07,  0x0c,  0x9d,
-  0x07,  0x06,  0x13,  0xb8,  0x02,  0x26,  0xfe,  0x00,  0x1c,  0xfe,  0xf1,  0x10,  0xfe,  0x02,  0x1c,  0xfe,
-  0xed,  0x10,  0xfe,  0x1e,  0x1c,  0xfe,  0xe9,  0x10,  0x01,  0xfe,  0x0e,  0x17,  0xfe,  0xe7,  0x10,  0xfe,
-  0x06,  0xfc,  0xf5,  0x0e,  0x7b,  0x01,  0xc0,  0x02,  0x26,  0x17,  0x54,  0x47,  0xba,  0x01,  0xfe,  0x2c,
-  0x0f,  0x0e,  0x7b,  0x01,  0x9a,  0xfe,  0xbd,  0x10,  0x0e,  0x7b,  0x01,  0x9a,  0xfe,  0xad,  0x10,  0xfe,
-  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x07,  0x06,  0x13,  0xb8,  0x35,  0x1f,  0x26,  0xfe,  0x3d,  0xf0,  0xfe,
-  0xf8,  0x01,  0x27,  0xfe,  0x8a,  0x02,  0xfe,  0x5a,  0x1c,  0xd5,  0xfe,  0x14,  0x1c,  0x17,  0xfe,  0x30,
-  0x00,  0x47,  0xba,  0x01,  0xfe,  0x1c,  0x0f,  0x07,  0x06,  0x13,  0xb8,  0x02,  0xfc,  0x22,  0x2b,  0x05,
-  0x10,  0x2f,  0xfe,  0x69,  0x10,  0x07,  0x06,  0x13,  0xb8,  0xfe,  0x04,  0xec,  0x2b,  0x08,  0x2b,  0x07,
-  0x3a,  0x1d,  0x01,  0x40,  0x7f,  0xfe,  0x05,  0xf6,  0xf5,  0x01,  0xfe,  0x40,  0x16,  0x0b,  0x49,  0x89,
-  0x37,  0x11,  0x43,  0x1d,  0xca,  0x08,  0x1c,  0x07,  0x3f,  0x01,  0x6a,  0x02,  0x26,  0x0e,  0x3b,  0x01,
-  0x14,  0x05,  0x10,  0xd3,  0x08,  0x1c,  0x07,  0x3f,  0x01,  0x76,  0xfe,  0x28,  0x10,  0x0e,  0xbd,  0x01,
-  0x14,  0xe5,  0x0e,  0x7c,  0x01,  0x14,  0xfe,  0x49,  0x54,  0x72,  0xfe,  0x12,  0x03,  0x08,  0x1c,  0x07,
-  0x3f,  0x01,  0x6a,  0x02,  0x26,  0x35,  0x7f,  0xfe,  0x02,  0xe8,  0x2d,  0xf9,  0xfe,  0x9e,  0x43,  0xed,
-  0xfe,  0x07,  0x4b,  0xfe,  0x20,  0xf0,  0xd0,  0xfe,  0x40,  0x1c,  0x1f,  0xec,  0xfe,  0x26,  0xf0,  0xfe,
-  0x70,  0x03,  0xfe,  0xa0,  0xf0,  0xfe,  0x5e,  0x03,  0xfe,  0x11,  0xf0,  0xd0,  0xfe,  0x0e,  0x10,  0xfe,
-  0x9f,  0xf0,  0xfe,  0x7e,  0x03,  0xe8,  0x12,  0xfe,  0x11,  0x00,  0x02,  0x4b,  0x35,  0xfe,  0x48,  0x1c,
-  0xe8,  0x1f,  0xec,  0x33,  0xec,  0xfe,  0x82,  0xf0,  0xfe,  0x84,  0x03,  0x29,  0x22,  0xbb,  0x68,  0x16,
-  0xbb,  0x0e,  0x7c,  0x01,  0x14,  0x68,  0x7d,  0x08,  0x1c,  0x07,  0x3f,  0x01,  0x40,  0x11,  0x3b,  0x08,
-  0x3b,  0x07,  0x99,  0x01,  0x6a,  0xf3,  0x11,  0xfe,  0xe4,  0x00,  0x2c,  0xfe,  0xca,  0x03,  0x1f,  0x31,
-  0x20,  0xfe,  0xda,  0x03,  0x01,  0x4a,  0xcb,  0xfe,  0xea,  0x03,  0x69,  0x8e,  0xcf,  0xfe,  0xaa,  0x06,
-  0x02,  0x25,  0x04,  0x7b,  0x2a,  0x1b,  0xfe,  0x1c,  0x05,  0x17,  0x84,  0x01,  0x38,  0x01,  0x95,  0x01,
-  0x98,  0x33,  0xfe,  0x5c,  0x02,  0x02,  0xeb,  0xe8,  0x35,  0x51,  0x18,  0xfe,  0x67,  0x1b,  0xf9,  0xed,
-  0xfe,  0x48,  0x1c,  0x8b,  0x01,  0xee,  0xa8,  0xfe,  0x96,  0xf0,  0xfe,  0x24,  0x04,  0x2c,  0xfe,  0x28,
-  0x04,  0x33,  0x26,  0x0e,  0x3b,  0x01,  0x14,  0x05,  0x10,  0x1b,  0xfe,  0x08,  0x05,  0x3c,  0x92,  0x9e,
-  0x2d,  0x81,  0x6d,  0x1f,  0x31,  0x20,  0x25,  0x04,  0x7b,  0x2a,  0xfe,  0x10,  0x12,  0x17,  0x84,  0x01,
-  0x38,  0x33,  0xfe,  0x5c,  0x02,  0x02,  0xeb,  0x30,  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x5e,
-  0x12,  0x0b,  0x09,  0x06,  0xfe,  0x56,  0x12,  0x23,  0x28,  0x93,  0x01,  0x0a,  0x81,  0x6d,  0x20,  0xfe,
-  0xd8,  0x04,  0x23,  0x28,  0x93,  0x01,  0x0a,  0x20,  0x25,  0x23,  0x28,  0xb1,  0xfe,  0x4c,  0x44,  0xfe,
-  0x32,  0x12,  0x56,  0xfe,  0x44,  0x48,  0x08,  0xd6,  0xfe,  0x4c,  0x54,  0x72,  0xfe,  0x08,  0x05,  0x7f,
-  0x9e,  0x2d,  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x48,  0x13,  0x3d,  0x05,  0xfe,  0xcc,  0x00,
-  0xfe,  0x40,  0x13,  0x0b,  0x09,  0x06,  0x8d,  0xfe,  0x06,  0x10,  0x23,  0x28,  0xb1,  0x0b,  0x09,  0x36,
-  0xdb,  0x17,  0xa2,  0x0b,  0x09,  0x06,  0x50,  0x17,  0xfe,  0x0d,  0x00,  0x01,  0x38,  0x33,  0xfe,  0x86,
-  0x0c,  0x02,  0x25,  0x39,  0x11,  0xfe,  0xe6,  0x00,  0xfe,  0x1c,  0x90,  0xac,  0x03,  0x17,  0xa2,  0x01,
-  0x38,  0x33,  0x26,  0x1f,  0x26,  0x02,  0xfe,  0x10,  0x05,  0xfe,  0x42,  0x5b,  0x51,  0x18,  0xfe,  0x46,
-  0x59,  0xf9,  0xed,  0x17,  0x74,  0xfe,  0x07,  0x80,  0xfe,  0x31,  0x44,  0x0b,  0x09,  0x0c,  0xfe,  0x78,
-  0x13,  0xfe,  0x20,  0x80,  0x05,  0x18,  0xfe,  0x70,  0x12,  0x6c,  0x09,  0x06,  0xfe,  0x60,  0x13,  0x04,
-  0xfe,  0xa2,  0x00,  0x2a,  0x1b,  0xfe,  0xa8,  0x05,  0xfe,  0x31,  0xe4,  0x6f,  0x6c,  0x09,  0x0c,  0xfe,
-  0x4a,  0x13,  0x04,  0xfe,  0xa0,  0x00,  0x2a,  0xfe,  0x42,  0x12,  0x59,  0x2c,  0xfe,  0x68,  0x05,  0x1f,
-  0x31,  0xef,  0x01,  0x0a,  0x24,  0xfe,  0xc0,  0x05,  0x11,  0xfe,  0xe3,  0x00,  0x29,  0x6c,  0xfe,  0x4a,
-  0xf0,  0xfe,  0x92,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0x8c,  0x05,  0xd1,  0x21,  0xfe,  0x21,  0x00,  0xa4,
-  0x21,  0xfe,  0x22,  0x00,  0x9d,  0x21,  0x89,  0xfe,  0x09,  0x48,  0x01,  0x0a,  0x24,  0xfe,  0xc0,  0x05,
-  0xfe,  0xe2,  0x08,  0x6c,  0x09,  0xda,  0x50,  0x01,  0xb6,  0x21,  0x06,  0x16,  0xe2,  0x47,  0xfe,  0x27,
-  0x01,  0x0b,  0x09,  0x36,  0xe3,  0x4e,  0x01,  0xae,  0x17,  0xa2,  0x0b,  0x09,  0x06,  0x50,  0x17,  0xfe,
-  0x0d,  0x00,  0x01,  0x38,  0x01,  0x95,  0x01,  0x98,  0x33,  0xfe,  0x86,  0x0c,  0x02,  0x25,  0x04,  0xfe,
-  0x9c,  0x00,  0x2a,  0xfe,  0x3e,  0x12,  0x04,  0x52,  0x2a,  0xfe,  0x36,  0x13,  0x4e,  0x01,  0xae,  0x24,
-  0xfe,  0x38,  0x06,  0x0e,  0x06,  0x6c,  0x09,  0x19,  0xfe,  0x02,  0x12,  0x79,  0x01,  0xfe,  0xf0,  0x13,
-  0x20,  0xfe,  0x2e,  0x06,  0x11,  0xbe,  0x01,  0x4a,  0x11,  0xfe,  0xe5,  0x00,  0x04,  0x52,  0xb9,  0x0f,
-  0x52,  0x04,  0xf4,  0x2a,  0xfe,  0x62,  0x12,  0x04,  0x4d,  0x2a,  0xfe,  0x5a,  0x13,  0x01,  0xfe,  0x60,
-  0x18,  0x01,  0xfe,  0xb2,  0x18,  0xe6,  0xc8,  0x19,  0x08,  0x61,  0xff,  0x02,  0x00,  0x57,  0x64,  0x7e,
-  0x1a,  0x4f,  0xc7,  0xc8,  0x87,  0x4e,  0x01,  0xae,  0x24,  0xfe,  0xa2,  0x06,  0x6c,  0x09,  0x1e,  0xa3,
-  0x7a,  0x0e,  0x54,  0x01,  0xfe,  0x1e,  0x14,  0x20,  0xfe,  0x98,  0x06,  0x11,  0xbe,  0x01,  0x4a,  0x11,
-  0xfe,  0xe5,  0x00,  0x04,  0x4d,  0xb9,  0x0f,  0x4d,  0x07,  0x06,  0x01,  0xae,  0xf3,  0x71,  0x8b,  0x01,
-  0xee,  0xa8,  0x11,  0xfe,  0xe2,  0x00,  0x2c,  0xf8,  0x1f,  0x31,  0xcf,  0xfe,  0xd6,  0x06,  0x80,  0xfe,
-  0x74,  0x07,  0xcb,  0xfe,  0x7c,  0x07,  0x69,  0x8e,  0x02,  0x25,  0x0b,  0x09,  0x0c,  0xfe,  0x2e,  0x12,
-  0x15,  0x18,  0x01,  0x0a,  0x15,  0x00,  0x01,  0x0a,  0x15,  0x00,  0x01,  0x0a,  0x15,  0x00,  0x01,  0x0a,
-  0xfe,  0x99,  0xa4,  0x01,  0x0a,  0x15,  0x00,  0x02,  0xfe,  0x3a,  0x08,  0x66,  0x09,  0x1e,  0x8d,  0x0b,
-  0x09,  0x1e,  0xfe,  0x30,  0x13,  0x15,  0xfe,  0x1b,  0x00,  0x01,  0x0a,  0x15,  0x00,  0x01,  0x0a,  0x15,
-  0x00,  0x01,  0x0a,  0x15,  0x00,  0x01,  0x0a,  0x15,  0x06,  0x01,  0x0a,  0x15,  0x00,  0x02,  0xc9,  0x79,
-  0xfe,  0x9a,  0x81,  0x65,  0x89,  0xfe,  0x09,  0x6f,  0xfe,  0x93,  0x45,  0x1b,  0xfe,  0x84,  0x07,  0x2c,
-  0xfe,  0x5c,  0x07,  0x1f,  0x31,  0xcf,  0xfe,  0x54,  0x07,  0x69,  0x8e,  0x80,  0xfe,  0x74,  0x07,  0x02,
-  0x25,  0x01,  0x4a,  0x02,  0xf8,  0x15,  0x19,  0x02,  0xf8,  0xfe,  0x9c,  0xf7,  0xfe,  0xf0,  0x07,  0xfe,
-  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x73,  0xfe,  0xd2,  0x07,  0x0f,  0x5c,  0x13,  0x5d,  0x0b,  0x49,  0x6f,
-  0x37,  0x01,  0xfe,  0xf6,  0x17,  0x05,  0x10,  0x82,  0xfe,  0x83,  0xe7,  0x88,  0xa4,  0xfe,  0x03,  0x40,
-  0x0b,  0x49,  0x74,  0x37,  0x01,  0xb7,  0xab,  0xfe,  0x1f,  0x40,  0x16,  0x60,  0x01,  0xf6,  0xfe,  0x08,
-  0x50,  0xfe,  0x8a,  0x50,  0xfe,  0x34,  0x51,  0xfe,  0xb6,  0x51,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,
-  0x0f,  0x5a,  0x13,  0x5b,  0xfe,  0x0c,  0x90,  0xfe,  0x8e,  0x90,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,
-  0x0f,  0x41,  0x13,  0x42,  0xfe,  0x4a,  0x10,  0x0b,  0x09,  0x6f,  0xe3,  0xfe,  0x2c,  0x90,  0xfe,  0xae,
-  0x90,  0x0f,  0x5c,  0x13,  0x5d,  0x0b,  0x09,  0x74,  0xc7,  0x01,  0xb7,  0xfe,  0x1f,  0x80,  0x16,  0x60,
-  0xfe,  0x34,  0x90,  0xfe,  0xb6,  0x90,  0x0f,  0x5e,  0x13,  0x5f,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,
-  0x0f,  0x5a,  0x13,  0x5b,  0xfe,  0x28,  0x90,  0xfe,  0xaa,  0x90,  0x0f,  0x41,  0x13,  0x42,  0x0f,  0x3e,
-  0x13,  0x57,  0x0b,  0x49,  0x19,  0x37,  0x35,  0x08,  0xa1,  0x2c,  0xfe,  0x50,  0x08,  0xfe,  0x9e,  0xf0,
-  0xfe,  0x64,  0x08,  0xc2,  0x1b,  0x31,  0x35,  0x6b,  0xfe,  0xed,  0x10,  0xa5,  0xfe,  0x88,  0x08,  0xa6,
-  0xfe,  0xa4,  0x08,  0x80,  0xfe,  0x7c,  0x08,  0xcb,  0xfe,  0x82,  0x08,  0x69,  0x8e,  0x02,  0x25,  0x01,
-  0x4a,  0xfe,  0xc9,  0x10,  0x15,  0x19,  0xfe,  0xc9,  0x10,  0x66,  0x09,  0x06,  0xfe,  0x10,  0x12,  0x66,
-  0x09,  0x0c,  0x48,  0x0b,  0x09,  0x0c,  0xfe,  0x66,  0x12,  0xfe,  0x2e,  0x1c,  0xa7,  0x66,  0x09,  0x06,
-  0x48,  0x66,  0x09,  0x0c,  0xfe,  0x52,  0x12,  0xfe,  0x2c,  0x1c,  0xfe,  0xaa,  0xf0,  0xfe,  0x24,  0x09,
-  0xfe,  0xac,  0xf0,  0xfe,  0xc4,  0x08,  0xfe,  0x92,  0x10,  0xfe,  0x34,  0x1c,  0xfe,  0xf3,  0x10,  0xfe,
-  0xad,  0xf0,  0xfe,  0xd0,  0x08,  0x02,  0xfe,  0x32,  0x0a,  0xfe,  0x36,  0x1c,  0xfe,  0xe7,  0x10,  0xfe,
-  0x2b,  0xf0,  0xb0,  0xfe,  0x6b,  0x18,  0x1a,  0xfe,  0x00,  0xfe,  0xdb,  0xc3,  0xfe,  0xd2,  0xf0,  0xb0,
-  0xfe,  0x76,  0x18,  0x1a,  0x18,  0x1b,  0xb0,  0x04,  0xe1,  0x1a,  0x06,  0x1b,  0xb0,  0xa5,  0x77,  0xa6,
-  0x77,  0xfe,  0x34,  0x1c,  0xfe,  0x36,  0x1c,  0xfe,  0xb1,  0x10,  0x8b,  0x59,  0x39,  0x17,  0xa2,  0x01,
-  0x38,  0x12,  0xfe,  0x35,  0x00,  0x33,  0x4b,  0x12,  0x8c,  0x02,  0x4b,  0xfe,  0x74,  0x18,  0x1a,  0xfe,
-  0x00,  0xf8,  0x1b,  0x77,  0x51,  0x1e,  0x01,  0xfe,  0x42,  0x0d,  0xd2,  0x08,  0x1c,  0x07,  0x3f,  0x01,
-  0x6a,  0x22,  0x2d,  0x3c,  0x51,  0x18,  0x02,  0x77,  0xfe,  0x98,  0x80,  0xd8,  0x0c,  0x27,  0xfe,  0x14,
-  0x0a,  0x0b,  0x09,  0x6f,  0xfe,  0x82,  0x12,  0x0b,  0x09,  0x19,  0xfe,  0x66,  0x13,  0x22,  0x60,  0x68,
-  0xc6,  0xfe,  0x83,  0x80,  0xfe,  0xc8,  0x44,  0xfe,  0x2e,  0x13,  0xfe,  0x04,  0x91,  0xfe,  0x86,  0x91,
-  0x62,  0x2d,  0xfe,  0x40,  0x59,  0xfe,  0xc1,  0x59,  0x73,  0xfb,  0x04,  0x5c,  0x2e,  0x5d,  0x0f,  0xaa,
-  0x13,  0x8c,  0x9b,  0x5c,  0x9c,  0x5d,  0x01,  0xb7,  0xab,  0x62,  0x2d,  0x16,  0x60,  0xa0,  0x3e,  0x67,
-  0x57,  0x63,  0x5e,  0x30,  0x5f,  0xe7,  0xfe,  0xe5,  0x55,  0xfe,  0x04,  0xfa,  0x3e,  0xfe,  0x05,  0xfa,
-  0x57,  0x01,  0xf6,  0xfe,  0x36,  0x10,  0x29,  0x0f,  0xaa,  0x0f,  0x8c,  0x63,  0x5e,  0x30,  0x5f,  0xa7,
-  0x0b,  0x09,  0x19,  0x1b,  0xfb,  0x63,  0x41,  0x30,  0x42,  0x0b,  0x09,  0xfe,  0xf7,  0x00,  0x37,  0x04,
-  0x5a,  0x2e,  0x5b,  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0x02,
-  0x77,  0x0b,  0x09,  0x19,  0x1b,  0xfb,  0x0b,  0x09,  0xfe,  0xf7,  0x00,  0x37,  0xfe,  0x3a,  0x55,  0xfe,
-  0x19,  0x81,  0x79,  0xfe,  0x10,  0x90,  0xfe,  0x92,  0x90,  0xfe,  0xd7,  0x10,  0x3d,  0x05,  0xbf,  0x1b,
-  0xfe,  0xcc,  0x08,  0x11,  0xbf,  0xfe,  0x98,  0x80,  0xd8,  0x0c,  0xfe,  0x14,  0x13,  0x04,  0x41,  0x2e,
-  0x42,  0x73,  0xfe,  0xcc,  0x08,  0xfe,  0x0c,  0x58,  0xfe,  0x8d,  0x58,  0x02,  0x77,  0x29,  0x4e,  0xfe,
-  0x19,  0x80,  0xfe,  0xf1,  0x10,  0x0b,  0x09,  0x0c,  0xa3,  0xfe,  0x6c,  0x19,  0xfe,  0x19,  0x41,  0xfe,
-  0x94,  0x10,  0xfe,  0x6c,  0x19,  0x9b,  0x41,  0xfe,  0xed,  0x19,  0x9c,  0x42,  0xfe,  0x0c,  0x51,  0xfe,
-  0x8e,  0x51,  0xfe,  0x6b,  0x18,  0x1a,  0xfe,  0x00,  0xff,  0x2f,  0xfe,  0x7a,  0x10,  0xc3,  0xfe,  0xd2,
-  0xf0,  0xfe,  0xac,  0x0a,  0xfe,  0x76,  0x18,  0x1a,  0x18,  0xce,  0x04,  0xe1,  0x1a,  0x06,  0x83,  0x12,
-  0xfe,  0x16,  0x00,  0x02,  0x4b,  0xfe,  0xd1,  0xf0,  0xfe,  0xe2,  0x0a,  0x17,  0xa1,  0x01,  0x38,  0x12,
-  0xd6,  0xfe,  0x48,  0x10,  0xfe,  0xce,  0xf0,  0xfe,  0xca,  0x0a,  0x12,  0xfe,  0x21,  0x00,  0x02,  0x4b,
-  0xfe,  0xcd,  0xf0,  0xfe,  0xd6,  0x0a,  0x12,  0xfe,  0x22,  0x00,  0x02,  0x4b,  0xfe,  0xcb,  0xf0,  0xfe,
-  0xe2,  0x0a,  0x12,  0xfe,  0x24,  0x00,  0x02,  0x4b,  0xfe,  0xd0,  0xf0,  0xfe,  0xec,  0x0a,  0x12,  0x88,
-  0xd9,  0xfe,  0xcf,  0xf0,  0xfe,  0xf6,  0x0a,  0x12,  0x89,  0xd4,  0xfe,  0xcc,  0xf0,  0xc9,  0xfe,  0x84,
-  0x80,  0xd8,  0x19,  0xfe,  0xd5,  0x12,  0x12,  0xfe,  0x12,  0x00,  0x2c,  0xc9,  0x1f,  0x31,  0xa5,  0x25,
-  0xa6,  0x25,  0x35,  0xf3,  0x2c,  0xfe,  0x1a,  0x0b,  0x1f,  0x31,  0x80,  0xfe,  0x36,  0x0b,  0x69,  0x8e,
-  0xa5,  0xfe,  0xf0,  0x07,  0xa6,  0xfe,  0xf0,  0x07,  0x02,  0x25,  0x01,  0x4a,  0xfe,  0xdb,  0x10,  0x11,
-  0xfe,  0xe8,  0x00,  0x8b,  0x81,  0x6d,  0xfe,  0x89,  0xf0,  0x25,  0x23,  0x28,  0xfe,  0xe9,  0x09,  0x01,
-  0x0a,  0x81,  0x6d,  0x20,  0x25,  0x23,  0x28,  0x93,  0x33,  0xfe,  0x6e,  0x0b,  0x1f,  0x31,  0x02,  0xfe,
-  0x62,  0x0b,  0xc2,  0x48,  0x12,  0xfe,  0x42,  0x00,  0x02,  0x4b,  0x9f,  0x06,  0xfe,  0x81,  0x49,  0xfe,
-  0xcc,  0x12,  0x0b,  0x09,  0x0c,  0xfe,  0x5a,  0x13,  0x12,  0x00,  0x58,  0x0c,  0xfe,  0x6a,  0x12,  0x58,
-  0xfe,  0x28,  0x00,  0x27,  0xfe,  0xb4,  0x0c,  0x0e,  0x7c,  0x01,  0x14,  0x05,  0x00,  0x83,  0x34,  0xfe,
-  0x28,  0x00,  0x02,  0xfe,  0xb4,  0x0c,  0x01,  0x95,  0x01,  0x98,  0x0e,  0xbd,  0x01,  0xfe,  0x10,  0x0e,
-  0xaf,  0x08,  0x3b,  0x07,  0x99,  0x01,  0x40,  0x11,  0x43,  0x08,  0x1c,  0x07,  0x3f,  0x01,  0x76,  0x02,
-  0x26,  0x12,  0xfe,  0x44,  0x00,  0x58,  0x0c,  0xa3,  0x34,  0x0c,  0xfe,  0xc0,  0x10,  0x01,  0xb6,  0x34,
-  0x0c,  0xfe,  0xb6,  0x10,  0x01,  0xb6,  0xfe,  0x19,  0x82,  0xfe,  0x34,  0x46,  0xfe,  0x0a,  0x13,  0x34,
-  0x0c,  0x12,  0xfe,  0x43,  0x00,  0xfe,  0xa2,  0x10,  0x0b,  0x49,  0x0c,  0x37,  0x01,  0x95,  0x01,  0x98,
-  0xaf,  0x08,  0x3b,  0x07,  0x99,  0x01,  0x40,  0x11,  0x43,  0x08,  0x1c,  0x07,  0x3f,  0x01,  0x76,  0x51,
-  0x0c,  0xaf,  0x1d,  0xca,  0x02,  0xfe,  0x48,  0x03,  0x0b,  0x09,  0x0c,  0xce,  0x34,  0x0c,  0x12,  0x00,
-  0xfe,  0x54,  0x10,  0x66,  0x09,  0x1e,  0xfe,  0x50,  0x12,  0x0b,  0x09,  0x1e,  0xfe,  0x48,  0x13,  0xfe,
-  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x72,  0x0c,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x78,
-  0x0c,  0x0b,  0x49,  0x1e,  0x37,  0xfe,  0x95,  0x10,  0x12,  0xfe,  0x15,  0x00,  0xfe,  0x04,  0xe6,  0x0c,
-  0x79,  0xfe,  0x26,  0x10,  0x12,  0xfe,  0x13,  0x00,  0xd4,  0x12,  0xfe,  0x47,  0x00,  0xa4,  0x12,  0xfe,
-  0x41,  0x00,  0x9d,  0x12,  0xfe,  0x24,  0x00,  0x04,  0x7b,  0x2a,  0x27,  0xeb,  0x79,  0xfe,  0x04,  0xe6,
-  0x1e,  0xfe,  0x9d,  0x41,  0xfe,  0x1c,  0x42,  0xaf,  0x01,  0xd7,  0x02,  0x26,  0xd5,  0x17,  0x0c,  0x47,
-  0xf2,  0xdf,  0x17,  0xfe,  0x31,  0x00,  0x47,  0xba,  0x01,  0xfe,  0x1c,  0x0f,  0x02,  0xfc,  0x1d,  0xfe,
-  0x06,  0xec,  0xf7,  0x85,  0x34,  0x36,  0xbc,  0x2f,  0x1d,  0xfe,  0x06,  0xea,  0xf7,  0xfe,  0x47,  0x4b,
-  0x7a,  0xfe,  0x75,  0x57,  0x04,  0x55,  0xfe,  0x98,  0x56,  0xfe,  0x28,  0x12,  0x0e,  0x7c,  0xfe,  0xfa,
-  0x14,  0x4e,  0xe5,  0x0e,  0xbd,  0xfe,  0xf0,  0x14,  0xfe,  0x49,  0x54,  0x91,  0xfe,  0x28,  0x0d,  0x0e,
-  0x1c,  0xfe,  0xe4,  0x14,  0xfe,  0x44,  0x48,  0x02,  0xfe,  0x48,  0x03,  0x0e,  0x55,  0xfe,  0xc8,  0x14,
-  0x85,  0x34,  0x36,  0xbc,  0x2f,  0x1d,  0xfe,  0xce,  0x47,  0xfe,  0xbd,  0x13,  0x02,  0x26,  0x22,  0x2b,
-  0x05,  0x10,  0xfe,  0x78,  0x12,  0x29,  0x16,  0x54,  0x16,  0xa9,  0x22,  0x43,  0x4e,  0x47,  0x43,  0xc2,
-  0xfe,  0x0c,  0x13,  0xfe,  0xbc,  0xf0,  0xfe,  0xc4,  0x0d,  0x08,  0x06,  0x16,  0x54,  0x01,  0xfe,  0xd0,
-  0x15,  0x04,  0xfe,  0x38,  0x01,  0x2e,  0xfe,  0x3a,  0x01,  0x73,  0xfe,  0xc8,  0x0d,  0x04,  0xfe,  0x38,
-  0x01,  0x1a,  0xfe,  0xf0,  0xff,  0x0f,  0xfe,  0x60,  0x01,  0x04,  0xfe,  0x3a,  0x01,  0x0f,  0xfe,  0x62,
-  0x01,  0x21,  0x06,  0x16,  0x43,  0xfe,  0x04,  0xec,  0x2b,  0x08,  0x2b,  0x07,  0x3a,  0x1d,  0x01,  0x40,
-  0x7f,  0xfe,  0x05,  0xf6,  0xfe,  0x34,  0x01,  0x01,  0xfe,  0x40,  0x16,  0x11,  0x43,  0xca,  0x08,  0x06,
-  0x03,  0x29,  0x03,  0x22,  0x54,  0xfe,  0xf7,  0x12,  0x22,  0xa9,  0x68,  0x16,  0xa9,  0x05,  0xa1,  0xfe,
-  0x93,  0x13,  0xfe,  0x24,  0x1c,  0x17,  0x18,  0x47,  0xf2,  0xdf,  0xfe,  0xd9,  0x10,  0x94,  0xfe,  0x03,
-  0xdc,  0xfe,  0x73,  0x57,  0xfe,  0x80,  0x5d,  0x03,  0x94,  0xfe,  0x03,  0xdc,  0x29,  0xfe,  0x70,  0x57,
-  0xfe,  0x33,  0x54,  0xfe,  0x3b,  0x54,  0xfe,  0x80,  0x5d,  0x03,  0xfe,  0x03,  0x57,  0x94,  0x29,  0xfe,
-  0x00,  0xcc,  0x03,  0xfe,  0x03,  0x57,  0x94,  0x7d,  0x03,  0x01,  0xfe,  0x70,  0x16,  0x3d,  0x05,  0x43,
-  0xfe,  0x0a,  0x13,  0x08,  0x1c,  0x07,  0x3f,  0xd4,  0x01,  0x95,  0x01,  0x98,  0x08,  0x3b,  0x07,  0x99,
-  0x01,  0x40,  0x11,  0xfe,  0xe9,  0x00,  0x0b,  0x09,  0x89,  0xfe,  0x52,  0x13,  0x01,  0xfe,  0x02,  0x16,
-  0xfe,  0x1e,  0x1c,  0xfe,  0x14,  0x90,  0x0f,  0xfe,  0x64,  0x01,  0xfe,  0x16,  0x90,  0x0f,  0xfe,  0x66,
-  0x01,  0x0b,  0x09,  0x74,  0x8d,  0xfe,  0x03,  0x80,  0x6b,  0x3c,  0x11,  0x75,  0x08,  0x2b,  0x07,  0x3a,
-  0x1d,  0x92,  0x01,  0x6a,  0xfe,  0x62,  0x08,  0x68,  0x3c,  0x11,  0x75,  0x08,  0x2b,  0x07,  0x3a,  0x1d,
-  0x92,  0x01,  0x6a,  0x62,  0x2d,  0x11,  0x75,  0x08,  0x2b,  0x07,  0x3a,  0x1d,  0x92,  0x01,  0x76,  0x03,
-  0xfe,  0x08,  0x1c,  0x04,  0xfe,  0xac,  0x00,  0xfe,  0x06,  0x58,  0x04,  0xfe,  0xae,  0x00,  0xfe,  0x07,
-  0x58,  0x04,  0xfe,  0xb0,  0x00,  0xfe,  0x08,  0x58,  0x04,  0xfe,  0xb2,  0x00,  0xfe,  0x09,  0x58,  0xfe,
-  0x0a,  0x1c,  0x21,  0x87,  0x16,  0xf7,  0x29,  0x0f,  0x52,  0x0f,  0x4d,  0x21,  0x10,  0x16,  0x2b,  0x16,
-  0x3a,  0x56,  0x9f,  0xd6,  0x08,  0x2b,  0x07,  0x3a,  0x1d,  0x01,  0x76,  0x7f,  0x11,  0x75,  0xfe,  0x14,
-  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0xf6,  0x0e,  0xd5,  0x8b,  0xfe,  0x14,  0x1c,  0xfe,  0x10,  0x1c,  0xfe,
-  0x18,  0x1c,  0x03,  0x1d,  0xfe,  0x0c,  0x14,  0x85,  0xfe,  0x07,  0xe6,  0x36,  0xfe,  0xce,  0x47,  0xfe,
-  0xf5,  0x13,  0x03,  0x01,  0xb6,  0x0e,  0x3b,  0x01,  0x14,  0x05,  0x10,  0xd3,  0x0e,  0x1c,  0x01,  0x14,
-  0x05,  0x10,  0xdb,  0xfe,  0x44,  0x58,  0x3c,  0xfe,  0x01,  0xec,  0xba,  0xfe,  0x9e,  0x40,  0xfe,  0x9d,
-  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x1e,  0x9e,  0x2d,  0x01,  0xd7,  0xfe,  0xc9,  0x10,  0x03,  0x35,  0x81,
-  0x6d,  0x23,  0x28,  0xb1,  0x05,  0x1e,  0xfe,  0x48,  0x12,  0x05,  0x0c,  0xfe,  0x4c,  0x12,  0x05,  0x18,
-  0x38,  0x05,  0xcc,  0x1b,  0xfe,  0xc0,  0x10,  0x05,  0xfe,  0x23,  0x00,  0x1b,  0xfe,  0xcc,  0x10,  0x05,
-  0x06,  0x1b,  0xfe,  0x2a,  0x11,  0x05,  0x19,  0xfe,  0x12,  0x12,  0x05,  0x00,  0x1b,  0x25,  0x17,  0xcc,
-  0x01,  0x38,  0xc4,  0x39,  0x01,  0x0a,  0x80,  0x4a,  0x03,  0x39,  0x11,  0xfe,  0xcc,  0x00,  0x02,  0x26,
-  0x39,  0x3d,  0x05,  0xbf,  0xfe,  0xe3,  0x13,  0x63,  0x41,  0x30,  0x42,  0x73,  0xfe,  0x7e,  0x10,  0x0b,
-  0x09,  0x6f,  0xfe,  0x72,  0x12,  0xa0,  0x3e,  0x67,  0x57,  0xe7,  0xfe,  0xe5,  0x55,  0x91,  0xfe,  0x48,
-  0x10,  0x22,  0x60,  0xfe,  0x26,  0x13,  0x04,  0xaa,  0x2e,  0x8c,  0x73,  0xfe,  0x98,  0x0c,  0x0f,  0x5c,
-  0x13,  0x5d,  0x29,  0x0f,  0xaa,  0x0f,  0x8c,  0x01,  0xb7,  0x21,  0x87,  0x6b,  0x16,  0x60,  0x01,  0xf6,
-  0xa0,  0x3e,  0x67,  0x57,  0xfe,  0x04,  0x55,  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,  0x3e,  0xfe,  0x05,
-  0xfa,  0x57,  0xfe,  0x91,  0x10,  0x04,  0x5e,  0x2e,  0x5f,  0xfe,  0x40,  0x56,  0xfe,  0xe1,  0x56,  0x0f,
-  0x5e,  0x13,  0x5f,  0xd1,  0xa0,  0x3e,  0x67,  0x57,  0xe7,  0xfe,  0xe5,  0x55,  0x04,  0x5a,  0x2e,  0x5b,
-  0xfe,  0x00,  0x56,  0xfe,  0xa1,  0x56,  0x0f,  0x5a,  0x13,  0x5b,  0x0b,  0x09,  0x6f,  0xfe,  0x1e,  0x12,
-  0x22,  0x60,  0xfe,  0x1f,  0x40,  0x04,  0x5c,  0x2e,  0x5d,  0xfe,  0x2c,  0x50,  0xfe,  0xae,  0x50,  0x04,
-  0x5e,  0x2e,  0x5f,  0xfe,  0x34,  0x50,  0xfe,  0xb6,  0x50,  0x04,  0x5a,  0x2e,  0x5b,  0xfe,  0x08,  0x50,
-  0xfe,  0x8a,  0x50,  0x04,  0x41,  0x2e,  0x42,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,  0x02,  0x97,  0x21,
-  0x06,  0x16,  0xf1,  0x02,  0x78,  0x39,  0x01,  0x0a,  0x20,  0x4c,  0x23,  0x28,  0xb1,  0x05,  0x06,  0x27,
-  0x4c,  0x3d,  0x05,  0xbf,  0x27,  0x78,  0x01,  0xee,  0x1a,  0x4f,  0x1b,  0x4c,  0x0b,  0x09,  0x0c,  0xde,
-  0x63,  0x41,  0x30,  0x42,  0xfe,  0x0a,  0x55,  0x2f,  0xfe,  0x8b,  0x55,  0x9b,  0x41,  0x9c,  0x42,  0xfe,
-  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0x02,  0x78,  0xfe,  0x19,  0x81,  0xfe,  0x0a,  0x45,  0xfe,  0x19,  0x41,
-  0x02,  0x78,  0x39,  0x01,  0x0a,  0x20,  0xfe,  0xc2,  0x0f,  0x23,  0x28,  0xfe,  0xe9,  0x09,  0x58,  0x18,
-  0xfe,  0x94,  0x12,  0x58,  0x0c,  0x50,  0x02,  0x4c,  0x2c,  0xfe,  0x4a,  0x11,  0x1f,  0x31,  0x20,  0xfe,
-  0xc2,  0x0f,  0x23,  0x28,  0x93,  0x05,  0x18,  0x27,  0x4c,  0x01,  0x0a,  0x20,  0xfe,  0xc2,  0x0f,  0x23,
-  0x28,  0xfe,  0xe8,  0x09,  0x56,  0x04,  0xfe,  0x9c,  0x00,  0x2a,  0x2f,  0xfe,  0xbb,  0x45,  0x58,  0x00,
-  0x48,  0x34,  0x06,  0x9f,  0x4f,  0xfe,  0xc0,  0x14,  0xfe,  0xf8,  0x14,  0xa8,  0x3d,  0x05,  0xbe,  0xfe,
-  0x16,  0x13,  0x04,  0xf4,  0x2a,  0xce,  0x04,  0x4d,  0x2a,  0x2f,  0x59,  0x02,  0x78,  0xfe,  0xc0,  0x5d,
-  0xfe,  0xe4,  0x14,  0xfe,  0x03,  0x17,  0x04,  0x52,  0xb9,  0x0f,  0x52,  0x59,  0x39,  0x01,  0x0a,  0x24,
-  0x97,  0x01,  0xfe,  0xf0,  0x13,  0x02,  0x97,  0x2c,  0xfe,  0xd4,  0x11,  0x1f,  0x31,  0x20,  0x4c,  0x23,
-  0x28,  0x93,  0x05,  0x06,  0x27,  0x4c,  0xfe,  0xf6,  0x14,  0xfe,  0x42,  0x58,  0xfe,  0x70,  0x14,  0xfe,
-  0x92,  0x14,  0xa8,  0xfe,  0x4a,  0xf4,  0x0c,  0x1b,  0x4c,  0xfe,  0x4a,  0xf4,  0x06,  0xd2,  0x3d,  0x05,
-  0xbe,  0xc7,  0x02,  0x78,  0x04,  0x4d,  0xb9,  0x0f,  0x4d,  0x59,  0x39,  0x01,  0x0a,  0x24,  0x97,  0x01,
-  0xfe,  0x1e,  0x14,  0x02,  0x97,  0x24,  0xfe,  0x3c,  0x12,  0x71,  0xef,  0x71,  0x03,  0x33,  0x8d,  0x69,
-  0x8d,  0x59,  0x39,  0x01,  0x0a,  0xfe,  0xe3,  0x10,  0x08,  0x61,  0xff,  0x02,  0x00,  0x57,  0x64,  0x7e,
-  0x1a,  0xfe,  0xff,  0x7f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x08,  0x61,  0xff,  0x02,  0x00,
-  0x57,  0x64,  0x7e,  0x1a,  0x4f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x08,  0x61,  0xff,  0x02,
-  0x00,  0x57,  0x64,  0x7e,  0x03,  0x08,  0x61,  0xff,  0x02,  0x00,  0x57,  0x64,  0x7e,  0xfe,  0x0b,  0x58,
-  0x03,  0x0e,  0x52,  0x01,  0x9a,  0x0e,  0x4d,  0x01,  0x9a,  0x03,  0xc6,  0x1a,  0x10,  0xff,  0x03,  0x00,
-  0x54,  0xfe,  0x00,  0xf4,  0x19,  0x64,  0xfe,  0x00,  0x7d,  0xfe,  0x01,  0x7d,  0xfe,  0x02,  0x7d,  0xfe,
-  0x03,  0x7c,  0x62,  0x2d,  0x0f,  0x5a,  0x13,  0x5b,  0x9b,  0x5e,  0x9c,  0x5f,  0x03,  0xfe,  0x62,  0x18,
-  0xfe,  0x82,  0x5a,  0xfe,  0xe1,  0x1a,  0xb4,  0xfe,  0x02,  0x58,  0x03,  0x01,  0xfe,  0x60,  0x18,  0xfe,
-  0x42,  0x48,  0x79,  0x56,  0x7a,  0x01,  0x0a,  0x20,  0xfe,  0xe8,  0x13,  0x23,  0x28,  0xfe,  0xe9,  0x09,
-  0xfe,  0xc1,  0x59,  0x01,  0x0a,  0x20,  0xfe,  0xe8,  0x13,  0x23,  0x28,  0xfe,  0xe8,  0x0a,  0x04,  0xf4,
-  0x2a,  0xfe,  0xc2,  0x12,  0x29,  0xad,  0x1e,  0xde,  0x58,  0xcd,  0x72,  0xfe,  0x38,  0x13,  0x50,  0x08,
-  0x06,  0x07,  0xcd,  0x9f,  0xfe,  0x00,  0x10,  0xfe,  0x78,  0x10,  0xff,  0x02,  0x83,  0x55,  0xa4,  0xff,
-  0x02,  0x83,  0x55,  0xad,  0x18,  0xfe,  0x12,  0x13,  0x70,  0xfe,  0x30,  0x00,  0x91,  0xf0,  0x07,  0x84,
-  0x08,  0x06,  0xfe,  0x56,  0x10,  0xad,  0x0c,  0xfe,  0x16,  0x13,  0x70,  0xfe,  0x64,  0x00,  0x91,  0xf0,
-  0x0e,  0xfe,  0x64,  0x00,  0x07,  0x88,  0x08,  0x06,  0xfe,  0x28,  0x10,  0xad,  0x06,  0xfe,  0x5e,  0x13,
-  0x70,  0xfe,  0xc8,  0x00,  0x91,  0xf0,  0x0e,  0xfe,  0xc8,  0x00,  0x07,  0x54,  0x08,  0x06,  0xd1,  0x70,
-  0xfe,  0x90,  0x01,  0xea,  0xfe,  0x9e,  0x13,  0x7a,  0xa7,  0xfe,  0x43,  0xf4,  0xa9,  0xfe,  0x56,  0xf0,
-  0xfe,  0xb0,  0x13,  0xfe,  0x04,  0xf4,  0x61,  0xfe,  0x43,  0xf4,  0x88,  0xfe,  0xf3,  0x10,  0xac,  0x01,
-  0xfe,  0x7a,  0x12,  0x1a,  0x4f,  0xd3,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x87,  0xea,  0xfe,  0xe2,
-  0x13,  0x7a,  0xfe,  0x14,  0x10,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x19,  0xea,  0xfe,  0xe2,  0x13,
-  0xc8,  0x19,  0x9d,  0x56,  0x7a,  0x08,  0x06,  0xfe,  0xb4,  0x56,  0xfe,  0xc3,  0x58,  0x03,  0x56,  0x08,
-  0x0c,  0x03,  0x15,  0x06,  0x01,  0x0a,  0x24,  0xdc,  0x15,  0x0c,  0x01,  0x0a,  0x24,  0xdc,  0x15,  0x18,
-  0x01,  0x0a,  0x24,  0xdc,  0x71,  0xfe,  0x89,  0x49,  0x01,  0x0a,  0x03,  0x15,  0x06,  0x01,  0x0a,  0x24,
-  0x90,  0x15,  0x18,  0x01,  0x0a,  0x24,  0x90,  0x15,  0x06,  0x01,  0x0a,  0x24,  0x90,  0xfe,  0x89,  0x49,
-  0x01,  0x0a,  0x24,  0x90,  0x71,  0xfe,  0x89,  0x4a,  0x01,  0x0a,  0x03,  0x56,  0x03,  0x22,  0xe2,  0x05,
-  0x06,  0xfe,  0x44,  0x13,  0xab,  0x16,  0xe2,  0xfe,  0x49,  0xf4,  0x00,  0x50,  0x71,  0xc4,  0x59,  0xfe,
-  0x01,  0xec,  0xfe,  0x27,  0x01,  0xef,  0x01,  0x0a,  0x3d,  0x05,  0xfe,  0xe3,  0x00,  0xfe,  0x20,  0x13,
-  0x20,  0xfe,  0xa0,  0x14,  0x29,  0x16,  0xf1,  0x01,  0x4a,  0x22,  0xf1,  0x05,  0x06,  0x48,  0x0b,  0x49,
-  0x06,  0x37,  0x03,  0x0f,  0x53,  0x13,  0x8a,  0xfe,  0x43,  0x58,  0x01,  0x14,  0x05,  0x10,  0xfe,  0x1e,
-  0x12,  0x45,  0xe6,  0x8f,  0x01,  0x44,  0xfe,  0x90,  0x4d,  0xe0,  0x10,  0xfe,  0xc5,  0x59,  0x01,  0x44,
-  0xfe,  0x8d,  0x56,  0xb4,  0x45,  0x03,  0x45,  0x30,  0x8a,  0x01,  0x14,  0x45,  0x8f,  0x01,  0x44,  0xe4,
-  0x10,  0xe0,  0x10,  0x30,  0x53,  0x70,  0x1c,  0x83,  0x0e,  0x55,  0x01,  0xc0,  0x03,  0x0f,  0x53,  0x13,
-  0x8a,  0xfe,  0xc3,  0x58,  0x01,  0x14,  0x05,  0x10,  0xfe,  0x1a,  0x12,  0x45,  0xe6,  0x8f,  0x01,  0x44,
-  0xe4,  0x10,  0xfe,  0x80,  0x4d,  0xfe,  0xc5,  0x59,  0x01,  0x44,  0x45,  0x03,  0x45,  0x30,  0x53,  0x01,
-  0x14,  0x45,  0x8f,  0x01,  0x44,  0xe4,  0x10,  0xe0,  0x10,  0x30,  0x53,  0x70,  0x1c,  0x83,  0x0e,  0x55,
-  0x01,  0xc0,  0x03,  0x0f,  0x53,  0x13,  0x8a,  0xfe,  0x43,  0x58,  0x01,  0x14,  0xfe,  0x42,  0x48,  0x8f,
-  0x01,  0x44,  0xfe,  0xc0,  0x5a,  0xac,  0xfe,  0x00,  0xcd,  0xfe,  0x01,  0xcc,  0xfe,  0x4a,  0x46,  0xde,
-  0x94,  0x7d,  0x05,  0x10,  0xfe,  0x2e,  0x13,  0x67,  0x53,  0xfe,  0x4d,  0xf4,  0x1c,  0xfe,  0x1c,  0x13,
-  0x0e,  0x55,  0x01,  0x9a,  0xa7,  0xfe,  0x40,  0x4c,  0xfe,  0xc5,  0x58,  0x01,  0x44,  0xfe,  0x00,  0x07,
-  0x7d,  0x05,  0x10,  0x83,  0x67,  0x8a,  0xfe,  0x05,  0x57,  0xfe,  0x08,  0x10,  0xfe,  0x45,  0x58,  0x01,
-  0x44,  0xfe,  0x8d,  0x56,  0xb4,  0xfe,  0x80,  0x4c,  0xfe,  0x05,  0x17,  0x03,  0x07,  0x10,  0x6e,  0x65,
-  0xfe,  0x60,  0x01,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x24,  0x1c,  0xdd,  0x36,  0x96,  0xfe,
-  0xe4,  0x15,  0x01,  0xfe,  0xea,  0x16,  0xfe,  0x0c,  0x13,  0x86,  0x36,  0x65,  0xfe,  0x2c,  0x01,  0xfe,
-  0x2f,  0x19,  0x03,  0xb5,  0x27,  0xfe,  0xd4,  0x15,  0xfe,  0xda,  0x10,  0x07,  0x10,  0x6e,  0x04,  0xfe,
-  0x64,  0x01,  0xfe,  0x00,  0xf4,  0x19,  0xfe,  0x18,  0x58,  0x04,  0xfe,  0x66,  0x01,  0xfe,  0x19,  0x58,
-  0x86,  0x19,  0xfe,  0x3c,  0x90,  0xfe,  0x30,  0xf4,  0x06,  0xfe,  0x3c,  0x50,  0x65,  0xfe,  0x38,  0x00,
-  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0x19,  0x96,  0xfe,  0x2e,  0x16,  0xfe,  0xb6,  0x14,  0x2f,  0x03,
-  0xb5,  0x27,  0xfe,  0x06,  0x16,  0xfe,  0x9c,  0x10,  0x07,  0x10,  0x6e,  0xb4,  0xfe,  0x18,  0xdf,  0xfe,
-  0x19,  0xdf,  0xdd,  0x3e,  0x96,  0xfe,  0x50,  0x16,  0xfe,  0x94,  0x14,  0xfe,  0x10,  0x13,  0x86,  0x3e,
-  0x65,  0x1e,  0xfe,  0xaf,  0x19,  0xfe,  0x98,  0xe7,  0x00,  0x03,  0xb5,  0x27,  0xfe,  0x44,  0x16,  0xfe,
-  0x6c,  0x10,  0x07,  0x10,  0x6e,  0xfe,  0x30,  0xbc,  0xfe,  0xb2,  0xbc,  0x86,  0xda,  0x65,  0x1e,  0xfe,
-  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0xda,  0x96,  0xfe,  0x88,  0x16,  0xfe,  0x5c,  0x14,  0x2f,  0x03,  0xb5,
-  0x27,  0xfe,  0x74,  0x16,  0xfe,  0x42,  0x10,  0xfe,  0x02,  0xf6,  0x10,  0x6e,  0xfe,  0x18,  0xfe,  0x5c,
-  0xfe,  0x19,  0xfe,  0x5d,  0xc6,  0xdd,  0x74,  0x96,  0xfe,  0xae,  0x16,  0xfe,  0x36,  0x14,  0xfe,  0x1c,
-  0x13,  0x86,  0x74,  0x4e,  0xfe,  0x83,  0x58,  0xfe,  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x10,  0xfe,  0x81,
-  0xe7,  0x10,  0x11,  0xfe,  0xdd,  0x00,  0x62,  0x2d,  0x03,  0x62,  0x2d,  0xfe,  0x12,  0x45,  0x27,  0xfe,
-  0x9e,  0x16,  0x17,  0x06,  0x47,  0xf2,  0xdf,  0x02,  0x26,  0xfe,  0x39,  0xf0,  0xfe,  0xf2,  0x16,  0x29,
-  0x03,  0xfe,  0x7e,  0x18,  0x1a,  0x18,  0x82,  0x08,  0x0d,  0x03,  0x6e,  0x04,  0xe1,  0x1a,  0x06,  0xfe,
-  0xef,  0x12,  0xfe,  0xe1,  0x10,  0x1d,  0x0e,  0x1c,  0x01,  0x14,  0x05,  0x10,  0x48,  0x3c,  0xfe,  0x78,
-  0x14,  0xfe,  0x34,  0x12,  0x4f,  0x85,  0x34,  0x36,  0xbc,  0xfe,  0xe9,  0x13,  0x1d,  0x0e,  0x3b,  0x01,
-  0x14,  0x05,  0x10,  0x48,  0x3c,  0x90,  0xe3,  0x4f,  0x85,  0x34,  0x36,  0xbc,  0xfe,  0xe9,  0x13,  0x07,
-  0x0c,  0x03,  0xfe,  0x9c,  0xe7,  0x0c,  0x12,  0xfe,  0x15,  0x00,  0x92,  0x9e,  0x2d,  0x01,  0xd7,  0x07,
-  0x06,  0x03,  0x0b,  0x49,  0x36,  0x37,  0x08,  0x3b,  0x07,  0x99,  0x01,  0x40,  0x11,  0x43,  0x08,  0x1c,
-  0x07,  0x3f,  0x01,  0x76,  0x07,  0x06,  0x03,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,  0x63,  0xf5,  0x30,
-  0x75,  0xfe,  0x48,  0x55,  0x2f,  0xfe,  0xc9,  0x55,  0x03,  0x22,  0xbb,  0x6b,  0x16,  0xbb,  0x03,  0x0e,
-  0xbd,  0x01,  0x14,  0xe5,  0x0e,  0x7c,  0x01,  0x14,  0xfe,  0x49,  0x44,  0x27,  0xfe,  0xe8,  0x17,  0x0e,
-  0x1c,  0x01,  0x14,  0x05,  0x10,  0x48,  0x0e,  0x55,  0x01,  0xc0,  0x0e,  0x7c,  0x01,  0x14,  0x6b,  0x7d,
-  0x03,  0xfe,  0x40,  0x5e,  0xfe,  0xe2,  0x08,  0xfe,  0xc0,  0x4c,  0x22,  0x3a,  0x05,  0x10,  0xfe,  0x52,
-  0x12,  0x3c,  0x05,  0x00,  0xfe,  0x18,  0x12,  0xfe,  0xe1,  0x18,  0xfe,  0x19,  0xf4,  0xfe,  0x7f,  0x00,
-  0xfe,  0x10,  0x13,  0xfe,  0xe2,  0x08,  0x6b,  0x3c,  0x3d,  0x05,  0x75,  0xa3,  0xfe,  0x82,  0x48,  0xfe,
-  0x01,  0x80,  0xfe,  0xd7,  0x10,  0xfe,  0xc4,  0x48,  0x08,  0x2b,  0x07,  0x3a,  0xfe,  0x40,  0x5f,  0x1d,
-  0x01,  0x40,  0x11,  0xfe,  0xdd,  0x00,  0xfe,  0x14,  0x46,  0x08,  0x2b,  0x07,  0x3a,  0x01,  0x40,  0x11,
-  0xfe,  0xdd,  0x00,  0xfe,  0x40,  0x4a,  0x68,  0xfe,  0x06,  0x17,  0xfe,  0x01,  0x07,  0xfe,  0x82,  0x48,
-  0xfe,  0x04,  0x17,  0x03,  0xe9,  0x18,  0x72,  0xfe,  0x70,  0x18,  0x04,  0xfe,  0x90,  0x00,  0xfe,  0x3a,
-  0x45,  0xfe,  0x2c,  0x10,  0xe9,  0xcc,  0x72,  0xfe,  0x82,  0x18,  0x04,  0xfe,  0x92,  0x00,  0xc5,  0x1e,
-  0xd9,  0xe9,  0xfe,  0x0b,  0x00,  0x72,  0xfe,  0x94,  0x18,  0x04,  0xfe,  0x94,  0x00,  0xc5,  0x19,  0xfe,
-  0x08,  0x10,  0x04,  0xfe,  0x96,  0x00,  0xc5,  0x84,  0xfe,  0x4e,  0x45,  0xd2,  0xfe,  0x0a,  0x45,  0xff,
-  0x04,  0x68,  0x54,  0xfe,  0xf1,  0x10,  0x1a,  0x87,  0x03,  0x05,  0xa1,  0xfe,  0x5a,  0xf0,  0xfe,  0xc0,
-  0x18,  0x21,  0xfe,  0x09,  0x00,  0xfe,  0x34,  0x10,  0x05,  0x1e,  0xfe,  0x5a,  0xf0,  0xfe,  0xce,  0x18,
-  0x21,  0xcd,  0xfe,  0x26,  0x10,  0x05,  0x18,  0x82,  0x21,  0x84,  0xd9,  0x05,  0x0c,  0x82,  0x21,  0x88,
-  0xfe,  0x0e,  0x10,  0x05,  0x06,  0x82,  0x21,  0x54,  0xc4,  0xab,  0x03,  0x17,  0xfe,  0x09,  0x00,  0x01,
-  0x38,  0x2c,  0xfe,  0xfe,  0x18,  0x04,  0x6d,  0xac,  0x03,  0x1f,  0xfe,  0x16,  0x19,  0xfe,  0x14,  0xf0,
-  0x0a,  0x2c,  0xfe,  0x12,  0x19,  0x03,  0xff,  0x34,  0x00,  0x00,};
+  0x00,  0x00,  0x00,  0xf2,  0x00,  0xf0,  0x00,  0x16,  0x00,  0xfc,  0x48,  0xe4,  0x01,  0x00,  0x18,  0xe4,
+  0x00,  0xf6,  0x01,  0xf6,  0x18,  0x80,  0x48,  0x19,  0x02,  0x00,  0xff,  0xff,  0x03,  0xf6,  0x00,  0xfa,
+  0xff,  0x00,  0x82,  0xe7,  0x01,  0xfa,  0x9e,  0xe7,  0x09,  0xe7,  0x3a,  0x0e,  0x00,  0xea,  0x01,  0xe6,
+  0x55,  0xf0,  0x03,  0x00,  0x08,  0x00,  0x18,  0xf4,  0x3e,  0x01,  0x3e,  0x57,  0x04,  0x00,  0x85,  0xf0,
+  0x00,  0xe6,  0x00,  0xec,  0x1e,  0xf0,  0x32,  0xf0,  0x34,  0x19,  0x86,  0xf0,  0xd0,  0x01,  0xd5,  0xf0,
+  0xde,  0x0c,  0x98,  0x57,  0xbc,  0x00,  0x0c,  0x1c,  0x0e,  0x13,  0x38,  0x54,  0xb1,  0xf0,  0xb4,  0x00,
+  0x01,  0xfc,  0x03,  0xfc,  0xd8,  0x0c,  0x00,  0x57,  0x01,  0xf0,  0x02,  0x13,  0x03,  0xe6,  0x10,  0x00,
+  0x18,  0x40,  0x3e,  0x1c,  0x6c,  0x01,  0x6e,  0x01,  0xbd,  0x00,  0xe0,  0x00,  0x02,  0x48,  0x02,  0x80,
+  0x08,  0x12,  0x30,  0xe4,  0x3c,  0x00,  0x4e,  0x01,  0x64,  0x12,  0x80,  0x00,  0x9c,  0x15,  0xbb,  0x00,
+  0x00,  0x4e,  0x01,  0x01,  0x01,  0xea,  0x04,  0x12,  0x9e,  0x0f,  0xb6,  0x00,  0xb9,  0x54,  0xe2,  0x0f,
+  0x00,  0x80,  0x06,  0xf7,  0x10,  0x44,  0x24,  0x01,  0x28,  0x01,  0x32,  0x00,  0x3c,  0x01,  0x3c,  0x56,
+  0x3e,  0x00,  0x4b,  0xe4,  0x4c,  0x1c,  0x68,  0x01,  0x6a,  0x01,  0x70,  0x01,  0x72,  0x01,  0x74,  0x01,
+  0x76,  0x01,  0x78,  0x01,  0xe2,  0x0c,  0x00,  0x01,  0x02,  0xee,  0x02,  0xfc,  0x03,  0x58,  0x03,  0xf7,
+  0x04,  0x80,  0x05,  0xfc,  0x08,  0x44,  0x09,  0xf0,  0x0f,  0x00,  0x1b,  0x80,  0x20,  0x01,  0x38,  0x1c,
+  0x40,  0x00,  0x40,  0x15,  0x4b,  0xf4,  0x4e,  0x1c,  0x5b,  0xf0,  0x5d,  0xf0,  0xaa,  0x00,  0xbb,  0x55,
+  0xbe,  0x00,  0xc0,  0x00,  0xe0,  0x08,  0xe0,  0x14,  0xec,  0x0f,  0x00,  0x4c,  0x00,  0xdc,  0x02,  0x4a,
+  0x05,  0x00,  0x05,  0xf0,  0x05,  0xf8,  0x06,  0x13,  0x08,  0x13,  0x0c,  0x00,  0x0e,  0x47,  0x0e,  0xf7,
+  0x19,  0x00,  0x20,  0x00,  0x2a,  0x01,  0x30,  0x0e,  0x32,  0x1c,  0x36,  0x00,  0x45,  0x5a,  0x59,  0xf0,
+  0x62,  0x0a,  0x69,  0x08,  0x72,  0x0b,  0x83,  0x59,  0xb8,  0xf0,  0xbd,  0x56,  0xcc,  0x12,  0xec,  0x17,
+  0xee,  0x0f,  0xf0,  0x00,  0xf8,  0x17,  0x01,  0x48,  0x02,  0xfa,  0x03,  0xfa,  0x04,  0x10,  0x04,  0xea,
+  0x04,  0xf6,  0x04,  0xfc,  0x05,  0x80,  0x05,  0xe6,  0x06,  0x00,  0x06,  0x12,  0x0a,  0x10,  0x0b,  0xf0,
+  0x0c,  0x10,  0x0c,  0xf0,  0x12,  0x10,  0x26,  0x0e,  0x30,  0x1c,  0x33,  0x00,  0x34,  0x00,  0x38,  0x44,
+  0x40,  0x5c,  0x4a,  0xe4,  0x62,  0x1a,  0x68,  0x08,  0x68,  0x54,  0x83,  0x55,  0x83,  0x5a,  0x8c,  0x14,
+  0x8e,  0x0a,  0x90,  0x14,  0x91,  0x44,  0xa4,  0x00,  0xb0,  0x57,  0xb5,  0x00,  0xba,  0x00,  0xce,  0x45,
+  0xd0,  0x00,  0xd8,  0x16,  0xe1,  0x00,  0xe7,  0x00,  0x00,  0x54,  0x01,  0x58,  0x02,  0x10,  0x02,  0xe6,
+  0x03,  0xa1,  0x04,  0x13,  0x06,  0x83,  0x06,  0xf0,  0x07,  0x00,  0x0a,  0x00,  0x0a,  0x12,  0x0a,  0xf0,
+  0x0c,  0x04,  0x0c,  0x12,  0x0c,  0x90,  0x10,  0x10,  0x10,  0x13,  0x12,  0x1c,  0x17,  0x00,  0x19,  0xe4,
+  0x1a,  0x10,  0x1c,  0x00,  0x1c,  0x12,  0x1d,  0xf7,  0x1e,  0x13,  0x20,  0x1c,  0x20,  0xe7,  0x22,  0x01,
+  0x26,  0x01,  0x2a,  0x12,  0x30,  0xe7,  0x34,  0x1c,  0x36,  0x1c,  0x38,  0x12,  0x41,  0x58,  0x43,  0x48,
+  0x44,  0x55,  0x46,  0x1c,  0x4c,  0x0e,  0x4e,  0xe4,  0x52,  0x14,  0x5c,  0xf0,  0x72,  0x02,  0x74,  0x03,
+  0x77,  0x57,  0x89,  0x48,  0x8e,  0x90,  0x99,  0x00,  0x9b,  0x00,  0x9c,  0x32,  0x9e,  0x00,  0xa8,  0x00,
+  0xb9,  0x00,  0xba,  0x06,  0xbc,  0x12,  0xbf,  0x57,  0xc0,  0x01,  0xfe,  0x9c,  0xf0,  0x26,  0x02,  0xfe,
+  0x00,  0x0d,  0xff,  0x10,  0x00,  0x00,  0xfe,  0xc2,  0x01,  0xfe,  0x56,  0x19,  0x00,  0xfc,  0xfe,  0x80,
+  0x01,  0xff,  0x03,  0x00,  0x00,  0xfe,  0x6a,  0x13,  0xfe,  0x05,  0x05,  0xff,  0x40,  0x00,  0x00,  0x0d,
+  0xff,  0x09,  0x00,  0x00,  0xff,  0x08,  0x01,  0x01,  0xff,  0x10,  0xff,  0xff,  0xff,  0x1f,  0x00,  0x00,
+  0xff,  0x10,  0xff,  0xff,  0xff,  0x0f,  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,
+  0x00,  0x00,  0xfe,  0x04,  0xf7,  0xfc,  0x2b,  0x51,  0x0c,  0x01,  0xfe,  0xea,  0x0e,  0xfe,  0x04,  0xf7,
+  0xfc,  0x51,  0x0c,  0x1d,  0x2b,  0xfe,  0x3d,  0xf0,  0xfe,  0xf8,  0x01,  0xfe,  0x20,  0xf0,  0xd0,  0x04,
+  0x56,  0x4b,  0x02,  0xfe,  0x1c,  0x0d,  0x01,  0xfe,  0x7c,  0x0d,  0xfe,  0xe9,  0x12,  0x02,  0xfe,  0x04,
+  0x03,  0xfe,  0x28,  0x1c,  0x04,  0xfe,  0xa6,  0x00,  0xfe,  0xdd,  0x12,  0x4e,  0x12,  0xfe,  0xa6,  0x00,
+  0xc5,  0xfe,  0x48,  0xf0,  0xfe,  0x7c,  0x02,  0xfe,  0x49,  0xf0,  0xfe,  0x96,  0x02,  0xfe,  0x4a,  0xf0,
+  0xfe,  0xb4,  0x02,  0xfe,  0x46,  0xf0,  0xfe,  0x46,  0x02,  0xfe,  0x47,  0xf0,  0xfe,  0x4c,  0x02,  0xfe,
+  0x43,  0xf0,  0xfe,  0x3a,  0x02,  0xfe,  0x44,  0xf0,  0xfe,  0x3e,  0x02,  0xfe,  0x45,  0xf0,  0xfe,  0x42,
+  0x02,  0x09,  0x0c,  0x9e,  0x09,  0x06,  0x12,  0xbb,  0x02,  0x26,  0xfe,  0x00,  0x1c,  0xfe,  0xf1,  0x10,
+  0xfe,  0x02,  0x1c,  0xfe,  0xed,  0x10,  0xfe,  0x1e,  0x1c,  0xfe,  0xe9,  0x10,  0x01,  0xfe,  0x4c,  0x17,
+  0xfe,  0xe7,  0x10,  0xfe,  0x06,  0xfc,  0xf7,  0x0e,  0x78,  0x01,  0xab,  0x02,  0x26,  0x17,  0x55,  0x4a,
+  0xbd,  0x01,  0xfe,  0x60,  0x0f,  0x0e,  0x78,  0x01,  0x8b,  0xfe,  0xbd,  0x10,  0x0e,  0x78,  0x01,  0x8b,
+  0xfe,  0xad,  0x10,  0xfe,  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x09,  0x06,  0x12,  0xbb,  0x2b,  0x22,  0x26,
+  0xfe,  0x3d,  0xf0,  0xfe,  0xf8,  0x01,  0x27,  0xfe,  0x8a,  0x02,  0xfe,  0x5a,  0x1c,  0xd5,  0xfe,  0x14,
+  0x1c,  0x17,  0xfe,  0x30,  0x00,  0x4a,  0xbd,  0x01,  0xfe,  0x50,  0x0f,  0x09,  0x06,  0x12,  0xbb,  0x02,
+  0xfe,  0xc2,  0x01,  0x21,  0x2a,  0x05,  0x10,  0x35,  0xfe,  0x69,  0x10,  0x09,  0x06,  0x12,  0xbb,  0xfe,
+  0x04,  0xec,  0x2a,  0x08,  0x2a,  0x09,  0x3c,  0x1d,  0x01,  0x46,  0x7f,  0xfe,  0x05,  0xf6,  0xf7,  0x01,
+  0xfe,  0x76,  0x16,  0x0a,  0x41,  0x89,  0x38,  0x11,  0x47,  0x1d,  0xca,  0x08,  0x1c,  0x09,  0x43,  0x01,
+  0x71,  0x02,  0x26,  0x0e,  0x3d,  0x01,  0x15,  0x05,  0x10,  0x2c,  0x08,  0x1c,  0x09,  0x43,  0x01,  0x7b,
+  0xfe,  0x28,  0x10,  0x0e,  0xc0,  0x01,  0x15,  0xe6,  0x0e,  0x79,  0x01,  0x15,  0xfe,  0x49,  0x54,  0x74,
+  0xfe,  0x12,  0x03,  0x08,  0x1c,  0x09,  0x43,  0x01,  0x71,  0x02,  0x26,  0x2b,  0x7f,  0xfe,  0x02,  0xe8,
+  0x2f,  0xfb,  0xfe,  0x9e,  0x43,  0xf0,  0xfe,  0x07,  0x4b,  0xfe,  0x20,  0xf0,  0xd0,  0xfe,  0x40,  0x1c,
+  0x22,  0xef,  0xfe,  0x26,  0xf0,  0xfe,  0x70,  0x03,  0xfe,  0xa0,  0xf0,  0xfe,  0x5e,  0x03,  0xfe,  0x11,
+  0xf0,  0xd0,  0xfe,  0x0e,  0x10,  0xfe,  0x9f,  0xf0,  0xfe,  0x7e,  0x03,  0xe9,  0x13,  0xfe,  0x11,  0x00,
+  0x02,  0x62,  0x2b,  0xfe,  0x48,  0x1c,  0xe9,  0x22,  0xef,  0x34,  0xef,  0xfe,  0x82,  0xf0,  0xfe,  0x84,
+  0x03,  0x2d,  0x21,  0xbe,  0x6a,  0x16,  0xbe,  0x0e,  0x79,  0x01,  0x15,  0x6a,  0x7d,  0x08,  0x1c,  0x09,
+  0x43,  0x01,  0x46,  0x11,  0x3d,  0x08,  0x3d,  0x09,  0x99,  0x01,  0x71,  0xf5,  0x11,  0xfe,  0xe4,  0x00,
+  0x2e,  0xfe,  0xca,  0x03,  0x22,  0x32,  0x1f,  0xfe,  0xda,  0x03,  0x01,  0x4c,  0xcb,  0xfe,  0xea,  0x03,
+  0x6b,  0x92,  0xcf,  0xfe,  0xaa,  0x06,  0x02,  0x28,  0x04,  0x78,  0x29,  0x18,  0xfe,  0x1c,  0x05,  0x17,
+  0x85,  0x01,  0x44,  0x01,  0x97,  0x01,  0x9a,  0x34,  0xfe,  0x5c,  0x02,  0x02,  0xee,  0xe9,  0x2b,  0x51,
+  0x19,  0xfe,  0x67,  0x1b,  0xfb,  0xf0,  0xfe,  0x48,  0x1c,  0x8c,  0x01,  0xfa,  0xac,  0xfe,  0x96,  0xf0,
+  0xfe,  0x24,  0x04,  0x2e,  0xfe,  0x28,  0x04,  0x34,  0x26,  0x0e,  0x3d,  0x01,  0x15,  0x05,  0x10,  0x18,
+  0xfe,  0x08,  0x05,  0x3e,  0x90,  0x9f,  0x2f,  0x82,  0x6e,  0x22,  0x32,  0x1f,  0x28,  0x04,  0x78,  0x29,
+  0xfe,  0x10,  0x12,  0x17,  0x85,  0x01,  0x44,  0x34,  0xfe,  0x5c,  0x02,  0x02,  0xee,  0x31,  0xfe,  0xa0,
+  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x5e,  0x12,  0x0a,  0x07,  0x06,  0xfe,  0x56,  0x12,  0x23,  0x24,  0x91,
+  0x01,  0x0b,  0x82,  0x6e,  0x1f,  0xfe,  0xd8,  0x04,  0x23,  0x24,  0x91,  0x01,  0x0b,  0x1f,  0x28,  0x23,
+  0x24,  0xb3,  0xfe,  0x4c,  0x44,  0xfe,  0x32,  0x12,  0x57,  0xfe,  0x44,  0x48,  0x08,  0xd6,  0xfe,  0x4c,
+  0x54,  0x74,  0xfe,  0x08,  0x05,  0x7f,  0x9f,  0x2f,  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x48,
+  0x13,  0x3f,  0x05,  0xfe,  0xcc,  0x00,  0xfe,  0x40,  0x13,  0x0a,  0x07,  0x06,  0xe5,  0xfe,  0x06,  0x10,
+  0x23,  0x24,  0xb3,  0x0a,  0x07,  0x37,  0xda,  0x17,  0xa4,  0x0a,  0x07,  0x06,  0x4b,  0x17,  0xfe,  0x0d,
+  0x00,  0x01,  0x44,  0x34,  0xfe,  0xc0,  0x0c,  0x02,  0x28,  0x39,  0x11,  0xfe,  0xe6,  0x00,  0xfe,  0x1c,
+  0x90,  0xb0,  0x03,  0x17,  0xa4,  0x01,  0x44,  0x34,  0x26,  0x22,  0x26,  0x02,  0xfe,  0x10,  0x05,  0xfe,
+  0x42,  0x5b,  0x51,  0x19,  0xfe,  0x46,  0x59,  0xfb,  0xf0,  0x17,  0x45,  0xfe,  0x07,  0x80,  0xfe,  0x31,
+  0x44,  0x0a,  0x07,  0x0c,  0xfe,  0x78,  0x13,  0xfe,  0x20,  0x80,  0x05,  0x19,  0xfe,  0x70,  0x12,  0x6d,
+  0x07,  0x06,  0xfe,  0x60,  0x13,  0x04,  0xfe,  0xa2,  0x00,  0x29,  0x18,  0xfe,  0xa8,  0x05,  0xfe,  0x31,
+  0xe4,  0x70,  0x6d,  0x07,  0x0c,  0xfe,  0x4a,  0x13,  0x04,  0xfe,  0xa0,  0x00,  0x29,  0xfe,  0x42,  0x12,
+  0x5a,  0x2e,  0xfe,  0x68,  0x05,  0x22,  0x32,  0xf1,  0x01,  0x0b,  0x25,  0xfe,  0xc0,  0x05,  0x11,  0xfe,
+  0xe3,  0x00,  0x2d,  0x6d,  0xfe,  0x4a,  0xf0,  0xfe,  0x92,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0x8c,  0x05,
+  0xa8,  0x20,  0xfe,  0x21,  0x00,  0xa6,  0x20,  0xfe,  0x22,  0x00,  0x9e,  0x20,  0x89,  0xfe,  0x09,  0x48,
+  0x01,  0x0b,  0x25,  0xfe,  0xc0,  0x05,  0xfe,  0xe2,  0x08,  0x6d,  0x07,  0xd9,  0x4b,  0x01,  0x96,  0x20,
+  0x06,  0x16,  0xe0,  0x4a,  0xfe,  0x27,  0x01,  0x0a,  0x07,  0x37,  0xe1,  0x4e,  0x01,  0xb9,  0x17,  0xa4,
+  0x0a,  0x07,  0x06,  0x4b,  0x17,  0xfe,  0x0d,  0x00,  0x01,  0x44,  0x01,  0x97,  0x01,  0x9a,  0x34,  0xfe,
+  0xc0,  0x0c,  0x02,  0x28,  0x04,  0xfe,  0x9c,  0x00,  0x29,  0xfe,  0x3e,  0x12,  0x04,  0x53,  0x29,  0xfe,
+  0x36,  0x13,  0x4e,  0x01,  0xb9,  0x25,  0xfe,  0x38,  0x06,  0x0e,  0x06,  0x6d,  0x07,  0x1a,  0xfe,  0x02,
+  0x12,  0x77,  0x01,  0xfe,  0x26,  0x14,  0x1f,  0xfe,  0x2e,  0x06,  0x11,  0xc2,  0x01,  0x4c,  0x11,  0xfe,
+  0xe5,  0x00,  0x04,  0x53,  0xbc,  0x0f,  0x53,  0x04,  0xf6,  0x29,  0xfe,  0x62,  0x12,  0x04,  0x4d,  0x29,
+  0xfe,  0x5a,  0x13,  0x01,  0xfe,  0x9e,  0x18,  0x01,  0xfe,  0xf0,  0x18,  0xe7,  0xa3,  0x1a,  0x08,  0x63,
+  0xff,  0x02,  0x00,  0x57,  0x66,  0x7e,  0x1b,  0x50,  0xc9,  0xa3,  0x6c,  0x4e,  0x01,  0xb9,  0x25,  0xfe,
+  0xa2,  0x06,  0x6d,  0x07,  0x1e,  0xa5,  0x95,  0x0e,  0x55,  0x01,  0xfe,  0x54,  0x14,  0x1f,  0xfe,  0x98,
+  0x06,  0x11,  0xc2,  0x01,  0x4c,  0x11,  0xfe,  0xe5,  0x00,  0x04,  0x4d,  0xbc,  0x0f,  0x4d,  0x09,  0x06,
+  0x01,  0xb9,  0xf5,  0x73,  0x8c,  0x01,  0xfa,  0xac,  0x11,  0xfe,  0xe2,  0x00,  0x2e,  0xf9,  0x22,  0x32,
+  0xcf,  0xfe,  0xd6,  0x06,  0x81,  0xfe,  0x74,  0x07,  0xcb,  0xfe,  0x7c,  0x07,  0x6b,  0x92,  0x02,  0x28,
+  0x0a,  0x07,  0x0c,  0xfe,  0x2e,  0x12,  0x14,  0x19,  0x01,  0x0b,  0x14,  0x00,  0x01,  0x0b,  0x14,  0x00,
+  0x01,  0x0b,  0x14,  0x00,  0x01,  0x0b,  0xfe,  0x99,  0xa4,  0x01,  0x0b,  0x14,  0x00,  0x02,  0xfe,  0x4c,
+  0x08,  0x68,  0x07,  0x1e,  0xe5,  0x0a,  0x07,  0x1e,  0xfe,  0x30,  0x13,  0x14,  0xfe,  0x1b,  0x00,  0x01,
+  0x0b,  0x14,  0x00,  0x01,  0x0b,  0x14,  0x00,  0x01,  0x0b,  0x14,  0x00,  0x01,  0x0b,  0x14,  0x06,  0x01,
+  0x0b,  0x14,  0x00,  0x02,  0xfe,  0x2a,  0x0b,  0x77,  0xfe,  0x9a,  0x81,  0x67,  0x89,  0xfe,  0x09,  0x6f,
+  0xfe,  0x93,  0x45,  0x18,  0xfe,  0x84,  0x07,  0x2e,  0xfe,  0x5c,  0x07,  0x22,  0x32,  0xcf,  0xfe,  0x54,
+  0x07,  0x6b,  0x92,  0x81,  0xfe,  0x74,  0x07,  0x02,  0x28,  0x01,  0x4c,  0x02,  0xf9,  0x14,  0x1a,  0x02,
+  0xf9,  0xfe,  0x9c,  0xf7,  0xfe,  0xec,  0x07,  0xfe,  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x75,  0xfe,  0xd2,
+  0x07,  0x0f,  0x5d,  0x12,  0x5e,  0x0a,  0x41,  0x70,  0x38,  0x01,  0xfe,  0x34,  0x18,  0x05,  0x10,  0x83,
+  0xfe,  0x83,  0xe7,  0x88,  0xa6,  0xfe,  0x03,  0x40,  0x0a,  0x41,  0x45,  0x38,  0x01,  0xc1,  0xaf,  0xfe,
+  0x1f,  0x40,  0x16,  0x61,  0x01,  0xfe,  0xde,  0x12,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0xfe,  0x34,
+  0x51,  0xfe,  0xb6,  0x51,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,  0x0f,  0x5b,  0x12,  0x5c,  0xd2,  0xf2,
+  0x0f,  0x3a,  0x12,  0x3b,  0xfe,  0x60,  0x10,  0x0a,  0x07,  0x70,  0xe1,  0xfe,  0x2c,  0x90,  0xfe,  0xae,
+  0x90,  0x0f,  0x5d,  0x12,  0x5e,  0x0a,  0x07,  0x45,  0xc9,  0x01,  0xc1,  0xfe,  0x1f,  0x80,  0x16,  0x61,
+  0xfe,  0x34,  0x90,  0xfe,  0xb6,  0x90,  0x0f,  0x5f,  0x12,  0x60,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,
+  0x0f,  0x5b,  0x12,  0x5c,  0xa2,  0x07,  0x45,  0x2c,  0xd2,  0xf2,  0x0f,  0x3a,  0x12,  0x3b,  0xa8,  0xfe,
+  0x28,  0x90,  0xfe,  0xaa,  0x90,  0x0f,  0x3a,  0x12,  0x3b,  0x0f,  0x42,  0x12,  0x58,  0x0a,  0x41,  0x1a,
+  0x38,  0x2b,  0x08,  0x80,  0x2e,  0xfe,  0x62,  0x08,  0xfe,  0x9e,  0xf0,  0xfe,  0x76,  0x08,  0x9b,  0x18,
+  0x32,  0x2b,  0x52,  0xfe,  0xed,  0x10,  0xa7,  0xfe,  0x9a,  0x08,  0xa9,  0xfe,  0xb6,  0x08,  0x81,  0xfe,
+  0x8e,  0x08,  0xcb,  0xfe,  0x94,  0x08,  0x6b,  0x92,  0x02,  0x28,  0x01,  0x4c,  0xfe,  0xc9,  0x10,  0x14,
+  0x1a,  0xfe,  0xc9,  0x10,  0x68,  0x07,  0x06,  0xfe,  0x10,  0x12,  0x68,  0x07,  0x0c,  0x40,  0x0a,  0x07,
+  0x0c,  0xfe,  0x7e,  0x12,  0xfe,  0x2e,  0x1c,  0xaa,  0x68,  0x07,  0x06,  0x40,  0x68,  0x07,  0x0c,  0xfe,
+  0x6a,  0x12,  0xfe,  0x2c,  0x1c,  0xa2,  0x07,  0x45,  0xd4,  0xa2,  0x41,  0x45,  0xfe,  0x05,  0x40,  0xd2,
+  0xf2,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,  0xfe,  0xaa,  0xf0,  0xfe,  0x4e,  0x09,  0xfe,  0xac,  0xf0,
+  0xfe,  0xee,  0x08,  0xfe,  0x92,  0x10,  0xe3,  0xfe,  0xf3,  0x10,  0xfe,  0xad,  0xf0,  0xfe,  0xfa,  0x08,
+  0x02,  0xfe,  0x5c,  0x0a,  0xe4,  0xfe,  0xe7,  0x10,  0xfe,  0x2b,  0xf0,  0xb8,  0xfe,  0x6b,  0x18,  0x1b,
+  0xfe,  0x00,  0xfe,  0xda,  0xc5,  0xfe,  0xd2,  0xf0,  0xb8,  0xfe,  0x76,  0x18,  0x1b,  0x19,  0x18,  0xb8,
+  0x04,  0xdf,  0x1b,  0x06,  0x18,  0xb8,  0xa7,  0x7a,  0xa9,  0x7a,  0xe3,  0xe4,  0xfe,  0xb1,  0x10,  0x8c,
+  0x5a,  0x39,  0x17,  0xa4,  0x01,  0x44,  0x13,  0xfe,  0x35,  0x00,  0x34,  0x62,  0x13,  0x8d,  0x02,  0x62,
+  0xfe,  0x74,  0x18,  0x1b,  0xfe,  0x00,  0xf8,  0x18,  0x7a,  0x51,  0x1e,  0x01,  0xfe,  0x7c,  0x0d,  0xd1,
+  0x08,  0x1c,  0x09,  0x43,  0x01,  0x71,  0x21,  0x2f,  0x3e,  0x51,  0x19,  0x02,  0x7a,  0xfe,  0x98,  0x80,
+  0xd7,  0x0c,  0x27,  0xfe,  0x3e,  0x0a,  0x0a,  0x07,  0x70,  0xfe,  0x82,  0x12,  0x0a,  0x07,  0x1a,  0xfe,
+  0x66,  0x13,  0x21,  0x61,  0x6a,  0xc8,  0xfe,  0x83,  0x80,  0xfe,  0xc8,  0x44,  0xfe,  0x2e,  0x13,  0xfe,
+  0x04,  0x91,  0xfe,  0x86,  0x91,  0x64,  0x2f,  0xfe,  0x40,  0x59,  0xfe,  0xc1,  0x59,  0x75,  0xfe,  0xea,
+  0x08,  0x04,  0x5d,  0x30,  0x5e,  0x0f,  0xae,  0x12,  0x8d,  0x9c,  0x5d,  0x9d,  0x5e,  0x01,  0xc1,  0xaf,
+  0x64,  0x2f,  0x16,  0x61,  0xa1,  0x42,  0x69,  0x58,  0x65,  0x5f,  0x31,  0x60,  0xe8,  0xfe,  0xe5,  0x55,
+  0xfe,  0x04,  0xfa,  0x42,  0xfe,  0x05,  0xfa,  0x58,  0x01,  0xfe,  0xde,  0x12,  0xfe,  0x36,  0x10,  0x2d,
+  0x0f,  0xae,  0x0f,  0x8d,  0x65,  0x5f,  0x31,  0x60,  0xaa,  0x0a,  0x07,  0x1a,  0x18,  0xfe,  0xea,  0x08,
+  0x65,  0x3a,  0x31,  0x3b,  0x0a,  0x07,  0xfe,  0xf7,  0x00,  0x38,  0x04,  0x5b,  0x30,  0x5c,  0xfe,  0x10,
+  0x58,  0xfe,  0x91,  0x58,  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0x02,  0x7a,  0x0a,  0x07,  0x1a,  0x18,
+  0xfe,  0xea,  0x08,  0x0a,  0x07,  0xfe,  0xf7,  0x00,  0x38,  0xfe,  0x3a,  0x55,  0xfe,  0x19,  0x81,  0x77,
+  0xfe,  0x10,  0x90,  0xfe,  0x92,  0x90,  0xfe,  0xd7,  0x10,  0x3f,  0x05,  0xc3,  0x18,  0xfe,  0xf6,  0x08,
+  0x11,  0xc3,  0xfe,  0x98,  0x80,  0xd7,  0x0c,  0xfe,  0x14,  0x13,  0x04,  0x3a,  0x30,  0x3b,  0x75,  0xfe,
+  0xf6,  0x08,  0xfe,  0x0c,  0x58,  0xfe,  0x8d,  0x58,  0x02,  0x7a,  0x2d,  0x4e,  0xfe,  0x19,  0x80,  0xfe,
+  0xf1,  0x10,  0x0a,  0x07,  0x0c,  0xa5,  0xfe,  0x6c,  0x19,  0xfe,  0x19,  0x41,  0xfe,  0x8e,  0x10,  0xfe,
+  0x6c,  0x19,  0x9c,  0x3a,  0xfe,  0xed,  0x19,  0x9d,  0x3b,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0xfe,
+  0x6b,  0x18,  0x1b,  0xfe,  0x00,  0xff,  0x35,  0xfe,  0x74,  0x10,  0xc5,  0xfe,  0xd2,  0xf0,  0xfe,  0xd6,
+  0x0a,  0xfe,  0x76,  0x18,  0x1b,  0x19,  0xce,  0x04,  0xdf,  0x1b,  0x06,  0x84,  0x13,  0xfe,  0x16,  0x00,
+  0x02,  0x62,  0xfe,  0xd1,  0xf0,  0xfe,  0xe8,  0x0a,  0x17,  0x80,  0x01,  0x44,  0x13,  0xd6,  0xfe,  0x42,
+  0x10,  0xfe,  0xce,  0xf0,  0xfe,  0xee,  0x0a,  0xfe,  0x3c,  0x10,  0xfe,  0xcd,  0xf0,  0xfe,  0xfa,  0x0a,
+  0x13,  0xfe,  0x22,  0x00,  0x02,  0x62,  0xfe,  0xcb,  0xf0,  0xfe,  0x06,  0x0b,  0x13,  0xfe,  0x24,  0x00,
+  0x02,  0x62,  0xfe,  0xd0,  0xf0,  0xfe,  0x10,  0x0b,  0x13,  0x88,  0xd8,  0xfe,  0xcf,  0xf0,  0xfe,  0x1a,
+  0x0b,  0x13,  0x89,  0xd3,  0xfe,  0xcc,  0xf0,  0xfe,  0x2a,  0x0b,  0xfe,  0x84,  0x80,  0xd7,  0x1a,  0x4b,
+  0x13,  0xfe,  0x12,  0x00,  0x2b,  0x08,  0x80,  0x2e,  0xfe,  0x30,  0x0b,  0xfe,  0x9e,  0xf0,  0xfe,  0x44,
+  0x0b,  0x9b,  0x18,  0x32,  0x2b,  0x52,  0xfe,  0xed,  0x10,  0xa7,  0x28,  0xa9,  0x28,  0x2b,  0xf5,  0x2e,
+  0xfe,  0x50,  0x0b,  0x22,  0x32,  0x81,  0xfe,  0x6c,  0x0b,  0x6b,  0x92,  0xa7,  0xfe,  0xec,  0x07,  0xa9,
+  0xfe,  0xec,  0x07,  0x02,  0x28,  0x01,  0x4c,  0xfe,  0xdb,  0x10,  0x11,  0xfe,  0xe8,  0x00,  0xe3,  0xe4,
+  0x8c,  0x82,  0x6e,  0xfe,  0x89,  0xf0,  0x28,  0x23,  0x24,  0xfe,  0xe9,  0x09,  0x01,  0x0b,  0x82,  0x6e,
+  0x1f,  0x28,  0x23,  0x24,  0x91,  0x34,  0xfe,  0xa8,  0x0b,  0x22,  0x32,  0x02,  0xfe,  0x9c,  0x0b,  0x9b,
+  0x40,  0x13,  0xfe,  0x42,  0x00,  0x02,  0x62,  0xa0,  0x06,  0xfe,  0x81,  0x49,  0x96,  0x0a,  0x07,  0x0c,
+  0xfe,  0x5a,  0x13,  0x13,  0x00,  0x59,  0x0c,  0xfe,  0x6a,  0x12,  0x59,  0xfe,  0x28,  0x00,  0x27,  0xfe,
+  0xee,  0x0c,  0x0e,  0x79,  0x01,  0x15,  0x05,  0x00,  0x84,  0x36,  0xfe,  0x28,  0x00,  0x02,  0xfe,  0xee,
+  0x0c,  0x01,  0x97,  0x01,  0x9a,  0x0e,  0xc0,  0x01,  0xfe,  0x44,  0x0e,  0xb2,  0x08,  0x3d,  0x09,  0x99,
+  0x01,  0x46,  0x11,  0x47,  0x08,  0x1c,  0x09,  0x43,  0x01,  0x7b,  0x02,  0x26,  0x13,  0xfe,  0x44,  0x00,
+  0x59,  0x0c,  0xa5,  0x36,  0x0c,  0xfe,  0xc0,  0x10,  0x01,  0x96,  0x36,  0x0c,  0xfe,  0xb6,  0x10,  0x01,
+  0x96,  0xfe,  0x19,  0x82,  0xfe,  0x34,  0x46,  0xfe,  0x0a,  0x13,  0x36,  0x0c,  0x13,  0xfe,  0x43,  0x00,
+  0xfe,  0xa2,  0x10,  0x0a,  0x41,  0x0c,  0x38,  0x01,  0x97,  0x01,  0x9a,  0xb2,  0x08,  0x3d,  0x09,  0x99,
+  0x01,  0x46,  0x11,  0x47,  0x08,  0x1c,  0x09,  0x43,  0x01,  0x7b,  0x51,  0x0c,  0xb2,  0x1d,  0xca,  0x02,
+  0xfe,  0x48,  0x03,  0x0a,  0x07,  0x0c,  0xce,  0x36,  0x0c,  0x13,  0x00,  0xfe,  0x54,  0x10,  0x68,  0x07,
+  0x1e,  0xfe,  0x50,  0x12,  0x0a,  0x07,  0x1e,  0xfe,  0x48,  0x13,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,
+  0xfe,  0xac,  0x0c,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0xb2,  0x0c,  0x0a,  0x41,  0x1e,  0x38,
+  0xfe,  0x95,  0x10,  0x13,  0xfe,  0x15,  0x00,  0xfe,  0x04,  0xe6,  0x0c,  0x77,  0xfe,  0x26,  0x10,  0x13,
+  0xfe,  0x13,  0x00,  0xd3,  0x13,  0xfe,  0x47,  0x00,  0xa6,  0x13,  0xfe,  0x41,  0x00,  0x9e,  0x13,  0xfe,
+  0x24,  0x00,  0x04,  0x78,  0x29,  0x27,  0xee,  0x77,  0xfe,  0x04,  0xe6,  0x1e,  0xfe,  0x9d,  0x41,  0xfe,
+  0x1c,  0x42,  0xb2,  0x01,  0xea,  0x02,  0x26,  0xd5,  0x17,  0x0c,  0x4a,  0xf4,  0xdd,  0x17,  0xfe,  0x31,
+  0x00,  0x4a,  0xbd,  0x01,  0xfe,  0x50,  0x0f,  0x02,  0xfe,  0xc2,  0x01,  0x1d,  0xfe,  0x06,  0xec,  0xf8,
+  0x86,  0x36,  0x37,  0xbf,  0x35,  0x1d,  0xfe,  0x06,  0xea,  0xf8,  0xfe,  0x47,  0x4b,  0x95,  0xfe,  0x75,
+  0x57,  0x04,  0x56,  0xfe,  0x98,  0x56,  0xfe,  0x28,  0x12,  0x0e,  0x79,  0xfe,  0xf4,  0x14,  0x4e,  0xe6,
+  0x0e,  0xc0,  0xfe,  0xea,  0x14,  0xfe,  0x49,  0x54,  0x8f,  0xfe,  0x62,  0x0d,  0x0e,  0x1c,  0xfe,  0xde,
+  0x14,  0xfe,  0x44,  0x48,  0x02,  0xfe,  0x48,  0x03,  0x0e,  0x56,  0xfe,  0xc8,  0x14,  0x86,  0x36,  0x37,
+  0xbf,  0x35,  0x1d,  0xfe,  0xce,  0x47,  0xfe,  0xbd,  0x13,  0x02,  0x26,  0x21,  0x2a,  0x05,  0x10,  0xfe,
+  0x78,  0x12,  0x2d,  0x16,  0x55,  0x16,  0xad,  0x21,  0x47,  0x4e,  0x4a,  0x47,  0x9b,  0xfe,  0x0c,  0x13,
+  0xfe,  0xbc,  0xf0,  0xfe,  0xfe,  0x0d,  0x08,  0x06,  0x16,  0x55,  0x01,  0xfe,  0x06,  0x16,  0x04,  0xfe,
+  0x38,  0x01,  0x30,  0xfe,  0x3a,  0x01,  0x75,  0xfe,  0x02,  0x0e,  0x04,  0xfe,  0x38,  0x01,  0x1b,  0xfe,
+  0xf0,  0xff,  0x0f,  0xfe,  0x60,  0x01,  0x04,  0xfe,  0x3a,  0x01,  0x0f,  0xfe,  0x62,  0x01,  0x20,  0x06,
+  0x16,  0x47,  0xfe,  0x04,  0xec,  0x2a,  0x08,  0x2a,  0x09,  0x3c,  0x1d,  0x01,  0x46,  0x7f,  0xfe,  0x05,
+  0xf6,  0xfe,  0x34,  0x01,  0x01,  0xfe,  0x76,  0x16,  0x11,  0x47,  0xca,  0x08,  0x06,  0x03,  0x2d,  0x03,
+  0x21,  0x55,  0xfe,  0xf7,  0x12,  0x21,  0xad,  0x6a,  0x16,  0xad,  0x05,  0x80,  0xfe,  0x93,  0x13,  0xfe,
+  0x24,  0x1c,  0x17,  0x19,  0x4a,  0xf4,  0xdd,  0xfe,  0xd9,  0x10,  0x93,  0xfe,  0x03,  0xdc,  0xfe,  0x73,
+  0x57,  0xfe,  0x80,  0x5d,  0x03,  0x93,  0xfe,  0x03,  0xdc,  0xfe,  0x5b,  0x57,  0xfe,  0x80,  0x5d,  0x03,
+  0xfe,  0x03,  0x57,  0x93,  0x2d,  0xfe,  0x00,  0xcc,  0x03,  0xfe,  0x03,  0x57,  0x93,  0x7d,  0x03,  0x01,
+  0xfe,  0xae,  0x16,  0x3f,  0x05,  0x47,  0xfe,  0x0a,  0x13,  0x08,  0x1c,  0x09,  0x43,  0xd3,  0x01,  0x97,
+  0x01,  0x9a,  0x08,  0x3d,  0x09,  0x99,  0x01,  0x46,  0x11,  0xfe,  0xe9,  0x00,  0x0a,  0x07,  0x89,  0xfe,
+  0x52,  0x13,  0x01,  0xfe,  0x38,  0x16,  0xfe,  0x1e,  0x1c,  0xfe,  0x14,  0x90,  0x0f,  0xfe,  0x64,  0x01,
+  0xfe,  0x16,  0x90,  0x0f,  0xfe,  0x66,  0x01,  0x0a,  0x07,  0x45,  0xe5,  0xfe,  0x03,  0x80,  0x52,  0x3e,
+  0x11,  0x76,  0x08,  0x2a,  0x09,  0x3c,  0x1d,  0x90,  0x01,  0x71,  0xfe,  0x62,  0x08,  0x6a,  0x3e,  0x11,
+  0x76,  0x08,  0x2a,  0x09,  0x3c,  0x1d,  0x90,  0x01,  0x71,  0x64,  0x2f,  0x11,  0x76,  0x08,  0x2a,  0x09,
+  0x3c,  0x1d,  0x90,  0x01,  0x7b,  0x03,  0xfe,  0x08,  0x1c,  0x04,  0xfe,  0xac,  0x00,  0xfe,  0x06,  0x58,
+  0x04,  0xfe,  0xae,  0x00,  0xfe,  0x07,  0x58,  0x04,  0xfe,  0xb0,  0x00,  0xfe,  0x08,  0x58,  0x04,  0xfe,
+  0xb2,  0x00,  0xfe,  0x09,  0x58,  0xfe,  0x0a,  0x1c,  0x20,  0x6c,  0x16,  0xf8,  0x2d,  0x0f,  0x53,  0x0f,
+  0x4d,  0x20,  0x10,  0x16,  0x2a,  0x16,  0x3c,  0x57,  0xa0,  0xd6,  0x08,  0x2a,  0x09,  0x3c,  0x1d,  0x01,
+  0x7b,  0x7f,  0x11,  0x76,  0xfe,  0x14,  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0x2a,  0x0f,  0xd5,  0x8c,  0xfe,
+  0x14,  0x1c,  0xfe,  0x10,  0x1c,  0xfe,  0x18,  0x1c,  0x03,  0x1d,  0xfe,  0x0c,  0x14,  0x86,  0xfe,  0x07,
+  0xe6,  0x37,  0xfe,  0xce,  0x47,  0xfe,  0xf5,  0x13,  0x03,  0x01,  0x96,  0x0e,  0x3d,  0x01,  0x15,  0x05,
+  0x10,  0x2c,  0x0e,  0x1c,  0x01,  0x15,  0x05,  0x10,  0xda,  0xfe,  0x44,  0x58,  0x3e,  0xfe,  0x01,  0xec,
+  0xbd,  0xfe,  0x9e,  0x40,  0xfe,  0x9d,  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x1e,  0x9f,  0x2f,  0x01,  0xea,
+  0xfe,  0xc9,  0x10,  0x03,  0x2b,  0x82,  0x6e,  0x23,  0x24,  0xb3,  0x05,  0x1e,  0xfe,  0x48,  0x12,  0x05,
+  0x0c,  0xfe,  0x4c,  0x12,  0x05,  0x19,  0xfe,  0x30,  0x12,  0x05,  0xcc,  0x18,  0xfe,  0xf4,  0x10,  0x05,
+  0xfe,  0x23,  0x00,  0x18,  0xfe,  0x00,  0x11,  0x05,  0x06,  0x18,  0xfe,  0x5e,  0x11,  0x05,  0x1a,  0xfe,
+  0x12,  0x12,  0x05,  0x00,  0x18,  0x28,  0x17,  0xcc,  0x01,  0x44,  0xc6,  0x39,  0x01,  0x0b,  0x81,  0x4c,
+  0x03,  0x39,  0x11,  0xfe,  0xcc,  0x00,  0x02,  0x26,  0x39,  0x3f,  0x05,  0xc3,  0xfe,  0xe3,  0x13,  0x65,
+  0x3a,  0x31,  0x3b,  0x75,  0xfe,  0xb2,  0x10,  0x0a,  0x07,  0x70,  0xfe,  0x72,  0x12,  0xa1,  0x42,  0x69,
+  0x58,  0xe8,  0xfe,  0xe5,  0x55,  0x8f,  0xfe,  0x7c,  0x10,  0x21,  0x61,  0xfe,  0x26,  0x13,  0x04,  0xae,
+  0x30,  0x8d,  0x75,  0xfe,  0xd2,  0x0c,  0x0f,  0x5d,  0x12,  0x5e,  0x2d,  0x0f,  0xae,  0x0f,  0x8d,  0x01,
+  0xc1,  0x20,  0x6c,  0x52,  0x16,  0x61,  0x01,  0xfe,  0xde,  0x12,  0xa1,  0x42,  0x69,  0x58,  0xfe,  0x04,
+  0x55,  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,  0x42,  0xfe,  0x05,  0xfa,  0x58,  0xfe,  0x91,  0x10,  0x04,
+  0x5f,  0x30,  0x60,  0xfe,  0x40,  0x56,  0xfe,  0xe1,  0x56,  0x0f,  0x5f,  0x12,  0x60,  0xa8,  0xa1,  0x42,
+  0x69,  0x58,  0xe8,  0xfe,  0xe5,  0x55,  0x04,  0x5b,  0x30,  0x5c,  0xfe,  0x00,  0x56,  0xfe,  0xa1,  0x56,
+  0x0f,  0x5b,  0x12,  0x5c,  0x0a,  0x07,  0x70,  0xfe,  0x1e,  0x12,  0x21,  0x61,  0xfe,  0x1f,  0x40,  0x04,
+  0x5d,  0x30,  0x5e,  0xfe,  0x2c,  0x50,  0xfe,  0xae,  0x50,  0x04,  0x5f,  0x30,  0x60,  0xfe,  0x34,  0x50,
+  0xfe,  0xb6,  0x50,  0x04,  0x5b,  0x30,  0x5c,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0x04,  0x3a,  0x30,
+  0x3b,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,  0x02,  0x98,  0x20,  0x06,  0x16,  0xf3,  0x02,  0x7c,  0x39,
+  0x01,  0x0b,  0x1f,  0x4f,  0x23,  0x24,  0xb3,  0x05,  0x06,  0x27,  0x4f,  0x3f,  0x05,  0xc3,  0x27,  0x7c,
+  0x01,  0xfa,  0x1b,  0x50,  0x18,  0x4f,  0x0a,  0x07,  0x0c,  0xdc,  0x65,  0x3a,  0x31,  0x3b,  0xfe,  0x0a,
+  0x55,  0x35,  0xfe,  0x8b,  0x55,  0x9c,  0x3a,  0x9d,  0x3b,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0x02,
+  0x7c,  0xfe,  0x19,  0x81,  0xfe,  0x0a,  0x45,  0xfe,  0x19,  0x41,  0x02,  0x7c,  0x39,  0x01,  0x0b,  0x1f,
+  0xfe,  0xf6,  0x0f,  0x23,  0x24,  0xfe,  0xe9,  0x09,  0x59,  0x19,  0xfe,  0x94,  0x12,  0x59,  0x0c,  0x4b,
+  0x02,  0x4f,  0x2e,  0xfe,  0x7e,  0x11,  0x22,  0x32,  0x1f,  0xfe,  0xf6,  0x0f,  0x23,  0x24,  0x91,  0x05,
+  0x19,  0x27,  0x4f,  0x01,  0x0b,  0x1f,  0xfe,  0xf6,  0x0f,  0x23,  0x24,  0xfe,  0xe8,  0x09,  0x57,  0x04,
+  0xfe,  0x9c,  0x00,  0x29,  0x35,  0xfe,  0xbb,  0x45,  0x59,  0x00,  0x40,  0x36,  0x06,  0xa0,  0x50,  0xfe,
+  0xc0,  0x14,  0xfe,  0xf8,  0x14,  0xac,  0x3f,  0x05,  0xc2,  0xfe,  0x16,  0x13,  0x04,  0xf6,  0x29,  0xce,
+  0x04,  0x4d,  0x29,  0x35,  0x5a,  0x02,  0x7c,  0xfe,  0xc0,  0x5d,  0xfe,  0xe4,  0x14,  0xfe,  0x03,  0x17,
+  0x04,  0x53,  0xbc,  0x0f,  0x53,  0x5a,  0x39,  0x01,  0x0b,  0x25,  0x98,  0x01,  0xfe,  0x26,  0x14,  0x02,
+  0x98,  0x2e,  0x40,  0x22,  0x32,  0x1f,  0x4f,  0x23,  0x24,  0x91,  0x05,  0x06,  0x27,  0x4f,  0xfe,  0xf6,
+  0x14,  0xfe,  0x42,  0x58,  0xfe,  0x70,  0x14,  0xfe,  0x92,  0x14,  0xac,  0xfe,  0x4a,  0xf4,  0x0c,  0x18,
+  0x4f,  0xfe,  0x4a,  0xf4,  0x06,  0xd1,  0x3f,  0x05,  0xc2,  0xc9,  0x02,  0x7c,  0x04,  0x4d,  0xbc,  0x0f,
+  0x4d,  0x5a,  0x39,  0x01,  0x0b,  0x25,  0x98,  0x01,  0xfe,  0x54,  0x14,  0x02,  0x98,  0x25,  0xfe,  0x70,
+  0x12,  0x73,  0xf1,  0x73,  0x03,  0x34,  0xfe,  0x6c,  0x12,  0x6b,  0xfe,  0x6c,  0x12,  0x5a,  0x39,  0x01,
+  0x0b,  0xfe,  0xe3,  0x10,  0x08,  0x63,  0xff,  0x02,  0x00,  0x57,  0x66,  0x7e,  0x1b,  0xfe,  0xff,  0x7f,
+  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x08,  0x63,  0xff,  0x02,  0x00,  0x57,  0x66,  0x7e,  0x1b,
+  0x50,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x08,  0x63,  0xff,  0x02,  0x00,  0x57,  0x66,  0x7e,
+  0x03,  0x08,  0x63,  0xff,  0x02,  0x00,  0x57,  0x66,  0x7e,  0xfe,  0x0b,  0x58,  0x03,  0x0e,  0x53,  0x01,
+  0x8b,  0x0e,  0x4d,  0x01,  0x8b,  0x03,  0xc8,  0x1b,  0x10,  0xff,  0x03,  0x00,  0x54,  0xfe,  0x00,  0xf4,
+  0x1a,  0x66,  0xfe,  0x00,  0x7d,  0xfe,  0x01,  0x7d,  0xfe,  0x02,  0x7d,  0xfe,  0x03,  0x7c,  0x64,  0x2f,
+  0x0f,  0x5b,  0x12,  0x5c,  0x9c,  0x5f,  0x9d,  0x60,  0x03,  0xfe,  0x62,  0x18,  0xfe,  0x82,  0x5a,  0xfe,
+  0xe1,  0x1a,  0xb6,  0xfe,  0x02,  0x58,  0x03,  0x01,  0xfe,  0x9e,  0x18,  0xfe,  0x42,  0x48,  0x77,  0x57,
+  0x95,  0x01,  0x0b,  0x1f,  0xfe,  0x1e,  0x14,  0x23,  0x24,  0xfe,  0xe9,  0x09,  0xfe,  0xc1,  0x59,  0x01,
+  0x0b,  0x1f,  0xfe,  0x1e,  0x14,  0x23,  0x24,  0xfe,  0xe8,  0x0a,  0x04,  0xf6,  0x29,  0xfe,  0xc4,  0x12,
+  0x2d,  0xb1,  0x1e,  0xdc,  0x59,  0xcd,  0x74,  0xfe,  0x6c,  0x13,  0x4b,  0x08,  0x06,  0x09,  0xcd,  0xa0,
+  0xfe,  0x00,  0x10,  0xfe,  0x78,  0x10,  0xff,  0x02,  0x83,  0x55,  0xa6,  0xff,  0x02,  0x83,  0x55,  0xb1,
+  0x19,  0xfe,  0x12,  0x13,  0x72,  0xfe,  0x30,  0x00,  0x8f,  0xfe,  0xc6,  0x13,  0x09,  0x85,  0x08,  0x06,
+  0xfe,  0x56,  0x10,  0xb1,  0x0c,  0xfe,  0x16,  0x13,  0x72,  0xfe,  0x64,  0x00,  0x8f,  0xfe,  0xc6,  0x13,
+  0x0e,  0xfe,  0x64,  0x00,  0x09,  0x88,  0x08,  0x06,  0xfe,  0x28,  0x10,  0xb1,  0x06,  0xfe,  0x60,  0x13,
+  0x72,  0xfe,  0xc8,  0x00,  0x8f,  0xfe,  0xc6,  0x13,  0x0e,  0xfe,  0xc8,  0x00,  0x09,  0x55,  0x08,  0x06,
+  0xa8,  0x72,  0xfe,  0x90,  0x01,  0xed,  0xfe,  0xd2,  0x13,  0x95,  0xaa,  0xfe,  0x43,  0xf4,  0xad,  0xfe,
+  0x56,  0xf0,  0xfe,  0xe4,  0x13,  0xfe,  0x04,  0xf4,  0x63,  0xfe,  0x43,  0xf4,  0x88,  0xfe,  0xf3,  0x10,
+  0xb0,  0x01,  0xfe,  0xae,  0x12,  0x1b,  0x50,  0xd4,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x6c,  0xed,
+  0xfe,  0x18,  0x14,  0xa3,  0x6c,  0xfe,  0x14,  0x10,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x1a,  0xed,
+  0xfe,  0x18,  0x14,  0xa3,  0x1a,  0x9e,  0x57,  0x95,  0x08,  0x06,  0xfe,  0xb4,  0x56,  0xfe,  0xc3,  0x58,
+  0x03,  0x57,  0x08,  0x0c,  0x03,  0x14,  0x06,  0x01,  0x0b,  0x25,  0xec,  0x14,  0x0c,  0x01,  0x0b,  0x25,
+  0xec,  0x14,  0x19,  0x01,  0x0b,  0x25,  0xec,  0x73,  0xfe,  0x89,  0x49,  0x01,  0x0b,  0x03,  0x14,  0x06,
+  0x01,  0x0b,  0x25,  0xb7,  0x14,  0x19,  0x01,  0x0b,  0x25,  0xb7,  0x14,  0x06,  0x01,  0x0b,  0x25,  0xb7,
+  0xfe,  0x89,  0x49,  0x01,  0x0b,  0x25,  0xb7,  0x73,  0xfe,  0x89,  0x4a,  0x01,  0x0b,  0x03,  0x57,  0x03,
+  0x21,  0xe0,  0x05,  0x06,  0xfe,  0x44,  0x13,  0xaf,  0x16,  0xe0,  0xfe,  0x49,  0xf4,  0x00,  0x4b,  0x73,
+  0xc6,  0x5a,  0xfe,  0x01,  0xec,  0xfe,  0x27,  0x01,  0xf1,  0x01,  0x0b,  0x3f,  0x05,  0xfe,  0xe3,  0x00,
+  0xfe,  0x20,  0x13,  0x1f,  0xfe,  0xd6,  0x14,  0x2d,  0x16,  0xf3,  0x01,  0x4c,  0x21,  0xf3,  0x05,  0x06,
+  0x40,  0x0a,  0x41,  0x06,  0x38,  0x03,  0x0f,  0x54,  0x12,  0x8a,  0xfe,  0x43,  0x58,  0x01,  0x15,  0x05,
+  0x10,  0xfe,  0x1e,  0x12,  0x48,  0xe7,  0x8e,  0x01,  0x2c,  0xfe,  0x90,  0x4d,  0xde,  0x10,  0xfe,  0xc5,
+  0x59,  0x01,  0x2c,  0xfe,  0x8d,  0x56,  0xb6,  0x48,  0x03,  0x48,  0x31,  0x8a,  0x01,  0x15,  0x48,  0x8e,
+  0x01,  0x2c,  0xe2,  0x10,  0xde,  0x10,  0x31,  0x54,  0x72,  0x1c,  0x84,  0x0e,  0x56,  0x01,  0xab,  0x03,
+  0x0f,  0x54,  0x12,  0x8a,  0xfe,  0xc3,  0x58,  0x01,  0x15,  0x05,  0x10,  0xfe,  0x1a,  0x12,  0x48,  0xe7,
+  0x8e,  0x01,  0x2c,  0xe2,  0x10,  0xfe,  0x80,  0x4d,  0xfe,  0xc5,  0x59,  0x01,  0x2c,  0x48,  0x03,  0x48,
+  0x31,  0x54,  0x01,  0x15,  0x48,  0x8e,  0x01,  0x2c,  0xe2,  0x10,  0xde,  0x10,  0x31,  0x54,  0x72,  0x1c,
+  0x84,  0x0e,  0x56,  0x01,  0xab,  0x03,  0x0f,  0x54,  0x12,  0x8a,  0xfe,  0x43,  0x58,  0x01,  0x15,  0xfe,
+  0x42,  0x48,  0x8e,  0x01,  0x2c,  0xfe,  0xc0,  0x5a,  0xb0,  0xfe,  0x00,  0xcd,  0xfe,  0x01,  0xcc,  0xfe,
+  0x4a,  0x46,  0xdc,  0x93,  0x7d,  0x05,  0x10,  0xfe,  0x2e,  0x13,  0x69,  0x54,  0xfe,  0x4d,  0xf4,  0x1c,
+  0xfe,  0x1c,  0x13,  0x0e,  0x56,  0x01,  0x8b,  0xaa,  0xfe,  0x40,  0x4c,  0xfe,  0xc5,  0x58,  0x01,  0x2c,
+  0xfe,  0x00,  0x07,  0x7d,  0x05,  0x10,  0x84,  0x69,  0x8a,  0xfe,  0x05,  0x57,  0xfe,  0x08,  0x10,  0xfe,
+  0x45,  0x58,  0x01,  0x2c,  0xfe,  0x8d,  0x56,  0xb6,  0xfe,  0x80,  0x4c,  0xfe,  0x05,  0x17,  0x03,  0x09,
+  0x10,  0x6f,  0x67,  0xfe,  0x60,  0x01,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x24,  0x1c,  0xdb,
+  0x37,  0x94,  0xfe,  0x1a,  0x16,  0x01,  0xfe,  0x28,  0x17,  0xfe,  0x0c,  0x13,  0x87,  0x37,  0x67,  0xfe,
+  0x2c,  0x01,  0xfe,  0x2f,  0x19,  0x03,  0xba,  0x27,  0xfe,  0x0a,  0x16,  0xfe,  0xe2,  0x10,  0x09,  0x10,
+  0x6f,  0x04,  0xfe,  0x64,  0x01,  0xfe,  0x00,  0xf4,  0x1a,  0xfe,  0x18,  0x58,  0x04,  0xfe,  0x66,  0x01,
+  0xfe,  0x19,  0x58,  0x87,  0x1a,  0xfe,  0x3c,  0x90,  0xfe,  0x30,  0xf4,  0x06,  0xfe,  0x3c,  0x50,  0x67,
+  0xfe,  0x38,  0x00,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0x1a,  0x94,  0xfe,  0x64,  0x16,  0xfe,  0xbe,
+  0x14,  0x35,  0x03,  0xba,  0x27,  0xfe,  0x3c,  0x16,  0xfe,  0xa4,  0x10,  0x09,  0x10,  0x6f,  0xb6,  0xfe,
+  0x18,  0xdf,  0xfe,  0x19,  0xdf,  0xdb,  0x42,  0x94,  0xfe,  0x86,  0x16,  0xfe,  0x9c,  0x14,  0xfe,  0x18,
+  0x13,  0x87,  0x42,  0x67,  0x1e,  0xfe,  0xaf,  0x19,  0xfe,  0x98,  0xe7,  0x00,  0xa2,  0x07,  0xfe,  0x7f,
+  0x00,  0xfe,  0x05,  0x40,  0x03,  0xba,  0x27,  0xfe,  0x7a,  0x16,  0xfe,  0x6c,  0x10,  0x09,  0x10,  0x6f,
+  0xfe,  0x30,  0xbc,  0xfe,  0xb2,  0xbc,  0x87,  0xd9,  0x67,  0x1e,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,
+  0xd9,  0x94,  0xfe,  0xc6,  0x16,  0xfe,  0x5c,  0x14,  0x35,  0x03,  0xba,  0x27,  0xfe,  0xb2,  0x16,  0xfe,
+  0x42,  0x10,  0xfe,  0x02,  0xf6,  0x10,  0x6f,  0xfe,  0x18,  0xfe,  0x5d,  0xfe,  0x19,  0xfe,  0x5e,  0xc8,
+  0xdb,  0x45,  0x94,  0xfe,  0xec,  0x16,  0xfe,  0x36,  0x14,  0xfe,  0x1c,  0x13,  0x87,  0x45,  0x4e,  0xfe,
+  0x83,  0x58,  0xfe,  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x10,  0xfe,  0x81,  0xe7,  0x10,  0x11,  0xfe,  0xdd,
+  0x00,  0x64,  0x2f,  0x03,  0x64,  0x2f,  0xfe,  0x12,  0x45,  0x27,  0xfe,  0xdc,  0x16,  0x17,  0x06,  0x4a,
+  0xf4,  0xdd,  0x02,  0x26,  0xfe,  0x39,  0xf0,  0xfe,  0x30,  0x17,  0x2d,  0x03,  0xfe,  0x7e,  0x18,  0x1b,
+  0x19,  0x83,  0x08,  0x0d,  0x03,  0x6f,  0x04,  0xdf,  0x1b,  0x06,  0xfe,  0xef,  0x12,  0xfe,  0xe1,  0x10,
+  0x1d,  0x0e,  0x1c,  0x01,  0x15,  0x05,  0x10,  0x40,  0x3e,  0xfe,  0x78,  0x14,  0xfe,  0x34,  0x12,  0x50,
+  0x86,  0x36,  0x37,  0xbf,  0xfe,  0xe9,  0x13,  0x1d,  0x0e,  0x3d,  0x01,  0x15,  0x05,  0x10,  0x40,  0x3e,
+  0xfe,  0x56,  0x14,  0xe1,  0x50,  0x86,  0x36,  0x37,  0xbf,  0xfe,  0xe9,  0x13,  0x09,  0x0c,  0x03,  0xfe,
+  0x9c,  0xe7,  0x0c,  0x13,  0xfe,  0x15,  0x00,  0x90,  0x9f,  0x2f,  0x01,  0xea,  0x09,  0x06,  0x03,  0x0a,
+  0x41,  0x37,  0x38,  0x08,  0x3d,  0x09,  0x99,  0x01,  0x46,  0x11,  0x47,  0x08,  0x1c,  0x09,  0x43,  0x01,
+  0x7b,  0x09,  0x06,  0x03,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,  0x65,  0xf7,  0x31,  0x76,  0xfe,  0x48,
+  0x55,  0x35,  0xfe,  0xc9,  0x55,  0x03,  0x21,  0xbe,  0x52,  0x16,  0xbe,  0x03,  0x0e,  0xc0,  0x01,  0x15,
+  0xe6,  0x0e,  0x79,  0x01,  0x15,  0xfe,  0x49,  0x44,  0x27,  0xfe,  0x26,  0x18,  0x0e,  0x1c,  0x01,  0x15,
+  0x05,  0x10,  0x40,  0x0e,  0x56,  0x01,  0xab,  0x0e,  0x79,  0x01,  0x15,  0x52,  0x7d,  0x03,  0xfe,  0x40,
+  0x5e,  0xfe,  0xe2,  0x08,  0xfe,  0xc0,  0x4c,  0x21,  0x3c,  0x05,  0x10,  0xfe,  0x52,  0x12,  0x3e,  0x05,
+  0x00,  0xfe,  0x18,  0x12,  0xfe,  0xe1,  0x18,  0xfe,  0x19,  0xf4,  0xfe,  0x7f,  0x00,  0xd4,  0xfe,  0xe2,
+  0x08,  0x52,  0x3e,  0x3f,  0x05,  0x76,  0xa5,  0xfe,  0x82,  0x48,  0xfe,  0x01,  0x80,  0xfe,  0xd7,  0x10,
+  0xfe,  0xc4,  0x48,  0x08,  0x2a,  0x09,  0x3c,  0xfe,  0x40,  0x5f,  0x1d,  0x01,  0x46,  0x11,  0xfe,  0xdd,
+  0x00,  0xfe,  0x14,  0x46,  0x08,  0x2a,  0x09,  0x3c,  0x01,  0x46,  0x11,  0xfe,  0xdd,  0x00,  0xfe,  0x40,
+  0x4a,  0x6a,  0xfe,  0x06,  0x17,  0xfe,  0x01,  0x07,  0xfe,  0x82,  0x48,  0xfe,  0x04,  0x17,  0x03,  0xeb,
+  0x19,  0x74,  0xfe,  0xae,  0x18,  0x04,  0xfe,  0x90,  0x00,  0xfe,  0x3a,  0x45,  0xfe,  0x2c,  0x10,  0xeb,
+  0xcc,  0x74,  0xfe,  0xc0,  0x18,  0x04,  0xfe,  0x92,  0x00,  0xc7,  0x1e,  0xd8,  0xeb,  0xfe,  0x0b,  0x00,
+  0x74,  0xfe,  0xd2,  0x18,  0x04,  0xfe,  0x94,  0x00,  0xc7,  0x1a,  0xfe,  0x08,  0x10,  0x04,  0xfe,  0x96,
+  0x00,  0xc7,  0x85,  0xfe,  0x4e,  0x45,  0xd1,  0xfe,  0x0a,  0x45,  0xff,  0x04,  0x68,  0x54,  0xfe,  0xf1,
+  0x10,  0x1b,  0x6c,  0x03,  0x05,  0x80,  0xfe,  0x5a,  0xf0,  0xfe,  0xfe,  0x18,  0x20,  0xfe,  0x09,  0x00,
+  0xfe,  0x34,  0x10,  0x05,  0x1e,  0xfe,  0x5a,  0xf0,  0xfe,  0x0c,  0x19,  0x20,  0xcd,  0xfe,  0x26,  0x10,
+  0x05,  0x19,  0x83,  0x20,  0x85,  0xd8,  0x05,  0x0c,  0x83,  0x20,  0x88,  0xfe,  0x0e,  0x10,  0x05,  0x06,
+  0x83,  0x20,  0x55,  0xc6,  0xaf,  0x03,  0x17,  0xfe,  0x09,  0x00,  0x01,  0x44,  0x2e,  0xfe,  0x3c,  0x19,
+  0x04,  0x6e,  0xb0,  0x03,  0x22,  0xfe,  0x54,  0x19,  0xfe,  0x14,  0xf0,  0x0b,  0x2e,  0xfe,  0x50,  0x19,
+  0x03,  0xff,  0x15,  0x00,  0x00,
+};
 
 STATIC unsigned short _adv_asc3550_size =
-    sizeof(_adv_asc3550_buf); /* 0x13AA */
-STATIC unsigned long _adv_asc3550_chksum =
-    0x04F4788EUL; /* Expanded checksum. */
+    sizeof(_adv_asc3550_buf); /* 0x13E5 */
+STATIC ADV_DCNT _adv_asc3550_chksum =
+    0x04FFFF0E; /* Expanded checksum. */
 
 STATIC unsigned char _adv_asc38C0800_buf[] = {
-  0x00,  0x00,  0x00,  0xf2,  0x00,  0xf0,  0x00,  0x16,  0x00,  0xfc,  0x48,  0xe4,  0x01,  0x00,  0x00,  0xf6,
-  0x18,  0xe4,  0x01,  0xf6,  0x18,  0x80,  0x02,  0x00,  0x02,  0x1a,  0xff,  0xff,  0x00,  0xfa,  0x03,  0xf6,
-  0xff,  0x00,  0x82,  0xe7,  0x01,  0xfa,  0x9e,  0xe7,  0x09,  0xe7,  0xe6,  0x0e,  0x00,  0xea,  0x01,  0xe6,
-  0x03,  0x00,  0x1e,  0xf0,  0x55,  0xf0,  0x18,  0xf4,  0x3e,  0x57,  0x04,  0x00,  0x3e,  0x01,  0x85,  0xf0,
-  0x00,  0xe6,  0x03,  0xfc,  0x08,  0x00,  0x32,  0xf0,  0x38,  0x54,  0x84,  0x0d,  0x86,  0xf0,  0xd4,  0x01,
-  0xd5,  0xf0,  0xee,  0x19,  0x00,  0xec,  0x01,  0xfc,  0x98,  0x57,  0xbc,  0x00,  0x10,  0x13,  0xb1,  0xf0,
-  0x02,  0x13,  0x3c,  0x00,  0x7e,  0x0d,  0xb4,  0x00,  0x00,  0x57,  0x01,  0xf0,  0x02,  0xfc,  0x03,  0xe6,
-  0x0c,  0x1c,  0x10,  0x00,  0x18,  0x40,  0x3e,  0x1c,  0xbd,  0x00,  0xe0,  0x00,  0x02,  0x80,  0x3e,  0x00,
-  0x46,  0x16,  0x4a,  0x10,  0x6c,  0x01,  0x6e,  0x01,  0x74,  0x01,  0x76,  0x01,  0xb9,  0x54,  0xba,  0x13,
-  0xbb,  0x00,  0x00,  0x4e,  0x01,  0x01,  0x01,  0xea,  0x02,  0x48,  0x02,  0xfa,  0x08,  0x12,  0x30,  0xe4,
-  0x3c,  0x56,  0x4e,  0x01,  0x5d,  0xf0,  0x7a,  0x01,  0x88,  0x0d,  0x8e,  0x10,  0xb6,  0x00,  0xc4,  0x08,
-  0x00,  0x80,  0x04,  0x12,  0x05,  0xfc,  0x24,  0x01,  0x28,  0x01,  0x32,  0x00,  0x3c,  0x01,  0x40,  0x00,
-  0x4b,  0xe4,  0x4b,  0xf4,  0x4c,  0x1c,  0x68,  0x01,  0x6a,  0x01,  0x70,  0x01,  0x72,  0x01,  0x78,  0x01,
-  0x7c,  0x01,  0xbb,  0x55,  0x00,  0x01,  0x02,  0xee,  0x03,  0x58,  0x03,  0xf7,  0x03,  0xfa,  0x04,  0x80,
-  0x08,  0x44,  0x09,  0xf0,  0x10,  0x44,  0x1b,  0x80,  0x20,  0x01,  0x38,  0x1c,  0x4e,  0x1c,  0x5b,  0xf0,
-  0x80,  0x00,  0x8a,  0x15,  0x98,  0x10,  0xaa,  0x00,  0xbd,  0x56,  0xbe,  0x00,  0xc0,  0x00,  0x00,  0x4c,
-  0x00,  0xdc,  0x02,  0x4a,  0x04,  0xfc,  0x05,  0xf0,  0x05,  0xf8,  0x06,  0x13,  0x06,  0xf7,  0x08,  0x13,
-  0x0c,  0x00,  0x0e,  0x47,  0x0e,  0xf7,  0x0f,  0x00,  0x1c,  0x0c,  0x20,  0x00,  0x2a,  0x01,  0x32,  0x1c,
-  0x36,  0x00,  0x42,  0x54,  0x44,  0x0b,  0x44,  0x55,  0x45,  0x5a,  0x59,  0xf0,  0x5c,  0xf0,  0x62,  0x0a,
-  0x69,  0x08,  0x78,  0x13,  0x83,  0x59,  0x8e,  0x18,  0x9a,  0x10,  0x9a,  0x18,  0xb8,  0xf0,  0xd6,  0x0e,
-  0xea,  0x15,  0xf0,  0x00,  0x04,  0x10,  0x04,  0xea,  0x04,  0xf6,  0x05,  0x00,  0x06,  0x00,  0x06,  0x12,
-  0x0a,  0x10,  0x0a,  0x12,  0x0b,  0xf0,  0x0c,  0x10,  0x0c,  0xf0,  0x12,  0x10,  0x19,  0x00,  0x19,  0xe4,
-  0x2a,  0x12,  0x30,  0x1c,  0x33,  0x00,  0x34,  0x00,  0x36,  0x15,  0x38,  0x44,  0x3a,  0x15,  0x40,  0x5c,
-  0x4a,  0xe4,  0x62,  0x1a,  0x68,  0x08,  0x68,  0x54,  0x7a,  0x17,  0x83,  0x55,  0x83,  0x5a,  0x91,  0x44,
-  0xa2,  0x10,  0xa4,  0x00,  0xb0,  0x57,  0xb5,  0x00,  0xba,  0x00,  0xcc,  0x0e,  0xce,  0x45,  0xd0,  0x00,
-  0xe1,  0x00,  0xe5,  0x55,  0xe7,  0x00,  0x00,  0x54,  0x01,  0x48,  0x01,  0x58,  0x02,  0x10,  0x02,  0xe6,
-  0x03,  0xa1,  0x04,  0x13,  0x05,  0xe6,  0x06,  0x83,  0x06,  0xf0,  0x07,  0x00,  0x0a,  0x00,  0x0a,  0xf0,
-  0x0c,  0x12,  0x0c,  0x13,  0x0e,  0x13,  0x10,  0x04,  0x10,  0x10,  0x12,  0x1c,  0x19,  0x81,  0x1a,  0x10,
-  0x1c,  0x00,  0x1c,  0x12,  0x1c,  0x13,  0x1d,  0xf7,  0x1e,  0x13,  0x20,  0x1c,  0x20,  0xe7,  0x22,  0x01,
-  0x26,  0x01,  0x30,  0xe7,  0x38,  0x12,  0x3a,  0x55,  0x3f,  0x00,  0x41,  0x58,  0x43,  0x48,  0x46,  0x1c,
-  0x4e,  0xe4,  0x5a,  0x13,  0x68,  0x13,  0x72,  0x14,  0x76,  0x02,  0x77,  0x57,  0x78,  0x03,  0x89,  0x48,
-  0x8a,  0x13,  0x98,  0x80,  0x99,  0x00,  0x9b,  0x00,  0x9c,  0x32,  0xfe,  0x9c,  0xf0,  0x27,  0x02,  0xfe,
-  0xa6,  0x0d,  0xff,  0x10,  0x00,  0x00,  0xfe,  0xc6,  0x01,  0xfe,  0x18,  0x1a,  0x00,  0xfe,  0xc4,  0x01,
-  0xfe,  0x84,  0x01,  0xff,  0x03,  0x00,  0x00,  0x30,  0xfe,  0x01,  0x05,  0xff,  0x40,  0x00,  0x00,  0x0d,
-  0xff,  0x09,  0x00,  0x00,  0xff,  0x08,  0x01,  0x01,  0xff,  0x10,  0xff,  0xff,  0xff,  0x1f,  0x00,  0x00,
-  0xff,  0x10,  0xff,  0xff,  0xff,  0x11,  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,
-  0x00,  0x00,  0xfe,  0x04,  0xf7,  0xfe,  0xc4,  0x01,  0x38,  0x86,  0x0b,  0x01,  0xfe,  0x96,  0x0f,  0xfe,
-  0x04,  0xf7,  0xfe,  0xc4,  0x01,  0x86,  0x0b,  0x1c,  0x38,  0xfe,  0x3d,  0xf0,  0xfe,  0xfc,  0x01,  0xfe,
-  0x20,  0xf0,  0xdb,  0x04,  0x5e,  0x59,  0x02,  0xfe,  0xc2,  0x0d,  0x01,  0xfe,  0x22,  0x0e,  0xfe,  0xe9,
-  0x12,  0x02,  0xfe,  0x08,  0x03,  0xfe,  0x28,  0x1c,  0x04,  0xfe,  0xa6,  0x00,  0xfe,  0xdd,  0x12,  0x46,
-  0x12,  0xfe,  0xa6,  0x00,  0xcd,  0xfe,  0x48,  0xf0,  0xfe,  0x80,  0x02,  0xfe,  0x49,  0xf0,  0xfe,  0x9a,
-  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xb8,  0x02,  0xfe,  0x46,  0xf0,  0xfe,  0x4a,  0x02,  0xfe,  0x47,  0xf0,
-  0xfe,  0x50,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x3e,  0x02,  0xfe,  0x44,  0xf0,  0xfe,  0x42,  0x02,  0xfe,
-  0x45,  0xf0,  0xfe,  0x46,  0x02,  0x09,  0x0b,  0xa2,  0x09,  0x06,  0x12,  0xc1,  0x02,  0x27,  0xfe,  0x00,
-  0x1c,  0xfe,  0xf1,  0x10,  0xfe,  0x02,  0x1c,  0xfe,  0xed,  0x10,  0xfe,  0x1e,  0x1c,  0xfe,  0xe9,  0x10,
-  0x01,  0xfe,  0xee,  0x17,  0xfe,  0xe7,  0x10,  0xfe,  0x06,  0xfc,  0xfe,  0xa8,  0x00,  0x0f,  0x7d,  0x01,
-  0xc5,  0x02,  0x27,  0x17,  0x5d,  0x4b,  0xc3,  0x01,  0xab,  0x0f,  0x7d,  0x01,  0x9f,  0xfe,  0xbd,  0x10,
-  0x0f,  0x7d,  0x01,  0x9f,  0xfe,  0xad,  0x10,  0xfe,  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x09,  0x06,  0x12,
-  0xc1,  0x38,  0x19,  0x27,  0xfe,  0x3d,  0xf0,  0xfe,  0xfc,  0x01,  0x28,  0xfe,  0x8e,  0x02,  0xfe,  0x5a,
-  0x1c,  0xdd,  0xfe,  0x14,  0x1c,  0x17,  0xfe,  0x30,  0x00,  0x4b,  0xc3,  0x01,  0xfe,  0xfc,  0x0f,  0x09,
-  0x06,  0x12,  0xc1,  0x02,  0xfe,  0xc6,  0x01,  0x2a,  0x2d,  0x05,  0x10,  0x30,  0xfe,  0x69,  0x10,  0x09,
-  0x06,  0x12,  0xc1,  0xfe,  0x04,  0xec,  0x2d,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x01,  0x40,  0x81,  0xfe,
-  0x05,  0xf6,  0xfe,  0xa8,  0x00,  0x01,  0xfe,  0x20,  0x17,  0x0a,  0x4f,  0x8d,  0x3a,  0x11,  0x48,  0x1c,
-  0xd3,  0x07,  0x1e,  0x09,  0x51,  0x01,  0xa0,  0x02,  0x27,  0x0f,  0x3d,  0x01,  0x15,  0x05,  0x10,  0xda,
-  0x07,  0x1e,  0x09,  0x51,  0x01,  0x79,  0xfe,  0x28,  0x10,  0x0f,  0xc7,  0x01,  0x15,  0xed,  0x0f,  0x7e,
-  0x01,  0x15,  0xfe,  0x49,  0x54,  0x77,  0xfe,  0x16,  0x03,  0x07,  0x1e,  0x09,  0x51,  0x01,  0xa0,  0x02,
-  0x27,  0x38,  0x81,  0xfe,  0x02,  0xe8,  0x33,  0xfe,  0xbf,  0x57,  0xfe,  0x9e,  0x43,  0xf5,  0xfe,  0x07,
-  0x4b,  0xfe,  0x20,  0xf0,  0xdb,  0xfe,  0x40,  0x1c,  0x19,  0xf6,  0xfe,  0x26,  0xf0,  0xfe,  0x74,  0x03,
-  0xfe,  0xa0,  0xf0,  0xfe,  0x62,  0x03,  0xfe,  0x11,  0xf0,  0xdb,  0xfe,  0x0e,  0x10,  0xfe,  0x9f,  0xf0,
-  0xfe,  0x82,  0x03,  0xef,  0x13,  0xfe,  0x11,  0x00,  0x02,  0x54,  0x38,  0xfe,  0x48,  0x1c,  0xef,  0x19,
-  0xf6,  0x35,  0xf6,  0xfe,  0x82,  0xf0,  0xfe,  0x88,  0x03,  0x24,  0x2a,  0xc4,  0x70,  0x16,  0xc4,  0x0f,
-  0x7e,  0x01,  0x15,  0x70,  0x7f,  0x07,  0x1e,  0x09,  0x51,  0x01,  0x40,  0x11,  0x3d,  0x07,  0x3d,  0x09,
-  0xa1,  0x01,  0xa0,  0xfc,  0x11,  0xfe,  0xe4,  0x00,  0x2f,  0xfe,  0xce,  0x03,  0x19,  0x32,  0x1f,  0xfe,
-  0xde,  0x03,  0x01,  0x41,  0xd4,  0xfe,  0xee,  0x03,  0x71,  0x8c,  0xd7,  0xfe,  0xae,  0x06,  0x02,  0x25,
-  0x04,  0x7d,  0x2c,  0x1a,  0xfe,  0x20,  0x05,  0x17,  0x88,  0x01,  0x2e,  0x01,  0x9b,  0x01,  0x9d,  0x35,
-  0xfe,  0x60,  0x02,  0x02,  0xf4,  0xef,  0x38,  0x86,  0x18,  0xfe,  0x67,  0x1b,  0xfe,  0xbf,  0x57,  0xf5,
-  0xfe,  0x48,  0x1c,  0x8f,  0x01,  0xf2,  0xb1,  0xfe,  0x96,  0xf0,  0xfe,  0x28,  0x04,  0x2f,  0xfe,  0x2c,
-  0x04,  0x35,  0x27,  0x0f,  0x3d,  0x01,  0x15,  0x05,  0x10,  0x1a,  0xfe,  0x0c,  0x05,  0x4c,  0x97,  0xa3,
-  0x33,  0x84,  0x74,  0x19,  0x32,  0x1f,  0x25,  0x04,  0x7d,  0x2c,  0xfe,  0x10,  0x12,  0x17,  0x88,  0x01,
-  0x2e,  0x35,  0xfe,  0x60,  0x02,  0x02,  0xf4,  0x21,  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x5e,
-  0x12,  0x0a,  0x08,  0x06,  0xfe,  0x56,  0x12,  0x23,  0x29,  0x98,  0x01,  0x0c,  0x84,  0x74,  0x1f,  0xfe,
-  0xdc,  0x04,  0x23,  0x29,  0x98,  0x01,  0x0c,  0x1f,  0x25,  0x23,  0x29,  0xba,  0xfe,  0x4c,  0x44,  0xfe,
-  0x32,  0x12,  0x50,  0xfe,  0x44,  0x48,  0x07,  0xfe,  0x93,  0x00,  0xfe,  0x4c,  0x54,  0x77,  0xfe,  0x0c,
-  0x05,  0x81,  0xa3,  0x33,  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x48,  0x13,  0x3e,  0x05,  0xfe,
-  0xcc,  0x00,  0xfe,  0x40,  0x13,  0x0a,  0x08,  0x06,  0xea,  0xfe,  0x06,  0x10,  0x23,  0x29,  0xba,  0x0a,
-  0x08,  0x39,  0xe1,  0x17,  0xa6,  0x0a,  0x08,  0x06,  0x59,  0x17,  0xfe,  0x0d,  0x00,  0x01,  0x2e,  0x35,
-  0xfe,  0x66,  0x0d,  0x02,  0x25,  0x3b,  0x11,  0xfe,  0xe6,  0x00,  0xfe,  0x1c,  0x90,  0xb7,  0x03,  0x17,
-  0xa6,  0x01,  0x2e,  0x35,  0x27,  0x19,  0x27,  0x02,  0xfe,  0x14,  0x05,  0xfe,  0x42,  0x5b,  0x86,  0x18,
-  0xfe,  0x46,  0x59,  0xfe,  0xbf,  0x57,  0xf5,  0x17,  0x78,  0xfe,  0x07,  0x80,  0xfe,  0x31,  0x44,  0x0a,
-  0x08,  0x0b,  0x99,  0xfe,  0x20,  0x80,  0x05,  0x18,  0xfe,  0x70,  0x12,  0x73,  0x08,  0x06,  0xfe,  0x60,
-  0x13,  0x04,  0xfe,  0xa2,  0x00,  0x2c,  0x1a,  0xfe,  0xac,  0x05,  0xfe,  0x31,  0xe4,  0x5f,  0x73,  0x08,
-  0x0b,  0xfe,  0x4a,  0x13,  0x04,  0xfe,  0xa0,  0x00,  0x2c,  0xfe,  0x42,  0x12,  0x62,  0x2f,  0xfe,  0x6c,
-  0x05,  0x19,  0x32,  0xf7,  0x01,  0x0c,  0x26,  0xfe,  0xc4,  0x05,  0x11,  0xfe,  0xe3,  0x00,  0x24,  0x73,
-  0xfe,  0x4a,  0xf0,  0xfe,  0x96,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0x90,  0x05,  0xab,  0x20,  0xfe,  0x21,
-  0x00,  0xa8,  0x20,  0xfe,  0x22,  0x00,  0xa2,  0x20,  0x8d,  0xfe,  0x09,  0x48,  0x01,  0x0c,  0x26,  0xfe,
-  0xc4,  0x05,  0xfe,  0xe2,  0x08,  0x73,  0x08,  0xe0,  0x59,  0x01,  0x99,  0x20,  0x06,  0x16,  0xe8,  0x4b,
-  0xfe,  0x27,  0x01,  0x0a,  0x08,  0x39,  0xb0,  0x46,  0x01,  0xb6,  0x17,  0xa6,  0x0a,  0x08,  0x06,  0x59,
-  0x17,  0xfe,  0x0d,  0x00,  0x01,  0x2e,  0x01,  0x9b,  0x01,  0x9d,  0x35,  0xfe,  0x66,  0x0d,  0x02,  0x25,
-  0x04,  0xfe,  0x9c,  0x00,  0x2c,  0xfe,  0x3e,  0x12,  0x04,  0x5b,  0x2c,  0xfe,  0x36,  0x13,  0x46,  0x01,
-  0xb6,  0x26,  0xfe,  0x3c,  0x06,  0x0f,  0x06,  0x73,  0x08,  0x22,  0xfe,  0x02,  0x12,  0x69,  0x01,  0xfe,
-  0xd0,  0x14,  0x1f,  0xfe,  0x32,  0x06,  0x11,  0xc8,  0x01,  0x41,  0x11,  0xfe,  0xe5,  0x00,  0x04,  0x5b,
-  0xc2,  0x0e,  0x5b,  0x04,  0xfe,  0x9e,  0x00,  0x2c,  0xfe,  0x62,  0x12,  0x04,  0x56,  0x2c,  0xf1,  0x01,
-  0xfe,  0x40,  0x19,  0x01,  0xfe,  0xaa,  0x19,  0xee,  0xd2,  0xec,  0x07,  0x6a,  0xff,  0x02,  0x00,  0x57,
-  0x6c,  0x80,  0x1b,  0x58,  0xd1,  0xd2,  0x8b,  0x46,  0x01,  0xb6,  0x26,  0xfe,  0xa6,  0x06,  0x73,  0x08,
-  0x1d,  0xa7,  0x7c,  0x0f,  0x5d,  0x01,  0xfe,  0xfe,  0x14,  0x1f,  0xfe,  0x9c,  0x06,  0x11,  0xc8,  0x01,
-  0x41,  0x11,  0xfe,  0xe5,  0x00,  0x04,  0x56,  0xc2,  0x0e,  0x56,  0x09,  0x06,  0x01,  0xb6,  0xfc,  0x76,
-  0x8f,  0x01,  0xf2,  0xb1,  0x11,  0xfe,  0xe2,  0x00,  0x2f,  0xfe,  0xbe,  0x06,  0x19,  0x32,  0xd7,  0xfe,
-  0xda,  0x06,  0x83,  0xfe,  0x78,  0x07,  0xd4,  0xfe,  0x80,  0x07,  0x71,  0x8c,  0x02,  0x25,  0x0a,  0x08,
+  0x00,  0x00,  0x00,  0xf2,  0x00,  0xf0,  0x00,  0x16,  0x00,  0xfc,  0x48,  0xe4,  0x01,  0x00,  0x18,  0xe4,
+  0x00,  0xf6,  0x01,  0xf6,  0x18,  0x80,  0x02,  0x00,  0x40,  0x1a,  0x00,  0xfa,  0xff,  0xff,  0x03,  0xf6,
+  0xff,  0x00,  0x82,  0xe7,  0x01,  0xfa,  0x9e,  0xe7,  0x09,  0xe7,  0x1a,  0x0f,  0x00,  0xea,  0x01,  0xe6,
+  0x03,  0x00,  0x55,  0xf0,  0x18,  0xf4,  0x1e,  0xf0,  0x3e,  0x57,  0x04,  0x00,  0x3e,  0x01,  0x85,  0xf0,
+  0x00,  0xe6,  0x03,  0xfc,  0x08,  0x00,  0x2c,  0x1a,  0x32,  0xf0,  0x86,  0xf0,  0xbe,  0x0d,  0xd4,  0x01,
+  0xd5,  0xf0,  0x00,  0xec,  0x01,  0xfc,  0x38,  0x54,  0x98,  0x57,  0xbc,  0x00,  0x0c,  0x1c,  0xb1,  0xf0,
+  0x3c,  0x00,  0xb4,  0x00,  0xb8,  0x0d,  0x00,  0x57,  0x01,  0xf0,  0x02,  0x13,  0x02,  0xfc,  0x03,  0xe6,
+  0x10,  0x00,  0x18,  0x40,  0x3e,  0x1c,  0x44,  0x13,  0x6c,  0x01,  0x6e,  0x01,  0xbd,  0x00,  0xe0,  0x00,
+  0x02,  0x80,  0x30,  0xe4,  0x3e,  0x00,  0x74,  0x01,  0x76,  0x01,  0x7c,  0x16,  0x80,  0x00,  0xb9,  0x54,
+  0xbb,  0x00,  0xee,  0x13,  0x00,  0x4e,  0x01,  0x01,  0x01,  0xea,  0x02,  0x48,  0x02,  0xfa,  0x04,  0x12,
+  0x08,  0x12,  0x3c,  0x56,  0x4e,  0x01,  0x5d,  0xf0,  0x7a,  0x01,  0x7e,  0x10,  0xb6,  0x00,  0xc2,  0x10,
+  0xee,  0x08,  0x00,  0x80,  0x05,  0xfc,  0x10,  0x44,  0x24,  0x01,  0x28,  0x01,  0x32,  0x00,  0x3c,  0x01,
+  0x40,  0x00,  0x4b,  0xe4,  0x4b,  0xf4,  0x4c,  0x1c,  0x68,  0x01,  0x6a,  0x01,  0x70,  0x01,  0x72,  0x01,
+  0x78,  0x01,  0x7c,  0x01,  0xbb,  0x55,  0xc2,  0x0d,  0x00,  0x01,  0x02,  0xee,  0x03,  0x58,  0x03,  0xf7,
+  0x03,  0xfa,  0x04,  0x80,  0x08,  0x44,  0x09,  0xf0,  0x0f,  0x00,  0x1b,  0x80,  0x20,  0x01,  0x38,  0x1c,
+  0x4e,  0x1c,  0x5b,  0xf0,  0x62,  0x0a,  0xaa,  0x00,  0xbe,  0x00,  0xc0,  0x00,  0xc0,  0x15,  0xcc,  0x10,
+  0x00,  0x4c,  0x00,  0xdc,  0x02,  0x4a,  0x04,  0xfc,  0x05,  0x00,  0x05,  0xf0,  0x05,  0xf8,  0x06,  0x13,
+  0x06,  0xf7,  0x08,  0x13,  0x0a,  0x10,  0x0c,  0x00,  0x0e,  0x47,  0x0e,  0xf7,  0x10,  0x0f,  0x20,  0x00,
+  0x20,  0x16,  0x2a,  0x01,  0x32,  0x1c,  0x36,  0x00,  0x42,  0x54,  0x44,  0x55,  0x45,  0x5a,  0x52,  0x0c,
+  0x59,  0xf0,  0x5c,  0xf0,  0x69,  0x08,  0x6e,  0x0b,  0x83,  0x59,  0xb8,  0xf0,  0xbd,  0x56,  0xcc,  0x18,
+  0xce,  0x10,  0xd8,  0x18,  0xf0,  0x00,  0x01,  0x48,  0x04,  0x10,  0x04,  0xea,  0x04,  0xf6,  0x05,  0x80,
+  0x05,  0xe6,  0x06,  0x00,  0x06,  0x0f,  0x06,  0x12,  0x0b,  0xf0,  0x0c,  0x10,  0x0c,  0xf0,  0x10,  0x13,
+  0x12,  0x10,  0x19,  0x00,  0x19,  0xe4,  0x30,  0x1c,  0x33,  0x00,  0x34,  0x00,  0x38,  0x44,  0x40,  0x5c,
+  0x4a,  0xe4,  0x62,  0x1a,  0x68,  0x08,  0x68,  0x54,  0x6c,  0x15,  0x70,  0x15,  0x83,  0x55,  0x83,  0x5a,
+  0x91,  0x44,  0xa4,  0x00,  0xac,  0x13,  0xb0,  0x57,  0xb5,  0x00,  0xb8,  0x17,  0xba,  0x00,  0xce,  0x45,
+  0xd0,  0x00,  0xe1,  0x00,  0xe5,  0x55,  0xe7,  0x00,  0x00,  0x54,  0x01,  0x58,  0x02,  0x10,  0x02,  0xe6,
+  0x03,  0xa1,  0x04,  0x13,  0x06,  0x83,  0x06,  0xf0,  0x07,  0x00,  0x0a,  0x00,  0x0a,  0x12,  0x0a,  0xf0,
+  0x0c,  0x12,  0x0c,  0x13,  0x0c,  0x90,  0x0e,  0x13,  0x10,  0x04,  0x10,  0x10,  0x12,  0x1c,  0x19,  0x81,
+  0x1a,  0x10,  0x1c,  0x00,  0x1c,  0x12,  0x1d,  0xf7,  0x1e,  0x13,  0x20,  0x1c,  0x20,  0xe7,  0x22,  0x01,
+  0x26,  0x01,  0x2a,  0x12,  0x2c,  0x0f,  0x30,  0xe7,  0x32,  0x15,  0x34,  0x1c,  0x36,  0x1c,  0x38,  0x12,
+  0x3a,  0x55,  0x3f,  0x00,  0x41,  0x58,  0x43,  0x48,  0x46,  0x1c,  0x4e,  0xe4,  0x76,  0x02,  0x77,  0x57,
+  0x78,  0x03,  0x89,  0x48,  0x8e,  0x90,  0x98,  0x80,  0x99,  0x00,  0xfe,  0x9c,  0xf0,  0x27,  0x02,  0xfe,
+  0xe0,  0x0d,  0xff,  0x10,  0x00,  0x00,  0xfe,  0xc6,  0x01,  0xfe,  0x56,  0x1a,  0x00,  0xfe,  0xc4,  0x01,
+  0xfe,  0x84,  0x01,  0xff,  0x03,  0x00,  0x00,  0xfe,  0x6a,  0x13,  0xfe,  0x05,  0x05,  0xff,  0x40,  0x00,
+  0x00,  0x0e,  0xff,  0x09,  0x00,  0x00,  0xff,  0x08,  0x01,  0x01,  0xff,  0x10,  0xff,  0xff,  0xff,  0x1f,
+  0x00,  0x00,  0xff,  0x10,  0xff,  0xff,  0xff,  0x11,  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,
+  0xff,  0x21,  0x00,  0x00,  0xfe,  0x04,  0xf7,  0xfe,  0xc4,  0x01,  0x2e,  0x88,  0x0b,  0x01,  0xfe,  0xca,
+  0x0f,  0xfe,  0x04,  0xf7,  0xfe,  0xc4,  0x01,  0x88,  0x0b,  0x1c,  0x2e,  0xfe,  0x3d,  0xf0,  0xfe,  0xfc,
+  0x01,  0xfe,  0x20,  0xf0,  0xdc,  0x04,  0x5f,  0x4f,  0x02,  0xfe,  0xfc,  0x0d,  0x01,  0xfe,  0x5c,  0x0e,
+  0xfe,  0xe9,  0x12,  0x02,  0xfe,  0x08,  0x03,  0xfe,  0x28,  0x1c,  0x04,  0xfe,  0xa6,  0x00,  0xfe,  0xdd,
+  0x12,  0x47,  0x12,  0xfe,  0xa6,  0x00,  0xcd,  0xfe,  0x48,  0xf0,  0xfe,  0x80,  0x02,  0xfe,  0x49,  0xf0,
+  0xfe,  0x9a,  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xb8,  0x02,  0xfe,  0x46,  0xf0,  0xfe,  0x4a,  0x02,  0xfe,
+  0x47,  0xf0,  0xfe,  0x50,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x3e,  0x02,  0xfe,  0x44,  0xf0,  0xfe,  0x42,
+  0x02,  0xfe,  0x45,  0xf0,  0xfe,  0x46,  0x02,  0x09,  0x0b,  0xa4,  0x09,  0x06,  0x12,  0xc1,  0x02,  0x27,
+  0xfe,  0x00,  0x1c,  0xfe,  0xf1,  0x10,  0xfe,  0x02,  0x1c,  0xfe,  0xed,  0x10,  0xfe,  0x1e,  0x1c,  0xfe,
+  0xe9,  0x10,  0x01,  0xfe,  0x2c,  0x18,  0xfe,  0xe7,  0x10,  0xfe,  0x06,  0xfc,  0xfe,  0xa8,  0x00,  0x0f,
+  0x7c,  0x01,  0xaa,  0x02,  0x27,  0x17,  0x5e,  0x4c,  0xc4,  0x01,  0xfe,  0x40,  0x10,  0x0f,  0x7c,  0x01,
+  0x8e,  0xfe,  0xbd,  0x10,  0x0f,  0x7c,  0x01,  0x8e,  0xfe,  0xad,  0x10,  0xfe,  0x16,  0x1c,  0xfe,  0x58,
+  0x1c,  0x09,  0x06,  0x12,  0xc1,  0x2e,  0x1b,  0x27,  0xfe,  0x3d,  0xf0,  0xfe,  0xfc,  0x01,  0x28,  0xfe,
+  0x8e,  0x02,  0xfe,  0x5a,  0x1c,  0xde,  0xfe,  0x14,  0x1c,  0x17,  0xfe,  0x30,  0x00,  0x4c,  0xc4,  0x01,
+  0xfe,  0x30,  0x10,  0x09,  0x06,  0x12,  0xc1,  0x02,  0xfe,  0xc6,  0x01,  0x29,  0x2d,  0x05,  0x10,  0x35,
+  0xfe,  0x69,  0x10,  0x09,  0x06,  0x12,  0xc1,  0xfe,  0x04,  0xec,  0x2d,  0x08,  0x2d,  0x09,  0x3e,  0x1c,
+  0x01,  0x45,  0x82,  0xfe,  0x05,  0xf6,  0xfe,  0xa8,  0x00,  0x01,  0xfe,  0x56,  0x17,  0x0a,  0x41,  0x8f,
+  0x39,  0x11,  0x48,  0x1c,  0xd2,  0x08,  0x1e,  0x09,  0x52,  0x01,  0x90,  0x02,  0x27,  0x0f,  0x3f,  0x01,
+  0x15,  0x05,  0x10,  0xdb,  0x08,  0x1e,  0x09,  0x52,  0x01,  0x7e,  0xfe,  0x28,  0x10,  0x0f,  0xc8,  0x01,
+  0x15,  0xf2,  0x0f,  0x7d,  0x01,  0x15,  0xfe,  0x49,  0x54,  0x79,  0xfe,  0x16,  0x03,  0x08,  0x1e,  0x09,
+  0x52,  0x01,  0x90,  0x02,  0x27,  0x2e,  0x82,  0xfe,  0x02,  0xe8,  0x31,  0xfe,  0xbf,  0x57,  0xfe,  0x9e,
+  0x43,  0xf7,  0xfe,  0x07,  0x4b,  0xfe,  0x20,  0xf0,  0xdc,  0xfe,  0x40,  0x1c,  0x1b,  0xf8,  0xfe,  0x26,
+  0xf0,  0xfe,  0x74,  0x03,  0xfe,  0xa0,  0xf0,  0xfe,  0x62,  0x03,  0xfe,  0x11,  0xf0,  0xdc,  0xfe,  0x0e,
+  0x10,  0xfe,  0x9f,  0xf0,  0xfe,  0x82,  0x03,  0xf4,  0x13,  0xfe,  0x11,  0x00,  0x02,  0x6b,  0x2e,  0xfe,
+  0x48,  0x1c,  0xf4,  0x1b,  0xf8,  0x34,  0xf8,  0xfe,  0x82,  0xf0,  0xfe,  0x88,  0x03,  0x2b,  0x29,  0xc6,
+  0x72,  0x16,  0xc6,  0x0f,  0x7d,  0x01,  0x15,  0x72,  0x80,  0x08,  0x1e,  0x09,  0x52,  0x01,  0x45,  0x11,
+  0x3f,  0x08,  0x3f,  0x09,  0xa2,  0x01,  0x90,  0xfe,  0x9c,  0x32,  0x11,  0xfe,  0xe4,  0x00,  0x2f,  0xfe,
+  0xce,  0x03,  0x1b,  0x32,  0x1f,  0xfe,  0xde,  0x03,  0x01,  0x55,  0xd3,  0xfe,  0xee,  0x03,  0x73,  0x97,
+  0xd7,  0xfe,  0xae,  0x06,  0x02,  0x26,  0x04,  0x7c,  0x2c,  0x19,  0xfe,  0x20,  0x05,  0x17,  0x8b,  0x01,
+  0x3b,  0x01,  0x9f,  0x01,  0xa1,  0x34,  0xfe,  0x60,  0x02,  0x02,  0xf6,  0xf4,  0x2e,  0x88,  0x18,  0xfe,
+  0x67,  0x1b,  0xfe,  0xbf,  0x57,  0xf7,  0xfe,  0x48,  0x1c,  0x92,  0x01,  0xfe,  0x9c,  0x13,  0xb3,  0xfe,
+  0x96,  0xf0,  0xfe,  0x28,  0x04,  0x2f,  0xfe,  0x2c,  0x04,  0x34,  0x27,  0x0f,  0x3f,  0x01,  0x15,  0x05,
+  0x10,  0x19,  0xfe,  0x0c,  0x05,  0x4d,  0x7a,  0xa5,  0x31,  0x86,  0x76,  0x1b,  0x32,  0x1f,  0x26,  0x04,
+  0x7c,  0x2c,  0xfe,  0x10,  0x12,  0x17,  0x8b,  0x01,  0x3b,  0x34,  0xfe,  0x60,  0x02,  0x02,  0xf6,  0x21,
+  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x5e,  0x12,  0x0a,  0x07,  0x06,  0xfe,  0x56,  0x12,  0x24,
+  0x23,  0x9a,  0x01,  0x0c,  0x86,  0x76,  0x1f,  0xfe,  0xdc,  0x04,  0x24,  0x23,  0x9a,  0x01,  0x0c,  0x1f,
+  0x26,  0x24,  0x23,  0xba,  0xfe,  0x4c,  0x44,  0xfe,  0x32,  0x12,  0x51,  0xfe,  0x44,  0x48,  0x08,  0xfe,
+  0x93,  0x00,  0xfe,  0x4c,  0x54,  0x79,  0xfe,  0x0c,  0x05,  0x82,  0xa5,  0x31,  0xfe,  0x06,  0x80,  0xfe,
+  0x48,  0x47,  0xfe,  0x48,  0x13,  0x40,  0x05,  0xfe,  0xcc,  0x00,  0xfe,  0x40,  0x13,  0x0a,  0x07,  0x06,
+  0xef,  0xfe,  0x06,  0x10,  0x24,  0x23,  0xba,  0x0a,  0x07,  0x38,  0xe2,  0x17,  0xa9,  0x0a,  0x07,  0x06,
+  0x4f,  0x17,  0xfe,  0x0d,  0x00,  0x01,  0x3b,  0x34,  0xfe,  0xa0,  0x0d,  0x02,  0x26,  0x3a,  0x11,  0xfe,
+  0xe6,  0x00,  0xfe,  0x1c,  0x90,  0xb7,  0x03,  0x17,  0xa9,  0x01,  0x3b,  0x34,  0x27,  0x1b,  0x27,  0x02,
+  0xfe,  0x14,  0x05,  0xfe,  0x42,  0x5b,  0x88,  0x18,  0xfe,  0x46,  0x59,  0xfe,  0xbf,  0x57,  0xf7,  0x17,
+  0x46,  0xfe,  0x07,  0x80,  0xfe,  0x31,  0x44,  0x0a,  0x07,  0x0b,  0xfe,  0x78,  0x13,  0xfe,  0x20,  0x80,
+  0x05,  0x18,  0xfe,  0x70,  0x12,  0x75,  0x07,  0x06,  0xfe,  0x60,  0x13,  0x04,  0xfe,  0xa2,  0x00,  0x2c,
+  0x19,  0xfe,  0xac,  0x05,  0xfe,  0x31,  0xe4,  0x60,  0x75,  0x07,  0x0b,  0xfe,  0x4a,  0x13,  0x04,  0xfe,
+  0xa0,  0x00,  0x2c,  0xfe,  0x42,  0x12,  0x63,  0x2f,  0xfe,  0x6c,  0x05,  0x1b,  0x32,  0xf9,  0x01,  0x0c,
+  0x25,  0xfe,  0xc4,  0x05,  0x11,  0xfe,  0xe3,  0x00,  0x2b,  0x75,  0xfe,  0x4a,  0xf0,  0xfe,  0x96,  0x05,
+  0xfe,  0x49,  0xf0,  0xfe,  0x90,  0x05,  0xad,  0x20,  0xfe,  0x21,  0x00,  0x8a,  0x20,  0xfe,  0x22,  0x00,
+  0xa4,  0x20,  0x8f,  0xfe,  0x09,  0x48,  0x01,  0x0c,  0x25,  0xfe,  0xc4,  0x05,  0xfe,  0xe2,  0x08,  0x75,
+  0x07,  0xe1,  0x4f,  0x01,  0xc2,  0x20,  0x06,  0x16,  0xe8,  0x4c,  0xfe,  0x27,  0x01,  0x0a,  0x07,  0x38,
+  0xe9,  0x47,  0x01,  0xbd,  0x17,  0xa9,  0x0a,  0x07,  0x06,  0x4f,  0x17,  0xfe,  0x0d,  0x00,  0x01,  0x3b,
+  0x01,  0x9f,  0x01,  0xa1,  0x34,  0xfe,  0xa0,  0x0d,  0x02,  0x26,  0x04,  0xfe,  0x9c,  0x00,  0x2c,  0xfe,
+  0x3e,  0x12,  0x04,  0x5c,  0x2c,  0xfe,  0x36,  0x13,  0x47,  0x01,  0xbd,  0x25,  0xfe,  0x3c,  0x06,  0x0f,
+  0x06,  0x75,  0x07,  0x22,  0xfe,  0x02,  0x12,  0x6a,  0x01,  0xfe,  0x06,  0x15,  0x1f,  0xfe,  0x32,  0x06,
+  0x11,  0xc9,  0x01,  0x55,  0x11,  0xfe,  0xe5,  0x00,  0x04,  0x5c,  0xc3,  0x0d,  0x5c,  0x04,  0xfe,  0x9e,
+  0x00,  0x2c,  0xfe,  0x62,  0x12,  0x04,  0x56,  0x2c,  0xfe,  0x5a,  0x13,  0x01,  0xfe,  0x7e,  0x19,  0x01,
+  0xfe,  0xe8,  0x19,  0xf3,  0xa8,  0xf1,  0x08,  0x6c,  0xff,  0x02,  0x00,  0x57,  0x6e,  0x81,  0x1a,  0x59,
+  0xd1,  0xa8,  0x74,  0x47,  0x01,  0xbd,  0x25,  0xfe,  0xa6,  0x06,  0x75,  0x07,  0x1d,  0xab,  0x9e,  0x0f,
+  0x5e,  0x01,  0xfe,  0x34,  0x15,  0x1f,  0xfe,  0x9c,  0x06,  0x11,  0xc9,  0x01,  0x55,  0x11,  0xfe,  0xe5,
+  0x00,  0x04,  0x56,  0xc3,  0x0d,  0x56,  0x09,  0x06,  0x01,  0xbd,  0xfe,  0x9c,  0x32,  0x78,  0x92,  0x01,
+  0xfe,  0x9c,  0x13,  0xb3,  0x11,  0xfe,  0xe2,  0x00,  0x2f,  0xfe,  0xbe,  0x06,  0x1b,  0x32,  0xd7,  0xfe,
+  0xda,  0x06,  0x85,  0xfe,  0x78,  0x07,  0xd3,  0xfe,  0x80,  0x07,  0x73,  0x97,  0x02,  0x26,  0x0a,  0x07,
   0x0b,  0xfe,  0x2e,  0x12,  0x14,  0x18,  0x01,  0x0c,  0x14,  0x00,  0x01,  0x0c,  0x14,  0x00,  0x01,  0x0c,
-  0x14,  0x00,  0x01,  0x0c,  0xfe,  0x99,  0xa4,  0x01,  0x0c,  0x14,  0x00,  0x02,  0xfe,  0x3e,  0x08,  0x6f,
-  0x08,  0x1d,  0xea,  0x0a,  0x08,  0x1d,  0xfe,  0x30,  0x13,  0x14,  0xfe,  0x1b,  0x00,  0x01,  0x0c,  0x14,
+  0x14,  0x00,  0x01,  0x0c,  0xfe,  0x99,  0xa4,  0x01,  0x0c,  0x14,  0x00,  0x02,  0xfe,  0x50,  0x08,  0x71,
+  0x07,  0x1d,  0xef,  0x0a,  0x07,  0x1d,  0xfe,  0x30,  0x13,  0x14,  0xfe,  0x1b,  0x00,  0x01,  0x0c,  0x14,
   0x00,  0x01,  0x0c,  0x14,  0x00,  0x01,  0x0c,  0x14,  0x00,  0x01,  0x0c,  0x14,  0x06,  0x01,  0x0c,  0x14,
-  0x00,  0x02,  0xfe,  0xe6,  0x0b,  0x69,  0xfe,  0x9a,  0x81,  0x6d,  0x8d,  0xfe,  0x09,  0x6f,  0xfe,  0x93,
-  0x45,  0x1a,  0xfe,  0x88,  0x07,  0x2f,  0xfe,  0x60,  0x07,  0x19,  0x32,  0xd7,  0xfe,  0x58,  0x07,  0x71,
-  0x8c,  0x83,  0xfe,  0x78,  0x07,  0x02,  0x25,  0x01,  0x41,  0x02,  0xfe,  0xbe,  0x06,  0x14,  0x22,  0x02,
-  0xfe,  0xbe,  0x06,  0xfe,  0x9c,  0xf7,  0xfe,  0xf4,  0x07,  0xfe,  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x52,
-  0xfe,  0xd6,  0x07,  0x0e,  0x65,  0x12,  0x66,  0x0a,  0x4f,  0x5f,  0x3a,  0x01,  0xfe,  0xd6,  0x18,  0x05,
-  0x10,  0x85,  0xfe,  0x83,  0xe7,  0xfe,  0x95,  0x00,  0xa8,  0xfe,  0x03,  0x40,  0x0a,  0x4f,  0x78,  0x3a,
-  0x01,  0xbc,  0xb5,  0xfe,  0x1f,  0x40,  0x16,  0x67,  0x01,  0xf8,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,
-  0xfe,  0x34,  0x51,  0xfe,  0xb6,  0x51,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,  0x0e,  0x63,  0x12,  0x64,
-  0xfe,  0x0c,  0x90,  0xfe,  0x8e,  0x90,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,  0x0e,  0x42,  0x12,  0x43,
-  0x41,  0x0a,  0x08,  0x5f,  0xb0,  0xfe,  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x0e,  0x65,  0x12,  0x66,  0x0a,
-  0x08,  0x78,  0xd1,  0x01,  0xbc,  0xfe,  0x1f,  0x80,  0x16,  0x67,  0xfe,  0x34,  0x90,  0xfe,  0xb6,  0x90,
-  0x0e,  0x44,  0x12,  0x45,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,  0x0e,  0x63,  0x12,  0x64,  0xfe,  0x28,
-  0x90,  0xfe,  0xaa,  0x90,  0x0e,  0x42,  0x12,  0x43,  0x0e,  0x31,  0x12,  0x3f,  0x24,  0x0e,  0x53,  0x0e,
-  0x68,  0x0a,  0x4f,  0x22,  0x3a,  0x38,  0x07,  0xa5,  0x2f,  0xfe,  0x5e,  0x08,  0xfe,  0x9e,  0xf0,  0xfe,
-  0x72,  0x08,  0xcc,  0x1a,  0x32,  0x38,  0x72,  0xfe,  0xed,  0x10,  0xaa,  0xfe,  0x96,  0x08,  0xac,  0xfe,
-  0xb2,  0x08,  0x83,  0xfe,  0x8a,  0x08,  0xd4,  0xfe,  0x90,  0x08,  0x71,  0x8c,  0x02,  0x25,  0x01,  0x41,
-  0xfe,  0xc9,  0x10,  0x14,  0x22,  0xfe,  0xc9,  0x10,  0x6f,  0x08,  0x06,  0xfe,  0x10,  0x12,  0x6f,  0x08,
-  0x0b,  0x4e,  0x0a,  0x08,  0x0b,  0xfe,  0x8e,  0x12,  0xfe,  0x2e,  0x1c,  0xad,  0x6f,  0x08,  0x06,  0x4e,
-  0x6f,  0x08,  0x0b,  0xfe,  0x7a,  0x12,  0xfe,  0x2c,  0x1c,  0xfe,  0xaa,  0xf0,  0xfe,  0xcc,  0x09,  0xfe,
-  0xac,  0xf0,  0xfe,  0xfa,  0x08,  0x02,  0xfe,  0xd8,  0x09,  0xfe,  0xb7,  0xf0,  0xfe,  0xf6,  0x08,  0xfe,
-  0x02,  0xf6,  0x1d,  0x69,  0xfe,  0x70,  0x18,  0xfe,  0xf1,  0x18,  0xfe,  0x40,  0x55,  0xfe,  0xe1,  0x55,
-  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0x19,  0x92,  0xfe,  0x8c,
-  0xf0,  0xfe,  0xf6,  0x08,  0xfe,  0xac,  0xf0,  0xfe,  0xea,  0x08,  0xfe,  0x34,  0x1c,  0xfe,  0xcb,  0x10,
-  0xfe,  0xad,  0xf0,  0xfe,  0x06,  0x09,  0x02,  0xfe,  0x12,  0x0b,  0xfe,  0x36,  0x1c,  0xfe,  0xbf,  0x10,
-  0xfe,  0x2b,  0xf0,  0x92,  0xfe,  0x6b,  0x18,  0x1b,  0xfe,  0x00,  0xfe,  0xe1,  0xcd,  0xfe,  0xd2,  0xf0,
-  0x92,  0xfe,  0x76,  0x18,  0x1b,  0x18,  0x1a,  0x92,  0x04,  0xe7,  0x1b,  0x06,  0x1a,  0x92,  0xaa,  0x57,
-  0xac,  0x57,  0xfe,  0x34,  0x1c,  0xfe,  0x36,  0x1c,  0xfe,  0x89,  0x10,  0x8f,  0x62,  0x3b,  0x17,  0xa6,
-  0x01,  0x2e,  0x13,  0xfe,  0x35,  0x00,  0x35,  0x54,  0x13,  0x90,  0x02,  0x54,  0xf9,  0xaf,  0x0b,  0xfe,
-  0x1a,  0x12,  0x50,  0xfe,  0x19,  0x82,  0xfe,  0x6c,  0x18,  0xfe,  0x44,  0x54,  0xeb,  0xde,  0xfe,  0x74,
-  0x18,  0x91,  0x93,  0x1a,  0xfe,  0xc8,  0x08,  0x02,  0x57,  0x0a,  0x08,  0x5f,  0x2e,  0x04,  0x31,  0x2b,
-  0x3f,  0x0e,  0x44,  0x12,  0x45,  0x82,  0x31,  0x5a,  0x3f,  0xfe,  0x6c,  0x18,  0xfe,  0xed,  0x18,  0xfe,
-  0x44,  0x54,  0xfe,  0xe5,  0x54,  0x36,  0x44,  0x21,  0x45,  0x04,  0x53,  0x2b,  0x68,  0x91,  0xfe,  0xe3,
-  0x54,  0xfe,  0x74,  0x18,  0xfe,  0xf5,  0x18,  0x91,  0xfe,  0xe3,  0x54,  0x93,  0xc9,  0x52,  0xfe,  0xc8,
-  0x08,  0x02,  0x57,  0xfe,  0x37,  0xf0,  0xfe,  0xd4,  0x09,  0xfe,  0x8b,  0xf0,  0xfe,  0x5a,  0x09,  0x02,
-  0x57,  0xf9,  0xaf,  0x0b,  0x28,  0xfe,  0xf4,  0x0a,  0x36,  0x53,  0x21,  0x68,  0x52,  0xfe,  0x38,  0x0a,
-  0x07,  0xfe,  0xc0,  0x07,  0x46,  0x61,  0x00,  0xd9,  0xfe,  0x01,  0x59,  0xfe,  0x52,  0xf0,  0xfe,  0x06,
-  0x0a,  0x91,  0x96,  0xfe,  0x1e,  0x0a,  0x36,  0x53,  0x91,  0xfe,  0xe3,  0x54,  0x4d,  0x53,  0x6e,  0x68,
-  0xfe,  0x14,  0x58,  0xfe,  0x95,  0x58,  0x02,  0x57,  0x36,  0x53,  0x21,  0x68,  0xfe,  0x14,  0x59,  0xfe,
-  0x95,  0x59,  0xeb,  0x4d,  0x53,  0x4d,  0x68,  0x02,  0x57,  0x0a,  0x08,  0x5f,  0xfe,  0x82,  0x12,  0x0a,
-  0x08,  0x22,  0xfe,  0x66,  0x13,  0x2a,  0x67,  0x70,  0xd0,  0xfe,  0x83,  0x80,  0xfe,  0xc8,  0x44,  0xfe,
-  0x2e,  0x13,  0xfe,  0x04,  0x91,  0xfe,  0x86,  0x91,  0x6b,  0x33,  0xfe,  0x40,  0x59,  0xfe,  0xc1,  0x59,
-  0x52,  0xfe,  0xd0,  0x08,  0x04,  0x65,  0x2b,  0x66,  0x0e,  0xb3,  0x12,  0x90,  0x4d,  0x65,  0x6e,  0x66,
-  0x01,  0xbc,  0xb5,  0x6b,  0x33,  0x16,  0x67,  0x82,  0x31,  0x5a,  0x3f,  0x36,  0x44,  0x21,  0x45,  0x93,
-  0xc9,  0xfe,  0x04,  0xfa,  0x31,  0xfe,  0x05,  0xfa,  0x3f,  0x01,  0xf8,  0xfe,  0x36,  0x10,  0x24,  0x0e,
-  0xb3,  0x0e,  0x90,  0x36,  0x44,  0x21,  0x45,  0xad,  0x0a,  0x08,  0x22,  0x1a,  0xfe,  0xd0,  0x08,  0x36,
-  0x42,  0x21,  0x43,  0x0a,  0x08,  0xfe,  0xf7,  0x00,  0x3a,  0x04,  0x63,  0x2b,  0x64,  0xfe,  0x10,  0x58,
-  0xfe,  0x91,  0x58,  0x4d,  0x53,  0x6e,  0x68,  0x02,  0xfe,  0xee,  0x09,  0x0a,  0x08,  0x22,  0x1a,  0xfe,
-  0xd0,  0x08,  0x0a,  0x08,  0xfe,  0xf7,  0x00,  0x3a,  0xeb,  0xde,  0x69,  0xfe,  0x10,  0x90,  0xfe,  0x92,
-  0x90,  0xfe,  0xd3,  0x10,  0x3e,  0x05,  0xca,  0x1a,  0xfe,  0x02,  0x09,  0x11,  0xca,  0xf9,  0xaf,  0x0b,
-  0xfe,  0x14,  0x13,  0x04,  0x42,  0x2b,  0x43,  0x52,  0xfe,  0x02,  0x09,  0xfe,  0x0c,  0x58,  0xfe,  0x8d,
-  0x58,  0x02,  0x57,  0x24,  0x46,  0xfe,  0x19,  0x80,  0xfe,  0xf1,  0x10,  0x0a,  0x08,  0x0b,  0xa7,  0xfe,
-  0x6c,  0x19,  0xfe,  0x19,  0x41,  0xfe,  0x94,  0x10,  0xfe,  0x6c,  0x19,  0x4d,  0x42,  0xfe,  0xed,  0x19,
-  0x6e,  0x43,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0xfe,  0x6b,  0x18,  0x1b,  0xfe,  0x00,  0xff,  0x30,
-  0xfe,  0x7a,  0x10,  0xcd,  0xfe,  0xd2,  0xf0,  0xfe,  0x8c,  0x0b,  0xfe,  0x76,  0x18,  0x1b,  0x18,  0xa9,
-  0x04,  0xe7,  0x1b,  0x06,  0x87,  0x13,  0xfe,  0x16,  0x00,  0x02,  0x54,  0xfe,  0xd1,  0xf0,  0xfe,  0xc2,
-  0x0b,  0x17,  0xa5,  0x01,  0x2e,  0x13,  0xfe,  0x17,  0x00,  0xfe,  0x48,  0x10,  0xfe,  0xce,  0xf0,  0xfe,
-  0xaa,  0x0b,  0x13,  0xfe,  0x21,  0x00,  0x02,  0x54,  0xfe,  0xcd,  0xf0,  0xfe,  0xb6,  0x0b,  0x13,  0xfe,
-  0x22,  0x00,  0x02,  0x54,  0xfe,  0xcb,  0xf0,  0xfe,  0xc2,  0x0b,  0x13,  0xfe,  0x24,  0x00,  0x02,  0x54,
-  0xfe,  0xd0,  0xf0,  0xfe,  0xcc,  0x0b,  0x13,  0xae,  0xdf,  0xfe,  0xcf,  0xf0,  0xfe,  0xd6,  0x0b,  0x13,
-  0x8d,  0xdc,  0xfe,  0xcc,  0xf0,  0xfe,  0xe6,  0x0b,  0xfe,  0x84,  0x80,  0xaf,  0x22,  0xfe,  0xd5,  0x12,
-  0x13,  0xfe,  0x12,  0x00,  0x2f,  0xfe,  0xe6,  0x0b,  0x19,  0x32,  0xaa,  0x25,  0xac,  0x25,  0x38,  0xfc,
-  0x2f,  0xfe,  0xfa,  0x0b,  0x19,  0x32,  0x83,  0xfe,  0x16,  0x0c,  0x71,  0x8c,  0xaa,  0xfe,  0xf4,  0x07,
-  0xac,  0xfe,  0xf4,  0x07,  0x02,  0x25,  0x01,  0x41,  0xfe,  0xdb,  0x10,  0x11,  0xfe,  0xe8,  0x00,  0x8f,
-  0x84,  0x74,  0xfe,  0x89,  0xf0,  0x25,  0x23,  0x29,  0xfe,  0xe9,  0x09,  0x01,  0x0c,  0x84,  0x74,  0x1f,
-  0x25,  0x23,  0x29,  0x98,  0x35,  0xfe,  0x4e,  0x0c,  0x19,  0x32,  0x02,  0xfe,  0x42,  0x0c,  0xcc,  0x4e,
-  0x13,  0xfe,  0x42,  0x00,  0x02,  0x54,  0xa4,  0x06,  0xfe,  0x81,  0x49,  0xfe,  0xcc,  0x12,  0x0a,  0x08,
-  0x0b,  0xf1,  0x13,  0x00,  0x60,  0x0b,  0xfe,  0x6a,  0x12,  0x60,  0xfe,  0x28,  0x00,  0x28,  0xfe,  0x94,
-  0x0d,  0x0f,  0x7e,  0x01,  0x15,  0x05,  0x00,  0x87,  0x37,  0xfe,  0x28,  0x00,  0x02,  0xfe,  0x94,  0x0d,
-  0x01,  0x9b,  0x01,  0x9d,  0x0f,  0xc7,  0x01,  0xfe,  0xf0,  0x0e,  0xb9,  0x07,  0x3d,  0x09,  0xa1,  0x01,
-  0x40,  0x11,  0x48,  0x07,  0x1e,  0x09,  0x51,  0x01,  0x79,  0x02,  0x27,  0x13,  0xfe,  0x44,  0x00,  0x60,
-  0x0b,  0xa7,  0x37,  0x0b,  0xfe,  0xc0,  0x10,  0x01,  0x99,  0x37,  0x0b,  0xfe,  0xb6,  0x10,  0x01,  0x99,
-  0xfe,  0x19,  0x82,  0xfe,  0x34,  0x46,  0xfe,  0x0a,  0x13,  0x37,  0x0b,  0x13,  0xfe,  0x43,  0x00,  0xc0,
-  0x0a,  0x4f,  0x0b,  0x3a,  0x01,  0x9b,  0x01,  0x9d,  0xb9,  0x07,  0x3d,  0x09,  0xa1,  0x01,  0x40,  0x11,
-  0x48,  0x07,  0x1e,  0x09,  0x51,  0x01,  0x79,  0x86,  0x0b,  0xb9,  0x1c,  0xd3,  0x02,  0xfe,  0x4c,  0x03,
-  0x0a,  0x08,  0x0b,  0xa9,  0x37,  0x0b,  0x13,  0x00,  0xfe,  0x54,  0x10,  0x6f,  0x08,  0x1d,  0xfe,  0x50,
-  0x12,  0x0a,  0x08,  0x1d,  0xfe,  0x48,  0x13,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x52,  0x0d,
-  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x58,  0x0d,  0x0a,  0x4f,  0x1d,  0x3a,  0xfe,  0x95,  0x10,
-  0x13,  0xfe,  0x15,  0x00,  0xfe,  0x04,  0xe6,  0x0b,  0x69,  0xfe,  0x26,  0x10,  0x13,  0xfe,  0x13,  0x00,
-  0xdc,  0x13,  0xfe,  0x47,  0x00,  0xa8,  0x13,  0xfe,  0x41,  0x00,  0xa2,  0x13,  0xfe,  0x24,  0x00,  0x04,
-  0x7d,  0x2c,  0x28,  0xf4,  0x69,  0xfe,  0x04,  0xe6,  0x1d,  0xfe,  0x9d,  0x41,  0xfe,  0x1c,  0x42,  0xb9,
-  0x01,  0xfe,  0xf8,  0x0e,  0x02,  0x27,  0xdd,  0x17,  0x0b,  0x4b,  0xfb,  0xe5,  0x17,  0xfe,  0x31,  0x00,
-  0x4b,  0xc3,  0x01,  0xfe,  0xfc,  0x0f,  0x02,  0xfe,  0xc6,  0x01,  0x1c,  0xfe,  0x06,  0xec,  0xfe,  0xb9,
-  0x00,  0x89,  0x37,  0x39,  0xc6,  0x30,  0x1c,  0xfe,  0x06,  0xea,  0xfe,  0xb9,  0x00,  0xfe,  0x47,  0x4b,
-  0x7c,  0xfe,  0x75,  0x57,  0x04,  0x5e,  0xfe,  0x98,  0x56,  0xfe,  0x28,  0x12,  0x0f,  0x7e,  0xfe,  0xfa,
-  0x14,  0x46,  0xed,  0x0f,  0xc7,  0xfe,  0xf0,  0x14,  0xfe,  0x49,  0x54,  0x95,  0xfe,  0x08,  0x0e,  0x0f,
-  0x1e,  0xfe,  0xe4,  0x14,  0xfe,  0x44,  0x48,  0x02,  0xfe,  0x4c,  0x03,  0x0f,  0x5e,  0xfe,  0xc8,  0x14,
-  0x89,  0x37,  0x39,  0xc6,  0x30,  0x1c,  0xfe,  0xce,  0x47,  0xfe,  0xbd,  0x13,  0x02,  0x27,  0x2a,  0x2d,
-  0x05,  0x10,  0xfe,  0x78,  0x12,  0x24,  0x16,  0x5d,  0x16,  0xb2,  0x2a,  0x48,  0x46,  0x4b,  0x48,  0xcc,
-  0xd9,  0xfe,  0xbc,  0xf0,  0xfe,  0xa4,  0x0e,  0x07,  0x06,  0x16,  0x5d,  0x01,  0xfe,  0xb0,  0x16,  0x04,
-  0xfe,  0x38,  0x01,  0x2b,  0xfe,  0x3a,  0x01,  0x52,  0xfe,  0xa8,  0x0e,  0x04,  0xfe,  0x38,  0x01,  0x1b,
-  0xfe,  0xf0,  0xff,  0x0e,  0xfe,  0x60,  0x01,  0x04,  0xfe,  0x3a,  0x01,  0x0e,  0xfe,  0x62,  0x01,  0x20,
-  0x06,  0x16,  0x48,  0xfe,  0x04,  0xec,  0x2d,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x01,  0x40,  0x81,  0xfe,
-  0x05,  0xf6,  0xfe,  0x34,  0x01,  0x01,  0xfe,  0x20,  0x17,  0x11,  0x48,  0xd3,  0x07,  0x06,  0x03,  0x24,
-  0x03,  0x2a,  0x5d,  0xfe,  0xf7,  0x12,  0x2a,  0xb2,  0x70,  0x16,  0xb2,  0x05,  0xa5,  0xfe,  0x93,  0x13,
-  0xfe,  0x24,  0x1c,  0x17,  0x18,  0x4b,  0xfb,  0xe5,  0xfe,  0xd9,  0x10,  0x9a,  0xfe,  0x03,  0xdc,  0xfe,
-  0x73,  0x57,  0xfe,  0x80,  0x5d,  0x03,  0x9a,  0xfe,  0x03,  0xdc,  0x24,  0xfe,  0x70,  0x57,  0xfe,  0x33,
-  0x54,  0xfe,  0x3b,  0x54,  0xfe,  0x80,  0x5d,  0x03,  0xfe,  0x03,  0x57,  0x9a,  0x24,  0xfe,  0x00,  0xcc,
-  0x03,  0xfe,  0x03,  0x57,  0x9a,  0x7f,  0x03,  0x01,  0xfe,  0x50,  0x17,  0x3e,  0x05,  0x48,  0xfe,  0x0a,
-  0x13,  0x07,  0x1e,  0x09,  0x51,  0xdc,  0x01,  0x9b,  0x01,  0x9d,  0x07,  0x3d,  0x09,  0xa1,  0x01,  0x40,
-  0x11,  0xfe,  0xe9,  0x00,  0x0a,  0x08,  0x8d,  0xfe,  0x52,  0x13,  0x01,  0xfe,  0xe2,  0x16,  0xfe,  0x1e,
-  0x1c,  0xfe,  0x14,  0x90,  0x0e,  0xfe,  0x64,  0x01,  0xfe,  0x16,  0x90,  0x0e,  0xfe,  0x66,  0x01,  0x0a,
-  0x08,  0x78,  0xea,  0xfe,  0x03,  0x80,  0x72,  0x4c,  0x11,  0x7b,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x97,
-  0x01,  0xa0,  0xfe,  0x62,  0x08,  0x70,  0x4c,  0x11,  0x7b,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x97,  0x01,
-  0xa0,  0x6b,  0x33,  0x11,  0x7b,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x97,  0x01,  0x79,  0x03,  0xfe,  0x08,
-  0x1c,  0x04,  0xfe,  0xac,  0x00,  0xfe,  0x06,  0x58,  0x04,  0xfe,  0xae,  0x00,  0xfe,  0x07,  0x58,  0x04,
-  0xfe,  0xb0,  0x00,  0xfe,  0x08,  0x58,  0x04,  0xfe,  0xb2,  0x00,  0xfe,  0x09,  0x58,  0xfe,  0x0a,  0x1c,
-  0x20,  0x8b,  0x16,  0xfe,  0xb9,  0x00,  0x24,  0x0e,  0x5b,  0x0e,  0x56,  0x20,  0x10,  0x16,  0x2d,  0x16,
-  0x3c,  0x50,  0xa4,  0xfe,  0x93,  0x00,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x01,  0x79,  0x81,  0x11,  0x7b,
-  0xfe,  0x14,  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0xd6,  0x0f,  0xdd,  0x8f,  0xfe,  0x14,  0x1c,  0xfe,  0x10,
-  0x1c,  0xfe,  0x18,  0x1c,  0x03,  0x1c,  0xfe,  0x0c,  0x14,  0x89,  0xfe,  0x07,  0xe6,  0x39,  0xfe,  0xce,
-  0x47,  0xfe,  0xf5,  0x13,  0x03,  0x01,  0x99,  0x0f,  0x3d,  0x01,  0x15,  0x05,  0x10,  0xda,  0x0f,  0x1e,
-  0x01,  0x15,  0x05,  0x10,  0xe1,  0xfe,  0x44,  0x58,  0x4c,  0xfe,  0x01,  0xec,  0xc3,  0xfe,  0x9e,  0x40,
-  0xfe,  0x9d,  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x1d,  0xa3,  0x33,  0x01,  0xfe,  0xf8,  0x0e,  0xfe,  0xc9,
-  0x10,  0x03,  0x38,  0x84,  0x74,  0x23,  0x29,  0xba,  0x05,  0x1d,  0xfe,  0x48,  0x12,  0x05,  0x0b,  0xfe,
-  0x4c,  0x12,  0x05,  0x18,  0xfe,  0x30,  0x12,  0x05,  0xd5,  0x1a,  0xfe,  0xa0,  0x11,  0x05,  0xfe,  0x23,
-  0x00,  0x1a,  0xfe,  0xac,  0x11,  0x05,  0x06,  0x1a,  0xa9,  0x05,  0x22,  0xfe,  0x12,  0x12,  0x05,  0x00,
-  0x1a,  0x25,  0x17,  0xd5,  0x01,  0x2e,  0xce,  0x3b,  0x01,  0x0c,  0x83,  0x41,  0x03,  0x3b,  0x11,  0xfe,
-  0xcc,  0x00,  0x02,  0x27,  0x3b,  0x3e,  0x05,  0xca,  0xfe,  0xe3,  0x13,  0x36,  0x42,  0x21,  0x43,  0x52,
-  0xfe,  0x5e,  0x11,  0x0a,  0x08,  0x5f,  0xfe,  0x72,  0x12,  0x82,  0x31,  0x5a,  0x3f,  0x93,  0xc9,  0x95,
-  0xfe,  0x28,  0x11,  0x2a,  0x67,  0xfe,  0x26,  0x13,  0x04,  0xb3,  0x2b,  0x90,  0x52,  0xfe,  0x78,  0x0d,
-  0x0e,  0x65,  0x12,  0x66,  0x24,  0x0e,  0xb3,  0x0e,  0x90,  0x01,  0xbc,  0x20,  0x8b,  0x72,  0x16,  0x67,
-  0x01,  0xf8,  0x82,  0x31,  0x5a,  0x3f,  0xfe,  0x04,  0x55,  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,  0x31,
-  0xfe,  0x05,  0xfa,  0x3f,  0xfe,  0x91,  0x10,  0x04,  0x44,  0x2b,  0x45,  0xfe,  0x40,  0x56,  0xfe,  0xe1,
-  0x56,  0x0e,  0x44,  0x12,  0x45,  0xab,  0x82,  0x31,  0x5a,  0x3f,  0x93,  0xc9,  0x04,  0x63,  0x2b,  0x64,
-  0xfe,  0x00,  0x56,  0xfe,  0xa1,  0x56,  0x0e,  0x63,  0x12,  0x64,  0x0a,  0x08,  0x5f,  0xfe,  0x1e,  0x12,
-  0x2a,  0x67,  0xfe,  0x1f,  0x40,  0x04,  0x65,  0x2b,  0x66,  0xfe,  0x2c,  0x50,  0xfe,  0xae,  0x50,  0x04,
-  0x44,  0x2b,  0x45,  0xfe,  0x34,  0x50,  0xfe,  0xb6,  0x50,  0x04,  0x63,  0x2b,  0x64,  0xfe,  0x08,  0x50,
-  0xfe,  0x8a,  0x50,  0x04,  0x42,  0x2b,  0x43,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,  0x02,  0x9c,  0x20,
-  0x06,  0x16,  0xfa,  0x02,  0x7a,  0x3b,  0x01,  0x0c,  0x1f,  0x55,  0x23,  0x29,  0xba,  0x05,  0x06,  0x28,
-  0x55,  0x3e,  0x05,  0xca,  0x28,  0x7a,  0x01,  0xf2,  0x1b,  0x58,  0x1a,  0x55,  0x0a,  0x08,  0x0b,  0xe4,
-  0x36,  0x42,  0x21,  0x43,  0xfe,  0x0a,  0x55,  0x30,  0xfe,  0x8b,  0x55,  0x4d,  0x42,  0x6e,  0x43,  0xfe,
-  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0x02,  0x7a,  0xde,  0xfe,  0x0a,  0x45,  0xfe,  0x19,  0x41,  0x02,  0x7a,
-  0x3b,  0x01,  0x0c,  0x1f,  0xc0,  0x23,  0x29,  0xfe,  0xe9,  0x09,  0x60,  0x18,  0xfe,  0x94,  0x12,  0x60,
-  0x0b,  0x59,  0x02,  0x55,  0x2f,  0xb0,  0x19,  0x32,  0x1f,  0xc0,  0x23,  0x29,  0x98,  0x05,  0x18,  0x28,
-  0x55,  0x01,  0x0c,  0x1f,  0xc0,  0x23,  0x29,  0xfe,  0xe8,  0x09,  0x50,  0x04,  0xfe,  0x9c,  0x00,  0x2c,
-  0x30,  0xfe,  0xbb,  0x45,  0x60,  0x00,  0x4e,  0x37,  0x06,  0xa4,  0x58,  0xfe,  0xc0,  0x14,  0xfe,  0xf8,
-  0x14,  0xb1,  0x3e,  0x05,  0xc8,  0xfe,  0x16,  0x13,  0x04,  0xfe,  0x9e,  0x00,  0x2c,  0xa9,  0x04,  0x56,
-  0x2c,  0x30,  0x62,  0x02,  0x7a,  0xfe,  0xc0,  0x5d,  0xfe,  0xe4,  0x14,  0xfe,  0x03,  0x17,  0x04,  0x5b,
-  0xc2,  0x0e,  0x5b,  0x62,  0x3b,  0x01,  0x0c,  0x26,  0x9c,  0x01,  0xfe,  0xd0,  0x14,  0x02,  0x9c,  0x2f,
-  0xfe,  0xb4,  0x12,  0x19,  0x32,  0x1f,  0x55,  0x23,  0x29,  0x98,  0x05,  0x06,  0x28,  0x55,  0xfe,  0xf6,
-  0x14,  0xfe,  0x42,  0x58,  0xfe,  0x70,  0x14,  0xfe,  0x92,  0x14,  0xb1,  0xfe,  0x4a,  0xf4,  0x0b,  0x1a,
-  0x55,  0xfe,  0x4a,  0xf4,  0x06,  0xd8,  0x3e,  0x05,  0xc8,  0xd1,  0x02,  0x7a,  0x04,  0x56,  0xc2,  0x0e,
-  0x56,  0x62,  0x3b,  0x01,  0x0c,  0x26,  0x9c,  0x01,  0xfe,  0xfe,  0x14,  0x02,  0x9c,  0x26,  0xe2,  0x76,
-  0xf7,  0x76,  0x03,  0x35,  0xfe,  0x18,  0x13,  0x71,  0xfe,  0x18,  0x13,  0x62,  0x3b,  0x01,  0x0c,  0xfe,
-  0xe3,  0x10,  0x07,  0x6a,  0xff,  0x02,  0x00,  0x57,  0x6c,  0x80,  0x1b,  0xfe,  0xff,  0x7f,  0xfe,  0x30,
-  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x07,  0x6a,  0xff,  0x02,  0x00,  0x57,  0x6c,  0x80,  0x1b,  0x58,  0xfe,
-  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x07,  0x6a,  0xff,  0x02,  0x00,  0x57,  0x6c,  0x80,  0x03,  0x07,
-  0x6a,  0xff,  0x02,  0x00,  0x57,  0x6c,  0x80,  0xfe,  0x0b,  0x58,  0x03,  0x0f,  0x5b,  0x01,  0x9f,  0x0f,
-  0x56,  0x01,  0x9f,  0x03,  0xd0,  0x1b,  0x10,  0xff,  0x03,  0x00,  0x54,  0xfe,  0x00,  0xf4,  0x22,  0x6c,
-  0xfe,  0x00,  0x7d,  0xfe,  0x01,  0x7d,  0xfe,  0x02,  0x7d,  0xfe,  0x03,  0x7c,  0x6b,  0x33,  0x0e,  0x63,
-  0x12,  0x64,  0x4d,  0x44,  0x6e,  0x45,  0x03,  0xfe,  0x62,  0x18,  0xfe,  0x82,  0x5a,  0xfe,  0xe1,  0x1a,
-  0xbe,  0xfe,  0x02,  0x58,  0x03,  0x01,  0xfe,  0x40,  0x19,  0xfe,  0x42,  0x48,  0x69,  0x50,  0x7c,  0x01,
-  0x0c,  0x1f,  0xfe,  0xc8,  0x14,  0x23,  0x29,  0xfe,  0xe9,  0x09,  0xfe,  0xc1,  0x59,  0x01,  0x0c,  0x1f,
-  0xfe,  0xc8,  0x14,  0x23,  0x29,  0xfe,  0xe8,  0x0a,  0x04,  0xfe,  0x9e,  0x00,  0x2c,  0xfe,  0xc2,  0x12,
-  0x24,  0xb8,  0x1d,  0xe4,  0x60,  0xd6,  0x77,  0xfe,  0x18,  0x14,  0x59,  0x07,  0x06,  0x09,  0xd6,  0xa4,
-  0xfe,  0x00,  0x10,  0xfe,  0x78,  0x10,  0xff,  0x02,  0x83,  0x55,  0xa8,  0xff,  0x02,  0x83,  0x55,  0xb8,
-  0x18,  0xfe,  0x12,  0x13,  0x61,  0xfe,  0x30,  0x00,  0x95,  0xf3,  0x09,  0x88,  0x07,  0x06,  0xfe,  0x56,
-  0x10,  0xb8,  0x0b,  0xfe,  0x16,  0x13,  0x61,  0xfe,  0x64,  0x00,  0x95,  0xf3,  0x0f,  0xfe,  0x64,  0x00,
-  0x09,  0xae,  0x07,  0x06,  0xfe,  0x28,  0x10,  0xb8,  0x06,  0xfe,  0x5e,  0x13,  0x61,  0xfe,  0xc8,  0x00,
-  0x95,  0xf3,  0x0f,  0xfe,  0xc8,  0x00,  0x09,  0x5d,  0x07,  0x06,  0xab,  0x61,  0xfe,  0x90,  0x01,  0x96,
-  0xfe,  0x7e,  0x14,  0x7c,  0xad,  0xfe,  0x43,  0xf4,  0xb2,  0xfe,  0x56,  0xf0,  0xfe,  0x90,  0x14,  0xfe,
-  0x04,  0xf4,  0x6a,  0xfe,  0x43,  0xf4,  0xae,  0xfe,  0xf3,  0x10,  0xb7,  0x01,  0xf1,  0x1b,  0x58,  0xda,
-  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x8b,  0x96,  0xfe,  0xc2,  0x14,  0x7c,  0xfe,  0x14,  0x10,  0xfe,
-  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0xec,  0x96,  0xfe,  0xc2,  0x14,  0xd2,  0xec,  0xa2,  0x50,  0x7c,  0x07,
-  0x06,  0xfe,  0xb4,  0x56,  0xfe,  0xc3,  0x58,  0x03,  0x50,  0x07,  0x0b,  0x03,  0x14,  0x06,  0x01,  0x0c,
-  0x26,  0xfe,  0xfc,  0x14,  0x14,  0x0b,  0x01,  0x0c,  0x26,  0xfe,  0xfc,  0x14,  0x14,  0x18,  0x01,  0x0c,
-  0x26,  0xfe,  0xfc,  0x14,  0x76,  0xfe,  0x89,  0x49,  0x01,  0x0c,  0x03,  0x14,  0x06,  0x01,  0x0c,  0x26,
-  0xb4,  0x14,  0x18,  0x01,  0x0c,  0x26,  0xb4,  0x14,  0x06,  0x01,  0x0c,  0x26,  0xb4,  0xfe,  0x89,  0x49,
-  0x01,  0x0c,  0x26,  0xb4,  0x76,  0xfe,  0x89,  0x4a,  0x01,  0x0c,  0x03,  0x50,  0x03,  0x2a,  0xe8,  0x05,
-  0x06,  0xfe,  0x44,  0x13,  0xb5,  0x16,  0xe8,  0xfe,  0x49,  0xf4,  0x00,  0x59,  0x76,  0xce,  0x62,  0xfe,
-  0x01,  0xec,  0xfe,  0x27,  0x01,  0xf7,  0x01,  0x0c,  0x3e,  0x05,  0xfe,  0xe3,  0x00,  0xfe,  0x20,  0x13,
-  0x1f,  0xfe,  0x80,  0x15,  0x24,  0x16,  0xfa,  0x01,  0x41,  0x2a,  0xfa,  0x05,  0x06,  0x4e,  0x0a,  0x4f,
-  0x06,  0x3a,  0x03,  0x0e,  0x5c,  0x12,  0x8e,  0xfe,  0x43,  0x58,  0x01,  0x15,  0x05,  0x10,  0xfe,  0x1e,
-  0x12,  0x49,  0xee,  0x94,  0x01,  0x47,  0xfe,  0x90,  0x4d,  0xe6,  0x10,  0xfe,  0xc5,  0x59,  0x01,  0x47,
-  0xfe,  0x8d,  0x56,  0xbe,  0x49,  0x03,  0x49,  0x21,  0x8e,  0x01,  0x15,  0x49,  0x94,  0x01,  0x47,  0xe9,
-  0x10,  0xe6,  0x10,  0x21,  0x5c,  0x61,  0x1e,  0x87,  0x0f,  0x5e,  0x01,  0xc5,  0x03,  0x0e,  0x5c,  0x12,
-  0x8e,  0xfe,  0xc3,  0x58,  0x01,  0x15,  0x05,  0x10,  0xfe,  0x1a,  0x12,  0x49,  0xee,  0x94,  0x01,  0x47,
-  0xe9,  0x10,  0xfe,  0x80,  0x4d,  0xfe,  0xc5,  0x59,  0x01,  0x47,  0x49,  0x03,  0x49,  0x21,  0x5c,  0x01,
-  0x15,  0x49,  0x94,  0x01,  0x47,  0xe9,  0x10,  0xe6,  0x10,  0x21,  0x5c,  0x61,  0x1e,  0x87,  0x0f,  0x5e,
-  0x01,  0xc5,  0x03,  0x0e,  0x5c,  0x12,  0x8e,  0xfe,  0x43,  0x58,  0x01,  0x15,  0xfe,  0x42,  0x48,  0x94,
-  0x01,  0x47,  0xfe,  0xc0,  0x5a,  0xb7,  0xfe,  0x00,  0xcd,  0xfe,  0x01,  0xcc,  0xfe,  0x4a,  0x46,  0xe4,
-  0x9a,  0x7f,  0x05,  0x10,  0xfe,  0x2e,  0x13,  0x5a,  0x5c,  0xfe,  0x4d,  0xf4,  0x1e,  0xe2,  0x0f,  0x5e,
-  0x01,  0x9f,  0xad,  0xfe,  0x40,  0x4c,  0xfe,  0xc5,  0x58,  0x01,  0x47,  0xfe,  0x00,  0x07,  0x7f,  0x05,
-  0x10,  0x87,  0x5a,  0x8e,  0xfe,  0x05,  0x57,  0xfe,  0x08,  0x10,  0xfe,  0x45,  0x58,  0x01,  0x47,  0xfe,
-  0x8d,  0x56,  0xbe,  0xfe,  0x80,  0x4c,  0xfe,  0x05,  0x17,  0x03,  0x09,  0x10,  0x75,  0x6d,  0xfe,  0x60,
-  0x01,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x24,  0x1c,  0xe3,  0x39,  0x9e,  0xfe,  0xc4,  0x16,
-  0x01,  0xfe,  0xca,  0x17,  0xd9,  0x8a,  0x39,  0x6d,  0xfe,  0x2c,  0x01,  0xfe,  0x2f,  0x19,  0x03,  0xbf,
-  0x28,  0xfe,  0xb4,  0x16,  0xfe,  0xda,  0x10,  0x09,  0x10,  0x75,  0x04,  0xfe,  0x64,  0x01,  0xfe,  0x00,
-  0xf4,  0x22,  0xfe,  0x18,  0x58,  0x04,  0xfe,  0x66,  0x01,  0xfe,  0x19,  0x58,  0x8a,  0x22,  0xfe,  0x3c,
-  0x90,  0xfe,  0x30,  0xf4,  0x06,  0xfe,  0x3c,  0x50,  0x6d,  0xfe,  0x38,  0x00,  0xfe,  0x0f,  0x79,  0xfe,
-  0x1c,  0xf7,  0x22,  0x9e,  0xfe,  0x0e,  0x17,  0xfe,  0xb6,  0x14,  0x30,  0x03,  0xbf,  0x28,  0xfe,  0xe6,
-  0x16,  0xfe,  0x9c,  0x10,  0x09,  0x10,  0x75,  0xbe,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xdf,  0xe3,  0x31,
-  0x9e,  0xfe,  0x30,  0x17,  0xfe,  0x94,  0x14,  0x2e,  0x8a,  0x31,  0x6d,  0x1d,  0xfe,  0xaf,  0x19,  0xfe,
-  0x98,  0xe7,  0x00,  0x03,  0xbf,  0x28,  0xfe,  0x24,  0x17,  0xfe,  0x6c,  0x10,  0x09,  0x10,  0x75,  0xfe,
-  0x30,  0xbc,  0xfe,  0xb2,  0xbc,  0x8a,  0xe0,  0x6d,  0x1d,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0xe0,
-  0x9e,  0xfe,  0x68,  0x17,  0xfe,  0x5c,  0x14,  0x30,  0x03,  0xbf,  0x28,  0xfe,  0x54,  0x17,  0xfe,  0x42,
-  0x10,  0xfe,  0x02,  0xf6,  0x10,  0x75,  0xfe,  0x18,  0xfe,  0x65,  0xfe,  0x19,  0xfe,  0x66,  0xd0,  0xe3,
-  0x78,  0x9e,  0xfe,  0x8e,  0x17,  0xfe,  0x36,  0x14,  0xe2,  0x8a,  0x78,  0x46,  0xfe,  0x83,  0x58,  0xfe,
-  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x10,  0xfe,  0x81,  0xe7,  0x10,  0x11,  0xfe,  0xdd,  0x00,  0x6b,  0x33,
-  0x03,  0x6b,  0x33,  0xfe,  0x12,  0x45,  0x28,  0xfe,  0x7e,  0x17,  0x17,  0x06,  0x4b,  0xfb,  0xe5,  0x02,
-  0x27,  0xfe,  0x39,  0xf0,  0xfe,  0xd2,  0x17,  0x24,  0x03,  0xfe,  0x7e,  0x18,  0x1b,  0x18,  0x85,  0x07,
-  0x0d,  0x03,  0x75,  0x04,  0xe7,  0x1b,  0x06,  0xfe,  0xef,  0x12,  0xfe,  0xe1,  0x10,  0x1c,  0x0f,  0x1e,
-  0x01,  0x15,  0x05,  0x10,  0x4e,  0x4c,  0xfe,  0x78,  0x14,  0xfe,  0x34,  0x12,  0x58,  0x89,  0x37,  0x39,
-  0xc6,  0xfe,  0xe9,  0x13,  0x1c,  0x0f,  0x3d,  0x01,  0x15,  0x05,  0x10,  0x4e,  0x4c,  0xfe,  0x56,  0x14,
-  0xb0,  0x58,  0x89,  0x37,  0x39,  0xc6,  0xfe,  0xe9,  0x13,  0x09,  0x0b,  0x03,  0xfe,  0x9c,  0xe7,  0x0b,
-  0x13,  0xfe,  0x15,  0x00,  0x97,  0xa3,  0x33,  0x01,  0xfe,  0xf8,  0x0e,  0x09,  0x06,  0x03,  0x0a,  0x4f,
-  0x39,  0x3a,  0x07,  0x3d,  0x09,  0xa1,  0x01,  0x40,  0x11,  0x48,  0x07,  0x1e,  0x09,  0x51,  0x01,  0x79,
-  0x09,  0x06,  0x03,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,  0x36,  0xfe,  0xa8,  0x00,  0x21,  0x7b,  0xfe,
-  0x48,  0x55,  0x30,  0xfe,  0xc9,  0x55,  0x03,  0x2a,  0xc4,  0x72,  0x16,  0xc4,  0x03,  0x0f,  0xc7,  0x01,
-  0x15,  0xed,  0x0f,  0x7e,  0x01,  0x15,  0xfe,  0x49,  0x44,  0x28,  0xfe,  0xc8,  0x18,  0x0f,  0x1e,  0x01,
-  0x15,  0x05,  0x10,  0x4e,  0x0f,  0x5e,  0x01,  0xc5,  0x0f,  0x7e,  0x01,  0x15,  0x72,  0x7f,  0x03,  0xfe,
-  0x40,  0x5e,  0xfe,  0xe2,  0x08,  0xfe,  0xc0,  0x4c,  0x2a,  0x3c,  0x05,  0x10,  0xfe,  0x52,  0x12,  0x4c,
-  0x05,  0x00,  0xfe,  0x18,  0x12,  0xfe,  0xe1,  0x18,  0xfe,  0x19,  0xf4,  0xfe,  0x7f,  0x00,  0x2e,  0xfe,
-  0xe2,  0x08,  0x72,  0x4c,  0x3e,  0x05,  0x7b,  0xa7,  0xfe,  0x82,  0x48,  0xfe,  0x01,  0x80,  0xfe,  0xd7,
-  0x10,  0xfe,  0xc4,  0x48,  0x07,  0x2d,  0x09,  0x3c,  0xfe,  0x40,  0x5f,  0x1c,  0x01,  0x40,  0x11,  0xfe,
-  0xdd,  0x00,  0xfe,  0x14,  0x46,  0x07,  0x2d,  0x09,  0x3c,  0x01,  0x40,  0x11,  0xfe,  0xdd,  0x00,  0xfe,
-  0x40,  0x4a,  0x70,  0xfe,  0x06,  0x17,  0xfe,  0x01,  0x07,  0xfe,  0x82,  0x48,  0xfe,  0x04,  0x17,  0x03,
-  0xf0,  0x18,  0x77,  0xfe,  0x50,  0x19,  0x04,  0xfe,  0x90,  0x00,  0xfe,  0x3a,  0x45,  0xfe,  0x2c,  0x10,
-  0xf0,  0xd5,  0x77,  0xfe,  0x62,  0x19,  0x04,  0xfe,  0x92,  0x00,  0xcf,  0x1d,  0xdf,  0xf0,  0xfe,  0x0b,
-  0x00,  0x77,  0xfe,  0x74,  0x19,  0x04,  0xfe,  0x94,  0x00,  0xcf,  0x22,  0xfe,  0x08,  0x10,  0x04,  0xfe,
-  0x96,  0x00,  0xcf,  0x88,  0xfe,  0x4e,  0x45,  0xd8,  0xfe,  0x0a,  0x45,  0xff,  0x04,  0x68,  0x54,  0xfe,
-  0xf1,  0x10,  0x1b,  0x8b,  0xfe,  0x08,  0x1c,  0xfe,  0x67,  0x19,  0xfe,  0x0a,  0x1c,  0xfe,  0x1a,  0xf4,
-  0xfe,  0x00,  0x04,  0xd8,  0xfe,  0x48,  0xf4,  0x18,  0x96,  0xfe,  0xa8,  0x19,  0x07,  0x18,  0x03,  0x05,
-  0xa5,  0xfe,  0x5a,  0xf0,  0xfe,  0xb8,  0x19,  0x20,  0xfe,  0x09,  0x00,  0xfe,  0x34,  0x10,  0x05,  0x1d,
-  0xfe,  0x5a,  0xf0,  0xfe,  0xc6,  0x19,  0x20,  0xd6,  0xfe,  0x26,  0x10,  0x05,  0x18,  0x85,  0x20,  0x88,
-  0xdf,  0x05,  0x0b,  0x85,  0x20,  0xae,  0xfe,  0x0e,  0x10,  0x05,  0x06,  0x85,  0x20,  0x5d,  0xce,  0xb5,
-  0x03,  0x17,  0xfe,  0x09,  0x00,  0x01,  0x2e,  0x2f,  0xfe,  0xf6,  0x19,  0x04,  0x74,  0xb7,  0x03,  0x19,
-  0xfe,  0x16,  0x1a,  0xfe,  0x14,  0xf0,  0x0c,  0x2f,  0xfe,  0x0a,  0x1a,  0x19,  0xfe,  0x16,  0x1a,  0xfe,
-  0x82,  0xf0,  0xfe,  0x0e,  0x1a,  0x03,  0xff,  0x34,  0x00,  0x00,};
+  0x00,  0x02,  0xfe,  0x0a,  0x0c,  0x6a,  0xfe,  0x9a,  0x81,  0x6f,  0x8f,  0xfe,  0x09,  0x6f,  0xfe,  0x93,
+  0x45,  0x19,  0xfe,  0x88,  0x07,  0x2f,  0xfe,  0x60,  0x07,  0x1b,  0x32,  0xd7,  0xfe,  0x58,  0x07,  0x73,
+  0x97,  0x85,  0xfe,  0x78,  0x07,  0x02,  0x26,  0x01,  0x55,  0x02,  0xfe,  0xbe,  0x06,  0x14,  0x22,  0x02,
+  0xfe,  0xbe,  0x06,  0xfe,  0x9c,  0xf7,  0xfe,  0xf0,  0x07,  0xfe,  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x53,
+  0xfe,  0xd6,  0x07,  0x0d,  0x66,  0x12,  0x67,  0x0a,  0x41,  0x60,  0x39,  0x01,  0xfe,  0x14,  0x19,  0x05,
+  0x10,  0x87,  0xfe,  0x83,  0xe7,  0xfe,  0x95,  0x00,  0x8a,  0xfe,  0x03,  0x40,  0x0a,  0x41,  0x46,  0x39,
+  0x01,  0xc5,  0xb6,  0xfe,  0x1f,  0x40,  0x16,  0x68,  0x01,  0xfe,  0xbe,  0x13,  0xfe,  0x08,  0x50,  0xfe,
+  0x8a,  0x50,  0xfe,  0x34,  0x51,  0xfe,  0xb6,  0x51,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,  0x0d,  0x64,
+  0x12,  0x65,  0xda,  0xfa,  0x0d,  0x3c,  0x12,  0x3d,  0xfe,  0x60,  0x10,  0x0a,  0x07,  0x60,  0xe9,  0xfe,
+  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x0d,  0x66,  0x12,  0x67,  0x0a,  0x07,  0x46,  0xd1,  0x01,  0xc5,  0xfe,
+  0x1f,  0x80,  0x16,  0x68,  0xfe,  0x34,  0x90,  0xfe,  0xb6,  0x90,  0x0d,  0x43,  0x12,  0x44,  0xfe,  0x08,
+  0x90,  0xfe,  0x8a,  0x90,  0x0d,  0x64,  0x12,  0x65,  0xa7,  0x07,  0x46,  0xdb,  0xda,  0xfa,  0x0d,  0x3c,
+  0x12,  0x3d,  0xad,  0xfe,  0x28,  0x90,  0xfe,  0xaa,  0x90,  0x0d,  0x3c,  0x12,  0x3d,  0x0d,  0x30,  0x12,
+  0x42,  0x2b,  0x0d,  0x54,  0x0d,  0x69,  0x0a,  0x41,  0x22,  0x39,  0x2e,  0x08,  0x84,  0x2f,  0xfe,  0x70,
+  0x08,  0xfe,  0x9e,  0xf0,  0xfe,  0x84,  0x08,  0xa3,  0x19,  0x32,  0x2e,  0x5b,  0xfe,  0xed,  0x10,  0xac,
+  0xfe,  0xa8,  0x08,  0xae,  0xfe,  0xc4,  0x08,  0x85,  0xfe,  0x9c,  0x08,  0xd3,  0xfe,  0xa2,  0x08,  0x73,
+  0x97,  0x02,  0x26,  0x01,  0x55,  0xfe,  0xc9,  0x10,  0x14,  0x22,  0xfe,  0xc9,  0x10,  0x71,  0x07,  0x06,
+  0xfe,  0x10,  0x12,  0x71,  0x07,  0x0b,  0x50,  0x0a,  0x07,  0x0b,  0xfe,  0xa6,  0x12,  0xfe,  0x2e,  0x1c,
+  0xb0,  0x71,  0x07,  0x06,  0x50,  0x71,  0x07,  0x0b,  0xfe,  0x92,  0x12,  0xfe,  0x2c,  0x1c,  0xa7,  0x07,
+  0x46,  0xaf,  0xa7,  0x41,  0x46,  0xfe,  0x05,  0x40,  0xda,  0xfa,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,
+  0xfe,  0xaa,  0xf0,  0xfe,  0xf6,  0x09,  0xfe,  0xac,  0xf0,  0xfe,  0x24,  0x09,  0x02,  0xfe,  0x02,  0x0a,
+  0xfe,  0xb7,  0xf0,  0xfe,  0x20,  0x09,  0xfe,  0x02,  0xf6,  0x1d,  0x6a,  0xfe,  0x70,  0x18,  0xfe,  0xf1,
+  0x18,  0xfe,  0x40,  0x55,  0xfe,  0xe1,  0x55,  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,  0xfe,  0x14,  0x59,
+  0xfe,  0x95,  0x59,  0x1b,  0x9b,  0xfe,  0x8c,  0xf0,  0xfe,  0x20,  0x09,  0xfe,  0xac,  0xf0,  0xfe,  0x14,
+  0x09,  0xed,  0xfe,  0xcb,  0x10,  0xfe,  0xad,  0xf0,  0xfe,  0x30,  0x09,  0x02,  0xfe,  0x3c,  0x0b,  0xee,
+  0xfe,  0xbf,  0x10,  0xfe,  0x2b,  0xf0,  0x9b,  0xfe,  0x6b,  0x18,  0x1a,  0xfe,  0x00,  0xfe,  0xe2,  0xcd,
+  0xfe,  0xd2,  0xf0,  0x9b,  0xfe,  0x76,  0x18,  0x1a,  0x18,  0x19,  0x9b,  0x04,  0xe7,  0x1a,  0x06,  0x19,
+  0x9b,  0xac,  0x58,  0xae,  0x58,  0xed,  0xee,  0xfe,  0x89,  0x10,  0x92,  0x63,  0x3a,  0x17,  0xa9,  0x01,
+  0x3b,  0x13,  0xfe,  0x35,  0x00,  0x34,  0x6b,  0x13,  0x93,  0x02,  0x6b,  0xfb,  0xb2,  0x0b,  0xfe,  0x1a,
+  0x12,  0x51,  0xfe,  0x19,  0x82,  0xfe,  0x6c,  0x18,  0xfe,  0x44,  0x54,  0xf0,  0xdf,  0xfe,  0x74,  0x18,
+  0x94,  0x95,  0x19,  0xfe,  0xf2,  0x08,  0x02,  0x58,  0x0a,  0x07,  0x60,  0xaf,  0x04,  0x30,  0x2a,  0x42,
+  0x0d,  0x43,  0x12,  0x44,  0x83,  0x30,  0x5a,  0x42,  0xfe,  0x6c,  0x18,  0xfe,  0xed,  0x18,  0xfe,  0x44,
+  0x54,  0xfe,  0xe5,  0x54,  0x36,  0x43,  0x21,  0x44,  0x04,  0x54,  0x2a,  0x69,  0x94,  0xfe,  0xe3,  0x54,
+  0xfe,  0x74,  0x18,  0xfe,  0xf5,  0x18,  0x94,  0xfe,  0xe3,  0x54,  0x95,  0xca,  0x53,  0xfe,  0xf2,  0x08,
+  0x02,  0x58,  0xfe,  0x37,  0xf0,  0xfe,  0xfe,  0x09,  0xfe,  0x8b,  0xf0,  0xfe,  0x84,  0x09,  0x02,  0x58,
+  0xfb,  0xb2,  0x0b,  0x28,  0xfe,  0x1e,  0x0b,  0x36,  0x54,  0x21,  0x69,  0x53,  0x7a,  0x08,  0xfe,  0xc0,
+  0x07,  0x47,  0x62,  0x00,  0xd9,  0xfe,  0x01,  0x59,  0xfe,  0x52,  0xf0,  0xfe,  0x30,  0x0a,  0x94,  0x99,
+  0xfe,  0x48,  0x0a,  0x36,  0x54,  0x94,  0xfe,  0xe3,  0x54,  0x4e,  0x54,  0x70,  0x69,  0xfe,  0x14,  0x58,
+  0xfe,  0x95,  0x58,  0x02,  0x58,  0x36,  0x54,  0x21,  0x69,  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0xf0,
+  0x4e,  0x54,  0x4e,  0x69,  0x02,  0x58,  0x0a,  0x07,  0x60,  0xfe,  0x82,  0x12,  0x0a,  0x07,  0x22,  0xfe,
+  0x66,  0x13,  0x29,  0x68,  0x72,  0xd0,  0xfe,  0x83,  0x80,  0xfe,  0xc8,  0x44,  0xfe,  0x2e,  0x13,  0xfe,
+  0x04,  0x91,  0xfe,  0x86,  0x91,  0x6d,  0x31,  0xfe,  0x40,  0x59,  0xfe,  0xc1,  0x59,  0x53,  0xfe,  0xfa,
+  0x08,  0x04,  0x66,  0x2a,  0x67,  0x0d,  0xb5,  0x12,  0x93,  0x4e,  0x66,  0x70,  0x67,  0x01,  0xc5,  0xb6,
+  0x6d,  0x31,  0x16,  0x68,  0x83,  0x30,  0x5a,  0x42,  0x36,  0x43,  0x21,  0x44,  0x95,  0xca,  0xfe,  0x04,
+  0xfa,  0x30,  0xfe,  0x05,  0xfa,  0x42,  0x01,  0xfe,  0xbe,  0x13,  0xfe,  0x36,  0x10,  0x2b,  0x0d,  0xb5,
+  0x0d,  0x93,  0x36,  0x43,  0x21,  0x44,  0xb0,  0x0a,  0x07,  0x22,  0x19,  0xfe,  0xfa,  0x08,  0x36,  0x3c,
+  0x21,  0x3d,  0x0a,  0x07,  0xfe,  0xf7,  0x00,  0x39,  0x04,  0x64,  0x2a,  0x65,  0xfe,  0x10,  0x58,  0xfe,
+  0x91,  0x58,  0x4e,  0x54,  0x70,  0x69,  0x02,  0xfe,  0x18,  0x0a,  0x0a,  0x07,  0x22,  0x19,  0xfe,  0xfa,
+  0x08,  0x0a,  0x07,  0xfe,  0xf7,  0x00,  0x39,  0xf0,  0xdf,  0x6a,  0xfe,  0x10,  0x90,  0xfe,  0x92,  0x90,
+  0xfe,  0xd3,  0x10,  0x40,  0x05,  0xcb,  0x19,  0xfe,  0x2c,  0x09,  0x11,  0xcb,  0xfb,  0xb2,  0x0b,  0xfe,
+  0x14,  0x13,  0x04,  0x3c,  0x2a,  0x3d,  0x53,  0xfe,  0x2c,  0x09,  0xfe,  0x0c,  0x58,  0xfe,  0x8d,  0x58,
+  0x02,  0x58,  0x2b,  0x47,  0xfe,  0x19,  0x80,  0xfe,  0xf1,  0x10,  0x0a,  0x07,  0x0b,  0xab,  0xfe,  0x6c,
+  0x19,  0xfe,  0x19,  0x41,  0xfe,  0x8e,  0x10,  0xfe,  0x6c,  0x19,  0x4e,  0x3c,  0xfe,  0xed,  0x19,  0x70,
+  0x3d,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0xfe,  0x6b,  0x18,  0x1a,  0xfe,  0x00,  0xff,  0x35,  0xfe,
+  0x74,  0x10,  0xcd,  0xfe,  0xd2,  0xf0,  0xfe,  0xb6,  0x0b,  0xfe,  0x76,  0x18,  0x1a,  0x18,  0xd6,  0x04,
+  0xe7,  0x1a,  0x06,  0x89,  0x13,  0xfe,  0x16,  0x00,  0x02,  0x6b,  0xfe,  0xd1,  0xf0,  0xfe,  0xc8,  0x0b,
+  0x17,  0x84,  0x01,  0x3b,  0x13,  0xfe,  0x17,  0x00,  0xfe,  0x42,  0x10,  0xfe,  0xce,  0xf0,  0xfe,  0xce,
+  0x0b,  0xfe,  0x3c,  0x10,  0xfe,  0xcd,  0xf0,  0xfe,  0xda,  0x0b,  0x13,  0xfe,  0x22,  0x00,  0x02,  0x6b,
+  0xfe,  0xcb,  0xf0,  0xfe,  0xe6,  0x0b,  0x13,  0xfe,  0x24,  0x00,  0x02,  0x6b,  0xfe,  0xd0,  0xf0,  0xfe,
+  0xf0,  0x0b,  0x13,  0xb1,  0xe0,  0xfe,  0xcf,  0xf0,  0xfe,  0xfa,  0x0b,  0x13,  0x8f,  0xdd,  0xfe,  0xcc,
+  0xf0,  0xfe,  0x0a,  0x0c,  0xfe,  0x84,  0x80,  0xb2,  0x22,  0x4f,  0x13,  0xfe,  0x12,  0x00,  0x2e,  0x08,
+  0x84,  0x2f,  0xfe,  0x10,  0x0c,  0xfe,  0x9e,  0xf0,  0xfe,  0x24,  0x0c,  0xa3,  0x19,  0x32,  0x2e,  0x5b,
+  0xfe,  0xed,  0x10,  0xac,  0x26,  0xae,  0x26,  0x2e,  0xfe,  0x9c,  0x32,  0x2f,  0xfe,  0x30,  0x0c,  0x1b,
+  0x32,  0x85,  0xfe,  0x4c,  0x0c,  0x73,  0x97,  0xac,  0xfe,  0xf0,  0x07,  0xae,  0xfe,  0xf0,  0x07,  0x02,
+  0x26,  0x01,  0x55,  0xfe,  0xdb,  0x10,  0x11,  0xfe,  0xe8,  0x00,  0xed,  0xee,  0x92,  0x86,  0x76,  0xfe,
+  0x89,  0xf0,  0x26,  0x24,  0x23,  0xfe,  0xe9,  0x09,  0x01,  0x0c,  0x86,  0x76,  0x1f,  0x26,  0x24,  0x23,
+  0x9a,  0x34,  0xfe,  0x88,  0x0c,  0x1b,  0x32,  0x02,  0xfe,  0x7c,  0x0c,  0xa3,  0x50,  0x13,  0xfe,  0x42,
+  0x00,  0x02,  0x6b,  0xa6,  0x06,  0xfe,  0x81,  0x49,  0xfe,  0xcc,  0x12,  0x0a,  0x07,  0x0b,  0xfe,  0x5a,
+  0x13,  0x13,  0x00,  0x61,  0x0b,  0xfe,  0x6a,  0x12,  0x61,  0xfe,  0x28,  0x00,  0x28,  0xfe,  0xce,  0x0d,
+  0x0f,  0x7d,  0x01,  0x15,  0x05,  0x00,  0x89,  0x37,  0xfe,  0x28,  0x00,  0x02,  0xfe,  0xce,  0x0d,  0x01,
+  0x9f,  0x01,  0xa1,  0x0f,  0xc8,  0x01,  0xfe,  0x24,  0x0f,  0xb9,  0x08,  0x3f,  0x09,  0xa2,  0x01,  0x45,
+  0x11,  0x48,  0x08,  0x1e,  0x09,  0x52,  0x01,  0x7e,  0x02,  0x27,  0x13,  0xfe,  0x44,  0x00,  0x61,  0x0b,
+  0xab,  0x37,  0x0b,  0xfe,  0xc0,  0x10,  0x01,  0xc2,  0x37,  0x0b,  0xfe,  0xb6,  0x10,  0x01,  0xc2,  0xfe,
+  0x19,  0x82,  0xfe,  0x34,  0x46,  0xfe,  0x0a,  0x13,  0x37,  0x0b,  0x13,  0xfe,  0x43,  0x00,  0xfe,  0xa2,
+  0x10,  0x0a,  0x41,  0x0b,  0x39,  0x01,  0x9f,  0x01,  0xa1,  0xb9,  0x08,  0x3f,  0x09,  0xa2,  0x01,  0x45,
+  0x11,  0x48,  0x08,  0x1e,  0x09,  0x52,  0x01,  0x7e,  0x88,  0x0b,  0xb9,  0x1c,  0xd2,  0x02,  0xfe,  0x4c,
+  0x03,  0x0a,  0x07,  0x0b,  0xd6,  0x37,  0x0b,  0x13,  0x00,  0xfe,  0x54,  0x10,  0x71,  0x07,  0x1d,  0xfe,
+  0x50,  0x12,  0x0a,  0x07,  0x1d,  0xfe,  0x48,  0x13,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x8c,
+  0x0d,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x92,  0x0d,  0x0a,  0x41,  0x1d,  0x39,  0xfe,  0x95,
+  0x10,  0x13,  0xfe,  0x15,  0x00,  0xfe,  0x04,  0xe6,  0x0b,  0x6a,  0xfe,  0x26,  0x10,  0x13,  0xfe,  0x13,
+  0x00,  0xdd,  0x13,  0xfe,  0x47,  0x00,  0x8a,  0x13,  0xfe,  0x41,  0x00,  0xa4,  0x13,  0xfe,  0x24,  0x00,
+  0x04,  0x7c,  0x2c,  0x28,  0xf6,  0x6a,  0xfe,  0x04,  0xe6,  0x1d,  0xfe,  0x9d,  0x41,  0xfe,  0x1c,  0x42,
+  0xb9,  0x01,  0xea,  0x02,  0x27,  0xde,  0x17,  0x0b,  0x4c,  0xfe,  0x9b,  0x00,  0xe5,  0x17,  0xfe,  0x31,
+  0x00,  0x4c,  0xc4,  0x01,  0xfe,  0x30,  0x10,  0x02,  0xfe,  0xc6,  0x01,  0x1c,  0xfe,  0x06,  0xec,  0xfe,
+  0xb9,  0x00,  0x8c,  0x37,  0x38,  0xc7,  0x35,  0x1c,  0xfe,  0x06,  0xea,  0xfe,  0xb9,  0x00,  0xfe,  0x47,
+  0x4b,  0x9e,  0xfe,  0x75,  0x57,  0x04,  0x5f,  0xfe,  0x98,  0x56,  0xfe,  0x28,  0x12,  0x0f,  0x7d,  0xfe,
+  0xf4,  0x14,  0x47,  0xf2,  0x0f,  0xc8,  0xfe,  0xea,  0x14,  0xfe,  0x49,  0x54,  0x98,  0xfe,  0x42,  0x0e,
+  0x0f,  0x1e,  0xfe,  0xde,  0x14,  0xfe,  0x44,  0x48,  0x02,  0xfe,  0x4c,  0x03,  0x0f,  0x5f,  0xfe,  0xc8,
+  0x14,  0x8c,  0x37,  0x38,  0xc7,  0x35,  0x1c,  0xfe,  0xce,  0x47,  0xfe,  0xbd,  0x13,  0x02,  0x27,  0x29,
+  0x2d,  0x05,  0x10,  0xfe,  0x78,  0x12,  0x2b,  0x16,  0x5e,  0x16,  0xb4,  0x29,  0x48,  0x47,  0x4c,  0x48,
+  0xa3,  0xd9,  0xfe,  0xbc,  0xf0,  0xfe,  0xde,  0x0e,  0x08,  0x06,  0x16,  0x5e,  0x01,  0xfe,  0xe6,  0x16,
+  0x04,  0xfe,  0x38,  0x01,  0x2a,  0xfe,  0x3a,  0x01,  0x53,  0xfe,  0xe2,  0x0e,  0x04,  0xfe,  0x38,  0x01,
+  0x1a,  0xfe,  0xf0,  0xff,  0x0d,  0xfe,  0x60,  0x01,  0x04,  0xfe,  0x3a,  0x01,  0x0d,  0xfe,  0x62,  0x01,
+  0x20,  0x06,  0x16,  0x48,  0xfe,  0x04,  0xec,  0x2d,  0x08,  0x2d,  0x09,  0x3e,  0x1c,  0x01,  0x45,  0x82,
+  0xfe,  0x05,  0xf6,  0xfe,  0x34,  0x01,  0x01,  0xfe,  0x56,  0x17,  0x11,  0x48,  0xd2,  0x08,  0x06,  0x03,
+  0x2b,  0x03,  0x29,  0x5e,  0xfe,  0xf7,  0x12,  0x29,  0xb4,  0x72,  0x16,  0xb4,  0x05,  0x84,  0xfe,  0x93,
+  0x13,  0xfe,  0x24,  0x1c,  0x17,  0x18,  0x4c,  0xfe,  0x9b,  0x00,  0xe5,  0xfe,  0xd9,  0x10,  0x9c,  0xfe,
+  0x03,  0xdc,  0xfe,  0x73,  0x57,  0xfe,  0x80,  0x5d,  0x03,  0x9c,  0xfe,  0x03,  0xdc,  0xfe,  0x5b,  0x57,
+  0xfe,  0x80,  0x5d,  0x03,  0xfe,  0x03,  0x57,  0x9c,  0x2b,  0xfe,  0x00,  0xcc,  0x03,  0xfe,  0x03,  0x57,
+  0x9c,  0x80,  0x03,  0x01,  0xfe,  0x8e,  0x17,  0x40,  0x05,  0x48,  0xfe,  0x0a,  0x13,  0x08,  0x1e,  0x09,
+  0x52,  0xdd,  0x01,  0x9f,  0x01,  0xa1,  0x08,  0x3f,  0x09,  0xa2,  0x01,  0x45,  0x11,  0xfe,  0xe9,  0x00,
+  0x0a,  0x07,  0x8f,  0xfe,  0x52,  0x13,  0x01,  0xfe,  0x18,  0x17,  0xfe,  0x1e,  0x1c,  0xfe,  0x14,  0x90,
+  0x0d,  0xfe,  0x64,  0x01,  0xfe,  0x16,  0x90,  0x0d,  0xfe,  0x66,  0x01,  0x0a,  0x07,  0x46,  0xef,  0xfe,
+  0x03,  0x80,  0x5b,  0x4d,  0x11,  0x7b,  0x08,  0x2d,  0x09,  0x3e,  0x1c,  0x7a,  0x01,  0x90,  0xfe,  0x62,
+  0x08,  0x72,  0x4d,  0x11,  0x7b,  0x08,  0x2d,  0x09,  0x3e,  0x1c,  0x7a,  0x01,  0x90,  0x6d,  0x31,  0x11,
+  0x7b,  0x08,  0x2d,  0x09,  0x3e,  0x1c,  0x7a,  0x01,  0x7e,  0x03,  0xfe,  0x08,  0x1c,  0x04,  0xfe,  0xac,
+  0x00,  0xfe,  0x06,  0x58,  0x04,  0xfe,  0xae,  0x00,  0xfe,  0x07,  0x58,  0x04,  0xfe,  0xb0,  0x00,  0xfe,
+  0x08,  0x58,  0x04,  0xfe,  0xb2,  0x00,  0xfe,  0x09,  0x58,  0xfe,  0x0a,  0x1c,  0x20,  0x74,  0x16,  0xfe,
+  0xb9,  0x00,  0x2b,  0x0d,  0x5c,  0x0d,  0x56,  0x20,  0x10,  0x16,  0x2d,  0x16,  0x3e,  0x51,  0xa6,  0xfe,
+  0x93,  0x00,  0x08,  0x2d,  0x09,  0x3e,  0x1c,  0x01,  0x7e,  0x82,  0x11,  0x7b,  0xfe,  0x14,  0x56,  0xfe,
+  0xd6,  0xf0,  0x8a,  0xde,  0x92,  0xfe,  0x14,  0x1c,  0xfe,  0x10,  0x1c,  0xfe,  0x18,  0x1c,  0x03,  0x1c,
+  0xfe,  0x0c,  0x14,  0x8c,  0xfe,  0x07,  0xe6,  0x38,  0xfe,  0xce,  0x47,  0xfe,  0xf5,  0x13,  0x03,  0x01,
+  0xc2,  0x0f,  0x3f,  0x01,  0x15,  0x05,  0x10,  0xdb,  0x0f,  0x1e,  0x01,  0x15,  0x05,  0x10,  0xe2,  0xfe,
+  0x44,  0x58,  0x4d,  0xfe,  0x01,  0xec,  0xc4,  0xfe,  0x9e,  0x40,  0xfe,  0x9d,  0xe7,  0x00,  0xfe,  0x9c,
+  0xe7,  0x1d,  0xa5,  0x31,  0x01,  0xea,  0xfe,  0xc9,  0x10,  0x03,  0x2e,  0x86,  0x76,  0x24,  0x23,  0xba,
+  0x05,  0x1d,  0xfe,  0x48,  0x12,  0x05,  0x0b,  0xfe,  0x4c,  0x12,  0x05,  0x18,  0xfe,  0x30,  0x12,  0x05,
+  0xd4,  0x19,  0xfe,  0xd4,  0x11,  0x05,  0xfe,  0x23,  0x00,  0x19,  0xfe,  0xe0,  0x11,  0x05,  0x06,  0x19,
+  0xfe,  0x3e,  0x12,  0x05,  0x22,  0xfe,  0x12,  0x12,  0x05,  0x00,  0x19,  0x26,  0x17,  0xd4,  0x01,  0x3b,
+  0xce,  0x3a,  0x01,  0x0c,  0x85,  0x55,  0x03,  0x3a,  0x11,  0xfe,  0xcc,  0x00,  0x02,  0x27,  0x3a,  0x40,
+  0x05,  0xcb,  0xfe,  0xe3,  0x13,  0x36,  0x3c,  0x21,  0x3d,  0x53,  0xfe,  0x92,  0x11,  0x0a,  0x07,  0x60,
+  0xfe,  0x72,  0x12,  0x83,  0x30,  0x5a,  0x42,  0x95,  0xca,  0x98,  0xfe,  0x5c,  0x11,  0x29,  0x68,  0xfe,
+  0x26,  0x13,  0x04,  0xb5,  0x2a,  0x93,  0x53,  0xfe,  0xb2,  0x0d,  0x0d,  0x66,  0x12,  0x67,  0x2b,  0x0d,
+  0xb5,  0x0d,  0x93,  0x01,  0xc5,  0x20,  0x74,  0x5b,  0x16,  0x68,  0x01,  0xfe,  0xbe,  0x13,  0x83,  0x30,
+  0x5a,  0x42,  0xfe,  0x04,  0x55,  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,  0x30,  0xfe,  0x05,  0xfa,  0x42,
+  0xfe,  0x91,  0x10,  0x04,  0x43,  0x2a,  0x44,  0xfe,  0x40,  0x56,  0xfe,  0xe1,  0x56,  0x0d,  0x43,  0x12,
+  0x44,  0xad,  0x83,  0x30,  0x5a,  0x42,  0x95,  0xca,  0x04,  0x64,  0x2a,  0x65,  0xfe,  0x00,  0x56,  0xfe,
+  0xa1,  0x56,  0x0d,  0x64,  0x12,  0x65,  0x0a,  0x07,  0x60,  0xfe,  0x1e,  0x12,  0x29,  0x68,  0xfe,  0x1f,
+  0x40,  0x04,  0x66,  0x2a,  0x67,  0xfe,  0x2c,  0x50,  0xfe,  0xae,  0x50,  0x04,  0x43,  0x2a,  0x44,  0xfe,
+  0x34,  0x50,  0xfe,  0xb6,  0x50,  0x04,  0x64,  0x2a,  0x65,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0x04,
+  0x3c,  0x2a,  0x3d,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,  0x02,  0xa0,  0x20,  0x06,  0x16,  0xfc,  0x02,
+  0x7f,  0x3a,  0x01,  0x0c,  0x1f,  0x57,  0x24,  0x23,  0xba,  0x05,  0x06,  0x28,  0x57,  0x40,  0x05,  0xcb,
+  0x28,  0x7f,  0x01,  0xfe,  0x9c,  0x13,  0x1a,  0x59,  0x19,  0x57,  0x0a,  0x07,  0x0b,  0xe4,  0x36,  0x3c,
+  0x21,  0x3d,  0xfe,  0x0a,  0x55,  0x35,  0xfe,  0x8b,  0x55,  0x4e,  0x3c,  0x70,  0x3d,  0xfe,  0x0c,  0x51,
+  0xfe,  0x8e,  0x51,  0x02,  0x7f,  0xdf,  0xfe,  0x0a,  0x45,  0xfe,  0x19,  0x41,  0x02,  0x7f,  0x3a,  0x01,
+  0x0c,  0x1f,  0xfe,  0xd6,  0x10,  0x24,  0x23,  0xfe,  0xe9,  0x09,  0x61,  0x18,  0xfe,  0x94,  0x12,  0x61,
+  0x0b,  0x4f,  0x02,  0x57,  0x2f,  0xfe,  0x5e,  0x12,  0x1b,  0x32,  0x1f,  0xfe,  0xd6,  0x10,  0x24,  0x23,
+  0x9a,  0x05,  0x18,  0x28,  0x57,  0x01,  0x0c,  0x1f,  0xfe,  0xd6,  0x10,  0x24,  0x23,  0xfe,  0xe8,  0x09,
+  0x51,  0x04,  0xfe,  0x9c,  0x00,  0x2c,  0x35,  0xfe,  0xbb,  0x45,  0x61,  0x00,  0x50,  0x37,  0x06,  0xa6,
+  0x59,  0xfe,  0xc0,  0x14,  0xfe,  0xf8,  0x14,  0xb3,  0x40,  0x05,  0xc9,  0xfe,  0x16,  0x13,  0x04,  0xfe,
+  0x9e,  0x00,  0x2c,  0xd6,  0x04,  0x56,  0x2c,  0x35,  0x63,  0x02,  0x7f,  0xfe,  0xc0,  0x5d,  0xfe,  0xe4,
+  0x14,  0xfe,  0x03,  0x17,  0x04,  0x5c,  0xc3,  0x0d,  0x5c,  0x63,  0x3a,  0x01,  0x0c,  0x25,  0xa0,  0x01,
+  0xfe,  0x06,  0x15,  0x02,  0xa0,  0x2f,  0xfe,  0xe8,  0x12,  0x1b,  0x32,  0x1f,  0x57,  0x24,  0x23,  0x9a,
+  0x05,  0x06,  0x28,  0x57,  0xfe,  0xf6,  0x14,  0xfe,  0x42,  0x58,  0xfe,  0x70,  0x14,  0xfe,  0x92,  0x14,
+  0xb3,  0xfe,  0x4a,  0xf4,  0x0b,  0x19,  0x57,  0xfe,  0x4a,  0xf4,  0x06,  0xd8,  0x40,  0x05,  0xc9,  0xd1,
+  0x02,  0x7f,  0x04,  0x56,  0xc3,  0x0d,  0x56,  0x63,  0x3a,  0x01,  0x0c,  0x25,  0xa0,  0x01,  0xfe,  0x34,
+  0x15,  0x02,  0xa0,  0x25,  0xfe,  0x50,  0x13,  0x78,  0xf9,  0x78,  0x03,  0x34,  0xfe,  0x4c,  0x13,  0x73,
+  0xfe,  0x4c,  0x13,  0x63,  0x3a,  0x01,  0x0c,  0xfe,  0xe3,  0x10,  0x08,  0x6c,  0xff,  0x02,  0x00,  0x57,
+  0x6e,  0x81,  0x1a,  0xfe,  0xff,  0x7f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x08,  0x6c,  0xff,
+  0x02,  0x00,  0x57,  0x6e,  0x81,  0x1a,  0x59,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x08,  0x6c,
+  0xff,  0x02,  0x00,  0x57,  0x6e,  0x81,  0x03,  0x08,  0x6c,  0xff,  0x02,  0x00,  0x57,  0x6e,  0x81,  0xfe,
+  0x0b,  0x58,  0x03,  0x0f,  0x5c,  0x01,  0x8e,  0x0f,  0x56,  0x01,  0x8e,  0x03,  0xd0,  0x1a,  0x10,  0xff,
+  0x03,  0x00,  0x54,  0xfe,  0x00,  0xf4,  0x22,  0x6e,  0xfe,  0x00,  0x7d,  0xfe,  0x01,  0x7d,  0xfe,  0x02,
+  0x7d,  0xfe,  0x03,  0x7c,  0x6d,  0x31,  0x0d,  0x64,  0x12,  0x65,  0x4e,  0x43,  0x70,  0x44,  0x03,  0xfe,
+  0x62,  0x18,  0xfe,  0x82,  0x5a,  0xfe,  0xe1,  0x1a,  0xbf,  0xfe,  0x02,  0x58,  0x03,  0x01,  0xfe,  0x7e,
+  0x19,  0xfe,  0x42,  0x48,  0x6a,  0x51,  0x9e,  0x01,  0x0c,  0x1f,  0xfe,  0xfe,  0x14,  0x24,  0x23,  0xfe,
+  0xe9,  0x09,  0xfe,  0xc1,  0x59,  0x01,  0x0c,  0x1f,  0xfe,  0xfe,  0x14,  0x24,  0x23,  0xfe,  0xe8,  0x0a,
+  0x04,  0xfe,  0x9e,  0x00,  0x2c,  0xfe,  0xc4,  0x12,  0x2b,  0xb8,  0x1d,  0xe4,  0x61,  0xd5,  0x79,  0xfe,
+  0x4c,  0x14,  0x4f,  0x08,  0x06,  0x09,  0xd5,  0xa6,  0xfe,  0x00,  0x10,  0xfe,  0x78,  0x10,  0xff,  0x02,
+  0x83,  0x55,  0x8a,  0xff,  0x02,  0x83,  0x55,  0xb8,  0x18,  0xfe,  0x12,  0x13,  0x62,  0xfe,  0x30,  0x00,
+  0x98,  0xfe,  0xa6,  0x14,  0x09,  0x8b,  0x08,  0x06,  0xfe,  0x56,  0x10,  0xb8,  0x0b,  0xfe,  0x16,  0x13,
+  0x62,  0xfe,  0x64,  0x00,  0x98,  0xfe,  0xa6,  0x14,  0x0f,  0xfe,  0x64,  0x00,  0x09,  0xb1,  0x08,  0x06,
+  0xfe,  0x28,  0x10,  0xb8,  0x06,  0xfe,  0x60,  0x13,  0x62,  0xfe,  0xc8,  0x00,  0x98,  0xfe,  0xa6,  0x14,
+  0x0f,  0xfe,  0xc8,  0x00,  0x09,  0x5e,  0x08,  0x06,  0xad,  0x62,  0xfe,  0x90,  0x01,  0x99,  0xfe,  0xb2,
+  0x14,  0x9e,  0xb0,  0xfe,  0x43,  0xf4,  0xb4,  0xfe,  0x56,  0xf0,  0xfe,  0xc4,  0x14,  0xfe,  0x04,  0xf4,
+  0x6c,  0xfe,  0x43,  0xf4,  0xb1,  0xfe,  0xf3,  0x10,  0xb7,  0x01,  0xfe,  0x8e,  0x13,  0x1a,  0x59,  0xaf,
+  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x74,  0x99,  0xfe,  0xf8,  0x14,  0xa8,  0x74,  0xfe,  0x14,  0x10,
+  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0xf1,  0x99,  0xfe,  0xf8,  0x14,  0xa8,  0xf1,  0xa4,  0x51,  0x9e,
+  0x08,  0x06,  0xfe,  0xb4,  0x56,  0xfe,  0xc3,  0x58,  0x03,  0x51,  0x08,  0x0b,  0x03,  0x14,  0x06,  0x01,
+  0x0c,  0x25,  0xec,  0x14,  0x0b,  0x01,  0x0c,  0x25,  0xec,  0x14,  0x18,  0x01,  0x0c,  0x25,  0xec,  0x78,
+  0xfe,  0x89,  0x49,  0x01,  0x0c,  0x03,  0x14,  0x06,  0x01,  0x0c,  0x25,  0xbc,  0x14,  0x18,  0x01,  0x0c,
+  0x25,  0xbc,  0x14,  0x06,  0x01,  0x0c,  0x25,  0xbc,  0xfe,  0x89,  0x49,  0x01,  0x0c,  0x25,  0xbc,  0x78,
+  0xfe,  0x89,  0x4a,  0x01,  0x0c,  0x03,  0x51,  0x03,  0x29,  0xe8,  0x05,  0x06,  0x3b,  0xb6,  0x16,  0xe8,
+  0xfe,  0x49,  0xf4,  0x00,  0x4f,  0x78,  0xce,  0x63,  0xfe,  0x01,  0xec,  0xfe,  0x27,  0x01,  0xf9,  0x01,
+  0x0c,  0x40,  0x05,  0xfe,  0xe3,  0x00,  0xfe,  0x20,  0x13,  0x1f,  0xfe,  0xb6,  0x15,  0x2b,  0x16,  0xfc,
+  0x01,  0x55,  0x29,  0xfc,  0x05,  0x06,  0x50,  0x0a,  0x41,  0x06,  0x39,  0x03,  0x0d,  0x5d,  0x12,  0x91,
+  0xfe,  0x43,  0x58,  0x01,  0x15,  0x05,  0x10,  0xfe,  0x1e,  0x12,  0x4a,  0xf3,  0x96,  0x01,  0x49,  0xfe,
+  0x90,  0x4d,  0xe6,  0x10,  0xfe,  0xc5,  0x59,  0x01,  0x49,  0xfe,  0x8d,  0x56,  0xbf,  0x4a,  0x03,  0x4a,
+  0x21,  0x91,  0x01,  0x15,  0x4a,  0x96,  0x01,  0x49,  0xeb,  0x10,  0xe6,  0x10,  0x21,  0x5d,  0x62,  0x1e,
+  0x89,  0x0f,  0x5f,  0x01,  0xaa,  0x03,  0x0d,  0x5d,  0x12,  0x91,  0xfe,  0xc3,  0x58,  0x01,  0x15,  0x05,
+  0x10,  0xfe,  0x1a,  0x12,  0x4a,  0xf3,  0x96,  0x01,  0x49,  0xeb,  0x10,  0xfe,  0x80,  0x4d,  0xfe,  0xc5,
+  0x59,  0x01,  0x49,  0x4a,  0x03,  0x4a,  0x21,  0x5d,  0x01,  0x15,  0x4a,  0x96,  0x01,  0x49,  0xeb,  0x10,
+  0xe6,  0x10,  0x21,  0x5d,  0x62,  0x1e,  0x89,  0x0f,  0x5f,  0x01,  0xaa,  0x03,  0x0d,  0x5d,  0x12,  0x91,
+  0xfe,  0x43,  0x58,  0x01,  0x15,  0xfe,  0x42,  0x48,  0x96,  0x01,  0x49,  0xfe,  0xc0,  0x5a,  0xb7,  0xfe,
+  0x00,  0xcd,  0xfe,  0x01,  0xcc,  0xfe,  0x4a,  0x46,  0xe4,  0x9c,  0x80,  0x05,  0x10,  0xfe,  0x2e,  0x13,
+  0x5a,  0x5d,  0xfe,  0x4d,  0xf4,  0x1e,  0xfe,  0x1c,  0x13,  0x0f,  0x5f,  0x01,  0x8e,  0xb0,  0xfe,  0x40,
+  0x4c,  0xfe,  0xc5,  0x58,  0x01,  0x49,  0xfe,  0x00,  0x07,  0x80,  0x05,  0x10,  0x89,  0x5a,  0x91,  0xfe,
+  0x05,  0x57,  0xfe,  0x08,  0x10,  0xfe,  0x45,  0x58,  0x01,  0x49,  0xfe,  0x8d,  0x56,  0xbf,  0xfe,  0x80,
+  0x4c,  0xfe,  0x05,  0x17,  0x03,  0x09,  0x10,  0x77,  0x6f,  0xfe,  0x60,  0x01,  0xfe,  0x18,  0xdf,  0xfe,
+  0x19,  0xde,  0xfe,  0x24,  0x1c,  0xe3,  0x38,  0x9d,  0xfe,  0xfa,  0x16,  0x01,  0xfe,  0x08,  0x18,  0xd9,
+  0x8d,  0x38,  0x6f,  0xfe,  0x2c,  0x01,  0xfe,  0x2f,  0x19,  0x03,  0xc0,  0x28,  0xfe,  0xea,  0x16,  0xfe,
+  0xe2,  0x10,  0x09,  0x10,  0x77,  0x04,  0xfe,  0x64,  0x01,  0xfe,  0x00,  0xf4,  0x22,  0xfe,  0x18,  0x58,
+  0x04,  0xfe,  0x66,  0x01,  0xfe,  0x19,  0x58,  0x8d,  0x22,  0xfe,  0x3c,  0x90,  0xfe,  0x30,  0xf4,  0x06,
+  0xfe,  0x3c,  0x50,  0x6f,  0xfe,  0x38,  0x00,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0x22,  0x9d,  0xfe,
+  0x44,  0x17,  0xfe,  0xbe,  0x14,  0x35,  0x03,  0xc0,  0x28,  0xfe,  0x1c,  0x17,  0xfe,  0xa4,  0x10,  0x09,
+  0x10,  0x77,  0xbf,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xdf,  0xe3,  0x30,  0x9d,  0xfe,  0x66,  0x17,  0xfe,
+  0x9c,  0x14,  0xfe,  0x18,  0x13,  0x8d,  0x30,  0x6f,  0x1d,  0xfe,  0xaf,  0x19,  0xfe,  0x98,  0xe7,  0x00,
+  0xa7,  0x07,  0xfe,  0x7f,  0x00,  0xfe,  0x05,  0x40,  0x03,  0xc0,  0x28,  0xfe,  0x5a,  0x17,  0xfe,  0x6c,
+  0x10,  0x09,  0x10,  0x77,  0xfe,  0x30,  0xbc,  0xfe,  0xb2,  0xbc,  0x8d,  0xe1,  0x6f,  0x1d,  0xfe,  0x0f,
+  0x79,  0xfe,  0x1c,  0xf7,  0xe1,  0x9d,  0xfe,  0xa6,  0x17,  0xfe,  0x5c,  0x14,  0x35,  0x03,  0xc0,  0x28,
+  0xfe,  0x92,  0x17,  0xfe,  0x42,  0x10,  0xfe,  0x02,  0xf6,  0x10,  0x77,  0xfe,  0x18,  0xfe,  0x66,  0xfe,
+  0x19,  0xfe,  0x67,  0xd0,  0xe3,  0x46,  0x9d,  0xfe,  0xcc,  0x17,  0xfe,  0x36,  0x14,  0xfe,  0x1c,  0x13,
+  0x8d,  0x46,  0x47,  0xfe,  0x83,  0x58,  0xfe,  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x10,  0xfe,  0x81,  0xe7,
+  0x10,  0x11,  0xfe,  0xdd,  0x00,  0x6d,  0x31,  0x03,  0x6d,  0x31,  0xfe,  0x12,  0x45,  0x28,  0xfe,  0xbc,
+  0x17,  0x17,  0x06,  0x4c,  0xfe,  0x9b,  0x00,  0xe5,  0x02,  0x27,  0xfe,  0x39,  0xf0,  0xfe,  0x10,  0x18,
+  0x2b,  0x03,  0xfe,  0x7e,  0x18,  0x1a,  0x18,  0x87,  0x08,  0x0e,  0x03,  0x77,  0x04,  0xe7,  0x1a,  0x06,
+  0xfe,  0xef,  0x12,  0xfe,  0xe1,  0x10,  0x1c,  0x0f,  0x1e,  0x01,  0x15,  0x05,  0x10,  0x50,  0x4d,  0xfe,
+  0x78,  0x14,  0xfe,  0x34,  0x12,  0x59,  0x8c,  0x37,  0x38,  0xc7,  0xfe,  0xe9,  0x13,  0x1c,  0x0f,  0x3f,
+  0x01,  0x15,  0x05,  0x10,  0x50,  0x4d,  0xfe,  0x56,  0x14,  0xe9,  0x59,  0x8c,  0x37,  0x38,  0xc7,  0xfe,
+  0xe9,  0x13,  0x09,  0x0b,  0x03,  0xfe,  0x9c,  0xe7,  0x0b,  0x13,  0xfe,  0x15,  0x00,  0x7a,  0xa5,  0x31,
+  0x01,  0xea,  0x09,  0x06,  0x03,  0x0a,  0x41,  0x38,  0x39,  0x08,  0x3f,  0x09,  0xa2,  0x01,  0x45,  0x11,
+  0x48,  0x08,  0x1e,  0x09,  0x52,  0x01,  0x7e,  0x09,  0x06,  0x03,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,
+  0x36,  0xfe,  0xa8,  0x00,  0x21,  0x7b,  0xfe,  0x48,  0x55,  0x35,  0xfe,  0xc9,  0x55,  0x03,  0x29,  0xc6,
+  0x5b,  0x16,  0xc6,  0x03,  0x0f,  0xc8,  0x01,  0x15,  0xf2,  0x0f,  0x7d,  0x01,  0x15,  0xfe,  0x49,  0x44,
+  0x28,  0xfe,  0x06,  0x19,  0x0f,  0x1e,  0x01,  0x15,  0x05,  0x10,  0x50,  0x0f,  0x5f,  0x01,  0xaa,  0x0f,
+  0x7d,  0x01,  0x15,  0x5b,  0x80,  0x03,  0xfe,  0x40,  0x5e,  0xfe,  0xe2,  0x08,  0xfe,  0xc0,  0x4c,  0x29,
+  0x3e,  0x05,  0x10,  0xfe,  0x52,  0x12,  0x4d,  0x05,  0x00,  0xfe,  0x18,  0x12,  0xfe,  0xe1,  0x18,  0xfe,
+  0x19,  0xf4,  0xfe,  0x7f,  0x00,  0xaf,  0xfe,  0xe2,  0x08,  0x5b,  0x4d,  0x40,  0x05,  0x7b,  0xab,  0xfe,
+  0x82,  0x48,  0xfe,  0x01,  0x80,  0xfe,  0xd7,  0x10,  0xfe,  0xc4,  0x48,  0x08,  0x2d,  0x09,  0x3e,  0xfe,
+  0x40,  0x5f,  0x1c,  0x01,  0x45,  0x11,  0xfe,  0xdd,  0x00,  0xfe,  0x14,  0x46,  0x08,  0x2d,  0x09,  0x3e,
+  0x01,  0x45,  0x11,  0xfe,  0xdd,  0x00,  0xfe,  0x40,  0x4a,  0x72,  0xfe,  0x06,  0x17,  0xfe,  0x01,  0x07,
+  0xfe,  0x82,  0x48,  0xfe,  0x04,  0x17,  0x03,  0xf5,  0x18,  0x79,  0xfe,  0x8e,  0x19,  0x04,  0xfe,  0x90,
+  0x00,  0xfe,  0x3a,  0x45,  0xfe,  0x2c,  0x10,  0xf5,  0xd4,  0x79,  0xfe,  0xa0,  0x19,  0x04,  0xfe,  0x92,
+  0x00,  0xcf,  0x1d,  0xe0,  0xf5,  0xfe,  0x0b,  0x00,  0x79,  0xfe,  0xb2,  0x19,  0x04,  0xfe,  0x94,  0x00,
+  0xcf,  0x22,  0xfe,  0x08,  0x10,  0x04,  0xfe,  0x96,  0x00,  0xcf,  0x8b,  0xfe,  0x4e,  0x45,  0xd8,  0xfe,
+  0x0a,  0x45,  0xff,  0x04,  0x68,  0x54,  0xfe,  0xf1,  0x10,  0x1a,  0x74,  0xfe,  0x08,  0x1c,  0xfe,  0x67,
+  0x19,  0xfe,  0x0a,  0x1c,  0xfe,  0x1a,  0xf4,  0xfe,  0x00,  0x04,  0xd8,  0xfe,  0x48,  0xf4,  0x18,  0x99,
+  0xfe,  0xe6,  0x19,  0x08,  0x18,  0x03,  0x05,  0x84,  0xfe,  0x5a,  0xf0,  0xfe,  0xf6,  0x19,  0x20,  0xfe,
+  0x09,  0x00,  0xfe,  0x34,  0x10,  0x05,  0x1d,  0xfe,  0x5a,  0xf0,  0xfe,  0x04,  0x1a,  0x20,  0xd5,  0xfe,
+  0x26,  0x10,  0x05,  0x18,  0x87,  0x20,  0x8b,  0xe0,  0x05,  0x0b,  0x87,  0x20,  0xb1,  0xfe,  0x0e,  0x10,
+  0x05,  0x06,  0x87,  0x20,  0x5e,  0xce,  0xb6,  0x03,  0x17,  0xfe,  0x09,  0x00,  0x01,  0x3b,  0x2f,  0xfe,
+  0x34,  0x1a,  0x04,  0x76,  0xb7,  0x03,  0x1b,  0xfe,  0x54,  0x1a,  0xfe,  0x14,  0xf0,  0x0c,  0x2f,  0xfe,
+  0x48,  0x1a,  0x1b,  0xfe,  0x54,  0x1a,  0xfe,  0x82,  0xf0,  0xfe,  0x4c,  0x1a,  0x03,  0xff,  0x15,  0x00,
+  0x00,
+};
 
 STATIC unsigned short _adv_asc38C0800_size =
-    sizeof(_adv_asc38C0800_buf); /* 0x14AA */
-STATIC unsigned long _adv_asc38C0800_chksum =
-    0x05297A65UL; /* Expanded checksum. */
+    sizeof(_adv_asc38C0800_buf); /* 0x14F1 */
+STATIC ADV_DCNT _adv_asc38C0800_chksum =
+    0x053503A5; /* Expanded checksum. */
 
 /* a_init.c */
 /*
@@ -15384,8 +15456,8 @@
  */
 STATIC ADVEEP_3550_CONFIG
 Default_3550_EEPROM_Config ASC_INITDATA = {
-    ADV_EEPROM_BIOS_ENABLE,     /* cfg_msw */
-    0x0000,                     /* cfg_lsw */
+    ADV_EEPROM_BIOS_ENABLE,     /* cfg_lsw */
+    0x0000,                     /* cfg_msw */
     0xFFFF,                     /* disc_enable */
     0xFFFF,                     /* wdtr_able */
     0xFFFF,                     /* sdtr_able */
@@ -15422,8 +15494,8 @@
 
 STATIC ADVEEP_38C0800_CONFIG
 Default_38C0800_EEPROM_Config ASC_INITDATA = {
-    ADV_EEPROM_BIOS_ENABLE,     /* 00 cfg_msw */
-    0x0000,                     /* 01 cfg_lsw */
+    ADV_EEPROM_BIOS_ENABLE,     /* 00 cfg_lsw */
+    0x0000,                     /* 01 cfg_msw */
     0xFFFF,                     /* 02 disc_enable */
     0xFFFF,                     /* 03 wdtr_able */
     0x4444,                     /* 04 sdtr_speed1 */
@@ -15509,6 +15581,9 @@
 
     /*
      * PCI Command Register
+     *
+     * Note: AscPCICmdRegBits_BusMastering definition (0x0007) includes
+     * I/O Space Control, Memory Space Control and Bus Master Control bits.
      */
 
     if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc,
@@ -15562,11 +15637,11 @@
     asc_dvc->cfg->chip_version =
       AdvGetChipVersion(iop_base, asc_dvc->bus_type);
 
-    ASC_DBG2(1, "iopb_chip_id_1: %x %x\n",
+    ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: %x %x\n",
         (ushort) AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
         (ushort) ADV_CHIP_ID_BYTE);
 
-    ASC_DBG2(1, "iopw_chip_id_0: %x %x\n",
+    ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: %x %x\n",
         (ushort) AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
         (ushort) ADV_CHIP_ID_WORD);
 
@@ -15631,7 +15706,7 @@
 {
     AdvPortAddr iop_base;
     ushort      warn_code;
-    ulong       sum;
+    ADV_DCNT    sum;
     int         begin_addr;
     int         end_addr;
     ushort      code_sum;
@@ -15639,9 +15714,9 @@
     int         j;
     int         adv_asc3550_expanded_size;
     ADV_CARR_T  *carrp;
-    ulong       contig_len;
-    long        buf_size;
-    ulong       carr_paddr;
+    ADV_DCNT    contig_len;
+    ADV_SDCNT   buf_size;
+    ADV_PADDR   carr_paddr;
     int         i;
     ushort      scsi_cfg1;
     uchar       tid;
@@ -15690,7 +15765,7 @@
         bios_version = bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM)/2];
         major = (bios_version  >> 12) & 0xF;
         minor = (bios_version  >> 8) & 0xF;
-        if (major <= 3 || (major == 3 && minor == 1))
+        if (major < 3 || (major == 3 && minor == 1))
         {
             /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
             AdvReadWordLram(iop_base, 0x120, wdtr_able);
@@ -15735,21 +15810,24 @@
         {
             for (j = 0; j < _adv_asc3550_buf[i + 1]; j++)
             {
-                AdvWriteWordAutoIncLram(iop_base,
-                    *((ushort *) (&_adv_asc3550_buf[i + 2])));
+                AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                    _adv_asc3550_buf[i + 3] << 8) |
+                    _adv_asc3550_buf[i + 2]));
                 word++;
             }
-           i += 3;
+            i += 3;
         } else if (_adv_asc3550_buf[i] == 0xfe)
         {
-            AdvWriteWordAutoIncLram(iop_base,
-                *((ushort *) (&_adv_asc3550_buf[i + 1])));
+            AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                _adv_asc3550_buf[i + 2] << 8) |
+                _adv_asc3550_buf[i + 1]));
             i += 2;
             word++;
         } else
         {
-            AdvWriteWordAutoIncLram(iop_base,
-                *((ushort *) &_adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
+            AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) |
+                _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
             word++;
         }
     }
@@ -15849,7 +15927,7 @@
      * queuing will be set in AdvInquiryHandling() based on what a
      * device reports it is capable of in Inquiry byte 7.
      *
-     * If SCSI Bus Resets haev been disabled, then directly set
+     * If SCSI Bus Resets have been disabled, then directly set
      * SDTR and WDTR from the EEPROM configuration. This will allow
      * the BIOS and warm boot to work without a SCSI bus hang on
      * the Inquiry caused by host and target mismatched DTR values.
@@ -16028,7 +16106,7 @@
      * after it is started below.
      */
     AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
-        FLTR_11_TO_20NS | scsi_cfg1);
+        FLTR_DISABLE | scsi_cfg1);
 
     /*
      * Set MEM_CFG Microcode Default Value
@@ -16058,7 +16136,7 @@
      *
      * Driver must have already allocated memory and set 'carrier_buf'.
      */
-    ADV_ASSERT(asc_dvc->carrier_buf != NULL);
+    ASC_ASSERT(asc_dvc->carrier_buf != NULL);
 
     carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
     asc_dvc->carr_freelist = NULL;
@@ -16075,8 +16153,8 @@
          * Get physical address of the carrier 'carrp'.
          */
         contig_len = sizeof(ADV_CARR_T);
-        carr_paddr = DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
-            (long *) &contig_len, ADV_IS_CARRIER_FLAG);
+        carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
+            (ADV_SDCNT *) &contig_len, ADV_IS_CARRIER_FLAG));
 
         buf_size -= sizeof(ADV_CARR_T);
 
@@ -16092,12 +16170,12 @@
         }
 
         carrp->carr_pa = carr_paddr;
-        carrp->carr_va = (ulong) carrp;
+        carrp->carr_va = ADV_VADDR_TO_U32(carrp);
 
         /*
          * Insert the carrier at the beginning of the freelist.
          */
-        carrp->next_vpa = (ulong) asc_dvc->carr_freelist;
+        carrp->next_vpa = ADV_VADDR_TO_U32(asc_dvc->carr_freelist);
         asc_dvc->carr_freelist = carrp;
 
         carrp++;
@@ -16113,7 +16191,8 @@
         asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
         return ADV_ERROR;
     }
-    asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->icq_sp->next_vpa;
+    asc_dvc->carr_freelist =
+        (ADV_CARR_T *) ADV_U32_TO_VADDR(asc_dvc->icq_sp->next_vpa);
 
     /*
      * The first command issued will be placed in the stopper carrier.
@@ -16123,7 +16202,8 @@
     /*
      * Set RISC ICQ physical address start value.
      */
-    AdvWriteDWordLram(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+    AdvWriteDWordLram(iop_base, ASC_MC_ICQ,
+        cpu_to_le32(asc_dvc->icq_sp->carr_pa));
 
     /*
      * Set-up the RISC->Host Initiator Response Queue (IRQ).
@@ -16133,7 +16213,8 @@
         asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
         return ADV_ERROR;
     }
-    asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->irq_sp->next_vpa;
+    asc_dvc->carr_freelist =
+        (ADV_CARR_T *) ADV_U32_TO_VADDR(asc_dvc->irq_sp->next_vpa);
 
     /*
      * The first command completed by the RISC will be placed in
@@ -16147,7 +16228,8 @@
     /*
      * Set RISC IRQ physical address start value.
      */
-    AdvWriteDWordLram(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+    AdvWriteDWordLram(iop_base, ASC_MC_IRQ,
+        cpu_to_le32(asc_dvc->irq_sp->carr_pa));
     asc_dvc->carr_pending_cnt = 0;
 
     AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
@@ -16214,7 +16296,7 @@
 {
     AdvPortAddr iop_base;
     ushort      warn_code;
-    ulong       sum;
+    ADV_DCNT    sum;
     int         begin_addr;
     int         end_addr;
     ushort      code_sum;
@@ -16222,9 +16304,9 @@
     int         j;
     int         adv_asc38C0800_expanded_size;
     ADV_CARR_T  *carrp;
-    ulong       contig_len;
-    long        buf_size;
-    ulong       carr_paddr;
+    ADV_DCNT    contig_len;
+    ADV_SDCNT   buf_size;
+    ADV_PADDR   carr_paddr;
     int         i;
     ushort      scsi_cfg1;
     uchar       byte;
@@ -16378,21 +16460,24 @@
         {
             for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++)
             {
-                AdvWriteWordAutoIncLram(iop_base,
-                    *((ushort *) (&_adv_asc38C0800_buf[i + 2])));
+                AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                    _adv_asc38C0800_buf[i + 3] << 8) |
+                    _adv_asc38C0800_buf[i + 2]));
                 word++;
             }
-           i += 3;
+            i += 3;
         } else if (_adv_asc38C0800_buf[i] == 0xfe)
         {
-            AdvWriteWordAutoIncLram(iop_base,
-                *((ushort *) (&_adv_asc38C0800_buf[i + 1])));
+            AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                _adv_asc38C0800_buf[i + 2] << 8) |
+                _adv_asc38C0800_buf[i + 1]));
             i += 2;
             word++;
         } else
         {
-            AdvWriteWordAutoIncLram(iop_base, *((ushort *)
-                &_adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
+            AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) |
+                _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
             word++;
         }
     }
@@ -16422,6 +16507,11 @@
     {
         sum += AdvReadWordAutoIncLram(iop_base);
     }
+    ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
+
+    ASC_DBG2(1,
+        "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
+        (ulong) sum, (ulong) _adv_asc38C0800_chksum);
 
     if (sum != _adv_asc38C0800_chksum)
     {
@@ -16677,8 +16767,7 @@
      *
      * Driver must have already allocated memory and set 'carrier_buf'.
      */
-
-    ADV_ASSERT(asc_dvc->carrier_buf != NULL);
+    ASC_ASSERT(asc_dvc->carrier_buf != NULL);
 
     carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
     asc_dvc->carr_freelist = NULL;
@@ -16695,8 +16784,8 @@
          * Get physical address for the carrier 'carrp'.
          */
         contig_len = sizeof(ADV_CARR_T);
-        carr_paddr = DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
-            (long *) &contig_len, ADV_IS_CARRIER_FLAG);
+        carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
+            (ADV_SDCNT *) &contig_len, ADV_IS_CARRIER_FLAG));
 
         buf_size -= sizeof(ADV_CARR_T);
 
@@ -16712,12 +16801,12 @@
         }
 
         carrp->carr_pa = carr_paddr;
-        carrp->carr_va = (ulong) carrp;
+        carrp->carr_va = ADV_VADDR_TO_U32(carrp);
 
         /*
          * Insert the carrier at the beginning of the freelist.
          */
-        carrp->next_vpa = (ulong) asc_dvc->carr_freelist;
+        carrp->next_vpa = ADV_VADDR_TO_U32(asc_dvc->carr_freelist);
         asc_dvc->carr_freelist = carrp;
 
         carrp++;
@@ -16733,7 +16822,8 @@
         asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
         return ADV_ERROR;
     }
-    asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->icq_sp->next_vpa;
+    asc_dvc->carr_freelist =
+        (ADV_CARR_T *) ADV_U32_TO_VADDR(asc_dvc->icq_sp->next_vpa);
 
     /*
      * The first command issued will be placed in the stopper carrier.
@@ -16743,7 +16833,8 @@
     /*
      * Set RISC ICQ physical address start value.
      */
-    AdvWriteDWordLram(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+    AdvWriteDWordLram(iop_base, ASC_MC_ICQ,
+        cpu_to_le32(asc_dvc->icq_sp->carr_pa));
 
     /*
      * Set-up the RISC->Host Initiator Response Queue (IRQ).
@@ -16753,7 +16844,8 @@
         asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
         return ADV_ERROR;
     }
-    asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->irq_sp->next_vpa;
+    asc_dvc->carr_freelist =
+        (ADV_CARR_T *) ADV_U32_TO_VADDR(asc_dvc->irq_sp->next_vpa);
 
     /*
      * The first command completed by the RISC will be placed in
@@ -16767,7 +16859,8 @@
     /*
      * Set RISC IRQ physical address start value.
      */
-    AdvWriteDWordLram(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+    AdvWriteDWordLram(iop_base, ASC_MC_IRQ,
+        cpu_to_le32(asc_dvc->irq_sp->carr_pa));
     asc_dvc->carr_pending_cnt = 0;
 
     AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
@@ -16834,15 +16927,13 @@
  */
 ASC_INITFUNC(
 STATIC int,
-AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
+AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
 )
 {
-    AdvPortAddr              iop_base;
-    ushort                   warn_code;
-    ADVEEP_38C0800_CONFIG    eep_config;
-    int                      i;
-    uchar                    tid, termination;
-    ushort                   sdtr_speed = 0;
+    AdvPortAddr         iop_base;
+    ushort              warn_code;
+    ADVEEP_3550_CONFIG  eep_config;
+    int                 i;
 
     iop_base = asc_dvc->iop_base;
 
@@ -16852,18 +16943,20 @@
      * Read the board's EEPROM configuration.
      *
      * Set default values if a bad checksum is found.
+     *
+     * XXX - Don't handle big-endian access to EEPROM yet.
      */
-    if (AdvGet38C0800EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
+    if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
     {
         warn_code |= ASC_WARN_EEPROM_CHKSUM;
 
         /*
          * Set EEPROM default values.
          */
-        for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++)
+        for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++)
         {
             *((uchar *) &eep_config + i) =
-                *((uchar *) &Default_38C0800_EEPROM_Config + i);
+                *((uchar *) &Default_3550_EEPROM_Config + i);
         }
 
         /*
@@ -16880,19 +16973,17 @@
         eep_config.serial_number_word1 =
             AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3);
 
-        AdvSet38C0800EEPConfig(iop_base, &eep_config);
+        AdvSet3550EEPConfig(iop_base, &eep_config);
     }
     /*
-     * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
+     * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
      * EEPROM configuration that was read.
      *
      * This is the mapping of EEPROM fields to Adv Library fields.
      */
     asc_dvc->wdtr_able = eep_config.wdtr_able;
-    asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
-    asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
-    asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
-    asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
+    asc_dvc->sdtr_able = eep_config.sdtr_able;
+    asc_dvc->ultra_able = eep_config.ultra_able;
     asc_dvc->tagqng_able = eep_config.tagqng_able;
     asc_dvc->cfg->disc_enable = eep_config.disc_enable;
     asc_dvc->max_host_qng = eep_config.max_host_qng;
@@ -16907,33 +16998,6 @@
     asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
 
     /*
-     * For every Target ID if any of its 'sdtr_speed[1234]' bits
-     * are set, then set an 'sdtr_able' bit for it.
-     */
-    asc_dvc->sdtr_able = 0;
-    for (tid = 0; tid <= ADV_MAX_TID; tid++)
-    {
-        if (tid == 0)
-        {
-            sdtr_speed = asc_dvc->sdtr_speed1;
-        } else if (tid == 4)
-        {
-            sdtr_speed = asc_dvc->sdtr_speed2;
-        } else if (tid == 8)
-        {
-            sdtr_speed = asc_dvc->sdtr_speed3;
-        } else if (tid == 12)
-        {
-            sdtr_speed = asc_dvc->sdtr_speed4;
-        }
-        if (sdtr_speed & ADV_MAX_TID)
-        {
-            asc_dvc->sdtr_able |= (1 << tid);
-        }
-        sdtr_speed >>= 4;
-    }
-
-    /*
      * Set the host maximum queuing (max. 253, min. 16) and the per device
      * maximum queuing (max. 63, min. 4).
      */
@@ -16983,6 +17047,7 @@
     asc_dvc->max_host_qng = eep_config.max_host_qng;
     asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
 
+
     /*
      * If the EEPROM 'termination' field is set to automatic (0), then set
      * the ADV_DVC_CFG 'termination' field to automatic also.
@@ -16991,63 +17056,32 @@
      * value check that a legal value is set and set the ADV_DVC_CFG
      * 'termination' field appropriately.
      */
-    if (eep_config.termination_se == 0)
-    {
-        termination = 0;                         /* auto termination for SE */
-    } else
-    {
-        /* Enable manual control with low off / high off. */
-        if (eep_config.termination_se == 1)
-        {
-            termination = 0;
-
-        /* Enable manual control with low off / high on. */
-        } else if (eep_config.termination_se == 2)
-        {
-            termination = TERM_SE_HI;
-
-        /* Enable manual control with low on / high on. */
-        } else if (eep_config.termination_se == 3)
-        {
-            termination = TERM_SE;
-        } else
-        {
-            /*
-             * The EEPROM 'termination_se' field contains a bad value.
-             * Use automatic termination instead.
-             */
-            termination = 0;
-            warn_code |= ASC_WARN_EEPROM_TERMINATION;
-        }
-    }
-
-    if (eep_config.termination_lvd == 0)
+    if (eep_config.termination == 0)
     {
-        asc_dvc->cfg->termination = termination; /* auto termination for LVD */
+        asc_dvc->cfg->termination = 0;    /* auto termination */
     } else
     {
         /* Enable manual control with low off / high off. */
-        if (eep_config.termination_lvd == 1)
+        if (eep_config.termination == 1)
         {
-            asc_dvc->cfg->termination = termination;
+            asc_dvc->cfg->termination = TERM_CTL_SEL;
 
         /* Enable manual control with low off / high on. */
-        } else if (eep_config.termination_lvd == 2)
+        } else if (eep_config.termination == 2)
         {
-            asc_dvc->cfg->termination = termination | TERM_LVD_HI;
+            asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
 
         /* Enable manual control with low on / high on. */
-        } else if (eep_config.termination_lvd == 3)
+        } else if (eep_config.termination == 3)
         {
-            asc_dvc->cfg->termination =
-                termination | TERM_LVD;
+            asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
         } else
         {
             /*
-             * The EEPROM 'termination_lvd' field contains a bad value.
-             * Use automatic termination instead.
+             * The EEPROM 'termination' field contains a bad value. Use
+             * automatic termination instead.
              */
-            asc_dvc->cfg->termination = termination;
+            asc_dvc->cfg->termination = 0;
             warn_code |= ASC_WARN_EEPROM_TERMINATION;
         }
     }
@@ -17069,13 +17103,15 @@
  */
 ASC_INITFUNC(
 STATIC int,
-AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
+AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
 )
 {
-    AdvPortAddr         iop_base;
-    ushort              warn_code;
-    ADVEEP_3550_CONFIG  eep_config;
-    int                 i;
+    AdvPortAddr              iop_base;
+    ushort                   warn_code;
+    ADVEEP_38C0800_CONFIG    eep_config;
+    int                      i;
+    uchar                    tid, termination;
+    ushort                   sdtr_speed = 0;
 
     iop_base = asc_dvc->iop_base;
 
@@ -17085,18 +17121,20 @@
      * Read the board's EEPROM configuration.
      *
      * Set default values if a bad checksum is found.
+     *
+     * XXX - Don't handle big-endian access to EEPROM yet.
      */
-    if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
+    if (AdvGet38C0800EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
     {
         warn_code |= ASC_WARN_EEPROM_CHKSUM;
 
         /*
          * Set EEPROM default values.
          */
-        for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++)
+        for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++)
         {
             *((uchar *) &eep_config + i) =
-                *((uchar *) &Default_3550_EEPROM_Config + i);
+                *((uchar *) &Default_38C0800_EEPROM_Config + i);
         }
 
         /*
@@ -17113,17 +17151,19 @@
         eep_config.serial_number_word1 =
             AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3);
 
-        AdvSet3550EEPConfig(iop_base, &eep_config);
+        AdvSet38C0800EEPConfig(iop_base, &eep_config);
     }
     /*
-     * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
+     * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
      * EEPROM configuration that was read.
      *
      * This is the mapping of EEPROM fields to Adv Library fields.
      */
     asc_dvc->wdtr_able = eep_config.wdtr_able;
-    asc_dvc->sdtr_able = eep_config.sdtr_able;
-    asc_dvc->ultra_able = eep_config.ultra_able;
+    asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
+    asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
+    asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
+    asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
     asc_dvc->tagqng_able = eep_config.tagqng_able;
     asc_dvc->cfg->disc_enable = eep_config.disc_enable;
     asc_dvc->max_host_qng = eep_config.max_host_qng;
@@ -17138,6 +17178,33 @@
     asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
 
     /*
+     * For every Target ID if any of its 'sdtr_speed[1234]' bits
+     * are set, then set an 'sdtr_able' bit for it.
+     */
+    asc_dvc->sdtr_able = 0;
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        if (tid == 0)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed1;
+        } else if (tid == 4)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed2;
+        } else if (tid == 8)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed3;
+        } else if (tid == 12)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed4;
+        }
+        if (sdtr_speed & ADV_MAX_TID)
+        {
+            asc_dvc->sdtr_able |= (1 << tid);
+        }
+        sdtr_speed >>= 4;
+    }
+
+    /*
      * Set the host maximum queuing (max. 253, min. 16) and the per device
      * maximum queuing (max. 63, min. 4).
      */
@@ -17187,7 +17254,6 @@
     asc_dvc->max_host_qng = eep_config.max_host_qng;
     asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
 
-
     /*
      * If the EEPROM 'termination' field is set to automatic (0), then set
      * the ADV_DVC_CFG 'termination' field to automatic also.
@@ -17196,32 +17262,63 @@
      * value check that a legal value is set and set the ADV_DVC_CFG
      * 'termination' field appropriately.
      */
-    if (eep_config.termination == 0)
+    if (eep_config.termination_se == 0)
     {
-        asc_dvc->cfg->termination = 0;    /* auto termination */
+        termination = 0;                         /* auto termination for SE */
     } else
     {
         /* Enable manual control with low off / high off. */
-        if (eep_config.termination == 1)
+        if (eep_config.termination_se == 1)
         {
-            asc_dvc->cfg->termination = TERM_CTL_SEL;
+            termination = 0;
 
         /* Enable manual control with low off / high on. */
-        } else if (eep_config.termination == 2)
+        } else if (eep_config.termination_se == 2)
         {
-            asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
+            termination = TERM_SE_HI;
 
         /* Enable manual control with low on / high on. */
-        } else if (eep_config.termination == 3)
+        } else if (eep_config.termination_se == 3)
         {
-            asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
+            termination = TERM_SE;
         } else
         {
             /*
-             * The EEPROM 'termination' field contains a bad value. Use
-             * automatic termination instead.
+             * The EEPROM 'termination_se' field contains a bad value.
+             * Use automatic termination instead.
              */
-            asc_dvc->cfg->termination = 0;
+            termination = 0;
+            warn_code |= ASC_WARN_EEPROM_TERMINATION;
+        }
+    }
+
+    if (eep_config.termination_lvd == 0)
+    {
+        asc_dvc->cfg->termination = termination; /* auto termination for LVD */
+    } else
+    {
+        /* Enable manual control with low off / high off. */
+        if (eep_config.termination_lvd == 1)
+        {
+            asc_dvc->cfg->termination = termination;
+
+        /* Enable manual control with low off / high on. */
+        } else if (eep_config.termination_lvd == 2)
+        {
+            asc_dvc->cfg->termination = termination | TERM_LVD_HI;
+
+        /* Enable manual control with low on / high on. */
+        } else if (eep_config.termination_lvd == 3)
+        {
+            asc_dvc->cfg->termination =
+                termination | TERM_LVD;
+        } else
+        {
+            /*
+             * The EEPROM 'termination_lvd' field contains a bad value.
+             * Use automatic termination instead.
+             */
+            asc_dvc->cfg->termination = termination;
             warn_code |= ASC_WARN_EEPROM_TERMINATION;
         }
     }
@@ -17236,8 +17333,7 @@
  */
 ASC_INITFUNC(
 STATIC ushort,
-AdvGet38C0800EEPConfig(AdvPortAddr iop_base,
-                       ADVEEP_38C0800_CONFIG *cfg_buf)
+AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
 )
 {
     ushort              wval, chksum;
@@ -17266,7 +17362,6 @@
     return chksum;
 }
 
-
 /*
  * Read EEPROM configuration into the specified buffer.
  *
@@ -17274,7 +17369,8 @@
  */
 ASC_INITFUNC(
 STATIC ushort,
-AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+AdvGet38C0800EEPConfig(AdvPortAddr iop_base,
+                       ADVEEP_38C0800_CONFIG *cfg_buf)
 )
 {
     ushort              wval, chksum;
@@ -17303,6 +17399,7 @@
     return chksum;
 }
 
+
 /*
  * Read the EEPROM from specified location
  */
@@ -17337,7 +17434,7 @@
     }
     if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) == 0)
     {
-        ADV_ASSERT(0);
+        ASC_ASSERT(0);
     }
     return;
 }
@@ -17456,6 +17553,10 @@
  * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
  * set to SCSI_MAX_RETRY.
  *
+ * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
+ * for DMA addresses or math operations are byte swapped to little-endian
+ * order.
+ *
  * Return:
  *      ADV_SUCCESS(1) - The request was successfully queued.
  *      ADV_BUSY(0) -    Resource unavailable; Retry again after pending
@@ -17469,11 +17570,11 @@
 {
     int                    last_int_level;
     AdvPortAddr            iop_base;
-    long                   req_size;
-    ulong                  req_paddr;
+    ADV_DCNT               req_size;
+    ADV_PADDR              req_paddr;
     ADV_CARR_T             *new_carrp;
 
-    ADV_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
+    ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
 
     /*
      * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
@@ -17497,7 +17598,8 @@
     {
        return ADV_BUSY;
     }
-    asc_dvc->carr_freelist = (ADV_CARR_T *) new_carrp->next_vpa;
+    asc_dvc->carr_freelist =
+        (ADV_CARR_T *) ADV_U32_TO_VADDR(new_carrp->next_vpa);
     asc_dvc->carr_pending_cnt++;
 
     /*
@@ -17513,18 +17615,21 @@
     scsiq->a_flag &= ~ADV_SCSIQ_DONE;
 
     req_size = sizeof(ADV_SCSI_REQ_Q);
-    req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *) scsiq,
-        (long *) &req_size, ADV_IS_SCSIQ_FLAG);
+    req_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, scsiq, (uchar *) scsiq,
+        (ADV_SDCNT *) &req_size, ADV_IS_SCSIQ_FLAG));
 
-    ADV_ASSERT(ADV_DWALIGN(req_paddr) == req_paddr);
-    ADV_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
+    ASC_ASSERT(ADV_DWALIGN(req_paddr) == req_paddr);
+    ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
 
-    /* Save virtual and physical address of ADV_SCSI_REQ_Q and Carrier. */
-    scsiq->scsiq_ptr = (ADV_SCSI_REQ_Q *) scsiq;
+    /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
+    scsiq->scsiq_ptr = ADV_VADDR_TO_U32(scsiq);
     scsiq->scsiq_rptr = req_paddr;
 
-    /* XXX - Could have the RISC set these values. */
-    scsiq->carr_va = (ulong) asc_dvc->icq_sp;
+    scsiq->carr_va = ADV_VADDR_TO_U32(asc_dvc->icq_sp);
+    /*
+     * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
+     * order during initialization.
+     */
     scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
 
    /*
@@ -17532,7 +17637,7 @@
     * the microcode. The newly allocated stopper will become the new
     * stopper.
     */
-    asc_dvc->icq_sp->areq_vpa = (ulong) req_paddr;
+    asc_dvc->icq_sp->areq_vpa = req_paddr;
 
     /*
      * Set the 'next_vpa' pointer for the old stopper to be the
@@ -17607,7 +17712,7 @@
         return status;
     }
 
-    DvcSleepMilliSecond((ulong) asc_dvc->scsi_reset_wait * 1000);
+    DvcSleepMilliSecond((ADV_DCNT) asc_dvc->scsi_reset_wait * 1000);
 
     return status;
 }
@@ -17727,7 +17832,7 @@
     uchar                       int_stat;
     ushort                      target_bit;
     ADV_CARR_T                  *free_carrp;
-    ulong                       irq_next_vpa;
+    ADV_VADDR                   irq_next_vpa;
     int                         flags;
     ADV_SCSI_REQ_Q              *scsiq;
 
@@ -17778,8 +17883,13 @@
         /*
          * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
          * The RISC will have set 'areq_vpa' to a virtual address.
+         *
+         * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
+         * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
+         * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
+         * in AdvExeScsiQueue().
          */
-        scsiq = (ADV_SCSI_REQ_Q *) asc_dvc->irq_sp->areq_vpa;
+        scsiq = (ADV_SCSI_REQ_Q *) ADV_U32_TO_VADDR(asc_dvc->irq_sp->areq_vpa);
 
         /*
          * Advance the stopper pointer to the next carrier
@@ -17787,14 +17897,14 @@
          * stopper carrier.
          */
         free_carrp = asc_dvc->irq_sp;
-        asc_dvc->irq_sp = ASC_GET_CARRP(irq_next_vpa);
+        asc_dvc->irq_sp = (ADV_CARR_T *)
+            ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
 
-        free_carrp->next_vpa = (ulong) asc_dvc->carr_freelist;
-        asc_dvc->carr_freelist = (ADV_CARR_T *) free_carrp;
+        free_carrp->next_vpa = ADV_VADDR_TO_U32(asc_dvc->carr_freelist);
+        asc_dvc->carr_freelist = free_carrp;
         asc_dvc->carr_pending_cnt--;
 
-
-        ADV_ASSERT(scsiq != NULL);
+        ASC_ASSERT(scsiq != NULL);
         target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
 
         /*
@@ -17802,22 +17912,23 @@
          */
         scsiq->cntl = 0;
 
+#if __BIG_ENDIAN
         /*
-         * Check Condition handling
+         * After the request completes the only field in the ASC_SCSI_REQ_Q
+         * structure needs to be byte swapped from little endian order to
+         * big endian order is the residual data count.
          */
-        if ((scsiq->done_status == QD_WITH_ERROR) &&
-            (scsiq->scsi_status == SS_CHK_CONDITION)
-            )
-        {
-        }
+        scsiqp->data_cnt = le32_to_cpu(scsiqp->data_cnt);
+#endif /* __BIG_ENDIAN */
+
         /*
          * If the command that completed was a SCSI INQUIRY and
          * LUN 0 was sent the command, then process the INQUIRY
          * command information for the device.
          */
-        else if (scsiq->done_status == QD_NO_ERROR &&
-                 scsiq->cdb[0] == SCSICMD_Inquiry &&
-                 scsiq->target_lun == 0)
+        if (scsiq->done_status == QD_NO_ERROR &&
+            scsiq->cdb[0] == SCSICMD_Inquiry &&
+            scsiq->target_lun == 0)
         {
             AdvInquiryHandling(asc_dvc, scsiq);
         }
@@ -17867,11 +17978,11 @@
 STATIC int
 AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
                ushort idle_cmd,
-               ulong idle_cmd_parameter)
+               ADV_DCNT idle_cmd_parameter)
 {
     int         last_int_level;
     int         result;
-    ulong       i, j;
+    ADV_DCNT    i, j;
     AdvPortAddr iop_base;
 
     last_int_level = DvcEnterCritical();
@@ -17926,7 +18037,7 @@
         }
     }
 
-    ADV_ASSERT(0); /* The idle command should never timeout. */
+    ASC_ASSERT(0); /* The idle command should never timeout. */
     DvcLeaveCritical(last_int_level);
     return ADV_ERROR;
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/advansys.h linux.14p16/drivers/scsi/advansys.h
--- linux.vanilla/drivers/scsi/advansys.h	Sun Mar 28 19:04:05 1999
+++ linux.14p16/drivers/scsi/advansys.h	Tue Dec 21 00:51:22 1999
@@ -1,4 +1,4 @@
-/* $Id: advansys.h,v 1.17 1998/01/08 21:23:49 bobf Exp bobf $ */
+/* $Id: advansys.h,v 1.18 1999/11/29 21:47:16 bobf Exp bobf $ */
 
 /*
  * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters
@@ -49,7 +49,9 @@
 int advansys_biosparam(Disk *, int, int[]);
 #else /* version >= v1.3.0 */
 int advansys_biosparam(Disk *, kdev_t, int[]);
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28)
 extern struct proc_dir_entry proc_scsi_advansys;
+#endif /* version < v2.3.28 */
 int advansys_proc_info(char *, char **, off_t, int, int, int);
 #endif /* version >= v1.3.0 */
 
@@ -142,7 +144,7 @@
      */ \
     ENABLE_CLUSTERING,        /* unsigned use_clustering:1 */ \
 }
-#else /* version >= v2.1.75 */
+#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28)
 #define ADVANSYS { \
     proc_dir:     &proc_scsi_advansys, \
     proc_info:    advansys_proc_info, \
@@ -154,7 +156,7 @@
     queuecommand: advansys_queuecommand, \
     abort:        advansys_abort, \
     reset:        advansys_reset, \
-    bios_param:    advansys_biosparam, \
+    bios_param:   advansys_biosparam, \
     /* \
      * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
      * must be set. The flag will be cleared in advansys_detect for non-ISA \
@@ -170,5 +172,33 @@
      */ \
     use_clustering: ENABLE_CLUSTERING, \
 }
-#endif /* version >= v2.1.75 */
+#else /* version >= v2.3.28 */
+#define ADVANSYS { \
+    proc_name:    "advansys", \
+    proc_info:    advansys_proc_info, \
+    name:         "advansys", \
+    detect:       advansys_detect, \
+    release:      advansys_release, \
+    info:         advansys_info, \
+    command:      advansys_command, \
+    queuecommand: advansys_queuecommand, \
+    abort:        advansys_abort, \
+    reset:        advansys_reset, \
+    bios_param:   advansys_biosparam, \
+    /* \
+     * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
+     * must be set. The flag will be cleared in advansys_detect for non-ISA \
+     * adapters. Refer to the comment in scsi_module.c for more information. \
+     */ \
+    unchecked_isa_dma: 1, \
+    /* \
+     * All adapters controlled by this driver are capable of large \
+     * scatter-gather lists. According to the mid-level SCSI documentation \
+     * this obviates any performance gain provided by setting \
+     * 'use_clustering'. But empirically while CPU utilization is increased \
+     * by enabling clustering, I/O throughput increases as well. \
+     */ \
+    use_clustering: ENABLE_CLUSTERING, \
+}
+#endif /* version >= v2.3.28 */
 #endif /* _ADVANSYS_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.seq linux.14p16/drivers/scsi/aic7xxx/aic7xxx.seq
--- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.seq	Sat Aug 14 02:26:49 1999
+++ linux.14p16/drivers/scsi/aic7xxx/aic7xxx.seq	Thu Dec  9 15:33:55 1999
@@ -446,7 +446,8 @@
 data_phase_reinit:
 	if ((p->features & AHC_CMD_CHAN) != 0) {
 		if ((p->features & AHC_ULTRA2) != 0) {
-			bmov	HCNT, SCB_RESID_DCNT, 3;
+			bmov	HADDR, SHADDR, 4;
+			bmov    HCNT, SCB_RESID_DCNT, 3;
 		}
 		bmov    STCNT, SCB_RESID_DCNT, 3;
 	} else {
@@ -658,11 +659,25 @@
 		test	DFCNTRL, DIRECTION jnz ultra2_dmahalt;
 		and	DFCNTRL, ~SCSIEN;
 		test	DFCNTRL, SCSIEN jnz .;
+ultra2_dmafifoflush:
 		or	DFCNTRL, FIFOFLUSH;
 		test	DFSTATUS, FIFOEMP jz . - 1;
+		/*
+		 * hardware bug alert!  This needless set of jumps is to
+		 * protect against a FIFOEMP status bit glitch in the
+		 * silicon.
+		 */
+		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		test	DFSTATUS, MREQPEND	jnz .;
 ultra2_dmahalt:
-		and     DFCNTRL, ~(SCSIEN|HDMAEN);
+		and     DFCNTRL, ~HDMAEN;
 		test	DFCNTRL, HDMAEN jnz .;
+		and     DFCNTRL, ~SCSIEN;
+		test	DFCNTRL, SCSIEN jnz .;
 		bmov	SCB_RESID_DCNT, STCNT, 3;
 		mov	SCB_RESID_SGCNT, SG_COUNT;
 		or	SXFRCTL0, CLRSTCNT|CLRCHN;
@@ -701,8 +716,10 @@
 		test	SSTAT0, DMADONE jnz p_command_ultra2_dma_done;
 		test	SSTAT1,PHASEMIS	jz p_command_dma_loop;	/* ie. underrun */
 p_command_ultra2_dma_done:
-		and     DFCNTRL, ~(SCSIEN|HDMAEN);
+		and     DFCNTRL, ~HDMAEN;
 		test	DFCNTRL, HDMAEN jnz .;
+		and	DFCNTRL, ~SCSIEN;
+		test	DFCNTRL, SCSIEN jnz .;
 		or	SXFRCTL0, CLRSTCNT|CLRCHN;
 	}
 	jmp	ITloop;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/aic7xxx.c linux.14p16/drivers/scsi/aic7xxx.c
--- linux.vanilla/drivers/scsi/aic7xxx.c	Wed Oct 20 01:12:40 1999
+++ linux.14p16/drivers/scsi/aic7xxx.c	Thu Dec  9 15:33:50 1999
@@ -270,7 +270,7 @@
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.20"
+#define AIC7XXX_C_VERSION  "5.1.21"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -1362,6 +1362,18 @@
  */
 static int aic7xxx_scbram = 0;
 /*
+ * So that we can set how long each device is given as a selection timeout.
+ * The table of values goes like this:
+ * 	0 - 256ms
+ * 	1 - 128ms
+ * 	2 - 64ms
+ * 	3 - 32ms
+ * We default to 64ms because it's fast.  Some old SCSI-I devices need a
+ * longer time.  The final value has to be left shifted by 3, hence 0x10
+ * is the final value.
+ */
+static int aic7xxx_seltime = 0x10;
+/*
  * So that insmod can find the variable and make it point to something
  */
 #ifdef MODULE
@@ -1522,6 +1534,7 @@
     { "dump_card", &aic7xxx_dump_card },
     { "dump_sequencer", &aic7xxx_dump_sequencer },
     { "scbram", &aic7xxx_scbram },
+    { "seltime", &aic7xxx_seltime },
     { "tag_info",    NULL }
   };
 
@@ -1615,6 +1628,10 @@
         else if (p[n] == ':')
         {
           *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
+          if(!strncmp(p, "seltime", n))
+          {
+            *(options[i].flag) = (*(options[i].flag) % 4) << 3;
+          }
         }
         else if (!strncmp(p, "verbose", n))
         {
@@ -1623,6 +1640,10 @@
         else
         {
           *(options[i].flag) = ~(*(options[i].flag));
+          if(!strncmp(p, "seltime", n))
+          {
+            *(options[i].flag) = (*(options[i].flag) % 4) << 3;
+          }
         }
       }
     }
@@ -1857,10 +1878,13 @@
         }
       }
       aic_outb(p, (instr.integer & 0xff), SEQRAM);
+      udelay(50);
       aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM);
+      udelay(50);
       aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM);
+      udelay(50);
       aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM);
-      udelay(15);
+      udelay(50);
       break;
 
     default:
@@ -8124,7 +8148,7 @@
     aic_outb(p, p->scsi_id_b, SCSIID);
     scsi_conf = aic_inb(p, SCSICONF + 1);
     aic_outb(p, DFON | SPIOEN, SXFRCTL0);
-    aic_outb(p, (scsi_conf & ENSPCHK) | STIMESEL | term | 
+    aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term | 
          ENSTIMER | ACTNEGEN, SXFRCTL1);
     aic_outb(p, 0, SIMODE0);
     aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
@@ -8148,7 +8172,7 @@
     term = ((p->flags & (AHC_TERM_ENB_A|AHC_TERM_ENB_LVD)) ? STPWEN : 0);
   scsi_conf = aic_inb(p, SCSICONF);
   aic_outb(p, DFON | SPIOEN, SXFRCTL0);
-  aic_outb(p, (scsi_conf & ENSPCHK) | STIMESEL | term | 
+  aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term | 
        ENSTIMER | ACTNEGEN, SXFRCTL1);
   aic_outb(p, 0, SIMODE0);
   aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/aic7xxx_proc.c linux.14p16/drivers/scsi/aic7xxx_proc.c
--- linux.vanilla/drivers/scsi/aic7xxx_proc.c	Sat Aug 14 02:27:30 1999
+++ linux.14p16/drivers/scsi/aic7xxx_proc.c	Thu Dec  9 15:33:52 1999
@@ -224,6 +224,11 @@
   {
     size += sprintf(BLS, "    BIOS Memory Address: 0x%08x\n", p->bios_address);
   }
+  if( p->chip & AHC_PCI )
+  {
+    size += sprintf(BLS, "    PCI Bus 0x%02x Device 0x%02x\n", p->pci_bus,
+              p->pci_device_fn);
+  }
   size += sprintf(BLS, " Adapter SEEPROM Config: %s\n",
           (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." :
          ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." :
@@ -373,11 +378,9 @@
   }
   else
   {
-    *start = &aic7xxx_buffer[offset];   /* Start of wanted data */
-    if (size - offset < length)
-    {
-      length = size - offset;
-    }
+    *start = buffer;
+    length = MIN(length, size - offset);
+    memcpy(buffer, &aic7xxx_buffer[offset], length);
   }
 
   return (length);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/aic7xxx_seq.c linux.14p16/drivers/scsi/aic7xxx_seq.c
--- linux.vanilla/drivers/scsi/aic7xxx_seq.c	Sat Aug 14 02:26:49 1999
+++ linux.14p16/drivers/scsi/aic7xxx_seq.c	Thu Dec  9 15:33:55 1999
@@ -26,12 +26,12 @@
 	0x00, 0x4d, 0x12, 0x70,
 	0x01, 0x4e, 0x9c, 0x18,
 	0xbf, 0x60, 0xc0, 0x08,
-	0x00, 0x6a, 0x92, 0x5c,
+	0x00, 0x6a, 0xa8, 0x5c,
 	0xff, 0x4e, 0xc8, 0x18,
-	0x02, 0x6a, 0xa8, 0x5b,
+	0x02, 0x6a, 0xbe, 0x5b,
 	0xff, 0x52, 0x20, 0x09,
 	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0x52, 0x1e, 0x5c,
+	0x00, 0x52, 0x34, 0x5c,
 	0x03, 0xb0, 0x52, 0x31,
 	0xff, 0xb0, 0x52, 0x09,
 	0xff, 0xb1, 0x54, 0x09,
@@ -76,7 +76,7 @@
 	0x10, 0x03, 0xfc, 0x78,
 	0xff, 0x50, 0xc8, 0x08,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x49, 0x6a, 0x0e, 0x5c,
+	0x49, 0x6a, 0x24, 0x5c,
 	0x01, 0x6a, 0x26, 0x01,
 	0xff, 0x6a, 0xca, 0x08,
 	0x08, 0x01, 0x02, 0x00,
@@ -117,11 +117,11 @@
 	0xff, 0x65, 0xca, 0x18,
 	0xff, 0x65, 0xd8, 0x68,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x84, 0x5c,
+	0x00, 0x65, 0x9a, 0x5c,
 	0x40, 0x51, 0xf0, 0x78,
 	0xe4, 0x6a, 0x06, 0x00,
 	0x08, 0x01, 0x02, 0x00,
-	0x04, 0x6a, 0x40, 0x5b,
+	0x04, 0x6a, 0x56, 0x5b,
 	0x01, 0x50, 0xa0, 0x18,
 	0x00, 0x50, 0xf6, 0xe0,
 	0xff, 0x6a, 0xa0, 0x08,
@@ -147,13 +147,13 @@
 	0x08, 0x6a, 0x66, 0x58,
 	0x80, 0x6a, 0x68, 0x00,
 	0x80, 0x36, 0x6c, 0x00,
-	0x00, 0x65, 0xf2, 0x5b,
+	0x00, 0x65, 0x08, 0x5c,
 	0xff, 0x3d, 0xc8, 0x08,
-	0xbf, 0x64, 0x58, 0x79,
-	0x80, 0x64, 0x0e, 0x72,
-	0xa0, 0x64, 0x3a, 0x72,
-	0xc0, 0x64, 0x32, 0x72,
-	0xe0, 0x64, 0x7a, 0x72,
+	0xbf, 0x64, 0x5a, 0x79,
+	0x80, 0x64, 0x20, 0x72,
+	0xa0, 0x64, 0x50, 0x72,
+	0xc0, 0x64, 0x48, 0x72,
+	0xe0, 0x64, 0x90, 0x72,
 	0x01, 0x6a, 0x22, 0x01,
 	0x00, 0x65, 0x22, 0x41,
 	0xf7, 0x11, 0x22, 0x08,
@@ -169,16 +169,17 @@
 	0xdf, 0x01, 0x02, 0x08,
 	0x01, 0x6a, 0x7a, 0x00,
 	0xff, 0x6a, 0x6c, 0x0c,
+	0x04, 0x14, 0x10, 0x31,
 	0x03, 0xa9, 0x18, 0x31,
 	0x03, 0xa9, 0x10, 0x30,
 	0x08, 0x6a, 0xcc, 0x00,
-	0xa9, 0x6a, 0x08, 0x5c,
-	0x00, 0x65, 0x78, 0x41,
+	0xa9, 0x6a, 0x1e, 0x5c,
+	0x00, 0x65, 0x7a, 0x41,
 	0xa8, 0x6a, 0x6a, 0x00,
 	0x79, 0x6a, 0x6a, 0x00,
-	0x40, 0x3d, 0x60, 0x69,
+	0x40, 0x3d, 0x62, 0x69,
 	0x04, 0x35, 0x6a, 0x00,
-	0x00, 0x65, 0x62, 0x5b,
+	0x00, 0x65, 0x78, 0x5b,
 	0x80, 0x6a, 0xd4, 0x01,
 	0x10, 0x36, 0x4e, 0x69,
 	0x10, 0x36, 0x6c, 0x00,
@@ -186,11 +187,11 @@
 	0x03, 0x8c, 0x10, 0x30,
 	0x05, 0xa3, 0x70, 0x30,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xac, 0x6a, 0x00, 0x5c,
-	0x00, 0x65, 0xfa, 0x5b,
+	0xac, 0x6a, 0x16, 0x5c,
+	0x00, 0x65, 0x10, 0x5c,
 	0x38, 0x6a, 0xcc, 0x00,
-	0xa3, 0x6a, 0x04, 0x5c,
-	0xff, 0x38, 0x88, 0x69,
+	0xa3, 0x6a, 0x1a, 0x5c,
+	0xff, 0x38, 0x8a, 0x69,
 	0x80, 0x02, 0x04, 0x00,
 	0xe7, 0x35, 0x6a, 0x08,
 	0x03, 0x69, 0x18, 0x31,
@@ -198,51 +199,51 @@
 	0xff, 0x6a, 0x10, 0x00,
 	0xff, 0x6a, 0x12, 0x00,
 	0xff, 0x6a, 0x14, 0x00,
-	0x01, 0x38, 0x8c, 0x61,
+	0x01, 0x38, 0x8e, 0x61,
 	0xbf, 0x35, 0x6a, 0x08,
 	0xff, 0x69, 0xca, 0x08,
 	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x0b, 0x90, 0x69,
+	0x04, 0x0b, 0x92, 0x69,
+	0x04, 0x0b, 0x9e, 0x69,
+	0x10, 0x0c, 0x94, 0x79,
 	0x04, 0x0b, 0x9c, 0x69,
-	0x10, 0x0c, 0x92, 0x79,
-	0x04, 0x0b, 0x9a, 0x69,
 	0xff, 0x6a, 0xca, 0x08,
-	0x00, 0x35, 0x4a, 0x5b,
-	0x80, 0x02, 0xf0, 0x69,
-	0xff, 0x65, 0xe0, 0x79,
+	0x00, 0x35, 0x60, 0x5b,
+	0x80, 0x02, 0xf2, 0x69,
+	0xff, 0x65, 0xe2, 0x79,
 	0xff, 0x38, 0x70, 0x18,
-	0xff, 0x38, 0xe0, 0x79,
-	0x80, 0xea, 0xbc, 0x61,
+	0xff, 0x38, 0xe2, 0x79,
+	0x80, 0xea, 0xbe, 0x61,
 	0xef, 0x38, 0xc8, 0x18,
 	0x80, 0x6a, 0xc8, 0x00,
-	0x00, 0x65, 0xae, 0x49,
+	0x00, 0x65, 0xb0, 0x49,
 	0x33, 0x38, 0xc8, 0x28,
 	0xff, 0x64, 0xd0, 0x09,
 	0x04, 0x39, 0xc0, 0x31,
 	0x09, 0x6a, 0xd6, 0x01,
-	0x80, 0xeb, 0xb4, 0x79,
+	0x80, 0xeb, 0xb6, 0x79,
 	0xf7, 0xeb, 0xd6, 0x09,
-	0x08, 0xeb, 0xb8, 0x69,
+	0x08, 0xeb, 0xba, 0x69,
 	0x01, 0x6a, 0xd6, 0x01,
 	0x08, 0xe9, 0x10, 0x31,
 	0x03, 0x8c, 0x10, 0x30,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x39, 0x6a, 0x06, 0x5c,
+	0x39, 0x6a, 0x1c, 0x5c,
 	0x08, 0x6a, 0x18, 0x01,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0x0d, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x84, 0x5c,
-	0x88, 0x6a, 0x74, 0x5c,
-	0x00, 0x65, 0xfa, 0x5b,
+	0x00, 0x65, 0x9a, 0x5c,
+	0x88, 0x6a, 0x8a, 0x5c,
+	0x00, 0x65, 0x10, 0x5c,
 	0xff, 0x6a, 0xc8, 0x08,
 	0x08, 0x39, 0x72, 0x18,
 	0x00, 0x3a, 0x74, 0x20,
-	0x01, 0x0c, 0xd8, 0x79,
-	0x10, 0x0c, 0x78, 0x79,
+	0x01, 0x0c, 0xda, 0x79,
+	0x10, 0x0c, 0x7a, 0x79,
 	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x0b, 0xde, 0x69,
-	0x00, 0x65, 0xf8, 0x59,
+	0x04, 0x0b, 0xe0, 0x69,
+	0x00, 0x65, 0xfa, 0x59,
 	0x03, 0x08, 0x52, 0x31,
 	0xff, 0x38, 0x50, 0x09,
 	0xff, 0x08, 0x52, 0x09,
@@ -250,265 +251,275 @@
 	0xff, 0x0a, 0x56, 0x09,
 	0xff, 0x38, 0x50, 0x09,
 	0x00, 0x65, 0x22, 0x41,
-	0x00, 0x65, 0xf8, 0x59,
+	0x00, 0x65, 0xfa, 0x59,
 	0x7f, 0x02, 0x04, 0x08,
 	0xe1, 0x6a, 0x22, 0x01,
 	0x00, 0x65, 0x22, 0x41,
-	0x04, 0x93, 0x02, 0x6a,
+	0x04, 0x93, 0x10, 0x6a,
 	0xdf, 0x93, 0x26, 0x09,
-	0x20, 0x93, 0xfc, 0x69,
+	0x20, 0x93, 0xfe, 0x69,
 	0x02, 0x93, 0x26, 0x01,
-	0x01, 0x94, 0xfe, 0x79,
-	0xd7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0x04, 0x6a,
+	0x01, 0x94, 0x00, 0x7a,
+	0x01, 0x94, 0x00, 0x7a,
+	0x01, 0x94, 0x00, 0x7a,
+	0x01, 0x94, 0x00, 0x7a,
+	0x01, 0x94, 0x00, 0x7a,
+	0x01, 0x94, 0x00, 0x7a,
+	0x10, 0x94, 0x0e, 0x6a,
+	0xf7, 0x93, 0x26, 0x09,
+	0x08, 0x93, 0x12, 0x6a,
+	0xdf, 0x93, 0x26, 0x09,
+	0x20, 0x93, 0x16, 0x6a,
 	0x03, 0x08, 0x52, 0x31,
 	0xff, 0x38, 0x50, 0x09,
 	0x12, 0x01, 0x02, 0x00,
 	0xff, 0x6a, 0xd4, 0x0c,
-	0x00, 0x65, 0x62, 0x5b,
+	0x00, 0x65, 0x78, 0x5b,
 	0x05, 0xb4, 0x10, 0x31,
 	0x02, 0x6a, 0x1a, 0x31,
 	0x03, 0x8c, 0x10, 0x30,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xb4, 0x6a, 0x04, 0x5c,
+	0xb4, 0x6a, 0x1a, 0x5c,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
-	0x00, 0x65, 0xfa, 0x5b,
-	0x3d, 0x6a, 0x4a, 0x5b,
+	0x00, 0x65, 0x10, 0x5c,
+	0x3d, 0x6a, 0x60, 0x5b,
 	0xac, 0x6a, 0x26, 0x01,
-	0x04, 0x0b, 0x24, 0x6a,
-	0x01, 0x0b, 0x2a, 0x6a,
-	0x10, 0x0c, 0x26, 0x7a,
-	0xd7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0x2c, 0x6a,
+	0x04, 0x0b, 0x36, 0x6a,
+	0x01, 0x0b, 0x3c, 0x6a,
+	0x10, 0x0c, 0x38, 0x7a,
+	0xf7, 0x93, 0x26, 0x09,
+	0x08, 0x93, 0x3e, 0x6a,
+	0xdf, 0x93, 0x26, 0x09,
+	0x20, 0x93, 0x42, 0x6a,
 	0x12, 0x01, 0x02, 0x00,
 	0x00, 0x65, 0x22, 0x41,
-	0x00, 0x65, 0x62, 0x5b,
+	0x00, 0x65, 0x78, 0x5b,
 	0xff, 0x06, 0x44, 0x09,
 	0x00, 0x65, 0x22, 0x41,
 	0x10, 0x3d, 0x06, 0x00,
 	0xff, 0x34, 0xca, 0x08,
-	0x80, 0x65, 0x5e, 0x62,
+	0x80, 0x65, 0x74, 0x62,
 	0x0f, 0xa1, 0xca, 0x08,
 	0x07, 0xa1, 0xca, 0x08,
 	0x40, 0xa0, 0xc8, 0x08,
 	0x00, 0x65, 0xca, 0x00,
 	0x80, 0x65, 0xca, 0x00,
-	0x80, 0xa0, 0x4e, 0x7a,
+	0x80, 0xa0, 0x64, 0x7a,
 	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x60, 0x42,
-	0x20, 0xa0, 0x66, 0x7a,
+	0x00, 0x65, 0x76, 0x42,
+	0x20, 0xa0, 0x7c, 0x7a,
 	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0xf2, 0x5b,
-	0xa0, 0x3d, 0x6e, 0x62,
+	0x00, 0x65, 0x08, 0x5c,
+	0xa0, 0x3d, 0x84, 0x62,
 	0x23, 0xa0, 0x0c, 0x08,
-	0x00, 0x65, 0xf2, 0x5b,
-	0xa0, 0x3d, 0x6e, 0x62,
-	0x00, 0xb9, 0x66, 0x42,
-	0xff, 0x65, 0x66, 0x62,
+	0x00, 0x65, 0x08, 0x5c,
+	0xa0, 0x3d, 0x84, 0x62,
+	0x00, 0xb9, 0x7c, 0x42,
+	0xff, 0x65, 0x7c, 0x62,
 	0xa1, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
-	0x10, 0x51, 0x6e, 0x72,
+	0x10, 0x51, 0x84, 0x72,
 	0x40, 0x6a, 0x18, 0x00,
 	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0xf2, 0x5b,
-	0xa0, 0x3d, 0x38, 0x72,
+	0x00, 0x65, 0x08, 0x5c,
+	0xa0, 0x3d, 0x4e, 0x72,
 	0x40, 0x6a, 0x18, 0x00,
 	0xff, 0x34, 0xa6, 0x08,
-	0x80, 0x34, 0x76, 0x62,
+	0x80, 0x34, 0x8c, 0x62,
 	0x7f, 0xa0, 0x40, 0x09,
 	0x08, 0x6a, 0x68, 0x00,
 	0x00, 0x65, 0x22, 0x41,
-	0x64, 0x6a, 0x3a, 0x5b,
-	0x80, 0x64, 0xea, 0x6a,
-	0x04, 0x64, 0xcc, 0x72,
-	0x02, 0x64, 0xd2, 0x72,
-	0x00, 0x6a, 0x94, 0x72,
-	0x03, 0x64, 0xe6, 0x72,
-	0x01, 0x64, 0xc8, 0x72,
-	0x07, 0x64, 0x28, 0x73,
-	0x08, 0x64, 0x90, 0x72,
+	0x64, 0x6a, 0x50, 0x5b,
+	0x80, 0x64, 0x00, 0x6b,
+	0x04, 0x64, 0xe2, 0x72,
+	0x02, 0x64, 0xe8, 0x72,
+	0x00, 0x6a, 0xaa, 0x72,
+	0x03, 0x64, 0xfc, 0x72,
+	0x01, 0x64, 0xde, 0x72,
+	0x07, 0x64, 0x3e, 0x73,
+	0x08, 0x64, 0xa6, 0x72,
 	0x11, 0x6a, 0x22, 0x01,
-	0x07, 0x6a, 0x2c, 0x5b,
+	0x07, 0x6a, 0x42, 0x5b,
 	0xff, 0x06, 0xd4, 0x08,
 	0x00, 0x65, 0x22, 0x41,
-	0xff, 0xa8, 0x98, 0x6a,
-	0xff, 0xa2, 0xb0, 0x7a,
+	0xff, 0xa8, 0xae, 0x6a,
+	0xff, 0xa2, 0xc6, 0x7a,
 	0x01, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0x1e, 0x5c,
-	0xff, 0xa2, 0xb0, 0x7a,
+	0x00, 0xb9, 0x34, 0x5c,
+	0xff, 0xa2, 0xc6, 0x7a,
 	0x71, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
-	0x40, 0x51, 0xb0, 0x62,
+	0x40, 0x51, 0xc6, 0x62,
 	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0x1e, 0x5c,
+	0x00, 0xb9, 0x34, 0x5c,
 	0xff, 0x3e, 0x74, 0x09,
 	0xff, 0x90, 0x7c, 0x08,
 	0x00, 0x65, 0x50, 0x58,
 	0x00, 0x65, 0x34, 0x41,
-	0x20, 0xa0, 0xb8, 0x6a,
+	0x20, 0xa0, 0xce, 0x6a,
 	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0x6a, 0xc8, 0x5b,
-	0xff, 0x6a, 0xde, 0x5b,
+	0x00, 0x6a, 0xde, 0x5b,
+	0xff, 0x6a, 0xf4, 0x5b,
 	0xff, 0xf8, 0xc8, 0x08,
 	0xff, 0x4f, 0xc8, 0x08,
-	0x01, 0x6a, 0xc8, 0x5b,
-	0x00, 0xb9, 0xde, 0x5b,
+	0x01, 0x6a, 0xde, 0x5b,
+	0x00, 0xb9, 0xf4, 0x5b,
 	0x01, 0x4f, 0x9e, 0x18,
 	0x02, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x8c, 0x5c,
+	0x00, 0x65, 0xa2, 0x5c,
 	0x00, 0x65, 0x34, 0x41,
 	0x41, 0x6a, 0x22, 0x01,
 	0x00, 0x65, 0x22, 0x41,
 	0x04, 0xa0, 0x40, 0x01,
-	0x00, 0x65, 0xa4, 0x5c,
+	0x00, 0x65, 0xba, 0x5c,
 	0x00, 0x65, 0x34, 0x41,
-	0x10, 0x36, 0x90, 0x7a,
+	0x10, 0x36, 0xa6, 0x7a,
 	0x05, 0x38, 0x46, 0x31,
 	0x04, 0x14, 0x58, 0x31,
 	0x03, 0xa9, 0x60, 0x31,
 	0xa3, 0x6a, 0xcc, 0x00,
-	0x38, 0x6a, 0x04, 0x5c,
+	0x38, 0x6a, 0x1a, 0x5c,
 	0xac, 0x6a, 0xcc, 0x00,
-	0x14, 0x6a, 0x06, 0x5c,
-	0xa9, 0x6a, 0x08, 0x5c,
-	0x00, 0x65, 0x90, 0x42,
+	0x14, 0x6a, 0x1c, 0x5c,
+	0xa9, 0x6a, 0x1e, 0x5c,
+	0x00, 0x65, 0xa6, 0x42,
 	0xef, 0x36, 0x6c, 0x08,
-	0x00, 0x65, 0x90, 0x42,
+	0x00, 0x65, 0xa6, 0x42,
 	0x0f, 0x64, 0xc8, 0x08,
 	0x07, 0x64, 0xc8, 0x08,
 	0x00, 0x37, 0x6e, 0x00,
 	0xff, 0x6a, 0xa4, 0x00,
-	0x00, 0x65, 0x98, 0x5b,
-	0xff, 0x51, 0xfc, 0x72,
-	0x20, 0x36, 0x06, 0x7b,
-	0x00, 0x90, 0x86, 0x5b,
-	0x00, 0x65, 0x08, 0x43,
+	0x00, 0x65, 0xae, 0x5b,
+	0xff, 0x51, 0x12, 0x73,
+	0x20, 0x36, 0x1c, 0x7b,
+	0x00, 0x90, 0x9c, 0x5b,
+	0x00, 0x65, 0x1e, 0x43,
 	0xff, 0x06, 0xd4, 0x08,
-	0x00, 0x65, 0xf2, 0x5b,
-	0xe0, 0x3d, 0x22, 0x63,
-	0x20, 0x12, 0x22, 0x63,
-	0x51, 0x6a, 0x30, 0x5b,
-	0x00, 0x65, 0x80, 0x5b,
+	0x00, 0x65, 0x08, 0x5c,
+	0xe0, 0x3d, 0x38, 0x63,
+	0x20, 0x12, 0x38, 0x63,
+	0x51, 0x6a, 0x46, 0x5b,
+	0x00, 0x65, 0x96, 0x5b,
 	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0xa1, 0x1a, 0x63,
-	0x04, 0xa0, 0x1a, 0x7b,
+	0x00, 0xa1, 0x30, 0x63,
+	0x04, 0xa0, 0x30, 0x7b,
 	0xfb, 0xa0, 0x40, 0x09,
 	0x80, 0x36, 0x6c, 0x00,
-	0x80, 0xa0, 0x90, 0x7a,
+	0x80, 0xa0, 0xa6, 0x7a,
 	0x7f, 0xa0, 0x40, 0x09,
-	0xff, 0x6a, 0x2c, 0x5b,
-	0x00, 0x65, 0x90, 0x42,
-	0x04, 0xa0, 0x20, 0x7b,
-	0x00, 0x65, 0xa4, 0x5c,
-	0x00, 0x65, 0x22, 0x43,
-	0x00, 0x65, 0x8c, 0x5c,
+	0xff, 0x6a, 0x42, 0x5b,
+	0x00, 0x65, 0xa6, 0x42,
+	0x04, 0xa0, 0x36, 0x7b,
+	0x00, 0x65, 0xba, 0x5c,
+	0x00, 0x65, 0x38, 0x43,
+	0x00, 0x65, 0xa2, 0x5c,
 	0x31, 0x6a, 0x22, 0x01,
-	0x0c, 0x6a, 0x2c, 0x5b,
-	0x00, 0x65, 0x90, 0x42,
+	0x0c, 0x6a, 0x42, 0x5b,
+	0x00, 0x65, 0xa6, 0x42,
 	0x61, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x90, 0x42,
+	0x00, 0x65, 0xa6, 0x42,
 	0x10, 0x3d, 0x06, 0x00,
 	0xff, 0x65, 0x68, 0x0c,
 	0xff, 0x06, 0xd4, 0x08,
-	0x01, 0x0c, 0x32, 0x7b,
-	0x04, 0x0c, 0x32, 0x6b,
+	0x01, 0x0c, 0x48, 0x7b,
+	0x04, 0x0c, 0x48, 0x6b,
 	0xe0, 0x03, 0x7a, 0x08,
-	0xe0, 0x3d, 0x46, 0x63,
+	0xe0, 0x3d, 0x5c, 0x63,
 	0xff, 0x65, 0xcc, 0x08,
 	0xff, 0x12, 0xda, 0x0c,
 	0xff, 0x06, 0xd4, 0x0c,
 	0xff, 0x65, 0x0c, 0x08,
-	0x02, 0x0b, 0x42, 0x7b,
+	0x02, 0x0b, 0x58, 0x7b,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0xd1, 0x6a, 0x22, 0x01,
 	0x00, 0x65, 0x22, 0x41,
 	0xff, 0x65, 0x26, 0x09,
-	0x01, 0x0b, 0x5a, 0x6b,
-	0x10, 0x0c, 0x4c, 0x7b,
-	0x04, 0x0b, 0x54, 0x6b,
+	0x01, 0x0b, 0x70, 0x6b,
+	0x10, 0x0c, 0x62, 0x7b,
+	0x04, 0x0b, 0x6a, 0x6b,
 	0xff, 0x6a, 0xca, 0x08,
-	0x04, 0x93, 0x58, 0x6b,
-	0x01, 0x94, 0x56, 0x7b,
-	0x10, 0x94, 0x58, 0x6b,
+	0x04, 0x93, 0x6e, 0x6b,
+	0x01, 0x94, 0x6c, 0x7b,
+	0x10, 0x94, 0x6e, 0x6b,
 	0xc7, 0x93, 0x26, 0x09,
 	0xff, 0x99, 0xd4, 0x08,
-	0x38, 0x93, 0x5c, 0x6b,
+	0x38, 0x93, 0x72, 0x6b,
 	0xff, 0x6a, 0xd4, 0x0c,
-	0x80, 0x36, 0x60, 0x6b,
+	0x80, 0x36, 0x76, 0x6b,
 	0x21, 0x6a, 0x22, 0x05,
 	0xff, 0x65, 0x20, 0x09,
-	0xff, 0x51, 0x6e, 0x63,
+	0xff, 0x51, 0x84, 0x63,
 	0xff, 0x37, 0xc8, 0x08,
-	0xa1, 0x6a, 0x7a, 0x43,
+	0xa1, 0x6a, 0x90, 0x43,
 	0xff, 0x51, 0xc8, 0x08,
-	0xb9, 0x6a, 0x7a, 0x43,
+	0xb9, 0x6a, 0x90, 0x43,
 	0xff, 0x90, 0xa4, 0x08,
-	0xff, 0xba, 0x7e, 0x73,
+	0xff, 0xba, 0x94, 0x73,
 	0xff, 0xba, 0x20, 0x09,
 	0xff, 0x65, 0xca, 0x18,
-	0x00, 0x6c, 0x72, 0x63,
+	0x00, 0x6c, 0x88, 0x63,
 	0xff, 0x90, 0xca, 0x0c,
 	0xff, 0x6a, 0xca, 0x04,
-	0x20, 0x36, 0x92, 0x7b,
-	0x00, 0x90, 0x66, 0x5b,
-	0xff, 0x65, 0x92, 0x73,
-	0xff, 0x52, 0x90, 0x73,
+	0x20, 0x36, 0xa8, 0x7b,
+	0x00, 0x90, 0x7c, 0x5b,
+	0xff, 0x65, 0xa8, 0x73,
+	0xff, 0x52, 0xa6, 0x73,
 	0xff, 0xba, 0xcc, 0x08,
 	0xff, 0x52, 0x20, 0x09,
 	0xff, 0x66, 0x74, 0x09,
 	0xff, 0x65, 0x20, 0x0d,
 	0xff, 0xba, 0x7e, 0x0c,
-	0x00, 0x6a, 0x92, 0x5c,
+	0x00, 0x6a, 0xa8, 0x5c,
 	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0x51, 0x1e, 0x44,
-	0xff, 0x3f, 0xec, 0x73,
+	0x00, 0x51, 0x34, 0x44,
+	0xff, 0x3f, 0x02, 0x74,
 	0xff, 0x6a, 0xa2, 0x00,
-	0x00, 0x3f, 0x66, 0x5b,
-	0xff, 0x65, 0xec, 0x73,
+	0x00, 0x3f, 0x7c, 0x5b,
+	0xff, 0x65, 0x02, 0x74,
 	0x20, 0x36, 0x6c, 0x00,
-	0x20, 0xa0, 0xa6, 0x6b,
+	0x20, 0xa0, 0xbc, 0x6b,
 	0xff, 0xb9, 0xa2, 0x0c,
 	0xff, 0x6a, 0xa2, 0x04,
 	0xff, 0x65, 0xa4, 0x08,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0x12, 0x5c,
+	0x45, 0x6a, 0x28, 0x5c,
 	0x01, 0x6a, 0xd0, 0x01,
 	0x09, 0x6a, 0xd6, 0x01,
-	0x80, 0xeb, 0xb2, 0x7b,
+	0x80, 0xeb, 0xc8, 0x7b,
 	0x01, 0x6a, 0xd6, 0x01,
 	0x01, 0xe9, 0xa4, 0x34,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0x12, 0x5c,
+	0x45, 0x6a, 0x28, 0x5c,
 	0x01, 0x6a, 0x18, 0x01,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0x0d, 0x6a, 0x26, 0x01,
-	0x00, 0x65, 0x84, 0x5c,
+	0x00, 0x65, 0x9a, 0x5c,
 	0xff, 0x99, 0xa4, 0x0c,
 	0xff, 0x65, 0xa4, 0x08,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0x12, 0x5c,
+	0x45, 0x6a, 0x28, 0x5c,
 	0x01, 0x6a, 0xd0, 0x01,
 	0x01, 0x6a, 0xdc, 0x05,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0x12, 0x5c,
+	0x45, 0x6a, 0x28, 0x5c,
 	0x01, 0x6a, 0x18, 0x01,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0x01, 0x6a, 0x26, 0x05,
 	0x01, 0x65, 0xd8, 0x31,
 	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0xe2, 0x7b,
+	0x80, 0xee, 0xf8, 0x7b,
 	0xff, 0x6a, 0xdc, 0x0d,
 	0xff, 0x65, 0x32, 0x09,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x84, 0x44,
+	0x00, 0x65, 0x9a, 0x44,
 	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0x6a, 0xa8, 0x5b,
+	0x00, 0x6a, 0xbe, 0x5b,
 	0xff, 0x52, 0xa2, 0x0c,
-	0x01, 0x0c, 0xf2, 0x7b,
-	0x04, 0x0c, 0xf2, 0x6b,
+	0x01, 0x0c, 0x08, 0x7c,
+	0x04, 0x0c, 0x08, 0x6c,
 	0xe0, 0x03, 0x06, 0x08,
 	0xe0, 0x03, 0x7a, 0x0c,
 	0xff, 0x8c, 0x10, 0x08,
@@ -531,29 +542,29 @@
 	0x00, 0x6c, 0xda, 0x24,
 	0xff, 0x65, 0xc8, 0x08,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x41, 0x6a, 0x0e, 0x5c,
+	0x41, 0x6a, 0x24, 0x5c,
 	0xff, 0x90, 0xe2, 0x09,
 	0x20, 0x6a, 0xd0, 0x01,
-	0x04, 0x35, 0x30, 0x7c,
+	0x04, 0x35, 0x46, 0x7c,
 	0x1d, 0x6a, 0xdc, 0x01,
-	0xdc, 0xee, 0x2c, 0x64,
-	0x00, 0x65, 0x3c, 0x44,
+	0xdc, 0xee, 0x42, 0x64,
+	0x00, 0x65, 0x52, 0x44,
 	0x01, 0x6a, 0xdc, 0x01,
 	0x20, 0xa0, 0xd8, 0x31,
 	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0x36, 0x7c,
+	0x80, 0xee, 0x4c, 0x7c,
 	0x19, 0x6a, 0xdc, 0x01,
-	0xd8, 0xee, 0x3a, 0x64,
+	0xd8, 0xee, 0x50, 0x64,
 	0xff, 0x6a, 0xdc, 0x09,
-	0x18, 0xee, 0x3e, 0x6c,
+	0x18, 0xee, 0x54, 0x6c,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x41, 0x6a, 0x0e, 0x5c,
+	0x41, 0x6a, 0x24, 0x5c,
 	0x20, 0x6a, 0x18, 0x01,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x35, 0x68, 0x6c,
+	0x04, 0x35, 0x7e, 0x6c,
 	0xa0, 0x6a, 0xca, 0x00,
 	0x20, 0x65, 0xc8, 0x18,
 	0xff, 0x6c, 0x32, 0x09,
@@ -564,14 +575,14 @@
 	0xff, 0x6c, 0x32, 0x09,
 	0xff, 0x6c, 0x32, 0x09,
 	0xff, 0x6c, 0x32, 0x09,
-	0x00, 0x65, 0x54, 0x64,
+	0x00, 0x65, 0x6a, 0x64,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x84, 0x5c,
-	0x04, 0x35, 0x60, 0x7b,
-	0xa0, 0x6a, 0x74, 0x5c,
-	0x00, 0x65, 0x76, 0x5c,
-	0x00, 0x65, 0x76, 0x5c,
-	0x00, 0x65, 0x76, 0x44,
+	0x00, 0x65, 0x9a, 0x5c,
+	0x04, 0x35, 0x76, 0x7b,
+	0xa0, 0x6a, 0x8a, 0x5c,
+	0x00, 0x65, 0x8c, 0x5c,
+	0x00, 0x65, 0x8c, 0x5c,
+	0x00, 0x65, 0x8c, 0x44,
 	0xff, 0x65, 0xcc, 0x08,
 	0xff, 0x99, 0xda, 0x08,
 	0xff, 0x99, 0xda, 0x08,
@@ -580,19 +591,19 @@
 	0xff, 0x99, 0xda, 0x08,
 	0xff, 0x99, 0xda, 0x08,
 	0xff, 0x99, 0xda, 0x0c,
-	0x08, 0x94, 0x84, 0x7c,
+	0x08, 0x94, 0x9a, 0x7c,
 	0xf7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0x88, 0x6c,
+	0x08, 0x93, 0x9e, 0x6c,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0xff, 0x40, 0x74, 0x09,
 	0xff, 0x90, 0x80, 0x08,
 	0xff, 0x6a, 0x72, 0x05,
-	0xff, 0x40, 0xa0, 0x64,
-	0xff, 0x3f, 0x98, 0x64,
+	0xff, 0x40, 0xb6, 0x64,
+	0xff, 0x3f, 0xae, 0x64,
 	0xff, 0x6a, 0xca, 0x04,
 	0xff, 0x3f, 0x20, 0x09,
 	0x01, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0x1e, 0x5c,
+	0x00, 0xb9, 0x34, 0x5c,
 	0xff, 0xba, 0x7e, 0x0c,
 	0xff, 0x40, 0x20, 0x09,
 	0xff, 0xba, 0x80, 0x0c,
@@ -739,60 +750,60 @@
 	{ aic7xxx_patch1_func, 68, 60, 1 },
 	{ aic7xxx_patch8_func, 162, 1, 2 },
 	{ aic7xxx_patch0_func, 163, 2, 1 },
-	{ aic7xxx_patch2_func, 167, 2, 3 },
-	{ aic7xxx_patch8_func, 167, 1, 1 },
-	{ aic7xxx_patch0_func, 169, 2, 1 },
-	{ aic7xxx_patch8_func, 172, 1, 2 },
-	{ aic7xxx_patch0_func, 173, 1, 1 },
-	{ aic7xxx_patch2_func, 177, 1, 1 },
-	{ aic7xxx_patch2_func, 180, 3, 2 },
-	{ aic7xxx_patch0_func, 183, 5, 1 },
-	{ aic7xxx_patch2_func, 191, 2, 3 },
-	{ aic7xxx_patch8_func, 191, 1, 1 },
-	{ aic7xxx_patch0_func, 193, 3, 1 },
-	{ aic7xxx_patch10_func, 196, 2, 1 },
-	{ aic7xxx_patch8_func, 198, 7, 2 },
-	{ aic7xxx_patch0_func, 205, 1, 1 },
-	{ aic7xxx_patch2_func, 210, 14, 3 },
-	{ aic7xxx_patch10_func, 223, 1, 1 },
-	{ aic7xxx_patch0_func, 224, 9, 1 },
-	{ aic7xxx_patch8_func, 238, 2, 1 },
-	{ aic7xxx_patch8_func, 240, 1, 1 },
-	{ aic7xxx_patch10_func, 241, 6, 3 },
-	{ aic7xxx_patch2_func, 241, 2, 2 },
-	{ aic7xxx_patch0_func, 243, 4, 1 },
-	{ aic7xxx_patch8_func, 248, 1, 1 },
-	{ aic7xxx_patch8_func, 252, 11, 1 },
-	{ aic7xxx_patch2_func, 264, 3, 3 },
-	{ aic7xxx_patch10_func, 266, 1, 1 },
-	{ aic7xxx_patch0_func, 267, 5, 1 },
-	{ aic7xxx_patch10_func, 272, 1, 2 },
-	{ aic7xxx_patch0_func, 273, 7, 1 },
-	{ aic7xxx_patch11_func, 287, 1, 2 },
-	{ aic7xxx_patch0_func, 288, 1, 1 },
-	{ aic7xxx_patch5_func, 348, 1, 2 },
-	{ aic7xxx_patch0_func, 349, 1, 1 },
-	{ aic7xxx_patch3_func, 352, 1, 1 },
-	{ aic7xxx_patch2_func, 362, 3, 2 },
-	{ aic7xxx_patch0_func, 365, 5, 1 },
-	{ aic7xxx_patch11_func, 373, 1, 2 },
-	{ aic7xxx_patch0_func, 374, 1, 1 },
-	{ aic7xxx_patch6_func, 379, 1, 1 },
-	{ aic7xxx_patch1_func, 416, 3, 1 },
-	{ aic7xxx_patch10_func, 421, 11, 1 },
-	{ aic7xxx_patch2_func, 469, 7, 2 },
-	{ aic7xxx_patch0_func, 476, 8, 1 },
-	{ aic7xxx_patch2_func, 485, 4, 2 },
-	{ aic7xxx_patch0_func, 489, 6, 1 },
-	{ aic7xxx_patch2_func, 495, 4, 2 },
-	{ aic7xxx_patch0_func, 499, 3, 1 },
-	{ aic7xxx_patch12_func, 509, 10, 1 },
-	{ aic7xxx_patch2_func, 528, 17, 4 },
-	{ aic7xxx_patch13_func, 536, 4, 2 },
-	{ aic7xxx_patch0_func, 540, 2, 1 },
-	{ aic7xxx_patch0_func, 545, 33, 1 },
-	{ aic7xxx_patch12_func, 578, 4, 1 },
-	{ aic7xxx_patch6_func, 582, 2, 1 },
-	{ aic7xxx_patch6_func, 585, 9, 1 },
+	{ aic7xxx_patch2_func, 167, 3, 3 },
+	{ aic7xxx_patch8_func, 167, 2, 1 },
+	{ aic7xxx_patch0_func, 170, 2, 1 },
+	{ aic7xxx_patch8_func, 173, 1, 2 },
+	{ aic7xxx_patch0_func, 174, 1, 1 },
+	{ aic7xxx_patch2_func, 178, 1, 1 },
+	{ aic7xxx_patch2_func, 181, 3, 2 },
+	{ aic7xxx_patch0_func, 184, 5, 1 },
+	{ aic7xxx_patch2_func, 192, 2, 3 },
+	{ aic7xxx_patch8_func, 192, 1, 1 },
+	{ aic7xxx_patch0_func, 194, 3, 1 },
+	{ aic7xxx_patch10_func, 197, 2, 1 },
+	{ aic7xxx_patch8_func, 199, 7, 2 },
+	{ aic7xxx_patch0_func, 206, 1, 1 },
+	{ aic7xxx_patch2_func, 211, 14, 3 },
+	{ aic7xxx_patch10_func, 224, 1, 1 },
+	{ aic7xxx_patch0_func, 225, 9, 1 },
+	{ aic7xxx_patch8_func, 239, 2, 1 },
+	{ aic7xxx_patch8_func, 241, 1, 1 },
+	{ aic7xxx_patch10_func, 242, 6, 3 },
+	{ aic7xxx_patch2_func, 242, 2, 2 },
+	{ aic7xxx_patch0_func, 244, 4, 1 },
+	{ aic7xxx_patch8_func, 249, 1, 1 },
+	{ aic7xxx_patch8_func, 253, 19, 1 },
+	{ aic7xxx_patch2_func, 273, 3, 3 },
+	{ aic7xxx_patch10_func, 275, 1, 1 },
+	{ aic7xxx_patch0_func, 276, 5, 1 },
+	{ aic7xxx_patch10_func, 281, 1, 2 },
+	{ aic7xxx_patch0_func, 282, 9, 1 },
+	{ aic7xxx_patch11_func, 298, 1, 2 },
+	{ aic7xxx_patch0_func, 299, 1, 1 },
+	{ aic7xxx_patch5_func, 359, 1, 2 },
+	{ aic7xxx_patch0_func, 360, 1, 1 },
+	{ aic7xxx_patch3_func, 363, 1, 1 },
+	{ aic7xxx_patch2_func, 373, 3, 2 },
+	{ aic7xxx_patch0_func, 376, 5, 1 },
+	{ aic7xxx_patch11_func, 384, 1, 2 },
+	{ aic7xxx_patch0_func, 385, 1, 1 },
+	{ aic7xxx_patch6_func, 390, 1, 1 },
+	{ aic7xxx_patch1_func, 427, 3, 1 },
+	{ aic7xxx_patch10_func, 432, 11, 1 },
+	{ aic7xxx_patch2_func, 480, 7, 2 },
+	{ aic7xxx_patch0_func, 487, 8, 1 },
+	{ aic7xxx_patch2_func, 496, 4, 2 },
+	{ aic7xxx_patch0_func, 500, 6, 1 },
+	{ aic7xxx_patch2_func, 506, 4, 2 },
+	{ aic7xxx_patch0_func, 510, 3, 1 },
+	{ aic7xxx_patch12_func, 520, 10, 1 },
+	{ aic7xxx_patch2_func, 539, 17, 4 },
+	{ aic7xxx_patch13_func, 547, 4, 2 },
+	{ aic7xxx_patch0_func, 551, 2, 1 },
+	{ aic7xxx_patch0_func, 556, 33, 1 },
+	{ aic7xxx_patch12_func, 589, 4, 1 },
+	{ aic7xxx_patch6_func, 593, 2, 1 },
+	{ aic7xxx_patch6_func, 596, 9, 1 },
 
 };
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/atp870u.c linux.14p16/drivers/scsi/atp870u.c
--- linux.vanilla/drivers/scsi/atp870u.c	Wed Oct 20 01:12:40 1999
+++ linux.14p16/drivers/scsi/atp870u.c	Thu Dec  9 15:33:55 1999
@@ -17,9 +17,9 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
+#include <asm/spinlock.h>
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/spinlock.h>
 #include <linux/pci.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -42,47 +42,59 @@
  *   static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $";
  */
 
-static unsigned char admaxu = 1, host_idu[2], chip_veru[2], scam_on[2], global_map[2];
-static unsigned short int active_idu[2], wide_idu[2], sync_idu, ultra_map[2];
-static int workingu[2] = {0, 0};
-
-static Scsi_Cmnd *querequ[2][qcnt], *curr_req[2][16];
-
-static unsigned char devspu[2][16] = {
-	{0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-	 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20},
-	{0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-	 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}
-};
+static unsigned char admaxu = 1;
+static unsigned short int sync_idu;
 
-static unsigned char dirctu[2][16], last_cmd[2], in_snd[2], in_int[2];
-static unsigned char ata_cdbu[2][16];
-static unsigned int ioportu[2] = {0, 0};
 static unsigned int irqnumu[2] = {0, 0};
-static unsigned short int pciportu[2];
-static unsigned long prdaddru[2][16], tran_lenu[2][16], last_lenu[2][16];
-static unsigned char prd_tableu[2][16][1024];
-static unsigned char *prd_posu[2][16];
-static unsigned char quhdu[2], quendu[2];
 
-static unsigned char devtypeu[2][16] =
+struct atp_unit
 {
-	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
-	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+	unsigned long ioport;
+	unsigned long irq;
+	unsigned long pciport;
+	unsigned char last_cmd;
+	unsigned char in_snd;
+	unsigned char in_int;
+	unsigned char quhdu;
+	unsigned char quendu;
+	unsigned char scam_on;
+	unsigned char global_map;
+	unsigned char chip_veru;
+	unsigned char host_idu;
+	int working;
+	unsigned short wide_idu;
+	unsigned short active_idu;
+	unsigned short ultra_map;
+	unsigned char ata_cdbu[16];
+	Scsi_Cmnd *querequ[qcnt];
+	struct atp_id
+	{
+		unsigned char dirctu;
+		unsigned char devspu;
+		unsigned char devtypeu;
+		unsigned long prdaddru;
+		unsigned long tran_lenu;
+		unsigned long last_lenu;
+		unsigned char *prd_posu;
+		unsigned char *prd_tableu;
+		Scsi_Cmnd *curr_req;
+	} id[16];
 };
 
 static struct Scsi_Host *atp_host[2] = {NULL, NULL};
+static struct atp_unit atp_unit[2];
 
 static void atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
 	unsigned short int tmpcip, id;
-	unsigned char i, j, h, tarid, lun;
+	unsigned char i, j, h, target_id, lun;
 	unsigned char *prd;
 	Scsi_Cmnd *workrequ;
 	unsigned int workportu, tmport;
 	unsigned long adrcntu, k;
 	int errstus;
+	struct atp_unit *dev = dev_id;
 
 	for (h = 0; h < 2; h++) {
 		if (irq == irqnumu[h]) {
@@ -91,59 +103,84 @@
 	}
 	return;
 irq_numok:
-	in_int[h] = 1;
-	workportu = ioportu[h];
+	dev->in_int = 1;
+	workportu = dev->ioport;
 	tmport = workportu;
-
-	if (workingu[h] != 0) 
+	
+	if (dev->working != 0) 
 	{
 		tmport += 0x1f;
 		j = inb(tmport);
 
-		tmpcip = pciportu[h];
+		tmpcip = dev->pciport;
 		if ((inb(tmpcip) & 0x08) != 0) 
 		{
 			tmpcip += 0x2;
-			while ((inb(tmpcip) & 0x08) != 0);
+			for (k=0; k < 1000; k++)
+			{
+				if ((inb(tmpcip) & 0x08) == 0)
+				{
+					goto stop_dma;
+				}
+				if ((inb(tmpcip) & 0x01) == 0)
+				{
+					goto stop_dma;
+				}    
+			}
 		}
-		tmpcip = pciportu[h];
+stop_dma:
+		tmpcip = dev->pciport;
 		outb(0x00, tmpcip);
 		tmport -= 0x08;
 
 		i = inb(tmport);
 		if ((j & 0x40) == 0) 
 		{
-			if ((last_cmd[h] & 0x40) == 0) 
+			if ((dev->last_cmd & 0x40) == 0) 
 			{
-				last_cmd[h] = 0xff;
+				dev->last_cmd = 0xff;
 			}
 		}
-		else last_cmd[h] |= 0x40;
+		else dev->last_cmd |= 0x40;
 
 		tmport -= 0x02;
-		tarid = inb(tmport);
+		target_id = inb(tmport);
 		tmport += 0x02;
 
-		if ((tarid & 0x40) != 0) {
-			tarid = (tarid & 0x07) | 0x08;
+		/*
+		 *	Remap wide devices onto id numbers
+		 */
+		 
+		if ((target_id & 0x40) != 0) {
+			target_id = (target_id & 0x07) | 0x08;
 		} else {
-			tarid &= 0x07;
+			target_id &= 0x07;
 		}
+		
 		if (i == 0x85) 
 		{
-			if (wide_idu[h] != 0) 
+			/*
+			 *	Flip wide
+			 */
+			if (dev->wide_idu != 0) 
 			{
 				tmport = workportu + 0x1b;
 				j = inb(tmport) & 0x0e;
 				j |= 0x01;
 				outb(j, tmport);
 			}
-			if (((quhdu[h] != quendu[h]) || (last_cmd[h] != 0xff)) &&
-			    (in_snd[h] == 0)) 
+			/*
+			 *	Issue more commands
+			 */
+			if (((dev->quhdu != dev->quendu) || (dev->last_cmd != 0xff)) &&
+			    (dev->in_snd == 0)) 
 			{
 				send_s870(h);
 			}
-			in_int[h] = 0;
+			/*
+			 *	Done
+			 */
+			dev->in_int = 0;
 			return;
 		}
 		if (i == 0x21) 
@@ -153,15 +190,15 @@
 			((unsigned char *) &adrcntu)[2] = inb(tmport++);
 			((unsigned char *) &adrcntu)[1] = inb(tmport++);
 			((unsigned char *) &adrcntu)[0] = inb(tmport);
-			k = last_lenu[h][tarid];
+			k = dev->id[target_id].last_lenu;
 			k -= adrcntu;
-			tran_lenu[h][tarid] = k;
-			last_lenu[h][tarid] = adrcntu;
+			dev->id[target_id].tran_lenu = k;
+			dev->id[target_id].last_lenu = adrcntu;
 			tmport -= 0x04;
 			outb(0x41, tmport);
 			tmport += 0x08;
 			outb(0x08, tmport);
-			in_int[h] = 0;
+			dev->in_int = 0;
 			return;
 		}
 		if ((i == 0x80) || (i == 0x8f)) 
@@ -169,7 +206,7 @@
 			lun = 0;
 			tmport -= 0x07;
 			j = inb(tmport);
-			if (j == 0x44) {
+			if (j == 0x44 || i==0x80) {
 				tmport += 0x0d;
 				lun = inb(tmport) & 0x07;
 			} else {
@@ -180,71 +217,80 @@
 					((unsigned char *) &adrcntu)[2] = inb(tmport++);
 					((unsigned char *) &adrcntu)[1] = inb(tmport++);
 					((unsigned char *) &adrcntu)[0] = inb(tmport);
-					k = last_lenu[h][tarid];
+					k = dev->id[target_id].last_lenu;
 					k -= adrcntu;
-					tran_lenu[h][tarid] = k;
-					last_lenu[h][tarid] = adrcntu;
+					dev->id[target_id].tran_lenu = k;
+					dev->id[target_id].last_lenu = adrcntu;
 					tmport += 0x04;
 					outb(0x08, tmport);
-					in_int[h] = 0;
+					dev->in_int = 0;
 					return;
 				}
 				else 
 				{
 					outb(0x46, tmport);
-					dirctu[h][tarid] = 0x00;
+					dev->id[target_id].dirctu = 0x00;
 					tmport += 0x02;
 					outb(0x00, tmport++);
 					outb(0x00, tmport++);
 					outb(0x00, tmport++);
 					tmport += 0x03;
 					outb(0x08, tmport);
-					in_int[h] = 0;
+					dev->in_int = 0;
 					return;
 				}
 			}
 			tmport = workportu + 0x10;
 			outb(0x45, tmport);
 			tmport += 0x06;
-			tarid = inb(tmport);
-			if ((tarid & 0x10) != 0) 
+			target_id = inb(tmport);
+			/*
+			 *	Remap wide identifiers
+			 */
+			if ((target_id & 0x10) != 0) 
 			{
-				tarid = (tarid & 0x07) | 0x08;
+				target_id = (target_id & 0x07) | 0x08;
 			} else {
-				tarid &= 0x07;
+				target_id &= 0x07;
 			}
-			workrequ = curr_req[h][tarid];
+			workrequ = dev->id[target_id].curr_req;
 			tmport = workportu + 0x0f;
 			outb(lun, tmport);
 			tmport += 0x02;
-			outb(devspu[h][tarid], tmport++);
-			adrcntu = tran_lenu[h][tarid];
-			k = last_lenu[h][tarid];
+			outb(dev->id[target_id].devspu, tmport++);
+			adrcntu = dev->id[target_id].tran_lenu;
+			k = dev->id[target_id].last_lenu;
 			outb(((unsigned char *) &k)[2], tmport++);
 			outb(((unsigned char *) &k)[1], tmport++);
 			outb(((unsigned char *) &k)[0], tmport++);
-			j = tarid;
-			if (tarid > 7) {
+			/* Remap wide */
+			j = target_id;
+			if (target_id > 7) {
 				j = (j & 0x07) | 0x40;
 			}
-			j |= dirctu[h][tarid];
+			/* Add direction */
+			j |= dev->id[target_id].dirctu;
 			outb(j, tmport++);
 			outb(0x80, tmport);
 			tmport = workportu + 0x1b;
 			j = inb(tmport) & 0x0e;
 			id = 1;
-			id = id << tarid;
-			if ((id & wide_idu[h]) != 0) {
+			id = id << target_id;
+			/*
+			 *	Is this a wide device
+			 */
+			if ((id & dev->wide_idu) != 0) {
 				j |= 0x01;
 			}
 			outb(j, tmport);
-			if (last_lenu[h][tarid] == 0) {
+			
+			if (dev->id[target_id].last_lenu == 0) {
 				tmport = workportu + 0x18;
 				outb(0x08, tmport);
-				in_int[h] = 0;
+				dev->in_int = 0;
 				return;
 			}
-			prd = prd_posu[h][tarid];
+			prd = dev->id[target_id].prd_posu;
 			while (adrcntu != 0) 
 			{
 				id = ((unsigned short int *) (prd))[2];
@@ -258,35 +304,44 @@
 					    (k - adrcntu);
 					((unsigned long *) (prd))[0] += adrcntu;
 					adrcntu = 0;
-					prd_posu[h][tarid] = prd;
+					dev->id[target_id].prd_posu = prd;
 				} else {
 					adrcntu -= k;
-					prdaddru[h][tarid] += 0x08;
+					dev->id[target_id].prdaddru += 0x08;
 					prd += 0x08;
 					if (adrcntu == 0) {
-						prd_posu[h][tarid] = prd;
+						dev->id[target_id].prd_posu = prd;
 					}
 				}
 			}
-			tmpcip = pciportu[h] + 0x04;
-			outl(prdaddru[h][tarid], tmpcip);
+			tmpcip = dev->pciport + 0x04;
+			outl(dev->id[target_id].prdaddru, tmpcip);
 			tmpcip -= 0x02;
 			outb(0x06, tmpcip);
 			outb(0x00, tmpcip);
 			tmpcip -= 0x02;
 			tmport = workportu + 0x18;
-			if (dirctu[h][tarid] != 0) {
+			/*
+			 *	Check transfer direction
+			 */
+			if (dev->id[target_id].dirctu != 0) {
 				outb(0x08, tmport);
 				outb(0x01, tmpcip);
-				in_int[h] = 0;
+				dev->in_int = 0;
 				return;
 			}
 			outb(0x08, tmport);
 			outb(0x09, tmpcip);
-			in_int[h] = 0;
+			dev->in_int = 0;
 			return;
 		}
-		workrequ = curr_req[h][tarid];
+		
+		/*
+		 *	Current scsi request on this target
+		 */
+		 
+		workrequ = dev->id[target_id].curr_req;
+		
 		if (i == 0x42) {
 			errstus = 0x02;
 			workrequ->result = errstus;
@@ -299,24 +354,36 @@
 			errstus = inb(tmport);
 			workrequ->result = errstus;
 go_42:
+			/*
+			 *	Complete the command
+			 */
 			spin_lock_irqsave(&io_request_lock, flags);
 			(*workrequ->scsi_done) (workrequ);
 			spin_unlock_irqrestore(&io_request_lock, flags);
 
-			curr_req[h][tarid] = 0;
-			workingu[h]--;
-			if (wide_idu[h] != 0) {
+			/*
+			 *	Clear it off the queue
+			 */
+			dev->id[target_id].curr_req = 0;
+			dev->working--;
+			/*
+			 *	Take it back wide
+			 */
+			if (dev->wide_idu != 0) {
 				tmport = workportu + 0x1b;
 				j = inb(tmport) & 0x0e;
 				j |= 0x01;
 				outb(j, tmport);
 			}
-			if (((last_cmd[h] != 0xff) || (quhdu[h] != quendu[h])) &&
-			    (in_snd[h] == 0)) 
+			/*
+			 *	If there is stuff to send and nothing going then send it
+			 */
+			if (((dev->last_cmd != 0xff) || (dev->quhdu != dev->quendu)) &&
+			    (dev->in_snd == 0)) 
 			{
 				send_s870(h);
 			}
-			in_int[h] = 0;
+			dev->in_int = 0;
 			return;
 		}
 		if (i == 0x4f) {
@@ -325,23 +392,23 @@
 		i &= 0x0f;
 		if (i == 0x09) {
 			tmpcip = tmpcip + 4;
-			outl(prdaddru[h][tarid], tmpcip);
+			outl(dev->id[target_id].prdaddru, tmpcip);
 			tmpcip = tmpcip - 2;
 			outb(0x06, tmpcip);
 			outb(0x00, tmpcip);
 			tmpcip = tmpcip - 2;
 			tmport = workportu + 0x10;
 			outb(0x41, tmport);
-			dirctu[h][tarid] = 0x00;
+			dev->id[target_id].dirctu = 0x00;
 			tmport += 0x08;
 			outb(0x08, tmport);
 			outb(0x09, tmpcip);
-			in_int[h] = 0;
+			dev->in_int = 0;
 			return;
 		}
 		if (i == 0x08) {
 			tmpcip = tmpcip + 4;
-			outl(prdaddru[h][tarid], tmpcip);
+			outl(dev->id[target_id].prdaddru, tmpcip);
 			tmpcip = tmpcip - 2;
 			outb(0x06, tmpcip);
 			outb(0x00, tmpcip);
@@ -350,11 +417,11 @@
 			outb(0x41, tmport);
 			tmport += 0x05;
 			outb((unsigned char) (inb(tmport) | 0x20), tmport);
-			dirctu[h][tarid] = 0x20;
+			dev->id[target_id].dirctu = 0x20;
 			tmport += 0x03;
 			outb(0x08, tmport);
 			outb(0x01, tmpcip);
-			in_int[h] = 0;
+			dev->in_int = 0;
 			return;
 		}
 		tmport -= 0x07;
@@ -363,20 +430,20 @@
 		} else {
 			outb(0x46, tmport);
 		}
-		dirctu[h][tarid] = 0x00;
+		dev->id[target_id].dirctu = 0x00;
 		tmport += 0x02;
 		outb(0x00, tmport++);
 		outb(0x00, tmport++);
 		outb(0x00, tmport++);
 		tmport += 0x03;
 		outb(0x08, tmport);
-		in_int[h] = 0;
+		dev->in_int = 0;
 		return;
 	} else {
 		tmport = workportu + 0x17;
 		inb(tmport);
-		workingu[h] = 0;
-		in_int[h] = 0;
+		dev->working = 0;
+		dev->in_int = 0;
 		return;
 	}
 }
@@ -387,6 +454,7 @@
 	unsigned long flags;
 	unsigned short int m;
 	unsigned int tmport;
+	struct atp_unit *dev;
 
 	for (h = 0; h <= admaxu; h++) {
 		if (req_p->host == atp_host[h]) {
@@ -400,9 +468,15 @@
 		done(req_p);
 		return 0;
 	}
+	dev = &atp_unit[h];
 	m = 1;
 	m = m << req_p->target;
-	if ((m & active_idu[h]) == 0) {
+
+	/*
+	 *	Fake a timeout for missing targets
+	 */
+	 
+	if ((m & dev->active_idu) == 0) {
 		req_p->result = 0x00040000;
 		done(req_p);
 		return 0;
@@ -410,30 +484,36 @@
 	if (done) {
 		req_p->scsi_done = done;
 	} else {
-		printk("atp870u_queuecommand: done can't be NULL\n");
+		printk(KERN_WARNING "atp870u_queuecommand: done can't be NULL\n");
 		req_p->result = 0;
 		done(req_p);
 		return 0;
 	}
-	quendu[h]++;
-	if (quendu[h] >= qcnt) {
-		quendu[h] = 0;
+	/*
+	 *	Count new command
+	 */
+	dev->quendu++;
+	if (dev->quendu >= qcnt) {
+		dev->quendu = 0;
 	}
+	/*
+	 *	Check queue state
+	 */
 wait_que_empty:
-	if (quhdu[h] == quendu[h]) {
+	if (dev->quhdu == dev->quendu) {
 		goto wait_que_empty;
 	}
 	save_flags(flags);
 	cli();
-	querequ[h][quendu[h]] = req_p;
-	if (quendu[h] == 0) {
+	dev->querequ[dev->quendu] = req_p;
+	if (dev->quendu == 0) {
 		i = qcnt - 1;
 	} else {
-		i = quendu[h] - 1;
+		i = dev->quendu - 1;
 	}
-	tmport = ioportu[h] + 0x1c;
+	tmport = dev->ioport + 0x1c;
 	restore_flags(flags);
-	if ((inb(tmport) == 0) && (in_int[h] == 0) && (in_snd[h] == 0)) {
+	if ((inb(tmport) == 0) && (dev->in_int == 0) && (dev->in_snd == 0)) {
 		send_s870(h);
 	}
 	return 0;
@@ -453,44 +533,45 @@
 	Scsi_Cmnd *workrequ;
 	unsigned long flags;
 	unsigned int i;
-	unsigned char j, tarid;
+	unsigned char j, target_id;
 	unsigned char *prd;
 	unsigned short int tmpcip, w;
 	unsigned long l, bttl;
 	unsigned int workportu;
 	struct scatterlist *sgpnt;
+	struct atp_unit *dev = &atp_unit[h];
 
 	save_flags(flags);
 	cli();
-	if (in_snd[h] != 0) {
+	if (dev->in_snd != 0) {
 		restore_flags(flags);
 		return;
 	}
-	in_snd[h] = 1;
-	if ((last_cmd[h] != 0xff) && ((last_cmd[h] & 0x40) != 0)) {
-		last_cmd[h] &= 0x0f;
-		workrequ = curr_req[h][last_cmd[h]];
+	dev->in_snd = 1;
+	if ((dev->last_cmd != 0xff) && ((dev->last_cmd & 0x40) != 0)) {
+		dev->last_cmd &= 0x0f;
+		workrequ = dev->id[dev->last_cmd].curr_req;
 		goto cmd_subp;
 	}
-	workingu[h]++;
-	j = quhdu[h];
-	quhdu[h]++;
-	if (quhdu[h] >= qcnt) {
-		quhdu[h] = 0;
-	}
-	workrequ = querequ[h][quhdu[h]];
-	if (curr_req[h][workrequ->target] == 0) {
-		curr_req[h][workrequ->target] = workrequ;
-		last_cmd[h] = workrequ->target;
+	dev->working++;
+	j = dev->quhdu;
+	dev->quhdu++;
+	if (dev->quhdu >= qcnt) {
+		dev->quhdu = 0;
+	}
+	workrequ = dev->querequ[dev->quhdu];
+	if (dev->id[workrequ->target].curr_req == 0) {
+		dev->id[workrequ->target].curr_req = workrequ;
+		dev->last_cmd = workrequ->target;
 		goto cmd_subp;
 	}
-	quhdu[h] = j;
-	workingu[h]--;
-	in_snd[h] = 0;
+	dev->quhdu = j;
+	dev->working--;
+	dev->in_snd = 0;
 	restore_flags(flags);
 	return;
 cmd_subp:
-	workportu = ioportu[h];
+	workportu = dev->ioport;
 	tmport = workportu + 0x1f;
 	if ((inb(tmport) & 0xb0) != 0) {
 		goto abortsnd;
@@ -500,43 +581,63 @@
 		goto oktosend;
 	}
 abortsnd:
-	last_cmd[h] |= 0x40;
-	in_snd[h] = 0;
+	dev->last_cmd |= 0x40;
+	dev->in_snd = 0;
 	restore_flags(flags);
 	return;
 oktosend:
-	memcpy(&ata_cdbu[h][0], &workrequ->cmnd[0], workrequ->cmd_len);
-	if (ata_cdbu[h][0] == 0x25) {
+	memcpy(&dev->ata_cdbu[0], &workrequ->cmnd[0], workrequ->cmd_len);
+	if (dev->ata_cdbu[0] == READ_CAPACITY) {
 		if (workrequ->request_bufflen > 8) {
 			workrequ->request_bufflen = 0x08;
 		}
 	}
-	if (ata_cdbu[h][0] == 0x12) {
+	/*
+	 *	Why limit this ????
+	 */
+	if (dev->ata_cdbu[0] == INQUIRY) {
 		if (workrequ->request_bufflen > 0x24) {
 			workrequ->request_bufflen = 0x24;
-			ata_cdbu[h][4] = 0x24;
+			dev->ata_cdbu[4] = 0x24;
 		}
 	}
+	
 	tmport = workportu + 0x1b;
 	j = inb(tmport) & 0x0e;
-	tarid = workrequ->target;
+	target_id = workrequ->target;
+	
+	/*
+	 *	Wide ?
+	 */
 	w = 1;
-	w = w << tarid;
-	if ((w & wide_idu[h]) != 0) {
+	w = w << target_id;
+	if ((w & dev->wide_idu) != 0) {
 		j |= 0x01;
-	}
+	}	
 	outb(j, tmport);
+	
+	/*
+	 *	Write the command
+	 */
+	 
 	tmport = workportu;
 	outb(workrequ->cmd_len, tmport++);
 	outb(0x2c, tmport++);
 	outb(0xcf, tmport++);
 	for (i = 0; i < workrequ->cmd_len; i++) {
-		outb(ata_cdbu[h][i], tmport++);
+		outb(dev->ata_cdbu[i], tmport++);
 	}
 	tmport = workportu + 0x0f;
-	outb(0x00, tmport);
+	outb(workrequ->lun, tmport);
 	tmport += 0x02;
-	outb(devspu[h][tarid], tmport++);
+	/*
+	 *	Write the target
+	 */
+	outb(dev->id[target_id].devspu, tmport++);
+	
+	/*
+	 *	Figure out the transfer size
+	 */
 	if (workrequ->use_sg) 
 	{
 		l = 0;
@@ -552,38 +653,54 @@
 	} else {
 		l = workrequ->request_bufflen;
 	}
+	/*
+	 *	Write transfer size
+	 */
 	outb((unsigned char) (((unsigned char *) (&l))[2]), tmport++);
 	outb((unsigned char) (((unsigned char *) (&l))[1]), tmport++);
 	outb((unsigned char) (((unsigned char *) (&l))[0]), tmport++);
-	j = tarid;
-	last_lenu[h][j] = l;
-	tran_lenu[h][j] = 0;
+	j = target_id;
+	dev->id[j].last_lenu = l;
+	dev->id[j].tran_lenu = 0;
+	/*
+	 *	Flip the wide bits
+	 */
 	if ((j & 0x08) != 0) {
 		j = (j & 0x07) | 0x40;
 	}
-	if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) ||
-	    (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15)) {
+	/*
+	 *	Check transfer direction
+	 */
+	if ((dev->ata_cdbu[0] == WRITE_6) || (dev->ata_cdbu[0] == WRITE_10) ||
+	    (dev->ata_cdbu[0] == WRITE_12) || (dev->ata_cdbu[0] == MODE_SELECT)) {
 		outb((unsigned char) (j | 0x20), tmport++);
 	} else {
 		outb(j, tmport++);
 	}
+	outb((unsigned char)(inb(tmport) | 0x80),tmport);
 	outb(0x80, tmport);
 	tmport = workportu + 0x1c;
-	dirctu[h][tarid] = 0;
+	dev->id[target_id].dirctu = 0;
 	if (l == 0) {
 		if (inb(tmport) == 0) {
 			tmport = workportu + 0x18;
 			outb(0x08, tmport);
 		} else {
-			last_cmd[h] |= 0x40;
+			dev->last_cmd |= 0x40;
 		}
-		in_snd[h] = 0;
+		dev->in_snd = 0;
 		restore_flags(flags);
 		return;
 	}
-	tmpcip = pciportu[h];
-	prd = &prd_tableu[h][tarid][0];
-	prd_posu[h][tarid] = prd;
+	tmpcip = dev->pciport;
+	prd = dev->id[target_id].prd_tableu;
+	dev->id[target_id].prd_posu = prd;
+	
+	/*
+	 *	Now write the request list. Either as scatter/gather or as
+	 *	a linear chain.
+	 */
+	 
 	if (workrequ->use_sg) 
 	{
 		sgpnt = (struct scatterlist *) workrequ->request_buffer;
@@ -596,6 +713,9 @@
 		}
 		(unsigned short int) (((unsigned short int *) (prd))[i - 1]) = 0x8000;
 	} else {
+		/*
+		 *	For a linear request write a chain of blocks
+		 */
 		bttl = virt_to_bus(workrequ->request_buffer);
 		l = workrequ->request_bufflen;
 		i = 0;
@@ -612,24 +732,24 @@
 		(unsigned long) (((unsigned long *) (prd))[i >> 1]) = bttl;
 	}
 	tmpcip = tmpcip + 4;
-	prdaddru[h][tarid] = virt_to_bus(&prd_tableu[h][tarid][0]);
-	outl(prdaddru[h][tarid], tmpcip);
+	dev->id[target_id].prdaddru = virt_to_bus(dev->id[target_id].prd_tableu);
+	outl(dev->id[target_id].prdaddru, tmpcip);
 	tmpcip = tmpcip - 2;
 	outb(0x06, tmpcip);
 	outb(0x00, tmpcip);
 	tmpcip = tmpcip - 2;
-	if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) ||
-	    (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15)) 
+	if ((dev->ata_cdbu[0] == WRITE_6) || (dev->ata_cdbu[0] == WRITE_10) ||
+	    (dev->ata_cdbu[0] == WRITE_12) || (dev->ata_cdbu[0] == MODE_SELECT)) 
 	{
-		dirctu[h][tarid] = 0x20;
+		dev->id[target_id].dirctu = 0x20;
 		if (inb(tmport) == 0) {
 			tmport = workportu + 0x18;
 			outb(0x08, tmport);
 			outb(0x01, tmpcip);
 		} else {
-			last_cmd[h] |= 0x40;
+			dev->last_cmd |= 0x40;
 		}
-		in_snd[h] = 0;
+		dev->in_snd = 0;
 		restore_flags(flags);
 		return;
 	}
@@ -639,9 +759,9 @@
 		outb(0x08, tmport);
 		outb(0x09, tmpcip);
 	} else {
-		last_cmd[h] |= 0x40;
+		dev->last_cmd |= 0x40;
 	}
-	in_snd[h] = 0;
+	dev->in_snd = 0;
 	restore_flags(flags);
 	return;
 
@@ -663,13 +783,13 @@
 	return SCpnt->result;
 }
 
-unsigned char fun_scam(unsigned char host, unsigned short int *val)
+unsigned char fun_scam(struct atp_unit *dev, unsigned short int *val)
 {
 	unsigned int tmport;
 	unsigned short int i, k;
 	unsigned char j;
 
-	tmport = ioportu[host] + 0x1c;
+	tmport = dev->ioport + 0x1c;
 	outw(*val, tmport);
 FUN_D7:
 	for (i = 0; i < 10; i++) {	/* stable >= bus settle delay(400 ns)  */
@@ -712,32 +832,34 @@
 	unsigned long n;
 	unsigned short int m, assignid_map, val;
 	unsigned char mbuf[33], quintet[2];
-	static unsigned char g2q_tab[8] =
-	{0x38, 0x31, 0x32, 0x2b, 0x34, 0x2d, 0x2e, 0x27};
+	struct atp_unit *dev = &atp_unit[host];
+	static unsigned char g2q_tab[8] = {
+		0x38, 0x31, 0x32, 0x2b, 0x34, 0x2d, 0x2e, 0x27
+	};
 
 
 	for (i = 0; i < 0x10; i++) {
 		mydlyu(0xffff);
 	}
 
-	tmport = ioportu[host] + 1;
+	tmport = dev->ioport + 1;
 	outb(0x08, tmport++);
 	outb(0x7f, tmport);
-	tmport = ioportu[host] + 0x11;
+	tmport = dev->ioport + 0x11;
 	outb(0x20, tmport);
 
-	if ((scam_on[host] & 0x40) == 0) {
+	if ((dev->scam_on & 0x40) == 0) {
 		return;
 	}
 	m = 1;
-	m <<= host_idu[host];
+	m <<= dev->host_idu;
 	j = 16;
-	if (chip_veru[host] < 4) {
+	if (dev->chip_veru < 4) {
 		m |= 0xff00;
 		j = 8;
 	}
 	assignid_map = m;
-	tmport = ioportu[host] + 0x02;
+	tmport = dev->ioport + 0x02;
 	outb(0x02, tmport++);	/* 2*2=4ms,3EH 2/32*3E=3.9ms */
 	outb(0, tmport++);
 	outb(0, tmport++);
@@ -752,7 +874,7 @@
 		if ((m & assignid_map) != 0) {
 			continue;
 		}
-		tmport = ioportu[host] + 0x0f;
+		tmport = dev->ioport + 0x0f;
 		outb(0, tmport++);
 		tmport += 0x02;
 		outb(0, tmport++);
@@ -764,14 +886,14 @@
 			k = i;
 		}
 		outb(k, tmport++);
-		tmport = ioportu[host] + 0x1b;
-		if (chip_veru[host] == 4) {
+		tmport = dev->ioport + 0x1b;
+		if (dev->chip_veru == 4) {
 			outb((unsigned char) ((inb(tmport) & 0x0e) | 0x01), tmport);
 		} else {
 			outb((unsigned char) (inb(tmport) & 0x0e), tmport);
 		}
 wait_rdyok:
-		tmport = ioportu[host] + 0x18;
+		tmport = dev->ioport + 0x18;
 		outb(0x09, tmport);
 		tmport += 0x07;
 
@@ -782,22 +904,22 @@
 			if ((k == 0x85) || (k == 0x42)) {
 				continue;
 			}
-			tmport = ioportu[host] + 0x10;
+			tmport = dev->ioport + 0x10;
 			outb(0x41, tmport);
 			goto wait_rdyok;
 		}
 		assignid_map |= m;
 
 	}
-	tmport = ioportu[host] + 0x02;
+	tmport = dev->ioport + 0x02;
 	outb(0x7f, tmport);
-	tmport = ioportu[host] + 0x1b;
+	tmport = dev->ioport + 0x1b;
 	outb(0x02, tmport);
 
 	outb(0, 0x80);
 
 	val = 0x0080;		/* bsy  */
-	tmport = ioportu[host] + 0x1c;
+	tmport = dev->ioport + 0x1c;
 	outw(val, tmport);
 	val |= 0x0040;		/* sel  */
 	outw(val, tmport);
@@ -842,7 +964,7 @@
 	if ((inb(tmport) & 0x80) == 0x00) {	/* bsy ? */
 		outw(0, tmport--);
 		outb(0, tmport);
-		tmport = ioportu[host] + 0x15;
+		tmport = dev->ioport + 0x15;
 		outb(0, tmport);
 		tmport += 0x03;
 		outb(0x09, tmport);
@@ -854,11 +976,11 @@
 	}
 	val &= 0x00ff;		/* synchronization  */
 	val |= 0x3f00;
-	fun_scam(host, &val);
+	fun_scam(dev, &val);
 	outb(3, 0x80);
 	val &= 0x00ff;		/* isolation        */
 	val |= 0x2000;
-	fun_scam(host, &val);
+	fun_scam(dev, &val);
 	outb(4, 0x80);
 	i = 8;
 	j = 0;
@@ -869,7 +991,7 @@
 	outb(5, 0x80);
 	val &= 0x00ff;		/* get ID_STRING */
 	val |= 0x2000;
-	k = fun_scam(host, &val);
+	k = fun_scam(dev, &val);
 	if ((k & 0x03) == 0) {
 		goto TCM_5;
 	}
@@ -933,11 +1055,11 @@
 	val &= 0x00ff;		/* AssignID 1stQuintet,AH=001xxxxx  */
 	m = quintet[0] << 8;
 	val |= m;
-	fun_scam(host, &val);
+	fun_scam(dev, &val);
 	val &= 0x00ff;		/* AssignID 2ndQuintet,AH=001xxxxx */
 	m = quintet[1] << 8;
 	val |= m;
-	fun_scam(host, &val);
+	fun_scam(dev, &val);
 
 	goto TCM_SYNC;
 
@@ -955,25 +1077,26 @@
 	static unsigned char synu[6] =	{0x80, 1, 3, 1, 0x0c, 0x0e};
 	static unsigned char synw[6] =	{0x80, 1, 3, 1, 0x0c, 0x07};
 	static unsigned char wide[6] =  {0x80, 1, 2, 3, 1, 0};
+	struct atp_unit *dev = &atp_unit[host];
 
 	sync_idu = 0;
 	tmport = wkport + 0x3a;
 	outb((unsigned char) (inb(tmport) | 0x10), tmport);
 
 	for (i = 0; i < 16; i++) {
-		if ((chip_veru[host] != 4) && (i > 7)) {
+		if ((dev->chip_veru != 4) && (i > 7)) {
 			break;
 		}
 		m = 1;
 		m = m << i;
-		if ((m & active_idu[host]) != 0) {
+		if ((m & dev->active_idu) != 0) {
 			continue;
 		}
-		if (i == host_idu[host]) {
-			printk("         ID: %2d  Host Adapter\n", host_idu[host]);
+		if (i == dev->host_idu) {
+			printk(KERN_INFO "         ID: %2d  Host Adapter\n", dev->host_idu);
 			continue;
 		}
-		if (chip_veru[host] == 4) {
+		if (dev->chip_veru == 4) {
 			tmport = wkport + 0x1b;
 			j = (inb(tmport) & 0x0e) | 0x01;
 			outb(j, tmport);
@@ -990,7 +1113,7 @@
 		tmport += 0x06;
 		outb(0, tmport);
 		tmport += 0x02;
-		outb(devspu[host][i], tmport++);
+		outb(dev->id[i].devspu, tmport++);
 		outb(0, tmport++);
 		outb(satn[6], tmport++);
 		outb(satn[7], tmport++);
@@ -1009,7 +1132,7 @@
 			continue;
 		}
 		while (inb(tmport) != 0x8e);
-		active_idu[host] |= m;
+		dev->active_idu |= m;
 
 		tmport = wkport + 0x10;
 		outb(0x30, tmport);
@@ -1039,7 +1162,7 @@
 		tmport += 0x07;
 		outb(0, tmport);
 		tmport += 0x02;
-		outb(devspu[host][i], tmport++);
+		outb(dev->id[i].devspu, tmport++);
 		outb(0, tmport++);
 		outb(inqd[6], tmport++);
 		outb(inqd[7], tmport++);
@@ -1052,7 +1175,7 @@
 			continue;
 		}
 		while (inb(tmport) != 0x8e);
-		if (chip_veru[host] == 4) {
+		if (dev->chip_veru == 4) {
 			tmport = wkport + 0x1b;
 			j = inb(tmport) & 0x0e;
 			outb(j, tmport);
@@ -1093,16 +1216,16 @@
 		}
 inq_ok:
 		mbuf[36] = 0;
-		printk("         ID: %2d  %s\n", i, &mbuf[8]);
-		devtypeu[host][i] = mbuf[0];
+		printk(KERN_INFO "         ID: %2d  %s\n", i, &mbuf[8]);
+		dev->id[i].devtypeu = mbuf[0];
 		rmb = mbuf[1];
-		if (chip_veru[host] != 4) {
+		if (dev->chip_veru != 4) {
 			goto not_wide;
 		}
 		if ((mbuf[7] & 0x60) == 0) {
 			goto not_wide;
 		}
-		if ((global_map[host] & 0x20) == 0) {
+		if ((dev->global_map & 0x20) == 0) {
 			goto not_wide;
 		}
 		tmport = wkport + 0x1b;
@@ -1118,7 +1241,7 @@
 		tmport += 0x06;
 		outb(0, tmport);
 		tmport += 0x02;
-		outb(devspu[host][i], tmport++);
+		outb(dev->id[i].devspu, tmport++);
 		outb(0, tmport++);
 		outb(satn[6], tmport++);
 		outb(satn[7], tmport++);
@@ -1244,16 +1367,16 @@
 		}
 		m = 1;
 		m = m << i;
-		wide_idu[host] |= m;
+		dev->wide_idu |= m;
 not_wide:
-		if ((devtypeu[host][i] == 0x00) || (devtypeu[host][i] == 0x07)) {
+		if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07)) {
 			goto set_sync;
 		}
 		continue;
 set_sync:
 		tmport = wkport + 0x1b;
 		j = inb(tmport) & 0x0e;
-		if ((m & wide_idu[host]) != 0) {
+		if ((m & dev->wide_idu) != 0) {
 			j |= 0x01;
 		}
 		outb(j, tmport);
@@ -1267,7 +1390,7 @@
 		tmport += 0x06;
 		outb(0, tmport);
 		tmport += 0x02;
-		outb(devspu[host][i], tmport++);
+		outb(dev->id[i].devspu, tmport++);
 		outb(0, tmport++);
 		outb(satn[6], tmport++);
 		outb(satn[7], tmport++);
@@ -1295,10 +1418,10 @@
 				if (rmb != 0) {
 					outb(synn[j++], tmport);
 				} else {
-					if ((m & wide_idu[host]) != 0) {
+					if ((m & dev->wide_idu) != 0) {
 						outb(synw[j++], tmport);
 					} else {
-						if ((m & ultra_map[host]) != 0) {
+						if ((m & dev->ultra_map) != 0) {
 							outb(synu[j++], tmport);
 						} else {
 							outb(synn[j++], tmport);
@@ -1413,7 +1536,7 @@
 		if (mbuf[4] > 0x0c) {
 			mbuf[4] = 0x0c;
 		}
-		devspu[host][i] = mbuf[4];
+		dev->id[i].devspu = mbuf[4];
 		if ((mbuf[3] < 0x0d) && (rmb == 0)) {
 			j = 0xa0;
 			goto set_syn_ok;
@@ -1432,7 +1555,7 @@
 		}
 		j = 0x60;
 	      set_syn_ok:
-		devspu[host][i] = (devspu[host][i] & 0x0f) | j;
+		dev->id[i].devspu = (dev->id[i].devspu & 0x0f) | j;
 	}
 	tmport = wkport + 0x3a;
 	outb((unsigned char) (inb(tmport) & 0xef), tmport);
@@ -1445,124 +1568,123 @@
 	unsigned long flags;
 	unsigned int base_io, error, tmport;
 	unsigned short index = 0;
-	unsigned char pci_bus[3], pci_device_fn[3], chip_ver[3], host_id;
+	struct pci_dev *pdev[3];
+	unsigned char chip_ver[3], host_id;
 	struct Scsi_Host *shpnt = NULL;
+	int tmpcnt = 0;
 	int count = 0;
-	static unsigned short devid[7] =
-	{0x8002, 0x8010, 0x8020, 0x8030, 0x8040, 0x8050, 0};
-	static struct pci_dev *pdev = NULL, *acard_pdev[3];
+	int result;
+	
+	static unsigned short devid[7] = {
+		0x8002, 0x8010, 0x8020, 0x8030, 0x8040, 0x8050, 0
+	};
 
-	printk("aec671x_detect: \n");
+	printk(KERN_INFO "aec671x_detect: \n");
 	if (!pci_present()) {
-		printk("   NO BIOS32 SUPPORT.\n");
+		printk(KERN_INFO"   NO PCI SUPPORT.\n");
 		return count;
 	}
-	tpnt->proc_dir = &proc_scsi_atp870u;
 
 	for (h = 0; h < 2; h++) {
-		active_idu[h] = 0;
-		wide_idu[h] = 0;
-		host_idu[h] = 0x07;
-		quhdu[h] = 0;
-		quendu[h] = 0;
-		pci_bus[h] = 0;
-		pci_device_fn[h] = 0xff;
-		chip_ver[h] = 0;
-		last_cmd[h] = 0xff;
-		in_snd[h] = 0;
-		in_int[h] = 0;
+		struct atp_unit *dev = &atp_unit[h];
+		for(k=0;k<16;k++)
+		{
+			dev->id[k].prd_tableu = kmalloc(1024, GFP_KERNEL);
+			dev->id[k].devspu=0x20;
+			dev->id[k].devtypeu = 0;
+			dev->id[k].curr_req = NULL;
+		}
+		dev->active_idu = 0;
+		dev->wide_idu = 0;
+		dev->host_idu = 0x07;
+		dev->quhdu = 0;
+		dev->quendu = 0;
+		pdev[h]=NULL;
+		pdev[2]=NULL;
+		dev->chip_veru = 0;
+		dev->last_cmd = 0xff;
+		dev->in_snd = 0;
+		dev->in_int = 0;
 		for (k = 0; k < qcnt; k++) {
-			querequ[h][k] = 0;
+			dev->querequ[k] = 0;
 		}
 		for (k = 0; k < 16; k++) {
-			curr_req[h][k] = 0;
+			dev->id[k].curr_req = 0;
 		}
 	}
 	h = 0;
 	while (devid[h] != 0) {
-		pdev = pci_find_device(0x1191, devid[h], pdev);
-		if (pdev == NULL) {
+		pdev[2] = pci_find_device(0x1191, devid[h], pdev[2]);
+		if (pdev[2] == NULL) {
 			h++;
 			index = 0;
 			continue;
 		}
 		chip_ver[2] = 0;
 
-		/* To avoid messing with the things below...  */
-		acard_pdev[2] = pdev;
-		pci_device_fn[2] = pdev->devfn;
-		pci_bus[2] = pdev->bus->number;
-
 		if (devid[h] == 0x8002) {
-			error = pci_read_config_byte(pdev, 0x08, &chip_ver[2]);
+			error = pci_read_config_byte(pdev[2], 0x08, &chip_ver[2]);
 			if (chip_ver[2] < 2) {
 				goto nxt_devfn;
 			}
 		}
-		if (devid[h] == 0x8010) {
+		if (devid[h] == 0x8010 || devid[h] == 0x8050) {
 			chip_ver[2] = 0x04;
 		}
-		if (pci_device_fn[2] < pci_device_fn[0]) {
-			acard_pdev[1] = acard_pdev[0];
-			pci_bus[1] = pci_bus[0];
-			pci_device_fn[1] = pci_device_fn[0];
-			chip_ver[1] = chip_ver[0];
-			acard_pdev[0] = acard_pdev[2];
-			pci_bus[0] = pci_bus[2];
-			pci_device_fn[0] = pci_device_fn[2];
-			chip_ver[0] = chip_ver[2];
-		} else if (pci_device_fn[2] < pci_device_fn[1]) {
-			acard_pdev[1] = acard_pdev[2];
-			pci_bus[1] = pci_bus[2];
-			pci_device_fn[1] = pci_device_fn[2];
-			chip_ver[1] = chip_ver[2];
-		}
+		pdev[tmpcnt] = pdev[2];
+		chip_ver[tmpcnt] = chip_ver[2];
+		tmpcnt++;
 	      nxt_devfn:
 		index++;
 		if (index > 3) {
 			index = 0;
 			h++;
 		}
+		if(tmpcnt>1)
+			break;
 	}
 	for (h = 0; h < 2; h++) {
-		if (pci_device_fn[h] == 0xff) {
+		struct atp_unit *dev=&atp_unit[h];
+		if (pdev[h]==NULL) {
 			return count;
 		}
-		pdev = acard_pdev[h];
-		pdev->devfn = pci_device_fn[h];
-		pdev->bus->number = pci_bus[h];
 
 		/* Found an atp870u/w. */
-		error = pci_read_config_dword(pdev, 0x10, &base_io);
-		error += pci_read_config_byte(pdev, 0x3c, &irq);
-		error += pci_read_config_byte(pdev, 0x49, &host_id);
+		base_io = pdev[h]->base_address[0];
+		irq = pdev[h]->irq;
+		error = pci_read_config_byte(pdev[h],0x49,&host_id);
 
 		base_io &= 0xfffffff8;
-		printk("   ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d    IO:%x, IRQ:%d.\n"
+
+		if (check_region(base_io,0x40) != 0)
+		{  
+			return 0;
+		}
+		printk(KERN_INFO "   ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d    IO:%x, IRQ:%d.\n"
 		       ,h, base_io, irq);
-		ioportu[h] = base_io;
-		pciportu[h] = base_io + 0x20;
+		dev->ioport = base_io;
+		dev->pciport = base_io + 0x20;
 		irqnumu[h] = irq;
 		host_id &= 0x07;
-		host_idu[h] = host_id;
-		chip_veru[h] = chip_ver[h];
+		dev->host_idu = host_id;
+		dev->chip_veru = chip_ver[h];
 
 		tmport = base_io + 0x22;
-		scam_on[h] = inb(tmport);
+		dev->scam_on = inb(tmport);
 		tmport += 0x0b;
-		global_map[h] = inb(tmport++);
-		ultra_map[h] = inw(tmport);
-		if (ultra_map[h] == 0) {
-			scam_on[h] = 0x00;
-			global_map[h] = 0x20;
-			ultra_map[h] = 0xffff;
+		dev->global_map = inb(tmport++);
+		dev->ultra_map = inw(tmport);
+		if (dev->ultra_map == 0) {
+			dev->scam_on = 0x00;
+			dev->global_map = 0x20;
+			dev->ultra_map = 0xffff;
 		}
 		shpnt = scsi_register(tpnt, 4);
 
 		save_flags(flags);
 		cli();
-		if (request_irq(irq, atp870u_intr_handle, 0, "atp870u", NULL)) {
-			printk("Unable to allocate IRQ for Acard controller.\n");
+		if (request_irq(irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", dev)) {
+			printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n");
 			goto unregister;
 		}
 		tmport = base_io + 0x3a;
@@ -1590,9 +1712,11 @@
 		is870(h, base_io);
 		tmport = base_io + 0x3a;
 		outb((inb(tmport) & 0xef), tmport);
+		tmport++;
+		outb((inb(tmport) | 0x20),tmport);
 
 		atp_host[h] = shpnt;
-		if (chip_ver[h] == 4) {
+		if (dev->chip_veru == 4) {
 			shpnt->max_id = 16;
 		}
 		shpnt->this_id = host_id;
@@ -1623,7 +1747,7 @@
 {
 	unsigned char h, j;
 	unsigned int tmport;
-/*    printk(" atp870u_abort: \n");   */
+	struct atp_unit *dev;
 	for (h = 0; h <= admaxu; h++) {
 		if (SCpnt->host == atp_host[h]) {
 			goto find_adp;
@@ -1631,20 +1755,23 @@
 	}
 	panic("Abort host not found !");
 find_adp:
-	printk(" workingu=%x last_cmd=%x ", workingu[h], last_cmd[h]);
-	printk(" quhdu=%x quendu=%x ", quhdu[h], quendu[h]);
-	tmport = ioportu[h];
+	dev=&atp_unit[h];
+	printk(KERN_DEBUG "working=%x last_cmd=%x ", dev->working, dev->last_cmd);
+	printk(" quhdu=%x quendu=%x ", dev->quhdu, dev->quendu);
+	tmport = dev->ioport;
 	for (j = 0; j < 0x17; j++) {
 		printk(" r%2x=%2x", j, inb(tmport++));
 	}
 	tmport += 0x05;
 	printk(" r1c=%2x", inb(tmport));
 	tmport += 0x03;
-	printk(" r1f=%2x in_snd=%2x ", inb(tmport), in_snd[h]);
+	printk(" r1f=%2x in_snd=%2x ", inb(tmport), dev->in_snd);
 	tmport++;
 	printk(" r20=%2x", inb(tmport));
 	tmport += 0x02;
-	printk(" r22=%2x \n", inb(tmport));
+	printk(" r22=%2x", inb(tmport));
+	tmport += 0x18;
+	printk(" r3a=%2x \n",inb(tmport));
 	return (SCSI_ABORT_SNOOZE);
 }
 
@@ -1654,7 +1781,6 @@
 	/*
 	 * See if a bus reset was suggested.
 	 */
-/*	printk("atp870u_reset: \n");    */
 	for (h = 0; h <= admaxu; h++) {
 		if (SCpnt->host == atp_host[h]) {
 			goto find_host;
@@ -1664,9 +1790,9 @@
 find_host:
 /*      SCpnt->result = 0x00080000;
 	SCpnt->scsi_done(SCpnt);
-	workingu[h]=0;
-	quhdu[h]=0;
-	quendu[h]=0;
+	dev->working=0;
+	dev->quhdu=0;
+	dev->quendu=0;
 	return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET);  */
 	return (SCSI_RESET_SNOOZE);
 }
@@ -1675,14 +1801,14 @@
 {
 	static char buffer[128];
 
-	strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V1.0 ");
+	strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V2.0+ac ");
 
 	return buffer;
 }
 
 int atp870u_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
 {
-	return (-ENOSYS);	/* Currently this is a no-op */
+	return -ENOSYS;		/* Currently this is a no-op */
 }
 
 #define BLS buffer + len + size
@@ -1720,7 +1846,7 @@
 	if (offset == 0) {
 		memset(buff, 0, sizeof(buff));
 	}
-	size += sprintf(BLS, "ACARD AEC-671X Driver Version: 1.0\n");
+	size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.0+ac\n");
 	len += size;
 	pos = begin + len;
 	size = 0;
@@ -1733,7 +1859,7 @@
 	pos = begin + len;
 	size = 0;
 
-      stop_output:
+stop_output:
 	*start = buffer + (offset - begin);	/* Start of wanted data */
 	len -= (offset - begin);	/* Start slop */
 	if (len > length) {
@@ -1762,6 +1888,26 @@
 	ip[2] = cylinders;
 
 	return 0;
+}
+
+
+int atp870u_release (struct Scsi_Host *pshost)
+{
+	int h;
+	for (h = 0; h <= admaxu; h++) 
+	{
+		if (pshost == atp_host[h]) {
+			int k;
+			free_irq (pshost->irq, &atp_unit[h]);
+			release_region (pshost->io_port, pshost->n_io_port);
+			scsi_unregister(pshost);
+			for(k=0;k<16;k++)
+				kfree(atp_unit[h].id[k].prd_tableu);
+			return 0;
+		}
+	}
+	panic("atp870u: bad scsi host passed.\n");
+		
 }
 
 #ifdef MODULE
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/atp870u.h linux.14p16/drivers/scsi/atp870u.h
--- linux.vanilla/drivers/scsi/atp870u.h	Wed Oct 20 01:12:41 1999
+++ linux.14p16/drivers/scsi/atp870u.h	Mon Dec 13 19:37:53 1999
@@ -24,49 +24,50 @@
 int atp870u_abort(Scsi_Cmnd *);
 int atp870u_reset(Scsi_Cmnd *, unsigned int);
 int atp870u_biosparam(Disk *, kdev_t, int *);
+int atp870u_release(struct Scsi_Host *);
 void send_s870(unsigned char);
 
-#define qcnt            32
-#define ATP870U_SCATTER 127
+#define qcnt		32
+#define ATP870U_SCATTER 128
 #define ATP870U_CMDLUN 1
 
 #ifndef NULL
 #define NULL 0
 #endif
 
-extern struct proc_dir_entry proc_scsi_atp870u;
-
 extern const char *atp870u_info(struct Scsi_Host *);
 
 extern int atp870u_proc_info(char *, char **, off_t, int, int, int);
+extern struct proc_dir_entry proc_scsi_atp870u;
 
-#define ATP870U {  						\
-	next:				NULL, 			\
-	module:				NULL, 			\
+#define ATP870U {						\
+	next: NULL,						\
+	module: NULL,						\
 	proc_dir:			&proc_scsi_atp870u,	\
-	proc_info:			atp870u_proc_info,      \
-	name:				NULL,			\
-	detect:                 	atp870u_detect,		\
-	release:               	 	NULL,                   \
-	info:                   	atp870u_info,           \
-	command:                	atp870u_command,	\
-        queuecommand:           	atp870u_queuecommand,	\
-        eh_strategy_handler: 		NULL,			\
-        eh_abort_handler: 		NULL,			\
-        eh_device_reset_handler:	NULL,			\
-        eh_bus_reset_handler:		NULL,			\
-        eh_host_reset_handler:		NULL,			\
-	abort:				atp870u_abort,          \
-	reset:				atp870u_reset,       	\
-	slave_attach:               	NULL,                   \
-	bios_param:                     atp870u_biosparam,	\
-	can_queue:                     	qcnt,                   \
-	this_id:                     	1,			\
-	sg_tablesize:                   ATP870U_SCATTER,        \
-	cmd_per_lun:                    ATP870U_CMDLUN,         \
-	present:                     	0,                      \
-	unchecked_isa_dma:              0,                      \
-	use_clustering:                 ENABLE_CLUSTERING,	\
-	use_new_eh_code:		0			\
+	proc_info: atp870u_proc_info,				\
+	name: NULL,						\
+	detect: atp870u_detect, 				\
+	release: atp870u_release,				\
+	info: atp870u_info,					\
+	command: atp870u_command,				\
+	queuecommand: atp870u_queuecommand,			\
+	eh_strategy_handler: NULL,				\
+	eh_abort_handler: NULL, 				\
+	eh_device_reset_handler: NULL,				\
+	eh_bus_reset_handler: NULL,				\
+	eh_host_reset_handler: NULL,				\
+	abort: atp870u_abort,					\
+	reset: atp870u_reset,					\
+	slave_attach: NULL,					\
+	bios_param: atp870u_biosparam,				\
+	can_queue: qcnt,	 /* max simultaneous cmds      */\
+	this_id: 7,	       /* scsi id of host adapter    */\
+	sg_tablesize: ATP870U_SCATTER,	/* max scatter-gather cmds    */\
+	cmd_per_lun: ATP870U_CMDLUN,	/* cmds per lun (linked cmds) */\
+	present: 0,		/* number of 7xxx's present   */\
+	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
+	use_clustering: ENABLE_CLUSTERING,			\
+	use_new_eh_code: 0					\
 }
+
 #endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/eata.c linux.14p16/drivers/scsi/eata.c
--- linux.vanilla/drivers/scsi/eata.c	Wed Oct 20 01:12:41 1999
+++ linux.14p16/drivers/scsi/eata.c	Thu Dec  9 15:33:50 1999
@@ -1,6 +1,13 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
+ *      16 Sep 1999 Rev. 5.11 for linux 2.2.12 and 2.3.18
+ *        + Updated to the new __setup interface for boot command line options.
+ *        + When loaded as a module, accepts the new parameter boot_options
+ *          which value is a string with the same format of the kernel boot
+ *          command line options. A valid example is:
+ *          modprobe eata 'boot_options=\"0x7410,0x230,lc:y,tc:n,mq:4\"'
+ *
  *       9 Sep 1999 Rev. 5.10 for linux 2.2.12 and 2.3.17
  *        + 64bit cleanup for Linux/Alpha platform support
  *          (contribution from H.J. Lu).
@@ -368,6 +375,7 @@
 #if defined(MODULE)
 #include <linux/module.h>
 
+MODULE_PARM(boot_options, "s");
 MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i");
 MODULE_PARM(linked_comm, "i");
 MODULE_PARM(tagged_comm, "i");
@@ -401,7 +409,13 @@
 #include <linux/config.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/ctype.h>
+
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)
 #include <asm/spinlock.h>
+#else
+#include <linux/spinlock.h>
+#endif
 
 #define SPIN_FLAGS unsigned long spin_flags;
 #define SPIN_LOCK spin_lock_irq(&io_request_lock);
@@ -410,8 +424,6 @@
 #define SPIN_UNLOCK_RESTORE \
                   spin_unlock_irqrestore(&io_request_lock, spin_flags);
 
-static int use_new_eh_code = TRUE;
-
 struct proc_dir_entry proc_scsi_eata2x = {
     PROC_SCSI_EATA2X, 6, "eata2x",
     S_IFDIR | S_IRUGO | S_IXUGO, 2
@@ -494,7 +506,7 @@
 #define ASOK              0x00
 #define ASST              0x01
 
-#if !defined(ARRAY_SIZE)
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)
 #define ARRAY_SIZE(x) (sizeof (x) / sizeof((x)[0]))
 #endif
 
@@ -646,7 +658,7 @@
 /* Initialize num_boards so that ihdlr can work while detect is in progress */
 static unsigned int num_boards = MAX_BOARDS;
 
-static unsigned long io_port[] __initdata = {
+static unsigned long io_port[] = {
 
    /* Space for MAX_INT_PARAM ports usable while loading as a module */
    SKIP,    SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,
@@ -686,6 +698,8 @@
 static int tag_mode = TAG_MIXED;
 static int ext_tran = FALSE;
 static int rev_scan = TRUE;
+static int use_new_eh_code = TRUE;
+static char *boot_options = NULL;
 
 #if defined(CONFIG_SCSI_EATA_TAGGED_QUEUE)
 static int tagged_comm = TRUE;
@@ -820,12 +834,6 @@
 
       if (!(dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) break;
 
-#if 0
-      /* Don't bother if PCI vendor and/or device don't match. */
-      if (dev->vendor != PCI_VENDOR_ID_DPT || dev->device != PCI_DEVICE_ID_DPT)
-		continue;
-#endif
-
       if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue;
 
 #if defined(DEBUG_PCI_DETECT)
@@ -857,12 +865,6 @@
 
    while((dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) {
 
-#if 0
-      /* Don't bother if PCI vendor and/or device don't match. */
-      if (dev->vendor != PCI_VENDOR_ID_DPT || dev->device != PCI_DEVICE_ID_DPT)
-		continue;
-#endif
-
       if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue;
 
 #if defined(DEBUG_PCI_DETECT)
@@ -913,7 +915,7 @@
    if (info.sign != EATA_SIGNATURE) return FALSE;
 
    if (DEV2H(info.data_len) < EATA_2_0A_SIZE) {
-      printk("%s: config structure size (%d bytes) too short, detaching.\n",
+      printk("%s: config structure size (%ld bytes) too short, detaching.\n",
              name, DEV2H(info.data_len));
       return FALSE;
       }
@@ -1166,7 +1168,7 @@
    return TRUE;
 }
 
-void eata2x_setup(char *str, int *ints) {
+static void internal_setup(char *str, int *ints) {
    int i, argc = ints[0];
    char *cur = str, *pc;
 
@@ -1202,6 +1204,22 @@
    return;
 }
 
+static int option_setup(char *str) {
+   int ints[MAX_INT_PARAM];
+   char *cur = str;
+   int i = 1;
+
+   while (cur && isdigit(*cur) && i <= MAX_INT_PARAM) {
+      ints[i++] = simple_strtoul(cur, NULL, 0);
+
+      if ((cur = strchr(cur, ',')) != NULL) cur++;
+   }
+
+   ints[0] = i - 1;
+   internal_setup(cur, ints);
+   return 0;
+}
+
 static void add_pci_ports(void) {
 
 #if defined(CONFIG_PCI)
@@ -1216,12 +1234,6 @@
 
       if (!(dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) break;
 
-#if 0
-      /* Don't bother if PCI vendor and/or device don't match. */
-      if (dev->vendor != PCI_VENDOR_ID_DPT || dev->device != PCI_DEVICE_ID_DPT)
-		continue;
-#endif
-
       if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue;
 
 #if defined(DEBUG_PCI_DETECT)
@@ -1247,6 +1259,8 @@
 
    tpnt->proc_dir = &proc_scsi_eata2x;
 
+   if(boot_options) option_setup(boot_options);
+
 #if defined(MODULE)
    /* io_port could have been modified when loading as a module */
    if(io_port[0] != SKIP) {
@@ -2281,4 +2295,15 @@
 Scsi_Host_Template driver_template = EATA;
 
 #include "scsi_module.c"
+
+#else
+
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)
+void eata2x_setup(char *str, int *ints) {
+   internal_setup(str, ints);
+}
+#else
+__setup("eata=", option_setup);
 #endif
+
+#endif /* end MODULE */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/eata.h linux.14p16/drivers/scsi/eata.h
--- linux.vanilla/drivers/scsi/eata.h	Wed Oct 20 01:12:41 1999
+++ linux.14p16/drivers/scsi/eata.h	Tue Dec 21 00:51:22 1999
@@ -16,9 +16,7 @@
 int eata2x_old_reset(Scsi_Cmnd *, unsigned int);
 int eata2x_biosparam(Disk *, kdev_t, int *);
 
-#define EATA_VERSION "5.10.00"
-
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+#define EATA_VERSION "5.11.01"
 
 #define EATA {                                                               \
                 name:              "EATA/DMA 2.0x rev. " EATA_VERSION " ",   \
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/esp.c linux.14p16/drivers/scsi/esp.c
--- linux.vanilla/drivers/scsi/esp.c	Wed Oct 20 01:12:41 1999
+++ linux.14p16/drivers/scsi/esp.c	Thu Dec  9 15:33:53 1999
@@ -1519,8 +1519,11 @@
 		 */
 		if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
 		   (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
-			/* But we are nice and allow tapes to disconnect. */
-			if(SDptr->type == TYPE_TAPE)
+			/* But we are nice and allow tapes and removable
+			 * disks (but not CDROMs) to disconnect.
+			 */
+			if(SDptr->type == TYPE_TAPE ||
+			   (SDptr->type != TYPE_ROM && SDptr->removable))
 				SDptr->disconnect = 1;
 			else
 				SDptr->disconnect = 0;
@@ -1538,7 +1541,8 @@
 		 */
 		if(esp->erev == fashme && !SDptr->wide) {
 			if(!SDptr->borken &&
-			   SDptr->type != TYPE_ROM) {
+			   SDptr->type != TYPE_ROM &&
+			   SDptr->removable == 0) {
 				build_wide_nego_msg(esp, 16);
 				SDptr->wide = 1;
 				esp->wnip = 1;
@@ -1556,6 +1560,11 @@
 					 "CDROM.\n", esp->esp_id));
 				cdrom_hwbug_wkaround = 1;
 				build_sync_nego_msg(esp, 0, 0);
+			} else if (SDptr->removable != 0) {
+				ESPMISC(("esp%d: Not negotiating sync/wide but "
+					 "allowing disconnect for removable media.\n",
+					 esp->esp_id));
+				build_sync_nego_msg(esp, 0, 0);
 			} else {
 				build_sync_nego_msg(esp, esp->sync_defp, 15);
 			}
@@ -1589,7 +1598,9 @@
 		 *           Therefore _no_ disconnects for SCSI1 targets
 		 *           thank you very much. ;-)
 		 */
-		if(((SDptr->scsi_level < 3) && (SDptr->type != TYPE_TAPE)) ||
+		if(((SDptr->scsi_level < 3) &&
+		    (SDptr->type != TYPE_TAPE) &&
+		    SDptr->removable == 0) ||
 		   cdrom_hwbug_wkaround || SDptr->borken) {
 			ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
 				 "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun));
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/fdomain.c linux.14p16/drivers/scsi/fdomain.c
--- linux.vanilla/drivers/scsi/fdomain.c	Tue Dec 29 19:44:53 1998
+++ linux.14p16/drivers/scsi/fdomain.c	Thu Dec  9 15:33:50 1999
@@ -875,6 +875,8 @@
    int              retcode;
    struct Scsi_Host *shpnt;
 #if DO_DETECT
+   int i = 0;
+   int j = 0;
    const int        buflen = 255;
    Scsi_Cmnd        SCinit;
    unsigned char    do_inquiry[] =       { INQUIRY, 0, 0, 0, buflen, 0 };
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/g_NCR5380.c linux.14p16/drivers/scsi/g_NCR5380.c
--- linux.vanilla/drivers/scsi/g_NCR5380.c	Wed Oct 20 01:12:41 1999
+++ linux.14p16/drivers/scsi/g_NCR5380.c	Thu Dec  9 15:33:51 1999
@@ -499,7 +499,7 @@
 	    dst[start+i] = NCR5380_read(C400_HOST_BUFFER);
 #else
 	/* implies CONFIG_SCSI_G_NCR5380_MEM */
-	memcpy(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
+	memcpy_fromio(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
 #endif
 	start+=128;
 	blocks--;
@@ -520,7 +520,7 @@
 	    dst[start+i] = NCR5380_read(C400_HOST_BUFFER);
 #else
 	/* implies CONFIG_SCSI_G_NCR5380_MEM */
-	memcpy(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
+	memcpy_fromio(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
 #endif
 	start+=128;
 	blocks--;
@@ -607,7 +607,7 @@
 	    NCR5380_write(C400_HOST_BUFFER, src[start+i]);
 #else
 	/* implies CONFIG_SCSI_G_NCR5380_MEM */
-	memcpy(NCR53C400_host_buffer+NCR5380_map_name,src+start,128);
+	memcpy_toio(NCR53C400_host_buffer+NCR5380_map_name,src+start,128);
 #endif
 	start+=128;
 	blocks--;
@@ -627,7 +627,7 @@
 	    NCR5380_write(C400_HOST_BUFFER, src[start+i]);
 #else
 	/* implies CONFIG_SCSI_G_NCR5380_MEM */
-	memcpy(NCR53C400_host_buffer+NCR5380_map_name,src+start,128);
+	memcpy_toio(NCR53C400_host_buffer+NCR5380_map_name,src+start,128);
 #endif
 	start+=128;
 	blocks--;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/gdth.c linux.14p16/drivers/scsi/gdth.c
--- linux.vanilla/drivers/scsi/gdth.c	Sat Aug 14 02:25:41 1999
+++ linux.14p16/drivers/scsi/gdth.c	Mon Dec 13 18:31:47 1999
@@ -20,9 +20,32 @@
  * along with this kernel; if not, write to the Free Software           *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
  *                                                                      *
- * Tested with Linux 1.2.13, ..., 2.2.4                                 *
+ * Tested with Linux 1.2.13, ..., 2.2.12                                *
  *                                                                      *
  * $Log: gdth.c,v $
+ * Revision 1.30  1999/11/02 13:42:39  achim
+ * ARRAY_DRV_LIST2 implemented
+ * Now 255 log. and 100 host drives supported
+ *
+ * Revision 1.29  1999/10/05 13:28:47  achim
+ * GDT_CLUST_RESET added
+ *
+ * Revision 1.28  1999/08/12 13:44:54  achim
+ * MOUNTALL removed
+ * Cluster drives -> removeable drives
+ *
+ * Revision 1.27  1999/06/22 07:22:38  achim
+ * Small changes
+ *
+ * Revision 1.26  1999/06/10 16:09:12  achim
+ * Cluster Host Drive support: Bugfixes
+ *
+ * Revision 1.25  1999/06/01 16:03:56  achim
+ * gdth_init_pci(): Manipulate config. space to start RP controller
+ *
+ * Revision 1.24  1999/05/26 11:53:06  achim
+ * Cluster Host Drive support added
+ *
  * Revision 1.23  1999/03/26 09:12:31  achim
  * Default value for hdr_channel set to 0
  *
@@ -120,7 +143,7 @@
  * Initial revision
  *
  ************************************************************************/
-#ident "$Id: gdth.c,v 1.23 1999/03/26 09:12:31 achim Exp $" 
+#ident "$Id: gdth.c,v 1.30 1999/11/02 13:42:39 achim Exp $" 
 
 /* All GDT Disk Array Controllers are fully supported by this driver.
  * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the
@@ -581,18 +604,18 @@
 {
     *cyls = size /HEADS/SECS;
     if (*cyls <= MAXCYLS) {
-	*heads = HEADS;
-	*secs = SECS;
-    } else {                            		/* too high for 64*32 */
-	*cyls = size /MEDHEADS/MEDSECS;
-	if (*cyls <= MAXCYLS) {
-	    *heads = MEDHEADS;
-	    *secs = MEDSECS;
-	} else {                        		/* too high for 127*63 */
-	    *cyls = size /BIGHEADS/BIGSECS;
-	    *heads = BIGHEADS;
-	    *secs = BIGSECS;
-	}
+        *heads = HEADS;
+        *secs = SECS;
+    } else {                                        /* too high for 64*32 */
+        *cyls = size /MEDHEADS/MEDSECS;
+        if (*cyls <= MAXCYLS) {
+            *heads = MEDHEADS;
+            *secs = MEDSECS;
+        } else {                                    /* too high for 127*63 */
+            *cyls = size /BIGHEADS/BIGSECS;
+            *heads = BIGHEADS;
+            *secs = BIGSECS;
+        }
     }
 }
 
@@ -686,7 +709,7 @@
             }
             TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%x\n",
                     pcistr[cnt].bus, PCI_SLOT(pcistr[cnt].device_fn), 
-                    pcistr[cnt].irq, pcistr[cnt].dpmem));
+                    pcistr[cnt].irq, (int)pcistr[cnt].dpmem));
             cnt++;
         }       
 #else   
@@ -981,7 +1004,11 @@
     register gdt6m_dpram_str *dp6m_ptr;
     ulong32 retries;
     unchar prot_ver;
+    ushort command;
     int i, found = FALSE;
+#if LINUX_VERSION_CODE < 0x2015C
+    int rom_addr;
+#endif
 
     TRACE(("gdth_init_pci()\n"));
 
@@ -1137,6 +1164,36 @@
             return 0;
         }
 
+        /* manipulate config. space to enable DPMEM, start RP controller */
+#if LINUX_VERSION_CODE >= 0x2015C
+        pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command);
+        command |= 6;
+        pci_write_config_word(pcistr->pdev, PCI_COMMAND, command);
+        if (pcistr->pdev->rom_address == 1UL)
+            pcistr->pdev->rom_address = 0UL;
+        i = 0xFEFF0001UL;
+        pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS, i);
+        gdth_delay(1);
+        pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS,
+                               pcistr->pdev->rom_address);
+#else
+        pcibios_read_config_word(pcistr->bus, pcistr->device_fn,
+                                 PCI_COMMAND, &command);
+        command |= 6;
+        pcibios_write_config_word(pcistr->bus, pcistr->device_fn, 
+                                  PCI_COMMAND, command);
+        pcibios_read_config_dword(pcistr->bus, pcistr->device_fn,
+                                  PCI_ROM_ADDRESS, &rom_addr);
+        if (rom_addr == 1UL)
+            rom_addr = 0UL;
+        i = 0xFEFF0001UL;
+        pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
+                                   PCI_ROM_ADDRESS, i);
+        gdth_delay(1);
+        pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
+                                   PCI_ROM_ADDRESS, rom_addr);
+#endif
+	
         /* check and reset interface area */
         dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
         gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u);
@@ -1585,7 +1642,8 @@
     gdth_drlist_str *drl;
     gdth_iochan_str *ioc;
     gdth_raw_iochan_str *iocr;
-    gdth_arraylist_str *alst;
+    gdth_arcdl_str *alst;
+    gdth_alist_str *alst2;
         
     TRACE(("gdth_search_drives() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
@@ -1607,19 +1665,6 @@
     TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n"));
     cdev_cnt = (ushort)ha->info;
 
-    /* mount all cache devices */
-    gdth_internal_cmd(hanum,CACHESERVICE,GDT_MOUNT,0xffff,1,0);
-    TRACE2(("gdth_search_drives(): mountall CACHESERVICE OK\n"));
-
-    /* initialize cache service after mountall */
-    if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) {
-        printk("GDT: Initialization error cache service (code %d)\n",
-               ha->status);
-        return 0;
-    }
-    TRACE2(("gdth_search_drives() CACHES. init. after mountall\n"));
-    cdev_cnt = (ushort)ha->info;
-
     /* detect number of buses - try new IOCTL */
     iocr = (gdth_raw_iochan_str *)ha->pscratch;
     iocr->hdr.version        = 0xffffffff;
@@ -1747,22 +1792,37 @@
                                   INVALID_CHANNEL,drv_cnt * sizeof(ulong32))) {
                 for (j = 0; j < drv_cnt; ++j) {
                     drv_no = ((ulong32 *)ha->pscratch)[j];
-                    if (drv_no < MAX_HDRIVES) {
+                    if (drv_no < MAX_LDRIVES) {
                         ha->hdr[drv_no].is_logdrv = TRUE;
                         TRACE2(("Drive %d is log. drive\n",drv_no));
                     }
                 }
             }
+	    alst = (gdth_arcdl_str *)ha->pscratch;
+	    alst->entries_avail = MAX_LDRIVES;
+	    alst->first_entry = 0;
+	    alst->list_offset = GDTOFFSOF(gdth_arcdl_str, list[0]);
             if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
-                                  ARRAY_DRV_LIST | LA_CTRL_PATTERN,
-                                  0, 35 * sizeof(gdth_arraylist_str))) {
+                                  ARRAY_DRV_LIST2 | LA_CTRL_PATTERN, 
+                                  INVALID_CHANNEL, sizeof(gdth_arcdl_str) +
+				  (alst->entries_avail-1) * sizeof(gdth_alist_str))) { 
+                for (j = 0; j < alst->entries_init; ++j) {
+                    ha->hdr[j].is_arraydrv = alst->list[j].is_arrayd;
+                    ha->hdr[j].is_master = alst->list[j].is_master;
+                    ha->hdr[j].is_parity = alst->list[j].is_parity;
+                    ha->hdr[j].is_hotfix = alst->list[j].is_hotfix;
+                    ha->hdr[j].master_no = alst->list[j].cd_handle;
+                }
+	    } else if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+					 ARRAY_DRV_LIST | LA_CTRL_PATTERN,
+					 0, 35 * sizeof(gdth_alist_str))) {
                 for (j = 0; j < 35; ++j) {
-                    alst = &((gdth_arraylist_str *)ha->pscratch)[j];
-                    ha->hdr[j].is_arraydrv = alst->is_arrayd;
-                    ha->hdr[j].is_master = alst->is_master;
-                    ha->hdr[j].is_parity = alst->is_parity;
-                    ha->hdr[j].is_hotfix = alst->is_hotfix;
-                    ha->hdr[j].master_no = alst->cd_handle;
+                    alst2 = &((gdth_alist_str *)ha->pscratch)[j];
+                    ha->hdr[j].is_arraydrv = alst2->is_arrayd;
+                    ha->hdr[j].is_master = alst2->is_master;
+                    ha->hdr[j].is_parity = alst2->is_parity;
+                    ha->hdr[j].is_hotfix = alst2->is_hotfix;
+                    ha->hdr[j].master_no = alst2->cd_handle;
                 }
             }
         }
@@ -1825,17 +1885,13 @@
     for (i=0; i<cdev_cnt && i<MAX_HDRIVES; ++i) {
         TRACE(("gdth_search_drives() cachedev. %d\n",i));
         if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_INFO,i,0,0)) {
-            /* static relation between host drive number and Bus/ID */
-            TRACE(("gdth_search_dr() drive %d mapped to bus/id %d/%d\n",
-                   i,ha->bus_cnt,i));
-
             ha->hdr[i].present = TRUE;
             ha->hdr[i].size = ha->info;
 
             /* evaluate mapping (sectors per head, heads per cylinder) */
             ha->hdr[i].size &= ~SECS32;
             if (ha->info2 == 0) {
-		gdth_eval_mapping(ha->hdr[i].size,&drv_cyls,&drv_hds,&drv_secs);
+                gdth_eval_mapping(ha->hdr[i].size,&drv_cyls,&drv_hds,&drv_secs);
             } else {
                 drv_hds = ha->info2 & 0xff;
                 drv_secs = (ha->info2 >> 8) & 0xff;
@@ -1851,10 +1907,30 @@
             /* get informations about device */
             if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,i,
                                   0,0)) {
-                TRACE(("gdth_search_dr() cache drive %d devtype %d\n",
+                TRACE2(("gdth_search_dr() cache drive %d devtype %d\n",
                        i,ha->info));
                 ha->hdr[i].devtype = (ushort)ha->info;
             }
+
+            /* cluster info */
+            if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_CLUST_INFO,i,
+                                  0,0)) {
+                TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n",
+                       i,ha->info));
+                ha->hdr[i].cluster_type = (unchar)ha->info;
+            } else {
+                ha->hdr[i].cluster_type = 0;
+            }           
+
+            /* R/W attributes */
+            if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_RW_ATTRIBS,i,
+                                  0,0)) {
+                TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n",
+                       i,ha->info));
+                ha->hdr[i].rw_attribs = (unchar)ha->info;
+            } else {
+                ha->hdr[i].rw_attribs = 0;
+            }           
         }
     }
 
@@ -1969,11 +2045,11 @@
         }
 
 #if LINUX_VERSION_CODE >= 0x010300
-        if (nscp->done != gdth_scsi_done) 
+        if (nscp->done != gdth_scsi_done || nscp->cmnd[0] != 0xff) 
 #endif
         {
         if (nscp->SCp.phase == -1) {
-            nscp->SCp.phase = SCSIRAWSERVICE;           /* default: raw svc. */ 
+            nscp->SCp.phase = CACHESERVICE;           /* default: cache svc. */ 
             if (nscp->cmnd[0] == TEST_UNIT_READY) {
                 TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n", 
                         b, t, nscp->lun));
@@ -1987,7 +2063,8 @@
                     if (b == 0 && ((t == 0 && nscp->lun == 1) ||
                          (t == 1 && nscp->lun == 0))) {
                         nscp->SCp.Status = GDT_SCAN_START;
-                        nscp->SCp.phase |= ((ha->scan_mode & 0x10 ? 1:0) << 8);
+                        nscp->SCp.phase = ((ha->scan_mode & 0x10 ? 1:0) << 8) 
+                            | SCSIRAWSERVICE;
                         ha->scan_mode = 0x12;
                         TRACE2(("Scan mode: 0x%x (SCAN_START)\n", 
                                 ha->scan_mode));
@@ -1997,6 +2074,7 @@
                     }                   
                 } else if (ha->scan_mode == 0x12) {
                     if (b == ha->bus_cnt && t == ha->tid_cnt-1) {
+                        nscp->SCp.phase = SCSIRAWSERVICE;
                         nscp->SCp.Status = GDT_SCAN_END;
                         ha->scan_mode &= 0x10;
                         TRACE2(("Scan mode: 0x%x (SCAN_END)\n", 
@@ -2004,19 +2082,55 @@
                     }
                 }
             }
+            if (b == ha->virt_bus && nscp->cmnd[0] != INQUIRY &&
+                nscp->cmnd[0] != READ_CAPACITY && nscp->cmnd[0] != MODE_SENSE &&
+                (ha->hdr[t].cluster_type & CLUSTER_DRIVE)) {
+                if (!(ha->hdr[t].cluster_type & CLUSTER_MOUNTED)) {
+                    /* cluster drive NOT MOUNTED */
+                    if (!(ha->hdr[t].cluster_type & CLUSTER_RESERVED)) {
+                        /* cluster drive NOT RESERVED */
+                        nscp->SCp.Status = GDT_MOUNT;
+                    } else {
+                        /* cluster drive RESERVED (on the other node) */
+                        nscp->SCp.Status = GDT_CLUST_INFO;
+                    }
+                } else {
+                    if (!(ha->hdr[t].cluster_type & CLUSTER_RESERVED)) {
+                        /* cluster drive MOUNTED and not RESERVED */
+                        nscp->SCp.Status = GDT_CLUST_INFO;
+                    }
+                }
+            }
         }
         }
 
         if (nscp->SCp.Status != -1) {
-            if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) {
+            if ((nscp->SCp.phase & 0xff) == CACHESERVICE) {
+                if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+                    this_cmd = FALSE;
+                next_cmd = FALSE;
+            } else if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) {
                 if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b))))
                     this_cmd = FALSE;
                 next_cmd = FALSE;
+            } else {
+                memset((char*)nscp->sense_buffer,0,16);
+                nscp->sense_buffer[0] = 0x70;
+                nscp->sense_buffer[2] = NOT_READY;
+                nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                if (!nscp->SCp.have_data_in)
+                    nscp->SCp.have_data_in++;
+                else {
+                    GDTH_UNLOCK_HA(ha,flags);
+                    /* io_request_lock already active ! */
+                    nscp->scsi_done(nscp);
+                    GDTH_LOCK_HA(ha,flags);
+                }
             }
         } else
 
 #if LINUX_VERSION_CODE >= 0x010300
-        if (nscp->done == gdth_scsi_done) {
+        if (nscp->done == gdth_scsi_done && nscp->cmnd[0] == 0xff) {
             if (!(cmd_index=gdth_special_cmd(hanum,nscp)))
                 this_cmd = FALSE;
             next_cmd = FALSE;
@@ -2080,6 +2194,14 @@
                 }
                 break;
                 
+              case RESERVE:
+              case RELEASE:
+                TRACE2(("cache cmd %s\n",nscp->cmnd[0] == RESERVE ?
+                        "RESERVE" : "RELEASE"));
+                if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+                    this_cmd = FALSE;
+                break;
+                
               case READ_6:
               case WRITE_6:
               case READ_10:
@@ -2184,7 +2306,10 @@
         inq.type_qual = (ha->hdr[t].devtype&4) ? TYPE_ROM:TYPE_DISK;
         /* you can here set all disks to removable, if you want to do
            a flush using the ALLOW_MEDIUM_REMOVAL command */
-        inq.modif_rmb = ha->hdr[t].devtype&1 ? 0x80:0x00;
+        inq.modif_rmb = 0x00;
+        if ((ha->hdr[t].devtype & 1) ||
+            (ha->hdr[t].cluster_type & CLUSTER_DRIVE))
+            inq.modif_rmb = 0x80;
         inq.version   = 2;
         inq.resp_aenc = 2;
         inq.add_length= 32;
@@ -2243,7 +2368,7 @@
     register gdth_cmd_str *cmdp;
     struct scatterlist *sl;
     ushort i;
-    int cmd_index;
+    int cmd_index, read_write;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     cmdp = ha->pccb;
@@ -2265,31 +2390,38 @@
         gdth_set_sema0(hanum);
 
     /* fill command */
-    if (scp->cmnd[0]==ALLOW_MEDIUM_REMOVAL) {
+    read_write = FALSE;
+    if (scp->SCp.Status != -1) 
+        cmdp->OpCode = scp->SCp.Status;         /* special cache cmd. */
+    else if (scp->cmnd[0] == RESERVE) 
+        cmdp->OpCode = GDT_RESERVE_DRV;
+    else if (scp->cmnd[0] == RELEASE)
+        cmdp->OpCode = GDT_RELEASE_DRV;
+    else if (scp->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
         if (scp->cmnd[4] & 1)                   /* prevent ? */
-            cmdp->OpCode      = GDT_MOUNT;
+            cmdp->OpCode = GDT_MOUNT;
         else if (scp->cmnd[3] & 1)              /* removable drive ? */
-            cmdp->OpCode      = GDT_UNMOUNT;
+            cmdp->OpCode = GDT_UNMOUNT;
         else
-            cmdp->OpCode      = GDT_FLUSH;
+            cmdp->OpCode = GDT_FLUSH;
+    } else if (scp->cmnd[0] == WRITE_6 || scp->cmnd[0] == WRITE_10) {
+        read_write = TRUE;
+        if (gdth_write_through || ((ha->hdr[hdrive].rw_attribs & 1) && 
+                                   (ha->cache_feat & GDT_WR_THROUGH)))
+            cmdp->OpCode = GDT_WRITE_THR;
+        else
+            cmdp->OpCode = GDT_WRITE;
     } else {
-        if (scp->cmnd[0]==WRITE_6 || scp->cmnd[0]==WRITE_10) {
-            if (gdth_write_through)
-                cmdp->OpCode  = GDT_WRITE_THR;
-            else
-                cmdp->OpCode  = GDT_WRITE;
-        } else {
-            cmdp->OpCode      = GDT_READ;
-        }
+        read_write = TRUE;
+        cmdp->OpCode = GDT_READ;
     }
+    
+    cmdp->BoardNode        = LOCALBOARD;
+    cmdp->u.cache.DeviceNo = hdrive;
+    cmdp->u.cache.BlockNo  = 1;
+    cmdp->u.cache.sg_canz  = 0;
 
-    cmdp->BoardNode           = LOCALBOARD;
-    cmdp->u.cache.DeviceNo    = hdrive;
-
-    if (scp->cmnd[0]==ALLOW_MEDIUM_REMOVAL) {
-        cmdp->u.cache.BlockNo = 1;
-        cmdp->u.cache.sg_canz = 0;
-    } else {
+    if (read_write) {
         if (scp->cmd_len != 6) {
             cmdp->u.cache.BlockNo = ntohl(*(ulong32*)&scp->cmnd[2]);
             cmdp->u.cache.BlockCnt= (ulong32)ntohs(*(ushort*)&scp->cmnd[7]);
@@ -2942,37 +3074,92 @@
         }
         /* cache or raw service */
         if (ha->status == S_OK) {
-            scp->SCp.Message = S_OK;
+            scp->SCp.Message = (int)(ha->info<<16|S_OK);
             if (scp->SCp.Status != -1) {
                 TRACE2(("gdth_sync_event(): special cmd 0x%x OK\n",
                         scp->SCp.Status));
-                scp->SCp.Status = -1;
-                scp->SCp.this_residual = HIGH_PRI;
-                return 2;
+                /* special commands GDT_CLUST_INFO/GDT_MOUNT ? */
+                if (scp->SCp.Status == GDT_CLUST_INFO) {
+                    ha->hdr[scp->target].cluster_type = (unchar)ha->info;
+                    if (!(ha->hdr[scp->target].cluster_type & 
+                        CLUSTER_MOUNTED)) {
+                        /* NOT MOUNTED -> MOUNT */
+                        if (!(ha->hdr[scp->target].cluster_type & 
+                            CLUSTER_RESERVED)) {
+                            /* cluster drive NOT RESERVED */
+                            scp->SCp.Status = GDT_MOUNT;
+                        } else {
+                            /* cluster drive RESERVED (on the other node) */
+                            scp->SCp.Status = GDT_MOUNT;
+                            scp->SCp.phase = -2;      /* reservation conflict */
+                        }
+                    } else {
+                        scp->SCp.Status = -1;
+                    }
+                    /* retry */
+                    scp->SCp.this_residual = HIGH_PRI;
+                    return 2;
+                } else if (scp->SCp.Status == GDT_MOUNT) {
+                    ha->hdr[scp->target].cluster_type |= CLUSTER_MOUNTED;
+                    scp->SCp.Status = -1;
+                    /* return UNIT_ATTENTION */
+                    memset((char*)scp->sense_buffer,0,16);
+                    scp->sense_buffer[0] = 0x70;
+                    scp->sense_buffer[2] = UNIT_ATTENTION;
+                    scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                } else {
+                    scp->SCp.Status = -1;
+                    /* retry */
+                    scp->SCp.this_residual = HIGH_PRI;
+                    return 2;
+                }
+            } else {
+                /* RESERVE/RELEASE ? */
+                if (scp->cmnd[0] == RESERVE) {
+                    ha->hdr[scp->target].cluster_type |= CLUSTER_RESERVED;
+                } else if (scp->cmnd[0] == RELEASE) {
+                    ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED;
+                }           
+                scp->result = DID_OK << 16;
             }
-            scp->result = DID_OK << 16;
         } else if (ha->status == S_BSY) {
             TRACE2(("Controller busy -> retry !\n"));
-            scp->SCp.Message = S_BSY;
+            scp->SCp.Message = (int)(ha->info<<16|S_BSY);
+            if (scp->SCp.Status == GDT_MOUNT)
+                scp->SCp.Status = GDT_CLUST_INFO;
+            /* retry */
             return 2;
         } else {
             scp->SCp.Message = (int)((ha->info<<16)|ha->status);
+            memset((char*)scp->sense_buffer,0,16);
+            scp->sense_buffer[0] = 0x70;
+            scp->sense_buffer[2] = NOT_READY;
+
             if (scp->SCp.Status != -1) {
                 TRACE2(("gdth_sync_event(): special cmd 0x%x error 0x%x\n",
                         scp->SCp.Status, ha->status));
-                scp->SCp.Status = -1;
-                scp->SCp.this_residual = HIGH_PRI;
-                return 2;
-            }
-            if (service == CACHESERVICE) {
-                memset((char*)scp->sense_buffer,0,16);
-                scp->sense_buffer[0] = 0x70;
-                scp->sense_buffer[2] = NOT_READY;
+                if (scp->SCp.Status == GDT_SCAN_START ||
+                    scp->SCp.Status == GDT_SCAN_END) {
+                    scp->SCp.Status = -1;
+                    /* retry */
+                    scp->SCp.this_residual = HIGH_PRI;
+                    return 2;
+                }
+                scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+            } else if (scp->cmnd[0] == RESERVE ||
+                       scp->cmnd[0] == RELEASE) {
+                scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+            } else if (service == CACHESERVICE) {
+		if (ha->status == S_CACHE_UNKNOWN &&
+		    (ha->hdr[scp->target].cluster_type & 
+		     CLUSTER_RESERVE_STATE) == CLUSTER_RESERVE_STATE) {
+		    /* bus reset -> force GDT_CLUST_INFO */
+		    ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED;
+		}
                 scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
-
 #if LINUX_VERSION_CODE >= 0x010300
                 if (scp->done != gdth_scsi_done)
-#endif 
+#endif  
                 {
                     dvr.size = sizeof(dvr.eu.sync);
                     dvr.eu.sync.ionode  = hanum;
@@ -3754,24 +3941,46 @@
     TRACE2(("gdth_eh_bus_reset()\n"));
     hanum = NUMDATA(scp->host)->hanum;
     ha    = HADATA(gdth_ctr_tab[hanum]);
-    if (scp->channel == ha->virt_bus)
-        return FAILED;
 
+    /* clear command tab */
     GDTH_LOCK_HA(ha, flags);
-    for (i = 0; i < MAXID; ++i)
-        ha->raw[BUS_L2P(ha,scp->channel)].io_cnt[i] = 0;
     for (i = 0; i < GDTH_MAXCMDS; ++i) {
         cmnd = ha->cmd_tab[i].cmnd;
         if (!SPECIAL_SCP(cmnd) && cmnd->channel == scp->channel)
             ha->cmd_tab[i].cmnd = UNUSED_CMND;
     }
-    gdth_polling = TRUE;
-    while (gdth_test_busy(hanum))
-        gdth_delay(0);
-    gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS,
-                      BUS_L2P(ha,scp->channel), 0, 0);
-    gdth_polling = FALSE;
     GDTH_UNLOCK_HA(ha, flags);
+
+    if (scp->channel == ha->virt_bus) {
+        /* host drives */
+        for (i = 0; i < MAX_HDRIVES; ++i) {
+            if (ha->hdr[i].present && 
+                (ha->hdr[i].cluster_type & CLUSTER_RESERVED) 
+                == CLUSTER_RESERVED) { 
+                GDTH_LOCK_HA(ha, flags);
+                gdth_polling = TRUE;
+                while (gdth_test_busy(hanum))
+                    gdth_delay(0);
+                if (gdth_internal_cmd(hanum, CACHESERVICE, 
+                                      GDT_CLUST_RESET, i, 0, 0))
+                    ha->hdr[i].cluster_type &= ~CLUSTER_RESERVED;
+                gdth_polling = FALSE;
+                GDTH_UNLOCK_HA(ha, flags);
+            }
+        }
+    } else {
+        /* raw devices */
+        GDTH_LOCK_HA(ha, flags);
+        for (i = 0; i < MAXID; ++i)
+            ha->raw[BUS_L2P(ha,scp->channel)].io_cnt[i] = 0;
+        gdth_polling = TRUE;
+        while (gdth_test_busy(hanum))
+            gdth_delay(0);
+        gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS,
+                          BUS_L2P(ha,scp->channel), 0, 0);
+        gdth_polling = FALSE;
+        GDTH_UNLOCK_HA(ha, flags);
+    }
     return SUCCESS;
 }
 
@@ -3800,12 +4009,12 @@
 
     if (disk->device->channel != ha->virt_bus || ha->hdr[t].heads == 0) {
         /* raw device or host drive without mapping information */
-	TRACE2(("Evaluate mapping\n"));
-	gdth_eval_mapping(disk->capacity,&ip[2],&ip[0],&ip[1]);
+        TRACE2(("Evaluate mapping\n"));
+        gdth_eval_mapping(disk->capacity,&ip[2],&ip[0],&ip[1]);
     } else {
-	ip[0] = ha->hdr[t].heads;
-	ip[1] = ha->hdr[t].secs;
-	ip[2] = disk->capacity / ip[0] / ip[1];
+        ip[0] = ha->hdr[t].heads;
+        ip[1] = ha->hdr[t].secs;
+        ip[2] = disk->capacity / ip[0] / ip[1];
     }
 
     TRACE2(("gdth_bios_param(): %d heads, %d secs, %d cyls\n",
@@ -3869,18 +4078,16 @@
     Scsi_Cmnd       scp;
     Scsi_Device     sdev;
     gdth_cmd_str    gdtcmd;
+    char            cmnd[12];   
 
     TRACE2(("gdth_flush() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
     memset(&sdev,0,sizeof(Scsi_Device));
     memset(&scp, 0,sizeof(Scsi_Cmnd));
-    sdev.host = gdth_ctr_tab[hanum];
-    sdev.id = sdev.host->this_id;
-    scp.cmd_len = 12;
-    scp.host = gdth_ctr_tab[hanum];
-    scp.target = sdev.host->this_id;
+    memset(cmnd, 0xff, 12);
+    sdev.host = scp.host = gdth_ctr_tab[hanum];
+    sdev.id = scp.target = sdev.host->this_id;
     scp.device = &sdev;
-    scp.use_sg = 0;
 
     for (i = 0; i < MAX_HDRIVES; ++i) {
         if (ha->hdr[i].present) {
@@ -3891,7 +4098,7 @@
             gdtcmd.u.cache.BlockNo = 1;
             gdtcmd.u.cache.sg_canz = 0;
             TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i));
-            gdth_do_cmd(&scp, &gdtcmd, 30);
+            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
         }
     }
 }
@@ -3908,10 +4115,11 @@
     Scsi_Cmnd       scp;
     Scsi_Device     sdev;
     gdth_cmd_str    gdtcmd;
+    char            cmnd[12];
 #endif
 
 #if LINUX_VERSION_CODE >= 0x020100
-    TRACE2(("gdth_halt() event %d\n",event));
+    TRACE2(("gdth_halt() event %d\n",(int)event));
     if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF)
         return NOTIFY_DONE;
 #else
@@ -3930,19 +4138,16 @@
         /* controller reset */
         memset(&sdev,0,sizeof(Scsi_Device));
         memset(&scp, 0,sizeof(Scsi_Cmnd));
-        sdev.host = gdth_ctr_tab[hanum];
-        sdev.id = sdev.host->this_id;
-        scp.cmd_len = 12;
-        scp.host = gdth_ctr_tab[hanum];
-        scp.target = sdev.host->this_id;
+        memset(cmnd, 0xff, 12);
+        sdev.host = scp.host = gdth_ctr_tab[hanum];
+        sdev.id = scp.target = sdev.host->this_id;
         scp.device = &sdev;
-        scp.use_sg = 0;
 
         gdtcmd.BoardNode = LOCALBOARD;
         gdtcmd.Service = CACHESERVICE;
         gdtcmd.OpCode = GDT_RESET;
         TRACE2(("gdth_halt(): reset controller %d\n", hanum));
-        gdth_do_cmd(&scp, &gdtcmd, 10);
+        gdth_do_cmd(&scp, &gdtcmd, cmnd, 10);
 #endif
     }
     printk("Done.\n");
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/gdth.h linux.14p16/drivers/scsi/gdth.h
--- linux.vanilla/drivers/scsi/gdth.h	Sat Aug 14 02:25:41 1999
+++ linux.14p16/drivers/scsi/gdth.h	Tue Dec 21 00:51:22 1999
@@ -10,7 +10,7 @@
  *
  * <achim@vortex.de>
  *
- * $Id: gdth.h,v 1.21 1999/03/26 09:12:24 achim Exp $
+ * $Id: gdth.h,v 1.24 1999/11/02 13:43:49 achim Exp $
  */
 
 #include <linux/version.h>
@@ -29,9 +29,9 @@
 /* defines, macros */
 
 /* driver version */
-#define GDTH_VERSION_STR        "1.14"
+#define GDTH_VERSION_STR        "1.17"
 #define GDTH_VERSION            1
-#define GDTH_SUBVERSION         14
+#define GDTH_SUBVERSION         17
 
 /* protocol version */
 #define PROTOCOL_VERSION        1
@@ -135,7 +135,8 @@
 #define MAXID           127
 #define MAXLUN          8
 #define MAXBUS          6
-#define MAX_HDRIVES     35                      /* max. host drive count */
+#define MAX_HDRIVES     100                     /* max. host drive count */
+#define MAX_LDRIVES     255                     /* max. log. drive count */
 #define MAX_EVENTS      100                     /* event buffer count */
 #define MAX_RES_ARGS    40                      /* device reservation, 
                                                    must be a multiple of 4 */
@@ -173,6 +174,12 @@
 #define IC_QUEUE_BYTES  4
 #define DPMEM_COMMAND_OFFSET    IC_HEADER_BYTES+IC_QUEUE_BYTES*MAXOFFSETS
 
+/* cluster_type constants */
+#define CLUSTER_DRIVE         1
+#define CLUSTER_MOUNTED       2
+#define CLUSTER_RESERVED      4
+#define CLUSTER_RESERVE_STATE (CLUSTER_DRIVE|CLUSTER_MOUNTED|CLUSTER_RESERVED)
+
 /* cache/raw service commands */
 #define GDT_INIT        0                       /* service initialization */
 #define GDT_READ        1                       /* read command */
@@ -189,6 +196,11 @@
 #define GDT_READ_THR    17                      /* read through */
 #define GDT_EXT_INFO    18                      /* extended info */
 #define GDT_RESET       19                      /* controller reset */
+#define GDT_RESERVE_DRV 20                      /* reserve host drive */
+#define GDT_RELEASE_DRV 21                      /* release host drive */
+#define GDT_CLUST_INFO  22                      /* cluster info */
+#define GDT_RW_ATTRIBS  23                      /* R/W attribs (write thru,..)*/
+#define GDT_CLUST_RESET 24                      /* releases the cluster drives*/
 
 /* additional raw service commands */
 #define GDT_RESERVE     14                      /* reserve dev. to raw serv. */
@@ -206,10 +218,11 @@
 #define SCSI_DEF_CNT    0x15                    /* grown/primary defects */
 #define DSK_STATISTICS  0x4b                    /* SCSI disk statistics */
 #define IOCHAN_DESC     0x5d                    /* description of IO channel */
-#define IOCHAN_RAW_DESC 0x5e                    /* description of raw IO channel */
+#define IOCHAN_RAW_DESC 0x5e                    /* description of raw IO chn. */
 #define L_CTRL_PATTERN  0x20000000L             /* SCSI IOCTL mask */
 #define ARRAY_INFO      0x12                    /* array drive info */
 #define ARRAY_DRV_LIST  0x0f                    /* array drive list */
+#define ARRAY_DRV_LIST2 0x34                    /* array drive list (new) */
 #define LA_CTRL_PATTERN 0x10000000L             /* array IOCTL mask */
 #define CACHE_DRV_CNT   0x01                    /* cache drive count */
 #define CACHE_DRV_LIST  0x02                    /* cache drive list */
@@ -235,6 +248,7 @@
 /* service errors */
 #define S_OK            1                       /* no error */
 #define S_BSY           7                       /* controller busy */
+#define S_CACHE_UNKNOWN 12                      /* cache serv.: drive unknown */
 #define S_RAW_SCSI      12                      /* raw serv.: target error */
 #define S_RAW_ILL       0xff                    /* raw serv.: illegal */
 
@@ -249,8 +263,10 @@
 #define HIGH_PRI        0x08
 
 /* data directions */
+#ifndef HOSTS_C
 #define DATA_IN         0x01000000L             /* data from target */
 #define DATA_OUT        0x00000000L             /* data to target */
+#endif
 
 /* BMIC registers (EISA controllers) */
 #define ID0REG          0x0c80                  /* board ID */
@@ -298,7 +314,7 @@
     unchar      revision[4];                    /* revision */
     ulong32     sy_rate;                        /* current rate for sync. tr. */
     ulong32     sy_max_rate;                    /* max. rate for sync. tr. */
-    ulong32     no_ldrive;                      /* belongs to this logical drv.*/
+    ulong32     no_ldrive;                      /* belongs to this log. drv.*/
     ulong32     blkcnt;                         /* number of blocks */
     ushort      blksize;                        /* size of block in bytes */
     unchar      available;                      /* flag: access is available */
@@ -453,7 +469,15 @@
     unchar      is_parity;                      /* Flag: is parity drive? */
     unchar      is_hotfix;                      /* Flag: is hotfix drive? */
     unchar      res[3];
-} PACKED gdth_arraylist_str;
+} PACKED gdth_alist_str;
+
+typedef struct {
+    ulong32	entries_avail;			/* allocated entries */
+    ulong32	entries_init;			/* returned entries */
+    ulong32	first_entry;			/* first entry number */
+    ulong32	list_offset;			/* offset of following list */
+    gdth_alist_str list[1];			/* list */
+} PACKED gdth_arcdl_str;
 
 /* cache info/config IOCTL */
 typedef struct {
@@ -862,13 +886,15 @@
         ulong32         size;                   /* capacity */
         unchar          ldr_no;                 /* log. drive no. */
         unchar          rw_attribs;             /* r/w attributes */
+        unchar          cluster_type;           /* cluster properties */
+        unchar          reserved;
         ulong32         start_sec;              /* start sector */
-    } hdr[MAX_HDRIVES];                         /* host drives */
+    } hdr[MAX_LDRIVES];                         /* host drives */
     struct {
         unchar          lock;                   /* channel locked? (hot plug) */
         unchar          pdev_cnt;               /* physical device count */
         unchar          local_no;               /* local channel number */
-	unchar          io_cnt[MAXID];          /* current IO count */
+        unchar          io_cnt[MAXID];          /* current IO count */
         ulong32         address;                /* channel address */
         ulong32         id_list[MAXID];         /* IDs of the phys. devices */
     } raw[MAXBUS];                              /* SCSI channels */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/gdth_ioctl.h linux.14p16/drivers/scsi/gdth_ioctl.h
--- linux.vanilla/drivers/scsi/gdth_ioctl.h	Mon Jan 11 18:17:20 1999
+++ linux.14p16/drivers/scsi/gdth_ioctl.h	Mon Dec 13 18:32:13 1999
@@ -2,7 +2,7 @@
 #define _GDTH_IOCTL_H
 
 /* gdth_ioctl.h
- * $Id: gdth_ioctl.h,v 1.2 1998/12/17 15:42:49 achim Exp $
+ * $Id: gdth_ioctl.h,v 1.3 1999/05/26 11:49:57 achim Exp $
  */
 
 /* IOCTLs */
@@ -11,10 +11,13 @@
 #define GDTIOCTL_DRVERS     (GDTIOCTL_MASK | 1) /* get driver version */
 #define GDTIOCTL_CTRTYPE    (GDTIOCTL_MASK | 2) /* get controller type */
 #define GDTIOCTL_OSVERS     (GDTIOCTL_MASK | 3) /* get OS version */
+#define GDTIOCTL_HDRLIST    (GDTIOCTL_MASK | 4) /* get host drive list */
 #define GDTIOCTL_CTRCNT     (GDTIOCTL_MASK | 5) /* get controller count */
 #define GDTIOCTL_LOCKDRV    (GDTIOCTL_MASK | 6) /* lock host drive */
 #define GDTIOCTL_LOCKCHN    (GDTIOCTL_MASK | 7) /* lock channel */
 #define GDTIOCTL_EVENT      (GDTIOCTL_MASK | 8) /* read controller events */
+#define GDTIOCTL_SCSI       (GDTIOCTL_MASK | 9) /* SCSI command */
+#define GDTIOCTL_RESET_BUS  (GDTIOCTL_MASK |10) /* reset SCSI bus */
 
 #define GDTIOCTL_MAGIC      0xaffe0001UL
 
@@ -45,6 +48,13 @@
             int             handle;
             unchar          evt[34];            /* event structure */
         } event;
+        struct {
+            unchar          bus;                /* SCSI bus */
+            unchar          target;             /* target ID */
+            unchar          lun;                /* LUN */
+            unchar          cmd_len;            /* command length */
+            unchar          cmd[12];            /* SCSI command */
+        } scsi;
     } iu;
 } gdth_iowr_str;
 
@@ -79,6 +89,12 @@
             int             handle;
             unchar          evt[34];            /* event structure */
         } event;
+        struct {
+            unchar          bus;                /* SCSI bus, 0xff: invalid */
+            unchar          target;             /* target ID */
+            unchar          lun;                /* LUN */
+            unchar          cluster_type;       /* cluster properties */
+        } hdr_list[35];                         /* index is host drive number */
     } iu;
 } gdth_iord_str;
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/gdth_proc.c linux.14p16/drivers/scsi/gdth_proc.c
--- linux.vanilla/drivers/scsi/gdth_proc.c	Sat Aug 14 02:27:31 1999
+++ linux.14p16/drivers/scsi/gdth_proc.c	Mon Dec 13 18:32:58 1999
@@ -1,9 +1,8 @@
 /* gdth_proc.c 
- * $Id: gdth_proc.c,v 1.13 1999/03/22 16:12:53 achim Exp $
+ * $Id: gdth_proc.c,v 1.16 1999/11/02 13:44:11 achim Exp $
  */
 
 #include "gdth_ioctl.h"
-#include <linux/version.h>
 
 int gdth_proc_info(char *buffer,char **start,off_t offset,int length,   
                    int hostno,int inout)
@@ -41,13 +40,9 @@
 
     memset(&sdev,0,sizeof(Scsi_Device));
     memset(&scp, 0,sizeof(Scsi_Cmnd));
-    sdev.host = gdth_ctr_vtab[vh];
-    sdev.id = sdev.host->this_id;
-    scp.cmd_len = 12;
-    scp.host = gdth_ctr_vtab[vh];
-    scp.target = sdev.host->this_id;
+    sdev.host = scp.host = gdth_ctr_vtab[vh];
+    sdev.id = scp.target = sdev.host->this_id;
     scp.device = &sdev;
-    scp.use_sg = 0;
 
     if (length >= 4) {
         if (strncmp(buffer,"gdth",4) == 0) {
@@ -73,6 +68,7 @@
     gdth_ha_str     *ha;
     gdth_cmd_str    gdtcmd;
     gdth_cpar_str   *pcpar;
+    char            cmnd[12];
 
     TRACE2(("gdth_set_asc_info() ha %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
@@ -80,6 +76,7 @@
     drive = -1;
     wb_mode = 0;
     found = FALSE;
+    memset(cmnd, 0xff, 12);
 
     if (length >= 5 && strncmp(buffer,"flush",5)==0) {
         buffer += 6;
@@ -106,7 +103,7 @@
                 gdtcmd.u.cache.DeviceNo = i;
                 gdtcmd.u.cache.BlockNo = 1;
                 gdtcmd.u.cache.sg_canz = 0;
-                gdth_do_cmd(&scp, &gdtcmd, 30);
+                gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
             }
         }
         if (!found)
@@ -159,7 +156,7 @@
         gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
         gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
         pcpar->write_back = wb_mode==1 ? 0:1;
-        gdth_do_cmd(&scp, &gdtcmd, 30);
+        gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
         gdth_ioctl_free(hanum);
         printk("Done.\n");
         return(orig_length);
@@ -180,6 +177,8 @@
     ulong32         *ppadd, add_size;
     ulong32         *ppadd2, add_size2;
     ulong           flags;
+    char            cmnd[12];   
+    gdth_cmd_str    gdtcmd;
 
     TRACE2(("gdth_set_bin_info() ha %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
@@ -188,6 +187,7 @@
     pcmd = NULL;
     ppadd = ppadd2 = NULL;
     add_size = add_size2 = 0;
+    memset(cmnd, 0xff, 12);
 
     if (length < GDTOFFSOF(gdth_iowr_str,iu))
         return(-EINVAL);
@@ -242,7 +242,7 @@
             *ppadd2 = virt_to_bus(piord->iu.general.data+add_size);
         }
         /* do IOCTL */
-        gdth_do_cmd(&scp, pcmd, piowr->timeout);
+        gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout);
         piord->status = (ulong32)scp.SCp.Message;
         break;
 
@@ -363,10 +363,10 @@
                 pevt->event_data.size = sizeof(pevt->event_data.eu.async);
                 gdth_log_event(&pevt->event_data, NULL);
             }
-	    GDTH_LOCK_HA(ha, flags);
+            GDTH_LOCK_HA(ha, flags);
             gdth_store_event(ha, pevt->event_source, pevt->event_idx,
                              &pevt->event_data);
-	    GDTH_UNLOCK_HA(ha, flags);
+            GDTH_UNLOCK_HA(ha, flags);
         } else if (piowr->iu.event.erase == 0xfe) {
             gdth_clear_events();
         } else if (piowr->iu.event.erase == 0) {
@@ -382,6 +382,58 @@
         piord->status = S_OK;
         break;
 
+      case GDTIOCTL_SCSI:
+        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) ))
+            return(-EBUSY);
+        piord = (gdth_iord_str *)ha->pscratch;
+        piord->size = sizeof(gdth_iord_str);
+        scp.target = scp.device->id = piowr->iu.scsi.target;
+        scp.channel = scp.device->channel = piowr->iu.scsi.bus;
+        memcpy(cmnd, piowr->iu.scsi.cmd, 12);
+        scp.cmd_len = piowr->iu.scsi.cmd_len;
+        gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout);
+        piord->status = (ulong32)scp.result;
+        break;
+
+      case GDTIOCTL_RESET_BUS:
+        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) ))
+            return(-EBUSY);
+        piord = (gdth_iord_str *)ha->pscratch;
+        piord->size = sizeof(gdth_iord_str);
+        scp.channel = scp.device->channel = piowr->iu.scsi.bus;
+        piord->status = (ulong32)gdth_eh_bus_reset( &scp );
+        break;
+
+      case GDTIOCTL_HDRLIST:
+        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) ))
+            return(-EBUSY);
+        piord = (gdth_iord_str *)ha->pscratch;
+        piord->size = sizeof(gdth_iord_str);
+        piord->status = S_OK;
+        for (i = 0; i < MAX_HDRIVES; ++i) {
+            if (ha->hdr[i].present) {
+                piord->iu.hdr_list[i].bus = ha->virt_bus;
+                piord->iu.hdr_list[i].target = i;
+                piord->iu.hdr_list[i].lun = 0;
+                piord->iu.hdr_list[i].cluster_type = ha->hdr[i].cluster_type;
+                if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) {
+                    gdtcmd.BoardNode = LOCALBOARD;
+                    gdtcmd.Service = CACHESERVICE;
+                    gdtcmd.OpCode = GDT_CLUST_INFO;
+                    gdtcmd.u.cache.DeviceNo = i;
+                    gdtcmd.u.cache.BlockNo = 0;
+                    gdtcmd.u.cache.sg_canz = 0;
+                    gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                    if ((scp.SCp.Message & 0xffff) == S_OK)
+                        piord->iu.hdr_list[i].cluster_type = 
+                            (unchar)(scp.SCp.Message>>16);
+		}
+            } else {
+                piord->iu.hdr_list[i].bus = 0xff;
+            }
+        }
+        break;
+
       default:
         return(-EINVAL);
     }
@@ -404,6 +456,7 @@
     gdth_evt_str estr;
     Scsi_Cmnd scp;
     Scsi_Device sdev;
+    char cmnd[12];
     char hrec[161];
     struct timeval tv;
 
@@ -420,13 +473,10 @@
 
     memset(&sdev,0,sizeof(Scsi_Device));
     memset(&scp, 0,sizeof(Scsi_Cmnd));
-    sdev.host = gdth_ctr_vtab[vh];
-    sdev.id = sdev.host->this_id;
-    scp.cmd_len = 12;
-    scp.host = gdth_ctr_vtab[vh];
-    scp.target = sdev.host->this_id;
+    memset(cmnd, 0xff, 12);
+    sdev.host = scp.host = gdth_ctr_vtab[vh];
+    sdev.id = scp.target = sdev.host->this_id;
     scp.device = &sdev;
-    scp.use_sg = 0;
 
     /* look for buffer ID in length */
     if (id > 1) {
@@ -514,7 +564,7 @@
             /* 2. about physical devices */
             size = sprintf(buffer+len,"\nPhysical Devices:");
             len += size;  pos = begin + len;
-	    flag = FALSE;
+            flag = FALSE;
             
             if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH))
                 goto stop_output;
@@ -536,8 +586,8 @@
                     sizeof(pds->list[0]);
                 if (pds->entries > cnt)
                     pds->entries = cnt;
-                gdth_do_cmd(&scp, &gdtcmd, 30);
-                if (scp.SCp.Message != S_OK) 
+                gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                if ((scp.SCp.Message & 0xffff) != S_OK) 
                     pds->count = 0;
                 TRACE2(("pdr_statistics() entries %d status %d\n",
                         pds->count, scp.SCp.Message));
@@ -556,8 +606,8 @@
                     gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN;
                     gdtcmd.u.ioctl.channel = 
                         ha->raw[i].address | ha->raw[i].id_list[j];
-                    gdth_do_cmd(&scp, &gdtcmd, 30);
-                    if (scp.SCp.Message == S_OK) {
+                    gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                    if ((scp.SCp.Message & 0xffff) == S_OK) {
                         strncpy(hrec,pdi->vendor,8);
                         strncpy(hrec+8,pdi->product,16);
                         strncpy(hrec+24,pdi->revision,4);
@@ -566,7 +616,7 @@
                                        "\n Chn/ID/LUN:   \t%c/%02d/%d    \tName:          \t%s\n",
                                        'A'+i,pdi->target_id,pdi->lun,hrec);
                         len += size;  pos = begin + len;
-			flag = TRUE;
+                        flag = TRUE;
                         pdi->no_ldrive &= 0xffff;
                         if (pdi->no_ldrive == 0xffff)
                             strcpy(hrec,"--");
@@ -607,8 +657,8 @@
                         gdtcmd.u.ioctl.channel = 
                             ha->raw[i].address | ha->raw[i].id_list[j];
                         pdef->sddc_type = 0x08;
-                        gdth_do_cmd(&scp, &gdtcmd, 30);
-                        if (scp.SCp.Message == S_OK) {
+                        gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                        if ((scp.SCp.Message & 0xffff) == S_OK) {
                             size = sprintf(buffer+len,
                                            " Grown Defects:\t%d\n",
                                            pdef->sddc_cnt);
@@ -619,10 +669,10 @@
             }
             gdth_ioctl_free(hanum);
 
-	    if (!flag) {
-		size = sprintf(buffer+len, "\n --\n");
-		len += size;  pos = begin + len;
-	    }
+            if (!flag) {
+                size = sprintf(buffer+len, "\n --\n");
+                len += size;  pos = begin + len;
+            }
             if (pos < offset) {
                 len = 0;
                 begin = pos;
@@ -633,11 +683,11 @@
             /* 3. about logical drives */
             size = sprintf(buffer+len,"\nLogical Drives:");
             len += size;  pos = begin + len;
-	    flag = FALSE;
+            flag = FALSE;
 
             if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH))
                 goto stop_output;
-            for (i = 0; i < MAX_HDRIVES; ++i) {
+            for (i = 0; i < MAX_LDRIVES; ++i) {
                 if (!ha->hdr[i].is_logdrv)
                     continue;
                 drv_no = i;
@@ -654,8 +704,8 @@
                     gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
                     gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO;
                     gdtcmd.u.ioctl.channel = drv_no;
-                    gdth_do_cmd(&scp, &gdtcmd, 30);
-                    if (scp.SCp.Message != S_OK)
+                    gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                    if ((scp.SCp.Message & 0xffff) != S_OK)
                         break;
                     pcdi->ld_dtype >>= 16;
                     j++;
@@ -675,7 +725,7 @@
                                        "\n Number:       \t%-2d        \tStatus:        \t%s\n",
                                        drv_no, hrec);
                         len += size;  pos = begin + len;
-			flag = TRUE;
+                        flag = TRUE;
                         no_mdrv = pcdi->cd_ldcnt;
                         if (no_mdrv > 1 || pcdi->ld_slave != -1) {
                             is_mirr = TRUE;
@@ -720,10 +770,10 @@
             }       
             gdth_ioctl_free(hanum);
         
-	    if (!flag) {
-		size = sprintf(buffer+len, "\n --\n");
-		len += size;  pos = begin + len;
-	    }	
+            if (!flag) {
+                size = sprintf(buffer+len, "\n --\n");
+                len += size;  pos = begin + len;
+            }   
             if (pos < offset) {
                 len = 0;
                 begin = pos;
@@ -734,11 +784,11 @@
             /* 4. about array drives */
             size = sprintf(buffer+len,"\nArray Drives:");
             len += size;  pos = begin + len;
-	    flag = FALSE;
+            flag = FALSE;
 
             if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH))
                 goto stop_output;
-            for (i = 0; i < MAX_HDRIVES; ++i) {
+            for (i = 0; i < MAX_LDRIVES; ++i) {
                 if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master))
                     continue;
                 /* 4.a array drive info */
@@ -751,8 +801,8 @@
                 gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str);
                 gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
                 gdtcmd.u.ioctl.channel = i;
-                gdth_do_cmd(&scp, &gdtcmd, 30);
-                if (scp.SCp.Message == S_OK) {
+                gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                if ((scp.SCp.Message & 0xffff) == S_OK) {
                     if (pai->ai_state == 0)
                         strcpy(hrec, "idle");
                     else if (pai->ai_state == 2)
@@ -792,10 +842,10 @@
             }
             gdth_ioctl_free(hanum);
         
-	    if (!flag) {
-		size = sprintf(buffer+len, "\n --\n");
-		len += size;  pos = begin + len;
-	    }
+            if (!flag) {
+                size = sprintf(buffer+len, "\n --\n");
+                len += size;  pos = begin + len;
+            }
             if (pos < offset) {
                 len = 0;
                 begin = pos;
@@ -806,11 +856,11 @@
             /* 5. about host drives */
             size = sprintf(buffer+len,"\nHost Drives:");
             len += size;  pos = begin + len;
-	    flag = FALSE;
+            flag = FALSE;
 
             if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH))
                 goto stop_output;
-            for (i = 0; i < MAX_HDRIVES; ++i) {
+            for (i = 0; i < MAX_LDRIVES; ++i) {
                 if (!ha->hdr[i].is_logdrv || 
                     (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master))
                     continue;
@@ -826,15 +876,15 @@
                 gdtcmd.u.ioctl.channel = i;
                 phg->entries = MAX_HDRIVES;
                 phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); 
-                gdth_do_cmd(&scp, &gdtcmd, 30);
-                if (scp.SCp.Message != S_OK) {
+                gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                if ((scp.SCp.Message & 0xffff) != S_OK) {
                     ha->hdr[i].ldr_no = i;
                     ha->hdr[i].rw_attribs = 0;
                     ha->hdr[i].start_sec = 0;
                 } else {
                     for (j = 0; j < phg->entries; ++j) {
                         k = phg->entry[j].host_drive;
-                        if (k >= MAX_HDRIVES)
+                        if (k >= MAX_LDRIVES)
                             continue;
                         ha->hdr[k].ldr_no = phg->entry[j].log_drive;
                         ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs;
@@ -854,7 +904,7 @@
                                "\n Number:       \t%-2d        \tArr/Log. Drive:\t%d\n",
                                i, ha->hdr[i].ldr_no);
                 len += size;  pos = begin + len;
-		flag = TRUE;
+                flag = TRUE;
 
                 size = sprintf(buffer+len,
                                " Capacity [MB]:\t%-6d    \tStart Sector:  \t%d\n",
@@ -862,10 +912,10 @@
                 len += size;  pos = begin + len;
             }
         
-	    if (!flag) {
-		size = sprintf(buffer+len, "\n --\n");
-		len += size;  pos = begin + len;
-	    }
+            if (!flag) {
+                size = sprintf(buffer+len, "\n --\n");
+                len += size;  pos = begin + len;
+            }
             if (pos < offset) {
                 len = 0;
                 begin = pos;
@@ -887,7 +937,7 @@
                 gdth_log_event(&estr.event_data, hrec);
                 do_gettimeofday(&tv);
                 sec = (int)(tv.tv_sec - estr.first_stamp);
-		if (sec < 0) sec = 0;
+                if (sec < 0) sec = 0;
                 size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n",
                                sec/3600, sec%3600/60, sec%60, hrec);
                 len += size;  pos = begin + len;
@@ -929,19 +979,24 @@
     return(len);
 }
 
-static void gdth_do_cmd(Scsi_Cmnd *scp,gdth_cmd_str *gdtcmd,int timeout)
+static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *gdtcmd, 
+                        char *cmnd, int timeout)
 {
-    char cmnd[12];
     struct semaphore sem = MUTEX_LOCKED;
+    unsigned bufflen;
 
     TRACE2(("gdth_do_cmd()\n"));
-    memset(cmnd, 0, 12);
+    if (gdtcmd != NULL) { 
+        scp->SCp.this_residual = IOCTL_PRI;
+        bufflen = sizeof(gdth_cmd_str);
+    } else {
+        scp->SCp.this_residual = DEFAULT_PRI;
+        bufflen = 0;
+    }
     scp->request.rq_status = RQ_SCSI_BUSY;
     scp->request.sem = &sem;
-    scp->SCp.this_residual = IOCTL_PRI;
     GDTH_LOCK_SCSI_DOCMD();
-    scsi_do_cmd(scp, cmnd, gdtcmd, sizeof(gdth_cmd_str), 
-                gdth_scsi_done, timeout*HZ, 1);
+    scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
     GDTH_UNLOCK_SCSI_DOCMD();
     down(&sem);
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/gdth_proc.h linux.14p16/drivers/scsi/gdth_proc.h
--- linux.vanilla/drivers/scsi/gdth_proc.h	Sat Aug 14 02:25:41 1999
+++ linux.14p16/drivers/scsi/gdth_proc.h	Mon Dec 13 18:33:16 1999
@@ -2,7 +2,7 @@
 #define _GDTH_PROC_H
 
 /* gdth_proc.h 
- * $Id: gdth_proc.h,v 1.6 1999/03/05 14:32:36 achim Exp $
+ * $Id: gdth_proc.h,v 1.7 1999/05/26 11:49:32 achim Exp $
  */
 
 static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum);
@@ -18,7 +18,8 @@
 static void gdth_start_timeout(int hanum, int busnum, int id);
 static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout);
 
-static void gdth_do_cmd(Scsi_Cmnd *scp,gdth_cmd_str *cmd,int timeout);
+static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *cmd, 
+                        char *cmnd, int timeout);
 void gdth_scsi_done(Scsi_Cmnd *scp);
 
 #endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/ide-scsi.c linux.14p16/drivers/scsi/ide-scsi.c
--- linux.vanilla/drivers/scsi/ide-scsi.c	Sat Aug 14 02:27:31 1999
+++ linux.14p16/drivers/scsi/ide-scsi.c	Thu Dec  9 15:33:51 1999
@@ -302,13 +302,13 @@
 
 static inline unsigned long get_timeout(idescsi_pc_t *pc)
 {
-	return IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
+	return IDE_MAX((30 * HZ), pc->timeout - jiffies);	/* CD-RW drives need long timeouts */
 }
 
 /*
  *	Our interrupt handler.
  */
-static void idescsi_pc_intr (ide_drive_t *drive)
+static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 	byte status, ireason;
@@ -338,15 +338,14 @@
 		if (status & ERR_STAT)
 			rq->errors++;
 		idescsi_end_request (1, HWGROUP(drive));
-		return;
+		return ide_stopped;
 	}
 	bcount = IN_BYTE (IDE_BCOUNTH_REG) << 8 | IN_BYTE (IDE_BCOUNTL_REG);
 	ireason = IN_BYTE (IDE_IREASON_REG);
 
 	if (ireason & IDESCSI_IREASON_COD) {
 		printk (KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 	if (ireason & IDESCSI_IREASON_IO) {
 		temp = pc->actually_transferred + bcount;
@@ -366,7 +365,7 @@
 				pc->current_position += temp;
 				idescsi_discard_data (drive,bcount - temp);
 				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc));
-				return;
+				return ide_started;
 			}
 #if IDESCSI_DEBUG_LOG
 			printk (KERN_NOTICE "ide-scsi: The scsi wants to send us more data than expected - allowing transfer\n");
@@ -390,32 +389,34 @@
 	pc->current_position+=bcount;
 
 	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc));	/* And set the interrupt handler again */
+	return ide_started;
 }
 
-static void idescsi_transfer_pc (ide_drive_t *drive)
+static ide_startstop_t idescsi_transfer_pc (ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 	idescsi_pc_t *pc = scsi->pc;
 	byte ireason;
+	ide_startstop_t startstop;
 
-	if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
 		printk (KERN_ERR "ide-scsi: Strange, packet command initiated yet DRQ isn't asserted\n");
-		return;
+		return startstop;
 	}
 	ireason = IN_BYTE (IDE_IREASON_REG);
 	if ((ireason & (IDESCSI_IREASON_IO | IDESCSI_IREASON_COD)) != IDESCSI_IREASON_COD) {
 		printk (KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while issuing a packet command\n");
-		ide_do_reset (drive);
-		return;
+		return ide_do_reset (drive);
 	}
 	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc));	/* Set the interrupt routine */
 	atapi_output_bytes (drive, scsi->pc->c, 12);			/* Send the actual packet */
+	return ide_started;
 }
 
 /*
  *	Issue a packet command
  */
-static void idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
+static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 	int bcount;
@@ -443,16 +444,17 @@
 	if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
 		ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc));
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
+		return ide_started;
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
-		idescsi_transfer_pc (drive);
+		return idescsi_transfer_pc (drive);
 	}
 }
 
 /*
  *	idescsi_do_request is our request handling function.
  */
-static void idescsi_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 #if IDESCSI_DEBUG_LOG
 	printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
@@ -460,11 +462,11 @@
 #endif /* IDESCSI_DEBUG_LOG */
 
 	if (rq->cmd == IDESCSI_PC_RQ) {
-		idescsi_issue_pc (drive, (idescsi_pc_t *) rq->buffer);
-		return;
+		return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->buffer);
 	}
 	printk (KERN_ERR "ide-scsi: %s: unsupported command in request queue (%x)\n", drive->name, rq->cmd);
 	idescsi_end_request (0,HWGROUP (drive));
+	return ide_stopped;
 }
 
 static int idescsi_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/in2000.h linux.14p16/drivers/scsi/in2000.h
--- linux.vanilla/drivers/scsi/in2000.h	Sat Aug 14 02:27:31 1999
+++ linux.14p16/drivers/scsi/in2000.h	Tue Dec 21 00:51:22 1999
@@ -62,6 +62,8 @@
  */
 
 #define FAST_READ2_IO()    \
+({ \
+int __dummy_1,__dummy_2; \
    __asm__ __volatile__ ("\n \
    cld                    \n \
    orl %%ecx, %%ecx       \n \
@@ -69,11 +71,14 @@
    rep                    \n \
    insw (%%dx),%%es:(%%edi) \n \
 1: "                       \
-   : "=D" (sp)                   /* output */   \
-   : "d" (f), "D" (sp), "c" (i)  /* input */    \
-   : "edx", "ecx", "edi" )       /* trashed */
+   : "=D" (sp) ,"=c" (__dummy_1) ,"=d" (__dummy_2)  /* output */   \
+   : "2" (f), "0" (sp), "1" (i)  /* input */    \
+   );       /* trashed */ \
+})
 
 #define FAST_WRITE2_IO()   \
+({ \
+int __dummy_1,__dummy_2; \
    __asm__ __volatile__ ("\n \
    cld                    \n \
    orl %%ecx, %%ecx       \n \
@@ -81,10 +86,10 @@
    rep                    \n \
    outsw %%ds:(%%esi),(%%dx) \n \
 1: "                       \
-   : "=S" (sp)                   /* output */   \
-   : "d" (f), "S" (sp), "c" (i)  /* input */    \
-   : "edx", "ecx", "esi" )       /* trashed */
-
+   : "=S" (sp) ,"=c" (__dummy_1) ,"=d" (__dummy_2)/* output */   \
+   : "2" (f), "0" (sp), "1" (i)  /* input */    \
+   );       /* trashed */ \
+})
 
 /* IN2000 io_port offsets */
 #define IO_WD_ASR       0x00     /* R - 3393 auxstat reg */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/ips.c linux.14p16/drivers/scsi/ips.c
--- linux.vanilla/drivers/scsi/ips.c	Wed Oct 20 01:12:41 1999
+++ linux.14p16/drivers/scsi/ips.c	Fri Dec 17 17:51:57 1999
@@ -60,6 +60,12 @@
 /* 0.99.05  - Fix an oops when we get certain passthru commands              */
 /* 1.00.00  - Initial Public Release                                         */
 /*            Functionally equivalent to 0.99.05                             */
+/* 3.60.00  - Bump max commands to 128 for use with ServeRAID firmware 3.60  */
+/*          - Change version to 3.60 to coincide with ServeRAID release      */
+/*            numbering.                                                     */
+/* 3.60.01  - Remove bogus error check in passthru routine                   */
+/* 3.60.02  - Make DCDB direction based on lookup table                      */
+/*          - Only allow one DCDB command to a SCSI ID at a time             */
 /*                                                                           */
 /*****************************************************************************/
 
@@ -111,8 +117,8 @@
 /*
  * DRIVER_VER
  */
-#define IPS_VERSION_HIGH        "1.00"  /* MUST be 4 chars */
-#define IPS_VERSION_LOW         ".00 "  /* MUST be 4 chars */
+#define IPS_VERSION_HIGH        "3.60"  /* MUST be 4 chars */
+#define IPS_VERSION_LOW         ".02 "  /* MUST be 4 chars */
 
 struct proc_dir_entry proc_scsi_ips = {
 #if !defined(PROC_SCSI_IPS)
@@ -170,6 +176,63 @@
 };
 
 /*
+ * Direction table
+ */
+static char ips_command_direction[] = {
+IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT,
+IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK,
+IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT,
+IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_OUT,
+IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT,
+IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_IN,
+IPS_DATA_UNK, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_UNK,
+IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT,
+IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE,
+IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT,
+IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT,
+IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_NONE,
+IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK,
+IPS_DATA_NONE, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_NONE,
+IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_OUT,
+IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_NONE,
+IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_OUT,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK
+};
+
+/*
  * Function prototypes
  */
 int ips_detect(Scsi_Host_Template *);
@@ -1351,7 +1414,7 @@
        (scb->cmd.basic_io.op_code == DIRECT_CDB_SCATTER_GATHER))
       return (0);
 
-   if (pt->CmdBSize && pt->CmdBuffer) {
+   if (pt->CmdBSize) {
       scb->data_busaddr = VIRT_TO_BUS(scb->scsi_cmd->request_buffer + sizeof(ips_passthru_t));
    } else {
       scb->data_busaddr = 0L;
@@ -1675,8 +1738,10 @@
 
    /* set controller IDs */
    ha->ha_id[0] = IPS_ADAPTER_ID;
-   for (i = 1; i < ha->nbus; i++)
+   for (i = 1; i < ha->nbus; i++) {
       ha->ha_id[i] = ha->conf->init_id[i-1] & 0x1f;
+      ha->dcdb_active[i-1] = 0;
+   }
 
    return (1);
 }
@@ -1696,6 +1761,7 @@
 ips_next(ips_ha_t *ha) {
    ips_scb_t    *scb;
    Scsi_Cmnd    *SC;
+   Scsi_Cmnd    *p;
    int           ret;
 
    DBG("ips_next");
@@ -1768,9 +1834,15 @@
    /*
     * Send "Normal" I/O commands
     */
-   while ((ha->scb_waitlist.head) &&
-          (scb = ips_getscb(ha))) {
-      SC = ips_removeq_wait_head(&ha->scb_waitlist);
+   p = ha->scb_waitlist.head;
+   while ((p) && (scb = ips_getscb(ha))) {
+      if ((p->channel > 0) && (ha->dcdb_active[p->channel-1] & (1 << p->target))) {
+         ips_freescb(ha, scb);
+         p = (Scsi_Cmnd *) p->host_scribble;
+         continue;
+      }
+
+      SC = ips_removeq_wait(&ha->scb_waitlist, p);
 
       SC->result = DID_OK;
       SC->host_scribble = NULL;
@@ -1785,7 +1857,7 @@
       scb->data_len = 0;
       scb->callback = ipsintr_done;
       scb->timeout = ips_cmd_timeout;
-      memset(&scb->cmd, 0, 4);
+      memset(&scb->cmd, 0, 16);
 
       /* copy in the CDB */
       memcpy(scb->cdb, SC->cmnd, SC->cmd_len);
@@ -1843,11 +1915,11 @@
 
       }
 
-      if ((scb->scsi_cmd->request.cmd == READ) && (SC->request_bufflen))
-         scb->dcdb.cmd_attribute |= DATA_IN;
+      scb->dcdb.cmd_attribute |=
+         ips_command_direction[scb->scsi_cmd->cmnd[0]];
 
-      if ((scb->scsi_cmd->request.cmd == WRITE) && (SC->request_bufflen))
-         scb->dcdb.cmd_attribute |= DATA_OUT;
+      if (!scb->dcdb.cmd_attribute & 0x3)
+         scb->dcdb.transfer_length = 0;
 
       if (scb->data_len >= IPS_MAX_XFER) {
          scb->dcdb.cmd_attribute |= TRANSFER_64K;
@@ -1866,16 +1938,25 @@
             scb->scsi_cmd->scsi_done(scb->scsi_cmd);
          }
 
+         if (scb->bus)
+            ha->dcdb_active[scb->bus-1] &= ~(1 << scb->target_id);
+
          ips_freescb(ha, scb);
          break;
       case IPS_SUCCESS_IMM:
          if (scb->scsi_cmd)
             scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+
+         if (scb->bus)
+            ha->dcdb_active[scb->bus-1] &= ~(1 << scb->target_id);
+
          ips_freescb(ha, scb);
          break;
       default:
          break;
       } /* end case */
+
+      p = (Scsi_Cmnd *) p->host_scribble;
    } /* end while */
 }
 
@@ -2277,11 +2358,11 @@
             scb->sg_len = 0;
          }
 
-         if ((scb->scsi_cmd->request.cmd == READ) && (scb->data_len))
-            scb->dcdb.cmd_attribute |= DATA_IN;
+         scb->dcdb.cmd_attribute |=
+            ips_command_direction[scb->scsi_cmd->cmnd[0]];
 
-         if ((scb->scsi_cmd->request.cmd == WRITE) && (scb->data_len))
-            scb->dcdb.cmd_attribute |= DATA_OUT;
+         if (!scb->dcdb.cmd_attribute & 0x3)
+            scb->dcdb.transfer_length = 0;
 
          if (scb->data_len >= IPS_MAX_XFER) {
             scb->dcdb.cmd_attribute |= TRANSFER_64K;
@@ -2317,6 +2398,9 @@
    } /* end if passthru */
 #endif
 
+   if (scb->bus)
+      ha->dcdb_active[scb->bus-1] &= ~(1 << scb->target_id);
+
    /* call back to SCSI layer */
    scb->scsi_cmd->scsi_done(scb->scsi_cmd);
    ips_freescb(ha, scb);
@@ -2341,6 +2425,16 @@
    DBG("ips_map_status");
 
    if (scb->bus) {
+#if IPS_DEBUG >= 10
+      printk(KERN_NOTICE "(%s) Physical device error: %x %x, Sense Key: %x, ASC: %x, ASCQ: %x\n",
+             ips_name,
+             scb->basic_status,
+             scb->extended_status,
+             scb->dcdb.sense_info[2] & 0xf,
+             scb->dcdb.sense_info[12],
+             scb->dcdb.sense_info[13]);
+#endif
+
       /* copy SCSI status and sense data for DCDB commands */
       memcpy(scb->scsi_cmd->sense_buffer, scb->dcdb.sense_info,
              sizeof(scb->scsi_cmd->sense_buffer));
@@ -2687,6 +2781,7 @@
       else
          scb->cmd.dcdb.op_code = DIRECT_CDB_SCATTER_GATHER;
 
+      ha->dcdb_active[scb->bus-1] |= (1 << scb->target_id);
       scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb);
       scb->cmd.dcdb.dcdb_address = VIRT_TO_BUS(&scb->dcdb);
       scb->cmd.dcdb.reserved = 0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/ips.h linux.14p16/drivers/scsi/ips.h
--- linux.vanilla/drivers/scsi/ips.h	Wed Oct 20 01:12:41 1999
+++ linux.14p16/drivers/scsi/ips.h	Fri Dec 17 17:52:21 1999
@@ -76,102 +76,102 @@
    #define UDELAY udelay
    #define MDELAY mdelay
 
-   #define verify_area_20(t,a,sz)               (0) /* success */
-   #define PUT_USER                             put_user
-   #define __PUT_USER                           __put_user
-   #define PUT_USER_RET                         put_user_ret
-   #define GET_USER                             get_user
-   #define __GET_USER                           __get_user
-   #define GET_USER_RET                         get_user_ret
+   #define verify_area_20(t,a,sz)       (0) /* success */
+   #define PUT_USER                     put_user
+   #define __PUT_USER                   __put_user
+   #define PUT_USER_RET                 put_user_ret
+   #define GET_USER                     get_user
+   #define __GET_USER                   __get_user
+   #define GET_USER_RET                 get_user_ret
 
 /*
  * Adapter address map equates
  */
-   #define HISR                 0x08    /* Host Interrupt Status Reg   */
-   #define CCSAR                0x10    /* Cmd Channel System Addr Reg */
-   #define CCCR                 0x14    /* Cmd Channel Control Reg     */
-   #define SQHR                 0x20    /* Status Q Head Reg           */
-   #define SQTR                 0x24    /* Status Q Tail Reg           */
-   #define SQER                 0x28    /* Status Q End Reg            */
-   #define SQSR                 0x2C    /* Status Q Start Reg          */
-   #define SCPR                 0x05    /* Subsystem control port reg  */
-   #define ISPR                 0x06    /* interrupt status port reg   */
-   #define CBSP                 0x07    /* CBSP register               */
+   #define HISR                         0x08    /* Host Interrupt Status Reg   */
+   #define CCSAR                        0x10    /* Cmd Channel System Addr Reg */
+   #define CCCR                         0x14    /* Cmd Channel Control Reg     */
+   #define SQHR                         0x20    /* Status Q Head Reg           */
+   #define SQTR                         0x24    /* Status Q Tail Reg           */
+   #define SQER                         0x28    /* Status Q End Reg            */
+   #define SQSR                         0x2C    /* Status Q Start Reg          */
+   #define SCPR                         0x05    /* Subsystem control port reg  */
+   #define ISPR                         0x06    /* interrupt status port reg   */
+   #define CBSP                         0x07    /* CBSP register               */
 
 /*
  * Adapter register bit equates
  */
-   #define GHI                  0x04    /* HISR General Host Interrupt */
-   #define SQO                  0x02    /* HISR Status Q Overflow      */
-   #define SCE                  0x01    /* HISR Status Channel Enqueue */
-   #define SEMAPHORE            0x08    /* CCCR Semaphore Bit          */
-   #define ILE                  0x10    /* CCCR ILE Bit                */
-   #define START_COMMAND        0x101A  /* CCCR Start Command Channel  */
-   #define START_STOP_BIT       0x0002  /* CCCR Start/Stop Bit         */
-   #define RST                  0x80    /* SCPR Reset Bit              */
-   #define EBM                  0x02    /* SCPR Enable Bus Master      */
-   #define EI                   0x80    /* HISR Enable Interrupts      */
-   #define OP                   0x01    /* OP bit in CBSP              */
+   #define GHI                          0x04    /* HISR General Host Interrupt */
+   #define SQO                          0x02    /* HISR Status Q Overflow      */
+   #define SCE                          0x01    /* HISR Status Channel Enqueue */
+   #define SEMAPHORE                    0x08    /* CCCR Semaphore Bit          */
+   #define ILE                          0x10    /* CCCR ILE Bit                */
+   #define START_COMMAND                0x101A  /* CCCR Start Command Channel  */
+   #define START_STOP_BIT               0x0002  /* CCCR Start/Stop Bit         */
+   #define RST                          0x80    /* SCPR Reset Bit              */
+   #define EBM                          0x02    /* SCPR Enable Bus Master      */
+   #define EI                           0x80    /* HISR Enable Interrupts      */
+   #define OP                           0x01    /* OP bit in CBSP              */
 
 /*
  * Adapter Command ID Equates
  */
-   #define GET_LOGICAL_DRIVE_INFO               0x19
-   #define GET_SUBSYS_PARAM                     0x40
-   #define READ_NVRAM_CONFIGURATION             0x38
-   #define RW_NVRAM_PAGE                        0xBC
-   #define IPS_READ                             0x02
-   #define IPS_WRITE                            0x03
-   #define ENQUIRY                              0x05
-   #define FLUSH_CACHE                          0x0A
-   #define NORM_STATE                           0x00
-   #define READ_SCATTER_GATHER                  0x82
-   #define WRITE_SCATTER_GATHER                 0x83
-   #define DIRECT_CDB                           0x04
-   #define DIRECT_CDB_SCATTER_GATHER            0x84
-   #define CONFIG_SYNC                          0x58
-   #define POCL                                 0x30
-   #define GET_ERASE_ERROR_TABLE                0x17
-   #define RESET_CHANNEL                        0x1A
-   #define CSL                                  0xFF
-   #define ADAPT_RESET                          0xFF
+   #define GET_LOGICAL_DRIVE_INFO       0x19
+   #define GET_SUBSYS_PARAM             0x40
+   #define READ_NVRAM_CONFIGURATION     0x38
+   #define RW_NVRAM_PAGE                0xBC
+   #define IPS_READ                     0x02
+   #define IPS_WRITE                    0x03
+   #define ENQUIRY                      0x05
+   #define FLUSH_CACHE                  0x0A
+   #define NORM_STATE                   0x00
+   #define READ_SCATTER_GATHER          0x82
+   #define WRITE_SCATTER_GATHER         0x83
+   #define DIRECT_CDB                   0x04
+   #define DIRECT_CDB_SCATTER_GATHER    0x84
+   #define CONFIG_SYNC                  0x58
+   #define POCL                         0x30
+   #define GET_ERASE_ERROR_TABLE        0x17
+   #define RESET_CHANNEL                0x1A
+   #define CSL                          0xFF
+   #define ADAPT_RESET                  0xFF
 
 /*
  * Adapter Equates
  */
-   #define IPS_MAX_ADAPTERS                     16
-   #define IPS_MAX_IOCTL                        1
-   #define IPS_MAX_IOCTL_QUEUE                  8
-   #define IPS_MAX_QUEUE                        128
-   #define IPS_BLKSIZE                          512
-   #define MAX_SG_ELEMENTS                      17
-   #define MAX_LOGICAL_DRIVES                   8
-   #define MAX_CHANNELS                         3
-   #define MAX_TARGETS                          15
-   #define MAX_CHUNKS                           16
-   #define MAX_CMDS                             64
-   #define IPS_MAX_XFER                         0x10000
-   #define COMP_MODE_HEADS                      128
-   #define COMP_MODE_SECTORS                    32
-   #define NORM_MODE_HEADS                      254
-   #define NORM_MODE_SECTORS                    63
-   #define NVRAM_PAGE5_SIGNATURE                0xFFDDBB99
-   #define MAX_POST_BYTES                       0x02
-   #define MAX_CONFIG_BYTES                     0x02
-   #define GOOD_POST_BASIC_STATUS               0x80
-   #define SEMAPHORE_TIMEOUT                    2000
-   #define IPS_INTR_OFF                         0
-   #define IPS_INTR_ON                          1
-   #define IPS_ADAPTER_ID                       0xF
-   #define IPS_VENDORID                         0x1014
-   #define IPS_DEVICEID                         0x002E
-   #define TIMEOUT_10                           0x10
-   #define TIMEOUT_60                           0x20
-   #define TIMEOUT_20M                          0x30
-   #define STATUS_SIZE                          4
-   #define STATUS_Q_SIZE                        (MAX_CMDS+1) * STATUS_SIZE
-   #define ONE_MSEC                             1
-   #define ONE_SEC                              1000
+   #define IPS_MAX_ADAPTERS             16
+   #define IPS_MAX_IOCTL                1
+   #define IPS_MAX_IOCTL_QUEUE          8
+   #define IPS_MAX_QUEUE                128
+   #define IPS_BLKSIZE                  512
+   #define MAX_SG_ELEMENTS              17
+   #define MAX_LOGICAL_DRIVES           8
+   #define MAX_CHANNELS                 3
+   #define MAX_TARGETS                  15
+   #define MAX_CHUNKS                   16
+   #define MAX_CMDS                     128
+   #define IPS_MAX_XFER                 0x10000
+   #define COMP_MODE_HEADS              128
+   #define COMP_MODE_SECTORS            32
+   #define NORM_MODE_HEADS              254
+   #define NORM_MODE_SECTORS            63
+   #define NVRAM_PAGE5_SIGNATURE        0xFFDDBB99
+   #define MAX_POST_BYTES               0x02
+   #define MAX_CONFIG_BYTES             0x02
+   #define GOOD_POST_BASIC_STATUS       0x80
+   #define SEMAPHORE_TIMEOUT            2000
+   #define IPS_INTR_OFF                 0
+   #define IPS_INTR_ON                  1
+   #define IPS_ADAPTER_ID               0xF
+   #define IPS_VENDORID                 0x1014
+   #define IPS_DEVICEID                 0x002E
+   #define TIMEOUT_10                   0x10
+   #define TIMEOUT_60                   0x20
+   #define TIMEOUT_20M                  0x30
+   #define STATUS_SIZE                  4
+   #define STATUS_Q_SIZE                (MAX_CMDS+1) * STATUS_SIZE
+   #define ONE_MSEC                     1
+   #define ONE_SEC                      1000
 
 /*
  * Adapter Basic Status Codes
@@ -195,24 +195,24 @@
 /*
  * Adapter Extended Status Equates
  */
-   #define SELECTION_TIMEOUT                    0xF0
-   #define DATA_OVER_UNDER_RUN                  0xF2
-   #define EXT_HOST_RESET                       0xF7
-   #define EXT_DEVICE_RESET                     0xF8
-   #define EXT_RECOVERY                         0xFC
-   #define EXT_CHECK_CONDITION                  0xFF
+   #define SELECTION_TIMEOUT            0xF0
+   #define DATA_OVER_UNDER_RUN          0xF2
+   #define EXT_HOST_RESET               0xF7
+   #define EXT_DEVICE_RESET             0xF8
+   #define EXT_RECOVERY                 0xFC
+   #define EXT_CHECK_CONDITION          0xFF
 
 /*
  * Operating System Defines
  */
-   #define OS_WINDOWS_NT                        0x01
-   #define OS_NETWARE                           0x02
-   #define OS_OPENSERVER                        0x03
-   #define OS_UNIXWARE                          0x04
-   #define OS_SOLARIS                           0x05
-   #define OS_OS2                               0x06
-   #define OS_LINUX                             0x07
-   #define OS_FREEBSD                           0x08
+   #define OS_WINDOWS_NT                0x01
+   #define OS_NETWARE                   0x02
+   #define OS_OPENSERVER                0x03
+   #define OS_UNIXWARE                  0x04
+   #define OS_SOLARIS                   0x05
+   #define OS_OS2                       0x06
+   #define OS_LINUX                     0x07
+   #define OS_FREEBSD                   0x08
 
 /*
  * Adapter Command/Status Packet Definitions
@@ -224,26 +224,28 @@
 /*
  * Logical Drive Equates
  */
-   #define OFF_LINE             0x02
-   #define OKAY                 0x03
-   #define FREE                 0x00
-   #define SYS                  0x06
-   #define CRS                  0x24
+   #define OFF_LINE                     0x02
+   #define OKAY                         0x03
+   #define FREE                         0x00
+   #define SYS                          0x06
+   #define CRS                          0x24
 
 /*
  * DCDB Table Equates
  */
+#ifndef HOSTS_C 
    #define NO_DISCONNECT                0x00
    #define DISCONNECT_ALLOWED           0x80
    #define NO_AUTO_REQUEST_SENSE        0x40
-   #define DATA_IN                      0x01
-   #define DATA_OUT                     0x02
+   #define IPS_DATA_NONE                0x00
+   #define IPS_DATA_UNK                 0x00
+   #define IPS_DATA_IN                  0x01
+   #define IPS_DATA_OUT                 0x02
    #define TRANSFER_64K                 0x08
    #define NOTIMEOUT                    0x00
    #define TIMEOUT10                    0x10
    #define TIMEOUT60                    0x20
    #define TIMEOUT20M                   0x30
-
 /*
  * Host adapter Flags (bit numbers)
  */
@@ -256,7 +258,7 @@
  */
    #define SCB_ACTIVE                   0x00001
    #define SCB_WAITING                  0x00002
-
+#endif /* HOSTS_C */
 /*
  * Passthru stuff
  */
@@ -590,6 +592,8 @@
 /*
  * Inquiry Data Format
  */
+#ifndef HOSTS_C
+
 typedef struct {
    u8        DeviceType:5;
    u8        DeviceTypeQualifier:3;
@@ -614,6 +618,7 @@
    u8        Reserved3[40];
 } INQUIRYDATA, *PINQUIRYDATA;
 
+#endif
 /*
  * Read Capacity Data Format
  */
@@ -734,6 +739,7 @@
 
 typedef struct ips_ha {
    u8                 ha_id[MAX_CHANNELS+1];
+   u32                dcdb_active[MAX_CHANNELS];
    u32                io_addr;            /* Base I/O address           */
    u8                 irq;                /* IRQ for adapter            */
    u8                 ntargets;           /* Number of targets          */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/megaraid.c linux.14p16/drivers/scsi/megaraid.c
--- linux.vanilla/drivers/scsi/megaraid.c	Sat Aug 28 20:00:57 1999
+++ linux.14p16/drivers/scsi/megaraid.c	Thu Dec  9 15:33:55 1999
@@ -9,7 +9,7 @@
  *              as published by the Free Software Foundation; either version
  *              2 of the License, or (at your option) any later version.
  *
- * Version : 1.04
+ * Version : 1.05
  * 
  * Description: Linux device driver for AMI MegaRAID controller
  *
@@ -111,6 +111,16 @@
  *    The addtional 32 bit field for 64bit address in the newly defined
  *      mailbox64 structure is set to 0 at this point.
  *
+ * Version 1.05
+ *    Changed the queing implementation for handling SCBs and completed
+ *      commands.
+ *    Added spinlocks in the interrupt service routine to enable the dirver
+ *      function in the SMP environment.
+ *    Fixed the problem of unnecessary aborts in the abort entry point, which
+ *      also enables the driver to handle large amount of I/O requests for
+ *      long duration of time.
+ *
+ *
  * BUGS:
  *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
  *     fails to detect the controller as a pci device on the system.
@@ -125,7 +135,8 @@
 #define CRLFSTR "\n"
 #define IOCTL_CMD_NEW  0x81
 
-#define MEGARAID_VERSION "v1.04 (August 16, 1999)"
+#define MEGARAID_VERSION "v1.05 (October 27, 1999)"
+
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -145,8 +156,6 @@
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/malloc.h>
 #include <linux/ioport.h>
 #include <linux/fcntl.h>
 #include <linux/delay.h>
@@ -209,31 +218,6 @@
 #define MAX_SERBUF 160
 #define COM_BASE 0x2f8
 
-#define ENQUEUE(obj,type,list,next) \
-{ type **node; long cpuflag; \
-  spin_lock_irqsave(&mega_lock,cpuflag);\
-  for(node=&(list); *node; node=(type **)&(*node)->##next); \
-  (*node) = obj; \
-  (*node)->##next = NULL; \
-  spin_unlock_irqrestore(&mega_lock,cpuflag);\
-}
-
-/* a non-locking version (if we already have the lock) */
-#define ENQUEUE_NL(obj,type,list,next) \
-{ type **node; \
-  for(node=&(list); *node; node=(type **)&(*node)->##next); \
-  (*node) = obj; \
-  (*node)->##next = NULL; \
-}
-
-#define DEQUEUE(obj,type,list,next) \
-{ long cpuflag; \
-  spin_lock_irqsave(&mega_lock,cpuflag);\
-  if ((obj=list) != NULL) {\
-    list = (type *)(list)->##next; \
-  } \
-  spin_unlock_irqrestore(&mega_lock,cpuflag);\
-};
 
 u32 RDINDOOR (mega_host_config * megaCfg)
 {
@@ -265,19 +249,67 @@
 			 u_char * mboxData,
 			 mega_scb * scb,
 			 int intr);
-static int build_sglist (mega_host_config * megaCfg, mega_scb * scb,
+static int mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
 			 u32 * buffer, u32 * length);
 
 static int mega_busyWaitMbox(mega_host_config *);
 static void mega_runpendq (mega_host_config *);
-static void mega_rundoneq (void);
+static void mega_rundoneq (mega_host_config *);
 static void mega_cmd_done (mega_host_config *, mega_scb *, int);
 static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt);
-static inline void freeSgList(mega_host_config *megaCfg);
+static inline void mega_freeSgList(mega_host_config *megaCfg);
 static void mega_Convert8ldTo40ld(  mega_RAIDINQ  *inquiry,
                                     mega_Enquiry3 *enquiry3,
                                     megaRaidProductInfo *productInfo );
 
+
+
+
+
+#if LINUX_VERSION_CODE > 0x020100
+#  include <asm/spinlock.h>
+#  include <linux/smp.h>
+#  define cpuid smp_processor_id()
+#  if LINUX_VERSION_CODE < 0x020195
+#    define DRIVER_LOCK_T unsigned long cpu_flags = 0;
+#    define DRIVER_LOCK_INIT(p) \
+       spin_lock_init(&p->mega_lock);
+#    define DRIVER_LOCK(p) \
+       if(!p->cpu_lock_count[cpuid]) { \
+         spin_lock_irqsave(&p->mega_lock, cpu_flags); \
+         p->cpu_lock_count[cpuid]++; \
+       } else { \
+         p->cpu_lock_count[cpuid]++; \
+       }
+#    define DRIVER_UNLOCK(p) \
+       if(--p->cpu_lock_count[cpuid] == 0) \
+         spin_unlock_irqrestore(&p->mega_lock, cpu_flags);
+#    define IO_LOCK(p)   spin_lock_irqsave(&io_request_lock,cpu_flags);
+#    define IO_UNLOCK(p) spin_unlock_irqrestore(&io_request_lock,cpu_flags);
+#  else
+#    define DRIVER_LOCK_T
+#    define DRIVER_LOCK_INIT(p)
+#    define DRIVER_LOCK(p)
+#    define DRIVER_UNLOCK(p)
+#    define IO_LOCK_T unsigned long io_flags = 0;
+#    define IO_LOCK spin_lock_irqsave(&io_request_lock,io_flags);
+#    define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags);
+#  endif
+#else
+#  define cpuid 0
+#  define DRIVER_LOCK_T long cpu_flags;
+#  define DRIVER_LOCK_INIT(p)
+#  define DRIVER_LOCK(p) \
+       save_flags(cpu_flags); \
+       cli();
+#  define DRIVER_UNLOCK(p) \
+       restore_flags(cpu_flags);
+#  define IO_LOCK(p)   DRIVER_LOCK(p)
+#  define IO_UNLOCK(p) DRIVER_UNLOCK(p)
+#  define le32_to_cpu(x) (x)
+#  define cpu_to_le32(x) (x)
+#endif
+
 /* set SERDEBUG to 1 to enable serial debugging */
 #define SERDEBUG 0
 #if SERDEBUG
@@ -314,13 +346,11 @@
 
 static mega_scb *pLastScb = NULL;
 
-/* Queue of pending/completed SCBs */
-static Scsi_Cmnd *qCompleted = NULL;
 
 #if SERDEBUG
 volatile static spinlock_t serial_lock;
 #endif
-volatile static spinlock_t mega_lock;
+//volatile static spinlock_t mega_lock;
 
 struct proc_dir_entry proc_scsi_megaraid =
 {
@@ -386,7 +416,7 @@
 #define TRACE(A)
 #endif
 
-void callDone (Scsi_Cmnd * SCpnt)
+static void callDone (Scsi_Cmnd * SCpnt)
 {
   if (SCpnt->result) {
     TRACE (("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number,
@@ -406,37 +436,66 @@
  * Free a SCB structure
  *=======================
  */
-static void freeSCB (mega_host_config *megaCfg, mega_scb * pScb)
+static void mega_freeSCB (mega_host_config *megaCfg, mega_scb * pScb)
 {
-  mega_scb **ppScb;
+
+  mega_scb *pScbtmp;
+
+  if ((pScb == NULL) || (pScb->idx >= 0xFE)) {
+    return ;
+  }
 
   /* Unlink from pending queue */
-  for(ppScb=&megaCfg->qPending; *ppScb; ppScb=&(*ppScb)->next) {
-    if (*ppScb == pScb) {
-	*ppScb = pScb->next;
+
+  if(pScb == megaCfg->qPendingH) {
+    if(megaCfg->qPendingH == megaCfg->qPendingT ) 
+      megaCfg->qPendingH = megaCfg->qPendingT = NULL;
+    else {
+      megaCfg->qPendingH = megaCfg->qPendingH->next;
+    }
+    megaCfg->qPcnt--;
+  }
+  else {
+    for(pScbtmp=megaCfg->qPendingH; pScbtmp; pScbtmp=pScbtmp->next) {
+      if (pScbtmp->next == pScb) {
+        pScbtmp->next = pScb->next;
+        if(pScb == megaCfg->qPendingT) {
+          megaCfg->qPendingT = pScbtmp;
+        }
+        megaCfg->qPcnt--;
 	break;
     }
   }
+  }
 
-  /* Link back into list */
+  /* Link back into free list */
   pScb->state = SCB_FREE;
   pScb->SCpnt = NULL;
 
-  pScb->next     = megaCfg->qFree;
-  megaCfg->qFree = pScb;
+  if(megaCfg->qFreeH == (mega_scb *) NULL ) {
+    megaCfg->qFreeH = megaCfg->qFreeT = pScb;
+  }
+  else {
+    megaCfg->qFreeT->next  = pScb;
+    megaCfg->qFreeT = pScb;
+  }
+  megaCfg->qFreeT->next = NULL;
+  megaCfg->qFcnt++;
+
 }
 
 /*===========================
  * Allocate a SCB structure
  *===========================
  */
-static mega_scb * allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+static mega_scb * mega_allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
 {
   mega_scb *pScb;
 
   /* Unlink command from Free List */
-  if ((pScb = megaCfg->qFree) != NULL) {
-    megaCfg->qFree = pScb->next;
+  if ((pScb = megaCfg->qFreeH) != NULL) {
+    megaCfg->qFreeH = pScb->next;
+    megaCfg->qFcnt--;
     
     pScb->isrcount = jiffies;
     pScb->next  = NULL;
@@ -455,62 +514,72 @@
  * Initialize SCB structures
  *================================================
  */
-static int initSCB (mega_host_config * megaCfg)
+static int mega_initSCB (mega_host_config * megaCfg)
 {
   int idx;
 
-  megaCfg->qFree = NULL;
+  megaCfg->qFreeH = NULL;
+  megaCfg->qFcnt = 0;
+#if DEBUG
+if(megaCfg->max_cmds >= MAX_COMMANDS) {
+printk("megaraid:ctlr max cmds = %x : MAX_CMDS = %x", megaCfg->max_cmds, MAX_COMMANDS);
+}
+#endif
+
   for (idx = megaCfg->max_cmds-1; idx >= 0; idx--) {
     megaCfg->scbList[idx].idx    = idx;
     megaCfg->scbList[idx].sgList = kmalloc(sizeof(mega_sglist) * MAX_SGLIST,
 					   GFP_ATOMIC | GFP_DMA);
     if (megaCfg->scbList[idx].sgList == NULL) {
       printk(KERN_WARNING "Can't allocate sglist for id %d\n",idx);
-      freeSgList(megaCfg);
+      mega_freeSgList(megaCfg);
       return -1;
     }
     
     if (idx < MAX_COMMANDS) {
       /* Link to free list */
-      freeSCB(megaCfg, &megaCfg->scbList[idx]);
+      mega_freeSCB(megaCfg, &megaCfg->scbList[idx]);
     }
   }
   return 0;
 }
 
 /* Run through the list of completed requests */
-static void mega_rundoneq ()
+static void mega_rundoneq (mega_host_config *megaCfg)
 {
   Scsi_Cmnd *SCpnt;
 
-  while (1) {
-    DEQUEUE (SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
-    if (SCpnt == NULL)
-      return;
+  while ((SCpnt = megaCfg->qCompletedH) != NULL) {
+    megaCfg->qCompletedH = (Scsi_Cmnd *)SCpnt->host_scribble;
+    megaCfg->qCcnt--;
 
+    SCpnt->host_scribble = (unsigned char *) NULL ; // XC : sep 14
     /* Callback */
     callDone (SCpnt);
   }
+  megaCfg->qCompletedH = megaCfg->qCompletedT = NULL;
 }
 
 /*
-  Runs through the list of pending requests
-  Assumes that mega_lock spin_lock has been acquired.
-*/
+ * Runs through the list of pending requests
+ * Assumes that mega_lock spin_lock has been acquired.
+ */
 static void mega_runpendq(mega_host_config *megaCfg)
 {
   mega_scb *pScb;
 
   /* Issue any pending commands to the card */
-  for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) {
+  for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) {
     if (pScb->state == SCB_ACTIVE) {
-      megaIssueCmd(megaCfg, pScb->mboxData, pScb, 1);
+      if(megaIssueCmd(megaCfg, pScb->mboxData, pScb, 1))
+	return;
     }
   }
 }
 
 /* Add command to the list of completed requests */
-static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, 
+static void
+mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, 
 			   int status)
 {
   int islogical;
@@ -533,7 +602,7 @@
 	TRACE(("pScb->idx = ",pScb->idx));
 	TRACE(("pScb->state = ",pScb->state));
 	TRACE(("pScb->state = ",pScb->state));
-	printk("Problem...!\n");
+	printk("megaraid:Problem...!\n");
 	while(1);
   }
 
@@ -588,10 +657,18 @@
   /* not IOCTL_CMD_NEW SCB, freeSCB()*/
   /* For IOCTL_CMD_NEW SCB, delay freeSCB() in megaraid_queue()
    * after copy data back to user space*/
-     freeSCB(megaCfg, pScb);
+     mega_freeSCB(megaCfg, pScb);
 
   /* Add Scsi_Command to end of completed queue */
-  ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+    if( megaCfg->qCompletedH == NULL ) {
+      megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+    }
+    else {
+      megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+      megaCfg->qCompletedT = SCpnt;
+   }
+   megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+   megaCfg->qCcnt++;
 }
 
 /*-------------------------------------------------------------------
@@ -661,7 +738,7 @@
     case READ_CAPACITY:
     case INQUIRY:
       /* Allocate a SCB and initialize passthru */
-      if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) {
+      if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
 	SCpnt->result = (DID_ERROR << 16);
 	callDone (SCpnt);
 	return NULL;
@@ -692,7 +769,7 @@
     case READ_10:
     case WRITE_10:
       /* Allocate a SCB and initialize mailbox */
-      if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) {
+      if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
 	SCpnt->result = (DID_ERROR << 16);
 	callDone (SCpnt);
 	return NULL;
@@ -728,7 +805,7 @@
       }
 
       /* Calculate Scatter-Gather info */
-      mbox->numsgelements = build_sglist (megaCfg, pScb,
+      mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
 					  (u32 *) & mbox->xferaddr,
 					  (u32 *) & seg);
 
@@ -747,7 +824,7 @@
    *-----------------------------------------------------*/
   else {
     /* Allocate a SCB and initialize passthru */
-    if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) {
+    if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
       SCpnt->result = (DID_ERROR << 16);
       callDone (SCpnt);
       return NULL;
@@ -768,7 +845,7 @@
     pthru->cdblen = SCpnt->cmd_len;
     memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
 
-    pthru->numsgelements = build_sglist (megaCfg, pScb,
+    pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
 					 (u32 *) & pthru->dataxferaddr,
 					 (u32 *) & pthru->dataxferlen);
 
@@ -795,19 +872,12 @@
   unsigned char *data = (unsigned char *)SCpnt->request_buffer;
   int i;
 
-  if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) {
+  if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
     SCpnt->result = (DID_ERROR << 16);
     callDone (SCpnt);
     return NULL;
   }
 
-#if 0
-  printk("\nBUF: ");
-  for (i=0;i<18;i++) {
-     printk(" %x",data[i]);
-  }
-  printk("......\n");
-#endif
 
   mboxdata = (u8 *) & pScb->mboxData;
   mbox = (mega_ioctl_mbox *) & pScb->mboxData;
@@ -831,7 +901,7 @@
     mailbox->cmd = MEGA_MBOXCMD_PASSTHRU;
     mailbox->xferaddr = virt_to_bus (pthru);
 
-    pthru->numsgelements = build_sglist (megaCfg, pScb,
+    pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
 					 (u32 *) & pthru->dataxferaddr,
 					 (u32 *) & pthru->dataxferlen);
 
@@ -890,7 +960,7 @@
   } 
   else {
 
-      mbox->numsgelements = build_sglist (megaCfg, pScb,
+      mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
 				      (u32 *) & mbox->xferaddr,
 				      (u32 *) & seg);
 
@@ -918,32 +988,35 @@
 }
 #endif
 
+#if DEBUG
+static unsigned int cum_time = 0;
+static unsigned int cum_time_cnt = 0;
+#endif
+
 /*--------------------------------------------------------------------
  * Interrupt service routine
  *--------------------------------------------------------------------*/
 static void megaraid_isr (int irq, void *devp, struct pt_regs *regs)
 {
+  IO_LOCK_T
   mega_host_config    *megaCfg;
   u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE];
-  u32 dword;
+  u32 dword=0;
   mega_mailbox *mbox;
   mega_scb *pScb;
-  long flags;
-  int qCnt, qStatus;
+  u_char qCnt, qStatus;
+  u_char            completed[MAX_FIRMWARE_STATUS];
+  Scsi_Cmnd *SCpnt;
 
   megaCfg = (mega_host_config *) devp;
   mbox = (mega_mailbox *)tmpBox;
 
-#if LINUX_VERSION_CODE >= 0x20100
-  spin_lock_irqsave (&io_request_lock, flags);
-#endif
-
-  while (megaCfg->host->irq == irq) {
 
-    spin_lock_irqsave (&mega_lock, flags);
+  if (megaCfg->host->irq == irq) {
 
     if (megaCfg->flag & IN_ISR) {
       TRACE (("ISR called reentrantly!!\n"));
+      printk ("ISR called reentrantly!!\n");
     }
 
     megaCfg->flag |= IN_ISR;
@@ -952,48 +1025,75 @@
 	printk(KERN_WARNING "Error: mailbox busy in isr!\n");
     }
 
-
     /* Check if a valid interrupt is pending */
     if (megaCfg->flag & BOARD_QUARTZ) {
       dword = RDOUTDOOR (megaCfg);
       if (dword != 0x10001234) {
 	/* Spurious interrupt */
 	megaCfg->flag &= ~IN_ISR;
-	spin_unlock_irqrestore (&mega_lock, flags);
-	break;
+//#if LINUX_VERSION_CODE >= 0x20100
+//        IO_UNLOCK;
+//#endif
+//	break;
+	return;
       }
-      WROUTDOOR (megaCfg, dword);
-
-      /* Copy to temp location */
-      memcpy(tmpBox, (mega_mailbox *)megaCfg->mbox, MAILBOX_SIZE);
-
-      /* Acknowledge interrupt */
-      WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
-      while (RDINDOOR (megaCfg) & 0x02);
     }
     else {
       byte = READ_PORT (megaCfg->host->io_port, INTR_PORT);
       if ((byte & VALID_INTR_BYTE) == 0) {
 	/* Spurious interrupt */
 	megaCfg->flag &= ~IN_ISR;
-	spin_unlock_irqrestore (&mega_lock, flags);
-	break;
+//#if LINUX_VERSION_CODE >= 0x20100
+//	IO_UNLOCK;
+//#endif
+//	break;
+	return;
       }
       WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
+    }
+
+    for(idx=0;idx<MAX_FIRMWARE_STATUS;idx++ ) completed[idx] = 0;
+
+#if LINUX_VERSION_CODE >= 0x20100
+    IO_LOCK;
+#endif
+
+    qCnt = 0xff;
+    while ((qCnt = megaCfg->mbox->numstatus) == 0xFF) 
+      ;
 
-      /* Copy to temp location */
-      memcpy(tmpBox, (mega_mailbox *)megaCfg->mbox, MAILBOX_SIZE);
+    qStatus = 0xff;
+    while ((qStatus = megaCfg->mbox->status) == 0xFF)
+      ;
 
+    /* Get list of completed requests */
+    for (idx = 0; idx<qCnt; idx++) {
+      while ((sIdx = megaCfg->mbox->completed[idx]) == 0xFF) {
+	printk("p");
+      }
+      completed[idx] = sIdx;
+      sIdx = 0xFF;
+    }
+
+    if (megaCfg->flag & BOARD_QUARTZ) {
+      WROUTDOOR (megaCfg, dword);
       /* Acknowledge interrupt */
+      WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
+      while (RDINDOOR (megaCfg) & 0x02);
+    }
+    else {
       CLEAR_INTR (megaCfg->host->io_port);
     }
 
-    qCnt = mbox->numstatus;
-    qStatus = mbox->status;
+#if DEBUG
+    if(qCnt >= MAX_FIRMWARE_STATUS) {
+      printk("megaraid_isr: cmplt=%d ", qCnt);
+    }
+#endif
 
     for (idx = 0; idx < qCnt; idx++) {
-      sIdx = mbox->completed[idx];
-      if (sIdx > 0) {
+      sIdx = completed[idx];
+      if ((sIdx > 0) && (sIdx <= MAX_COMMANDS)) {
 	pScb = &megaCfg->scbList[sIdx - 1];
 
 	/* ASSERT(pScb->state == SCB_ISSUED); */
@@ -1001,12 +1101,33 @@
 #if DEBUG
 	if (((jiffies) - pScb->isrcount) > maxCmdTime) {
 	  maxCmdTime = (jiffies) - pScb->isrcount;
-	  printk("cmd time = %u\n", maxCmdTime);
+	  printk("megaraid_isr : cmd time = %u\n", maxCmdTime);
 	}
 #endif
-
+/*
+ * Assuming that the scsi command, for which an abort request was received
+ * earlier has completed.
+ */
 	if (pScb->state == SCB_ABORTED) {
-	  printk("Received aborted SCB! %u\n", (int)((jiffies)-pScb->isrcount));
+          SCpnt = pScb->SCpnt;
+#if DEBUG
+printk("megaraid_isr:fcnt=%d, pcnt=%d, qcnt=%d\n",megaCfg->qFcnt, megaCfg->qPcnt, megaCfg->qCcnt); 
+#endif
+	}
+	if (pScb->state == SCB_RESET) {
+          SCpnt = pScb->SCpnt;
+	  mega_freeSCB (megaCfg, pScb);
+	  SCpnt->result = (DID_RESET << 16) ;
+          if( megaCfg->qCompletedH == NULL ) {
+            megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+          }
+          else {
+            megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+            megaCfg->qCompletedT = SCpnt;
+          }
+          megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+          megaCfg->qCcnt++;
+          continue;
 	}
 
         if (*(pScb->SCpnt->cmnd)==IOCTL_CMD_NEW) 
@@ -1017,24 +1138,23 @@
 	mega_cmd_done(megaCfg, pScb, qStatus);
 
       }
-
+      else {
+        printk("megaraid: wrong cmd id completed from firmware:id=%x\n",sIdx);
+	for(;;);
+      }
     }
-    spin_unlock_irqrestore (&mega_lock, flags);
 
-    megaCfg->flag &= ~IN_ISR;
-
-    mega_rundoneq();
+    mega_rundoneq(megaCfg);
 
+    megaCfg->flag &= ~IN_ISR;
     /* Loop through any pending requests */
-    spin_lock_irqsave(&mega_lock, flags);
     mega_runpendq(megaCfg);
-    spin_unlock_irqrestore(&mega_lock,flags);
+#if LINUX_VERSION_CODE >= 0x20100
+    IO_UNLOCK;
+#endif
 
   }
 
-#if LINUX_VERSION_CODE >= 0x20100
-  spin_unlock_irqrestore (&io_request_lock, flags);
-#endif
 }
 
 /*==================================================*/
@@ -1078,7 +1198,6 @@
   mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
   u_char byte;
   u32 cmdDone;
-  Scsi_Cmnd *SCpnt;
   u32 phys_mbox;
   u8 retval=-1;
 
@@ -1087,18 +1206,15 @@
 
   phys_mbox = virt_to_bus (megaCfg->mbox);
 
-#if 0
-  if (intr && mbox->busy) {
-    return 0;
-  }
-#endif
-
 #if DEBUG
   showMbox(pScb);
 #endif
 
   /* Wait until mailbox is free */
-  while (mega_busyWaitMbox (megaCfg)) {
+#if 0
+  while (mega_busyWaitMbox (megaCfg))
+#endif
+  if (mega_busyWaitMbox (megaCfg)) {
     printk("Blocked mailbox......!!\n");
     udelay(1000);
 
@@ -1108,14 +1224,10 @@
     
     /* Abort command */
     if (pScb == NULL) {
-	printk("NULL pScb in megaIssue\n");
 	TRACE(("NULL pScb in megaIssue\n"));
+	printk("NULL pScb in megaIssue\n");
     }
-    SCpnt = pScb->SCpnt;
-    freeSCB(megaCfg, pScb);
-
-    SCpnt->result = (DID_ABORT << 16);
-    callDone(SCpnt);
+    mega_cmd_done (megaCfg, pScb, 0x08);
     return -1;
   }
 
@@ -1154,7 +1266,7 @@
 
       if (pScb) {
 	mega_cmd_done (megaCfg, pScb, mbox->status);
-	mega_rundoneq ();
+//	mega_rundoneq (megaCfg);
       }
 
       WRINDOOR (megaCfg, phys_mbox | 0x2);
@@ -1168,26 +1280,26 @@
       while (!((byte = READ_PORT (megaCfg->host->io_port, INTR_PORT)) & INTR_VALID));
       WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
 
-
       ENABLE_INTR (megaCfg->host->io_port);
       CLEAR_INTR (megaCfg->host->io_port);
 
       if (pScb) {
 	mega_cmd_done (megaCfg, pScb, mbox->status);
-	mega_rundoneq ();
+//	mega_rundoneq (megaCfg);
       }
       else {
 	TRACE (("Error: NULL pScb!\n"));
       }
-
     }
     enable_irq(megaCfg->host->irq);
     retval=mbox->status;
   }
+#if DEBUG
   while (mega_busyWaitMbox (megaCfg)) {
     printk("Blocked mailbox on exit......!\n");
     udelay(1000);
   }
+#endif
 
   return retval;
 }
@@ -1195,7 +1307,7 @@
 /*-------------------------------------------------------------------
  * Copies data to SGLIST
  *-------------------------------------------------------------------*/
-static int build_sglist (mega_host_config * megaCfg, mega_scb * scb,
+static int mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
 	      u32 * buffer, u32 * length)
 {
   struct scatterlist *sgList;
@@ -1254,9 +1366,7 @@
   paddr = (paddr + 4 + 16) & 0xfffffff0;
 
   /* Register mailbox area with the firmware */
-  if (megaCfg->flag & BOARD_QUARTZ) {
-  }
-  else {
+  if (!(megaCfg->flag & BOARD_QUARTZ)) {
     WRITE_PORT (megaCfg->host->io_port, MBOX_PORT0, paddr & 0xFF);
     WRITE_PORT (megaCfg->host->io_port, MBOX_PORT1, (paddr >> 8) & 0xFF);
     WRITE_PORT (megaCfg->host->io_port, MBOX_PORT2, (paddr >> 16) & 0xFF);
@@ -1314,7 +1424,6 @@
   u32 paddr;
   u8 retval;
 
-  spin_lock_init (&mega_lock);
 
   /* Initialize adapter inquiry mailbox*/
   paddr = virt_to_bus (megaCfg->mega_buffer);
@@ -1375,9 +1484,17 @@
     /*(megaCfg->flag & BOARD_40LD)?FC_MAX_TARGETS_PER_CHANNEL:MAX_TARGET+1;*/ 
   megaCfg->host->max_lun =              /* max lun */
     (megaCfg->flag & BOARD_40LD) ? FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES; 
+  megaCfg->host->cmd_per_lun = MAX_CMD_PER_LUN;
 
   megaCfg->numldrv = enquiry3Pnt->numLDrv;
   megaCfg->max_cmds = megaCfg->productInfo.MaxConcCmds;
+  if(megaCfg->max_cmds > MAX_COMMANDS) megaCfg->max_cmds = MAX_COMMANDS - 1;
+
+  megaCfg->host->can_queue   = megaCfg->max_cmds;
+
+  if (megaCfg->host->can_queue >= MAX_COMMANDS) {
+    megaCfg->host->can_queue = MAX_COMMANDS-1;
+  }
 
 #if 0 
   int i;
@@ -1443,7 +1560,7 @@
   return 0;
 }
 
-int findCard (Scsi_Host_Template * pHostTmpl,
+int mega_findCard (Scsi_Host_Template * pHostTmpl,
 	  u16 pciVendor, u16 pciDev,
 	  long flag)
 {
@@ -1518,8 +1635,15 @@
 	    host->host_no, (u_int) megaBase, megaIrq);
 
     /* Copy resource info into structure */
-    megaCfg->qPending = NULL;
-    megaCfg->qFree    = NULL;
+    megaCfg->qCompletedH = NULL;
+    megaCfg->qCompletedT = NULL;
+    megaCfg->qPendingH = NULL;
+    megaCfg->qPendingT = NULL;
+    megaCfg->qFreeH    = NULL;
+    megaCfg->qFreeT    = NULL;
+    megaCfg->qFcnt = 0;
+    megaCfg->qPcnt = 0;
+    megaCfg->qCcnt = 0;
     megaCfg->flag = flag;
     megaCfg->host = host;
     megaCfg->base = megaBase;
@@ -1551,7 +1675,7 @@
     mega_i_query_adapter (megaCfg);
     
     /* Initialize SCBs */
-    if (initSCB (megaCfg)) {
+    if (mega_initSCB (megaCfg)) {
       scsi_unregister (host);
       continue;
     }
@@ -1589,9 +1713,9 @@
 
   printk ("megaraid: " MEGARAID_VERSION CRLFSTR);
 
-  count += findCard (pHostTmpl, 0x101E, 0x9010, 0);
-  count += findCard (pHostTmpl, 0x101E, 0x9060, 0);
-  count += findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);
+  count += mega_findCard (pHostTmpl, 0x101E, 0x9010, 0);
+  count += mega_findCard (pHostTmpl, 0x101E, 0x9060, 0);
+  count += mega_findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);
 
   return count;
 }
@@ -1626,13 +1750,13 @@
     release_region (megaCfg->host->io_port, 16);
   }
 
-  freeSgList(megaCfg);
+  mega_freeSgList(megaCfg);
   scsi_unregister (pSHost);
 
   return 0;
 }
 
-static inline void freeSgList(mega_host_config *megaCfg)
+static inline void mega_freeSgList(mega_host_config *megaCfg)
 {
   int i;
 
@@ -1678,13 +1802,12 @@
  *-----------------------------------------------------------------*/
 int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *))
 {
+  DRIVER_LOCK_T
   mega_host_config *megaCfg;
   mega_scb *pScb;
-  long flags;
-
-  spin_lock_irqsave(&mega_lock,flags);
 
   megaCfg = (mega_host_config *) SCpnt->host->hostdata;
+  DRIVER_LOCK(megaCfg);
 
   if (!(megaCfg->flag & (1L << SCpnt->channel))) {
     if (SCpnt->channel < SCpnt->host->max_channel)
@@ -1701,33 +1824,69 @@
 
   /* If driver in abort or reset.. cancel this command */
   if (megaCfg->flag & IN_ABORT) {
+#if DEBUG
+printk("mq: got a request while in abort\n");
+#endif
     SCpnt->result = (DID_ABORT << 16);
-    ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+    /* Add Scsi_Command to end of completed queue */
+    if( megaCfg->qCompletedH == NULL ) {
+      megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+    }
+    else {
+      megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+      megaCfg->qCompletedT = SCpnt;
+    }
+    megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+    megaCfg->qCcnt++;
 
-    spin_unlock_irqrestore(&mega_lock,flags);
+    DRIVER_UNLOCK(megaCfg);
     return 0;
   }
   else if (megaCfg->flag & IN_RESET) {
+#if DEBUG
+printk("mq: got a request while in reset\n");
+#endif
     SCpnt->result = (DID_RESET << 16);
-    ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+    /* Add Scsi_Command to end of completed queue */
+    if( megaCfg->qCompletedH == NULL ) {
+      megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+    }
+    else {
+      megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+      megaCfg->qCompletedT = SCpnt;
+    }
+    megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+    megaCfg->qCcnt++;
 
-    spin_unlock_irqrestore(&mega_lock,flags);
+    DRIVER_UNLOCK(megaCfg);
     return 0;
   }
 
+  megaCfg->flag |= IN_QUEUE;
   /* Allocate and build a SCB request */
   if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) {
               /*build SCpnt for IOCTL_CMD_NEW cmd in mega_ioctl()*/
     /* Add SCB to the head of the pending queue */
-    ENQUEUE_NL (pScb, mega_scb, megaCfg->qPending, next);
-
-    /* Issue any pending command to the card if not in ISR */
-    if (!(megaCfg->flag & IN_ISR)) {
-      mega_runpendq(megaCfg);
+    /* Add SCB to the head of the pending queue */
+    if( megaCfg->qPendingH == NULL ) {
+      megaCfg->qPendingH = megaCfg->qPendingT = pScb;
     }
     else {
-      printk("IRQ pend...\n");
+      megaCfg->qPendingT->next = pScb;
+      megaCfg->qPendingT = pScb;
     }
+    megaCfg->qPendingT->next = NULL;
+    megaCfg->qPcnt++;
+
+
+    /* Issue any pending command to the card if not in ISR */
+//    if (!(megaCfg->flag & IN_ISR)) {
+      mega_runpendq(megaCfg);
+//    }
+/* 
+ * try running the pend queue, irrespective of the driver's context.
+ * -cn 
+ */
 
     if ( SCpnt->cmnd[0]==IOCTL_CMD_NEW )
     {  /* user data from external user buffer */
@@ -1744,12 +1903,12 @@
 
           kfree(pScb->kern_area);
 
-          freeSCB(megaCfg, pScb);
+          mega_freeSCB(megaCfg, pScb);
     }
-
   }
 
-  spin_unlock_irqrestore(&mega_lock,flags);
+  megaCfg->flag &= ~IN_QUEUE;
+  DRIVER_UNLOCK(megaCfg);
 
   return 0;
 }
@@ -1787,41 +1946,70 @@
 /*---------------------------------------------------------------------
  * Abort a previous SCSI request
  *---------------------------------------------------------------------*/
-int megaraid_abort (Scsi_Cmnd * SCpnt)
+int
+megaraid_abort (Scsi_Cmnd * SCpnt)
 {
   mega_host_config *megaCfg;
-  int   rc, idx;
-  long  flags;
+  int   rc; //, idx;
   mega_scb *pScb;
 
-  rc = SCSI_ABORT_SUCCESS;
-
-  spin_lock_irqsave (&mega_lock, flags);
+  rc = SCSI_ABORT_NOT_RUNNING;
 
   megaCfg = (mega_host_config *) SCpnt->host->hostdata;
 
   megaCfg->flag |= IN_ABORT;
 
-  for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) {
+#if DEBUG
+printk("ma:fcnt=%d, pcnt=%d, qcnt=%d\n",megaCfg->qFcnt, megaCfg->qPcnt, megaCfg->qCcnt); 
+#endif
+  for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) {
     if (pScb->SCpnt == SCpnt) {
       /* Found an aborting command */
 #if DEBUG
       showMbox(pScb);
 #endif
 
-      printk("Abort: %d %u\n", 
-	     SCpnt->timeout_per_command,
-	     (uint)((jiffies) - pScb->isrcount));
+/*
+ * If the command is queued to be issued to the firmware, abort the scsi cmd,
+ * If the command is already aborted in a previous call to the _abort entry
+ *  point, return SCSI_ABORT_SNOOZE, suggesting a reset.
+ * If the command is issued to the firmware, which might complete after
+ *  some time, we will mark the scb as aborted, and return to the mid layer, 
+ *  that abort could not be done.
+ *  In the ISR, when this command actually completes, we will perform a normal
+ *  completion.
+ *
+ * Oct 27, 1999
+ */
 
       switch(pScb->state) {
       case SCB_ABORTED: /* Already aborted */
 	rc = SCSI_ABORT_SNOOZE;
 	break;
       case SCB_ISSUED: /* Waiting on ISR result */
-	rc = SCSI_ABORT_PENDING;
+	rc = SCSI_ABORT_NOT_RUNNING;
 	pScb->state = SCB_ABORTED;
 	break;
+      case SCB_ACTIVE: /* still on the pending queue */
+	mega_freeSCB (megaCfg, pScb);
+	SCpnt->result = (DID_ABORT << 16) ;
+        if( megaCfg->qCompletedH == NULL ) {
+          megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+        }
+        else {
+          megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+          megaCfg->qCompletedT = SCpnt;
+        }
+        megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+        megaCfg->qCcnt++;
+	rc = SCSI_ABORT_SUCCESS;
+        break;
+      default:
+        printk("megaraid_abort: unknown command state!!\n");
+        rc = SCSI_ABORT_NOT_RUNNING;
+	break;
       }
+      break;
     }
   }
 
@@ -1839,26 +2027,29 @@
     }
   }
 #endif
-
-  /*
-   * Walk list of SCBs for any that are still outstanding
-   */
-  for (idx = 0; idx < megaCfg->max_cmds; idx++) {
-    if (megaCfg->scbList[idx].state != SCB_FREE) {
-      if (megaCfg->scbList[idx].SCpnt == SCpnt) {
-	freeSCB (megaCfg, &megaCfg->scbList[idx]);
-
-	SCpnt->result = (DID_ABORT << 16) | (SUGGEST_RETRY << 24);
-	ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
-      }
-    }
-  }
-  
   megaCfg->flag &= ~IN_ABORT;
 
-  spin_unlock_irqrestore (&mega_lock, flags);
+#if DEBUG
+if(megaCfg->flag & IN_QUEUE)  printk("ma:flag is in queue\n");
+if(megaCfg->qCompletedH == NULL) printk("ma:qchead == null\n");
+#endif
+  
+/*
+ * This is required here to complete any completed requests to be communicated
+ * over to the mid layer.
+ * Calling just mega_rundoneq() did not work.
+ */
+if(megaCfg->qCompletedH) {
+  SCpnt = megaCfg->qCompletedH;
+  megaCfg->qCompletedH = (Scsi_Cmnd *)SCpnt->host_scribble;
+  megaCfg->qCcnt--;
+
+  SCpnt->host_scribble = (unsigned char *) NULL ; // XC : sep 14
+  /* Callback */
+  callDone (SCpnt);
+}
+  mega_rundoneq(megaCfg);
 
-  mega_rundoneq();
 
   return rc;
 }
@@ -1870,14 +2061,18 @@
 {
   mega_host_config *megaCfg;
   int idx;
-  long flags;
-
-  spin_lock_irqsave (&mega_lock, flags);
+  int rc;
+  mega_scb *pScb;
 
+  rc = SCSI_RESET_NOT_RUNNING;
   megaCfg = (mega_host_config *) SCpnt->host->hostdata;
 
   megaCfg->flag |= IN_RESET;
 
+  printk ("megaraid_RESET: %.08lx cmd=%.02x <c=%d.t=%d.l=%d>, flag = %x\n",
+	SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
+	  SCpnt->lun, rstflags);
+
   TRACE (("RESET: %.08lx %.02x <%d.%d.%d>\n",
 	SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
 	  SCpnt->lun));
@@ -1888,20 +2083,18 @@
   for (idx = 0; idx < megaCfg->max_cmds; idx++) {
     if (megaCfg->scbList[idx].state != SCB_FREE) {
       SCpnt = megaCfg->scbList[idx].SCpnt;
+      pScb = &megaCfg->scbList[idx];
       if (SCpnt != NULL) {
-	freeSCB (megaCfg, &megaCfg->scbList[idx]);
-	SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24);
-	ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+        pScb->state = SCB_RESET;
+        break;
       }
     }
   }
 
   megaCfg->flag &= ~IN_RESET;
 
-  spin_unlock_irqrestore (&mega_lock, flags);
-
-  mega_rundoneq();
-  return SCSI_RESET_PUNT;
+  mega_rundoneq(megaCfg);
+  return rc;
 }
 
 /*-------------------------------------------------------------
@@ -1947,4 +2140,3 @@
 
 #include "scsi_module.c"
 #endif
-
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/megaraid.h linux.14p16/drivers/scsi/megaraid.h
--- linux.vanilla/drivers/scsi/megaraid.h	Sat Aug 28 20:00:57 1999
+++ linux.14p16/drivers/scsi/megaraid.h	Tue Dec 21 00:51:22 1999
@@ -8,9 +8,11 @@
 #define IN_ISR                  0x80000000L
 #define IN_ABORT                0x40000000L
 #define IN_RESET                0x20000000L
+#define IN_QUEUE                0x10000000L
 #define BOARD_QUARTZ            0x08000000L
 #define BOARD_40LD              0x04000000L
 
+#ifndef HOSTS_C
 #define SCB_FREE     0x0
 #define SCB_ACTIVE   0x1
 #define SCB_WAITQ    0x2
@@ -18,12 +20,19 @@
 #define SCB_COMPLETE 0x4
 #define SCB_ABORTED  0x5
 #define SCB_RESET    0x6
+#endif
 
 #define MEGA_CMD_TIMEOUT        10
 
-#define MAX_SGLIST              17
-#define MAX_COMMANDS            250
+/* Feel free to fiddle with these.. max values are:
+   SGLIST     0..26
+   COMMANDS   0..253
+   CMDPERLUN  0..63
+*/
+#define MAX_SGLIST              0x1A
+#define MAX_COMMANDS            127
 #define MAX_CMD_PER_LUN         63
+#define MAX_FIRMWARE_STATUS     46
 
 #define MAX_LOGICAL_DRIVES      8
 #define MAX_CHANNEL             5
@@ -505,7 +514,7 @@
     u32 dataxferlen;
 } mega_passthru;
 
-typedef struct _mega_mailbox {
+struct _mega_mailbox {
     /* 0x0 */ u8 cmd;
     /* 0x1 */ u8 cmdid;
     /* 0x2 */ u16 numsectors;
@@ -520,8 +529,9 @@
     /* 0x12 */ u8 completed[46];
     u8 mraid_poll;
     u8 mraid_ack;
-    u8 pad[16];
-} mega_mailbox;
+    u8 pad[16]; /* for alignment purposes */
+}__attribute__((packed));
+typedef struct _mega_mailbox mega_mailbox;
 
 typedef struct {
     u32 xferSegment;      /* for 64-bit controllers */
@@ -575,8 +585,16 @@
     u32 flag;
     u32 base;
  
-    mega_scb *qFree;
-    mega_scb *qPending;
+    mega_scb *qFreeH;
+    mega_scb *qFreeT;
+    mega_scb *qPendingH;
+    mega_scb *qPendingT;
+    
+    Scsi_Cmnd *qCompletedH;
+    Scsi_Cmnd *qCompletedT;
+    u32 qFcnt;
+    u32 qPcnt;
+    u32 qCcnt;
 
     u32 nReads[FC_MAX_LOGICAL_DRIVES];
     u32 nWrites[FC_MAX_LOGICAL_DRIVES];
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/mesh.c linux.14p16/drivers/scsi/mesh.c
--- linux.vanilla/drivers/scsi/mesh.c	Wed Oct 20 01:12:41 1999
+++ linux.14p16/drivers/scsi/mesh.c	Thu Dec  9 15:33:55 1999
@@ -29,6 +29,10 @@
 #include <asm/processor.h>
 #include <asm/spinlock.h>
 #include <asm/feature.h>
+#ifdef CONFIG_PMAC_PBOOK
+#include <asm/adb.h>
+#include <asm/pmu.h>
+#endif
 
 #include "scsi.h"
 #include "hosts.h"
@@ -154,6 +158,8 @@
 	struct dbdma_cmd *dma_cmds;	/* space for dbdma commands, aligned */
 	int	clk_freq;
 	struct mesh_target tgts[8];
+	struct device_node *dnode;
+	unsigned char *mio_base;
 #ifndef MESH_NEW_STYLE_EH
 	Scsi_Cmnd *completed_q;
 	Scsi_Cmnd *completed_qtail;
@@ -166,6 +172,14 @@
 #endif
 };
 
+#ifdef CONFIG_PMAC_PBOOK
+static int mesh_notify_sleep(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier mesh_sleep_notifier = {
+	mesh_notify_sleep,
+	SLEEP_LEVEL_BLOCK,
+};
+#endif
+
 #ifdef MESH_DBG
 
 static void dlog(struct mesh_state *ms, char *fmt, int a);
@@ -213,6 +227,7 @@
 static void halt_dma(struct mesh_state *);
 static int data_goes_out(Scsi_Cmnd *);
 static void do_abort(struct mesh_state *ms);
+static void set_mesh_power(struct mesh_state *ms, int state);
 
 static struct notifier_block mesh_notifier = {
 	mesh_notify_reboot,
@@ -247,6 +262,7 @@
 	if (mesh == 0)
 		mesh = find_compatible_devices("scsi", "chrp,mesh0");
 	for (; mesh != 0; mesh = mesh->next) {
+		struct device_node *mio;
 		if (mesh->n_addrs != 2 || mesh->n_intrs != 2) {
 			printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs"
 			       " (got %d,%d)", mesh->n_addrs, mesh->n_intrs);
@@ -267,6 +283,7 @@
 			panic("no mesh state");
 		memset(ms, 0, sizeof(*ms));
 		ms->host = mesh_host;
+		ms->dnode = mesh;
 		ms->mesh = (volatile struct mesh_regs *)
 			ioremap(mesh->addrs[0].address, 0x1000);
 		ms->dma = (volatile struct dbdma_regs *)
@@ -310,9 +327,16 @@
 		if (mesh_sync_period < minper)
 			mesh_sync_period = minper;
 
-		feature_set(mesh, FEATURE_MESH_enable);
-		mdelay(200);
+		ms->mio_base = 0;
+		for (mio = ms->dnode->parent; mio; mio = mio->parent)
+			if (strcmp(mio->name, "mac-io") == 0
+			    && mio->n_addrs > 0)
+				break;
+		if (mio)
+			ms->mio_base = (unsigned char *)
+				ioremap(mio->addrs[0].address, 0x40);
 
+		set_mesh_power(ms, 1);
 		mesh_init(ms);
 
 		if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms)) {
@@ -322,11 +346,73 @@
 		++nmeshes;
 	}
 
-	if ((_machine == _MACH_Pmac) && (nmeshes > 0))
-		register_reboot_notifier(&mesh_notifier);
+	if ((_machine == _MACH_Pmac) && (nmeshes > 0)) {
+#ifdef CONFIG_PMAC_PBOOK
+		pmu_register_sleep_notifier(&mesh_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+ 		register_reboot_notifier(&mesh_notifier);
+	}		
 
 	return nmeshes;
 }
+
+static void
+set_mesh_power(struct mesh_state *ms, int state)
+{
+	if (_machine != _MACH_Pmac || ms->mio_base == 0)
+		return;
+		
+	if (state) {
+		feature_set(ms->dnode, FEATURE_MESH_enable);
+		/* This seems to enable the termination power. strangely
+		   this doesn't fully agree with OF, but with MacOS */
+		if (ms->mio_base)
+			out_8(ms->mio_base + 0x36, 0x70);
+		mdelay(200);
+	} else {
+		feature_clear(ms->dnode, FEATURE_MESH_enable);
+		if (ms->mio_base)
+			out_8(ms->mio_base + 0x36, 0x34);
+		mdelay(10);
+	}
+}			
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * notify clients before sleep and reset bus afterwards
+ */
+int
+mesh_notify_sleep(struct pmu_sleep_notifier *self, int when)
+{
+	struct mesh_state *ms;
+	
+	switch (when) {
+	case PBOOK_SLEEP_REQUEST:
+		/* XXX We should wait for current transactions and queue
+		 * new ones that would be posted beyond this point 
+		 */ 
+		break;
+	case PBOOK_SLEEP_REJECT:
+		break;
+		
+	case PBOOK_SLEEP_NOW:
+		for (ms = all_meshes; ms != 0; ms = ms->next) {
+			disable_irq(ms->meshintr);
+			set_mesh_power(ms, 0);
+		}
+		break;
+	case PBOOK_WAKE:
+		for (ms = all_meshes; ms != 0; ms = ms->next) {
+			set_mesh_power(ms, 1);
+			mesh_init(ms);
+			enable_irq(ms->meshintr);
+		}
+		break;
+	}
+	return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
+ 
 
 int
 mesh_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/ncr53c8xx.c linux.14p16/drivers/scsi/ncr53c8xx.c
--- linux.vanilla/drivers/scsi/ncr53c8xx.c	Wed Oct 20 01:12:41 1999
+++ linux.14p16/drivers/scsi/ncr53c8xx.c	Thu Dec  9 15:33:51 1999
@@ -1763,6 +1763,8 @@
 	*/
 	u_short		device_id;	/* PCI device id		*/
 	u_char		revision_id;	/* PCI device revision id	*/
+	u_char		pci_bus;	/* PCI bus number		*/
+	u_char		pci_devfn;	/* PCI device and function	*/
 	u_long		port;		/* IO space base address	*/
 	u_int		irq;		/* IRQ level			*/
 	u_int		features;	/* Chip features map		*/
@@ -4393,6 +4395,8 @@
 	sprintf(np->inst_name, "ncr53c%s-%d", np->chip_name, np->unit);
 	np->device_id	= device->chip.device_id;
 	np->revision_id	= device->chip.revision_id;
+	np->pci_bus	= device->slot.bus;
+	np->pci_devfn	= device->slot.device_fn;
 	np->features	= device->chip.features;
 	np->clock_divn	= device->chip.nr_divisor;
 	np->maxoffs	= device->chip.offset_max;
@@ -10088,7 +10092,15 @@
 */
 const char *ncr53c8xx_info (struct Scsi_Host *host)
 {
+#ifdef __sparc__
+	/* Ok to do this on all archs? */
+	static char buffer[80];
+	ncb_p np = ((struct host_data *) host->hostdata)->ncb;
+	sprintf (buffer, "%s\nPCI bus %02x device %02x", SCSI_NCR_DRIVER_NAME, np->pci_bus, np->pci_devfn);
+	return buffer;
+#else
 	return SCSI_NCR_DRIVER_NAME;
+#endif
 }
 
 /*
@@ -10673,6 +10685,8 @@
 	copy_info(&info, "  IO port address 0x%lx, ", (u_long) np->port);
 #ifdef __sparc__
 	copy_info(&info, "IRQ number %s\n", __irq_itoa(np->irq));
+	/* Ok to do this on all archs? */
+	copy_info(&info, "PCI bus %02x device %02x\n", np->pci_bus, np->pci_devfn);
 #else
 	copy_info(&info, "IRQ number %d\n", (int) np->irq);
 #endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/psi240i.h linux.14p16/drivers/scsi/psi240i.h
--- linux.vanilla/drivers/scsi/psi240i.h	Mon Dec 28 06:19:22 1998
+++ linux.14p16/drivers/scsi/psi240i.h	Mon Dec 13 19:37:53 1999
@@ -211,6 +211,8 @@
 	}	READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
 
 // SCSI inquiry data
+#ifndef HOSTS_C
+
 typedef struct _INQUIRYDATA
 	{
 	UCHAR DeviceType			:5;
@@ -235,6 +237,7 @@
     UCHAR VendorSpecific[20];
     UCHAR Reserved3[40];
 	}	INQUIRYDATA, *PINQUIRYDATA;
+#endif
 
 // IDE IDENTIFY data
 typedef struct _IDENTIFY_DATA
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/qlogicfc.c linux.14p16/drivers/scsi/qlogicfc.c
--- linux.vanilla/drivers/scsi/qlogicfc.c	Wed Oct 20 01:12:41 1999
+++ linux.14p16/drivers/scsi/qlogicfc.c	Mon Dec 13 18:36:21 1999
@@ -758,7 +758,7 @@
 			hostdata->control_block.firm_opts = 0x0108;
 			hostdata->control_block.max_frame_len = 2048;
 			hostdata->control_block.max_iocb = 256;
-			hostdata->control_block.exec_throttle = 8;
+			hostdata->control_block.exec_throttle = QLOGICFC_CMD_PER_LUN;
 			hostdata->control_block.retry_delay = 5;
 			hostdata->control_block.retry_cnt = 1;
 			hostdata->control_block.node_name[0] = 0x0020;
@@ -1287,8 +1287,9 @@
 		/* scsi.c expects sense info in a different buffer */
 		cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->sense_buffer);
 #if BITS_PER_LONG > 32
-		cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->request_buffer);
+		cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->sense_buffer);
 #endif
+		cmd->dataseg[0].d_count = sizeof(Cmnd->sense_buffer);
 		cmd->segment_cnt = 1;
 		cmd->control_flags = CFLAG_READ;
 		break;
@@ -1855,7 +1856,7 @@
 
 static int isp2x00_init(struct Scsi_Host *sh)
 {
-	u_int io_base;
+	u_long io_base;
 	struct isp2x00_hostdata *hostdata;
 	u_char revision;
 	u_int irq;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/qlogicisp.c linux.14p16/drivers/scsi/qlogicisp.c
--- linux.vanilla/drivers/scsi/qlogicisp.c	Wed Oct 20 01:12:42 1999
+++ linux.14p16/drivers/scsi/qlogicisp.c	Thu Dec  9 15:33:54 1999
@@ -1262,6 +1262,13 @@
 		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, latency_timer);
 	}
 #endif
+#ifdef __alpha__
+	/* Force ALPHA to use bus I/O and not bus MEM. 
+	   This is to avoid having to use HAE_MEM registers,
+	   which is broken on some platforms and with SMP.
+	*/
+	command &= ~PCI_COMMAND_MEMORY;
+#endif
 
 	if ((command & PCI_COMMAND_MEMORY) &&
 	    ((mem_base & 1) == 0)) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/qlogicpti.c linux.14p16/drivers/scsi/qlogicpti.c
--- linux.vanilla/drivers/scsi/qlogicpti.c	Wed Oct 20 01:12:42 1999
+++ linux.14p16/drivers/scsi/qlogicpti.c	Thu Dec  9 15:33:54 1999
@@ -43,7 +43,7 @@
 #include <linux/module.h>
 
 #define MAX_TARGETS	16
-#define MAX_LUNS	8
+#define MAX_LUNS	8	/* 32 for 1.31 F/W */
 
 #define DEFAULT_LOOP_COUNT	10000
 
@@ -244,6 +244,46 @@
 	return 0;
 }
 
+static inline void qlogicpti_set_hostdev_defaults(struct qlogicpti *qpti)
+{
+	int i;
+
+	qpti->host_param.initiator_scsi_id = qpti->scsi_id;
+	qpti->host_param.bus_reset_delay = 3;
+	qpti->host_param.retry_count = 0;
+	qpti->host_param.retry_delay = 5;
+	qpti->host_param.async_data_setup_time = 3;
+	qpti->host_param.req_ack_active_negation = 1;
+	qpti->host_param.data_line_active_negation = 1;
+	qpti->host_param.data_dma_burst_enable = 1;
+	qpti->host_param.command_dma_burst_enable = 1;
+	qpti->host_param.tag_aging = 8;
+	qpti->host_param.selection_timeout = 250;
+	qpti->host_param.max_queue_depth = 256;
+
+	for(i = 0; i < MAX_TARGETS; i++) {
+		/*
+		 * disconnect, parity, arq, reneg on reset, and, oddly enough
+		 * tags...the midlayer's notion of tagged support has to match
+		 * our device settings, and since we base whether we enable a
+		 * tag on a  per-cmnd basis upon what the midlayer sez, we
+		 * actually enable the capability here.
+		 */
+		qpti->dev_param[i].device_flags = 0xcd;
+		qpti->dev_param[i].execution_throttle = 16;
+		if (qpti->ultra) {
+			qpti->dev_param[i].synchronous_period = 12;
+			qpti->dev_param[i].synchronous_offset = 8;
+		} else {
+			qpti->dev_param[i].synchronous_period = 25;
+			qpti->dev_param[i].synchronous_offset = 12;
+		}
+		qpti->dev_param[i].device_enable = 1;
+	}
+	/* this is very important to set! */
+	qpti->sbits = 1 << qpti->scsi_id;
+}
+
 static int qlogicpti_reset_hardware(struct Scsi_Host *host)
 {
 	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
@@ -288,6 +328,10 @@
 		qregs->risc_mtreg = (RISC_MTREG_P0DFLT | RISC_MTREG_P1DFLT);
 	}
 
+	/* reset adapter and per-device default values. */
+	/* do it after finding out whether we're ultra mode capable */
+	qlogicpti_set_hostdev_defaults(qpti);
+
 	/* Release the RISC processor. */
 	qregs->hcctrl = HCCTRL_REL;
 
@@ -365,9 +409,11 @@
 		param[0] = MBOX_SET_TARGET_PARAMS;
 		param[1] = (i << 8);
 		param[2] = (qpti->dev_param[i].device_flags << 8);
-		if (qpti->is_pti == 0)	/* really, is it 1.31 f/w or later? */
-			param[2] |= 0xc0;
-		param[3] = 0;	/* no sync mode at first */
+		/*
+		 * Since we're now loading 1.31 f/w, force narrow/async.
+		 */
+		param[2] |= 0xc0;
+		param[3] = 0;	/* no offset, we do not have sync mode yet */
 		qlogicpti_mbox_command(qpti, param, 0);
 	}
 
@@ -392,9 +438,6 @@
 	unsigned short param[6];
 	unsigned short *risc_code, risc_code_addr, risc_code_length;
 	unsigned long flags;
-#if !defined(MODULE) && !defined(__sparc_v9__)
-	unsigned long dvma_addr;
-#endif
 	int i, timeout;
 
 	risc_code = &sbus_risc_code01[0];
@@ -409,6 +452,7 @@
 	for(i = 0; i < risc_code_length; i++)
 		csum += risc_code[i];
 	if(csum) {
+		restore_flags(flags);
 		printk(KERN_EMERG "qlogicpti%d: Aieee, firmware checksum failed!",
 		       qpti->qpti_id);
 		return 1;
@@ -420,6 +464,7 @@
 	while(--timeout && (qregs->sbus_ctrl & SBUS_CTRL_RESET))
 		udelay(20);
 	if(!timeout) {
+		restore_flags(flags);
 		printk(KERN_EMERG "qlogicpti%d: Cannot reset the ISP.", qpti->qpti_id);
 		return 1;
 	}
@@ -449,6 +494,9 @@
 		qpti->differential = 0;
 	qregs->hcctrl = HCCTRL_REL;
 
+	/* This shouldn't be necessary- we've reset things so we should be
+	   running from the ROM now.. */
+
 	param[0] = MBOX_STOP_FIRMWARE;
 	param[1] = param[2] = param[3] = param[4] = param[5] = 0;
 	if(qlogicpti_mbox_command(qpti, param, 1)) {
@@ -459,38 +507,18 @@
 	}		
 
 	/* Load the firmware. */
-#if !defined(MODULE) && !defined(__sparc_v9__)
-	if (sparc_cpu_model != sun4d) {
-		dvma_addr = (unsigned long) mmu_lockarea((char *)&risc_code[0],
-							 (sizeof(u_short) * risc_code_length));
-		param[0] = MBOX_LOAD_RAM;
-		param[1] = risc_code_addr;
-		param[2] = (dvma_addr >> 16);
-		param[3] = (dvma_addr & 0xffff);
-		param[4] = (sizeof(u_short) * risc_code_length);
+	for(i = 0; i < risc_code_length; i++) {
+		param[0] = MBOX_WRITE_RAM_WORD;
+		param[1] = risc_code_addr + i;
+		param[2] = risc_code[i];
 		if(qlogicpti_mbox_command(qpti, param, 1) ||
-		   (param[0] != MBOX_COMMAND_COMPLETE)) {
-			printk(KERN_EMERG "qlogicpti%d: Firmware dload failed, I'm bolixed!\n",
+		   param[0] != MBOX_COMMAND_COMPLETE) {
+			printk("qlogicpti%d: Firmware dload failed, I'm bolixed!\n",
 			       qpti->qpti_id);
 			restore_flags(flags);
 			return 1;
 		}
-		mmu_unlockarea((char *)dvma_addr, (sizeof(u_short) * risc_code_length));
-	} else
-#endif
-	/* We need to do it this slow way always on Ultra, SS[12]000. */
-		for(i = 0; i < risc_code_length; i++) {
-			param[0] = MBOX_WRITE_RAM_WORD;
-			param[1] = risc_code_addr + i;
-			param[2] = risc_code[i];
-			if(qlogicpti_mbox_command(qpti, param, 1) ||
-			   param[0] != MBOX_COMMAND_COMPLETE) {
-				printk("qlogicpti%d: Firmware dload failed, I'm bolixed!\n",
-				       qpti->qpti_id);
-				restore_flags(flags);
-				return 1;
-			}
-		}
+	}
 
 	/* Reset the ISP again. */
 	qregs->hcctrl = HCCTRL_RESET;
@@ -530,6 +558,17 @@
 	qpti->fware_minrev = param[2];
 	qpti->fware_micrev = param[3];
 
+	/* Set the clock rate */
+	param[0] = MBOX_SET_CLOCK_RATE;
+	param[1] = qpti->clock;
+	if(qlogicpti_mbox_command(qpti, param, 1) ||
+	   (param[0] != MBOX_COMMAND_COMPLETE)) {
+		printk(KERN_EMERG "qlogicpti%d: could not set clock rate.\n",
+		       qpti->qpti_id);
+		restore_flags(flags);
+		return 1;
+	}
+
 	if(qpti->is_pti != 0) {
 		/* Load scsi initiator ID and interrupt level into sbus static ram. */
 		param[0] = MBOX_WRITE_RAM_WORD;
@@ -578,39 +617,6 @@
 	return 0;
 }
 
-static inline void qlogicpti_set_hostdev_defaults(struct qlogicpti *qpti)
-{
-	int i;
-
-	qpti->host_param.initiator_scsi_id = qpti->scsi_id;
-	qpti->host_param.bus_reset_delay = 3;
-	qpti->host_param.retry_count = 0;
-	qpti->host_param.retry_delay = 5;
-	qpti->host_param.async_data_setup_time = 3;
-	qpti->host_param.req_ack_active_negation = 1;
-	qpti->host_param.data_line_active_negation = 1;
-	qpti->host_param.data_dma_burst_enable = 1;
-	qpti->host_param.command_dma_burst_enable = 1;
-	qpti->host_param.tag_aging = 8;
-	qpti->host_param.selection_timeout = 250;
-	qpti->host_param.max_queue_depth = 256;
-
-	for(i = 0; i < MAX_TARGETS; i++) {
-		/* disconnect, parity, arq, reneg on reset */
-		qpti->dev_param[i].device_flags = 0xc5;
-		qpti->dev_param[i].execution_throttle = 16;
-		if (qpti->ultra) {
-			qpti->dev_param[i].synchronous_period = 12;
-			qpti->dev_param[i].synchronous_offset = 8;
-		} else {
-			qpti->dev_param[i].synchronous_period = 16;
-			qpti->dev_param[i].synchronous_offset = 12;
-		}
-		qpti->dev_param[i].device_enable = 1;
-	}
-	qpti->sbits = 1 << qpti->host_param.initiator_scsi_id;
-}
-
 static void do_qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs);
 #ifndef __sparc_v9__
 static void do_qlogicpti_intr_handler_sun4m(int irq, void *dev_id, struct pt_regs *regs);
@@ -629,6 +635,7 @@
 	int nqptis = 0, nqptis_in_use = 0;
 	int qpti_node;
 	int is_pti;
+	unsigned int cfreq;
 
 	tpnt->proc_dir = &proc_scsi_qlogicpti;
 	qptichain = 0;
@@ -735,6 +742,7 @@
 				qpti->qdev->reg_addrs[0].reg_size;
 
 			qpti_host->irq = qpti->irq = qpti->qdev->irqs[0];
+			qpti->gotirq = 0;
 
 			/* On Ultra and S{S1,C2}000 we must always call request_irq for each
 			 * qpti, so that imap registers get setup etc.
@@ -757,6 +765,7 @@
 				/* XXX Unmap regs, unregister scsi host, free things. */
 				continue;
 			}
+			qpti->gotirq = 1;
 qpti_irq_acquired:
 			printk("qpti%d: IRQ %s ",
 			       qpti->qpti_id, __irq_itoa(qpti->qhost->irq));
@@ -790,6 +799,15 @@
 				bsizes = (DMA_BURST32 - 1);
 			qpti->bursts = bsizes;
 
+			/* Check for what the clock input to this card is.
+			 * Default to 40Mhz.
+			 */
+			cfreq = prom_getintdefault(qpti->prom_node,"clock-frequency",40000000);
+        		qpti->clock = (cfreq + 500000)/1000000;
+			if (qpti->clock == 0) /* bullshit */
+				qpti->clock = 40;
+
+
 			/* Clear out Scsi_Cmnd array. */
 			memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots));
 
@@ -809,9 +827,6 @@
 #undef QSIZE
 
 
-			/* Set adapter and per-device default values. */
-			qlogicpti_set_hostdev_defaults(qpti);
-			
 			/* Load the firmware. */
 			if(qlogicpti_load_firmware(qpti))
 				panic("SBUS Qlogic/ISP firmware load failed");
@@ -856,17 +871,15 @@
 {
 	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
 	struct qlogicpti_regs *qregs = qpti->qregs;
-
 	/* Shut up the card. */
 	qregs->sbus_ctrl = 0;
-
 	/* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
-	free_irq(host->irq, qpti);
+	if (qpti->gotirq)
+		free_irq(host->irq, qpti);
 	unmapioaddr((unsigned long)qregs);
 	/* QLGC,isp doesn't have status reg */
 	if (strcmp (qpti->prom_name, "QLGC,isp"))
 		unmapioaddr((unsigned long)qpti->sreg);
-
 	return 0;
 }
 
@@ -1019,30 +1032,28 @@
 	Cmnd->host_scribble = NULL;
 
 	if ((qpti->sbits & (1 << tgt)) == 0) {
-		if (Cmnd->cmnd[0] == 0x12 && host_byte(Cmnd->result) == DID_OK) {
+		int ok = host_byte(Cmnd->result) == DID_OK;
+		if (Cmnd->cmnd[0] == 0x12 && ok) {
 			unsigned char *iqd;
 			if (Cmnd->use_sg == 0) {
 				iqd = ((unsigned char *)Cmnd->buffer);
 			} else {
 				iqd = ((struct scatterlist *) Cmnd->request_buffer)->address;
 			}
-			/* Tags? */
-			if (iqd[7] & 0x2) {
-				qpti->dev_param[tgt].device_flags |= 0x8;
-			}
-			/* Sync Mode? */
+			/* tags handled in midlayer */
+			/* enable sync mode? */
 			if (iqd[7] & 0x10) {
 				qpti->dev_param[tgt].device_flags |= 0x10;
 			} else {
 				qpti->dev_param[tgt].synchronous_offset = 0;
 				qpti->dev_param[tgt].synchronous_period = 0;
 			}
-			/* Wide Capable? */
+			/* are we wide capable? */
 			if (iqd[7] & 0x20) {
 				qpti->dev_param[tgt].device_flags |= 0x20;
 			}
 			qpti->sbits |= (1 << tgt);
-		} else if (host_byte(Cmnd->result) != DID_OK) {
+		} else if (!ok) {
 			qpti->sbits |= (1 << tgt);
 		}
 	}
@@ -1051,28 +1062,64 @@
 
 int qlogicpti_queuecommand_slow(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
 {
+	unsigned long flags;
 	struct qlogicpti *qpti = (struct qlogicpti *) Cmnd->host->hostdata;
-	/* check to see if we're done scanning */
+
+	/*
+	 * done checking this host adapter?
+	 * If not, then rewrite the command
+	 * to finish through ourdone so we
+	 * can peek at Inquiry data results.
+	 */
+	if (qpti->sbits && qpti->sbits != 0xffff) {
+		Cmnd->host_scribble = (char *) done;
+		return qlogicpti_queuecommand(Cmnd, ourdone);
+	}
+	save_flags(flags); cli();
+
+	/*
+	 * We've peeked at all targets for this bus- time
+	 * to set parameters for devices for real now.
+	 */
 	if (qpti->sbits == 0xffff) {
 		int i;
-		unsigned long flags;
-		save_flags(flags); cli();
 		for(i = 0; i < MAX_TARGETS; i++) {
 			u_short param[6];
 			param[0] = MBOX_SET_TARGET_PARAMS;
 			param[1] = (i << 8);
 			param[2] = (qpti->dev_param[i].device_flags << 8);
-			param[3] = (qpti->dev_param[i].synchronous_offset << 8)|
-				qpti->dev_param[i].synchronous_period;
-			qlogicpti_mbox_command(qpti, param, 0);
+			if (qpti->dev_param[i].device_flags & 0x10) {
+				param[3] = (qpti->dev_param[i].synchronous_offset << 8) |
+					qpti->dev_param[i].synchronous_period;
+			} else {
+				param[3] = 0;
+			}
+			(void) qlogicpti_mbox_command(qpti, param, 0);
+		}
+		/*
+		 * set to zero so any traverse through ourdone
+		 * doesn't start the whole process again,
+		 */
+		qpti->sbits = 0;
+	}
+
+	/* check to see if we're done with all adapters... */
+	for (qpti = qptichain; qpti != NULL; qpti = qpti->next) {
+		if (qpti->sbits) {
+			break;
 		}
-		restore_flags(flags);
-		Cmnd->host->hostt->queuecommand = qlogicpti_queuecommand;
-		return qlogicpti_queuecommand(Cmnd, done);
-	} else {
-		Cmnd->host_scribble = (char *) done;
-		return qlogicpti_queuecommand(Cmnd, ourdone);
 	}
+
+	/*
+	 * if we hit the end of the chain w/o finding adapters still
+	 * capability-configuring, then we're done with all adapters
+	 * and can rock on..
+	 */
+	if (qpti == NULL)
+		Cmnd->host->hostt->queuecommand = qlogicpti_queuecommand;
+
+	restore_flags(flags);
+	return qlogicpti_queuecommand(Cmnd, done);
 }
 
 /*
@@ -1140,7 +1187,7 @@
 	return 0;
 }
 
-static int qlogicpti_return_status(struct Status_Entry *sts)
+static int qlogicpti_return_status(struct Status_Entry *sts, int id)
 {
 	int host_status = DID_ERROR;
 
@@ -1195,8 +1242,8 @@
 		host_status = DID_OK;
 		break;
 	      default:
-		printk(KERN_EMERG "qlogicpti : unknown completion status 0x%04x\n",
-		       sts->completion_status);
+		printk(KERN_EMERG "qpti%d: unknown completion status 0x%04x\n",
+		       id, sts->completion_status);
 		host_status = DID_ERROR;
 		break;
 	}
@@ -1259,7 +1306,8 @@
 			       sizeof(Cmnd->sense_buffer));
 
 		if(sts->hdr.entry_type == ENTRY_STATUS)
-			Cmnd->result = qlogicpti_return_status(sts);
+			Cmnd->result =
+			    qlogicpti_return_status(sts, qpti->qpti_id);
 		else
 			Cmnd->result = DID_ERROR << 16;
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/qlogicpti.h linux.14p16/drivers/scsi/qlogicpti.h
--- linux.vanilla/drivers/scsi/qlogicpti.h	Wed Oct 20 01:12:42 1999
+++ linux.14p16/drivers/scsi/qlogicpti.h	Thu Dec  9 15:33:54 1999
@@ -483,7 +483,7 @@
 	int                       prom_node;
 	char                      prom_name[64];
 	int                       irq;
-	char                      differential, ultra;
+	char                      differential, ultra, clock;
 	unsigned char             bursts;
 	struct	host_param        host_param;
 	struct	dev_param         dev_param[MAX_TARGETS];
@@ -496,8 +496,10 @@
 #define SREG_IMASK                0x0c   /* Interrupt level            */
 #define SREG_SPMASK               0x03   /* Mask for switch pack       */
 	unsigned char             swsreg;
-	unsigned char             is_pti; /* Non-zero if this is a PTI board. */
-	unsigned short            sbits;
+	unsigned int	
+		gotirq	:	1,	/* this instance got an irq */
+		is_pti	: 	1,	/* Non-zero if this is a PTI board. */
+		sbits	:	16;	/* syncmode known bits */
 };
 
 /* How to twiddle them bits... */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/script_asm.pl linux.14p16/drivers/scsi/script_asm.pl
--- linux.vanilla/drivers/scsi/script_asm.pl	Tue Jun 17 00:35:56 1997
+++ linux.14p16/drivers/scsi/script_asm.pl	Thu Dec  9 15:33:51 1999
@@ -896,7 +896,7 @@
 open (OUTPUT, ">$output") || die "$0 : can't open $output for writing\n";
 open (OUTPUTU, ">$outputu") || die "$0 : can't open $outputu for writing\n";
 
-print OUTPUT "u32 ".$prefix."SCRIPT[] = {\n";
+print OUTPUT "static u32 ".$prefix."SCRIPT[] = {\n";
 $instructions = 0;
 for ($i = 0; $i < $#code; ) {
     if ($list_in_array) {
@@ -935,7 +935,7 @@
     }
     printf OUTPUTU "#undef A_$i\n";
 
-    printf OUTPUT "u32 A_".$i."_used\[\] = {\n";
+    printf OUTPUT "static u32 A_".$i."_used\[\] __attribute((unused)) = {\n";
 printf STDERR "$i is used $symbol_references{$i}\n" if ($debug);
     foreach $j (split (/\s+/,$symbol_references{$i})) {
 	$j =~ /(ABS|REL),(.*),(.*)/;
@@ -957,15 +957,15 @@
 # NCR assembler outputs label patches in the form of indices into 
 # the code.
 #
-printf OUTPUT "u32 ".$prefix."LABELPATCHES[] = {\n";
+printf OUTPUT "static u32 ".$prefix."LABELPATCHES[] __attribute((unused)) = {\n";
 for $patch (sort {$a <=> $b} @label_patches) {
     printf OUTPUT "\t0x%08x,\n", $patch;
 }
 printf OUTPUT "};\n\n";
 
 $num_external_patches = 0;
-printf OUTPUT "struct {\n\tu32\toffset;\n\tvoid\t\t*address;\n".
-    "} ".$prefix."EXTERNAL_PATCHES[] = {\n";
+printf OUTPUT "static struct {\n\tu32\toffset;\n\tvoid\t\t*address;\n".
+    "} ".$prefix."EXTERNAL_PATCHES[] __attribute((unused)) = {\n";
 while ($ident = pop(@external_patches)) {
     $off = pop(@external_patches);
     printf OUTPUT "\t{0x%08x, &%s},\n", $off, $ident;
@@ -973,11 +973,11 @@
 }
 printf OUTPUT "};\n\n";
 
-printf OUTPUT "u32 ".$prefix."INSTRUCTIONS\t= %d;\n", 
+printf OUTPUT "static u32 ".$prefix."INSTRUCTIONS __attribute((unused))\t= %d;\n", 
     $instructions;
-printf OUTPUT "u32 ".$prefix."PATCHES\t= %d;\n", 
+printf OUTPUT "static u32 ".$prefix."PATCHES __attribute((unused))\t= %d;\n", 
     $#label_patches+1;
-printf OUTPUT "u32 ".$prefix."EXTERNAL_PATCHES_LEN\t= %d;\n",
+printf OUTPUT "static u32 ".$prefix."EXTERNAL_PATCHES_LEN __attribute((unused))\t= %d;\n",
     $num_external_patches;
 close OUTPUT;
 close OUTPUTU;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsi.c linux.14p16/drivers/scsi/scsi.c
--- linux.vanilla/drivers/scsi/scsi.c	Wed Oct 20 01:12:45 1999
+++ linux.14p16/drivers/scsi/scsi.c	Thu Dec  9 15:33:51 1999
@@ -135,6 +135,12 @@
 static unsigned char   ** dma_malloc_pages = NULL;
 
 /*
+ * get rid of callers having to aquire the io_request_lock before
+ * calling scsi_malloc and scsi_free
+ */
+spinlock_t		  scsi_malloc_lock = SPIN_LOCK_UNLOCKED;
+
+/*
  * Note - the initial logging level can be set here to log events at boot time.
  * After the system is up, you may enable logging via the /proc interface.
  */
@@ -258,6 +264,7 @@
 {"TEAC","CD-ROM","1.06", BLIST_NOLUN},          /* causes failed REQUEST SENSE on lun 1
 						 * for seagate controller, which causes
 						 * SCSI code to reset bus.*/
+	{"TEAC", "MT-2ST/45S2-27", "RV M", BLIST_NOLUN},	/* Responds to all lun */
 {"TEXEL","CD-ROM","1.06", BLIST_NOLUN},         /* causes failed REQUEST SENSE on lun 1
 						 * for seagate controller, which causes
 						 * SCSI code to reset bus.*/
@@ -268,7 +275,8 @@
 {"HP", "C1750A", "3226", BLIST_NOLUN},          /* scanjet iic */
 {"HP", "C1790A", "", BLIST_NOLUN},              /* scanjet iip */
 {"HP", "C2500A", "", BLIST_NOLUN},              /* scanjet iicx */
-{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},	/* extra reset */
+{"YAMAHA","CDR100","1.00", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
+{"YAMAHA","CDR102","1.00", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
 {"RELISYS", "Scorpio", "*", BLIST_NOLUN},	/* responds to all LUN */
 
 /*
@@ -292,12 +300,13 @@
 {"nCipher","Fastness Crypto","*", BLIST_FORCELUN},
 {"NEC","PD-1 ODX654P","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"MATSHITA","PD-1","*", BLIST_FORCELUN | BLIST_SINGLELUN},
-{"YAMAHA","CDR100","1.00", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
-{"YAMAHA","CDR102","1.00", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
 {"iomega","jaz 1GB","J.86", BLIST_NOTQ | BLIST_NOLUN},
 {"CREATIVE","DVD-RAM RAM","*", BLIST_GHOST},
 {"MATSHITA","PD-2 LF-D100","*", BLIST_GHOST},
+{"HITACHI","GF-1050","*", BLIST_GHOST},        /* Hitachi SCSI DVD-RAM */
 {"TOSHIBA","CDROM","*", BLIST_ISROM},
+{"TOSHIBA","DVD-RAM SD-W1101","*", BLIST_GHOST},
+{"TOSHIBA","DVD-RAM SD-W1111","*", BLIST_GHOST},
 /*
  * Must be at end of list...
  */
@@ -1887,6 +1896,7 @@
 void *scsi_malloc(unsigned int len)
 {
     unsigned int nbits, mask;
+    unsigned long flags;
     int i, j;
     if(len % SECTOR_SIZE != 0 || len > PAGE_SIZE)
 	return NULL;
@@ -1894,6 +1904,7 @@
     nbits = len >> 9;
     mask = (1 << nbits) - 1;
 
+    spin_lock_irqsave(&scsi_malloc_lock, flags);
     for(i=0;i < dma_sectors / SECTORS_PER_PAGE; i++)
 	for(j=0; j<=SECTORS_PER_PAGE - nbits; j++){
 	    if ((dma_malloc_freelist[i] & (mask << j)) == 0){
@@ -1903,15 +1914,18 @@
                 SCSI_LOG_MLQUEUE(3,printk("SMalloc: %d %p [From:%p]\n",len, dma_malloc_pages[i] + (j << 9)));
 		printk("SMalloc: %d %p [From:%p]\n",len, dma_malloc_pages[i] + (j << 9));
 #endif
+		spin_unlock_irqrestore(&scsi_malloc_lock, flags);
 		return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
 	    }
 	}
+    spin_unlock_irqrestore(&scsi_malloc_lock, flags);
     return NULL;  /* Nope.  No more */
 }
 
 int scsi_free(void *obj, unsigned int len)
 {
     unsigned int page, sector, nbits, mask;
+    unsigned long flags;
 
 #ifdef DEBUG
     unsigned long ret = 0;
@@ -1925,6 +1939,7 @@
     SCSI_LOG_MLQUEUE(3,printk("SFree: %p %d\n",obj, len));
 #endif
 
+    spin_lock_irqsave(&scsi_malloc_lock, flags);
     for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) {
         unsigned long page_addr = (unsigned long) dma_malloc_pages[page];
         if ((unsigned long) obj >= page_addr &&
@@ -1948,9 +1963,11 @@
             }
             scsi_dma_free_sectors += nbits;
             dma_malloc_freelist[page] &= ~(mask << sector);
+	    spin_unlock_irqrestore(&scsi_malloc_lock, flags);
             return 0;
 	}
     }
+    spin_unlock_irqrestore(&scsi_malloc_lock, flags);
     panic("scsi_free:Bad offset");
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsi.h linux.14p16/drivers/scsi/scsi.h
--- linux.vanilla/drivers/scsi/scsi.h	Sat Aug 14 02:27:33 1999
+++ linux.14p16/drivers/scsi/scsi.h	Wed Dec 15 23:14:21 1999
@@ -41,6 +41,7 @@
 
 #define MAX_SCSI_DEVICE_CODE 14
 extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
+extern spinlock_t scsi_malloc_lock;
 
 #ifdef DEBUG
     #define SCSI_TIMEOUT (5*HZ)
@@ -654,8 +655,8 @@
 	    req->nr_sectors -= bh->b_size >> 9;
 	    req->sector += bh->b_size >> 9;
 	    bh->b_reqnext = NULL;
-	    bh->b_end_io(bh, uptodate);
 	    sectors -= bh->b_size >> 9;
+	    bh->b_end_io(bh, uptodate);
 	    if ((bh = req->bh) != NULL) {
 		req->current_nr_sectors = bh->b_size >> 9;
 		if (req->nr_sectors < req->current_nr_sectors) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsi_ioctl.c linux.14p16/drivers/scsi/scsi_ioctl.c
--- linux.vanilla/drivers/scsi/scsi_ioctl.c	Sat Aug 14 02:26:16 1999
+++ linux.14p16/drivers/scsi/scsi_ioctl.c	Thu Dec  9 15:33:50 1999
@@ -227,10 +227,8 @@
     if(buf_needed){
 	buf_needed = (buf_needed + 511) & ~511;
 	if (buf_needed > MAX_BUF) buf_needed = MAX_BUF;
-        spin_lock_irqsave(&io_request_lock, flags);
-	buf = (char *) scsi_malloc(buf_needed);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if (!buf) return -ENOMEM;
+	if ((buf = (char *) scsi_malloc(buf_needed)) == NULL)
+		return -ENOMEM;
 	memset(buf, 0, buf_needed);
     } else
 	buf = NULL;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sd.c linux.14p16/drivers/scsi/sd.c
--- linux.vanilla/drivers/scsi/sd.c	Wed Oct 20 01:12:46 1999
+++ linux.14p16/drivers/scsi/sd.c	Thu Dec  9 15:33:50 1999
@@ -1239,13 +1239,16 @@
 		    spintime = jiffies;
 		}
 
-		time1 = jiffies + HZ;
 		spin_unlock_irq(&io_request_lock);
-		while(jiffies < time1); /* Wait 1 second for next try */
+		time1 = HZ;
+		do {
+		    current->state = TASK_UNINTERRUPTIBLE;
+		    time1 = schedule_timeout(time1);
+		} while (time1); /* Wait 1 second for next try */
 		printk( "." );
 		spin_lock_irq(&io_request_lock);
 	    }
-	} while(the_result && spintime && spintime+100*HZ > jiffies);
+	} while(the_result && spintime && time_before(jiffies, spintime+100*HZ));
 	if (spintime) {
 	    if (the_result)
 		printk( "not responding...\n" );
@@ -1315,6 +1318,7 @@
 
 	printk("%s : block size assumed to be 512 bytes, disk size 1GB.  \n",
 	       nbuff);
+
 	rscsi_disks[i].capacity = 0x1fffff;
 	rscsi_disks[i].sector_size = 512;
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/seagate.c linux.14p16/drivers/scsi/seagate.c
--- linux.vanilla/drivers/scsi/seagate.c	Tue Dec 29 19:40:35 1998
+++ linux.14p16/drivers/scsi/seagate.c	Thu Dec  9 15:33:54 1999
@@ -1216,6 +1216,9 @@
 
 /* SJT: Start. Slow Write. */
 #ifdef SEAGATE_USE_ASM
+
+int __dummy_1,__dummy_2;
+
 /*
  *      We loop as long as we are in a data out phase, there is data to send, 
  *      and BSY is still active.
@@ -1246,9 +1249,9 @@
                     "movb %%al, (%%edi)\n\t"
                     "loop 1b\n\t"
                 "2:\n"
-/* output */    : "=S" (data), "=c" (len) 
-/* input */     : "0" (data), "1" (len), "b" (phys_to_virt(st0x_cr_sr)), "D" (phys_to_virt(st0x_dr)) 
-/* clobbered */ : "eax", "ebx", "edi"); 
+/* output */    : "=S" (data), "=c" (len)  ,"=b" (__dummy_1) ,"=D" (__dummy_2)
+/* input */     : "0" (data), "1" (len), "2" (phys_to_virt(st0x_cr_sr)), "3" (phys_to_virt(st0x_dr)) 
+/* clobbered */ : "eax"); 
 #else /* SEAGATE_USE_ASM */
             while (len)
             {
@@ -1374,6 +1377,11 @@
 
 /* SJT: Start. */
 #ifdef SEAGATE_USE_ASM
+
+int __dummy_3,__dummy_4;
+
+/* Dummy clobbering variables for the new gcc-2.95 */
+
 /*
  *      We loop as long as we are in a data in phase, there is room to read, 
  *      and BSY is still active
@@ -1405,9 +1413,9 @@
                 "stosb\n\t"   
                 "loop 1b\n\t"
             "2:\n"
-/* output */    : "=D" (data), "=c" (len) 
-/* input */     : "0" (data), "1" (len), "S" (phys_to_virt(st0x_cr_sr)), "b" (phys_to_virt(st0x_dr)) 
-/* clobbered */ : "eax","ebx", "esi"); 
+/* output */    : "=D" (data), "=c" (len) ,"=S" (__dummy_3) ,"=b" (__dummy_4)
+/* input */     : "0" (data), "1" (len), "2" (phys_to_virt(st0x_cr_sr)), "3" (phys_to_virt(st0x_dr)) 
+/* clobbered */ : "eax" ); 
 #else /* SEAGATE_USE_ASM */
             while (len)
             {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sg.c linux.14p16/drivers/scsi/sg.c
--- linux.vanilla/drivers/scsi/sg.c	Sat Aug 14 02:26:50 1999
+++ linux.14p16/drivers/scsi/sg.c	Tue Dec 21 00:22:44 1999
@@ -16,41 +16,28 @@
  *
  *  Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book.
  */
- static char * sg_version_str = "Version: 2.1.34 (990603)";
- static int sg_version_num = 20134; /* 2 digits for each component */
+ static char * sg_version_str = "Version: 2.1.36 (991218)";
+ static int sg_version_num = 20136; /* 2 digits for each component */
 /*
  *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
  *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
  *        the kernel/module needs to be built with CONFIG_SCSI_LOGGING
- *        (otherwise the macros compile to empty statements), then do
- *        something like: 'echo "scsi log all" > /proc/scsi/scsi' to log
- *        everything or 'echo "scsi log {token} #N" > /proc/scsi/scsi'
- *        where {token} is one of [error,timeout,scan,mlqueue,mlcomplete,
- *        llqueue,llcomplete,hlqueue,hlcomplete,ioctl] and #N is 0...7
- *        (with 0 meaning off). For example: 'scsi log timeout 7 > 
- *        /proc/scsi/scsi' to get all logging messages from this driver.
- *        Should use hlcomplete but it is too "noisy" (sd uses it).
- *
- *      - This driver obtains memory (heap) for the low-level driver to
- *        transfer/dma to and from. It is obtained from up to 3 sources:
- *              - obtain heap via get_free_pages()
- *              - obtain heap from the shared scsi dma pool
- *              - obtain heap from kernel directly (kmalloc) [last choice]
- *        Each open() attempts to obtain a "reserve" buffer of
- *        SG_DEF_RESERVED_SIZE bytes (or 0 bytes if opened O_RDONLY). The
- *        amount actually obtained [which could be 0 bytes] can be found from
- *        the SG_GET_RESERVED_SIZE ioctl(). This reserved buffer size can
- *        be changed by calling the SG_SET_RESERVED_SIZE ioctl(). Since this
- *        is an ambit claim, it should be followed by a SG_GET_RESERVED_SIZE
- *        ioctl() to find out how much was actually obtained.
- *        A subsequent write() to this file descriptor will use the
- *        reserved buffer unless:
- *              - it is already in use (eg during command queuing)
- *              - or the write() needs a buffer size larger than the
- *                reserved size
- *        In these cases the write() will attempt to get the required memory
- *        for the duration of this request but, if memory is low, it may
- *        fail with ENOMEM.
+ *        (otherwise the macros compile to empty statements). 
+ *        Then before running the program to be debugged enter: 
+ *          # echo "scsi log timeout 7" > /proc/scsi/scsi 
+ *        This will send copious output to the console and the log which
+ *        is usually /var/log/messages. To turn off debugging enter:
+ *          # echo "scsi log timeout 0" > /proc/scsi/scsi 
+ *        The 'timeout' token was chosen because it is relatively unused.
+ *        The token 'hlcomplete' should be used but that triggers too
+ *        much output from the sd device driver. To dump the current
+ *        state of the SCSI mid level data structures enter:
+ *          # echo "scsi dump 1" > /proc/scsi/scsi 
+ *        To dump the state of sg's data structures get the 'sg_debug'
+ *        program from the utilities and enter:
+ *          # sg_debug /dev/sga 
+ *        or any valid sg device name. The state of _all_ sg devices
+ *        will be sent to the console and the log.
  *
  *      - The 'alt_address' field in the scatter_list structure and the
  *        related 'mem_src' indicate the source of the heap allocation.
@@ -158,7 +145,7 @@
     char closed;        /* 1 -> fd closed but request(s) outstanding */
     char my_mem_src;    /* heap whereabouts of this Sg_fd object */
     char cmd_q;         /* 1 -> allow command queuing, 0 -> don't */
-    char underrun_flag; /* 1 -> flag underruns, 0 -> don't, 2 -> test */
+    char underrun_flag; /* 1 -> flag underruns, 0 -> don't flag underruns */
     char next_cmd_len;  /* 0 -> automatic (def), >0 -> use on next write() */
 } Sg_fd; /* 1208 bytes long on i386 */
 
@@ -212,7 +199,6 @@
 static const int size_sg_header = sizeof(struct sg_header);
 
 
-
 static int sg_open(struct inode * inode, struct file * filp)
 {
     int dev = MINOR(inode->i_rdev);
@@ -316,7 +302,6 @@
     Sg_fd * sfp;
     Sg_request * srp;
     int req_pack_id = -1;
-    struct sg_header * shp = (struct sg_header *)buf;
 
     if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
         return -ENXIO;
@@ -329,8 +314,11 @@
         ; /* FIXME: Hmm.  Seek to the right place, or fail?  */
     if ((k = verify_area(VERIFY_WRITE, buf, count)))
         return k;
-    if (sfp->force_packid && (count >= size_sg_header))
-        req_pack_id = shp->pack_id;
+    if (sfp->force_packid && (count >= size_sg_header)) {
+        struct sg_header hdr;
+        copy_from_user(&hdr, buf, size_sg_header);
+        req_pack_id = hdr.pack_id;
+    }
     srp = sg_get_request(sfp, req_pack_id);
     if (! srp) { /* now wait on packet to arrive */
         if (filp->f_flags & O_NONBLOCK)
@@ -342,8 +330,7 @@
         if (res)
             return res; /* -ERESTARTSYS because signal hit process */
     }
-    if (2 != sfp->underrun_flag)
-        srp->header.pack_len = srp->header.reply_len;   /* Why ????? */
+    srp->header.pack_len = srp->header.reply_len;   /* Why ????? */
 
     /* Now copy the result back to the user buffer.  */
     if (count >= size_sg_header) {
@@ -391,9 +378,8 @@
     if (count < (size_sg_header + 6))
         return -EIO;   /* The minimum scsi command length is 6 bytes. */ 
 
-    srp = sg_add_request(sfp);
-    if (! srp) {
-        SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full, domain error\n"));
+    if (! (srp = sg_add_request(sfp))) {
+        SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full\n"));
         return -EDOM;
     }
     __copy_from_user(&srp->header, buf, size_sg_header); 
@@ -404,7 +390,8 @@
         if (sfp->next_cmd_len > MAX_COMMAND_SIZE) {
             SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n"));
             sfp->next_cmd_len = 0;
-            return -EDOM;
+            sg_remove_request(sfp, srp);
+            return -EIO;
         }
         cmd_size = sfp->next_cmd_len;
         sfp->next_cmd_len = 0; /* reset so only this write() effected */
@@ -422,9 +409,9 @@
                                                     srp->header.reply_len;
     mxsize -= size_sg_header;
     input_size -= size_sg_header;
-    if (input_size < 0) {
+    if ((input_size < 0)  || (srp->header.reply_len < 0)) {
         sg_remove_request(sfp, srp);
-        return -EIO; /* User did not pass enough bytes for this command. */
+        return -EIO; /* Count too small or reply_len negative. */
     }
     if ((k = sg_start_req(srp, mxsize, buf + cmd_size, input_size))) {
         SCSI_LOG_TIMEOUT(1, printk("sg_write: build err=%d\n", k));
@@ -432,8 +419,10 @@
         return k;    /* probably out of space --> ENOMEM */
     }
 /*  SCSI_LOG_TIMEOUT(7, printk("sg_write: allocating device\n")); */
-    if (! (SCpnt = scsi_allocate_device(NULL, sdp->device, 
-                                        !(filp->f_flags & O_NONBLOCK)))) {
+    spin_lock_irqsave(&io_request_lock, flags);
+    SCpnt = scsi_allocate_device(NULL, sdp->device, ! (filp->f_flags & O_NONBLOCK));
+    spin_unlock_irqrestore(&io_request_lock, flags);
+    if (! SCpnt) {
         sg_finish_rem_req(srp, NULL, 0);
         return -EAGAIN;   /* No available command blocks at the moment */
     }
@@ -490,7 +479,12 @@
     switch(cmd_in)
     {
     case SG_SET_TIMEOUT:
-        return get_user(sfp->timeout, (int *)arg);
+        result =  get_user(val, (int *)arg);
+        if (result) return result;
+        if (val < 0)
+            return -EIO;
+        sfp->timeout = val;
+        return 0;
     case SG_GET_TIMEOUT:  /* N.B. User receives timeout as return value */
         return sfp->timeout; /* strange ..., for backward compatibility */
     case SG_SET_FORCE_LOW_DMA:
@@ -514,14 +508,19 @@
         if (result) return result;
         else {
             Sg_scsi_id * sg_idp = (Sg_scsi_id *)arg;
-            __put_user((int)sdp->device->host->host_no, &sg_idp->host_no);
+            struct Scsi_Host * hostp = sdp->device->host;
+
+            __put_user((int)hostp->host_no, &sg_idp->host_no);
             __put_user((int)sdp->device->channel, &sg_idp->channel);
             __put_user((int)sdp->device->id, &sg_idp->scsi_id);
             __put_user((int)sdp->device->lun, &sg_idp->lun);
             __put_user((int)sdp->device->type, &sg_idp->scsi_type);
+            __put_user(hostp->cmd_per_lun ? hostp->cmd_per_lun :
+                       hostp->hostt->cmd_per_lun, &sg_idp->h_cmd_per_lun);
+            __put_user((short)sdp->device->queue_depth, 
+                       &sg_idp->d_queue_depth);
             __put_user(0, &sg_idp->unused1);
             __put_user(0, &sg_idp->unused2);
-            __put_user(0, &sg_idp->unused3);
             return 0;
         }
     case SG_SET_FORCE_PACK_ID:
@@ -605,6 +604,13 @@
         return put_user(sg_version_num, (int *)arg);
     case SG_EMULATED_HOST:
         return put_user(sdp->device->host->hostt->emulated, (int *)arg);
+    case SG_SCSI_RESET:
+        if (! scsi_block_when_processing_errors(sdp->device))
+            return -EBUSY;
+        result = get_user(val, (int *)arg);
+        if (result) return result;
+        /* Don't do anything till scsi mod level visibility */
+        return 0;
     case SCSI_IOCTL_SEND_COMMAND:
         /* Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the
            user already has read/write access to the generic device and so
@@ -685,10 +691,13 @@
     Sg_device * sdp;
     Sg_fd * sfp;
     Sg_request * srp = NULL;
-    int closed = 0;
+    static const int min_sb_len = 
+                SG_MAX_SENSE > sizeof(SCpnt->sense_buffer) ? 
+                        sizeof(SCpnt->sense_buffer) : SG_MAX_SENSE;
 
     if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max)) {
         SCSI_LOG_TIMEOUT(1, printk("sg__done: bad args dev=%d\n", dev));
+        wake_up(&SCpnt->device->device_wait);
         scsi_release_command(SCpnt);
         SCpnt = NULL;
         return;
@@ -711,6 +720,7 @@
     }
     if (! srp) {
         SCSI_LOG_TIMEOUT(1, printk("sg__done: req missing, dev=%d\n", dev));
+        wake_up(&SCpnt->device->device_wait);
         scsi_release_command(SCpnt);
         SCpnt = NULL;
         return;
@@ -720,15 +730,12 @@
     srp->data.sglist_len = SCpnt->sglist_len;
     srp->data.bufflen = SCpnt->bufflen;
     srp->data.buffer = SCpnt->buffer;
-    if (2 == sfp->underrun_flag)
-        srp->header.pack_len = SCpnt->underflow;
     sg_clr_scpnt(SCpnt);
     srp->my_cmdp = NULL;
 
     SCSI_LOG_TIMEOUT(4, printk("sg__done: dev=%d, scsi_stat=%d, res=0x%x\n", 
                 dev, (int)status_byte(SCpnt->result), (int)SCpnt->result));
-    memcpy(srp->header.sense_buffer, SCpnt->sense_buffer,
-           sizeof(SCpnt->sense_buffer));
+    memcpy(srp->header.sense_buffer, SCpnt->sense_buffer, min_sb_len);
     switch (host_byte(SCpnt->result)) 
     { /* This setup of 'result' is for backward compatibility and is best
          ignored by the user who should use target, host + driver status */
@@ -781,24 +788,28 @@
     srp->header.host_status = host_byte(SCpnt->result);
     srp->header.driver_status = driver_byte(SCpnt->result);
 
+    wake_up(&SCpnt->device->device_wait);
     scsi_release_command(SCpnt);
     SCpnt = NULL;
     if (sfp->closed) { /* whoops this fd already released, cleanup */
-        closed = 1;
         SCSI_LOG_TIMEOUT(1,
                printk("sg__done: already closed, freeing ...\n"));
 /* should check if module is unloaded <<<<<<< */
         sg_finish_rem_req(srp, NULL, 0);
+        srp = NULL;
         if (NULL == sfp->headrp) { 
             SCSI_LOG_TIMEOUT(1,
                 printk("sg__done: already closed, final cleanup\n"));
             sg_remove_sfp(sdp, sfp);
+            sfp = NULL;
         }
     }
 /* Now wake up any sg_read() that is waiting for this packet. */
-    wake_up_interruptible(&sfp->read_wait);
-    if ((sfp->async_qp) && (! closed))
-        kill_fasync(sfp->async_qp, SIGPOLL);
+    if (sfp && srp) {
+        wake_up_interruptible(&sfp->read_wait);
+        if (sfp->async_qp)
+            kill_fasync(sfp->async_qp, SIGPOLL);
+    }
 }
 
 static void sg_debug_all(const Sg_fd * sfp)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sim710_d.h linux.14p16/drivers/scsi/sim710_d.h
--- linux.vanilla/drivers/scsi/sim710_d.h	Wed Oct 20 01:12:47 1999
+++ linux.14p16/drivers/scsi/sim710_d.h	Thu Dec  9 15:33:56 1999
@@ -1,4 +1,4 @@
-u32 SCRIPT[] = {
+static u32 SCRIPT[] = {
 /*
 
 
@@ -1776,12 +1776,12 @@
 };
 
 #define A_dsa_cmnd	0x00000010
-u32 A_dsa_cmnd_used[] = {
+static u32 A_dsa_cmnd_used[] __attribute((unused)) = {
 	0x0000001d,
 };
 
 #define A_dsa_datain	0x00000028
-u32 A_dsa_datain_used[] = {
+static u32 A_dsa_datain_used[] __attribute((unused)) = {
 	0x0000003d,
 	0x0000003f,
 	0x00000041,
@@ -1913,7 +1913,7 @@
 };
 
 #define A_dsa_dataout	0x00000428
-u32 A_dsa_dataout_used[] = {
+static u32 A_dsa_dataout_used[] __attribute((unused)) = {
 	0x00000143,
 	0x00000145,
 	0x00000147,
@@ -2045,12 +2045,12 @@
 };
 
 #define A_dsa_msgin	0x00000020
-u32 A_dsa_msgin_used[] = {
+static u32 A_dsa_msgin_used[] __attribute((unused)) = {
 	0x0000002f,
 };
 
 #define A_dsa_msgout	0x00000008
-u32 A_dsa_msgout_used[] = {
+static u32 A_dsa_msgout_used[] __attribute((unused)) = {
 	0x00000013,
 	0x00000285,
 	0x000002c5,
@@ -2058,50 +2058,50 @@
 };
 
 #define A_dsa_select	0x00000000
-u32 A_dsa_select_used[] = {
+static u32 A_dsa_select_used[] __attribute((unused)) = {
 	0x00000006,
 };
 
 #define A_dsa_size	0x00000828
-u32 A_dsa_size_used[] = {
+static u32 A_dsa_size_used[] __attribute((unused)) = {
 };
 
 #define A_dsa_status	0x00000018
-u32 A_dsa_status_used[] = {
+static u32 A_dsa_status_used[] __attribute((unused)) = {
 	0x0000002b,
 };
 
 #define A_had_cmdout	0x00000004
-u32 A_had_cmdout_used[] = {
+static u32 A_had_cmdout_used[] __attribute((unused)) = {
 	0x0000001a,
 };
 
 #define A_had_datain	0x00000008
-u32 A_had_datain_used[] = {
+static u32 A_had_datain_used[] __attribute((unused)) = {
 	0x00000038,
 };
 
 #define A_had_dataout	0x00000010
-u32 A_had_dataout_used[] = {
+static u32 A_had_dataout_used[] __attribute((unused)) = {
 	0x0000013e,
 };
 
 #define A_had_extmsg	0x00000080
-u32 A_had_extmsg_used[] = {
+static u32 A_had_extmsg_used[] __attribute((unused)) = {
 	0x0000025a,
 	0x0000029a,
 	0x000002da,
 };
 
 #define A_had_msgin	0x00000040
-u32 A_had_msgin_used[] = {
+static u32 A_had_msgin_used[] __attribute((unused)) = {
 	0x00000248,
 	0x00000288,
 	0x000002c8,
 };
 
 #define A_had_msgout	0x00000002
-u32 A_had_msgout_used[] = {
+static u32 A_had_msgout_used[] __attribute((unused)) = {
 	0x00000010,
 	0x00000282,
 	0x000002c2,
@@ -2109,161 +2109,161 @@
 };
 
 #define A_had_select	0x00000001
-u32 A_had_select_used[] = {
+static u32 A_had_select_used[] __attribute((unused)) = {
 	0x0000000c,
 };
 
 #define A_had_status	0x00000020
-u32 A_had_status_used[] = {
+static u32 A_had_status_used[] __attribute((unused)) = {
 };
 
 #define A_int_bad_extmsg1a	0xab930000
-u32 A_int_bad_extmsg1a_used[] = {
+static u32 A_int_bad_extmsg1a_used[] __attribute((unused)) = {
 	0x00000263,
 };
 
 #define A_int_bad_extmsg1b	0xab930001
-u32 A_int_bad_extmsg1b_used[] = {
+static u32 A_int_bad_extmsg1b_used[] __attribute((unused)) = {
 	0x0000026b,
 };
 
 #define A_int_bad_extmsg2a	0xab930002
-u32 A_int_bad_extmsg2a_used[] = {
+static u32 A_int_bad_extmsg2a_used[] __attribute((unused)) = {
 	0x000002a3,
 };
 
 #define A_int_bad_extmsg2b	0xab930003
-u32 A_int_bad_extmsg2b_used[] = {
+static u32 A_int_bad_extmsg2b_used[] __attribute((unused)) = {
 	0x000002ab,
 };
 
 #define A_int_bad_extmsg3a	0xab930004
-u32 A_int_bad_extmsg3a_used[] = {
+static u32 A_int_bad_extmsg3a_used[] __attribute((unused)) = {
 	0x000002e3,
 };
 
 #define A_int_bad_extmsg3b	0xab930005
-u32 A_int_bad_extmsg3b_used[] = {
+static u32 A_int_bad_extmsg3b_used[] __attribute((unused)) = {
 	0x000002eb,
 };
 
 #define A_int_bad_msg1	0xab930006
-u32 A_int_bad_msg1_used[] = {
+static u32 A_int_bad_msg1_used[] __attribute((unused)) = {
 	0x00000255,
 };
 
 #define A_int_bad_msg2	0xab930007
-u32 A_int_bad_msg2_used[] = {
+static u32 A_int_bad_msg2_used[] __attribute((unused)) = {
 	0x00000295,
 };
 
 #define A_int_bad_msg3	0xab930008
-u32 A_int_bad_msg3_used[] = {
+static u32 A_int_bad_msg3_used[] __attribute((unused)) = {
 	0x000002d5,
 };
 
 #define A_int_cmd_bad_phase	0xab930009
-u32 A_int_cmd_bad_phase_used[] = {
+static u32 A_int_cmd_bad_phase_used[] __attribute((unused)) = {
 	0x00000027,
 };
 
 #define A_int_cmd_complete	0xab93000a
-u32 A_int_cmd_complete_used[] = {
+static u32 A_int_cmd_complete_used[] __attribute((unused)) = {
 	0x00000037,
 };
 
 #define A_int_data_bad_phase	0xab93000b
-u32 A_int_data_bad_phase_used[] = {
+static u32 A_int_data_bad_phase_used[] __attribute((unused)) = {
 	0x00000247,
 };
 
 #define A_int_disc1	0xab930019
-u32 A_int_disc1_used[] = {
+static u32 A_int_disc1_used[] __attribute((unused)) = {
 	0x00000277,
 };
 
 #define A_int_disc2	0xab93001a
-u32 A_int_disc2_used[] = {
+static u32 A_int_disc2_used[] __attribute((unused)) = {
 	0x000002b7,
 };
 
 #define A_int_disc3	0xab93001b
-u32 A_int_disc3_used[] = {
+static u32 A_int_disc3_used[] __attribute((unused)) = {
 	0x000002f7,
 };
 
 #define A_int_msg_sdtr1	0xab93000c
-u32 A_int_msg_sdtr1_used[] = {
+static u32 A_int_msg_sdtr1_used[] __attribute((unused)) = {
 	0x00000271,
 };
 
 #define A_int_msg_sdtr2	0xab93000d
-u32 A_int_msg_sdtr2_used[] = {
+static u32 A_int_msg_sdtr2_used[] __attribute((unused)) = {
 	0x000002b1,
 };
 
 #define A_int_msg_sdtr3	0xab93000e
-u32 A_int_msg_sdtr3_used[] = {
+static u32 A_int_msg_sdtr3_used[] __attribute((unused)) = {
 	0x000002f1,
 };
 
 #define A_int_no_msgout1	0xab93000f
-u32 A_int_no_msgout1_used[] = {
+static u32 A_int_no_msgout1_used[] __attribute((unused)) = {
 	0x00000281,
 };
 
 #define A_int_no_msgout2	0xab930010
-u32 A_int_no_msgout2_used[] = {
+static u32 A_int_no_msgout2_used[] __attribute((unused)) = {
 	0x000002c1,
 };
 
 #define A_int_no_msgout3	0xab930011
-u32 A_int_no_msgout3_used[] = {
+static u32 A_int_no_msgout3_used[] __attribute((unused)) = {
 	0x00000301,
 };
 
 #define A_int_not_cmd_complete	0xab930012
-u32 A_int_not_cmd_complete_used[] = {
+static u32 A_int_not_cmd_complete_used[] __attribute((unused)) = {
 	0x00000031,
 };
 
 #define A_int_not_rej	0xab93001c
-u32 A_int_not_rej_used[] = {
+static u32 A_int_not_rej_used[] __attribute((unused)) = {
 	0x0000030d,
 };
 
 #define A_int_resel_not_msgin	0xab930016
-u32 A_int_resel_not_msgin_used[] = {
+static u32 A_int_resel_not_msgin_used[] __attribute((unused)) = {
 	0x00000317,
 };
 
 #define A_int_reselected	0xab930017
-u32 A_int_reselected_used[] = {
+static u32 A_int_reselected_used[] __attribute((unused)) = {
 	0x0000031b,
 };
 
 #define A_int_sel_no_ident	0xab930013
-u32 A_int_sel_no_ident_used[] = {
+static u32 A_int_sel_no_ident_used[] __attribute((unused)) = {
 	0x0000000f,
 };
 
 #define A_int_sel_not_cmd	0xab930014
-u32 A_int_sel_not_cmd_used[] = {
+static u32 A_int_sel_not_cmd_used[] __attribute((unused)) = {
 	0x00000019,
 };
 
 #define A_int_selected	0xab930018
-u32 A_int_selected_used[] = {
+static u32 A_int_selected_used[] __attribute((unused)) = {
 	0x0000032d,
 };
 
 #define A_int_status_not_msgin	0xab930015
-u32 A_int_status_not_msgin_used[] = {
+static u32 A_int_status_not_msgin_used[] __attribute((unused)) = {
 	0x0000002d,
 };
 
 #define A_msgin_buf	0x00000000
-u32 A_msgin_buf_used[] = {
+static u32 A_msgin_buf_used[] __attribute((unused)) = {
 	0x0000024b,
 	0x0000025f,
 	0x00000267,
@@ -2280,7 +2280,7 @@
 };
 
 #define A_reselected_identify	0x00000000
-u32 A_reselected_identify_used[] = {
+static u32 A_reselected_identify_used[] __attribute((unused)) = {
 	0x00000319,
 };
 
@@ -2304,7 +2304,7 @@
 #define Ent_wait_disc2	0x00000ad0
 #define Ent_wait_disc3	0x00000bd0
 #define Ent_wait_disc_complete	0x000000d0
-u32 LABELPATCHES[] = {
+static u32 LABELPATCHES[] __attribute((unused)) = {
 	0x00000007,
 	0x00000009,
 	0x00000015,
@@ -2349,12 +2349,12 @@
 	0x0000032b,
 };
 
-struct {
+static struct {
 	u32	offset;
 	void		*address;
-} EXTERNAL_PATCHES[] = {
+} EXTERNAL_PATCHES[] __attribute((unused)) = {
 };
 
-u32 INSTRUCTIONS	= 407;
-u32 PATCHES	= 42;
-u32 EXTERNAL_PATCHES_LEN	= 0;
+static u32 INSTRUCTIONS __attribute((unused))	= 407;
+static u32 PATCHES __attribute((unused))	= 42;
+static u32 EXTERNAL_PATCHES_LEN __attribute((unused))	= 0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sr_ioctl.c linux.14p16/drivers/scsi/sr_ioctl.c
--- linux.vanilla/drivers/scsi/sr_ioctl.c	Sat Aug 14 02:26:50 1999
+++ linux.14p16/drivers/scsi/sr_ioctl.c	Thu Dec  9 15:33:50 1999
@@ -241,7 +241,6 @@
         u_char  sr_cmd[10];
 	char * buffer;
         int result;
-        unsigned long flags;
         	
 	sr_cmd[0] = SCMD_READ_SUBCHANNEL;
 	sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5);
@@ -253,20 +252,15 @@
 	sr_cmd[8] = 24;
 	sr_cmd[9] = 0;
 
-        spin_lock_irqsave(&io_request_lock, flags);
-	buffer = (unsigned char*) scsi_malloc(512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if(!buffer) return -ENOMEM;
+	if ((buffer = (unsigned char*) scsi_malloc(512)) == NULL)
+		return -ENOMEM;
 	
 	result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0);
 	
 	memcpy (mcn->medium_catalog_number, buffer + 9, 13);
         mcn->medium_catalog_number[13] = 0;
 
-        spin_lock_irqsave(&io_request_lock, flags);
 	scsi_free(buffer, 512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	
 	return result;
 }
 
@@ -395,7 +389,6 @@
     {
 	struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg;
 	char * buffer;
-        unsigned long flags;
 	
 	sr_cmd[0] = SCMD_READ_TOC;
 	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5);
@@ -405,19 +398,15 @@
 	sr_cmd[8] = 12;             /* LSB of length */
 	sr_cmd[9] = 0;
 	
-        spin_lock_irqsave(&io_request_lock, flags);
-	buffer = (unsigned char *) scsi_malloc(512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if(!buffer) return -ENOMEM;
+	if ((buffer = (unsigned char *) scsi_malloc(512)) == NULL)
+		return -ENOMEM;
 	
 	result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1);
 	
 	tochdr->cdth_trk0 = buffer[2];
 	tochdr->cdth_trk1 = buffer[3];
 	
-        spin_lock_irqsave(&io_request_lock, flags);
 	scsi_free(buffer, 512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
         break;
     }
 	
@@ -425,7 +414,6 @@
     {
 	struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg;
 	unsigned char * buffer;
-        unsigned long flags;
 	
 	sr_cmd[0] = SCMD_READ_TOC;
 	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) |
@@ -436,10 +424,8 @@
 	sr_cmd[8] = 12;            /* LSB of length */
 	sr_cmd[9] = 0;
 	
-        spin_lock_irqsave(&io_request_lock, flags);
-	buffer = (unsigned char *) scsi_malloc(512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if(!buffer) return -ENOMEM;
+	if ((buffer = (unsigned char *) scsi_malloc(512)) == NULL)
+		return -ENOMEM;
 	
 	result = sr_do_ioctl (target, sr_cmd, buffer, 12, 0);
 	
@@ -454,9 +440,7 @@
 	    tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
                                        + buffer[10]) << 8) + buffer[11];
 	
-        spin_lock_irqsave(&io_request_lock, flags);
 	scsi_free(buffer, 512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
         break;
     }
 	
@@ -482,7 +466,6 @@
     {
 	char * buffer, * mask;
 	struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
-        unsigned long flags;
 	
 	/* First we get the current params so we can just twiddle the volume */
 	
@@ -493,16 +476,12 @@
 	sr_cmd[4] = 28;
 	sr_cmd[5] = 0;
 	
-        spin_lock_irqsave(&io_request_lock, flags);
-	buffer = (unsigned char *) scsi_malloc(512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if(!buffer) return -ENOMEM;
+	if ((buffer = (unsigned char *) scsi_malloc(512)) == NULL)
+		return -ENOMEM;
 	
 	if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0))) {
 	    printk ("Hosed while obtaining audio mode page\n");
-            spin_lock_irqsave(&io_request_lock, flags);
 	    scsi_free(buffer, 512);
-            spin_unlock_irqrestore(&io_request_lock, flags);
             break;
 	}
 	
@@ -513,23 +492,17 @@
 	sr_cmd[4] = 28;
 	sr_cmd[5] = 0;
 	
-        spin_lock_irqsave(&io_request_lock, flags);
 	mask = (unsigned char *) scsi_malloc(512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
 	if(!mask) {
-            spin_lock_irqsave(&io_request_lock, flags);
 	    scsi_free(buffer, 512);
-            spin_unlock_irqrestore(&io_request_lock, flags);
 	    result = -ENOMEM;
             break;
 	};
 
 	if ((result = sr_do_ioctl (target, sr_cmd, mask, 28, 0))) {
 	    printk ("Hosed while obtaining mask for audio mode page\n");
-            spin_lock_irqsave(&io_request_lock, flags);
 	    scsi_free(buffer, 512);
 	    scsi_free(mask, 512);
-            spin_unlock_irqrestore(&io_request_lock, flags);
 	    break;
 	}
 	
@@ -548,10 +521,8 @@
 	sr_cmd[5] = 0;
 	
 	result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0);
-        spin_lock_irqsave(&io_request_lock, flags);
 	scsi_free(buffer, 512);
 	scsi_free(mask, 512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
         break;
     }
 	
@@ -559,7 +530,6 @@
     {
 	char * buffer;
 	struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
-        unsigned long flags;
 	
 	/* Get the current params */
 	
@@ -570,16 +540,12 @@
 	sr_cmd[4] = 28;
 	sr_cmd[5] = 0;
 	
-        spin_lock_irqsave(&io_request_lock, flags);
-	buffer = (unsigned char *) scsi_malloc(512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if(!buffer) return -ENOMEM;
+	if ((buffer = (unsigned char *) scsi_malloc(512)) == NULL)
+		return -ENOMEM;
 	
 	if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0))) {
 	    printk ("(CDROMVOLREAD) Hosed while obtaining audio mode page\n");
-            spin_lock_irqsave(&io_request_lock, flags);
 	    scsi_free(buffer, 512);
-            spin_unlock_irqrestore(&io_request_lock, flags);
             break;
 	}
 
@@ -588,9 +554,7 @@
 	volctrl->channel2 = buffer[25];
 	volctrl->channel3 = buffer[27];
 
-        spin_lock_irqsave(&io_request_lock, flags);
 	scsi_free(buffer, 512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
         break;
     }
 	
@@ -598,7 +562,6 @@
     {
 	struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg;
 	char * buffer;
-        unsigned long flags;
 	
 	sr_cmd[0] = SCMD_READ_SUBCHANNEL;
 	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02;    /* MSF format */
@@ -610,10 +573,8 @@
 	sr_cmd[8] = 16;
 	sr_cmd[9] = 0;
 	
-        spin_lock_irqsave(&io_request_lock, flags);
-	buffer = (unsigned char *) scsi_malloc(512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if(!buffer) return -ENOMEM;
+	if ((buffer = (unsigned char *) scsi_malloc(512)) == NULL)
+		return -ENOMEM;
 	
 	result = sr_do_ioctl(target, sr_cmd, buffer, 16, 0);
 	
@@ -630,9 +591,7 @@
 	subchnl->cdsc_absaddr.msf.second = buffer[10];
 	subchnl->cdsc_absaddr.msf.frame = buffer[11];
 	
-        spin_lock_irqsave(&io_request_lock, flags);
 	scsi_free(buffer, 512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
         break;
     }
     default:
@@ -740,15 +699,13 @@
 {
     unsigned char *raw_sector;
     int is_xa;
-    unsigned long flags;
     
     if (!xa_test)
         return 0;
    
-    spin_lock_irqsave(&io_request_lock, flags);
-    raw_sector = (unsigned char *) scsi_malloc(2048+512);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    if (!raw_sector) return -ENOMEM;
+    if ((raw_sector = (unsigned char *) scsi_malloc(2048+512)) == NULL)
+    	return -ENOMEM;
+
     if (0 == sr_read_sector(minor,scsi_CDs[minor].ms_offset+16,
                             CD_FRAMESIZE_RAW1,raw_sector)) {
         is_xa = (raw_sector[3] == 0x02) ? 1 : 0;
@@ -756,9 +713,7 @@
         /* read a raw sector failed for some reason. */
         is_xa = -1;
     }
-    spin_lock_irqsave(&io_request_lock, flags);
     scsi_free(raw_sector, 2048+512);
-    spin_unlock_irqrestore(&io_request_lock, flags);
 #ifdef DEBUG
     printk("sr%d: sr_is_xa: %d\n",minor,is_xa);
 #endif
@@ -781,7 +736,6 @@
         struct cdrom_msf   msf;
         int                lba, rc;
 	int                blocksize = 2048;
-        unsigned long flags;
 
         switch (cmd) {
         case CDROMREADMODE2: blocksize = CD_FRAMESIZE_RAW0; break; /* 2336 */
@@ -790,25 +744,24 @@
 
 	if (copy_from_user(&msf,(void*)arg,sizeof(msf)))
 		return -EFAULT;
-        spin_lock_irqsave(&io_request_lock, flags);
-        raw = scsi_malloc(2048+512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if (!(raw))
-                return -ENOMEM;
+
+	if ((raw = scsi_malloc(2048+512)) == NULL)
+		return -ENOMEM;
 
 	lba = (((msf.cdmsf_min0 * CD_SECS) + msf.cdmsf_sec0)
 			* CD_FRAMES + msf.cdmsf_frame0) - CD_MSF_OFFSET;
         if (lba < 0 || lba >= scsi_CDs[target].capacity)
+        {
+            scsi_free(raw, 2048+512);
             return -EINVAL;
+        }
 
         rc = sr_read_sector(target, lba, blocksize, raw);
 	if (!rc)
 		if (copy_to_user((void*)arg, raw, blocksize))
 			rc = -EFAULT;
 
-        spin_lock_irqsave(&io_request_lock, flags);
 	scsi_free(raw,2048+512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
 	return rc;
     }
     case CDROMREADAUDIO:
@@ -816,7 +769,6 @@
 	unsigned char      *raw;
         int                lba, rc=0;
         struct cdrom_read_audio ra;
-        unsigned long flags;
 
         if (!scsi_CDs[target].readcd_known || !scsi_CDs[target].readcd_cdda)
             return -EINVAL;  /* -EDRIVE_DOES_NOT_SUPPORT_THIS ? */
@@ -832,11 +784,8 @@
 
         if (lba < 0 || lba >= scsi_CDs[target].capacity)
             return -EINVAL;
-        spin_lock_irqsave(&io_request_lock, flags);
-        raw = scsi_malloc(2048+512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if (!(raw))
-            return -ENOMEM;
+        if ((raw = scsi_malloc(2048+512)) == NULL)
+		return -ENOMEM;
 
         while (ra.nframes > 0) {
             rc = sr_read_cd(target, raw, lba, 1, CD_FRAMESIZE_RAW);
@@ -850,9 +799,7 @@
             ra.nframes -= 1;
             lba++;
         }
-        spin_lock_irqsave(&io_request_lock, flags);
 	scsi_free(raw,2048+512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
         return rc;
     }
     case BLKRAGET:
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sr_vendor.c linux.14p16/drivers/scsi/sr_vendor.c
--- linux.vanilla/drivers/scsi/sr_vendor.c	Sat Aug 14 02:26:17 1999
+++ linux.14p16/drivers/scsi/sr_vendor.c	Thu Dec  9 15:33:54 1999
@@ -117,8 +117,8 @@
 		density = (blocklength > 2048) ? 0x81 : 0x83;
 #endif
 
-	buffer = (unsigned char *) scsi_malloc(512);
-	if (!buffer) return -ENOMEM;
+	if ((buffer = (unsigned char *) scsi_malloc(512)) == NULL)
+		return -ENOMEM;
 
 #ifdef DEBUG
 	printk("sr%d: MODE SELECT 0x%x/%d\n",minor,density,blocklength);
@@ -160,8 +160,8 @@
 	if (scsi_CDs[minor].cdi.mask & CDC_MULTI_SESSION)
 		return 0;
 	
-	buffer = (unsigned char *) scsi_malloc(512);
-	if(!buffer) return -ENOMEM;
+	if ((buffer = (unsigned char *) scsi_malloc(512)) == NULL)
+		return -ENOMEM;
 	
 	sector   = 0;         /* the multisession sector offset goes here  */
 	no_multi = 0;         /* flag: the drive can't handle multisession */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sym53c416.h linux.14p16/drivers/scsi/sym53c416.h
--- linux.vanilla/drivers/scsi/sym53c416.h	Sun Mar 28 19:04:11 1999
+++ linux.14p16/drivers/scsi/sym53c416.h	Tue Dec 21 00:51:22 1999
@@ -22,7 +22,9 @@
 #include <linux/version.h>
 #endif
 
+#ifndef LinuxVersionCode
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+#endif
 
 #include <linux/types.h>
 #include <linux/kdev_t.h>
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sym53c8xx.c linux.14p16/drivers/scsi/sym53c8xx.c
--- linux.vanilla/drivers/scsi/sym53c8xx.c	Wed Oct 20 01:12:47 1999
+++ linux.14p16/drivers/scsi/sym53c8xx.c	Thu Dec  9 15:33:56 1999
@@ -300,7 +300,7 @@
 **
 **==========================================================
 */
-#if	!defined(__i386__)
+#if	!defined(__i386__) && !defined(__sparc__)
 #define	SCSI_NCR_PCI_MEM_NOT_SUPPORTED
 #endif
 
@@ -586,10 +586,11 @@
 #endif
 
 #ifdef __sparc__
+#  include <asm/irq.h>
 #  define ioremap(base, size)		((u_long) __va(base))
 #  define iounmap(vaddr)
 #  define pcivtobus(p)			((p) & pci_dvma_mask)
-#  define memcpy_to_pci(a, b, c)	memcpy_toio((u_long) (a), (b), (c))
+#  define memcpy_to_pci(a, b, c)	memcpy_toio((void *) (a), (b), (c))
 #elif defined(__alpha__)
 #  define pcivtobus(p)			((p) & 0xfffffffful)
 #  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
@@ -1819,6 +1820,8 @@
 	*/
 	u_short		device_id;	/* PCI device id		*/
 	u_char		revision_id;	/* PCI device revision id	*/
+	u_char		pci_bus;	/* PCI bus number		*/
+	u_char		pci_devfn;	/* PCI device and function	*/
 	u_int		features;	/* Chip features map		*/
 	u_char		myaddr;		/* SCSI id of the adapter	*/
 	u_char		maxburst;	/* log base 2 of dwords burst	*/
@@ -4550,6 +4553,8 @@
 	sprintf(np->inst_name, NAME53C "%s-%d", np->chip_name, np->unit);
 	np->device_id	= device->chip.device_id;
 	np->revision_id	= device->chip.revision_id;
+	np->pci_bus	= device->slot.bus;
+	np->pci_devfn	= device->slot.device_fn;
 	np->features	= device->chip.features;
 	np->clock_divn	= device->chip.nr_divisor;
 	np->maxoffs	= device->chip.offset_max;
@@ -9476,6 +9481,8 @@
 	if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
 		unsigned f2;
 
+		OUTB(nc_istat, SRST); UDELAY (5); OUTB(nc_istat, 0);
+
 		(void) ncrgetfreq (np, 11);	/* throw away first result */
 		f1 = ncrgetfreq (np, 11);
 		f2 = ncrgetfreq (np, 11);
@@ -10261,6 +10268,8 @@
 	if (!cache_line_size)
 		suggested_cache_line_size = 16;
 
+	driver_setup.pci_fix_up |= 0x7;
+
 #endif	/* __sparc__ */
 
 #if defined(__i386__) && !defined(MODULE)
@@ -10574,7 +10583,15 @@
 */
 const char *sym53c8xx_info (struct Scsi_Host *host)
 {
+#ifdef __sparc__
+	/* Ok to do this on all archs? */
+	static char buffer[80];
+	ncb_p np = ((struct host_data *) host->hostdata)->ncb;
+	sprintf (buffer, "%s\nPCI bus %02x device %02x", SCSI_NCR_DRIVER_NAME, np->pci_bus, np->pci_devfn);
+	return buffer;
+#else
 	return SCSI_NCR_DRIVER_NAME;
+#endif
 }
 
 /*
@@ -11159,7 +11176,13 @@
 	copy_info(&info, "revision id 0x%x\n",	np->revision_id);
 
 	copy_info(&info, "  IO port address 0x%lx, ", (u_long) np->base_io);
+#ifdef __sparc__
+	copy_info(&info, "IRQ number %s\n", __irq_itoa(np->irq));
+	/* Ok to do this on all archs? */
+	copy_info(&info, "PCI bus %02x device %02x\n", np->pci_bus, np->pci_devfn);
+#else
 	copy_info(&info, "IRQ number %d\n", (int) np->irq);
+#endif
 
 #ifndef NCR_IOMAPPED
 	if (np->reg)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sym53c8xx_defs.h linux.14p16/drivers/scsi/sym53c8xx_defs.h
--- linux.vanilla/drivers/scsi/sym53c8xx_defs.h	Wed Oct 20 01:12:47 1999
+++ linux.14p16/drivers/scsi/sym53c8xx_defs.h	Tue Dec 21 00:51:22 1999
@@ -66,8 +66,9 @@
 #endif
 #include <linux/config.h>
 
+#ifndef LinuxVersionCode
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
+#endif
 /*
  * NCR PQS/PDS special device support.
  */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/u14-34f.c linux.14p16/drivers/scsi/u14-34f.c
--- linux.vanilla/drivers/scsi/u14-34f.c	Fri Oct  9 19:56:59 1998
+++ linux.14p16/drivers/scsi/u14-34f.c	Thu Dec  9 15:33:54 1999
@@ -1,6 +1,16 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *      16 Sep 1999 Rev. 5.11 for linux 2.2.12 and 2.3.18
+ *        + Updated to the new __setup interface for boot command line options.
+ *        + When loaded as a module, accepts the new parameter boot_options
+ *          which value is a string with the same format of the kernel boot
+ *          command line options. A valid example is:
+ *          modprobe u14-34f 'boot_options=\"0x230,0x340,lc:y,mq:4\"'
+ *
+ *      22 Jul 1999 Rev. 5.00 for linux 2.2.10 and 2.3.11
+ *        + Removed pre-2.2 source code compatibility.
+ *
  *      26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111
  *          Added command line option (et:[y|n]) to use the existing
  *          translation (returned by scsicam_bios_param) as disk geometry.
@@ -159,7 +169,7 @@
  *
  *          Multiple U14F and/or U34F host adapters are supported.
  *
- *  Copyright (C) 1994-1998 Dario Ballabio (dario@milano.europe.dg.com)
+ *  Copyright (C) 1994-1999 Dario Ballabio (dario@milano.europe.dg.com)
  *
  *  Redistribution and use in source and binary forms, with or without
  *  modification, are permitted provided that redistributions of source
@@ -251,7 +261,7 @@
  *  After the optional list of detection probes, other possible command line
  *  options are:
  *
- *  eh:y  use new scsi code (linux 2.2 only);
+ *  eh:y  use new scsi code;
  *  eh:n  use old scsi code;
  *  et:y  use disk geometry returned by scsicam_bios_param;
  *  et:n  use disk geometry jumpered on the board;
@@ -318,7 +328,7 @@
 #if defined(MODULE)
 #include <linux/module.h>
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,26)
+MODULE_PARM(boot_options, "s");
 MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i");
 MODULE_PARM(linked_comm, "i");
 MODULE_PARM(have_old_firmware, "i");
@@ -327,7 +337,6 @@
 MODULE_PARM(use_new_eh_code, "i");
 MODULE_PARM(ext_tran, "i");
 MODULE_AUTHOR("Dario Ballabio");
-#endif
 
 #endif
 
@@ -349,42 +358,21 @@
 #include "u14-34f.h"
 #include <linux/stat.h>
 #include <linux/config.h>
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,36)
 #include <linux/init.h>
+#include <linux/ctype.h>
+
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)
+#include <asm/spinlock.h>
 #else
-#define __initfunc(A) A
-#define __initdata
-#define __init
+#include <linux/spinlock.h>
 #endif
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
-#include <asm/spinlock.h>
-#define IRQ_FLAGS
-#define IRQ_LOCK
-#define IRQ_LOCK_SAVE
-#define IRQ_UNLOCK
-#define IRQ_UNLOCK_RESTORE
 #define SPIN_FLAGS unsigned long spin_flags;
 #define SPIN_LOCK spin_lock_irq(&io_request_lock);
 #define SPIN_LOCK_SAVE spin_lock_irqsave(&io_request_lock, spin_flags);
 #define SPIN_UNLOCK spin_unlock_irq(&io_request_lock);
 #define SPIN_UNLOCK_RESTORE \
                   spin_unlock_irqrestore(&io_request_lock, spin_flags);
-static int use_new_eh_code = TRUE;
-#else
-#define IRQ_FLAGS unsigned long irq_flags;
-#define IRQ_LOCK cli();
-#define IRQ_LOCK_SAVE do {save_flags(irq_flags); cli();} while (0);
-#define IRQ_UNLOCK sti();
-#define IRQ_UNLOCK_RESTORE do {restore_flags(irq_flags);} while (0);
-#define SPIN_FLAGS
-#define SPIN_LOCK
-#define SPIN_LOCK_SAVE
-#define SPIN_UNLOCK
-#define SPIN_UNLOCK_RESTORE
-static int use_new_eh_code = FALSE;
-#endif
 
 struct proc_dir_entry proc_scsi_u14_34f = {
     PROC_SCSI_U14_34F, 6, "u14_34f",
@@ -467,7 +455,10 @@
 #define ASOK              0x00
 #define ASST              0x91
 
-#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)
+#define ARRAY_SIZE(x) (sizeof (x) / sizeof((x)[0]))
+#endif
+
 #define YESNO(a) ((a) ? 'y' : 'n')
 #define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM)
 
@@ -532,7 +523,7 @@
 /* Initialize num_boards so that ihdlr can work while detect is in progress */
 static unsigned int num_boards = MAX_BOARDS;
 
-static unsigned long io_port[] __initdata = {
+static unsigned long io_port[] = {
 
    /* Space for MAX_INT_PARAM ports usable while loading as a module */
    SKIP,    SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,
@@ -570,6 +561,8 @@
 static int setup_done = FALSE;
 static int link_statistics = 0;
 static int ext_tran = FALSE;
+static int use_new_eh_code = TRUE;
+static char *boot_options = NULL;
 
 #if defined(HAVE_OLD_UX4F_FIRMWARE)
 static int have_old_firmware = TRUE;
@@ -592,9 +585,7 @@
 static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
    Scsi_Device *dev;
    int j, ntag = 0, nuntag = 0, tqd, utqd;
-   IRQ_FLAGS
 
-   IRQ_LOCK_SAVE
    j = ((struct hostdata *) host->hostdata)->board_number;
 
    for(dev = devlist; dev; dev = dev->next) {
@@ -642,7 +633,6 @@
              dev->queue_depth, link_suffix, tag_suffix);
       }
 
-   IRQ_UNLOCK_RESTORE
    return;
 }
 
@@ -686,10 +676,8 @@
    outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
 
    SPIN_UNLOCK
-   IRQ_UNLOCK
    time = jiffies;
    while ((jiffies - time) < HZ && limit++ < 20000) udelay(100L);
-   IRQ_LOCK
    SPIN_LOCK
 
    if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) {
@@ -701,8 +689,8 @@
    return FALSE;
 }
 
-__initfunc (static inline int port_detect \
-      (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
+static inline int port_detect \
+      (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt) {
    unsigned char irq, dma_channel, subversion, i;
    unsigned char in_byte;
    char *bus_type, dma_name[16];
@@ -747,7 +735,9 @@
    sprintf(name, "%s%d", driver_name, j);
 
    if(check_region(port_base, REGION_SIZE)) {
+#if defined(DEBUG_DETECT)
       printk("%s: address 0x%03lx in use, skipping probe.\n", name, port_base);
+#endif
       return FALSE;
       }
 
@@ -781,11 +771,7 @@
 
    if (have_old_firmware) tpnt->use_clustering = DISABLE_CLUSTERING;
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
    tpnt->use_new_eh_code = use_new_eh_code;
-#else
-   use_new_eh_code = FALSE;
-#endif
 
    sh[j] = scsi_register(tpnt, sizeof(struct hostdata));
 
@@ -894,7 +880,7 @@
    if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN;
 
    if (j == 0) {
-      printk("UltraStor 14F/34F: Copyright (C) 1994-1998 Dario Ballabio.\n");
+      printk("UltraStor 14F/34F: Copyright (C) 1994-1999 Dario Ballabio.\n");
       printk("%s config options -> of:%c, lc:%c, mq:%d, eh:%c, et:%c.\n",
              driver_name, YESNO(have_old_firmware), YESNO(linked_comm),
              max_queue_depth, YESNO(use_new_eh_code), YESNO(ext_tran));
@@ -915,7 +901,7 @@
    return TRUE;
 }
 
-__initfunc (void u14_34f_setup(char *str, int *ints)) {
+static void internal_setup(char *str, int *ints) {
    int i, argc = ints[0];
    char *cur = str, *pc;
 
@@ -949,13 +935,30 @@
    return;
 }
 
-__initfunc (int u14_34f_detect(Scsi_Host_Template *tpnt)) {
+static int option_setup(char *str) {
+   int ints[MAX_INT_PARAM];
+   char *cur = str;
+   int i = 1;
+
+   while (cur && isdigit(*cur) && i <= MAX_INT_PARAM) {
+      ints[i++] = simple_strtoul(cur, NULL, 0);
+
+      if ((cur = strchr(cur, ',')) != NULL) cur++;
+   }
+
+   ints[0] = i - 1;
+   internal_setup(cur, ints);
+   return 0;
+}
+
+int u14_34f_detect(Scsi_Host_Template *tpnt)
+{
    unsigned int j = 0, k;
-   IRQ_FLAGS
 
-   IRQ_LOCK_SAVE
    tpnt->proc_dir = &proc_scsi_u14_34f;
 
+   if(boot_options) option_setup(boot_options);
+
 #if defined(MODULE)
    /* io_port could have been modified when loading as a module */
    if(io_port[0] != SKIP) {
@@ -974,7 +977,6 @@
       }
 
    num_boards = j;
-   IRQ_UNLOCK_RESTORE
    return j;
 }
 
@@ -1110,11 +1112,8 @@
 
 int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
    int rtn;
-   IRQ_FLAGS
 
-   IRQ_LOCK_SAVE
    rtn = do_qcomm(SCpnt, done);
-   IRQ_UNLOCK_RESTORE
    return rtn;
 }
 
@@ -1186,16 +1185,11 @@
 
 int u14_34f_old_abort(Scsi_Cmnd *SCarg) {
    int rtn;
-   IRQ_FLAGS
 
-   IRQ_LOCK_SAVE
    rtn = do_old_abort(SCarg);
-   IRQ_UNLOCK_RESTORE
    return rtn;
 }
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
-
 static inline int do_abort(Scsi_Cmnd *SCarg) {
    unsigned int i, j;
 
@@ -1273,8 +1267,6 @@
    return do_abort(SCarg);
 }
 
-#endif /* new_eh_code */
-
 static inline int do_old_reset(Scsi_Cmnd *SCarg) {
    unsigned int i, j, time, k, c, limit = 0;
    int arg_done = FALSE;
@@ -1362,10 +1354,8 @@
 
    HD(j)->in_reset = TRUE;
    SPIN_UNLOCK
-   IRQ_UNLOCK
    time = jiffies;
    while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
-   IRQ_LOCK
    SPIN_LOCK
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
@@ -1401,7 +1391,6 @@
          continue;
 
       SCpnt->scsi_done(SCpnt);
-      IRQ_LOCK
       }
 
    HD(j)->in_reset = FALSE;
@@ -1419,16 +1408,11 @@
 
 int u14_34f_old_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
    int rtn;
-   IRQ_FLAGS
 
-   IRQ_LOCK_SAVE
    rtn = do_old_reset(SCarg);
-   IRQ_UNLOCK_RESTORE
    return rtn;
 }
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
-
 static inline int do_reset(Scsi_Cmnd *SCarg) {
    unsigned int i, j, time, k, c, limit = 0;
    int arg_done = FALSE;
@@ -1510,10 +1494,8 @@
 
    HD(j)->in_reset = TRUE;
    SPIN_UNLOCK
-   IRQ_UNLOCK
    time = jiffies;
    while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
-   IRQ_LOCK
    SPIN_LOCK
    printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
 
@@ -1549,7 +1531,6 @@
          continue;
 
       SCpnt->scsi_done(SCpnt);
-      IRQ_LOCK
       }
 
    HD(j)->in_reset = FALSE;
@@ -1566,8 +1547,6 @@
    return do_reset(SCarg);
 }
 
-#endif /* new_eh_code */
-
 int u14_34f_biosparam(Disk *disk, kdev_t dev, int *dkinfo) {
    unsigned int j = 0;
    int size = disk->capacity;
@@ -1956,24 +1935,18 @@
 
 static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
    unsigned int j;
-   IRQ_FLAGS
    SPIN_FLAGS
 
    /* Check if the interrupt must be processed by this handler */
    if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
 
    SPIN_LOCK_SAVE
-   IRQ_LOCK_SAVE
    ihdlr(irq, j);
-   IRQ_UNLOCK_RESTORE
    SPIN_UNLOCK_RESTORE
 }
 
 int u14_34f_release(struct Scsi_Host *shpnt) {
    unsigned int i, j;
-   IRQ_FLAGS
-
-   IRQ_LOCK_SAVE
 
    for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++);
 
@@ -1989,7 +1962,6 @@
 
    release_region(sh[j]->io_port, sh[j]->n_io_port);
    scsi_unregister(sh[j]);
-   IRQ_UNLOCK_RESTORE
    return FALSE;
 }
 
@@ -1997,4 +1969,15 @@
 Scsi_Host_Template driver_template = ULTRASTOR_14_34F;
 
 #include "scsi_module.c"
+
+#else
+
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)
+void u14_34f_setup(char *str, int *ints) {
+   internal_setup(str, ints);
+}
+#else
+__setup("u14-34f=", option_setup);
 #endif
+
+#endif /* end MODULE */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/u14-34f.h linux.14p16/drivers/scsi/u14-34f.h
--- linux.vanilla/drivers/scsi/u14-34f.h	Sun Mar 28 19:04:08 1999
+++ linux.14p16/drivers/scsi/u14-34f.h	Tue Dec 21 00:51:22 1999
@@ -16,11 +16,7 @@
 int u14_34f_old_reset(Scsi_Cmnd *, unsigned int);
 int u14_34f_biosparam(Disk *, kdev_t, int *);
 
-#define U14_34F_VERSION "4.33.00"
-
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
+#define U14_34F_VERSION "5.11.01"
 
 #define ULTRASTOR_14_34F {                                                   \
                 name:         "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
@@ -39,22 +35,5 @@
                 use_clustering:          ENABLE_CLUSTERING,                  \
                 use_new_eh_code:         1    /* Enable new error code */    \
                 }
-
-#else /* Use old scsi code */
-
-#define ULTRASTOR_14_34F {                                                   \
-                name:         "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
-                detect:                  u14_34f_detect,                     \
-                release:                 u14_34f_release,                    \
-                queuecommand:            u14_34f_queuecommand,               \
-                abort:                   u14_34f_old_abort,                  \
-                reset:                   u14_34f_old_reset,                  \
-                bios_param:              u14_34f_biosparam,                  \
-                this_id:                 7,                                  \
-                unchecked_isa_dma:       1,                                  \
-                use_clustering:          ENABLE_CLUSTERING                   \
-                }
-
-#endif
 
 #endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/Config.in linux.14p16/drivers/sound/Config.in
--- linux.vanilla/drivers/sound/Config.in	Wed Oct 20 01:12:47 1999
+++ linux.14p16/drivers/sound/Config.in	Thu Dec  9 15:34:01 1999
@@ -28,6 +28,9 @@
       hex 'Gameport I/O 200,208,210,218' CONFIG_SOUND_ES1371_GAMEPORT 200
    fi
 fi
+
+dep_tristate 'ESS Maestro' CONFIG_SOUND_MAESTRO $CONFIG_SOUND
+
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    dep_tristate 'ESS Solo1 (Experimental)' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND
 fi
@@ -114,8 +117,6 @@
       comment 'Enter -1 to the following question if you have something else such as SB16/32.'
       int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' CONFIG_SB_MPU_IRQ -1
   fi
-  
-  dep_tristate 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS
   
   dep_tristate 'Gravis Ultrasound support' CONFIG_SOUND_GUS $CONFIG_SOUND_OSS
   if [ "$CONFIG_SOUND_GUS" = "y" -o "$CONFIG_SOUND_GUS" = "m" ]; then
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/Makefile linux.14p16/drivers/sound/Makefile
--- linux.vanilla/drivers/sound/Makefile	Wed Oct 20 01:12:47 1999
+++ linux.14p16/drivers/sound/Makefile	Thu Dec  9 15:34:01 1999
@@ -43,7 +43,6 @@
 obj-$(CONFIG_SOUND)		+= soundcore.o
 obj-$(CONFIG_DMASOUND)		+= dmasound.o
 obj-$(CONFIG_SOUND_OSS)		+= sound.o
-obj-$(CONFIG_SOUND_ADLIB)	+= adlib_card.o opl3.o
 obj-$(CONFIG_SOUND_CS4232)	+= cs4232.o ad1848.o 
 
 # In theory, there's probably no reason to include the uart401 code
@@ -84,6 +83,7 @@
 obj-$(CONFIG_SOUND_ES1370)	+= es1370.o
 obj-$(CONFIG_SOUND_ES1371)	+= es1371.o
 obj-$(CONFIG_SOUND_ESSSOLO1)	+= esssolo1.o
+obj-$(CONFIG_SOUND_MAESTRO)	+= maestro.o
 obj-$(CONFIG_SOUND_SONICVIBES)	+= sonicvibes.o
 
 # Declare multi-part drivers.
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/ac97.c linux.14p16/drivers/sound/ac97.c
--- linux.vanilla/drivers/sound/ac97.c	Wed Oct 20 01:12:47 1999
+++ linux.14p16/drivers/sound/ac97.c	Mon Dec 13 19:29:11 1999
@@ -5,6 +5,10 @@
 /* And for stereo. */
 #define ST 1
 
+/* Whether or not the bits in the channel are inverted. */
+#define INV 1
+#define NINV 0
+
 static struct ac97_chn_desc {
     int ac97_regnum;
     int oss_channel;
@@ -13,21 +17,22 @@
     int oss_mask;
     int recordNum;
     u16 regmask;
+    int is_inverted;
 } mixerRegs[] = {
-    { AC97_MASTER_VOL_STEREO, SOUND_MIXER_VOLUME,   0x3f, ST, SOUND_MASK_VOLUME,   5, 0x0000 },
-    { AC97_MASTER_VOL_MONO,   SOUND_MIXER_PHONEOUT, 0x3f, MO, SOUND_MASK_PHONEOUT, 6, 0x0000 },
-    { AC97_MASTER_TONE,       SOUND_MIXER_TREBLE,   0x0f, MO, SOUND_MASK_TREBLE,  -1, 0x00ff },
-    { AC97_MASTER_TONE,       SOUND_MIXER_BASS,     0x0f, MO, SOUND_MASK_BASS,    -1, 0xff00 },
-    { AC97_PCBEEP_VOL,        SOUND_MIXER_SPEAKER,  0x0f, MO, SOUND_MASK_SPEAKER, -1, 0x001e },
-    { AC97_PHONE_VOL,         SOUND_MIXER_PHONEIN,  0x1f, MO, SOUND_MASK_PHONEIN,  7, 0x0000 },
-    { AC97_MIC_VOL,           SOUND_MIXER_MIC,      0x1f, MO, SOUND_MASK_MIC,      0, 0x0000 },
-    { AC97_LINEIN_VOL,        SOUND_MIXER_LINE,     0x1f, ST, SOUND_MASK_LINE,     4, 0x0000 },
-    { AC97_CD_VOL,            SOUND_MIXER_CD,       0x1f, ST, SOUND_MASK_CD,       1, 0x0000 },
-    { AC97_VIDEO_VOL,         SOUND_MIXER_VIDEO,    0x1f, ST, SOUND_MASK_VIDEO,    2, 0x0000 },
-    { AC97_AUX_VOL,           SOUND_MIXER_LINE1,    0x1f, ST, SOUND_MASK_LINE1,	   3, 0x0000 },
-    { AC97_PCMOUT_VOL,        SOUND_MIXER_PCM,      0x1f, ST, SOUND_MASK_PCM,     -1, 0x0000 },
-    { AC97_RECORD_GAIN,       SOUND_MIXER_IGAIN,    0x0f, ST, SOUND_MASK_IGAIN,   -1, 0x0000 },
-    { -1,   -1,                   0xff, 0, 0,                   -1, 0x0000 },
+    { AC97_MASTER_VOL_STEREO, SOUND_MIXER_VOLUME,   0x3f, ST, SOUND_MASK_VOLUME,   5, 0x0000, INV  },
+    { AC97_MASTER_VOL_MONO,   SOUND_MIXER_PHONEOUT, 0x3f, MO, SOUND_MASK_PHONEOUT, 6, 0x0000, INV  },
+    { AC97_MASTER_TONE,       SOUND_MIXER_TREBLE,   0x0f, MO, SOUND_MASK_TREBLE,  -1, 0x00ff, INV  },
+    { AC97_MASTER_TONE,       SOUND_MIXER_BASS,     0x0f, MO, SOUND_MASK_BASS,    -1, 0xff00, INV  },
+    { AC97_PCBEEP_VOL,        SOUND_MIXER_SPEAKER,  0x0f, MO, SOUND_MASK_SPEAKER, -1, 0x001e, INV  },
+    { AC97_PHONE_VOL,         SOUND_MIXER_PHONEIN,  0x1f, MO, SOUND_MASK_PHONEIN,  7, 0x0000, INV  },
+    { AC97_MIC_VOL,           SOUND_MIXER_MIC,      0x1f, MO, SOUND_MASK_MIC,      0, 0x0000, INV  },
+    { AC97_LINEIN_VOL,        SOUND_MIXER_LINE,     0x1f, ST, SOUND_MASK_LINE,     4, 0x0000, INV  },
+    { AC97_CD_VOL,            SOUND_MIXER_CD,       0x1f, ST, SOUND_MASK_CD,       1, 0x0000, INV  },
+    { AC97_VIDEO_VOL,         SOUND_MIXER_VIDEO,    0x1f, ST, SOUND_MASK_VIDEO,    2, 0x0000, INV  },
+    { AC97_AUX_VOL,           SOUND_MIXER_LINE1,    0x1f, ST, SOUND_MASK_LINE1,	   3, 0x0000, INV  },
+    { AC97_PCMOUT_VOL,        SOUND_MIXER_PCM,      0x1f, ST, SOUND_MASK_PCM,     -1, 0x0000, INV  },
+    { AC97_RECORD_GAIN,       SOUND_MIXER_IGAIN,    0x0f, ST, SOUND_MASK_IGAIN,   -1, 0x0000, NINV },
+    { -1,		      -1,		    0xff, 0,  0,                  -1, 0x0000, 0    },
 };
 
 static struct ac97_chn_desc *
@@ -104,6 +109,25 @@
     return 0;
 }
 
+/* Reset the mixer to the currently saved settings.  */
+int
+ac97_reset (struct ac97_hwint *dev)
+{
+    int x;
+
+    if (dev->reset_device (dev))
+	return -1;
+
+    /* Now set the registers back to their last-written values. */
+    for (x = 0; mixerRegs[x].ac97_regnum != -1; x++) {
+	int regnum = mixerRegs[x].ac97_regnum;
+	int value = dev->last_written_mixer_values [regnum / 2];
+	if (value >= 0)
+	    ac97_put_register (dev, regnum, value);
+    }
+    return 0;
+}
+
 /* Return the contents of register REG; use the cache if the value in it
    is valid.  Returns a negative error code on failure. */
 int
@@ -156,38 +180,45 @@
    scaled value on success.  */
 
 static int
-ac97_scale_to_oss_val (int value, int maxval, int is_stereo)
+ac97_scale_to_oss_val (int value, int maxval, int is_stereo, int inv)
 {
     /* Muted?  */
     if (value & AC97_MUTE)
 	return 0;
 
     if (is_stereo)
-	return (ac97_scale_to_oss_val (value & 255, maxval, 0) << 8)
-	| (ac97_scale_to_oss_val ((value >> 8) & 255, maxval, 0) << 0);
+	return (ac97_scale_to_oss_val (value & 255, maxval, 0, inv) << 8)
+	| (ac97_scale_to_oss_val ((value >> 8) & 255, maxval, 0, inv) << 0);
     else {
 	int i;
 	
 	/* Inverted. */
-	value = maxval - value;
+	if (inv)
+	    value = maxval - value;
 
 	i = (value * 100 + (maxval / 2)) / maxval;
 	if (i > 100)
 	     i = 100;
+	if (i < 0)
+	    i = 0;
 	return i;
     }
 }
 
 static int
-ac97_scale_from_oss_val (int value, int maxval, int is_stereo)
+ac97_scale_from_oss_val (int value, int maxval, int is_stereo, int inv)
 {
     if (is_stereo)
-	return (ac97_scale_from_oss_val (value & 255, maxval, 0) << 8)
-	| (ac97_scale_from_oss_val ((value >> 8) & 255, maxval, 0) << 0);
+	return (ac97_scale_from_oss_val (value & 255, maxval, 0, inv) << 8)
+	| (ac97_scale_from_oss_val ((value >> 8) & 255, maxval, 0, inv) << 0);
     else {
-	int i = maxval - ((value & 255) * maxval + 50) / 100;
+	int i = ((value & 255) * maxval + 50) / 100;
+	if (inv)
+	    i = maxval - i;
 	if (i < 0)
 	    i = 0;
+	if (i > maxval)
+	    i = maxval;
 	return i;
     }
 }
@@ -204,7 +235,8 @@
     if (! ac97_is_valid_channel (dev, channel))
 	return -ENODEV;
     scaled_value = ac97_scale_from_oss_val (oss_value, channel->maxval,
-					    channel->is_stereo);
+					    channel->is_stereo, 
+					    channel->is_inverted);
     if (scaled_value < 0)
 	return scaled_value;
 
@@ -253,7 +285,8 @@
 	    regval >>= 1;
     }
     return ac97_scale_to_oss_val (regval, channel->maxval,
-				  channel->is_stereo);
+				  channel->is_stereo, 
+				  channel->is_inverted);
 }
 
 int
@@ -383,8 +416,9 @@
 		    else
 			ret = -EFAULT;
 		}
-		if (ret >= 0) {
-		    if (dev->last_written_OSS_values[channel] == AC97_REGVAL_UNKNOWN)
+		if (ret >= 0 && (dir & _IOC_READ)) {
+		    if (dev->last_written_OSS_values[channel]
+			== AC97_REGVAL_UNKNOWN)
 			dev->last_written_OSS_values[channel]
 			    = ac97_get_mixer_scaled (dev, channel);
 		    ret = dev->last_written_OSS_values[channel];
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/ac97.h linux.14p16/drivers/sound/ac97.h
--- linux.vanilla/drivers/sound/ac97.h	Wed Oct 20 01:12:47 1999
+++ linux.14p16/drivers/sound/ac97.h	Tue Dec 21 01:05:24 1999
@@ -10,7 +10,7 @@
 #include "sound_config.h"
 #include "sound_calls.h"
 
-#define  AC97_RESET              0x0000      //  */
+#define  AC97_RESET              0x0000      //
 #define  AC97_MASTER_VOL_STEREO  0x0002      // Line Out
 #define  AC97_HEADPHONE_VOL      0x0004      // 
 #define  AC97_MASTER_VOL_MONO    0x0006      // TAD Output
@@ -33,6 +33,32 @@
 
 /* registers 0x0028 - 0x0058 are reserved */
 
+/* AC'97 2.0 */
+#define AC97_EXTENDED_ID	0x0028	/* Extended Audio ID */
+#define AC97_EXTENDED_STATUS	0x002A	/* Extended Audio Status */
+#define AC97_PCM_FRONT_DAC_RATE 0x002C  /* PCM Front DAC Rate */
+#define AC97_PCM_SURR_DAC_RATE  0x002E  /* PCM Surround DAC Rate */
+#define AC97_PCM_LFE_DAC_RATE   0x0030  /* PCM LFE DAC Rate */
+#define AC97_PCM_LR_DAC_RATE	0x0032	/* PCM LR DAC Rate */
+#define AC97_PCM_MIC_ADC_RATE   0x0034  /* PCM MIC ADC Rate */
+#define AC97_CENTER_LFE_MASTER  0x0036  /* Center + LFE Master Volume */
+#define AC97_SURROUND_MASTER    0x0038  /* Surround (Rear) Master Volume */
+#define AC97_RESERVED_3A	0x003A	/* Reserved */
+/* range 0x3c-0x58 - MODEM */
+
+/* AC'97 2.0 */
+#define AC97_EXTENDED_ID	0x0028	/* Extended Audio ID */
+#define AC97_EXTENDED_STATUS	0x002A	/* Extended Audio Status */
+#define AC97_PCM_FRONT_DAC_RATE 0x002C  /* PCM Front DAC Rate */
+#define AC97_PCM_SURR_DAC_RATE  0x002E  /* PCM Surround DAC Rate */
+#define AC97_PCM_LFE_DAC_RATE   0x0030  /* PCM LFE DAC Rate */
+#define AC97_PCM_LR_DAC_RATE	0x0032	/* PCM LR DAC Rate */
+#define AC97_PCM_MIC_ADC_RATE   0x0034  /* PCM MIC ADC Rate */
+#define AC97_CENTER_LFE_MASTER  0x0036  /* Center + LFE Master Volume */
+#define AC97_SURROUND_MASTER    0x0038  /* Surround (Rear) Master Volume */
+#define AC97_RESERVED_3A	0x003A	/* Reserved */
+/* range 0x3c-0x58 - MODEM */
+
 /* registers 0x005a - 0x007a are vendor reserved */
 
 #define  AC97_VENDOR_ID1         0x007c
@@ -194,6 +220,10 @@
 /* Default ioctl. */
 extern int ac97_mixer_ioctl (struct ac97_hwint *dev, unsigned int cmd,
 			     caddr_t arg);
+
+/* Do a complete reset on the AC97 mixer, restoring all mixer registers to
+   the current values.  Normally used after an APM resume event.  */
+extern int ac97_reset (struct ac97_hwint *dev);
 #endif
 
 /*
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/ad1848.c linux.14p16/drivers/sound/ad1848.c
--- linux.vanilla/drivers/sound/ad1848.c	Wed Oct 20 01:12:48 1999
+++ linux.14p16/drivers/sound/ad1848.c	Thu Dec  9 15:34:00 1999
@@ -71,7 +71,8 @@
 #define MD_4232		5
 #define MD_C930		6
 #define MD_IWAVE	7
-#define MD_4235         8 /* Crystal Audio CS4235 */
+#define MD_4235         8 /* Crystal Audio CS4235  */
+#define MD_1845_SSCAPE  9 /* Ensoniq Soundscape PNP*/
 
 	/* Mixer parameters */
 	int             recmask;
@@ -100,6 +101,7 @@
 
 static int nr_ad1848_devs = 0;
 int deskpro_xl = 0;
+int deskpro_m = 0;
 #ifdef CONFIG_SOUND_SPRO
 int soundpro = 1;
 #else
@@ -117,7 +119,7 @@
 
 #endif
 
-static int ad_format_mask[9 /*devc->model */ ] =
+static int ad_format_mask[10 /*devc->model */ ] =
 {
 	0,
 	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
@@ -127,7 +129,8 @@
 	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
 	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
 	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
-	AFMT_U8 | AFMT_S16_LE /* CS4235 */
+	AFMT_U8 | AFMT_S16_LE /* CS4235 */,
+	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW	/* Ensoniq Soundscape*/
 };
 
 static ad1848_info adev_info[MAX_AUDIO_DEV];
@@ -140,7 +143,7 @@
 static struct {
      unsigned char flags;
 #define CAP_F_TIMER 0x01     
-} capabilities [9 /*devc->model */ ] = {
+} capabilities [10 /*devc->model */ ] = {
      {0}
     ,{0}           /* MD_1848  */
     ,{CAP_F_TIMER} /* MD_4231  */
@@ -149,7 +152,8 @@
     ,{CAP_F_TIMER} /* MD_4232  */
     ,{0}           /* MD_C930  */
     ,{CAP_F_TIMER} /* MD_IWAVE */
-    ,{0}           /* MD_4235 */
+    ,{0}           /* MD_4235  */
+    ,{CAP_F_TIMER} /* MD_1845_SSCAPE */
 };
 
 static int      ad1848_open(int dev, int mode);
@@ -231,7 +235,7 @@
 	while (timeout > 0 && (ad_read(devc, 11) & 0x20))
 		timeout--;
 	if (ad_read(devc, 11) & 0x20)
-		if (devc->model != MD_1845)
+		if ( (devc->model != MD_1845) || (devc->model != MD_1845_SSCAPE))
 			printk(KERN_WARNING "ad1848: Auto calibration timed out(3).\n");
 }
 
@@ -555,6 +559,7 @@
 		case MD_4231:
 		case MD_4231A:
 		case MD_1845:
+		case MD_1845_SSCAPE:
 			devc->supported_devices = MODE2_MIXER_DEVICES;
 			break;
 
@@ -751,7 +756,7 @@
 	if (arg <= 0)
 		return portc->speed;
 
-	if (devc->model == MD_1845)	/* AD1845 has different timer than others */
+	if (devc->model == MD_1845 || devc->model == MD_1845_SSCAPE)	/* AD1845 has different timer than others */
 	{
 		if (arg < 4000)
 			arg = 4000;
@@ -1087,7 +1092,7 @@
 
 	ad_enter_MCE(devc);	/* Enables changes to the format select reg */
 
-	if (devc->model == MD_1845)	/* Use alternate speed select registers */
+	if (devc->model == MD_1845 || devc->model == MD_1845_SSCAPE) /* Use alternate speed select registers */
 	{
 		fs &= 0xf0;	/* Mask off the rate select bits */
 
@@ -1157,7 +1162,7 @@
 
 	ad_enter_MCE(devc);	/* Enables changes to the format select reg */
 
-	if (devc->model == MD_1845)	/* Use alternate speed select registers */
+	if ((devc->model == MD_1845) || (devc->model == MD_1845_SSCAPE))	/* Use alternate speed select registers */
 	{
 		fs &= 0xf0;	/* Mask off the rate select bits */
 
@@ -1193,7 +1198,7 @@
 		while (timeout < 10000 && inb(devc->base) == 0x80)
 			timeout++;
 
-		if (devc->model != MD_1848 && devc->model != MD_1845)
+		if (devc->model != MD_1848 && devc->model != MD_1845 && devc->model != MD_1845_SSCAPE)
 		{
 			/*
 			 * CS4231 compatible devices don't have separate sampling rate selection
@@ -1405,13 +1410,17 @@
 
 	if (devc->model > MD_1848)
 	{
-		ad_write(devc, 12, ad_read(devc, 12) | 0x40);		/* Mode2 = enabled */
+		if (devc->model == MD_1845_SSCAPE)
+			ad_write(devc, 12, ad_read(devc, 12) | 0x50);
+		else 
+			ad_write(devc, 12, ad_read(devc, 12) | 0x40);		/* Mode2 = enabled */
 
 		if (devc->model == MD_IWAVE)
 			ad_write(devc, 12, 0x6c);	/* Select codec mode 3 */
 
-		for (i = 16; i < 32; i++)
-			ad_write(devc, i, init_values[i]);
+		if (devc-> model != MD_1845_SSCAPE)
+			for (i = 16; i < 32; i++)
+				ad_write(devc, i, init_values[i]);
 
 		if (devc->model == MD_IWAVE)
 			ad_write(devc, 16, 0x30);	/* Playback and capture counters enabled */
@@ -1423,7 +1432,7 @@
 		else
 			ad_write(devc, 9, ad_read(devc, 9) | 0x04);	/* Single DMA mode */
 
-		if (devc->model == MD_1845)
+		if (devc->model == MD_1845 || devc->model == MD_1845_SSCAPE)
 			ad_write(devc, 27, ad_read(devc, 27) | 0x08);		/* Alternate freq select enabled */
 
 		if (devc->model == MD_IWAVE)
@@ -1462,6 +1471,7 @@
 	int interwave = 0;
 	int ad1847_flag = 0;
 	int cs4248_flag = 0;
+	int sscape_flag = 0;
 
 	int i;
 
@@ -1474,6 +1484,13 @@
 			interwave = 1;
 			*ad_flags = 0;
 		}
+		
+		if (*ad_flags == 0x87654321)
+		{
+			sscape_flag = 1;
+			*ad_flags = 0;
+		}
+		
 		if (*ad_flags == 0x12345677)
 		{
 		    cs4248_flag = 1;
@@ -1821,6 +1838,9 @@
 		devc->chip_name = "AD1847";
 
 
+	if (sscape_flag == 1)
+		devc->model = MD_1845_SSCAPE;
+
 	return 1;
 }
 
@@ -1979,7 +1999,7 @@
 	switch (cmd)
 	{
 		case AD1848_SET_XTAL:	/* Change clock frequency of AD1845 (only ) */
-			if (devc->model != MD_1845)
+			if (devc->model != MD_1845 || devc->model != MD_1845_SSCAPE)
 				return -EINVAL;
 			ad_enter_MCE(devc);
 			ad_write(devc, 29, (ad_read(devc, 29) & 0x1f) | (arg << 5));
@@ -2146,6 +2166,34 @@
 
 /*
  *	Experimental initialization sequence for the integrated sound system
+ *	of the Compaq Deskpro M.
+ */
+
+static int init_deskpro_m(struct address_info *hw_config)
+{
+	unsigned char   tmp;
+
+	if ((tmp = inb(0xc44)) == 0xff)
+	{
+		DDB(printk("init_deskpro_m: Dead port 0xc44\n"));
+		return 0;
+	}
+
+	outb(0x10, 0xc44);
+	outb(0x40, 0xc45);
+	outb(0x00, 0xc46);
+	outb(0xe8, 0xc47);
+	outb(0x14, 0xc44);
+	outb(0x40, 0xc45);
+	outb(0x00, 0xc46);
+	outb(0xe8, 0xc47);
+	outb(0x10, 0xc44);
+
+	return 1;
+}
+
+/*
+ *	Experimental initialization sequence for the integrated sound system
  *	of Compaq Deskpro XL.
  */
 
@@ -2370,6 +2418,12 @@
 			return 0;
 	}
 
+	if (deskpro_m)	/* Compaq Deskpro M */
+	{
+		if (!init_deskpro_m(hw_config))
+			return 0;
+	}
+
 	/*
 	   * Check if the IO port returns valid signature. The original MS Sound
 	   * system returns 0x04 while some cards (AudioTrix Pro for example)
@@ -2558,7 +2612,7 @@
 	 * the timer divider.
 	 */
 
-	if (devc->model == MD_1845)
+	if (devc->model == MD_1845 || devc->model == MD_1845_SSCAPE)
 		xtal_nsecs = 10050;
 	else if (ad_read(devc, 8) & 0x01)
 		xtal_nsecs = 9920;
@@ -2659,6 +2713,7 @@
 MODULE_PARM(dma2, "i");			/* Second DMA channel */
 MODULE_PARM(type, "i");			/* Card type */
 MODULE_PARM(deskpro_xl, "i");		/* Special magic for Deskpro XL boxen */
+MODULE_PARM(deskpro_m, "i");		/* Special magic for Deskpro M box */
 MODULE_PARM(soundpro, "i");		/* More special magic for SoundPro chips */
 
 int io = -1;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/adlib_card.c linux.14p16/drivers/sound/adlib_card.c
--- linux.vanilla/drivers/sound/adlib_card.c	Thu May 14 18:33:17 1998
+++ linux.14p16/drivers/sound/adlib_card.c	Thu Dec  9 15:34:01 1999
@@ -16,8 +16,6 @@
 #include "sound_config.h"
 #include "soundmodule.h"
 
-#ifdef CONFIG_YM3812
-
 void attach_adlib_card(struct address_info *hw_config)
 {
 	hw_config->slots[0] = opl3_init(hw_config->io_base, hw_config->osp);
@@ -69,5 +67,4 @@
 	SOUND_LOCK_END;
 }
 
-#endif
 #endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/dmasound.c linux.14p16/drivers/sound/dmasound.c
--- linux.vanilla/drivers/sound/dmasound.c	Sat Aug 28 20:00:58 1999
+++ linux.14p16/drivers/sound/dmasound.c	Tue Dec 14 16:15:21 1999
@@ -89,6 +89,7 @@
 #include <linux/malloc.h>
 #include <linux/sound.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 
 #if defined(__mc68000__) || defined(CONFIG_APUS)
 #include <asm/setup.h>
@@ -233,7 +234,7 @@
 	-269,	-245,	-218,	-187,	-153,	-117,	-79,	-40,
 };
 
-#define BEEP_SPEED	2	/* 22050 Hz sample rate */
+#define BEEP_SRATE	22050	/* 22050 Hz sample rate */
 #define BEEP_BUFLEN	512
 #define BEEP_VOLUME	15	/* 0 - 100 */
 
@@ -3003,8 +3004,9 @@
 
 static int __init PMacIrqInit(void)
 {
-	if (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", 0)
-	    || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0))
+	if (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", (void *) awacs)
+	    || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0,
+			   "AWACS out", (void *) awacs))
 		return 0;
 	return 1;
 }
@@ -3016,8 +3018,8 @@
 	out_le32(&awacs_txdma->control, RUN<<16);
 	/* disable interrupts from awacs interface */
 	out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
-	free_irq(awacs_irq, pmac_awacs_intr);
-	free_irq(awacs_tx_irq, pmac_awacs_tx_intr);
+	free_irq(awacs_irq, (void *) awacs);
+	free_irq(awacs_tx_irq, (void *) awacs);
 	kfree(awacs_tx_cmd_space);
 	if (beep_buf)
 		kfree(beep_buf);
@@ -3037,6 +3039,7 @@
 static int awacs_freqs[8] = {
 	44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
 };
+static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
 
 static void PMacInit(void)
 {
@@ -3060,10 +3063,13 @@
 	 * Otherwise choose the next higher rate.
 	 * N.B.: burgundy awacs (iMac and later) only works at 44100 Hz.
 	 */
-	i = (awacs_revision >= AWACS_BURGUNDY)? 1: 8;
+	i = 8;
 	do {
 		tolerance = catchRadius * awacs_freqs[--i] / 100;
-	} while (sound.soft.speed > awacs_freqs[i] + tolerance && i > 0);
+		if (awacs_freqs_ok[i]
+		    && sound.soft.speed <= awacs_freqs[i] + tolerance)
+			break;
+	} while (i > 0);
 	if (sound.soft.speed >= awacs_freqs[i] - tolerance)
 		sound.trans = &transAwacsNormal;
 	else
@@ -3171,7 +3177,7 @@
 		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
 		out_le32(&awacs->control,
 			 (in_le32(&awacs->control) & ~0x1f00)
-			 || (awacs_rate_index << 8));
+			 | (awacs_rate_index << 8));
 		out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
 		beep_playing = 0;
 	}
@@ -3259,6 +3265,11 @@
 	save_flags(flags); cli();
 	if (beep_playing) {
 		st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
+		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+		out_le32(&awacs->control,
+			 (in_le32(&awacs->control) & ~0x1f00)
+			 | (awacs_rate_index << 8));
+		out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
 		beep_playing = 0;
 	}
 	restore_flags(flags);
@@ -3271,8 +3282,8 @@
 static void awacs_mksound(unsigned int hz, unsigned int ticks)
 {
 	unsigned long flags;
-	int beep_speed = (awacs_revision < AWACS_BURGUNDY)? BEEP_SPEED: 0;
-	int srate = awacs_freqs[beep_speed];
+	int beep_speed = 0;
+	int srate;
 	int period, ncycles, nsamples;
 	int i, j, f;
 	short *p;
@@ -3280,6 +3291,11 @@
 	static int beep_nsamples_cache;
 	static int beep_volume_cache;
 
+	for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i)
+		if (awacs_freqs_ok[i])
+			beep_speed = i;
+	srate = awacs_freqs[beep_speed];
+
 	if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
 #if 1
 		/* this is a hack for broken X server code */
@@ -3366,6 +3382,12 @@
 		out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
 		enable_irq(awacs_irq);
 		enable_irq(awacs_tx_irq);
+		if (awacs_revision == 3) {
+			mdelay(100);
+			awacs_write(0x6000);
+			mdelay(2);
+			awacs_write(awacs_reg[1] | MASK_ADDR1);
+		}
 	}
 	return PBOOK_SLEEP_OK;
 }
@@ -4944,12 +4966,41 @@
 		np = find_devices("davbus");
 		sound = find_devices("sound");
 		if (sound != 0 && sound->parent == np) {
-			int *sfprop;
-			sfprop = (int *) get_property(sound, "sub-frame", 0);
-			if (sfprop != 0 && *sfprop >= 0 && *sfprop < 16)
-				awacs_subframe = *sfprop;
+			unsigned int *prop, l, i;
+			prop = (unsigned int *)
+				get_property(sound, "sub-frame", 0);
+			if (prop != 0 && *prop >= 0 && *prop < 16)
+				awacs_subframe = *prop;
 			if (device_is_compatible(sound, "burgundy"))
 				awacs_revision = AWACS_BURGUNDY;
+
+			/* look for a property saying what sample rates
+			   are available */
+			for (i = 0; i < 8; ++i)
+				awacs_freqs_ok[i] = 0;
+			prop = (unsigned int *) get_property
+				(sound, "sample-rates", &l);
+			if (prop == 0)
+				prop = (unsigned int *) get_property
+					(sound, "output-frame-rates", &l);
+			if (prop != 0) {
+				for (l /= sizeof(int); l > 0; --l) {
+					/* sometimes the rate is in the
+					   high-order 16 bits (?) */
+					unsigned int r = *prop++;
+					if (r >= 0x10000)
+						r >>= 16;
+					for (i = 0; i < 8; ++i) {
+						if (r == awacs_freqs[i]) {
+							awacs_freqs_ok[i] = 1;
+							break;
+						}
+					}
+				}
+			} else {
+				/* assume just 44.1k is OK */
+				awacs_freqs_ok[0] = 1;
+			}
 		}
 	}
 	if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/es1370.c linux.14p16/drivers/sound/es1370.c
--- linux.vanilla/drivers/sound/es1370.c	Sat Aug 14 02:27:34 1999
+++ linux.14p16/drivers/sound/es1370.c	Thu Dec  9 15:34:01 1999
@@ -101,6 +101,17 @@
  *    15.06.99   0.23  Fix bad allocation bug.
  *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
  *    28.06.99   0.24  Add pci_set_master
+ *    02.08.99   0.25  Added workaround for the "phantom write" bug first
+ *                     documented by Dave Sharpless from Anchor Games
+ *    03.08.99   0.26  adapt to Linus' new __setup/__initcall
+ *                     added kernel command line option "es1370=joystick[,lineout[,micbias]]"
+ *                     removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge
+ *    12.08.99   0.27  module_init/__setup fixes
+ *    19.08.99   0.28  SOUND_MIXER_IMIX fixes, reported by Gianluca <gialluca@mail.tiscalinet.it>
+ *    31.08.99   0.29  add spin_lock_init
+ *                     __initlocaldata to fix gcc 2.7.x problems
+ *    03.09.99   0.30  change read semantics for MIDI to match
+ *                     OSS more closely; remove possible wakeup race
  *
  * some important things missing in Ensoniq documentation:
  *
@@ -123,7 +134,6 @@
 
 /*****************************************************************************/
       
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/string.h>
@@ -175,12 +185,14 @@
 #define ES1370_REG_DAC2_SCOUNT    0x28
 #define ES1370_REG_ADC_SCOUNT     0x2c
 
-#define ES1370_REG_DAC1_FRAMEADR  0xc30
-#define ES1370_REG_DAC1_FRAMECNT  0xc34
-#define ES1370_REG_DAC2_FRAMEADR  0xc38
-#define ES1370_REG_DAC2_FRAMECNT  0xc3c
-#define ES1370_REG_ADC_FRAMEADR   0xd30
-#define ES1370_REG_ADC_FRAMECNT   0xd34
+#define ES1370_REG_DAC1_FRAMEADR    0xc30
+#define ES1370_REG_DAC1_FRAMECNT    0xc34
+#define ES1370_REG_DAC2_FRAMEADR    0xc38
+#define ES1370_REG_DAC2_FRAMECNT    0xc3c
+#define ES1370_REG_ADC_FRAMEADR     0xd30
+#define ES1370_REG_ADC_FRAMECNT     0xd34
+#define ES1370_REG_PHANTOM_FRAMEADR 0xd38
+#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c
 
 #define ES1370_FMT_U8_MONO     0
 #define ES1370_FMT_U8_STEREO   1
@@ -360,6 +372,13 @@
 
 static struct es1370_state *devs = NULL;
 
+/*
+ * The following buffer is used to point the phantom write channel to,
+ * so that it cannot wreak havoc. The attribute makes sure it doesn't
+ * cross a page boundary and ensures dword alignment for the DMA engine
+ */
+static unsigned char bugbuf[16] __attribute__ ((aligned (16)));
+
 /* --------------------------------------------------------------------- */
 
 extern inline unsigned ld2(unsigned int x)
@@ -779,10 +798,36 @@
 	[SOUND_MIXER_OGAIN]  = { 9, 0xf, 0x0, 0, 0x0000, 1 }    /* mono out */
 };
 
+static void set_recsrc(struct es1370_state *s, unsigned int val)
+{
+	unsigned int i, j;
+
+	for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+		if (!(val & (1 << i)))
+			continue;
+		if (!mixtable[i].recmask) {
+			val &= ~(1 << i);
+			continue;
+		}
+		j |= mixtable[i].recmask;
+	}
+	s->mix.recsrc = val;
+	wrcodec(s, 0x12, j & 0xd5);
+	wrcodec(s, 0x13, j & 0xaa);
+	wrcodec(s, 0x14, (j >> 8) & 0x17);
+	wrcodec(s, 0x15, (j >> 8) & 0x0f);
+	i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc60;
+	if (!s->mix.imix) {
+		i &= 0xff60;  /* mute record and line monitor */
+	}
+	wrcodec(s, 0x10, i);
+	wrcodec(s, 0x11, i >> 8);
+}
+
 static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long arg)
 {
 	unsigned long flags;
-	int i, val, j;
+	int i, val;
 	unsigned char l, r, rl, rr;
 
 	VALIDATE_STATE(s);
@@ -887,34 +932,13 @@
 	switch (_IOC_NR(cmd)) {
 
 	case SOUND_MIXER_IMIX:
-		if (arg == 0) 
-			return -EFAULT;
-		get_user_ret(s->mix.imix,(int *)arg, -EFAULT);
-		val = s->mix.recsrc;
-		/* fall through */
+		get_user_ret(s->mix.imix, (int *)arg, -EFAULT);
+		set_recsrc(s, s->mix.recsrc);
+		return 0;
 
 	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
 		get_user_ret(val, (int *)arg, -EFAULT);
-		for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
-			if (!(val & (1 << i)))
-				continue;
-			if (!mixtable[i].recmask) {
-				val &= ~(1 << i);
-				continue;
-			}
-			j |= mixtable[i].recmask;
-		}
-		s->mix.recsrc = val;
-		wrcodec(s, 0x12, j & 0xd5);
-		wrcodec(s, 0x13, j & 0xaa);
-		wrcodec(s, 0x14, (j >> 8) & 0x17);
-		wrcodec(s, 0x15, (j >> 8) & 0x0f);
-		i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc60;
-		if (!s->mix.imix) {
-		     i &= 0xff60;  /* mute record and line monitor */
-		}
-		wrcodec(s, 0x10, i);
-		wrcodec(s, 0x11, i >> 8);
+		set_recsrc(s, val);
 		return 0;
 
 	default:
@@ -1033,7 +1057,7 @@
 
 static int drain_dac1(struct es1370_state *s, int nonblock)
 {
-        struct wait_queue wait = { current, NULL };
+	struct wait_queue wait = { current, NULL };
 	unsigned long flags;
 	int count, tmo;
 	
@@ -1054,9 +1078,10 @@
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-		tmo = (count * HZ) / dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
+		tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2
+			/ dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
 		tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
-		if (!schedule_timeout(tmo ? : 1) && tmo)
+		if (!schedule_timeout(tmo + 1))
 			DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
         }
         remove_wait_queue(&s->dma_dac1.wait, &wait);
@@ -1089,9 +1114,10 @@
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-		tmo = (count * HZ) / DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV);
+		tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2
+			/ DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV);
 		tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
-		if (!schedule_timeout(tmo ? : 1) && tmo)
+		if (!schedule_timeout(tmo + 1))
 			DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
         }
         remove_wait_queue(&s->dma_dac2.wait, &wait);
@@ -2049,6 +2075,7 @@
 static ssize_t es1370_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct es1370_state *s = (struct es1370_state *)file->private_data;
+	struct wait_queue wait = { current, NULL };
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -2059,7 +2086,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.iwait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.ird;
@@ -2070,15 +2100,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.iwait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIINBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.ird = ptr;
@@ -2087,13 +2127,17 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
+		break;
 	}
+	current->state = TASK_RUNNING;
+        remove_wait_queue(&s->midi.iwait, &wait);
 	return ret;
 }
 
 static ssize_t es1370_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct es1370_state *s = (struct es1370_state *)file->private_data;
+	struct wait_queue wait = { current, NULL };
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -2104,7 +2148,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.owait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.owr;
@@ -2117,15 +2164,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.owait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIOUTBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.owr = ptr;
@@ -2138,6 +2195,8 @@
 		es1370_handle_midi(s);
 		spin_unlock_irqrestore(&s->lock, flags);
 	}
+	current->state = TASK_RUNNING;
+        remove_wait_queue(&s->midi.owait, &wait);
 	return ret;
 }
 
@@ -2217,7 +2276,7 @@
 static int es1370_midi_release(struct inode *inode, struct file *file)
 {
 	struct es1370_state *s = (struct es1370_state *)file->private_data;
-        struct wait_queue wait = { current, NULL };
+	struct wait_queue wait = { current, NULL };
 	unsigned long flags;
 	unsigned count, tmo;
 
@@ -2321,7 +2380,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1370: version v0.24 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1370: version v0.30 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) {
 		if (pcidev->base_address[0] == 0 || 
@@ -2341,6 +2400,7 @@
 		init_waitqueue(&s->midi.iwait);
 		init_waitqueue(&s->midi.owait);
 		s->open_sem = MUTEX;
+		spin_lock_init(&s->lock);
 		s->magic = ES1370_MAGIC;
 		s->io = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
 		s->irq = pcidev->irq;
@@ -2385,6 +2445,10 @@
 		/* initialize the chips */
 		outl(s->ctrl, s->io+ES1370_REG_CONTROL);
 		outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+		/* point phantom write channel to "bugbuf" */
+		outl((ES1370_REG_PHANTOM_FRAMEADR >> 8) & 15, s->io+ES1370_REG_MEMPAGE);
+		outl(virt_to_bus(bugbuf), s->io+(ES1370_REG_PHANTOM_FRAMEADR & 0xff));
+		outl(0, s->io+(ES1370_REG_PHANTOM_FRAMECNT & 0xff));
 		pci_set_master(pcidev);  /* enable bus mastering */
 		wrcodec(s, 0x16, 3); /* no RST, PD */
 		wrcodec(s, 0x17, 0); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off the LRCLK2 PLL; program DAC_SYNC=0!!  */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/es1371.c linux.14p16/drivers/sound/es1371.c
--- linux.vanilla/drivers/sound/es1371.c	Sat Aug 14 02:27:34 1999
+++ linux.14p16/drivers/sound/es1371.c	Thu Dec  9 15:34:02 1999
@@ -3,7 +3,7 @@
 /*
  *      es1371.c  --  Creative Ensoniq ES1371.
  *
- *      Copyright (C) 1998  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *      Copyright (C) 1998-1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
  *      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
@@ -68,14 +68,31 @@
  *    15.06.99   0.12  Fix bad allocation bug.
  *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
  *    28.06.99   0.13  Add pci_set_master
- *    21.07.99   0.14  S/PDIF module option for cards revision >= 4. Initial version
- *                     by Dave Platt <dplatt@snulbug.mtview.ca.us>.
+ *    03.08.99   0.14  adapt to Linus' new __setup/__initcall
+ *                     added kernel command line option "es1371=joystickaddr"
+ *                     removed CONFIG_SOUND_ES1371_JOYPORT_BOOT kludge
+ *    10.08.99   0.15  (Re)added S/PDIF module option for cards revision >= 4.
+ *                     Initial version by Dave Platt <dplatt@snulbug.mtview.ca.us>.
+ *                     module_init/__setup fixes
+ *    08.16.99   0.16  Joe Cotellese <joec@ensoniq.com>
+ *                     Added detection for ES1371 revision ID so that we can
+ *                     detect the ES1373 and later parts.
+ *                     added AC97 #defines for readability
+ *                     added a /proc file system for dumping hardware state
+ *                     updated SRC and CODEC w/r functions to accomodate bugs
+ *                     in some versions of the ES137x chips.
+ *    31.08.99   0.17  add spin_lock_init
+ *                     __initlocaldata to fix gcc 2.7.x problems
+ *                     replaced current->state = x with set_current_state(x)
+ *    03.09.99   0.18  change read semantics for MIDI to match
+ *                     OSS more closely; remove possible wakeup race
+ *    21.10.99   0.19  Round sampling rates, requested by
+ *                     Kasamatsu Kenichi <t29w0267@ip.media.kyoto-u.ac.jp>
  *
  */
 
 /*****************************************************************************/
       
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/string.h>
@@ -86,17 +103,21 @@
 #include <linux/malloc.h>
 #include <linux/soundcard.h>
 #include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/poll.h>
+#include <linux/bitops.h>
+#include <linux/proc_fs.h>
 #include <asm/spinlock.h>
+#include <asm/io.h>
+#include <asm/dma.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
+#include "ac97.h"
 
 /* --------------------------------------------------------------------- */
 
 #undef OSS_DOCUMENTED_MIXER_SEMANTICS
+#undef ES1371_DEBUG
 
 /* --------------------------------------------------------------------- */
 
@@ -107,6 +128,18 @@
 #define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371
 #endif
 
+/* ES1371 chip ID */
+/* This is a little confusing because all ES1371 compatible chips have the
+   same DEVICE_ID, the only thing differentiating them is the REV_ID field.
+   This is only significant if you want to enable features on the later parts.
+   Yes, I know it's stupid and why didn't we use the sub IDs?
+*/
+#define ES1371REV_ES1373_A  0x04
+#define ES1371REV_ES1373_B  0x06
+#define ES1371REV_CT5880_A  0x07
+#define ES1371REV_ES1371_B  0x09
+
+
 #define ES1371_MAGIC  ((PCI_VENDOR_ID_ENSONIQ<<16)|PCI_DEVICE_ID_ENSONIQ_ES1371)
 
 #define ES1371_EXTENT             0x40
@@ -206,14 +239,22 @@
 #define UCTRL_CNTRL_SWR 0x03        /* software reset command */
 
 /* sample rate converter */
+#define SRC_OKSTATE        1
+
 #define SRC_RAMADDR_MASK   0xfe000000
 #define SRC_RAMADDR_SHIFT  25
+#define SRC_DAC1FREEZE     (1UL << 21)
+#define SRC_DAC2FREEZE      (1UL << 20)
+#define SRC_ADCFREEZE      (1UL << 19)
+
+
 #define SRC_WE             0x01000000  /* read/write control for SRC RAM */
 #define SRC_BUSY           0x00800000  /* SRC busy */
 #define SRC_DIS            0x00400000  /* 1 = disable SRC */
 #define SRC_DDAC1          0x00200000  /* 1 = disable accum update for DAC1 */
 #define SRC_DDAC2          0x00100000  /* 1 = disable accum update for DAC2 */
 #define SRC_DADC           0x00080000  /* 1 = disable accum update for ADC2 */
+#define SRC_CTLMASK        0x00780000
 #define SRC_RAMDATA_MASK   0x0000ffff
 #define SRC_RAMDATA_SHIFT  0
 
@@ -293,7 +334,7 @@
 
 
 /* misc stuff */
-
+#define POLL_COUNT   0x1000
 #define FMODE_DAC         4           /* slight misuse of mode_t */
 
 /* MIDI buffer sizes */
@@ -352,8 +393,13 @@
 	/* hardware resources */
 	unsigned long io; /* long for SPARC */
 	unsigned int irq;
-
-	/* mixer registers; there is no HW readback */
+        u8 rev; /* the chip revision */
+        
+#ifdef ES1371_DEBUG
+        /* debug /proc entry */
+	struct proc_dir_entry *ps;
+#endif /* ES1371_DEBUG */
+        /* mixer registers; there is no HW readback */
 	struct {
 		unsigned short codec_id;
 		unsigned int modcnt;
@@ -438,31 +484,12 @@
 }
 
 /* --------------------------------------------------------------------- */
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#ifdef hweight32
-#undef hweight32
-#endif
-
-extern __inline__ unsigned int hweight32(unsigned int w)
-{
-        unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
-        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
-        res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
-        res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
-        return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
-}
-
-/* --------------------------------------------------------------------- */
 
 static unsigned wait_src_ready(struct es1371_state *s)
 {
 	unsigned int t, r;
 
-	for (t = 0; t < 1000; t++) {
+	for (t = 0; t < POLL_COUNT; t++) {
 		if (!((r = inl(s->io + ES1371_REG_SRCONV)) & SRC_BUSY))
 			return r;
 		udelay(1);
@@ -473,29 +500,53 @@
 
 static unsigned src_read(struct es1371_state *s, unsigned reg)
 {
-	unsigned int r;
+        unsigned int temp,i,orig;
 
-	r = wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC);
-	r |= (reg << SRC_RAMADDR_SHIFT) & SRC_RAMADDR_MASK;
-	outl(r, s->io + ES1371_REG_SRCONV);
-	return (wait_src_ready(s) & SRC_RAMDATA_MASK) >> SRC_RAMDATA_SHIFT;
-}
+        /* wait for ready */
+        temp = wait_src_ready (s);
+
+        /* we can only access the SRC at certain times, make sure
+           we're allowed to before we read */
+           
+        orig = temp;
+        /* expose the SRC state bits */
+        outl ( (temp & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT) | 0x10000UL,
+               s->io + ES1371_REG_SRCONV);
+
+        /* now, wait for busy and the correct time to read */
+        temp = wait_src_ready (s);
+
+        if ( (temp & 0x00870000UL ) != ( SRC_OKSTATE << 16 )){
+                /* wait for the right state */
+                for (i=0; i<POLL_COUNT; i++){
+                        temp = inl (s->io + ES1371_REG_SRCONV);
+                        if ( (temp & 0x00870000UL ) == ( SRC_OKSTATE << 16 ))
+                                break;
+                }
+        }
 
+        /* hide the state bits */
+        outl ((orig & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT), s->io + ES1371_REG_SRCONV);
+        return temp;
+                        
+                
+}
 
 static void src_write(struct es1371_state *s, unsigned reg, unsigned data)
 {
+      
 	unsigned int r;
 
 	r = wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC);
 	r |= (reg << SRC_RAMADDR_SHIFT) & SRC_RAMADDR_MASK;
 	r |= (data << SRC_RAMDATA_SHIFT) & SRC_RAMDATA_MASK;
 	outl(r | SRC_WE, s->io + ES1371_REG_SRCONV);
+
 }
 
 /* --------------------------------------------------------------------- */
 
 /* most of the following here is black magic */
-
 static void set_adc_rate(struct es1371_state *s, unsigned rate)
 {
 	unsigned long flags;
@@ -532,6 +583,7 @@
 	spin_unlock_irqrestore(&s->lock, flags);
 }
 
+
 static void set_dac1_rate(struct es1371_state *s, unsigned rate)
 {
 	unsigned long flags;
@@ -541,8 +593,8 @@
 		rate = 48000;
 	if (rate < 4000)
 		rate = 4000;
-        freq = (rate << 15) / 3000;
-	s->dac1rate = (freq * 3000) >> 15;
+        freq = ((rate << 15) + 1500) / 3000;
+	s->dac1rate = (freq * 3000 + 16384) >> 15;
 	spin_lock_irqsave(&s->lock, flags);
 	r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC2 | SRC_DADC)) | SRC_DDAC1;
 	outl(r, s->io + ES1371_REG_SRCONV);
@@ -564,8 +616,8 @@
 		rate = 48000;
 	if (rate < 4000)
 		rate = 4000;
-        freq = (rate << 15) / 3000;
-	s->dac2rate = (freq * 3000) >> 15;
+        freq = ((rate << 15) + 1500) / 3000;
+	s->dac2rate = (freq * 3000 + 16384) >> 15;
 	spin_lock_irqsave(&s->lock, flags);
 	r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DADC)) | SRC_DDAC2;
 	outl(r, s->io + ES1371_REG_SRCONV);
@@ -580,26 +632,80 @@
 
 /* --------------------------------------------------------------------- */
 
+static void __init src_init(struct es1371_state *s)
+{
+        unsigned int i;
+
+        /* before we enable or disable the SRC we need
+           to wait for it to become ready */
+        wait_src_ready(s);
+
+        outl(SRC_DIS, s->io + ES1371_REG_SRCONV);
+
+        for (i = 0; i < 0x80; i++)
+                src_write(s, i, 0);
+
+        src_write(s, SRCREG_DAC1+SRCREG_TRUNC_N, 16 << 4);
+        src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, 16 << 10);
+        src_write(s, SRCREG_DAC2+SRCREG_TRUNC_N, 16 << 4);
+        src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, 16 << 10);
+        src_write(s, SRCREG_VOL_ADC, 1 << 12);
+        src_write(s, SRCREG_VOL_ADC+1, 1 << 12);
+        src_write(s, SRCREG_VOL_DAC1, 1 << 12);
+        src_write(s, SRCREG_VOL_DAC1+1, 1 << 12);
+        src_write(s, SRCREG_VOL_DAC2, 1 << 12);
+        src_write(s, SRCREG_VOL_DAC2+1, 1 << 12);
+        set_adc_rate(s, 22050);
+        set_dac1_rate(s, 22050);
+        set_dac2_rate(s, 22050);
+
+        /* WARNING:
+         * enabling the sample rate converter without properly programming
+         * its parameters causes the chip to lock up (the SRC busy bit will
+         * be stuck high, and I've found no way to rectify this other than
+         * power cycle)
+         */
+        wait_src_ready(s);
+        outl(0, s->io+ES1371_REG_SRCONV);
+}
+
+/* --------------------------------------------------------------------- */
+
 static void wrcodec(struct es1371_state *s, unsigned addr, unsigned data)
 {
 	unsigned long flags;
 	unsigned t, x;
-
-	for (t = 0; t < 0x1000; t++)
+        
+	for (t = 0; t < POLL_COUNT; t++)
 		if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP))
 			break;
 	spin_lock_irqsave(&s->lock, flags);
-	/* save the current state for later */
-	x = inl(s->io+ES1371_REG_SRCONV);
-	/* enable SRC state data in SRC mux */
-	outl((wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000,
+
+        /* save the current state for later */
+        x = wait_src_ready(s);
+
+        /* enable SRC state data in SRC mux */
+	outl(( x & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000,
 	     s->io+ES1371_REG_SRCONV);
-	/* wait for a SAFE time to write addr/data and then do it, dammit */
-	for (t = 0; t < 0x1000; t++)
-		if ((inl(s->io+ES1371_REG_SRCONV) & 0x00070000) == 0x00010000)
-			break;
+
+        /* wait for not busy (state 0) first to avoid
+           transition states */
+        for (t=0; t<POLL_COUNT; t++){
+                if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0 )
+                    break;
+                udelay(1);
+        }
+        
+        /* wait for a SAFE time to write addr/data and then do it, dammit */
+        for (t=0; t<POLL_COUNT; t++){
+                if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000)
+                    break;
+                udelay(1);
+        }
+
 	outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) |
 	     ((data << CODEC_PODAT_SHIFT) & CODEC_PODAT_MASK), s->io+ES1371_REG_CODEC);
+
 	/* restore SRC reg */
 	wait_src_ready(s);
 	outl(x, s->io+ES1371_REG_SRCONV);
@@ -611,28 +717,50 @@
 	unsigned long flags;
 	unsigned t, x;
 
+        /* wait for WIP to go away */
 	for (t = 0; t < 0x1000; t++)
 		if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP))
 			break;
 	spin_lock_irqsave(&s->lock, flags);
+
 	/* save the current state for later */
-	x = inl(s->io+ES1371_REG_SRCONV);
+	x = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC));
+
 	/* enable SRC state data in SRC mux */
-	outl((wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000,
-	     s->io+ES1371_REG_SRCONV);
-	/* wait for a SAFE time to write addr/data and then do it, dammit */
-	for (t = 0; t < 0x1000; t++)
-		if ((inl(s->io+ES1371_REG_SRCONV) & 0x00070000) == 0x00010000)
-			break;
+	outl( x | 0x00010000,
+              s->io+ES1371_REG_SRCONV);
+
+        /* wait for not busy (state 0) first to avoid
+           transition states */
+        for (t=0; t<POLL_COUNT; t++){
+                if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0 )
+                    break;
+                udelay(1);
+        }
+        
+        /* wait for a SAFE time to write addr/data and then do it, dammit */
+        for (t=0; t<POLL_COUNT; t++){
+                if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000)
+                    break;
+                udelay(1);
+        }
+
 	outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) | CODEC_PORD, s->io+ES1371_REG_CODEC);
 	/* restore SRC reg */
 	wait_src_ready(s);
 	outl(x, s->io+ES1371_REG_SRCONV);
 	spin_unlock_irqrestore(&s->lock, flags);
-	/* now wait for the stinkin' data (RDY) */
+
+        /* wait for WIP again */
 	for (t = 0; t < 0x1000; t++)
+		if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP))
+			break;
+        
+	/* now wait for the stinkin' data (RDY) */
+	for (t = 0; t < POLL_COUNT; t++)
 		if ((x = inl(s->io+ES1371_REG_CODEC)) & CODEC_RDY)
 			break;
+        
 	return ((x & CODEC_PIDAT_MASK) >> CODEC_PIDAT_SHIFT);
 }
 
@@ -993,6 +1121,21 @@
 
 /* --------------------------------------------------------------------- */
 
+/*
+ * AC97 Mixer Register to Connections mapping of the Concert 97 board
+ *
+ * AC97_MASTER_VOL_STEREO   Line Out
+ * AC97_MASTER_VOL_MONO     TAD Output
+ * AC97_PCBEEP_VOL          none
+ * AC97_PHONE_VOL           TAD Input (mono)
+ * AC97_MIC_VOL             MIC Input (mono)
+ * AC97_LINEIN_VOL          Line Input (stereo)
+ * AC97_CD_VOL              CD Input (stereo)
+ * AC97_VIDEO_VOL           none
+ * AC97_AUX_VOL             Aux Input (stereo)
+ * AC97_PCMOUT_VOL          Wave Output (stereo)
+ */
+
 #define AC97_PESSIMISTIC
 
 /*
@@ -1018,25 +1161,25 @@
 static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = 
 {
 	/* 5 bit stereo */
-	[SOUND_MIXER_LINE] = 0x10,
-	[SOUND_MIXER_CD] = 0x12,
-	[SOUND_MIXER_VIDEO] = 0x14,
-	[SOUND_MIXER_LINE1] = 0x16,
-	[SOUND_MIXER_PCM] = 0x18,
+	[SOUND_MIXER_LINE] = AC97_LINEIN_VOL,
+	[SOUND_MIXER_CD] = AC97_CD_VOL,
+	[SOUND_MIXER_VIDEO] = AC97_VIDEO_VOL,
+	[SOUND_MIXER_LINE1] = AC97_AUX_VOL,
+	[SOUND_MIXER_PCM] = AC97_PCMOUT_VOL,
 	/* 6 bit stereo */
-	[SOUND_MIXER_VOLUME] = 0x02,
-	[SOUND_MIXER_PHONEOUT] = 0x04,
+	[SOUND_MIXER_VOLUME] = AC97_MASTER_VOL_STEREO,
+	[SOUND_MIXER_PHONEOUT] = AC97_HEADPHONE_VOL,
 	/* 6 bit mono */
-	[SOUND_MIXER_OGAIN] = 0x06,
-	[SOUND_MIXER_PHONEIN] = 0x0c,
+	[SOUND_MIXER_OGAIN] = AC97_MASTER_VOL_MONO,
+	[SOUND_MIXER_PHONEIN] = AC97_PHONE_VOL,
 	/* 4 bit mono but shifted by 1 */
-	[SOUND_MIXER_SPEAKER] = 0x08,
+	[SOUND_MIXER_SPEAKER] = AC97_MASTER_TONE,
 	/* 6 bit mono + preamp */
-	[SOUND_MIXER_MIC] = 0x0e,
+	[SOUND_MIXER_MIC] = AC97_MIC_VOL,
 	/* 4 bit stereo */
-	[SOUND_MIXER_RECLEV] = 0x1c,
+	[SOUND_MIXER_RECLEV] = AC97_RECORD_GAIN,
 	/* 4 bit mono */
-	[SOUND_MIXER_IGAIN] = 0x1e
+	[SOUND_MIXER_IGAIN] = AC97_RECORD_GAIN_MIC
 };
 
 #ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -1049,8 +1192,8 @@
 
 	switch (ch) {
 	case SOUND_MIXER_MIC:
-		j = rdcodec(s, 0x0e);
-		if (j & 0x8000)
+		j = rdcodec(s, AC97_MIC_VOL);
+		if (j & AC97_MUTE)
 			return put_user(0, (int *)arg);
 #ifdef AC97_PESSIMISTIC
 		return put_user(0x4949 - 0x202 * (j & 0x1f) + ((j & 0x40) ? 0x1b1b : 0), (int *)arg);
@@ -1061,7 +1204,7 @@
 	case SOUND_MIXER_OGAIN:
 	case SOUND_MIXER_PHONEIN:
 		j = rdcodec(s, volreg[ch]);
-		if (j & 0x8000)
+		if (j & AC97_MUTE)
 			return put_user(0, (int *)arg);
 #ifdef AC97_PESSIMISTIC
 		return put_user(0x6464 - 0x303 * (j & 0x1f), (int *)arg);
@@ -1075,7 +1218,7 @@
 		/* fall through */
 	case SOUND_MIXER_VOLUME:
 		j = rdcodec(s, volreg[ch]);
-		if (j & 0x8000)
+		if (j & AC97_MUTE)
 			return put_user(0, (int *)arg);
 #ifdef AC97_PESSIMISTIC
 		return put_user(0x6464 - (swab(j) & 0x1f1f) * 3, (int *)arg);
@@ -1084,8 +1227,8 @@
 #endif /* AC97_PESSIMISTIC */
 		
 	case SOUND_MIXER_SPEAKER:
-		j = rdcodec(s, 0x0a);
-		if (j & 0x8000)
+		j = rdcodec(s, AC97_PCBEEP_VOL);
+		if (j & AC97_MUTE
 			return put_user(0, (int *)arg);
 		return put_user(0x6464 - ((j >> 1) & 0xf) * 0x606, (int *)arg);
 		
@@ -1095,7 +1238,7 @@
 	case SOUND_MIXER_LINE1:
 	case SOUND_MIXER_PCM:
 		j = rdcodec(s, volreg[ch]);
-		if (j & 0x8000)
+		if (j & AC97_MUTE)
 			return put_user(0, (int *)arg);
 		return put_user(0x6464 - (swab(j) & 0x1f1f) * 3, (int *)arg);
 
@@ -1103,23 +1246,23 @@
 	case SOUND_MIXER_TREBLE:
 		if (!(s->mix.codec_id & CODEC_ID_BASSTREBLE))
 			return -EINVAL;
-		j = rdcodec(s, 0x08);
+		j = rdcodec(s, AC97_MASTER_TONE);
 		if (ch == SOUND_MIXER_BASS)
 			j >>= 8;
 		return put_user((((j & 15) * 100) / 15) * 0x101, (int *)arg);
 	
 		/* SOUND_MIXER_RECLEV and SOUND_MIXER_IGAIN specify gain */
 	case SOUND_MIXER_RECLEV:
-		j = rdcodec(s, 0x1c);
-		if (j & 0x8000)
+		j = rdcodec(s, AC97_RECORD_GAIN);
+		if (j & AC97_MUTE)
 			return put_user(0, (int *)arg);
 		return put_user((swab(j)  & 0xf0f) * 6 + 0xa0a, (int *)arg);
 		
 	case SOUND_MIXER_IGAIN:
 		if (!(s->mix.codec_id & CODEC_ID_DEDICATEDMIC))
 			return -EINVAL;
-		j = rdcodec(s, 0x1e);
-		if (j & 0x8000)
+		j = rdcodec(s, AC97_RECORD_GAIN_MIC);
+		if (j & AC97_MUTE)
 			return put_user(0, (int *)arg);
 		return put_user((j & 0xf) * 0x606 + 0xa0a, (int *)arg);
 	
@@ -1174,7 +1317,7 @@
 	case SOUND_MIXER_LINE1:
 	case SOUND_MIXER_PCM:
 		if (l1 < 7 && r1 < 7) {
-			wrcodec(s, volreg[ch], 0x8000);
+			wrcodec(s, volreg[ch], AC97_MUTE);
 			return 0;
 		}
 		if (l1 < 7)
@@ -1191,7 +1334,7 @@
 	case SOUND_MIXER_VOLUME:
 #ifdef AC97_PESSIMISTIC
 		if (l1 < 7 && r1 < 7) {
-			wrcodec(s, volreg[ch], 0x8000);
+			wrcodec(s, volreg[ch], AC97_MUTE);
 			return 0;
 		}
 		if (l1 < 7)
@@ -1202,7 +1345,7 @@
 		return 0;
 #else /* AC97_PESSIMISTIC */
 		if (l1 < 4 && r1 < 4) {
-			wrcodec(s, volreg[ch], 0x8000);
+			wrcodec(s, volreg[ch], AC97_MUTE);
 			return 0;
 		}
 		if (l1 < 4)
@@ -1216,21 +1359,21 @@
 	case SOUND_MIXER_OGAIN:
 	case SOUND_MIXER_PHONEIN:
 #ifdef AC97_PESSIMISTIC
-		wrcodec(s, volreg[ch], (l1 < 7) ? 0x8000 : (100 - l1) / 3);
+		wrcodec(s, volreg[ch], (l1 < 7) ? AC97_MUTE : (100 - l1) / 3);
 		return 0;
 #else /* AC97_PESSIMISTIC */
-		wrcodec(s, volreg[ch], (l1 < 4) ? 0x8000 : (2 * (100 - l1) / 3));
+		wrcodec(s, volreg[ch], (l1 < 4) ? AC97_MUTE : (2 * (100 - l1) / 3));
 		return 0;
 #endif /* AC97_PESSIMISTIC */
 			
 	case SOUND_MIXER_SPEAKER:
-		wrcodec(s, 0x0a, (l1 < 10) ? 0x8000 : ((100 - l1) / 6) << 1);
+		wrcodec(s, AC97_PCBEEP_VOL, (l1 < 10) ? AC97_MUTE : ((100 - l1) / 6) << 1);
 		return 0;
 
 	case SOUND_MIXER_MIC:
 #ifdef AC97_PESSIMISTIC
 		if (l1 < 11) {
-			wrcodec(s, 0x0e, 0x8000);
+			wrcodec(s, AC97_MIC_VOL, AC97_MUTE);
 			return 0;
 		}
 		i = 0;
@@ -1240,11 +1383,11 @@
 		}
 		if (l1 < 11) 
 			l1 = 11;
-		wrcodec(s, 0x0e, ((73 - l1) / 2) | i);
+		wrcodec(s, AC97_MIC_VOL, ((73 - l1) / 2) | i);
 		return 0;
 #else /* AC97_PESSIMISTIC */
 		if (l1 < 9) {
-			wrcodec(s, 0x0e, 0x8000);
+			wrcodec(s, AC97_MIC_VOL, AC97_MUTE);
 			return 0;
 		}
 		i = 0;
@@ -1254,37 +1397,37 @@
 		}
 		if (l1 < 9) 
 			l1 = 9;
-		wrcodec(s, 0x0e, (((87 - l1) * 4) / 5) | i);
+		wrcodec(s, AC97_MIC_VOL, (((87 - l1) * 4) / 5) | i);
 		return 0;
 #endif /* AC97_PESSIMISTIC */
 		
 	case SOUND_MIXER_BASS:
 		val = ((l1 * 15) / 100) & 0xf;
-		wrcodec(s, 0x08, (rdcodec(s, 0x08) & 0x00ff) | (val << 8));
+		wrcodec(s, AC97_MASTER_TONE, (rdcodec(s, AC97_MASTER_TONE) & 0x00ff) | (val << 8));
 		return 0;
 
 	case SOUND_MIXER_TREBLE:
 		val = ((l1 * 15) / 100) & 0xf;
-		wrcodec(s, 0x08, (rdcodec(s, 0x08) & 0xff00) | val);
+		wrcodec(s, AC97_MASTER_TONE, (rdcodec(s, AC97_MASTER_TONE) & 0xff00) | val);
 		return 0;
 		
 		/* SOUND_MIXER_RECLEV and SOUND_MIXER_IGAIN specify gain */
 	case SOUND_MIXER_RECLEV:
 		if (l1 < 10 || r1 < 10) {
-			wrcodec(s, 0x1c, 0x8000);
+			wrcodec(s, AC97_RECORD_GAIN, AC97_MUTE);
 			return 0;
 		}
 		if (l1 < 10)
 			l1 = 10;
 		if (r1 < 10)
 			r1 = 10;
-		wrcodec(s, 0x1c, (((l1 - 10) / 6) << 8) | ((r1 - 10) / 6));
+		wrcodec(s, AC97_RECORD_GAIN, (((l1 - 10) / 6) << 8) | ((r1 - 10) / 6));
 		return 0;
 
 	case SOUND_MIXER_IGAIN:
 		if (!(s->mix.codec_id & CODEC_ID_DEDICATEDMIC))
 			return -EINVAL;
-		wrcodec(s, 0x1e, (l1 < 10) ? 0x8000 : ((l1 - 10) / 6) & 0xf);
+		wrcodec(s, AC97_RECORD_GAIN_MIC, (l1 < 10) ? AC97_MUTE : ((l1 - 10) / 6) & 0xf);
 		return 0;
 		
 	default:
@@ -1302,8 +1445,8 @@
 			return -EINVAL;
 		get_user_ret(val, (int *)arg, -EFAULT);
 		if (val & 1)
-			wrcodec(s, 0x22, ((val << 3) & 0xf00) | ((val >> 1) & 0xf));
-		val = rdcodec(s, 0x22);
+			wrcodec(s, AC97_3D_CONTROL, ((val << 3) & 0xf00) | ((val >> 1) & 0xf));
+		val = rdcodec(s, AC97_3D_CONTROL);
 		return put_user(((val & 0xf) << 1) | ((val & 0xf00) >> 3), (int *)arg);
 	}
         if (cmd == SOUND_MIXER_INFO) {
@@ -1330,7 +1473,7 @@
         if (_IOC_DIR(cmd) == _IOC_READ) {
                 switch (_IOC_NR(cmd)) {
                 case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-			return put_user(recsrc[rdcodec(s, 0x1a) & 7], (int *)arg);
+			return put_user(recsrc[rdcodec(s, AC97_RECORD_SELECT) & 7], (int *)arg);
 			
                 case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
 			return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_VIDEO |
@@ -1377,10 +1520,10 @@
                 if (i == 0)
                         return 0; /*val = mixer_recmask(s);*/
                 else if (i > 1) 
-                        val &= ~recsrc[rdcodec(s, 0x1a) & 7];
+                        val &= ~recsrc[rdcodec(s, AC97_RECORD_SELECT) & 7];
                 for (i = 0; i < 8; i++) {
 			if (val & recsrc[i]) {
-				wrcodec(s, 0x1a, 0x101 * i);
+				wrcodec(s, AC97_RECORD_SELECT, 0x101 * i);
 				return 0;
 			}
 		}
@@ -1485,10 +1628,10 @@
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-		tmo = (count * HZ) / s->dac1rate;
+		tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate;
 		tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
-		if (!schedule_timeout(tmo ? : 1) && tmo)
-			printk(KERN_DEBUG "es1371: dma timed out??\n");
+		if (!schedule_timeout(tmo + 1))
+			printk(KERN_DEBUG "es1371: dac1 dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac1.wait, &wait);
         current->state = TASK_RUNNING;
@@ -1520,10 +1663,10 @@
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-		tmo = (count * HZ) / s->dac2rate;
+		tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate;
 		tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
-		if (!schedule_timeout(tmo ? : 1) && tmo)
-			printk(KERN_DEBUG "es1371: dma timed out??\n");
+		if (!schedule_timeout(tmo + 1))
+			printk(KERN_DEBUG "es1371: dac2 dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac2.wait, &wait);
         current->state = TASK_RUNNING;
@@ -2467,6 +2610,7 @@
 static ssize_t es1371_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct es1371_state *s = (struct es1371_state *)file->private_data;
+	struct wait_queue wait = { current, NULL };
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -2477,7 +2621,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.iwait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.ird;
@@ -2488,15 +2635,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.iwait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIINBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.ird = ptr;
@@ -2505,13 +2662,17 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
+		break;
 	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&s->midi.iwait, &wait);
 	return ret;
 }
 
 static ssize_t es1371_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct es1371_state *s = (struct es1371_state *)file->private_data;
+	struct wait_queue wait = { current, NULL };
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -2522,7 +2683,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.owait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.owr;
@@ -2535,15 +2699,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.owait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIOUTBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.owr = ptr;
@@ -2556,6 +2730,8 @@
 		es1371_handle_midi(s);
 		spin_unlock_irqrestore(&s->lock, flags);
 	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&s->midi.owait, &wait);
 	return ret;
 }
 
@@ -2697,6 +2873,44 @@
 
 /* --------------------------------------------------------------------- */
 
+/*
+ * for debugging purposes, we'll create a proc device that dumps the
+ *  CODEC chipstate
+ */
+
+#ifdef ES1371_DEBUG
+static int proc_es1371_dump (char *buf, char **start, off_t fpos, int length, int *eof, void *data)
+{
+        int len = 0;
+
+        struct es1371_state *s = devs;
+        int cnt;
+
+        /* print out header */
+        len += sprintf(buf + len, "\t\tCreative ES137x Debug Dump-o-matic\n");
+
+        /* print out CODEC state */
+        len += sprintf (buf + len, "AC97 CODEC state\n");
+        
+        for (cnt=0; cnt <= 0x7e; cnt = cnt +2)
+                len+= sprintf (buf + len, "reg:0x%02x  val:0x%04x\n", cnt, rdcodec(s , cnt));
+                
+        if (fpos >=len){
+                *start = buf;
+                *eof =1;
+                return 0;
+        }
+        *start = buf + fpos;
+        if ((len -= fpos) > length)
+                return length;
+        *eof =1;
+        return len;
+
+}
+#endif /* ES1371_DEBUG */
+
+/* --------------------------------------------------------------------- */
+
 /* maximum number of devices */
 #define NR_DEVICE 5
 
@@ -2740,12 +2954,11 @@
 	struct pci_dev *pcidev = NULL;
 	mm_segment_t fs;
 	int i, val, val2, index = 0;
-	u8 revision;
 	unsigned cssr;
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1371: version v0.13 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1371: version v0.19 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) {
 		if (pcidev->base_address[0] == 0 || 
@@ -2765,9 +2978,11 @@
 		init_waitqueue(&s->midi.iwait);
 		init_waitqueue(&s->midi.owait);
 		s->open_sem = MUTEX;
+		spin_lock_init(&s->lock);
 		s->magic = ES1371_MAGIC;
 		s->io = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
 		s->irq = pcidev->irq;
+		pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev);
 		if (check_region(s->io, ES1371_EXTENT)) {
 			printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1);
 			goto err_region;
@@ -2788,6 +3003,13 @@
 			goto err_dev3;
 		if ((s->dev_midi = register_sound_midi(&es1371_midi_fops, -1)) < 0)
 			goto err_dev4;
+#ifdef ES1371_DEBUG
+                /* intialize the debug proc device */
+                s->ps = create_proc_entry("es1371", S_IFREG | S_IRUGO, NULL);
+                if (s->ps)
+                        s->ps->read_proc = proc_es1371_dump;
+#endif /* ES1371_DEBUG */
+
 		/* initialize codec registers */
 		s->ctrl = 0;
 		if ((joystick[index] & ~0x18) == 0x200) {
@@ -2800,14 +3022,13 @@
 		s->sctrl = 0;
 		cssr = 0;
 		/* check to see if s/pdif mode is being requested */
-		pci_read_config_byte(pcidev, PCI_REVISION_ID, &revision);
 		if (spdif[index]) {
-			if (revision >= 4) {
+			if (s->rev >= 4) {
 				printk(KERN_INFO "es1371: enabling S/PDIF output\n");
 				cssr |= STAT_EN_SPDIF;
 				s->ctrl |= CTRL_SPDIFEN_B;
 			} else {
-				printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", revision);
+				printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", s->rev);
 			}
 		}
 		/* initialize the chips */
@@ -2820,35 +3041,12 @@
 		udelay(2);
 		outl(s->ctrl, s->io+ES1371_REG_CONTROL);
 		/* init the sample rate converter */
-		outl(SRC_DIS, s->io + ES1371_REG_SRCONV);
-		for (val = 0; val < 0x80; val++)
-			src_write(s, val, 0);
-		src_write(s, SRCREG_DAC1+SRCREG_TRUNC_N, 16 << 4);
-		src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, 16 << 10);
-		src_write(s, SRCREG_DAC2+SRCREG_TRUNC_N, 16 << 4);
-		src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, 16 << 10);
-		src_write(s, SRCREG_VOL_ADC, 1 << 12);
-		src_write(s, SRCREG_VOL_ADC+1, 1 << 12);
-		src_write(s, SRCREG_VOL_DAC1, 1 << 12);
-		src_write(s, SRCREG_VOL_DAC1+1, 1 << 12);
-		src_write(s, SRCREG_VOL_DAC2, 1 << 12);
-		src_write(s, SRCREG_VOL_DAC2+1, 1 << 12);
-		set_adc_rate(s, 22050);
-		set_dac1_rate(s, 22050);
-		set_dac2_rate(s, 22050);
-		/* WARNING:
-		 * enabling the sample rate converter without properly programming
-		 * its parameters causes the chip to lock up (the SRC busy bit will
-		 * be stuck high, and I've found no way to rectify this other than
-		 * power cycle)
-		 */
-		wait_src_ready(s);
-		outl(0, s->io+ES1371_REG_SRCONV);
+                src_init(s);
 		/* codec init */
-		wrcodec(s, 0x00, 0); /* reset codec */
-		s->mix.codec_id = rdcodec(s, 0x00);  /* get codec ID */
-		val = rdcodec(s, 0x7c);
-		val2 = rdcodec(s, 0x7e);
+		wrcodec(s, AC97_RESET, 0); /* reset codec */
+		s->mix.codec_id = rdcodec(s, AC97_RESET);  /* get codec ID */
+		val = rdcodec(s, AC97_VENDOR_ID1);
+		val2 = rdcodec(s, AC97_VENDOR_ID2);
 		printk(KERN_INFO "es1371: codec vendor %c%c%c revision %d\n", 
 		       (val >> 8) & 0xff, val & 0xff, (val2 >> 8) & 0xff, val2 & 0xff);
 		printk(KERN_INFO "es1371: codec features");
@@ -2875,6 +3073,7 @@
 		printk("%s\n", (s->mix.codec_id & 0x3ff) ? "" : " none");
 		val = (s->mix.codec_id >> CODEC_ID_SESHIFT) & CODEC_ID_SEMASK;
 		printk(KERN_INFO "es1371: stereo enhancement: %s\n", (val <= 20) ? stereo_enhancement[val] : "unknown");
+
 		fs = get_fs();
 		set_fs(KERNEL_DS);
 		val = SOUND_MASK_LINE;
@@ -2929,6 +3128,10 @@
 
 	while ((s = devs)) {
 		devs = devs->next;
+#ifdef ES1371_DEBUG
+		if (s->ps)
+			remove_proc_entry("es1371", NULL);
+#endif /* ES1371_DEBUG */
 		outl(0, s->io+ES1371_REG_CONTROL); /* switch everything off */
 		outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */
 		synchronize_irq();
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/esssolo1.c linux.14p16/drivers/sound/esssolo1.c
--- linux.vanilla/drivers/sound/esssolo1.c	Wed Oct 20 01:12:48 1999
+++ linux.14p16/drivers/sound/esssolo1.c	Thu Dec  9 15:34:02 1999
@@ -54,12 +54,17 @@
  *                     The fun part is that the Windows Solo1 driver doesn't
  *                     seem to do these tricks.
  *                     Bugs remaining: plops and clicks when starting/stopping playback
+ *    31.08.99   0.7   add spin_lock_init
+ *                     replaced current->state = x with set_current_state(x)
+ *    03.09.99   0.8   change read semantics for MIDI to match
+ *                     OSS more closely; remove possible wakeup race
+ *    07.10.99   0.9   Fix initialization; complain if sequencer writes time out
+ *                     Revised resource grabbing for the FM synthesizer
  *
  */
 
 /*****************************************************************************/
       
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/string.h>
@@ -96,7 +101,7 @@
 
 #define SOLO1_MAGIC  ((PCI_VENDOR_ID_ESS<<16)|PCI_DEVICE_ID_ESS_SOLO1)
 
-#define DDMABASE_OFFSET           0x10    /* chip bug workaround kludge */
+#define DDMABASE_OFFSET           0    /* chip bug workaround kludge */
 #define DDMABASE_EXTENT           16
 
 #define IOBASE_EXTENT             16
@@ -105,6 +110,7 @@
 #define MPUBASE_EXTENT            4
 #define GPBASE_EXTENT             4
 
+#define FMSYNTH_EXTENT            4
 
 /* MIDI buffer sizes */
 
@@ -137,6 +143,8 @@
 #define wait_queue_head_t struct wait_queue *
 #define init_waitqueue_head(w) *(w) = 0
 #define init_MUTEX(m) *(m) = MUTEX
+#define __set_current_state(x) do { current->state = (x); } while (0)
+#define set_current_state(x) __set_current_state(x)
 #endif
 
 /* --------------------------------------------------------------------- */
@@ -226,7 +234,7 @@
 {
         int i;
 	unsigned long flags;
-        
+
 	/* the __cli stunt is to send the data within the command window */
         for (i = 0; i < 0xffff; i++) {
 		__save_flags(flags);
@@ -238,6 +246,8 @@
                 }
 		__restore_flags(flags);
 	}
+	printk(KERN_ERR "esssolo1: write_seq timeout\n");
+	outb(data, s->sbbase+0xc);
 }
 
 extern inline int read_seq(struct solo1_state *s, unsigned char *data)
@@ -251,6 +261,7 @@
                         *data = inb(s->sbbase+0xa);
                         return 1;
                 }
+	printk(KERN_ERR "esssolo1: read_seq timeout\n");
         return 0;
 }
 
@@ -952,7 +963,7 @@
 	
 	if (s->dma_dac.mapped)
 		return 0;
-        current->state = TASK_INTERRUPTIBLE;
+        __set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&s->dma_dac.wait, &wait);
         for (;;) {
                 spin_lock_irqsave(&s->lock, flags);
@@ -964,7 +975,7 @@
                         break;
                 if (nonblock) {
                         remove_wait_queue(&s->dma_dac.wait, &wait);
-                        current->state = TASK_RUNNING;
+                        set_current_state(TASK_RUNNING);
                         return -EBUSY;
                 }
 		tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate;
@@ -976,7 +987,7 @@
                         printk(KERN_DEBUG "solo1: dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac.wait, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         if (signal_pending(current))
                 return -ERESTARTSYS;
         return 0;
@@ -1622,6 +1633,7 @@
 static ssize_t solo1_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -1632,7 +1644,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+	add_wait_queue(&s->midi.iwait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.ird;
@@ -1643,15 +1658,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.iwait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			__set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIINBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.ird = ptr;
@@ -1660,13 +1685,17 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
+		break;
 	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&s->midi.iwait, &wait);
 	return ret;
 }
 
 static ssize_t solo1_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -1677,7 +1706,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.owait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.owr;
@@ -1690,15 +1722,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.owait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			__set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIOUTBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.owr = ptr;
@@ -1711,6 +1753,8 @@
 		solo1_handle_midi(s);
 		spin_unlock_irqrestore(&s->lock, flags);
 	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&s->midi.owait, &wait);
 	return ret;
 }
 
@@ -1979,6 +2023,12 @@
 			return -ERESTARTSYS;
 		down(&s->open_sem);
 	}
+	if (check_region(s->sbbase, FMSYNTH_EXTENT)) {
+		up(&s->open_sem);
+		printk(KERN_ERR "solo1: FM synth io ports in use, opl3 loaded?\n");
+		return -EBUSY;
+	}
+	request_region(s->sbbase, FMSYNTH_EXTENT, "ESS Solo1");
 	/* init the stuff */
 	outb(1, s->sbbase);
 	outb(0x20, s->sbbase+1); /* enable waveforms */
@@ -2006,6 +2056,7 @@
 		outb(regb, s->sbbase+2);
 		outb(0, s->sbbase+3);
 	}
+	release_region(s->sbbase, FMSYNTH_EXTENT);
 	up(&s->open_sem);
 	wake_up(&s->open_wait);
 	MOD_DEC_USE_COUNT;
@@ -2062,7 +2113,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "solo1: version v0.6 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "solo1: version v0.9 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) {
 		if (pcidev->base_address[0] == 0 ||
@@ -2087,6 +2138,7 @@
 		init_waitqueue_head(&s->midi.iwait);
 		init_waitqueue_head(&s->midi.owait);
 		init_MUTEX(&s->open_sem);
+		spin_lock_init(&s->lock);
 		s->magic = SOLO1_MAGIC;
 		s->pcidev = pcidev;
 		s->iobase = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
@@ -2097,14 +2149,14 @@
 		s->gpbase = pcidev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
 		s->irq = pcidev->irq;
 		if (check_region(s->iobase, IOBASE_EXTENT) ||
-		    check_region(s->sbbase+4, SBBASE_EXTENT-4) ||
+		    check_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT) ||
 		    check_region(s->ddmabase, DDMABASE_EXTENT) ||
 		    check_region(s->mpubase, MPUBASE_EXTENT)) {
 			printk(KERN_ERR "solo1: io ports in use\n");
 			goto err_region;
 		}
 		request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1");
-		request_region(s->sbbase+4, SBBASE_EXTENT-4, "ESS Solo1");  /* allow OPL3 synth module */
+		request_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT, "ESS Solo1");  /* allow OPL3 synth module */
 		request_region(s->ddmabase, DDMABASE_EXTENT, "ESS Solo1");
 		request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1");
 		if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) {
@@ -2131,6 +2183,10 @@
 		if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0)
 			goto err_dev4;
 		/* initialize the chips */
+		if (!reset_ctrl(s)) {
+			printk(KERN_ERR "esssolo1: cannot reset controller\n");
+			goto err;
+		}
 		outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */
 
 		/* initialize mixer regs */
@@ -2165,6 +2221,8 @@
 		index++;
 		continue;
 
+	err:
+		unregister_sound_dsp(s->dev_dmfm);
 	err_dev4:
 		unregister_sound_dsp(s->dev_midi);
 	err_dev3:
@@ -2176,7 +2234,7 @@
 		free_irq(s->irq, s);
 	err_irq:
 		release_region(s->iobase, IOBASE_EXTENT);
-		release_region(s->sbbase+4, SBBASE_EXTENT-4);
+		release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
 		release_region(s->ddmabase, DDMABASE_EXTENT);
 		release_region(s->mpubase, MPUBASE_EXTENT);
 	err_region:
@@ -2206,7 +2264,7 @@
 		pci_write_config_word(s->pcidev, 0x60, 0); /* turn off DDMA controller address space */
 		free_irq(s->irq, s);
 		release_region(s->iobase, IOBASE_EXTENT);
-		release_region(s->sbbase+4, SBBASE_EXTENT-4);
+		release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
 		release_region(s->ddmabase, DDMABASE_EXTENT);
 		release_region(s->mpubase, MPUBASE_EXTENT);
 		unregister_sound_dsp(s->dev_audio);
@@ -2222,5 +2280,4 @@
 
 module_init(init_solo1);
 module_exit(cleanup_solo1);
-
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/lowlevel/Config.in linux.14p16/drivers/sound/lowlevel/Config.in
--- linux.vanilla/drivers/sound/lowlevel/Config.in	Sun Dec 27 18:53:45 1998
+++ linux.14p16/drivers/sound/lowlevel/Config.in	Thu Dec  9 15:34:01 1999
@@ -1,4 +1,5 @@
 dep_tristate 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER $CONFIG_SOUND_OSS
+dep_tristate 'MSP3400 Audio for BT848' CONFIG_VIDEO_MSP3400 $CONFIG_VIDEO_BT848 $CONFIG_SOUND
 
 dep_tristate 'AWE32 synth' CONFIG_AWE32_SYNTH $CONFIG_SOUND_OSS
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/lowlevel/miroaci.h linux.14p16/drivers/sound/lowlevel/miroaci.h
--- linux.vanilla/drivers/sound/lowlevel/miroaci.h	Sun Aug 23 21:32:25 1998
+++ linux.14p16/drivers/sound/lowlevel/miroaci.h	Thu Dec  9 15:34:01 1999
@@ -1,6 +1,11 @@
+#if defined(CONFIG_ACI_MIXER) || (defined(CONFIG_ACI_MIXER_MODULE) && defined(MODULE))
 extern int aci_implied_cmd(unsigned char opcode);
 extern int aci_write_cmd(unsigned char opcode, unsigned char parameter);
 extern int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2);
 extern int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter);
 extern int aci_indexed_cmd(unsigned char opcode, unsigned char index, unsigned char *parameter);
+#else
 
+#error Compiling a driver that needs the ACI-mixer but without ACI-mixer support
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/maestro.c linux.14p16/drivers/sound/maestro.c
--- linux.vanilla/drivers/sound/maestro.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/sound/maestro.c	Thu Dec  9 15:34:05 1999
@@ -0,0 +1,3556 @@
+/*****************************************************************************
+ *
+ *      ESS Maestro/Maestro-2/Maestro-2E driver for Linux 2.[23].x
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is 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.
+ *
+ *	(c) Copyright 1999	 Alan Cox <alan.cox@linux.org>
+ *
+ *	Based heavily on SonicVibes.c:
+ *      Copyright (C) 1998-1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *	Heavily modified by Zach Brown <zab@redhat.com> based on lunch
+ *	with ESS engineers.  Many thanks to Howard Kim for providing 
+ *	contacts and hardware.  Honorable mention goes to Eric 
+ *	Brombaugh for all sorts of things.  Best regards to the 
+ *	proprietors of Hack Central for fine lodging.
+ *
+ *  Supported devices:
+ *  /dev/dsp0-3    standard /dev/dsp device, (mostly) OSS compatible
+ *  /dev/mixer  standard /dev/mixer device, (mostly) OSS compatible
+ *
+ *  Hardware Description
+ *
+ *	A working Maestro setup contains the Maestro chip wired to a 
+ *	codec or 2.  In the Maestro we have the APUs, the ASSP, and the
+ *	Wavecache.  The APUs can be though of as virtual audio routing
+ *	channels.  They can take data from a number of sources and perform
+ *	basic encodings of the data.  The wavecache is a storehouse for
+ *	PCM data.  Typically it deals with PCI and interracts with the
+ *	APUs.  The ASSP is a wacky DSP like device that ESS is loth
+ *	to release docs on.  Thankfully it isn't required on the Maestro
+ *	until you start doing insane things like FM emulation and surround
+ *	encoding.  The codecs are almost always AC-97 compliant codecs, 
+ *	but it appears that early Maestros may have had PT101 (an ESS
+ *	part?) wired to them.  The only real difference in the Maestro
+ *	families is external goop like docking capability, memory for
+ *	the ASSP, and initialization differences.
+ *
+ *  Driver Operation
+ *
+ *	We only drive the APU/Wavecache as typical DACs and drive the
+ *	mixers in the codecs.  There are 64 APUs.  We assign 6 to each
+ *	/dev/dsp? device.  2 channels for output, and 4 channels for
+ *	input.
+ *
+ *	Each APU can do a number of things, but we only really use
+ *	3 basic functions.  For playback we use them to convert PCM
+ *	data fetched over PCI by the wavecahche into analog data that
+ *	is handed to the codec.  One APU for mono, and a pair for stereo.
+ *	When in stereo, the combination of smarts in the APU and Wavecache
+ *	decide which wavecache gets the left or right channel.
+ *
+ *	For record we still use the old overly mono system.  For each in
+ *	coming channel the data comes in from the codec, through a 'input'
+ *	APU, through another rate converter APU, and then into memory via
+ *	the wavecache and PCI.  If its stereo, we mash it back into LRLR in
+ *	software.  The pass between the 2 APUs is supposedly what requires us
+ *	to have a 512 byte buffer sitting around in wavecache/memory.
+ *
+ *	The wavecache makes our life even more fun.  First off, it can
+ *	only address the first 28 bits of PCI address space, making it
+ *	useless on quite a few architectures.  Secondly, its insane.
+ *	It claims to fetch from 4 regions of PCI space, each 4 meg in length.
+ *	But that doesn't really work.  You can only use 1 region.  So all our
+ *	allocations have to be in 4meg of each other.  Booo.  Hiss.
+ *	So we have a module parameter, dsps_order, that is the order of
+ *	the number of dsps to provide.  All their buffer space is allocated
+ *	on open time.  The sonicvibes OSS routines we inherited really want
+ *	power of 2 buffers, so we have all those next to each other, then
+ *	512 byte regions for the recording wavecaches.  This ends up
+ *	wasting quite a bit of memory.  The only fixes I can see would be 
+ *	getting a kernel allocator that could work in zones, or figuring out
+ *	just how to coerce the WP into doing what we want.
+ *
+ *	The indirection of the various registers means we have to spinlock
+ *	nearly all register accesses.  We have the main register indirection
+ *	like the wave cache, maestro registers, etc.  Then we have beasts
+ *	like the APU interface that is indirect registers gotten at through
+ *	the main maestro indirection.  Ouch.  We spinlock around the actual
+ *	ports on a per card basis.  This means spinlock activity at each IO
+ *	operation, but the only IO operation clusters are in non critical 
+ *	paths and it makes the code far easier to follow.  Interrupts are
+ *	blocked while holding the locks because the int handler has to
+ *	get at some of them :(.  The mixer interface doesn't, however.
+ *	We also have an OSS state lock that is thrown around in a few
+ *	places.
+ *
+ *	This driver has brute force APM suspend support.  We catch suspend
+ *	notifications and stop all work being done on the chip.  Any people
+ *	that try between this shutdown and the real suspend operation will
+ *	be put to sleep.  When we resume we restore our software state on
+ *	the chip and wake up the people that were using it.  The code thats
+ *	being used now is quite dirty and assumes we're on a uni-processor
+ *	machine.  Much of it will need to be cleaned up for SMP ACPI or 
+ *	similar.
+ *	
+ * History
+ *  v0.13 - Nov 18 1999 - Zach Brown <zab@redhat.com>
+ *	fix nec Versas?  man would that be cool.
+ *  v0.12 - Nov 12 1999 - Zach Brown <zab@redhat.com>
+ *	brown bag volume max fix..
+ *  v0.11 - Nov 11 1999 - Zach Brown <zab@redhat.com>
+ *	use proper stereo apu decoding, mmap/write should work.
+ *	make volume sliders more useful, tweak rate calculation.
+ *	fix lame 8bit format reporting bug.  duh. apm apu saving buglet also
+ *	fix maestro 1 clock freq "bug", remove pt101 support
+ *  v0.10 - Oct 28 1999 - Zach Brown <zab@redhat.com>
+ *	aha, so, sometimes the WP writes a status word to offset 0
+ *	  from one of the PCMBARs.  rearrange allocation accordingly..
+ *	  cheers again to Eric for being a good hacker in investigating this.
+ *	Jeroen Hoogervorst submits 7500 fix out of nowhere.  yay.  :)
+ *  v0.09 - Oct 23 1999 - Zach Brown <zab@redhat.com>
+ *	added APM support.
+ *	re-order something such that some 2Es now work.  Magic!
+ *	new codec reset routine.  made some codecs come to life.
+ *	fix clear_advance, sync some control with ESS.
+ *	now write to all base regs to be paranoid.
+ *  v0.08 - Oct 20 1999 - Zach Brown <zab@redhat.com>
+ *	Fix initial buflen bug.  I am so smart.  also smp compiling..
+ *	I owe Eric yet another beer: fixed recmask, igain, 
+ *	  muting, and adc sync consistency.  Go Team.
+ *  v0.07 - Oct 4 1999 - Zach Brown <zab@redhat.com>
+ *	tweak adc/dac, formating, and stuff to allow full duplex
+ *	allocate dsps memory at open() so we can fit in the wavecache window
+ *	fix wavecache braindamage.  again.  no more scribbling?
+ *	fix ess 1921 codec bug on some laptops.
+ *	fix dumb pci scanning bug
+ *	started 2.3 cleanup, redid spinlocks, little cleanups
+ *  v0.06 - Sep 20 1999 - Zach Brown <zab@redhat.com>
+ *	fix wavecache thinkos.  limit to 1 /dev/dsp.
+ *	eric is wearing his thinking toque this week.
+ *		spotted apu mode bugs and gain ramping problem
+ *	don't touch weird mixer regs, make recmask optional
+ *	fixed igain inversion, defaults for mixers, clean up rec_start
+ *	make mono recording work.
+ *	report subsystem stuff, please send reports.
+ *	littles: parallel out, amp now
+ *  v0.05 - Sep 17 1999 - Zach Brown <zab@redhat.com>
+ *	merged and fixed up Eric's initial recording code
+ *	munged format handling to catch misuse, needs rewrite.
+ *	revert ring bus init, fixup shared int, add pci busmaster setting
+ *	fix mixer oss interface, fix mic mute and recmask
+ *	mask off unsupported mixers, reset with all 1s, modularize defaults
+ *	make sure bob is running while we need it
+ *	got rid of device limit, initial minimal apm hooks
+ *	pull out dead code/includes, only allow multimedia/audio maestros
+ *  v0.04 - Sep 01 1999 - Zach Brown <zab@redhat.com>
+ *	copied memory leak fix from sonicvibes driver
+ *	different ac97 reset, play with 2.0 ac97, simplify ring bus setup
+ *	bob freq code, region sanity, jitter sync fix; all from Eric 
+ *
+ * TODO
+ *	some people get indir reg timeouts?
+ *	fix bob frequency
+ *	endianness
+ *	do smart things with ac97 2.0 bits.
+ *	docking and dual codecs and 978?
+ *	leave 54->61 open
+ *
+ *	it also would be fun to have a mode that would not use pci dma at all
+ *	but would copy into the wavecache on board memory and use that 
+ *	on architectures that don't like the maestro's pci dma ickiness.
+ */
+
+/*****************************************************************************/
+
+#include <linux/version.h>
+#include <linux/module.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+
+ #ifdef MODULE
+  #ifdef MODVERSIONS
+   #include <linux/modversions.h>
+  #endif
+ #endif
+ #define DECLARE_WAITQUEUE(QUEUE,INIT) struct wait_queue QUEUE = {INIT, NULL}
+ #define wait_queue_head_t struct wait_queue *
+ #define SILLY_PCI_BASE_ADDRESS(PCIDEV) (PCIDEV->base_address[0] & PCI_BASE_ADDRESS_IO_MASK)
+ #define SILLY_INIT_SEM(SEM) SEM=MUTEX;
+ #define init_waitqueue_head init_waitqueue
+ #define SILLY_MAKE_INIT(FUNC) __initfunc(FUNC)
+
+#else
+
+ #define SILLY_PCI_BASE_ADDRESS(PCIDEV) (PCIDEV->resource[0].start)
+ #define SILLY_INIT_SEM(SEM) init_MUTEX(&SEM)
+ #define SILLY_MAKE_INIT(FUNC) __init FUNC
+
+#endif
+
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/sound.h>
+#include <linux/malloc.h>
+#include <linux/soundcard.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+#include <asm/spinlock.h>
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int maestro_apm_callback(apm_event_t ae);
+static int in_suspend=0;
+wait_queue_head_t suspend_queue;
+static void check_suspend(void);
+#define CHECK_SUSPEND check_suspend();
+#else
+#define CHECK_SUSPEND
+#endif
+
+#include "maestro.h"
+
+/* --------------------------------------------------------------------- */
+
+#define M_DEBUG 1
+
+#ifdef M_DEBUG
+static int debug=0;
+static int dsps_order=0;
+#define M_printk(args...) {if (debug) printk(args);}
+#else
+#define M_printk(x)
+#endif
+
+/* --------------------------------------------------------------------- */
+#define DRIVER_VERSION "0.13"
+
+#ifndef PCI_VENDOR_ESS
+#define PCI_VENDOR_ESS			0x125D
+#define PCI_DEVICE_ID_ESS_ESS1968	0x1968		/* Maestro 2	*/
+#define PCI_DEVICE_ID_ESS_ESS1978      	0x1978		/* Maestro 2E	*/
+
+#define PCI_VENDOR_ESS_OLD		0x1285		/* Platform Tech, 
+						the people the maestro 
+						was bought from */
+#define PCI_DEVICE_ID_ESS_ESS0100	0x0100		/* maestro 1 */
+#endif /* PCI_VENDOR_ESS */
+
+#define ESS_CHAN_HARD		0x100
+
+/* NEC Versas ? */
+#define NEC_VERSA_SUBID1	0x80581033
+#define NEC_VERSA_SUBID2	0x803c1033
+
+
+/* changed so that I could actually find all the
+	references and fix them up.  its a little more readable now. */
+#define ESS_FMT_STEREO	0x01
+#define ESS_FMT_16BIT	0x02
+#define ESS_FMT_MASK	0x03
+#define ESS_DAC_SHIFT	0   
+#define ESS_ADC_SHIFT	4
+
+#define ESS_STATE_MAGIC		0x125D1968
+#define ESS_CARD_MAGIC		0x19283746
+
+#define DAC_RUNNING		1
+#define ADC_RUNNING		2
+
+#define MAX_DSP_ORDER	2
+#define MAX_DSPS	(1<<MAX_DSP_ORDER)
+#define NR_DSPS		(1<<dsps_order)
+#define NR_IDRS		32
+
+#define SND_DEV_DSP16   5 
+
+#define NR_APUS		64
+#define NR_APU_REGS	16
+
+static const unsigned sample_size[] = { 1, 2, 2, 4 };
+static const unsigned sample_shift[] = { 0, 1, 1, 2 };
+
+enum card_types_t {
+	TYPE_MAESTRO,
+	TYPE_MAESTRO2,
+	TYPE_MAESTRO2E
+};
+
+static const char *card_names[]={
+	[TYPE_MAESTRO] = "ESS Maestro",
+	[TYPE_MAESTRO2] = "ESS Maestro 2",
+	[TYPE_MAESTRO2E] = "ESS Maestro 2E"
+};
+
+static int clock_freq[]={
+	[TYPE_MAESTRO] = (49152000L / 1024L),
+	[TYPE_MAESTRO2] = (50000000L / 1024L),
+	[TYPE_MAESTRO2E] = (50000000L / 1024L)
+};
+
+/* --------------------------------------------------------------------- */
+
+struct ess_state {
+	unsigned int magic;
+	/* FIXME: we probably want submixers in here, but only one record pair */
+	u8 apu[6];		/* l/r output, l/r intput converters, l/r input apus */
+	u8 apu_mode[6];		/* Running mode for this APU */
+	u8 apu_pan[6];		/* Panning setup for this APU */
+	u32 apu_base[6];	/* base address for this apu */
+	struct ess_card *card;	/* Card info */
+	/* wave stuff */
+	unsigned int rateadc, ratedac;
+	unsigned char fmt, enable;
+
+	int index;
+
+	/* this locks around the oss state in the driver */
+	spinlock_t lock;
+	/* only let 1 be opening at a time */
+	struct semaphore open_sem;
+	wait_queue_head_t open_wait;
+	mode_t open_mode;
+
+	/* soundcore stuff */
+	int dev_audio;
+
+	struct dmabuf {
+		void *rawbuf;
+		unsigned buforder;
+		unsigned numfrag;
+		unsigned fragshift;
+		/* XXX zab - swptr only in here so that it can be referenced by
+			clear_advance, as far as I can tell :( */
+		unsigned hwptr, swptr;
+		unsigned total_bytes;
+		int count;
+		unsigned error; /* over/underrun */
+		wait_queue_head_t wait;
+		/* redundant, but makes calculations easier */
+		unsigned fragsize;
+		unsigned dmasize;
+		unsigned fragsamples;
+		/* OSS stuff */
+		unsigned mapped:1;
+		unsigned ready:1;	/* our oss buffers are ready to go */
+		unsigned endcleared:1;
+		unsigned ossfragshift;
+		int ossmaxfrags;
+		unsigned subdivision;
+		u16 base;		/* Offset for ptr */
+	} dma_dac, dma_adc;
+
+	/* pointer to each dsp?s piece of the apu->src buffer page */
+	void *mixbuf;
+};
+	
+struct ess_card {
+	unsigned int magic;
+
+	/* We keep maestro cards in a linked list */
+	struct ess_card *next;
+
+	int dev_mixer;
+
+	int card_type;
+
+	/* as most of this is static,
+		perhaps it should be a pointer to a global struct */
+	struct mixer_goo {
+		int modcnt;
+		int supported_mixers;
+		int stereo_mixers;
+		int record_sources;
+		/* the caller must guarantee arg sanity before calling these */
+/*		int (*read_mixer)(struct ess_card *card, int index);*/
+		void (*write_mixer)(struct ess_card *card,int mixer, unsigned int left,unsigned int right);
+		int (*recmask_io)(struct ess_card *card,int rw,int mask);
+		unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
+	} mix;
+	
+	struct ess_state channels[MAX_DSPS];
+	u16 maestro_map[NR_IDRS];	/* Register map */
+#ifdef CONFIG_APM
+	/* we have to store this junk so that we can come back from a
+		suspend */
+	u16 apu_map[NR_APUS][NR_APU_REGS];	/* contents of apu regs */
+#endif
+
+	/* this locks around the physical registers on the card */
+	spinlock_t lock;
+
+	/* memory for this card.. wavecache limited :(*/
+	void *dmapages;
+	int dmaorder;
+
+	/* hardware resources */
+	struct pci_dev pcidev; /* uck.. */
+	u32 iobase;
+	u32 irq;
+
+	int bob_freq;
+	char dsps_open;
+};
+
+static unsigned 
+ld2(unsigned int x)
+{
+	unsigned r = 0;
+	
+	if (x >= 0x10000) {
+		x >>= 16;
+		r += 16;
+	}
+	if (x >= 0x100) {
+		x >>= 8;
+		r += 8;
+	}
+	if (x >= 0x10) {
+		x >>= 4;
+		r += 4;
+	}
+	if (x >= 4) {
+		x >>= 2;
+		r += 2;
+	}
+	if (x >= 2)
+		r++;
+	return r;
+}
+
+
+/* --------------------------------------------------------------------- */
+
+static struct ess_card *devs = NULL;
+
+/* --------------------------------------------------------------------- */
+
+
+/*
+ *	ESS Maestro AC97 codec programming interface.
+ */
+	 
+static void maestro_ac97_set(int io, u8 cmd, u16 val)
+{
+	int i;
+	/*
+	 *	Wait for the codec bus to be free 
+	 */
+
+	CHECK_SUSPEND;
+	 
+	for(i=0;i<10000;i++)
+	{
+		if(!(inb(io+ESS_AC97_INDEX)&1)) 
+			break;
+	}
+	/*
+	 *	Write the bus
+	 */ 
+	outw(val, io+ESS_AC97_DATA);
+	mdelay(1);
+	outb(cmd, io+ESS_AC97_INDEX);
+	mdelay(1);
+}
+
+static u16 maestro_ac97_get(int io, u8 cmd)
+{
+	int sanity=10000;
+	u16 data;
+	int i;
+	
+	CHECK_SUSPEND;
+	/*
+	 *	Wait for the codec bus to be free 
+	 */
+	 
+	for(i=0;i<10000;i++)
+	{
+		if(!(inb(io+ESS_AC97_INDEX)&1))
+			break;
+	}
+
+	outb(cmd|0x80, io+ESS_AC97_INDEX);
+	mdelay(1);
+	
+	while(inb(io+ESS_AC97_INDEX)&1)
+	{
+		sanity--;
+		if(!sanity)
+		{
+			printk(KERN_ERR "maestro: ac97 codec timeout reading 0x%x.\n",cmd);
+			return 0;
+		}
+	}
+	data=inw(io+ESS_AC97_DATA);
+	mdelay(1);
+	return data;
+}
+
+/* OSS interface to the ac97s.. */
+
+#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|\
+	SOUND_MASK_PCM|SOUND_MASK_LINE|SOUND_MASK_CD|\
+	SOUND_MASK_VIDEO|SOUND_MASK_LINE1|SOUND_MASK_IGAIN)
+
+#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \
+	SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_MIC|\
+	SOUND_MASK_SPEAKER)
+
+#define AC97_RECORD_MASK (SOUND_MASK_MIC|\
+	SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\
+	SOUND_MASK_PHONEIN)
+
+#define supported_mixer(CARD,FOO) ( CARD->mix.supported_mixers & (1<<FOO) )
+
+/* this table has default mixer values for all OSS mixers.
+	be sure to fill it in if you add oss mixers
+	to anyone's supported mixer defines */
+
+ unsigned int mixer_defaults[SOUND_MIXER_NRDEVICES] = {
+	[SOUND_MIXER_VOLUME] =          0x3232,
+	[SOUND_MIXER_BASS] =            0x3232,
+	[SOUND_MIXER_TREBLE] =          0x3232,
+	[SOUND_MIXER_SPEAKER] =         0x3232,
+	[SOUND_MIXER_MIC] =     0x8000, /* annoying */
+	[SOUND_MIXER_LINE] =    0x3232,
+	[SOUND_MIXER_CD] =      0x3232,
+	[SOUND_MIXER_VIDEO] =   0x3232,
+	[SOUND_MIXER_LINE1] =   0x3232,
+	[SOUND_MIXER_PCM] =             0x3232,
+	[SOUND_MIXER_IGAIN] =           0x3232
+};
+	
+static struct ac97_mixer_hw {
+	unsigned char offset;
+	int scale;
+} ac97_hw[SOUND_MIXER_NRDEVICES]= {
+	[SOUND_MIXER_VOLUME]	=	{0x02,63},
+	[SOUND_MIXER_BASS]	=	{0x08,15},
+	[SOUND_MIXER_TREBLE]	=	{0x08,15},
+	[SOUND_MIXER_SPEAKER]	=	{0x0a,15},
+	[SOUND_MIXER_MIC]	=	{0x0e,31},
+	[SOUND_MIXER_LINE]	=	{0x10,31},
+	[SOUND_MIXER_CD]	=	{0x12,31},
+	[SOUND_MIXER_VIDEO]	=	{0x14,31},
+	[SOUND_MIXER_LINE1]	=	{0x16,31},
+	[SOUND_MIXER_PCM]	=	{0x18,31},
+	[SOUND_MIXER_IGAIN]	=	{0x1c,15}
+};
+
+#if 0 /* *shrug* removed simply because we never used it.
+		feel free to implement again if needed */
+
+/* reads the given OSS mixer from the ac97
+	the caller must have insured that the ac97 knows
+	about that given mixer, and should be holding a
+	spinlock for the card */
+static int ac97_read_mixer(struct ess_card *card, int mixer) 
+{
+	u16 val;
+	int ret=0;
+	struct ac97_mixer_hw *mh = &ac97_hw[mixer];
+
+	val = maestro_ac97_get(card->iobase , mh->offset);
+
+	if(AC97_STEREO_MASK & (1<<mixer)) {
+		/* nice stereo mixers .. */
+		int left,right;
+
+		left = (val >> 8)  & 0x7f;
+		right = val  & 0x7f;
+
+		if (mixer == SOUND_MIXER_IGAIN) {
+			right = (right * 100) / mh->scale;
+			left = (left * 100) / mh->scale;
+		else {
+			right = 100 - ((right * 100) / mh->scale);
+			left = 100 - ((left * 100) / mh->scale);
+		}
+
+		ret = left | (right << 8);
+	} else if (mixer == SOUND_MIXER_SPEAKER) {
+		ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
+	} else if (mixer == SOUND_MIXER_MIC) {
+		ret = 100 - (((val & 0x1f) * 100) / mh->scale);
+	/*  the low bit is optional in the tone sliders and masking
+		it lets is avoid the 0xf 'bypass'.. */
+	} else if (mixer == SOUND_MIXER_BASS) {
+		ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
+	} else if (mixer == SOUND_MIXER_TREBLE) {
+		ret = 100 - (((val & 0xe) * 100) / mh->scale);
+	}
+
+	M_printk("read mixer %d (0x%x) %x -> %x\n",mixer,mh->offset,val,ret);
+
+	return ret;
+}
+#endif
+
+/* write the OSS encoded volume to the given OSS encoded mixer,
+	again caller's job to make sure all is well in arg land,
+	call with spinlock held */
+	
+/* linear scale -> log */
+unsigned char lin2log[101] = 
+{
+0, 0 , 15 , 23 , 30 , 34 , 38 , 42 , 45 , 47 ,
+50 , 52 , 53 , 55 , 57 , 58 , 60 , 61 , 62 ,
+63 , 65 , 66 , 67 , 68 , 69 , 69 , 70 , 71 ,
+72 , 73 , 73 , 74 , 75 , 75 , 76 , 77 , 77 ,
+78 , 78 , 79 , 80 , 80 , 81 , 81 , 82 , 82 ,
+83 , 83 , 84 , 84 , 84 , 85 , 85 , 86 , 86 ,
+87 , 87 , 87 , 88 , 88 , 88 , 89 , 89 , 89 ,
+90 , 90 , 90 , 91 , 91 , 91 , 92 , 92 , 92 ,
+93 , 93 , 93 , 94 , 94 , 94 , 94 , 95 , 95 ,
+95 , 95 , 96 , 96 , 96 , 96 , 97 , 97 , 97 ,
+97 , 98 , 98 , 98 , 98 , 99 , 99 , 99 , 99 , 99 
+};
+
+static void ac97_write_mixer(struct ess_card *card,int mixer, unsigned int left, unsigned int right)
+{
+	u16 val=0;
+	struct ac97_mixer_hw *mh = &ac97_hw[mixer];
+
+	M_printk("wrote mixer %d (0x%x) %d,%d",mixer,mh->offset,left,right);
+
+	if(AC97_STEREO_MASK & (1<<mixer)) {
+		/* stereo mixers, mute them if we can */
+
+		if (mixer == SOUND_MIXER_IGAIN) {
+			/* igain's slider is reversed.. */
+			right = (right * mh->scale) / 100;
+			left = (left * mh->scale) / 100;
+			if ((left == 0) && (right == 0))
+				val |= 0x8000;
+		} else {
+			/* log conversion for the stereo controls */
+			if((left == 0) && (right == 0))
+				val = 0x8000;
+			right = ((100 - lin2log[right]) * mh->scale) / 100;
+			left = ((100 - lin2log[left]) * mh->scale) / 100;
+		}
+
+		val |= (left << 8) | right;
+
+	} else if (mixer == SOUND_MIXER_SPEAKER) {
+		val = (((100 - left) * mh->scale) / 100) << 1;
+	} else if (mixer == SOUND_MIXER_MIC) {
+		val = maestro_ac97_get(card->iobase , mh->offset) & ~0x801f;
+		val |= (((100 - left) * mh->scale) / 100);
+	/*  the low bit is optional in the tone sliders and masking
+		it lets is avoid the 0xf 'bypass'.. */
+	} else if (mixer == SOUND_MIXER_BASS) {
+		val = maestro_ac97_get(card->iobase , mh->offset) & ~0x0f00;
+		val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
+	} else if (mixer == SOUND_MIXER_TREBLE)  {
+		val = maestro_ac97_get(card->iobase , mh->offset) & ~0x000f;
+		val |= (((100 - left) * mh->scale) / 100) & 0x000e;
+	}
+
+	maestro_ac97_set(card->iobase , mh->offset, val);
+	
+	M_printk(" -> %x\n",val);
+}
+
+/* the following tables allow us to go from 
+	OSS <-> ac97 quickly. */
+
+enum ac97_recsettings {
+	AC97_REC_MIC=0,
+	AC97_REC_CD,
+	AC97_REC_VIDEO,
+	AC97_REC_AUX,
+	AC97_REC_LINE,
+	AC97_REC_STEREO, /* combination of all enabled outputs..  */
+	AC97_REC_MONO,        /*.. or the mono equivalent */
+	AC97_REC_PHONE        
+};
+
+static unsigned int ac97_oss_mask[] = {
+	[AC97_REC_MIC] = SOUND_MASK_MIC, 
+	[AC97_REC_CD] = SOUND_MASK_CD, 
+	[AC97_REC_VIDEO] = SOUND_MASK_VIDEO, 
+	[AC97_REC_AUX] = SOUND_MASK_LINE1, 
+	[AC97_REC_LINE] = SOUND_MASK_LINE, 
+	[AC97_REC_PHONE] = SOUND_MASK_PHONEIN
+};
+
+/* indexed by bit position */
+static unsigned int ac97_oss_rm[] = {
+	[SOUND_MIXER_MIC] = AC97_REC_MIC,
+	[SOUND_MIXER_CD] = AC97_REC_CD,
+	[SOUND_MIXER_VIDEO] = AC97_REC_VIDEO,
+	[SOUND_MIXER_LINE1] = AC97_REC_AUX,
+	[SOUND_MIXER_LINE] = AC97_REC_LINE,
+	[SOUND_MIXER_PHONEIN] = AC97_REC_PHONE
+};
+	
+/* read or write the recmask 
+	the ac97 can really have left and right recording
+	inputs independantly set, but OSS doesn't seem to 
+	want us to express that to the user. 
+	the caller guarantees that we have a supported bit set,
+	and they must be holding the card's spinlock */
+static int 
+ac97_recmask_io(struct ess_card *card, int read, int mask) 
+{
+	unsigned int val = ac97_oss_mask[ maestro_ac97_get(card->iobase, 0x1a) & 0x7 ];
+
+	if (read) return val;
+
+	/* oss can have many inputs, maestro cant.  try
+		to pick the 'new' one */
+
+	if (mask != val) mask &= ~val;
+
+	val = ffs(mask) - 1; 
+	val = ac97_oss_rm[val];
+	val |= val << 8;  /* set both channels */
+
+	M_printk("maestro: setting ac97 recmask to 0x%x\n",val);
+
+	maestro_ac97_set(card->iobase,0x1a,val);
+
+	return 0;
+};
+
+/*
+ *	The Maestro can be wired to a standard AC97 compliant codec
+ *	(see www.intel.com for the pdf's on this), or to a PT101 codec
+ *	which appears to be the ES1918 (data sheet on the esstech.com.tw site)
+ *
+ *	The PT101 setup is untested.
+ */
+ 
+static u16 maestro_ac97_init(struct ess_card *card, int iobase)
+{
+	u16 vend1, vend2, caps;
+
+	card->mix.supported_mixers = AC97_SUPPORTED_MASK;
+	card->mix.stereo_mixers = AC97_STEREO_MASK;
+	card->mix.record_sources = AC97_RECORD_MASK;
+/*	card->mix.read_mixer = ac97_read_mixer;*/
+	card->mix.write_mixer = ac97_write_mixer;
+	card->mix.recmask_io = ac97_recmask_io;
+
+	vend1 = maestro_ac97_get(iobase, 0x7c);
+	vend2 = maestro_ac97_get(iobase, 0x7e);
+
+	caps = maestro_ac97_get(iobase, 0x00);
+
+	printk(KERN_INFO "maestro: AC97 Codec detected: v: 0x%2x%2x caps: 0x%x pwr: 0x%x\n",
+		vend1,vend2,caps,maestro_ac97_get(iobase,0x26) & 0xf);
+
+	if (! (caps & 0x4) ) {
+		/* no bass/treble nobs */
+		card->mix.supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE);
+	}
+
+	/* XXX endianness, dork head. */
+	/* vendor specifc bits.. */
+	switch ((long)(vend1 << 16) | vend2) {
+	case 0x545200ff:	/* TriTech */
+		/* no idea what this does */
+		maestro_ac97_set(iobase,0x2a,0x0001);
+		maestro_ac97_set(iobase,0x2c,0x0000);
+		maestro_ac97_set(iobase,0x2c,0xffff);
+		break;
+	case 0x83847609:	/* ESS 1921 */
+		/* writing to 0xe (mic) or 0x1a (recmask) seems
+			to hang this codec */
+		card->mix.supported_mixers &= ~(SOUND_MASK_MIC);
+		card->mix.record_sources = 0;
+		card->mix.recmask_io = NULL;
+#if 0	/* don't ask.  I have yet to see what these actually do. */
+		maestro_ac97_set(iobase,0x76,0xABBA); /* o/~ Take a chance on me o/~ */
+		udelay(20);
+		maestro_ac97_set(iobase,0x78,0x3002);
+		udelay(20);
+		maestro_ac97_set(iobase,0x78,0x3802);
+		udelay(20);
+#endif
+		break;
+	default: break;
+	}
+
+	maestro_ac97_set(iobase, 0x1E, 0x0404);
+	/* null misc stuff */
+	maestro_ac97_set(iobase, 0x20, 0x0000);
+
+	return 0;
+}
+
+#if 0  /* there has been 1 person on the planet with a pt101 that we
+	know of.  If they care, they can put this back in :) */
+static u16 maestro_pt101_init(struct ess_card *card,int iobase)
+{
+	printk(KERN_INFO "maestro: PT101 Codec detected, initializing but _not_ installing mixer device.\n");
+	/* who knows.. */
+	maestro_ac97_set(iobase, 0x2A, 0x0001);
+	maestro_ac97_set(iobase, 0x2C, 0x0000);
+	maestro_ac97_set(iobase, 0x2C, 0xFFFF);
+	maestro_ac97_set(iobase, 0x10, 0x9F1F);
+	maestro_ac97_set(iobase, 0x12, 0x0808);
+	maestro_ac97_set(iobase, 0x14, 0x9F1F);
+	maestro_ac97_set(iobase, 0x16, 0x9F1F);
+	maestro_ac97_set(iobase, 0x18, 0x0404);
+	maestro_ac97_set(iobase, 0x1A, 0x0000);
+	maestro_ac97_set(iobase, 0x1C, 0x0000);
+	maestro_ac97_set(iobase, 0x02, 0x0404);
+	maestro_ac97_set(iobase, 0x04, 0x0808);
+	maestro_ac97_set(iobase, 0x0C, 0x801F);
+	maestro_ac97_set(iobase, 0x0E, 0x801F);
+	return 0;
+}
+#endif
+
+/* this is very magic, and very slow.. */
+static void 
+maestro_ac97_reset(int ioaddr, struct pci_dev *pcidev)
+{
+	u16 save_68;
+	u16 w;
+	u32 vend;
+
+	outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);
+	outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);
+	outw( inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);
+
+	/* reset the first codec */
+	outw(0x0000,  ioaddr+0x36);
+	save_68 = inw(ioaddr+0x68);
+	pci_read_config_word(pcidev, 0x58, &w);	/* something magical with gpio and bus arb. */
+	pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &vend);
+	if( w & 0x1)
+		save_68 |= 0x10;
+	outw(0xfffe, ioaddr + 0x64);	/* tickly gpio 0.. */
+	outw(0x0001, ioaddr + 0x68);
+	outw(0x0000, ioaddr + 0x60);
+	udelay(20);
+	outw(0x0001, ioaddr + 0x60);
+	mdelay(20);
+
+	outw(save_68 | 0x1, ioaddr + 0x68);	/* now restore .. */
+	outw( (inw(ioaddr + 0x38) & 0xfffc)|0x1, ioaddr + 0x38);
+	outw( (inw(ioaddr + 0x3a) & 0xfffc)|0x1, ioaddr + 0x3a);
+	outw( (inw(ioaddr + 0x3c) & 0xfffc)|0x1, ioaddr + 0x3c);
+
+	/* now the second codec */
+	outw(0x0000,  ioaddr+0x36);
+	outw(0xfff7, ioaddr + 0x64);
+	save_68 = inw(ioaddr+0x68);
+	outw(0x0009, ioaddr + 0x68);
+	outw(0x0001, ioaddr + 0x60);
+	udelay(20);
+	outw(0x0009, ioaddr + 0x60);
+	mdelay(500);	/* .. ouch.. */
+	outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);
+	outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);
+	outw( inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);
+
+#if 0 /* the loop here needs to be much better if we want it.. */
+	M_printk("trying software reset\n");
+	/* try and do a software reset */
+	outb(0x80|0x7c, ioaddr + 0x30);
+	for (w=0; ; w++) {
+		if ((inw(ioaddr+ 0x30) & 1) == 0) {
+			if(inb(ioaddr + 0x32) !=0) break;
+
+			outb(0x80|0x7d, ioaddr + 0x30);
+			if (((inw(ioaddr+ 0x30) & 1) == 0) && (inb(ioaddr + 0x32) !=0)) break;
+			outb(0x80|0x7f, ioaddr + 0x30);
+			if (((inw(ioaddr+ 0x30) & 1) == 0) && (inb(ioaddr + 0x32) !=0)) break;
+		}
+
+		if( w > 10000) {
+			outb( inb(ioaddr + 0x37) | 0x08, ioaddr + 0x37);  /* do a software reset */
+			mdelay(500); /* oh my.. */
+			outb( inb(ioaddr + 0x37) & ~0x08, ioaddr + 0x37);  
+			udelay(1);
+			outw( 0x80, ioaddr+0x30);
+			for(w = 0 ; w < 10000; w++) {
+				if((inw(ioaddr + 0x30) & 1) ==0) break;
+			}
+		}
+	}
+#endif
+	if ( vend == NEC_VERSA_SUBID1 || vend == NEC_VERSA_SUBID2) {
+		/* turn on external amp? */
+		outw(0xf9ff, ioaddr + 0x64);
+		outw(inw(ioaddr+0x68) | 0x600, ioaddr + 0x68);
+		outw(0x0209, ioaddr + 0x60);
+	}
+}
+/*
+ *	Indirect register access. Not all registers are readable so we
+ *	need to keep register state ourselves
+ */
+ 
+#define WRITEABLE_MAP	0xEFFFFF
+#define READABLE_MAP	0x64003F
+
+/*
+ *	The Maestro engineers were a little indirection happy. These indirected
+ *	registers themselves include indirect registers at another layer
+ */
+
+static void __maestro_write(struct ess_card *card, u16 reg, u16 data)
+{
+	long ioaddr = card->iobase;
+
+	outw(reg, ioaddr+0x02);
+	outw(data, ioaddr+0x00);
+	if( reg >= NR_IDRS) printk("maestro: IDR %d out of bounds!\n",reg);
+	else card->maestro_map[reg]=data;
+
+}
+ 
+static void maestro_write(struct ess_state *s, u16 reg, u16 data)
+{
+	unsigned long flags;
+
+	CHECK_SUSPEND;
+	spin_lock_irqsave(&s->card->lock,flags);
+
+	__maestro_write(s->card,reg,data);
+
+	spin_unlock_irqrestore(&s->card->lock,flags);
+}
+
+static u16 __maestro_read(struct ess_card *card, u16 reg)
+{
+	long ioaddr = card->iobase;
+
+	outw(reg, ioaddr+0x02);
+	return card->maestro_map[reg]=inw(ioaddr+0x00);
+}
+
+static u16 maestro_read(struct ess_state *s, u16 reg)
+{
+	if(READABLE_MAP & (1<<reg))
+	{
+		unsigned long flags;
+		CHECK_SUSPEND;
+		spin_lock_irqsave(&s->card->lock,flags);
+
+		__maestro_read(s->card,reg);
+
+		spin_unlock_irqrestore(&s->card->lock,flags);
+	}
+	return s->card->maestro_map[reg];
+}
+
+/*
+ *	These routines handle accessing the second level indirections to the
+ *	wave ram.
+ */
+
+/*
+ *	The register names are the ones ESS uses (see 104T31.ZIP)
+ */
+ 
+#define IDR0_DATA_PORT		0x00
+#define IDR1_CRAM_POINTER	0x01
+#define IDR2_CRAM_DATA		0x02
+#define IDR3_WAVE_DATA		0x03
+#define IDR4_WAVE_PTR_LOW	0x04
+#define IDR5_WAVE_PTR_HI	0x05
+#define IDR6_TIMER_CTRL		0x06
+#define IDR7_WAVE_ROMRAM	0x07
+
+static void apu_index_set(struct ess_card *card, u16 index)
+{
+	int i;
+	__maestro_write(card, IDR1_CRAM_POINTER, index);
+	for(i=0;i<1000;i++)
+		if(__maestro_read(card, IDR1_CRAM_POINTER)==index)
+			return;
+	printk(KERN_WARNING "maestro: APU register select failed.\n");
+}
+
+static void apu_data_set(struct ess_card *card, u16 data)
+{
+	int i;
+	for(i=0;i<1000;i++)
+	{
+		if(__maestro_read(card, IDR0_DATA_PORT)==data)
+			return;
+		__maestro_write(card, IDR0_DATA_PORT, data);
+	}
+}
+
+/*
+ *	This is the public interface for APU manipulation. It handles the
+ *	interlock to avoid two APU writes in parallel etc. Don't diddle
+ *	directly with the stuff above.
+ */
+
+static void apu_set_register(struct ess_state *s, u16 channel, u8 reg, u16 data)
+{
+	unsigned long flags;
+	
+	CHECK_SUSPEND;
+
+	if(channel&ESS_CHAN_HARD)
+		channel&=~ESS_CHAN_HARD;
+	else
+	{
+		if(channel>5)
+			printk("BAD CHANNEL %d.\n",channel);
+		else
+			channel = s->apu[channel];
+#ifdef	CONFIG_APM
+		/* store based on real hardware apu/reg */
+		s->card->apu_map[channel][reg]=data;
+#endif
+	}
+	reg|=(channel<<4);
+	
+	/* hooray for double indirection!! */
+	spin_lock_irqsave(&s->card->lock,flags);
+
+	apu_index_set(s->card, reg);
+	apu_data_set(s->card, data);
+
+	spin_unlock_irqrestore(&s->card->lock,flags);
+}
+
+static u16 apu_get_register(struct ess_state *s, u16 channel, u8 reg)
+{
+	unsigned long flags;
+	u16 v;
+	
+	CHECK_SUSPEND;
+
+	if(channel&ESS_CHAN_HARD)
+		channel&=~ESS_CHAN_HARD;
+	else
+		channel = s->apu[channel];
+
+	reg|=(channel<<4);
+	
+	spin_lock_irqsave(&s->card->lock,flags);
+
+	apu_index_set(s->card, reg);
+	v=__maestro_read(s->card, IDR0_DATA_PORT);
+
+	spin_unlock_irqrestore(&s->card->lock,flags);
+	return v;
+}
+
+
+/*
+ *	The wavecache buffers between the APUs and
+ *	pci bus mastering
+ */
+ 
+static void wave_set_register(struct ess_state *s, u16 reg, u16 value)
+{
+	long ioaddr = s->card->iobase;
+	unsigned long flags;
+	CHECK_SUSPEND;
+	
+	spin_lock_irqsave(&s->card->lock,flags);
+
+	outw(reg, ioaddr+0x10);
+	outw(value, ioaddr+0x12);
+
+	spin_unlock_irqrestore(&s->card->lock,flags);
+}
+
+static u16 wave_get_register(struct ess_state *s, u16 reg)
+{
+	long ioaddr = s->card->iobase;
+	unsigned long flags;
+	u16 value;
+	CHECK_SUSPEND;
+	
+	spin_lock_irqsave(&s->card->lock,flags);
+	outw(reg, ioaddr+0x10);
+	value=inw(ioaddr+0x12);
+	spin_unlock_irqrestore(&s->card->lock,flags);
+	
+	return value;
+}
+
+static void sound_reset(int ioaddr)
+{
+	outw(0x2000, 0x18+ioaddr);
+	udelay(1);
+	outw(0x0000, 0x18+ioaddr);
+	udelay(1);
+}
+
+/* sets the play formats of these apus, should be passed the already shifted format */
+static void set_apu_fmt(struct ess_state *s, int apu, int mode)
+{
+	int apu_fmt = 0x10;
+
+	if(!(mode&ESS_FMT_16BIT)) apu_fmt+=0x20; 
+	if((mode&ESS_FMT_STEREO)) apu_fmt+=0x10; 
+	s->apu_mode[apu]   = apu_fmt;
+	s->apu_mode[apu+1] = apu_fmt;
+}
+
+/* this only fixes the output apu mode to be later set by start_dac and
+	company.  output apu modes are set in ess_rec_setup */
+static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data)
+{
+	s->fmt = (s->fmt & mask) | data;
+	set_apu_fmt(s, 0, (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK);
+}
+
+/* this is off by a little bit.. */
+static u32 compute_rate(struct ess_state *s, u32 freq)
+{
+	u32 clock = clock_freq[s->card->card_type];     
+
+	if (freq == 48000) return 0x10000;
+
+	return ((freq / clock) <<16 )+  
+		(((freq % clock) << 16) / clock);
+}
+
+static void set_dac_rate(struct ess_state *s, unsigned int rate)
+{
+	u32 freq;
+	int fmt = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
+
+	if (rate > 48000)
+		rate = 48000;
+	if (rate < 4000)
+		rate = 4000;
+
+	s->ratedac = rate;
+
+	if(! (fmt & ESS_FMT_16BIT) && !(fmt & ESS_FMT_STEREO))
+		rate >>= 1;
+
+/*	M_printk("computing dac rate %d with mode %d\n",rate,s->fmt);*/
+
+	freq = compute_rate(s, rate);
+	
+	/* Load the frequency, turn on 6dB */
+	apu_set_register(s, 0, 2,(apu_get_register(s, 0, 2)&0x00FF)|
+		( ((freq&0xFF)<<8)|0x10 ));
+	apu_set_register(s, 0, 3, freq>>8);
+	apu_set_register(s, 1, 2,(apu_get_register(s, 1, 2)&0x00FF)|
+		( ((freq&0xFF)<<8)|0x10 ));
+	apu_set_register(s, 1, 3, freq>>8);
+}
+
+static void set_adc_rate(struct ess_state *s, unsigned rate)
+{
+	u32 freq;
+
+	/* Sample Rate conversion APUs don't like 0x10000 for their rate */
+	if (rate > 47999)
+		rate = 47999;
+	if (rate < 4000)
+		rate = 4000;
+
+	s->rateadc = rate;
+
+	freq = compute_rate(s, rate);
+	
+	/* Load the frequency, turn on 6dB */
+	apu_set_register(s, 2, 2,(apu_get_register(s, 2, 2)&0x00FF)|
+		( ((freq&0xFF)<<8)|0x10 ));
+	apu_set_register(s, 2, 3, freq>>8);
+	apu_set_register(s, 3, 2,(apu_get_register(s, 3, 2)&0x00FF)|
+		( ((freq&0xFF)<<8)|0x10 ));
+	apu_set_register(s, 3, 3, freq>>8);
+
+	/* fix mixer rate at 48khz.  and its _must_ be 0x10000. */
+	freq = 0x10000;
+
+	apu_set_register(s, 4, 2,(apu_get_register(s, 4, 2)&0x00FF)|
+		( ((freq&0xFF)<<8)|0x10 ));
+	apu_set_register(s, 4, 3, freq>>8);
+	apu_set_register(s, 5, 2,(apu_get_register(s, 5, 2)&0x00FF)|
+		( ((freq&0xFF)<<8)|0x10 ));
+	apu_set_register(s, 5, 3, freq>>8);
+}
+
+/* Stop our host of recording apus */
+extern inline void stop_adc(struct ess_state *s)
+{
+	/* XXX lets hope we don't have to lock around this */
+	if (! (s->enable & ADC_RUNNING)) return;
+
+	s->enable &= ~ADC_RUNNING;
+	apu_set_register(s, 2, 0, apu_get_register(s, 2, 0)&0xFF0F);
+	apu_set_register(s, 3, 0, apu_get_register(s, 3, 0)&0xFF0F);
+	apu_set_register(s, 4, 0, apu_get_register(s, 2, 0)&0xFF0F);
+	apu_set_register(s, 5, 0, apu_get_register(s, 3, 0)&0xFF0F);
+}	
+
+/* stop output apus */
+extern inline void stop_dac(struct ess_state *s)
+{
+	/* XXX have to lock around this? */
+	if (! (s->enable & DAC_RUNNING)) return;
+
+	s->enable &= ~DAC_RUNNING;
+	apu_set_register(s, 0, 0, apu_get_register(s, 0, 0)&0xFF0F);
+	apu_set_register(s, 1, 0, apu_get_register(s, 1, 0)&0xFF0F);
+}	
+
+static void start_dac(struct ess_state *s)
+{
+	/* XXX locks? */
+	if (	(s->dma_dac.mapped || s->dma_dac.count > 0) && 
+		s->dma_dac.ready &&
+		(! (s->enable & DAC_RUNNING)) ) {
+
+		s->enable |= DAC_RUNNING;
+
+		apu_set_register(s, 0, 0, 
+			(apu_get_register(s, 0, 0)&0xFF0F)|s->apu_mode[0]);
+
+		if((s->fmt >> ESS_DAC_SHIFT)  & ESS_FMT_STEREO) 
+			apu_set_register(s, 1, 0, 
+				(apu_get_register(s, 1, 0)&0xFF0F)|s->apu_mode[1]);
+	}
+}	
+
+static void start_adc(struct ess_state *s)
+{
+	/* XXX locks? */
+	if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) 
+	    && s->dma_adc.ready && (! (s->enable & ADC_RUNNING)) ) {
+
+		s->enable |= ADC_RUNNING;
+		apu_set_register(s, 2, 0, 
+			(apu_get_register(s, 2, 0)&0xFF0F)|s->apu_mode[2]);
+		apu_set_register(s, 4, 0, 
+			(apu_get_register(s, 4, 0)&0xFF0F)|s->apu_mode[4]);
+
+		if( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {
+			apu_set_register(s, 3, 0, 
+				(apu_get_register(s, 3, 0)&0xFF0F)|s->apu_mode[3]);
+			apu_set_register(s, 5, 0, 
+				(apu_get_register(s, 5, 0)&0xFF0F)|s->apu_mode[5]);
+		}
+			
+	}
+}	
+
+
+/*
+ *	Native play back driver 
+ */
+
+/* the mode passed should be already shifted and masked */
+static void 
+ess_play_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size)
+{
+	u32 pa;
+	u32 tmpval;
+	int high_apu = 0;
+	int channel;
+
+	M_printk("mode=%d rate=%d buf=%p len=%d.\n",
+		mode, rate, buffer, size);
+		
+	/* all maestro sizes are in 16bit words */
+	size >>=1;
+
+	if(mode&ESS_FMT_STEREO) {
+		high_apu++;
+		/* only 16/stereo gets size divided */
+		if(mode&ESS_FMT_16BIT)
+			size>>=1;
+	}
+	
+	for(channel=0; channel <= high_apu; channel++)
+	{
+		pa = virt_to_bus(buffer);
+
+		/* set the wavecache control reg */
+		tmpval = (pa - 0x10) & 0xFFF8;
+		if(!(mode & ESS_FMT_16BIT)) tmpval |= 4;
+		if(mode & ESS_FMT_STEREO) tmpval |= 2;
+		ess->apu_base[channel]=tmpval;
+		wave_set_register(ess, ess->apu[channel]<<3, tmpval);
+		
+		pa -= virt_to_bus(ess->card->dmapages);
+		pa>>=1; /* words */
+		
+		/* base offset of dma calcs when reading the pointer
+			on the left one */
+		if(!channel) ess->dma_dac.base = pa&0xFFFF;
+		
+		pa|=0x00400000;			/* System RAM */
+
+		/* XXX the 16bit here might not be needed.. */
+		if((mode & ESS_FMT_STEREO) && (mode & ESS_FMT_16BIT)) {
+			if(channel) 
+				pa|=0x00800000;			/* Stereo */
+			pa>>=1;
+		}
+			
+/* XXX think about endianess when writing these registers */
+		M_printk("maestro: ess_play_setup: APU[%d] pa = 0x%x\n", ess->apu[channel], pa);
+		/* Load the buffer into the wave engine */
+		apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8);
+		apu_set_register(ess, channel, 5, pa&0xFFFF);
+		apu_set_register(ess, channel, 6, (pa+size)&0xFFFF);
+		/* setting loop == sample len */
+		apu_set_register(ess, channel, 7, size);
+		
+		/* clear effects/env.. */
+		apu_set_register(ess, channel, 8, 0x0000);
+		/* set amp now to 0xd0 (?), low byte is 'amplitude dest'? */
+		apu_set_register(ess, channel, 9, 0xD000);
+
+		/* clear routing stuff */
+		apu_set_register(ess, channel, 11, 0x0000);
+		/* dma on, no envelopes, filter to all 1s) */
+		apu_set_register(ess, channel, 0, 0x400F);
+		
+		if(mode&ESS_FMT_16BIT)
+			ess->apu_mode[channel]=0x10;
+		else
+			ess->apu_mode[channel]=0x30;
+
+		if(mode&ESS_FMT_STEREO) {
+			/* set panning: left or right */
+			apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0x10 : 0));
+			ess->apu_mode[channel] += 0x10;
+		} else
+			apu_set_register(ess, channel, 10, 0x8F08);
+	}
+	
+	/* clear WP interupts */
+	outw(1, ess->card->iobase+0x04);
+	/* enable WP ints */
+	outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18);
+
+	/* go team! */
+	set_dac_rate(ess,rate);
+	start_dac(ess);
+}
+
+/*
+ *	Native record driver 
+ */
+
+/* again, passed mode is alrady shifted/masked */
+static void 
+ess_rec_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size)
+{
+	int apu_step = 2;
+	int channel;
+
+	M_printk("maestro: ess_rec_setup: mode=%d rate=%d buf=0x%p len=%d.\n",
+		mode, rate, buffer, size);
+		
+	/* all maestro sizes are in 16bit words */
+	size >>=1;
+
+	/* we're given the full size of the buffer, but
+	in stereo each channel will only use its half */
+	if(mode&ESS_FMT_STEREO) {
+		size >>=1; 
+		apu_step = 1;
+	}
+	
+	/* APU assignments: 2 = mono/left SRC
+	                    3 = right SRC
+	                    4 = mono/left Input Mixer
+	                    5 = right Input Mixer */
+	for(channel=2;channel<6;channel+=apu_step)
+	{
+		int i;
+		int bsize, route;
+		u32 pa;
+		u32 tmpval;
+
+		/* data seems to flow from the codec, through an apu into
+			the 'mixbuf' bit of page, then through the SRC apu
+			and out to the real 'buffer'.  ok.  sure.  */
+		
+		if(channel & 0x04) {
+			/* ok, we're an input mixer going from adc
+				through the mixbuf to the other apus */
+
+			if(!(channel & 0x01)) { 
+				pa = virt_to_bus(ess->mixbuf);
+			} else {
+				pa = virt_to_bus(ess->mixbuf + (PAGE_SIZE >> 4));
+			}
+
+			/* we source from a 'magic' apu */
+			bsize = PAGE_SIZE >> 5;	/* half of this channels alloc, in words */
+			route = 0x14 + (channel - 4); /* parallel in crap, see maestro reg 0xC [8-11] */
+			ess->apu_mode[channel] = 0x90;  /* Input Mixer */
+
+		} else {  
+			/* we're a rate converter taking
+				input from the input apus and outputing it to
+				system memory */
+			if(!(channel & 0x01))  {
+				pa = virt_to_bus(buffer);
+			} else {
+				/* right channel records its split half.
+				*2 accomodates for rampant shifting earlier */
+				pa = virt_to_bus(buffer + size*2);
+			}
+
+			ess->apu_mode[channel] = 0xB0;  /* Sample Rate Converter */
+
+			bsize = size; 
+			/* get input from inputing apu */
+			route = channel + 2;
+		}
+
+		M_printk("maestro: ess_rec_setup: getting pa 0x%x from %d\n",pa,channel);
+		
+		/* set the wavecache control reg */
+		tmpval = (pa - 0x10) & 0xFFF8;
+		ess->apu_base[channel]=tmpval;
+		wave_set_register(ess, ess->apu[channel]<<3, tmpval);
+		
+		pa -= virt_to_bus(ess->card->dmapages);
+		pa>>=1; /* words */
+		
+		/* base offset of dma calcs when reading the pointer
+			on this left one */
+		if(channel==2) ess->dma_adc.base = pa&0xFFFF;
+
+		pa|=0x00400000;			/* bit 22 -> System RAM */
+
+		M_printk("maestro: ess_rec_setup: APU[%d] pa = 0x%x size = 0x%x route = 0x%x\n", 
+			ess->apu[channel], pa, bsize, route);
+		
+		/* Begin loading the APU */		
+		for(i=0;i<15;i++)		/* clear all PBRs */
+			apu_set_register(ess, channel, i, 0x0000);
+			
+		apu_set_register(ess, channel, 0, 0x400F);
+
+		/* need to enable subgroups.. and we should probably
+			have different groups for different /dev/dsps..  */
+ 		apu_set_register(ess, channel, 2, 0x8);
+				
+		/* Load the buffer into the wave engine */
+		apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8);
+		/* XXX reg is little endian.. */
+		apu_set_register(ess, channel, 5, pa&0xFFFF);
+		apu_set_register(ess, channel, 6, (pa+bsize)&0xFFFF);
+		apu_set_register(ess, channel, 7, bsize);
+				
+		/* clear effects/env.. */
+		apu_set_register(ess, channel, 8, 0x00F0);
+		
+		/* amplitude now?  sure.  why not.  */
+		apu_set_register(ess, channel, 9, 0x0000);
+
+		/* set filter tune, radius, polar pan */
+		apu_set_register(ess, channel, 10, 0x8F08);
+
+		/* route input */
+		apu_set_register(ess, channel, 11, route);
+	}
+	
+	/* clear WP interupts */
+	outw(1, ess->card->iobase+0x04);
+	/* enable WP ints */
+	outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18);
+
+	/* let 'er rip */
+	set_adc_rate(ess,rate);
+	start_adc(ess);
+}
+/* --------------------------------------------------------------------- */
+
+static void set_dmaa(struct ess_state *s, unsigned int addr, unsigned int count)
+{
+	M_printk("set_dmaa??\n");
+}
+
+static void set_dmac(struct ess_state *s, unsigned int addr, unsigned int count)
+{
+	M_printk("set_dmac??\n");
+}
+
+/* Playback pointer */
+extern __inline__ unsigned get_dmaa(struct ess_state *s)
+{
+	int offset;
+
+	offset = apu_get_register(s,0,5);
+
+/*	M_printk("dmaa: offset: %d, base: %d\n",offset,s->dma_dac.base); */
+	
+	offset-=s->dma_dac.base;
+
+	return (offset&0xFFFE)<<1; /* hardware is in words */
+}
+
+/* Record pointer */
+extern __inline__ unsigned get_dmac(struct ess_state *s)
+{
+	int offset;
+
+	offset = apu_get_register(s,2,5);
+
+/*	M_printk("dmac: offset: %d, base: %d\n",offset,s->dma_adc.base); */
+	
+	/* The offset is an address not a position relative to base */
+	offset-=s->dma_adc.base;
+	
+	return (offset&0xFFFE)<<1; /* hardware is in words */
+}
+
+/*
+ *	Meet Bob, the timer...
+ */
+
+static void ess_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+static void stop_bob(struct ess_state *s)
+{
+	/* Mask IDR 11,17 */
+	maestro_write(s,  0x11, maestro_read(s, 0x11)&~1);
+	maestro_write(s,  0x17, maestro_read(s, 0x17)&~1);
+}
+
+/* eventually we could be clever and limit bob ints
+	to the frequency at which our smallest duration
+	chunks may expire */
+#define ESS_SYSCLK	50000000
+static void start_bob(struct ess_state *s)
+{
+	int prescale;
+	int divide;
+	
+	/* XXX make freq selector much smarter, see calc_bob_rate */
+	int freq = 150;		/* requested frequency - calculate what we want here. */
+	
+	/* compute ideal interrupt frequency for buffer size & play rate */
+	/* first, find best prescaler value to match freq */
+	for(prescale=5;prescale<12;prescale++)
+		if(freq > (ESS_SYSCLK>>(prescale+9)))
+			break;
+			
+	/* next, back off prescaler whilst getting divider into optimum range */
+	divide=1;
+	while((prescale > 5) && (divide<32))
+	{
+		prescale--;
+		divide <<=1;
+	}
+	divide>>=1;
+	
+	/* now fine-tune the divider for best match */
+	for(;divide<31;divide++)
+		if(freq >= ((ESS_SYSCLK>>(prescale+9))/(divide+1)))
+			break;
+	
+	/* divide = 0 is illegal, but don't let prescale = 4! */
+	if(divide == 0)
+	{
+		divide++;
+		if(prescale>5)
+			prescale--;
+	}
+
+	maestro_write(s, 6, 0x9000 | (prescale<<5) | divide); /* set reg */
+	
+	/* Now set IDR 11/17 */
+	maestro_write(s, 0x11, maestro_read(s, 0x11)|1);
+	maestro_write(s, 0x17, maestro_read(s, 0x17)|1);
+}
+/* --------------------------------------------------------------------- */
+
+/* this quickly calculates the frequency needed for bob
+	and sets it if its different than what bob is
+	currently running at.  its called often so 
+	needs to be fairly quick. */
+#define BOB_MIN 50
+#define BOB_MAX 400
+static void calc_bob_rate(struct ess_state *s) {
+#if 0 /* this thing tries to set the frequency of bob such that
+	there are 2 interrupts / buffer walked by the dac/adc.  That
+	is probably very wrong for people who actually care about 
+	mid buffer positioning.  it should be calculated as bytes/interrupt
+	and that needs to be decided :)  so for now just use the static 150
+	in start_bob.*/
+
+	unsigned int dac_rate=2,adc_rate=1,newrate;
+	static int israte=-1;
+
+	if (s->dma_dac.fragsize == 0) dac_rate = BOB_MIN;
+	else  {
+		dac_rate =	(2 * s->ratedac * sample_size[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]) /
+				(s->dma_dac.fragsize) ;
+	}
+		
+	if (s->dma_adc.fragsize == 0) adc_rate = BOB_MIN;
+	else {
+		adc_rate =	(2 * s->rateadc * sample_size[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]) /
+				(s->dma_adc.fragsize) ;
+	}
+
+	if(dac_rate > adc_rate) newrate = adc_rate;
+	else newrate=dac_rate;
+
+	if(newrate > BOB_MAX) newrate = BOB_MAX;
+	else {
+		if(newrate < BOB_MIN) 
+			newrate = BOB_MIN;
+	}
+
+	if( israte != newrate) {
+		printk("dac: %d  adc: %d rate: %d\n",dac_rate,adc_rate,israte);
+		israte=newrate;
+	}
+#endif
+
+}
+
+static int 
+prog_dmabuf(struct ess_state *s, unsigned rec)
+{
+	struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
+	unsigned rate = rec ? s->rateadc : s->ratedac;
+	unsigned bytepersec;
+	unsigned bufs;
+	unsigned char fmt;
+	unsigned long flags;
+
+	spin_lock_irqsave(&s->lock, flags);
+	fmt = s->fmt;
+	if (rec) {
+		stop_adc(s);
+		fmt >>= ESS_ADC_SHIFT;
+	} else {
+		stop_dac(s);
+		fmt >>= ESS_DAC_SHIFT;
+	}
+	spin_unlock_irqrestore(&s->lock, flags);
+	fmt &= ESS_FMT_MASK;
+
+	db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
+
+	bytepersec = rate << sample_shift[fmt];
+	bufs = PAGE_SIZE << db->buforder;
+	if (db->ossfragshift) {
+		if ((1000 << db->ossfragshift) < bytepersec)
+			db->fragshift = ld2(bytepersec/1000);
+		else
+			db->fragshift = db->ossfragshift;
+	} else {
+		db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
+		if (db->fragshift < 3)
+			db->fragshift = 3; 
+	}
+	db->numfrag = bufs >> db->fragshift;
+	while (db->numfrag < 4 && db->fragshift > 3) {
+		db->fragshift--;
+		db->numfrag = bufs >> db->fragshift;
+	}
+	db->fragsize = 1 << db->fragshift;
+	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+		db->numfrag = db->ossmaxfrags;
+	db->fragsamples = db->fragsize >> sample_shift[fmt];
+	db->dmasize = db->numfrag << db->fragshift;
+
+	M_printk("maestro: setup oss: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize);
+
+	memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize);
+
+	spin_lock_irqsave(&s->lock, flags);
+	if (rec) {
+		ess_rec_setup(s, fmt, s->rateadc, 
+			db->rawbuf, db->numfrag << db->fragshift);
+	} else {
+		ess_play_setup(s, fmt, s->ratedac, 
+			db->rawbuf, db->numfrag << db->fragshift);
+	}
+	spin_unlock_irqrestore(&s->lock, flags);
+	db->ready = 1;
+
+	return 0;
+}
+
+static __inline__ void 
+clear_advance(struct ess_state *s)
+{
+	unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80;
+	
+	unsigned char *buf = s->dma_dac.rawbuf;
+	unsigned bsize = s->dma_dac.dmasize;
+	unsigned bptr = s->dma_dac.swptr;
+	unsigned len = s->dma_dac.fragsize;
+	
+	if (bptr + len > bsize) {
+		unsigned x = bsize - bptr;
+		memset(buf + bptr, c, x);
+		/* account for wrapping? */
+		bptr = 0;
+		len -= x;
+	}
+	memset(buf + bptr, c, len);
+}
+
+/* call with spinlock held! */
+static void 
+ess_update_ptr(struct ess_state *s)
+{
+	unsigned hwptr;
+	int diff;
+
+	/* update ADC pointer */
+	if (s->dma_adc.ready) {
+		/* oh boy should this all be re-written.  everything in the current code paths think
+		that the various counters/pointers are expressed in bytes to the user but we have
+		two apus doing stereo stuff so we fix it up here.. it propogates to all the various
+		counters from here.  Notice that this means that mono recording is very very
+		broken right now.  */
+		if ( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {
+			hwptr = (get_dmac(s)*2) % s->dma_adc.dmasize;
+		} else {
+			hwptr = get_dmac(s) % s->dma_adc.dmasize;
+		}
+		diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
+		s->dma_adc.hwptr = hwptr;
+		s->dma_adc.total_bytes += diff;
+		s->dma_adc.count += diff;
+		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) 
+			wake_up(&s->dma_adc.wait);
+		if (!s->dma_adc.mapped) {
+			if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
+				/* FILL ME 
+				wrindir(s, SV_CIENABLE, s->enable); */
+				stop_adc(s); 
+				/* brute force everyone back in sync, sigh */
+				s->dma_adc.count = 0;
+				s->dma_adc.swptr = 0;
+				s->dma_adc.hwptr = 0;
+				s->dma_adc.error++;
+			}
+		}
+	}
+	/* update DAC pointer */
+	if (s->dma_dac.ready) {
+		hwptr = get_dmaa(s) % s->dma_dac.dmasize; 
+		/* the apu only reports the length it has seen, not the
+			length of the memory that has been used (the WP
+			knows that */
+		if ( ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK) == (ESS_FMT_STEREO|ESS_FMT_16BIT))
+			hwptr<<=1;
+
+		diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
+/*		M_printk("updating dac: hwptr: %d diff: %d\n",hwptr,diff);*/
+		s->dma_dac.hwptr = hwptr;
+		s->dma_dac.total_bytes += diff;
+		if (s->dma_dac.mapped) {
+			s->dma_dac.count += diff;
+			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) {
+				wake_up(&s->dma_dac.wait);
+			}
+		} else {
+			s->dma_dac.count -= diff;
+/*			M_printk("maestro: ess_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count); */
+			if (s->dma_dac.count <= 0) {
+				/* FILL ME 
+				wrindir(s, SV_CIENABLE, s->enable); */
+				/* XXX how on earth can calling this with the lock held work.. */
+				stop_dac(s);
+				/* brute force everyone back in sync, sigh */
+				s->dma_dac.count = 0; 
+				s->dma_dac.swptr = 0; 
+				s->dma_dac.hwptr = 0; 
+				s->dma_dac.error++;
+			} else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
+				clear_advance(s);
+				s->dma_dac.endcleared = 1;
+			}
+			if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) {
+				wake_up(&s->dma_dac.wait);
+			}
+		}
+	}
+}
+
+static void 
+ess_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+        struct ess_state *s;
+        struct ess_card *c = (struct ess_card *)dev_id;
+	int i;
+	u32 event;
+
+	if ( ! (event = inb(c->iobase+0x1A)) ) return;
+
+	outw(inw(c->iobase+4)&1, c->iobase+4);
+
+/*	M_printk("maestro int: %x\n",event);*/
+
+	if(event&(1<<6))
+	{
+		/* XXX if we have a hw volume control int enable
+			all the ints?  doesn't make sense.. */
+		event = inw(c->iobase+0x18);
+		outb(0xFF, c->iobase+0x1A);
+	}
+	else
+	{
+		/* else ack 'em all, i imagine */
+		outb(0xFF, c->iobase+0x1A);
+	}
+		
+	/*
+	 *	Update the pointers for all APU's we are running.
+	 */
+	for(i=0;i<NR_DSPS;i++)
+	{
+		s=&c->channels[i];
+		if(s->dev_audio == -1)
+			break;
+		spin_lock(&s->lock);
+		ess_update_ptr(s);
+		spin_unlock(&s->lock);
+	}
+}
+
+
+/* --------------------------------------------------------------------- */
+
+static const char invalid_magic[] = KERN_CRIT "maestro: invalid magic value in %s\n";
+
+#define VALIDATE_MAGIC(FOO,MAG)                         \
+({                                                \
+	if (!(FOO) || (FOO)->magic != MAG) { \
+		printk(invalid_magic,__FUNCTION__);            \
+		return -ENXIO;                    \
+	}                                         \
+})
+
+#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,ESS_STATE_MAGIC)
+#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,ESS_CARD_MAGIC)
+
+static void set_mixer(struct ess_card *card,unsigned int mixer, unsigned int val ) 
+{
+	unsigned int left,right;
+	/* cleanse input a little */
+	right = ((val >> 8)  & 0xff) ;
+	left = (val  & 0xff) ;
+
+	if(right > 100) right = 100;
+	if(left > 100) left = 100;
+
+	card->mix.mixer_state[mixer]=(right << 8) | left;
+	card->mix.write_mixer(card,mixer,left,right);
+}
+
+static void
+mixer_push_state(struct ess_card *card)
+{
+	int i;
+	for(i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++) {
+		if( ! supported_mixer(card,i)) continue;
+
+		set_mixer(card,i,card->mix.mixer_state[i]);
+	}
+}
+
+static int mixer_ioctl(struct ess_card *card, unsigned int cmd, unsigned long arg)
+{
+	int i, val=0;
+
+	VALIDATE_CARD(card);
+        if (cmd == SOUND_MIXER_INFO) {
+		mixer_info info;
+		strncpy(info.id, card_names[card->card_type], sizeof(info.id));
+		strncpy(info.name,card_names[card->card_type],sizeof(info.name));
+		info.modify_counter = card->mix.modcnt;
+		if (copy_to_user((void *)arg, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == SOUND_OLD_MIXER_INFO) {
+		_old_mixer_info info;
+		strncpy(info.id, card_names[card->card_type], sizeof(info.id));
+		strncpy(info.name,card_names[card->card_type],sizeof(info.name));
+		if (copy_to_user((void *)arg, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == OSS_GETVERSION)
+		return put_user(SOUND_VERSION, (int *)arg);
+
+	if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+                return -EINVAL;
+
+        if (_IOC_DIR(cmd) == _IOC_READ) {
+                switch (_IOC_NR(cmd)) {
+                case SOUND_MIXER_RECSRC: /* give them the current record source */
+
+			if(!card->mix.recmask_io) {
+				val = 0;
+			} else {
+				spin_lock(&card->lock);
+				val = card->mix.recmask_io(card,1,0);
+				spin_unlock(&card->lock);
+			}
+			break;
+			
+                case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
+			val = card->mix.supported_mixers;
+			break;
+
+                case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+			val = card->mix.record_sources;
+			break;
+			
+                case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+			val = card->mix.stereo_mixers;
+			break;
+			
+                case SOUND_MIXER_CAPS:
+			val = SOUND_CAP_EXCL_INPUT;
+			break;
+
+		default: /* read a specific mixer */
+			i = _IOC_NR(cmd);
+
+			if ( ! supported_mixer(card,i)) 
+				return -EINVAL;
+
+			/* do we ever want to touch the hardware? */
+/*			spin_lock(&card->lock);
+			val = card->mix.read_mixer(card,i);
+			spin_unlock(&card->lock);*/
+
+			val = card->mix.mixer_state[i];
+/*			M_printk("returned 0x%x for mixer %d\n",val,i);*/
+
+			break;
+		}
+		return put_user(val,(int *)arg);
+	}
+	
+        if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ))
+		return -EINVAL;
+	
+	card->mix.modcnt++;
+
+	get_user_ret(val, (int *)arg, -EFAULT);
+
+	switch (_IOC_NR(cmd)) {
+	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+
+		if (!card->mix.recmask_io) return -EINVAL;
+		if(!val) return 0;
+		if(! (val &= card->mix.record_sources)) return -EINVAL;
+
+		spin_lock(&card->lock);
+		card->mix.recmask_io(card,0,val);
+		spin_unlock(&card->lock);
+		return 0;
+
+	default:
+		i = _IOC_NR(cmd);
+
+		if ( ! supported_mixer(card,i)) 
+			return -EINVAL;
+
+		spin_lock(&card->lock);
+		set_mixer(card,i,val);
+		spin_unlock(&card->lock);
+
+		return 0;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static loff_t ess_llseek(struct file *file, loff_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int ess_open_mixdev(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct ess_card *card = devs;
+
+	while (card && card->dev_mixer != minor)
+		card = card->next;
+	if (!card)
+		return -ENODEV;
+
+	file->private_data = card;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int ess_release_mixdev(struct inode *inode, struct file *file)
+{
+	struct ess_card *card = (struct ess_card *)file->private_data;
+
+	VALIDATE_CARD(card);
+	
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int ess_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct ess_card *card = (struct ess_card *)file->private_data;
+
+	VALIDATE_CARD(card);
+
+	return mixer_ioctl(card, cmd, arg);
+}
+
+static /*const*/ struct file_operations ess_mixer_fops = {
+	&ess_llseek,
+	NULL,  /* read */
+	NULL,  /* write */
+	NULL,  /* readdir */
+	NULL,  /* poll */
+	&ess_ioctl_mixdev,
+	NULL,  /* mmap */
+	&ess_open_mixdev,
+	NULL,	/* flush */
+	&ess_release_mixdev,
+	NULL,  /* fsync */
+	NULL,  /* fasync */
+	NULL,  /* check_media_change */
+	NULL,  /* revalidate */
+	NULL,  /* lock */
+};
+
+/* --------------------------------------------------------------------- */
+
+static int drain_dac(struct ess_state *s, int nonblock)
+{
+	DECLARE_WAITQUEUE(wait,current);
+	unsigned long flags;
+	int count;
+	signed long tmo;
+
+	if (s->dma_dac.mapped || !s->dma_dac.ready)
+		return 0;
+	current->state = TASK_INTERRUPTIBLE;
+        add_wait_queue(&s->dma_dac.wait, &wait);
+        for (;;) {
+		/* XXX uhm.. questionable locking*/
+                spin_lock_irqsave(&s->lock, flags);
+		count = s->dma_dac.count;
+                spin_unlock_irqrestore(&s->lock, flags);
+		if (count <= 0)
+			break;
+		if (signal_pending(current))
+                        break;
+                if (nonblock) {
+                        remove_wait_queue(&s->dma_dac.wait, &wait);
+			current->state = TASK_RUNNING;
+                        return -EBUSY;
+                }
+		tmo = (count * HZ) / s->ratedac;
+		tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK];
+		/* XXX this is just broken.  someone is waking us up alot, or schedule_timeout is broken.
+			or something.  who cares. - zach */
+		if (!schedule_timeout(tmo ? tmo : 1) && tmo)
+			M_printk(KERN_DEBUG "maestro: dma timed out?? %ld\n",jiffies);
+        }
+        remove_wait_queue(&s->dma_dac.wait, &wait);
+	current->state = TASK_RUNNING;
+        if (signal_pending(current))
+                return -ERESTARTSYS;
+        return 0;
+}
+
+/* --------------------------------------------------------------------- */
+/* Zach sez: "god this is gross.." */
+static int 
+comb_stereo(unsigned char *real_buffer,unsigned char  *tmp_buffer, int offset, 
+	int count, int bufsize)
+{  
+	/* No such thing as stereo recording, so we
+	use dual input mixers.  which means we have to 
+	combine mono to stereo buffer.  yuck. 
+
+	but we don't have to be able to work a byte at a time..*/
+
+	unsigned char *so,*left,*right;
+	int i;
+
+	so = tmp_buffer;
+	left = real_buffer + offset;
+	right = real_buffer + bufsize/2 + offset;
+
+/*	M_printk("comb_stereo writing %d to %p from %p and %p, offset: %d size: %d\n",count/2, tmp_buffer,left,right,offset,bufsize);*/
+
+	for(i=count/4; i ; i--) {
+		(*(so+2)) = *(right++);
+		(*(so+3)) = *(right++);
+		(*so) = *(left++);
+		(*(so+1)) = *(left++);
+		so+=4;
+	}
+
+	return 0;
+}
+
+/* in this loop, dma_adc.count signifies the amount of data thats waiting
+	to be copied to the user's buffer.  it is filled by the interrupt
+	handler and drained by this loop. */
+static ssize_t 
+ess_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct ess_state *s = (struct ess_state *)file->private_data;
+	ssize_t ret;
+	unsigned long flags;
+	unsigned swptr;
+	int cnt;
+	unsigned char *combbuf = NULL;
+	
+	VALIDATE_STATE(s);
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (s->dma_adc.mapped)
+		return -ENXIO;
+	if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+		return ret;
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return -EFAULT;
+	if(!(combbuf = kmalloc(count,GFP_KERNEL)))
+		return -ENOMEM;
+	ret = 0;
+
+	calc_bob_rate(s);
+
+	while (count > 0) {
+		spin_lock_irqsave(&s->lock, flags);
+		/* remember, all these things are expressed in bytes to be
+			sent to the user.. hence the evil / 2 down below */
+		swptr = s->dma_adc.swptr;
+		cnt = s->dma_adc.dmasize-swptr;
+		if (s->dma_adc.count < cnt)
+			cnt = s->dma_adc.count;
+		spin_unlock_irqrestore(&s->lock, flags);
+
+		if (cnt > count)
+			cnt = count;
+
+		if ( cnt > 0 ) cnt &= ~3;
+
+		if (cnt <= 0) {
+			start_adc(s);
+			if (file->f_flags & O_NONBLOCK) 
+			{
+				ret = ret ? ret : -EAGAIN;
+				goto rec_return_free;
+			}
+			if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) {
+#ifdef CONFIG_APM
+				if(! in_suspend)
+#endif
+				printk(KERN_DEBUG "maestro: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+				       s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, 
+				       s->dma_adc.hwptr, s->dma_adc.swptr);
+				stop_adc(s);
+				spin_lock_irqsave(&s->lock, flags);
+				set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
+				/* program enhanced mode registers */
+				/* FILL ME */
+/*				wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8);
+				wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); */
+				s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
+				spin_unlock_irqrestore(&s->lock, flags);
+			}
+			if (signal_pending(current)) 
+			{
+				ret = ret ? ret : -ERESTARTSYS;
+				goto rec_return_free;
+			}
+			continue;
+		}
+	
+		if(s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {
+			/* swptr/2 so that we know the real offset in each apu's buffer */
+			comb_stereo(s->dma_adc.rawbuf,combbuf,swptr/2,cnt,s->dma_adc.dmasize);
+			if (copy_to_user(buffer, combbuf, cnt)) {
+				ret = ret ? ret : -EFAULT;
+				goto rec_return_free;
+			}
+		} else  {
+			if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
+				ret = ret ? ret : -EFAULT;
+				goto rec_return_free;
+			}
+		}
+
+		swptr = (swptr + cnt) % s->dma_adc.dmasize;
+		spin_lock_irqsave(&s->lock, flags);
+		s->dma_adc.swptr = swptr;
+		s->dma_adc.count -= cnt;
+		spin_unlock_irqrestore(&s->lock, flags);
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+		start_adc(s);
+	}
+
+rec_return_free:
+	if(combbuf) kfree(combbuf);
+	return ret;
+}
+
+static ssize_t 
+ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct ess_state *s = (struct ess_state *)file->private_data;
+	ssize_t ret;
+	unsigned long flags;
+	unsigned swptr;
+	int cnt;
+	
+	VALIDATE_STATE(s);
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (s->dma_dac.mapped)
+		return -ENXIO;
+	if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+		return ret;
+	if (!access_ok(VERIFY_READ, buffer, count))
+		return -EFAULT;
+	ret = 0;
+
+	calc_bob_rate(s);
+
+	while (count > 0) {
+		spin_lock_irqsave(&s->lock, flags);
+
+		if (s->dma_dac.count < 0) {
+			s->dma_dac.count = 0;
+			s->dma_dac.swptr = s->dma_dac.hwptr;
+		}
+		swptr = s->dma_dac.swptr;
+
+		cnt = s->dma_dac.dmasize-swptr;
+
+		if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
+			cnt = s->dma_dac.dmasize - s->dma_dac.count;
+
+		spin_unlock_irqrestore(&s->lock, flags);
+
+		if (cnt > count)
+			cnt = count;
+
+		if (cnt <= 0) {
+			start_dac(s);
+			if (file->f_flags & O_NONBLOCK) {
+				if(!ret) ret = -EAGAIN;
+				goto return_free;
+			}
+			if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) {
+#ifdef CONFIG_APM
+				if(! in_suspend)
+#endif
+				printk(KERN_DEBUG "maestro: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+				       s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, 
+				       s->dma_dac.hwptr, s->dma_dac.swptr);
+				stop_dac(s);
+				spin_lock_irqsave(&s->lock, flags);
+				set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
+				/* program enhanced mode registers */
+/*				wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8);
+				wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); */
+				/* FILL ME */
+				s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
+				spin_unlock_irqrestore(&s->lock, flags);
+			}
+			if (signal_pending(current)) {
+				if (!ret) ret = -ERESTARTSYS;
+				goto return_free;
+			}
+			continue;
+		}
+		if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
+			if (!ret) ret = -EFAULT;
+			goto return_free;
+		}
+
+		swptr = (swptr + cnt) % s->dma_dac.dmasize;
+
+		spin_lock_irqsave(&s->lock, flags);
+		s->dma_dac.swptr = swptr;
+		s->dma_dac.count += cnt;
+		s->dma_dac.endcleared = 0;
+		spin_unlock_irqrestore(&s->lock, flags);
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+		start_dac(s);
+	}
+return_free:
+	return ret;
+}
+
+static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct ess_state *s = (struct ess_state *)file->private_data;
+	unsigned long flags;
+	unsigned int mask = 0;
+
+	VALIDATE_STATE(s);
+	if (file->f_mode & FMODE_WRITE)
+		poll_wait(file, &s->dma_dac.wait, wait);
+	if (file->f_mode & FMODE_READ)
+		poll_wait(file, &s->dma_adc.wait, wait);
+	spin_lock_irqsave(&s->lock, flags);
+	ess_update_ptr(s);
+	if (file->f_mode & FMODE_READ) {
+		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+			mask |= POLLIN | POLLRDNORM;
+	}
+	if (file->f_mode & FMODE_WRITE) {
+		if (s->dma_dac.mapped) {
+			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) 
+				mask |= POLLOUT | POLLWRNORM;
+		} else {
+			if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
+				mask |= POLLOUT | POLLWRNORM;
+		}
+	}
+	spin_unlock_irqrestore(&s->lock, flags);
+	return mask;
+}
+
+static int ess_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct ess_state *s = (struct ess_state *)file->private_data;
+	struct dmabuf *db;
+	int ret;
+	unsigned long size;
+
+	VALIDATE_STATE(s);
+	if (vma->vm_flags & VM_WRITE) {
+		if ((ret = prog_dmabuf(s, 1)) != 0)
+			return ret;
+		db = &s->dma_dac;
+	} else 
+#if 0
+	/* if we can have the wp/wc do the combining
+		we can turn this back on.  */
+	      if (vma->vm_flags & VM_READ) {
+		if ((ret = prog_dmabuf(s, 0)) != 0)
+			return ret;
+		db = &s->dma_adc;
+	} else  
+#endif
+		return -EINVAL;
+	if (vma->vm_offset != 0)
+		return -EINVAL;
+	size = vma->vm_end - vma->vm_start;
+	if (size > (PAGE_SIZE << db->buforder))
+		return -EINVAL;
+	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+		return -EAGAIN;
+	db->mapped = 1;
+	return 0;
+}
+
+static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct ess_state *s = (struct ess_state *)file->private_data;
+	unsigned long flags;
+        audio_buf_info abinfo;
+        count_info cinfo;
+	int val, mapped, ret;
+	unsigned char fmtm, fmtd;
+
+/*	printk("maestro: ess_ioctl: cmd %d\n", cmd);*/
+	
+	VALIDATE_STATE(s);
+        mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+		((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+	switch (cmd) {
+	case OSS_GETVERSION:
+		return put_user(SOUND_VERSION, (int *)arg);
+
+	case SNDCTL_DSP_SYNC:
+		if (file->f_mode & FMODE_WRITE)
+			return drain_dac(s, file->f_flags & O_NONBLOCK);
+		return 0;
+		
+	case SNDCTL_DSP_SETDUPLEX:
+		/* XXX fix */
+		return 0;
+
+	case SNDCTL_DSP_GETCAPS:
+		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
+		
+        case SNDCTL_DSP_RESET:
+		if (file->f_mode & FMODE_WRITE) {
+			stop_dac(s);
+			synchronize_irq();
+			s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
+		}
+		if (file->f_mode & FMODE_READ) {
+			stop_adc(s);
+			synchronize_irq();
+			s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
+		}
+		return 0;
+
+        case SNDCTL_DSP_SPEED:
+                get_user_ret(val, (int *)arg, -EFAULT);
+		if (val >= 0) {
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(s);
+				s->dma_adc.ready = 0;
+				set_adc_rate(s, val);
+			}
+			if (file->f_mode & FMODE_WRITE) {
+				stop_dac(s);
+				s->dma_dac.ready = 0;
+				set_dac_rate(s, val);
+			}
+		}
+		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
+		
+        case SNDCTL_DSP_STEREO:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		fmtd = 0;
+		fmtm = ~0;
+		if (file->f_mode & FMODE_READ) {
+			stop_adc(s);
+			s->dma_adc.ready = 0;
+			if (val)
+				fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
+			else
+				fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			stop_dac(s);
+			s->dma_dac.ready = 0;
+			if (val)
+				fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
+			else
+				fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
+		}
+		set_fmt(s, fmtm, fmtd);
+		return 0;
+
+        case SNDCTL_DSP_CHANNELS:
+                get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != 0) {
+			fmtd = 0;
+			fmtm = ~0;
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(s);
+				s->dma_adc.ready = 0;
+				if (val >= 2)
+					fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
+				else
+					fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
+			}
+			if (file->f_mode & FMODE_WRITE) {
+				stop_dac(s);
+				s->dma_dac.ready = 0;
+				if (val >= 2)
+					fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
+				else
+					fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
+			}
+			set_fmt(s, fmtm, fmtd);
+		}
+		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) 
+					   : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+		
+	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+                return put_user(AFMT_U8|AFMT_S16_LE, (int *)arg);
+		
+	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != AFMT_QUERY) {
+			fmtd = 0;
+			fmtm = ~0;
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(s);
+				s->dma_adc.ready = 0;
+	/* fixed at 16bit for now */
+				fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
+#if 0
+				if (val == AFMT_S16_LE)
+					fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
+				else
+					fmtm &= ~(ESS_FMT_16BIT << ESS_ADC_SHIFT);
+#endif
+			}
+			if (file->f_mode & FMODE_WRITE) {
+				stop_dac(s);
+				s->dma_dac.ready = 0;
+				if (val == AFMT_S16_LE)
+					fmtd |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
+				else
+					fmtm &= ~(ESS_FMT_16BIT << ESS_DAC_SHIFT);
+			}
+			set_fmt(s, fmtm, fmtd);
+		}
+ 		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? 
+			(ESS_FMT_16BIT << ESS_ADC_SHIFT) 
+			: (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 
+				AFMT_S16_LE : 
+				AFMT_U8, 
+			(int *)arg);
+		
+	case SNDCTL_DSP_POST:
+                return 0;
+
+        case SNDCTL_DSP_GETTRIGGER:
+		val = 0;
+		if ((file->f_mode & FMODE_READ) && (s->enable & ADC_RUNNING))
+			val |= PCM_ENABLE_INPUT;
+		if ((file->f_mode & FMODE_WRITE) && (s->enable & DAC_RUNNING)) 
+			val |= PCM_ENABLE_OUTPUT;
+		return put_user(val, (int *)arg);
+		
+	case SNDCTL_DSP_SETTRIGGER:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (file->f_mode & FMODE_READ) {
+			if (val & PCM_ENABLE_INPUT) {
+				if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
+					return ret;
+				start_adc(s);
+			} else
+				stop_adc(s);
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			if (val & PCM_ENABLE_OUTPUT) {
+				if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+					return ret;
+				start_dac(s);
+			} else
+				stop_dac(s);
+		}
+		return 0;
+
+	case SNDCTL_DSP_GETOSPACE:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		if (!(s->enable & DAC_RUNNING) && (val = prog_dmabuf(s, 0)) != 0)
+			return val;
+		spin_lock_irqsave(&s->lock, flags);
+		ess_update_ptr(s);
+		abinfo.fragsize = s->dma_dac.fragsize;
+                abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
+                abinfo.fragstotal = s->dma_dac.numfrag;
+                abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;      
+		spin_unlock_irqrestore(&s->lock, flags);
+		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+	case SNDCTL_DSP_GETISPACE:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		if (!(s->enable & ADC_RUNNING) && (val = prog_dmabuf(s, 1)) != 0)
+			return val;
+		spin_lock_irqsave(&s->lock, flags);
+		ess_update_ptr(s);
+		abinfo.fragsize = s->dma_adc.fragsize;
+                abinfo.bytes = s->dma_adc.count;
+                abinfo.fragstotal = s->dma_adc.numfrag;
+                abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;      
+		spin_unlock_irqrestore(&s->lock, flags);
+		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+		
+        case SNDCTL_DSP_NONBLOCK:
+                file->f_flags |= O_NONBLOCK;
+                return 0;
+
+        case SNDCTL_DSP_GETODELAY:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		spin_lock_irqsave(&s->lock, flags);
+		ess_update_ptr(s);
+                val = s->dma_dac.count;
+		spin_unlock_irqrestore(&s->lock, flags);
+		return put_user(val, (int *)arg);
+
+        case SNDCTL_DSP_GETIPTR:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		spin_lock_irqsave(&s->lock, flags);
+		ess_update_ptr(s);
+                cinfo.bytes = s->dma_adc.total_bytes;
+                cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+                cinfo.ptr = s->dma_adc.hwptr;
+		if (s->dma_adc.mapped)
+			s->dma_adc.count &= s->dma_adc.fragsize-1;
+		spin_unlock_irqrestore(&s->lock, flags);
+                return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+        case SNDCTL_DSP_GETOPTR:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		spin_lock_irqsave(&s->lock, flags);
+		ess_update_ptr(s);
+                cinfo.bytes = s->dma_dac.total_bytes;
+                cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+                cinfo.ptr = s->dma_dac.hwptr;
+		if (s->dma_dac.mapped)
+			s->dma_dac.count &= s->dma_dac.fragsize-1;
+		spin_unlock_irqrestore(&s->lock, flags);
+                return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+        case SNDCTL_DSP_GETBLKSIZE:
+		if (file->f_mode & FMODE_WRITE) {
+			if ((val = prog_dmabuf(s, 0)))
+				return val;
+			return put_user(s->dma_dac.fragsize, (int *)arg);
+		}
+		if ((val = prog_dmabuf(s, 1)))
+			return val;
+		return put_user(s->dma_adc.fragsize, (int *)arg);
+
+        case SNDCTL_DSP_SETFRAGMENT:
+                get_user_ret(val, (int *)arg, -EFAULT);
+		if (file->f_mode & FMODE_READ) {
+			s->dma_adc.ossfragshift = val & 0xffff;
+			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+			if (s->dma_adc.ossfragshift < 4)
+				s->dma_adc.ossfragshift = 4;
+			if (s->dma_adc.ossfragshift > 15)
+				s->dma_adc.ossfragshift = 15;
+			if (s->dma_adc.ossmaxfrags < 4)
+				s->dma_adc.ossmaxfrags = 4;
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			s->dma_dac.ossfragshift = val & 0xffff;
+			s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+			if (s->dma_dac.ossfragshift < 4)
+				s->dma_dac.ossfragshift = 4;
+			if (s->dma_dac.ossfragshift > 15)
+				s->dma_dac.ossfragshift = 15;
+			if (s->dma_dac.ossmaxfrags < 4)
+				s->dma_dac.ossmaxfrags = 4;
+		}
+		return 0;
+
+        case SNDCTL_DSP_SUBDIVIDE:
+		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+		    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+			return -EINVAL;
+                get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != 1 && val != 2 && val != 4)
+			return -EINVAL;
+		if (file->f_mode & FMODE_READ)
+			s->dma_adc.subdivision = val;
+		if (file->f_mode & FMODE_WRITE)
+			s->dma_dac.subdivision = val;
+		return 0;
+
+        case SOUND_PCM_READ_RATE:
+		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
+
+        case SOUND_PCM_READ_CHANNELS:
+		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) 
+					   : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+
+        case SOUND_PCM_READ_BITS:
+		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT) 
+					   : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 16 : 8, (int *)arg);
+
+        case SOUND_PCM_WRITE_FILTER:
+        case SNDCTL_DSP_SETSYNCRO:
+        case SOUND_PCM_READ_FILTER:
+                return -EINVAL;
+		
+	}
+	return -EINVAL;
+}
+
+static void
+set_base_registers(struct ess_state *s,void *vaddr)
+{
+	unsigned long packed_phys = virt_to_bus(vaddr)>>12;
+	wave_set_register(s, 0x01FC , packed_phys);
+	wave_set_register(s, 0x01FD , packed_phys);
+	wave_set_register(s, 0x01FE , packed_phys);
+	wave_set_register(s, 0x01FF , packed_phys);
+}
+
+/* we allocate a large power of two for all our memory.
+	this is cut up into (not to scale :):
+	|silly fifo word	| 512byte mixbuf per adc	| dac/adc * channels |
+*/
+static int
+allocate_buffers(struct ess_state *s)
+{
+	void *rawbuf=NULL;
+	int order,i;
+	unsigned long mapend,map;
+
+	/* alloc as big a chunk as we can */
+	for (order = (dsps_order + (15-PAGE_SHIFT) + 1); order >= (dsps_order + 2 + 1); order--)
+		if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
+			break;
+
+	if (!rawbuf)
+		return 1;
+
+	M_printk("maestro: allocated %ld (%d) bytes at %p\n",PAGE_SIZE<<order,order, rawbuf);
+
+	if ((virt_to_bus(rawbuf) + (PAGE_SIZE << order) - 1) & ~((1<<28)-1))  {
+		printk(KERN_ERR "maestro: DMA buffer beyond 256MB! busaddr 0x%lx  size %ld\n",
+			virt_to_bus(rawbuf), PAGE_SIZE << order);
+		kfree(rawbuf);
+		return 1;
+	}
+
+	s->card->dmapages = rawbuf;
+	s->card->dmaorder = order;
+
+	/* play bufs are in the same first region as record bufs */
+	set_base_registers(s,rawbuf);
+
+	M_printk("maestro: writing %lx (%lx) to the wp\n",virt_to_bus(rawbuf),
+		((virt_to_bus(rawbuf))&0xFFE00000)>>12);
+
+	for(i=0;i<NR_DSPS;i++) {
+		struct ess_state *ess = &s->card->channels[i];
+
+		if(ess->dev_audio == -1)
+			continue;
+
+		ess->dma_dac.ready = s->dma_dac.mapped = 0;
+		ess->dma_adc.ready = s->dma_adc.mapped = 0;
+		ess->dma_adc.buforder = ess->dma_dac.buforder = order - 1 - dsps_order - 1;
+
+		/* offset dac and adc buffers starting half way through and then at each [da][ad]c's
+			order's intervals.. */
+		ess->dma_dac.rawbuf = rawbuf + (PAGE_SIZE<<(order-1)) + (i * ( PAGE_SIZE << (ess->dma_dac.buforder + 1 )));
+		ess->dma_adc.rawbuf = ess->dma_dac.rawbuf + ( PAGE_SIZE << ess->dma_dac.buforder);
+		/* offset mixbuf by a mixbuf so that the lame status fifo can
+			happily scribble away.. */ 
+		ess->mixbuf = rawbuf + (512 * (i+1));
+
+		M_printk("maestro: setup apu %d: %p %p %p\n",i,ess->dma_dac.rawbuf,
+			ess->dma_adc.rawbuf, ess->mixbuf);
+
+	}
+
+	/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+	mapend = MAP_NR(rawbuf + (PAGE_SIZE << order) - 1);
+	for (map = MAP_NR(rawbuf); map <= mapend; map++) {
+		set_bit(PG_reserved, &mem_map[map].flags);
+	}
+
+	return 0;
+} 
+static void
+free_buffers(struct ess_state *s)
+{
+	unsigned long map, mapend;
+
+	s->dma_dac.rawbuf = s->dma_adc.rawbuf = NULL;
+	s->dma_dac.mapped = s->dma_adc.mapped = 0;
+	s->dma_dac.ready = s->dma_adc.ready = 0;
+
+	M_printk("maestro: freeing %p\n",s->card->dmapages);
+	/* undo marking the pages as reserved */
+
+	mapend = MAP_NR(s->card->dmapages + (PAGE_SIZE << s->card->dmaorder) - 1);
+	for (map = MAP_NR(s->card->dmapages); map <= mapend; map++)
+		clear_bit(PG_reserved, &mem_map[map].flags);    
+
+	free_pages((unsigned long)s->card->dmapages,s->card->dmaorder);
+	s->card->dmapages = NULL;
+}
+
+static int 
+ess_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct ess_card *c = devs;
+	struct ess_state *s = NULL, *sp;
+	int i;
+	unsigned char fmtm = ~0, fmts = 0;
+
+	/*
+	 *	Scan the cards and find the channel. We only
+	 *	do this at open time so it is ok
+	 */
+	 
+	while (c!=NULL)
+	{
+		for(i=0;i<NR_DSPS;i++)
+		{
+			sp=&c->channels[i];
+			if(sp->dev_audio < 0)
+				continue;
+			if((sp->dev_audio ^ minor) & ~0xf)
+				continue;
+			s=sp;
+		}
+		c=c->next;
+	}
+		
+	if (!s)
+		return -ENODEV;
+		
+       	VALIDATE_STATE(s);
+	file->private_data = s;
+	/* wait for device to become free */
+	down(&s->open_sem);
+	while (s->open_mode & file->f_mode) {
+		if (file->f_flags & O_NONBLOCK) {
+			up(&s->open_sem);
+			return -EWOULDBLOCK;
+		}
+		up(&s->open_sem);
+		interruptible_sleep_on(&s->open_wait);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+		down(&s->open_sem);
+	}
+
+	/* under semaphore.. */
+	if ((s->card->dmapages==NULL) && allocate_buffers(s)) {
+		up(&s->open_sem);
+		return -ENOMEM;
+	}
+
+	if (file->f_mode & FMODE_READ) {
+/*
+		fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT);
+		if ((minor & 0xf) == SND_DEV_DSP16)
+			fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT; */
+
+		fmtm &= ~((ESS_FMT_STEREO|ESS_FMT_16BIT) << ESS_ADC_SHIFT);
+		fmts = (ESS_FMT_STEREO|ESS_FMT_16BIT) << ESS_ADC_SHIFT;
+
+		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+		set_adc_rate(s, 8000);
+	}
+	if (file->f_mode & FMODE_WRITE) {
+		fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT);
+		if ((minor & 0xf) == SND_DEV_DSP16)
+			fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
+
+		s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
+		set_dac_rate(s, 8000);
+	}
+	set_fmt(s, fmtm, fmts);
+	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+
+	/* we're covered by the open_sem */
+	if( ! s->card->dsps_open )  {
+		start_bob(s);
+	}
+	s->card->dsps_open++;
+	M_printk("maestro: open, %d bobs now\n",s->card->dsps_open);
+
+	up(&s->open_sem);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int 
+ess_release(struct inode *inode, struct file *file)
+{
+	struct ess_state *s = (struct ess_state *)file->private_data;
+
+	VALIDATE_STATE(s);
+	if (file->f_mode & FMODE_WRITE)
+		drain_dac(s, file->f_flags & O_NONBLOCK);
+	down(&s->open_sem);
+	if (file->f_mode & FMODE_WRITE) {
+		stop_dac(s);
+	}
+	if (file->f_mode & FMODE_READ) {
+		stop_adc(s);
+	}
+		
+	s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+	/* we're covered by the open_sem */
+	M_printk("maestro: %d dsps now alive\n",s->card->dsps_open-1);
+	if( --s->card->dsps_open <= 0) {
+		stop_bob(s);
+		free_buffers(s);
+	}
+	up(&s->open_sem);
+	wake_up(&s->open_wait);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static struct file_operations ess_audio_fops = {
+	&ess_llseek,
+	&ess_read,
+	&ess_write,
+	NULL,  /* readdir */
+	&ess_poll,
+	&ess_ioctl,
+	&ess_mmap,
+	&ess_open,
+	NULL,	/* flush */
+	&ess_release,
+	NULL,  /* fsync */
+	NULL,  /* fasync */
+	NULL,  /* check_media_change */
+	NULL,  /* revalidate */
+	NULL,  /* lock */
+};
+
+static int
+maestro_config(struct ess_card *card) 
+{
+	struct pci_dev *pcidev = &card->pcidev;
+	struct ess_state *ess = &card->channels[0];
+	int apu,iobase  = card->iobase;
+	u16 w;
+	u32 n;
+
+	/*
+	 *	Disable ACPI
+	 */
+	 
+	pci_write_config_dword(pcidev, 0x54, 0x00000000);
+	pci_write_config_dword(pcidev, 0x56, 0x00000000);
+	
+	/*
+	 *	Use TDMA for now. TDMA works on all boards, so while its
+	 *	not the most efficient its the simplest.
+	 */ 
+	 
+	pci_read_config_word(pcidev, 0x50, &w);
+
+	/* Clear DMA bits */
+	w&=~(1<<10|1<<9|1<<8);
+
+	/* TDMA on */
+	w|= (1<<8);
+
+	/*
+	 *	Some of these are undocumented bits
+	 */
+	 
+	w&=~(1<<13)|(1<<14);		/* PIC Snoop mode bits */
+	w&=~(1<<11);			/* Safeguard off */
+	w|= (1<<7);			/* Posted write */
+	w|= (1<<6);			/* ISA timing on */
+	/* XXX huh?  claims to be reserved.. */
+	w&=~(1<<5);			/* Don't swap left/right */
+	w&=~(1<<1);			/* Subtractive decode off */
+	
+	pci_write_config_word(pcidev, 0x50, w);
+	
+	pci_read_config_word(pcidev, 0x52, &w);
+	w&=~(1<<15);		/* Turn off internal clock multiplier */
+	/* XXX how do we know which to use? */
+	w&=~(1<<14);		/* External clock */
+	
+	w&=~(1<<7);		/* HWV off */
+	w&=~(1<<6);		/* Debounce off */
+	w&=~(1<<5);		/* GPIO 4:5 */
+	w|= (1<<4);             /* Disconnect from the CHI.  Enabling this made a dell 7500 work. */
+	w&=~(1<<3);		/* IDMA off (undocumented) */
+	w&=~(1<<2);		/* MIDI fix off (undoc) */
+	w&=~(1<<1);		/* reserved, always write 0 */
+	w&=~(1<<0);		/* IRQ to ISA off (undoc) */
+	pci_write_config_word(pcidev, 0x52, w);
+
+	/*
+	 *	DDMA off
+	 */
+
+	pci_read_config_word(pcidev, 0x60, &w);
+	w&=~(1<<0);
+	pci_write_config_word(pcidev, 0x60, w);
+	
+	/*
+	 *	Legacy mode
+	 */
+
+	pci_read_config_word(pcidev, 0x40, &w);
+	w|=(1<<15);	/* legacy decode off */
+	w&=~(1<<14);	/* Disable SIRQ */
+	w&=~(0x1f);	/* disable mpu irq/io, game port, fm, SB */
+	 
+	pci_write_config_word(pcidev, 0x40, w);
+
+	/* stake our claim on the iospace */
+	request_region(iobase, 256, card_names[card->card_type]);
+	
+	sound_reset(iobase);
+
+	/*
+	 *	Ring Bus Setup
+	 */
+
+	/* setup usual 0x34 stuff.. 0x36 may be chip specific */
+        outw(0xC090, iobase+0x34); /* direct sound, stereo */
+        udelay(20);
+        outw(0x3000, iobase+0x36); /* direct sound, stereo */
+        udelay(20);
+
+
+	/*
+	 *	Reset the CODEC
+	 */
+	 
+	maestro_ac97_reset(iobase,pcidev);
+	
+	/*
+	 *	Ring Bus Setup
+	 */
+	 	 
+	n=inl(iobase+0x34);
+	n&=~0xF000;
+	n|=12<<12;		/* Direct Sound, Stereo */
+	outl(n, iobase+0x34);
+
+	n=inl(iobase+0x34);
+	n&=~0x0F00;		/* Modem off */
+	outl(n, iobase+0x34);
+
+	n=inl(iobase+0x34);
+	n&=~0x00F0;
+	n|=9<<4;		/* DAC, Stereo */
+	outl(n, iobase+0x34);
+	
+	n=inl(iobase+0x34);
+	n&=~0x000F;		/* ASSP off */
+	outl(n, iobase+0x34);
+	
+	n=inl(iobase+0x34);
+	n|=(1<<29);		/* Enable ring bus */
+	outl(n, iobase+0x34);
+	
+	n=inl(iobase+0x34);
+	n|=(1<<28);		/* Enable serial bus */
+	outl(n, iobase+0x34);
+	
+	n=inl(iobase+0x34);
+	n&=~0x00F00000;		/* MIC off */
+	outl(n, iobase+0x34);
+	
+	n=inl(iobase+0x34);
+	n&=~0x000F0000;		/* I2S off */
+	outl(n, iobase+0x34);
+	
+
+	w=inw(iobase+0x18);
+	w&=~(1<<7);		/* ClkRun off */
+	outw(w, iobase+0x18);
+
+	w=inw(iobase+0x18);
+	w&=~(1<<6);		/* Harpo off */
+	outw(w, iobase+0x18);
+	
+	w=inw(iobase+0x18);
+	w&=~(1<<4);		/* ASSP irq off */
+	outw(w, iobase+0x18);
+	
+	w=inw(iobase+0x18);
+	w&=~(1<<3);		/* ISDN irq off */
+	outw(w, iobase+0x18);
+	
+	w=inw(iobase+0x18);
+	w|=(1<<2);		/* Direct Sound IRQ on */
+	outw(w, iobase+0x18);
+
+	w=inw(iobase+0x18);
+	w&=~(1<<1);		/* MPU401 IRQ off */
+	outw(w, iobase+0x18);
+
+	w=inw(iobase+0x18);
+	w|=(1<<0);		/* SB IRQ on */
+	outw(w, iobase+0x18);
+
+	/* it appears some maestros (dell 7500) only work if these are set,
+		regardless of wether we use the assp or not. */
+
+	outb(0, iobase+0xA4); 
+	outb(3, iobase+0xA2); 
+	outb(0, iobase+0xA6);
+	
+	for(apu=0;apu<16;apu++)
+	{
+		/* Write 0 into the buffer area 0x1E0->1EF */
+		outw(0x01E0+apu, 0x10+iobase);
+		outw(0x0000, 0x12+iobase);
+	
+		/*
+		 * The 1.10 test program seem to write 0 into the buffer area
+		 * 0x1D0-0x1DF too.
+		 */
+		outw(0x01D0+apu, 0x10+iobase);
+		outw(0x0000, 0x12+iobase);
+	}
+
+#if 1
+	wave_set_register(ess, IDR7_WAVE_ROMRAM, 
+		(wave_get_register(ess, IDR7_WAVE_ROMRAM)&0xFF00));
+	wave_set_register(ess, IDR7_WAVE_ROMRAM,
+		wave_get_register(ess, IDR7_WAVE_ROMRAM)|0x100);
+	wave_set_register(ess, IDR7_WAVE_ROMRAM,
+		wave_get_register(ess, IDR7_WAVE_ROMRAM)&~0x200);
+	wave_set_register(ess, IDR7_WAVE_ROMRAM,
+		wave_get_register(ess, IDR7_WAVE_ROMRAM)|~0x400);
+#else		
+	maestro_write(ess, IDR7_WAVE_ROMRAM, 
+		(maestro_read(ess, IDR7_WAVE_ROMRAM)&0xFF00));
+	maestro_write(ess, IDR7_WAVE_ROMRAM,
+		maestro_read(ess, IDR7_WAVE_ROMRAM)|0x100);
+	maestro_write(ess, IDR7_WAVE_ROMRAM,
+		maestro_read(ess, IDR7_WAVE_ROMRAM)&~0x200);
+	maestro_write(ess, IDR7_WAVE_ROMRAM,
+		maestro_read(ess, IDR7_WAVE_ROMRAM)|0x400);
+#endif
+	
+	maestro_write(ess, IDR2_CRAM_DATA, 0x0000);
+	maestro_write(ess, 0x08, 0xB004);
+	/* Now back to the DirectSound stuff */
+	maestro_write(ess, 0x09, 0x001B);
+	maestro_write(ess, 0x0A, 0x8000);
+	maestro_write(ess, 0x0B, 0x3F37);
+	maestro_write(ess, 0x0C, 0x0098);
+	
+	/* parallel out ?? */
+	maestro_write(ess, 0x0C, 
+		(maestro_read(ess, 0x0C)&~0xF000)|0x8000); 
+	/* parallel in, has something to do with recording :) */
+	maestro_write(ess, 0x0C, 
+		(maestro_read(ess, 0x0C)&~0x0F00)|0x0500);
+
+	maestro_write(ess, 0x0D, 0x7632);
+			
+	/* Wave cache control on - test off, sg off, 
+		enable, enable extra chans 1Mb */
+
+	outw(inw(0x14+iobase)|(1<<8),0x14+iobase);
+	outw(inw(0x14+iobase)&0xFE03,0x14+iobase);
+	outw((inw(0x14+iobase)&0xFFFC), 0x14+iobase);
+	outw(inw(0x14+iobase)|(1<<7),0x14+iobase);
+
+	outw(0xA1A0, 0x14+iobase);      /* 0300 ? */
+
+	/* Now clear the APU control ram */	
+	for(apu=0;apu<NR_APUS;apu++)
+	{
+		for(w=0;w<NR_APU_REGS;w++)
+			apu_set_register(ess, apu|ESS_CHAN_HARD, w, 0);
+		
+	}
+
+	return 0;
+	
+}
+
+
+static int 
+maestro_install(struct pci_dev *pcidev, int card_type)
+{
+	u32 n;
+	int iobase;
+	int i;
+	struct ess_card *card;
+	struct ess_state *ess;
+	int num = 0;
+
+	/* don't pick up weird modem maestros */
+	if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO)
+		return 0;
+			
+	iobase = SILLY_PCI_BASE_ADDRESS(pcidev); 
+
+	if(check_region(iobase, 256))
+	{
+		printk(KERN_WARNING "maestro: can't allocate 256 bytes I/O at 0x%4.4x\n", iobase);
+		return 0;
+	}
+
+	/* this was tripping up some machines */
+	if(pcidev->irq == 0) 
+	{
+		printk(KERN_WARNING "maestro: pci subsystem reports irq 0, this might not be correct.\n");
+	}
+
+	/* just to be sure */
+	pci_set_master(pcidev);
+
+	card = kmalloc(sizeof(struct ess_card), GFP_KERNEL);
+	if(card == NULL)
+	{
+		printk(KERN_WARNING "maestro: out of memory\n");
+		return 0;
+	}
+	
+	memset(card, 0, sizeof(*card));
+	memcpy(&card->pcidev,pcidev,sizeof(card->pcidev));
+
+#ifdef CONFIG_APM
+	if (apm_register_callback(maestro_apm_callback)) {
+		printk(KERN_WARNING "maestro: apm suspend might not work.\n");
+	}
+#endif
+
+	card->iobase = iobase;
+	card->card_type = card_type;
+	card->irq = pcidev->irq;
+	card->next = devs;
+	card->magic = ESS_CARD_MAGIC;
+	spin_lock_init(&card->lock);
+	devs = card;
+	
+	/* init our groups of 6 apus */
+	for(i=0;i<NR_DSPS;i++)
+	{
+		struct ess_state *s=&card->channels[i];
+
+		s->index = i;
+
+		s->card = card;
+		init_waitqueue_head(&s->dma_adc.wait);
+		init_waitqueue_head(&s->dma_dac.wait);
+		init_waitqueue_head(&s->open_wait);
+		spin_lock_init(&s->lock);
+		SILLY_INIT_SEM(s->open_sem);
+		s->magic = ESS_STATE_MAGIC;
+		
+		s->apu[0] = 6*i;
+		s->apu[1] = (6*i)+1;
+		s->apu[2] = (6*i)+2;
+		s->apu[3] = (6*i)+3;
+		s->apu[4] = (6*i)+4;
+		s->apu[5] = (6*i)+5;
+		
+		if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf)
+			printk("maestro: BOTCH!\n");
+		/* register devices */
+		if ((s->dev_audio = register_sound_dsp(&ess_audio_fops, -1)) < 0)
+			break;
+	}
+	
+	num = i;
+	
+	/* clear the rest if we ran out of slots to register */
+	for(;i<NR_DSPS;i++)
+	{
+		struct ess_state *s=&card->channels[i];
+		s->dev_audio = -1;
+	}
+	
+	ess = &card->channels[0];
+
+	/*
+	 *	Ok card ready. Begin setup proper
+	 */
+
+	printk(KERN_INFO "maestro: Configuring %s found at IO 0x%04X IRQ %d\n", 
+		card_names[card_type],iobase,card->irq);
+	pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &n);
+	printk(KERN_INFO "maestro:  subvendor id: 0x%08x\n",n); 
+
+	maestro_config(card);
+
+	if(maestro_ac97_get(iobase, 0x00)==0x0080) {
+		printk(KERN_ERR "maestro: my goodness!  you seem to have a pt101 codec, which is quite rare.\n"
+				"\tyou should tell someone about this.\n");
+	} else {
+		maestro_ac97_init(card,iobase);
+	}
+
+	if ((card->dev_mixer = register_sound_mixer(&ess_mixer_fops, -1)) < 0) {
+		printk("maestro: couldn't register mixer!\n");
+	} else {
+		memcpy(card->mix.mixer_state,mixer_defaults,sizeof(card->mix.mixer_state));
+		mixer_push_state(card);
+	}
+	
+	if(request_irq(card->irq, ess_interrupt, SA_SHIRQ, card_names[card_type], card))
+	{
+		printk(KERN_ERR "maestro: unable to allocate irq %d,\n", card->irq);
+		unregister_sound_mixer(card->dev_mixer);
+		for(i=0;i<NR_DSPS;i++)
+		{
+			struct ess_state *s = &card->channels[i];
+			if(s->dev_audio != -1)
+				unregister_sound_dsp(s->dev_audio);
+		}
+		release_region(card->iobase, 256);		
+		kfree(card);
+		return 0;
+	}
+
+	printk(KERN_INFO "maestro: %d channels configured.\n", num);
+	return 1; 
+}
+
+#ifdef MODULE
+int init_module(void)
+#else
+int SILLY_MAKE_INIT(init_maestro(void))
+#endif
+{
+	struct pci_dev *pcidev = NULL;
+	int foundone = 0;
+
+	if (!pci_present())   /* No PCI bus in this machine! */
+		return -ENODEV;
+	printk(KERN_INFO "maestro: version " DRIVER_VERSION " time " __TIME__ " " __DATE__ "\n");
+
+	pcidev = NULL;
+
+	if (dsps_order < 0)   {
+		dsps_order = 1;
+		printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order);
+	}
+	else if (dsps_order > MAX_DSP_ORDER)  {
+		dsps_order = MAX_DSP_ORDER;
+		printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order);
+	}
+
+#ifdef CONFIG_APM
+	init_waitqueue_head(&suspend_queue);
+#endif
+
+	/*
+	 *	Find the ESS Maestro 2.
+	 */
+
+	while( (pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, pcidev))!=NULL ) {
+		if (maestro_install(pcidev, TYPE_MAESTRO2))
+			foundone=1;
+	}
+
+	/*
+	 *	Find the ESS Maestro 2E
+	 */
+
+	while( (pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, pcidev))!=NULL) {
+		if (maestro_install(pcidev, TYPE_MAESTRO2E))
+			foundone=1;
+	}
+
+	/*
+	 *	ESS Maestro 1
+	 */
+
+	while((pcidev = pci_find_device(PCI_VENDOR_ESS_OLD, PCI_DEVICE_ID_ESS_ESS0100, pcidev))!=NULL) {
+		if (maestro_install(pcidev, TYPE_MAESTRO))
+			foundone=1;
+	}
+	if( ! foundone ) {
+		printk("maestro: no devices found.\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+#ifdef MODULE
+MODULE_AUTHOR("Zach Brown <zab@redhat.com>, Alan Cox <alan@redhat.com>");
+MODULE_DESCRIPTION("ESS Maestro Driver");
+#ifdef M_DEBUG
+MODULE_PARM(debug,"i");
+#endif
+MODULE_PARM(dsps_order,"i");
+
+void cleanup_module(void)
+{
+	struct ess_card *s;
+
+#ifdef CONFIG_APM
+	apm_unregister_callback(maestro_apm_callback);
+#endif
+	while ((s = devs)) {
+		int i;
+		devs = devs->next;
+	
+		/* XXX maybe should force stop bob, but should be all 
+			stopped by _release by now */
+		free_irq(s->irq, s);
+		unregister_sound_mixer(s->dev_mixer);
+		for(i=0;i<NR_DSPS;i++)
+		{
+			struct ess_state *ess = &s->channels[i];
+			if(ess->dev_audio != -1)
+				unregister_sound_dsp(ess->dev_audio);
+		}
+		release_region(s->iobase, 256);
+		kfree(s);
+	}
+	M_printk("maestro: unloading\n");
+}
+
+#endif /* MODULE */
+#ifdef CONFIG_APM
+
+void
+check_suspend(void)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	if(!in_suspend) return;
+
+	in_suspend++;
+	add_wait_queue(&suspend_queue, &wait);
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule();
+	remove_wait_queue(&suspend_queue, &wait);
+	current->state = TASK_RUNNING;
+}
+
+static int 
+maestro_suspend(void)
+{
+	struct ess_card *card;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	for (card = devs; card ; card = card->next) {
+		int i,j;
+
+		M_printk("maestro: apm in dev %p\n",card);
+
+		for(i=0;i<NR_DSPS;i++) {
+			struct ess_state *s = &card->channels[i];
+
+			if(s->dev_audio == -1)
+				continue;
+
+			M_printk("maestro: stopping apus for device %d\n",i);
+			stop_dac(s);
+			stop_adc(s);
+			for(j=0;j<6;j++) 
+				card->apu_map[s->apu[j]][5]=apu_get_register(s,j,5);
+
+		}
+
+		/* get rid of interrupts? */
+		if( card->dsps_open > 0)
+			stop_bob(&card->channels[0]);
+	}
+	in_suspend=1;
+
+	restore_flags(flags);
+
+	/* we'll let the bios do the rest of the power down.. */
+
+	return 0;
+}
+static int 
+maestro_resume(void)
+{
+	struct ess_card *card;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	in_suspend=0;
+	M_printk("maestro: resuming\n");
+
+	/* first lets just bring everything back. .*/
+	for (card = devs; card ; card = card->next) {
+		int i;
+
+		M_printk("maestro: apm in dev %p\n",card);
+
+		maestro_config(card);
+		/* need to restore the base pointers.. */ 
+		if(card->dmapages) 
+			set_base_registers(&card->channels[0],card->dmapages);
+
+		mixer_push_state(card);
+
+		for(i=0;i<NR_DSPS;i++) {
+			struct ess_state *s = &card->channels[i];
+			int chan,reg;
+
+			if(s->dev_audio == -1)
+				continue;
+
+			for(chan = 0 ; chan < 6 ; chan++) {
+				wave_set_register(s,s->apu[chan]<<3,s->apu_base[chan]);
+				for(reg = 1 ; reg < NR_APU_REGS ; reg++)  
+					apu_set_register(s,chan,reg,s->card->apu_map[s->apu[chan]][reg]);
+			}
+			for(chan = 0 ; chan < 6 ; chan++)  
+				apu_set_register(s,chan,0,s->card->apu_map[s->apu[chan]][0] & 0xFF0F);
+		}
+	}
+
+	/* now we flip on the music */
+	for (card = devs; card ; card = card->next) {
+		int i;
+
+		M_printk("maestro: apm in dev %p\n",card);
+
+		for(i=0;i<NR_DSPS;i++) {
+			struct ess_state *s = &card->channels[i];
+
+			/* these use the apu_mode, and can handle
+				spurious calls */
+			start_dac(s);	
+			start_adc(s);	
+		}
+		if( card->dsps_open > 0)
+			start_bob(&card->channels[0]);
+	}
+
+	restore_flags(flags);
+
+	wake_up(&suspend_queue);
+
+	return 0;
+}
+
+int 
+maestro_apm_callback(apm_event_t ae) {
+
+	M_printk("maestro: apm event received: 0x%x\n",ae);
+
+	switch(ae) {
+	case APM_SYS_SUSPEND: 
+	case APM_CRITICAL_SUSPEND: 
+	case APM_USER_SUSPEND: 
+		maestro_suspend();break;
+	case APM_NORMAL_RESUME: 
+	case APM_CRITICAL_RESUME: 
+	case APM_STANDBY_RESUME: 
+		maestro_resume();break;
+	default: break;
+	}
+
+	return 0;
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/maestro.h linux.14p16/drivers/sound/maestro.h
--- linux.vanilla/drivers/sound/maestro.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/sound/maestro.h	Thu Dec  9 15:34:05 1999
@@ -0,0 +1,60 @@
+/*
+ *	Registers for the ESS PCI cards
+ */
+ 
+/*
+ *	Memory access
+ */
+ 
+#define ESS_MEM_DATA		0x00
+#define	ESS_MEM_INDEX		0x02
+
+/*
+ *	AC-97 Codec port. Delay 1uS after each write. This is used to
+ *	talk AC-97 (see intel.com). Write data then register.
+ */
+ 
+#define ESS_AC97_INDEX		0x30		/* byte wide */
+#define ESS_AC97_DATA		0x32
+
+/* 
+ *	Reading is a bit different. You write register|0x80 to ubdex
+ *	delay 1uS poll the low bit of index, when it clears read the
+ *	data value.
+ */
+
+/*
+ *	Control port. Not yet fully understood
+ *	The value 0xC090 gets loaded to it then 0x0000 and 0x2800
+ *	to the data port. Then after 4uS the value 0x300 is written
+ */
+ 
+#define RING_BUS_CTRL_L		0x34
+#define RING_BUS_CTRL_H		0x36
+
+/*
+ *	This is also used during setup. The value 0x17 is written to it
+ */
+ 
+#define ESS_SETUP_18		0x18
+
+/*
+ *	And this one gets 0x000b
+ */
+ 
+#define ESS_SETUP_A2		0xA2
+
+/*
+ *	And this 0x0000
+ */
+ 
+#define ESS_SETUP_A4		0xA4
+#define ESS_SETUP_A6		0xA6
+
+/*
+ *	Stuff to do with Harpo - the wave stuff
+ */
+ 
+#define ESS_WAVETABLE_SIZE	0x14
+#define 	ESS_WAVETABLE_2M	0xA180
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/msnd_pinnacle.c linux.14p16/drivers/sound/msnd_pinnacle.c
--- linux.vanilla/drivers/sound/msnd_pinnacle.c	Wed Oct 20 01:12:48 1999
+++ linux.14p16/drivers/sound/msnd_pinnacle.c	Thu Dec  9 15:34:02 1999
@@ -46,6 +46,7 @@
 #  include <linux/init.h>
 #endif
 #include <asm/irq.h>
+#include <asm/io.h>
 #include "sound_config.h"
 #include "sound_firmware.h"
 #ifdef MSND_CLASSIC
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/nm256.h linux.14p16/drivers/sound/nm256.h
--- linux.vanilla/drivers/sound/nm256.h	Wed Oct 20 01:12:48 1999
+++ linux.14p16/drivers/sound/nm256.h	Tue Dec 21 01:05:50 1999
@@ -3,10 +3,12 @@
 
 #include "ac97.h"
 
+/* The revisions that we currently handle.  */
 enum nm256rev {
     REV_NM256AV, REV_NM256ZX
 };
 
+/* Per-card structure. */
 struct nm256_info 
 {
     /* Magic number used to verify that this struct is valid. */
@@ -34,10 +36,12 @@
     /* The mixer device. */
     int mixer_oss_dev;
 
-    /* Can only be opened once for each operation.  These aren't set
-       until an actual I/O operation is performed; this allows one
-       device to be open for read/write without inhibiting I/O to
-       the other device.  */
+    /* 
+     * Can only be opened once for each operation.  These aren't set
+     * until an actual I/O operation is performed; this allows one
+     * device to be open for read/write without inhibiting I/O to
+     * the other device.
+     */
     int is_open_play;
     int is_open_record;
 
@@ -46,25 +50,42 @@
     /* Ditto for recording a sample. */
     int recording;
 
-    /* The two memory ports. */
-    char *ports[2];
-
-    /* Starting offset of the port1 area mapped into memory. */
-    u32 port1_start;
-    /* Ending offset. */
-    u32 port1_end;
-    /* The offset of the end of the actual buffer area.  */
-    u32 bufend;
+    /* The two memory ports.  */
+    struct nm256_ports {
+	/* Physical address of the port. */
+	u32 physaddr;
+	/* Our mapped-in pointer. */
+	char *ptr;
+	/* PTR's offset within the physical port.  */
+	u32 start_offset;
+	/* And the offset of the end of the buffer.  */
+	u32 end_offset;
+    } port[2];
 
     /* The following are offsets within memory port 1. */
     u32 coeffBuf;
     u32 allCoeffBuf;
+
     /* Record and playback buffers. */
     u32 abuf1, abuf2;
 
     /* Offset of the AC97 mixer in memory port 2. */
     u32 mixer;
 
+    /* Offset of the mixer status register in memory port 2.  */
+    u32 mixer_status_offset;
+
+    /* Non-zero if we have written initial values to the mixer. */
+    u8 mixer_values_init;
+
+    u16 playRingsize;
+
+    /* 
+     * Status mask bit; (*mixer_status_loc & mixer_status_mask) == 0 means
+     * it's ready.  
+     */
+    u16 mixer_status_mask;
+
     /* The sizes of the playback and record ring buffers. */
     u32 playbackBufferSize;
     u32 recordBufferSize;
@@ -77,7 +98,7 @@
     /* The start of the block currently playing. */
     u32 curPlayPos;
 
-    /* The amount of data we requested to record. */
+    /* The amount of data we were requested to record. */
     u32 requestedRecAmt;
     /* The offset of the currently-recording block. */
     u32 curRecPos;
@@ -107,10 +128,17 @@
 /* Debug flag--bigger numbers mean more output. */
 extern int nm256_debug;
 
-/* Size of the second memory port. */
+/* The BIOS signature. */
+#define NM_SIGNATURE 0x4e4d0000
+/* Signature mask. */
+#define NM_SIG_MASK 0xffff0000
+
+/* Size of the second memory area. */
 #define NM_PORT2_SIZE 4096
-/* The location of the mixer. */
-#define NM_MIXER_BASE 0x600
+
+/* The base offset of the mixer in the second memory area. */
+#define NM_MIXER_OFFSET 0x600
+
 /* The maximum size of a coefficient entry. */
 #define NM_MAX_COEFFICIENT 0x5000
 
@@ -123,21 +151,33 @@
 #define NM_MISC_INT_2 0x1
 #define NM_ACK_INT(CARD, X) nm256_writePort16((CARD), 2, NM_INT_REG, (X) << 1)
 
-/* For the second revision.  It uses the same interrupt register, but it
-   holds 32 bits instead of 16.  */
+/* The AV's "mixer ready" status bit and location. */
+#define NM_MIXER_STATUS_OFFSET 0xa04
+#define NM_MIXER_READY_MASK 0x0800
+#define NM_MIXER_PRESENCE 0xa06
+#define NM_PRESENCE_MASK 0x0050
+#define NM_PRESENCE_VALUE 0x0040
+
+/*
+ * For the ZX.  It uses the same interrupt register, but it holds 32
+ * bits instead of 16.
+ */
 #define NM2_PLAYBACK_INT 0x10000
 #define NM2_RECORD_INT 0x80000
 #define NM2_MISC_INT_1 0x8
 #define NM2_MISC_INT_2 0x2
 #define NM2_ACK_INT(CARD, X) nm256_writePort32((CARD), 2, NM_INT_REG, (X))
 
+/* The ZX's "mixer ready" status bit and location. */
+#define NM2_MIXER_STATUS_OFFSET 0xa06
+#define NM2_MIXER_READY_MASK 0x0800
+
 /* The playback registers start from here. */
 #define NM_PLAYBACK_REG_OFFSET 0x0
 /* The record registers start from here. */
 #define NM_RECORD_REG_OFFSET 0x200
 
-/* The rate register is located 2 bytes from the start of the register
-   area. */
+/* The rate register is located 2 bytes from the start of the register area. */
 #define NM_RATE_REG_OFFSET 2
 
 /* Mono/stereo flag, number of bits on playback, and rate mask. */
@@ -156,7 +196,7 @@
 #define NM_AUDIO_MUTE_LEFT 0x8000
 #define NM_AUDIO_MUTE_RIGHT 0x0080
 
-/* Recording enable register */
+/* Recording enable register. */
 #define NM_RECORD_ENABLE_REG (NM_RECORD_REG_OFFSET + 0)
 #define NM_RECORD_ENABLE_FLAG 1
 #define NM_RECORD_FREERUN 2
@@ -179,26 +219,25 @@
   if (port < 1 || port > 2 || card == NULL) \
       return -1; \
 \
-  if (port == 1) { \
-        if (offset < card->port1_start || offset >= card->port1_end) { \
-	    printk (KERN_ERR "Bad port request port 1:0x%x\n", offset); \
-            return -1; \
-        } \
-        offset -= card->port1_start; \
-   } else if (offset < 0 || offset > 4096) { \
-        printk (KERN_ERR "Bad port request port 2: 0x%x\n", offset); \
-        return -1; \
-   }
+    if (offset < card->port[port - 1].start_offset \
+	|| offset >= card->port[port - 1].end_offset) { \
+	printk (KERN_ERR "Bad access: port %d, offset 0x%x\n", port, offset); \
+	return -1; \
+    } \
+    offset -= card->port[port - 1].start_offset;
 
 #define DEFwritePortX(X, func) \
 static inline int nm256_writePort##X (struct nm256_info *card,\
-					int port, int offset, int value)\
+				      int port, int offset, int value)\
 {\
     u##X *addr;\
 \
+    if (nm256_debug > 1)\
+        printk (KERN_DEBUG "Writing 0x%x to %d:0x%x\n", value, port, offset);\
+\
     NM_FIX_PORT;\
 \
-    addr = (u##X *)(card->ports[port - 1] + offset);\
+    addr = (u##X *)(card->port[port - 1].ptr + offset);\
     func (value, addr);\
     return 0;\
 }
@@ -207,29 +246,28 @@
 DEFwritePortX (16, writew)
 DEFwritePortX (32, writel)
 
-#define DEFreadPortX(X) \
+#define DEFreadPortX(X, func) \
 static inline u##X nm256_readPort##X (struct nm256_info *card,\
 					int port, int offset)\
 {\
-    u##X *addr, res;\
+    u##X *addr;\
 \
     NM_FIX_PORT\
 \
-    addr = (u##X *)(card->ports[port - 1] + offset);\
-    memcpy_fromio (&res, addr, sizeof (res));\
-    return res;\
+    addr = (u##X *)(card->port[port - 1].ptr + offset);\
+    return func(addr);\
 }
 
-DEFreadPortX (8)
-DEFreadPortX (16)
-DEFreadPortX (32)
+DEFreadPortX (8, readb)
+DEFreadPortX (16, readw)
+DEFreadPortX (32, readl)
 
 static inline int
 nm256_writeBuffer8 (struct nm256_info *card, u8 *src, int port, int offset,
 		      int amt)
 {
     NM_FIX_PORT;
-    memcpy_toio (card->ports[port - 1] + offset, src, amt);
+    memcpy_toio (card->port[port - 1].ptr + offset, src, amt);
     return 0;
 }
 
@@ -238,7 +276,7 @@
 		     int amt)
 {
     NM_FIX_PORT;
-    memcpy_fromio (dst, card->ports[port - 1] + offset, amt);
+    memcpy_fromio (dst, card->port[port - 1].ptr + offset, amt);
     return 0;
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/nm256_audio.c linux.14p16/drivers/sound/nm256_audio.c
--- linux.vanilla/drivers/sound/nm256_audio.c	Wed Oct 20 01:12:48 1999
+++ linux.14p16/drivers/sound/nm256_audio.c	Tue Dec 14 20:02:23 1999
@@ -1,27 +1,38 @@
-/* Audio driver for the NeoMagic 256AV and 256ZX chipsets in native
-   mode, with AC97 mixer support.
-
-   Overall design and parts of this code stolen from vidc_*.c and
-   skeleton.c.
-
-   Yeah, there are a lot of magic constants in here.  You tell ME what
-   they are.  I just get this stuff psychically, remember? 
-
-   This driver was written by someone who wishes to remain anonymous. 
-   It is in the public domain, so share and enjoy.  Try to make a profit
-   off of it; go on, I dare you.  */
-
+/* 
+ * Audio driver for the NeoMagic 256AV and 256ZX chipsets in native
+ * mode, with AC97 mixer support.
+ *
+ * Overall design and parts of this code stolen from vidc_*.c and
+ * skeleton.c.
+ *
+ * Yeah, there are a lot of magic constants in here.  You tell ME what
+ * they are.  I just get this stuff psychically, remember? 
+ *
+ * This driver was written by someone who wishes to remain anonymous. 
+ * It is in the public domain, so share and enjoy.  Try to make a profit
+ * off of it; go on, I dare you.  
+ */
+  
 #include <linux/config.h>
+#include <linux/version.h>
 #include <linux/pci.h>
 #include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/apm_bios.h>
+
 #include "sound_config.h"
 #include "soundmodule.h"
 #include "nm256.h"
 #include "nm256_coeff.h"
 
 int nm256_debug = 0;
+static int force_load = 0;
 
-/* The size of the playback reserve. */
+/* 
+ * The size of the playback reserve.  When the playback buffer has less
+ * than NM256_PLAY_WMARK_SIZE bytes to output, we request a new
+ * buffer.
+ */
 #define NM256_PLAY_WMARK_SIZE 512
 
 static struct audio_driver nm256_audio_driver;
@@ -29,16 +40,74 @@
 static int nm256_grabInterrupt (struct nm256_info *card);
 static int nm256_releaseInterrupt (struct nm256_info *card);
 static void nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy);
-static void nm256_interrupt_zx (int irq, void *dev_id, 
-				  struct pt_regs *dummy);
+static void nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy);
 
 /* These belong in linux/pci.h. */
 #define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005
 #define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006
 
+/* eeeew. */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
+#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
+#else
+#define RSRCADDRESS(dev,num) ((dev)->base_address[(num)] \
+			      & PCI_BASE_ADDRESS_MEM_MASK)
+
+#endif
+
 /* List of cards.  */
 static struct nm256_info *nmcard_list;
 
+/* Release the mapped-in memory for CARD.  */
+static void
+nm256_release_ports (struct nm256_info *card)
+{
+    int x;
+
+    for (x = 0; x < 2; x++) {
+	if (card->port[x].ptr != NULL) {
+	    u32 size = 
+		card->port[x].end_offset - card->port[x].start_offset;
+	    release_region ((unsigned long) card->port[x].ptr, size);
+	    card->port[x].ptr = NULL;
+	}
+    }
+}
+
+/* 
+ * Map in the memory ports for CARD, if they aren't already mapped in
+ * and have been configured.  If successful, a zero value is returned;
+ * otherwise any previously mapped-in areas are released and a non-zero
+ * value is returned.
+ *
+ * This is invoked twice, once for each port.  Ideally it would only be
+ * called once, but we now need to map in the second port in order to
+ * check how much memory the card has on the 256ZX.
+ */
+static int
+nm256_remap_ports (struct nm256_info *card)
+{
+    int x;
+
+    for (x = 0; x < 2; x++) {
+	if (card->port[x].ptr == NULL && card->port[x].end_offset > 0) {
+	    u32 physaddr 
+		= card->port[x].physaddr + card->port[x].start_offset;
+	    u32 size 
+		= card->port[x].end_offset - card->port[x].start_offset;
+
+	    card->port[x].ptr = ioremap_nocache (physaddr, size);
+						  
+	    if (card->port[x].ptr == NULL) {
+		printk (KERN_ERR "NM256: Unable to remap port %d\n", x + 1);
+		nm256_release_ports (card);
+		return -1;
+	    }
+	}
+    }
+    return 0;
+}
+
 /* Locate the card in our list. */
 static struct nm256_info *
 nm256_find_card (int dev)
@@ -52,8 +121,10 @@
     return NULL;
 }
 
-/* Ditto, but find the card struct corresponding to the mixer device DEV 
-   instead. */
+/*
+ * Ditto, but find the card struct corresponding to the mixer device DEV 
+ * instead. 
+ */
 static struct nm256_info *
 nm256_find_card_for_mixer (int dev)
 {
@@ -81,11 +152,13 @@
     8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999
 };
 
-/* Set the card samplerate, word size and stereo mode to correspond to
-   the settings in the CARD struct for the specified device in DEV.
-   We keep two separate sets of information, one for each device; the
-   hardware is not actually configured until a read or write is
-   attempted. */
+/*
+ * Set the card samplerate, word size and stereo mode to correspond to
+ * the settings in the CARD struct for the specified device in DEV.
+ * We keep two separate sets of information, one for each device; the
+ * hardware is not actually configured until a read or write is
+ * attempted.
+ */
 
 int
 nm256_setInfo (int dev, struct nm256_info *card)
@@ -113,24 +186,33 @@
 	    break;
 
     if (x < 8) {
-	u8 speedbits = ((x << 4) & NM_RATE_MASK)
-	    | (card->sinfo[w].bits == 16 ? NM_RATE_BITS_16: 0) 
-	    | (card->sinfo[w].stereo ? NM_RATE_STEREO : 0);
+	u8 ratebits = ((x << 4) & NM_RATE_MASK);
+	if (card->sinfo[w].bits == 16)
+	    ratebits |= NM_RATE_BITS_16;
+	if (card->sinfo[w].stereo)
+	    ratebits |= NM_RATE_STEREO;
 
 	card->sinfo[w].samplerate = samplerates[x];
 
+
 	if (card->dev_for_play == dev && card->playing) {
+	    if (nm256_debug)
+		printk (KERN_DEBUG "Setting play ratebits to 0x%x\n",
+			ratebits);
 	    nm256_loadCoefficient (card, 0, x);
 	    nm256_writePort8 (card, 2,
-				NM_PLAYBACK_REG_OFFSET + NM_RATE_REG_OFFSET,
-				speedbits);
+			      NM_PLAYBACK_REG_OFFSET + NM_RATE_REG_OFFSET,
+			      ratebits);
 	}
 
 	if (card->dev_for_record == dev && card->recording) {
+	    if (nm256_debug)
+		printk (KERN_DEBUG "Setting record ratebits to 0x%x\n",
+			ratebits);
 	    nm256_loadCoefficient (card, 1, x);
-	    nm256_writePort8 (card, 2, 
-				NM_RECORD_REG_OFFSET + NM_RATE_REG_OFFSET,
-				speedbits);
+	    nm256_writePort8 (card, 2,
+			      NM_RECORD_REG_OFFSET + NM_RATE_REG_OFFSET,
+			      ratebits);
 	}
 	return 0;
     }
@@ -149,7 +231,7 @@
 
 	    /* Enable playback engine and interrupts. */
 	    nm256_writePort8 (card, 2, NM_PLAYBACK_ENABLE_REG,
-				NM_PLAYBACK_ENABLE_FLAG | NM_PLAYBACK_FREERUN);
+			      NM_PLAYBACK_ENABLE_FLAG | NM_PLAYBACK_FREERUN);
 
 	    /* Enable both channels. */
 	    nm256_writePort16 (card, 2, NM_AUDIO_MUTE_REG, 0x0);
@@ -157,9 +239,11 @@
     }
 }
 
-/* Request one chunk of AMT bytes from the recording device.  When the
-   operation is complete, the data will be copied into BUFFER and the
-   function DMAbuf_inputintr will be invoked. */
+/* 
+ * Request one chunk of AMT bytes from the recording device.  When the
+ * operation is complete, the data will be copied into BUFFER and the
+ * function DMAbuf_inputintr will be invoked.
+ */
 
 static void
 nm256_startRecording (struct nm256_info *card, char *buffer, u32 amt)
@@ -167,11 +251,14 @@
     u32 endpos;
     int enableEngine = 0;
     u32 ringsize = card->recordBufferSize;
+    unsigned long flags;
 
     if (amt > (ringsize / 2)) {
-	/* Of course this won't actually work right, because the
-	   caller is going to assume we will give what we got asked
-	   for. */
+	/*
+	 * Of course this won't actually work right, because the
+	 * caller is going to assume we will give what we got asked
+	 * for.
+	 */
 	printk (KERN_ERR "NM256: Read request too large: %d\n", amt);
 	amt = ringsize / 2;
     }
@@ -181,8 +268,12 @@
 	return;
     }
 
-    /* If we're not currently recording, set up the start and end registers
-       for the recording engine. */
+    save_flags (flags);
+    cli ();
+    /*
+     * If we're not currently recording, set up the start and end registers
+     * for the recording engine.
+     */
     if (! card->recording) {
 	card->recording = 1;
 	if (nm256_grabInterrupt (card) == 0) {
@@ -198,10 +289,16 @@
 	}
 	else {
 	    /* Not sure what else to do here.  */
+	    restore_flags (flags);
 	    return;
 	}
     }
 
+    /* 
+     * If we happen to go past the end of the buffer a bit (due to a
+     * delayed interrupt) it's OK.  So might as well set the watermark
+     * right at the end of the data we want.
+     */
     endpos = card->abuf2 + ((card->curRecPos + amt) % ringsize);
 
     card->recBuf = buffer;
@@ -211,6 +308,8 @@
     if (enableEngine)
 	nm256_writePort8 (card, 2, NM_RECORD_ENABLE_REG,
 			    NM_RECORD_ENABLE_FLAG | NM_RECORD_FREERUN);
+
+    restore_flags (flags);
 }
 
 /* Stop the play engine. */
@@ -219,7 +318,7 @@
 {
     /* Shut off sound from both channels. */
     nm256_writePort16 (card, 2, NM_AUDIO_MUTE_REG,
-			 NM_AUDIO_MUTE_LEFT | NM_AUDIO_MUTE_RIGHT);
+		       NM_AUDIO_MUTE_LEFT | NM_AUDIO_MUTE_RIGHT);
     /* Disable play engine. */
     nm256_writePort8 (card, 2, NM_PLAYBACK_ENABLE_REG, 0);
     if (card->playing) {
@@ -246,18 +345,22 @@
     }
 }
 
-/* Ring buffers, man.  That's where the hip-hop, wild-n-wooly action's at.
-   1972?
-
-   Write AMT bytes of BUFFER to the playback ring buffer, and start the
-   playback engine running.  It will only accept up to 1/2 of the total
-   size of the ring buffer.  */
+/*
+ * Ring buffers, man.  That's where the hip-hop, wild-n-wooly action's at.
+ * 1972?  (Well, I suppose it was cheep-n-easy to implement.)
+ *
+ * Write AMT bytes of BUFFER to the playback ring buffer, and start the
+ * playback engine running.  It will only accept up to 1/2 of the total
+ * size of the ring buffer.  No check is made that we're about to overwrite
+ * the currently-playing sample.
+ */
 
 static void
 nm256_write_block (struct nm256_info *card, char *buffer, u32 amt)
 {
     u32 ringsize = card->playbackBufferSize;
     u32 endstop;
+    unsigned long flags;
 
     if (amt > (ringsize / 2)) {
 	printk (KERN_ERR "NM256: Write request too large: %d\n", amt);
@@ -273,48 +376,58 @@
 
     card->requested_amt = amt;
 
+    save_flags (flags);
+    cli ();
+
     if ((card->curPlayPos + amt) >= ringsize) {
 	u32 rem = ringsize - card->curPlayPos;
 
 	nm256_writeBuffer8 (card, buffer, 1,
-			      card->abuf1 + card->curPlayPos,
-			      rem);
+			    card->abuf1 + card->curPlayPos,
+			    rem);
 	if (amt > rem)
-	    nm256_writeBuffer8 (card, buffer, 1, card->abuf1,
-				  amt - rem);
+	    nm256_writeBuffer8 (card, buffer + rem, 1, card->abuf1,
+				amt - rem);
     } 
     else
 	nm256_writeBuffer8 (card, buffer, 1,
 			      card->abuf1 + card->curPlayPos,
 			      amt);
 
-    /* Setup the start-n-stop-n-limit registers, and start that engine
-       goin'. 
-
-       Normally we just let it wrap around to avoid the click-click
-       action scene. */
+    /*
+     * Setup the start-n-stop-n-limit registers, and start that engine
+     * goin'. 
+     *
+     * Normally we just let it wrap around to avoid the click-click
+     * action scene.
+     */
     if (! card->playing) {
-	/* The PBUFFER_END register in this case points to one "word"
+	/* The PBUFFER_END register in this case points to one sample
 	   before the end of the buffer. */
 	int w = (card->dev_for_play == card->dev[0] ? 0 : 1);
-	int wordsize = (card->sinfo[w].bits == 16 ? 2 : 1)
-	    * (card->sinfo[w].stereo ? 2 : 1);
+	int sampsize = (card->sinfo[w].bits == 16 ? 2 : 1);
+
+	if (card->sinfo[w].stereo)
+	    sampsize *= 2;
 
 	/* Need to set the not-normally-changing-registers up. */
 	nm256_writePort32 (card, 2, NM_PBUFFER_START,
 			     card->abuf1 + card->curPlayPos);
 	nm256_writePort32 (card, 2, NM_PBUFFER_END,
-			     card->abuf1 + ringsize - wordsize);
+			     card->abuf1 + ringsize - sampsize);
 	nm256_writePort32 (card, 2, NM_PBUFFER_CURRP,
 			     card->abuf1 + card->curPlayPos);
     }
     endstop = (card->curPlayPos + amt - NM256_PLAY_WMARK_SIZE) % ringsize;
     nm256_writePort32 (card, 2, NM_PBUFFER_WMARK, card->abuf1 + endstop);
+
     if (! card->playing)
 	startPlay (card);
+
+    restore_flags (flags);
 }
 
-/* We just got a card playback interrupt; process it. */
+/*  We just got a card playback interrupt; process it.  */
 static void
 nm256_get_new_block (struct nm256_info *card)
 {
@@ -332,13 +445,14 @@
 	amt -= card->curPlayPos;
 
     if (card->requested_amt > (amt + NM256_PLAY_WMARK_SIZE)) {
-	u32 endstop = 
+	u32 endstop =
 	    card->curPlayPos + card->requested_amt - NM256_PLAY_WMARK_SIZE;
 	nm256_writePort32 (card, 2, NM_PBUFFER_WMARK, card->abuf1 + endstop);
-    } else {
+    } 
+    else {
 	card->curPlayPos += card->requested_amt;
 	/* Get a new block to write.  This will eventually invoke
-	   nm256_write_block ().  */
+	   nm256_write_block () or stopPlay ().  */
 	DMAbuf_outputintr (card->dev_for_play, 1);
     }
 }
@@ -346,9 +460,11 @@
 /* Ultra cheez-whiz.  But I'm too lazy to grep headers. */
 #define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
 
-/* Read the last-recorded block from the ring buffer, copy it into the
-   saved buffer pointer, and invoke DMAuf_inputintr() with the recording
-   device. */
+/* 
+ * Read the last-recorded block from the ring buffer, copy it into the
+ * saved buffer pointer, and invoke DMAuf_inputintr() with the recording
+ * device. 
+ */
 
 static void
 nm256_read_block (struct nm256_info *card)
@@ -363,8 +479,10 @@
         currptr = 0;
     }
 
-    /* This test is probably redundant; we shouldn't be here unless
-       it's true.  */
+    /*
+     * This test is probably redundant; we shouldn't be here unless
+     * it's true.
+     */
     if (card->recording) {
 	/* If we wrapped around, copy everything from the start of our
 	   recording buffer to the end of the buffer. */
@@ -394,52 +512,28 @@
 }
 #undef MIN
 
-/* Initialize the hardware and various other card data we'll need
-   later. */
+/* 
+ * Initialize the hardware. 
+ */
 static void
 nm256_initHw (struct nm256_info *card)
 {
-    int x;
-
-    card->playbackBufferSize = 16384;
-    card->recordBufferSize = 16384;
-
-    card->coeffBuf = card->bufend - NM_MAX_COEFFICIENT;
-    card->abuf2 = card->coeffBuf - card->recordBufferSize;
-    card->abuf1 = card->abuf2 - card->playbackBufferSize;
-    card->allCoeffBuf = card->abuf2 - (NM_TOTAL_COEFF_COUNT * 4);
-
-    /* Fixed setting. */
-    card->mixer = NM_MIXER_BASE;
-
-    card->playing = 0;
-    card->is_open_play = 0;
-    card->curPlayPos = 0;
-
-    card->recording = 0;
-    card->is_open_record = 0;
-    card->curRecPos = 0;
-
-    card->coeffsCurrent = 0;
-
-    card->opencnt[0] = 0; card->opencnt[1] = 0;
-
     /* Reset everything. */
-    nm256_writePort8 (card, 2, 0, 0x11);
-
-    /* Disable recording. */
-    nm256_writePort8 (card, 2, NM_RECORD_ENABLE_REG, 0);
+    nm256_writePort8 (card, 2, 0x0, 0x11);
     nm256_writePort16 (card, 2, 0x214, 0);
 
-    /* Reasonable default settings, but largely unnecessary. */
-    for (x = 0; x < 2; x++) {
-	card->sinfo[x].bits = 8;
-	card->sinfo[x].stereo = 0;
-	card->sinfo[x].samplerate = 8000;
-    }
+    stopRecord (card);
+    stopPlay (card);
 }
 
-/* Handle a potential interrupt for the device referred to by DEV_ID. */
+/* 
+ * Handle a potential interrupt for the device referred to by DEV_ID. 
+ *
+ * I don't like the cut-n-paste job here either between the two routines,
+ * but there are sufficient differences between the two interrupt handlers
+ * that parameterizing it isn't all that great either.  (Could use a macro,
+ * I suppose...yucky bleah.)
+ */
 
 static void
 nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy)
@@ -458,14 +552,32 @@
     /* Not ours. */
     if (status == 0) {
 	if (badintrcount++ > 1000) {
-	    printk (KERN_ERR "NM256: Releasing interrupt, over 1000 invalid interrupts\n");
-	    nm256_releaseInterrupt (card);
+	    /*
+	     * I'm not sure if the best thing is to stop the card from
+	     * playing or just release the interrupt (after all, we're in
+	     * a bad situation, so doing fancy stuff may not be such a good
+	     * idea).
+	     *
+	     * I worry about the card engine continuing to play noise
+	     * over and over, however--that could become a very
+	     * obnoxious problem.  And we know that when this usually
+	     * happens things are fairly safe, it just means the user's
+	     * inserted a PCMCIA card and someone's spamming us with IRQ 9s.
+	     */
+
+	    if (card->playing)
+		stopPlay (card);
+	    if (card->recording)
+		stopRecord (card);
+	    badintrcount = 0;
 	}
 	return;
     }
 
     badintrcount = 0;
 
+    /* Rather boring; check for individual interrupts and process them. */
+
     if (status & NM_PLAYBACK_INT) {
 	status &= ~NM_PLAYBACK_INT;
 	NM_ACK_INT (card, NM_PLAYBACK_INT);
@@ -503,6 +615,7 @@
 	nm256_writePort8 (card, 2, 0x400, cbyte & ~2);
     }
 
+    /* Unknown interrupt. */
     if (status) {
 	printk (KERN_ERR "NM256: Fire in the hole! Unknown status 0x%x\n",
 		status);
@@ -511,8 +624,11 @@
     }
 }
 
-/* Handle a potential interrupt for the device referred to by DEV_ID.
-   This handler is for the 256ZX.  */
+/*
+ * Handle a potential interrupt for the device referred to by DEV_ID.
+ * This handler is for the 256ZX, and is very similar to the non-ZX
+ * routine.
+ */
 
 static void
 nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy)
@@ -532,13 +648,33 @@
     if (status == 0) {
 	if (badintrcount++ > 1000) {
 	    printk (KERN_ERR "NM256: Releasing interrupt, over 1000 invalid interrupts\n");
-	    nm256_releaseInterrupt (card);
+	    /*
+	     * I'm not sure if the best thing is to stop the card from
+	     * playing or just release the interrupt (after all, we're in
+	     * a bad situation, so doing fancy stuff may not be such a good
+	     * idea).
+	     *
+	     * I worry about the card engine continuing to play noise
+	     * over and over, however--that could become a very
+	     * obnoxious problem.  And we know that when this usually
+	     * happens things are fairly safe, it just means the user's
+	     * inserted a PCMCIA card and someone's spamming us with 
+	     * IRQ 9s.
+	     */
+
+	    if (card->playing)
+		stopPlay (card);
+	    if (card->recording)
+		stopRecord (card);
+	    badintrcount = 0;
 	}
 	return;
     }
 
     badintrcount = 0;
 
+    /* Rather boring; check for individual interrupts and process them. */
+
     if (status & NM2_PLAYBACK_INT) {
 	status &= ~NM2_PLAYBACK_INT;
 	NM2_ACK_INT (card, NM2_PLAYBACK_INT);
@@ -575,6 +711,7 @@
 	nm256_writePort8 (card, 2, 0x400, cbyte & ~2);
     }
 
+    /* Unknown interrupt. */
     if (status) {
 	printk (KERN_ERR "NM256: Fire in the hole! Unknown status 0x%x\n",
 		status);
@@ -583,7 +720,9 @@
     }
 }
 
-/* Request our interrupt. */
+/* 
+ * Request our interrupt.
+ */
 static int
 nm256_grabInterrupt (struct nm256_info *card)
 {
@@ -597,7 +736,9 @@
     return 0;
 }
 
-/* Release our interrupt. */
+/* 
+ * Release our interrupt. 
+ */
 static int
 nm256_releaseInterrupt (struct nm256_info *card)
 {
@@ -612,6 +753,11 @@
     return 0;
 }
 
+/*
+ * Waits for the mixer to become ready to be written; returns a zero value
+ * if it timed out.
+ */
+
 static int
 nm256_isReady (struct ac97_hwint *dev)
 {
@@ -626,26 +772,25 @@
 	return 0;
     }
 
-    if (card->rev == REV_NM256AV) {
-	testaddr = 0xa06;
-	testb = 0x0100;
-    } else if (card->rev == REV_NM256ZX) {
-	testaddr = 0xa08;
-	testb = 0x0800;
-    } else {
-	return -1;
-    }
+    testaddr = card->mixer_status_offset;
+    testb = card->mixer_status_mask;
 
-    while (t2-- > 0) {
-	if ((nm256_readPort16 (card, 2, testaddr) & testb) == 0) {
+    /* 
+     * Loop around waiting for the mixer to become ready. 
+     */
+    while (! done && t2-- > 0) {
+	if ((nm256_readPort16 (card, 2, testaddr) & testb) == 0)
 	    done = 1;
-	    break;
-	}
-	udelay (100);
+	else
+	    udelay (100);
     }
     return done;
 }
 
+/*
+ * Return the contents of the AC97 mixer register REG.  Returns a positive
+ * value if successful, or a negative error code.
+ */
 static int
 nm256_readAC97Reg (struct ac97_hwint *dev, u8 reg)
 {
@@ -661,6 +806,7 @@
 
 	nm256_isReady (dev);
 	res = nm256_readPort16 (card, 2, card->mixer + reg);
+	/* Magic delay.  Bleah yucky.  */
         udelay (1000);
 	return res;
     }
@@ -668,6 +814,10 @@
 	return -EINVAL;
 }
 
+/* 
+ * Writes VALUE to AC97 mixer register REG.  Returns 0 if successful, or
+ * a negative error code. 
+ */
 static int
 nm256_writeAC97Reg (struct ac97_hwint *dev, u8 reg, u16 value)
 {
@@ -706,6 +856,13 @@
     return ! done;
 }
 
+/* 
+ * Initial register values to be written to the AC97 mixer.
+ * While most of these are identical to the reset values, we do this
+ * so that we have most of the register contents cached--this avoids
+ * reading from the mixer directly (which seems to be problematic,
+ * probably due to ignorance).
+ */
 struct initialValues 
 {
     unsigned short port;
@@ -714,23 +871,24 @@
 
 static struct initialValues nm256_ac97_initial_values[] = 
 {
-    { 0x0002, 0x8000 },
-    { 0x0004, 0x0000 },
-    { 0x0006, 0x0000 },
-    { 0x000A, 0x0000 },
-    { 0x000C, 0x0008 },
-    { 0x000E, 0x8008 },
-    { 0x0010, 0x8808 },
-    { 0x0012, 0x8808 },
-    { 0x0014, 0x8808 },
-    { 0x0016, 0x8808 },
-    { 0x0018, 0x0808 },
-    { 0x001A, 0x0000 },
-    { 0x001C, 0x0B0B },
-    { 0x0020, 0x0000 },
+    { AC97_MASTER_VOL_STEREO, 0x8000 },
+    { AC97_HEADPHONE_VOL,     0x8000 },
+    { AC97_MASTER_VOL_MONO,   0x0000 },
+    { AC97_PCBEEP_VOL,        0x0000 },
+    { AC97_PHONE_VOL,         0x0008 },
+    { AC97_MIC_VOL,           0x8000 },
+    { AC97_LINEIN_VOL,        0x8808 },
+    { AC97_CD_VOL,            0x8808 },
+    { AC97_VIDEO_VOL,         0x8808 },
+    { AC97_AUX_VOL,           0x8808 },
+    { AC97_PCMOUT_VOL,        0x0808 },
+    { AC97_RECORD_SELECT,     0x0000 },
+    { AC97_RECORD_GAIN,       0x0B0B },
+    { AC97_GENERAL_PURPOSE,   0x0000 },
     { 0xffff, 0xffff }
 };
 
+/* Initialize the AC97 into a known state.  */
 static int
 nm256_resetAC97 (struct ac97_hwint *dev)
 {
@@ -742,22 +900,28 @@
 	return -EINVAL;
     }
 
-    /* Reset the card.  'Tis magic!  */
+    /* Reset the mixer.  'Tis magic!  */
     nm256_writePort8 (card, 2, 0x6c0, 1);
     nm256_writePort8 (card, 2, 0x6cc, 0x87);
     nm256_writePort8 (card, 2, 0x6cc, 0x80);
     nm256_writePort8 (card, 2, 0x6cc, 0x0);
 
-    for (x = 0; nm256_ac97_initial_values[x].port != 0xffff; x++) {
-	ac97_put_register (dev,
-			   nm256_ac97_initial_values[x].port, 
-			   nm256_ac97_initial_values[x].value);
+    if (! card->mixer_values_init) {
+	for (x = 0; nm256_ac97_initial_values[x].port != 0xffff; x++) {
+	    ac97_put_register (dev,
+			       nm256_ac97_initial_values[x].port,
+			       nm256_ac97_initial_values[x].value);
+	    card->mixer_values_init = 1;
+	}
     }
 
     return 0;
 }
 
-/* We don't do anything special here.  */
+/*
+ * We don't do anything particularly special here; it just passes the
+ * mixer ioctl to the AC97 driver.
+ */
 static int
 nm256_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
 {
@@ -774,7 +938,12 @@
     nm256_default_mixer_ioctl
 };
 
-/* I "love" C sometimes.  Got braces?  */
+/*
+ * Default settings for the OSS mixer.  These are set last, after the
+ * mixer is initialized.
+ *
+ * I "love" C sometimes.  Got braces?
+ */
 static struct ac97_mixer_value_list mixer_defaults[] = {
     { SOUND_MIXER_VOLUME,  { { 85, 85 } } },
     { SOUND_MIXER_SPEAKER, { { 100 } } },
@@ -783,6 +952,8 @@
     { -1,                  {  { 0,  0 } } }
 };
 
+
+/* Installs the AC97 mixer into CARD.  */
 static int
 nm256_install_mixer (struct nm256_info *card)
 {
@@ -812,36 +983,67 @@
     return 0;
 }
 
-/* See if the signature left by the NM256 BIOS is intact; if so, we use
-   the associated address as the end of our buffer. */
+/* Perform a full reset on the hardware; this is invoked when an APM
+   resume event occurs.  */
+static void
+nm256_full_reset (struct nm256_info *card)
+{
+    nm256_initHw (card);
+    ac97_reset (&(card->mdev));
+}
+
+/* 
+ * See if the signature left by the NM256 BIOS is intact; if so, we use
+ * the associated address as the end of our audio buffer in the video
+ * RAM.
+ */
+
 static void
-nm256_peek_for_sig (struct nm256_info *card, u32 port1addr)
+nm256_peek_for_sig (struct nm256_info *card)
 {
-    char *temp = ioremap_nocache (port1addr + card->port1_end - 0x0400, 16);
+    u32 port1offset 
+	= card->port[0].physaddr + card->port[0].end_offset - 0x0400;
+    /* The signature is located 1K below the end of video RAM.  */
+    char *temp = ioremap_nocache (port1offset, 16);
+    /* Default buffer end is 5120 bytes below the top of RAM.  */
+    u32 default_value = card->port[0].end_offset - 0x1400;
     u32 sig;
 
+    /* Install the default value first, so we don't have to repeatedly
+       do it if there is a problem.  */
+    card->port[0].end_offset = default_value;
+
     if (temp == NULL) {
 	printk (KERN_ERR "NM256: Unable to scan for card signature in video RAM\n");
 	return;
     }
-    memcpy_fromio (&sig, temp, sizeof (u32));
-    if ((sig & 0xffff0000) == 0x4e4d0000) {
-	memcpy_fromio (&(card->bufend), temp + 4, sizeof (u32));
+    sig = readl (temp);
+    if ((sig & NM_SIG_MASK) == NM_SIGNATURE) {
+	u32 pointer = readl (temp + 4);
+
+	/*
+	 * If it's obviously invalid, don't use it (the port already has a
+	 * suitable default value set).
+	 */
+	if (pointer != 0xffffffff)
+	    card->port[0].end_offset = pointer;
+
 	printk (KERN_INFO "NM256: Found card signature in video RAM: 0x%x\n",
-		card->bufend);
+		pointer);
     }
 
     release_region ((unsigned long) temp, 16);
 }
 
-/* Install a driver for the soundcard referenced by PCIDEV. */
+/* 
+ * Install a driver for the PCI device referenced by PCIDEV.
+ * VERSTR is a human-readable version string.
+ */
 
 static int
 nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr)
 {
     struct nm256_info *card;
-    u32 port1addr = (pcidev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK);
-    u32 port2addr = (pcidev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK);
     int x;
 
     card = kmalloc (sizeof (struct nm256_info), GFP_KERNEL);
@@ -855,52 +1057,85 @@
     card->recording = 0;
     card->rev = rev;
 
-    /* The NM256 has two memory ports.  The first port is nothing
-       more than a chunk of video RAM, which is used as the I/O ring
-       buffer.  The second port has the actual juicy stuff (like the
-       mixer and the playback engine control registers). */
-
-    card->ports[1] = ioremap_nocache (port2addr, NM_PORT2_SIZE);
+    /* Init the memory port info.  */
+    for (x = 0; x < 2; x++) {
+	card->port[x].physaddr = RSRCADDRESS (pcidev, x);
+	card->port[x].ptr = NULL;
+	card->port[x].start_offset = 0;
+	card->port[x].end_offset = 0;
+    }
 
-    if (card->ports[1] == NULL) {
-	printk (KERN_ERR "NM256: Unable to remap port 2\n");
+    /* Port 2 is easy.  */
+    card->port[1].start_offset = 0;
+    card->port[1].end_offset = NM_PORT2_SIZE;
+
+    /* Yuck.  But we have to map in port 2 so we can check how much RAM the
+       card has.  */
+    if (nm256_remap_ports (card)) {
 	kfree_s (card, sizeof (struct nm256_info));
 	return 0;
     }
 
+    /* 
+     * The NM256 has two memory ports.  The first port is nothing
+     * more than a chunk of video RAM, which is used as the I/O ring
+     * buffer.  The second port has the actual juicy stuff (like the
+     * mixer and the playback engine control registers).
+     */
+
     if (card->rev == REV_NM256AV) {
-	card->port1_end = 2560 * 1024;
+	/* Ok, try to see if this is a non-AC97 version of the hardware. */
+	int pval = nm256_readPort16 (card, 2, NM_MIXER_PRESENCE);
+	if ((pval & NM_PRESENCE_MASK) != NM_PRESENCE_VALUE) {
+	    if (! force_load) {
+		printk (KERN_ERR "NM256: This doesn't look to me like the AC97-compatible version.\n");
+		printk (KERN_ERR "       You can force the driver to load by passing in the module\n");
+		printk (KERN_ERR "       parameter:\n");
+		printk (KERN_ERR "              force_ac97 = 1\n");
+		printk (KERN_ERR "\n");
+		printk (KERN_ERR "       More likely, you should be using the appropriate SB-16 or\n");
+		printk (KERN_ERR "       CS4232 driver instead.  (If your BIOS has settings for\n");
+		printk (KERN_ERR "       IRQ and/or DMA for the sound card, this is *not* the correct\n");
+		printk (KERN_ERR "       driver to use.)\n");
+		nm256_release_ports (card);
+		kfree_s (card, sizeof (struct nm256_info));
+		return 0;
+	    }
+	    else {
+		printk (KERN_INFO "NM256: Forcing driver load as per user request.\n");
+	    }
+	}
+	else {
+	    printk (KERN_INFO "NM256: Congratulations. You're not running Eunice.\n");
+	}
+	card->port[0].end_offset = 2560 * 1024;
 	card->introutine = nm256_interrupt;
+	card->mixer_status_offset = NM_MIXER_STATUS_OFFSET;
+	card->mixer_status_mask = NM_MIXER_READY_MASK;
     } 
     else {
+	/* Not sure if there is any relevant detect for the ZX or not.  */
 	if (nm256_readPort8 (card, 2, 0xa0b) != 0)
-	    card->port1_end = 6144 * 1024;
+	    card->port[0].end_offset = 6144 * 1024;
 	else
-	    card->port1_end = 4096 * 1024;
+	    card->port[0].end_offset = 4096 * 1024;
 
 	card->introutine = nm256_interrupt_zx;
+	card->mixer_status_offset = NM2_MIXER_STATUS_OFFSET;
+	card->mixer_status_mask = NM2_MIXER_READY_MASK;
     }
 
-    /* Default value. */
-    card->bufend = card->port1_end - 0x1400;
-
-    if (buffertop >= 98304 && buffertop < card->port1_end)
-	card->bufend = buffertop;
+    if (buffertop >= 98304 && buffertop < card->port[0].end_offset)
+	card->port[0].end_offset = buffertop;
     else
-	nm256_peek_for_sig (card, port1addr);
+	nm256_peek_for_sig (card);
 
-    card->port1_start = card->bufend - 98304;
+    card->port[0].start_offset = card->port[0].end_offset - 98304;
 
     printk (KERN_INFO "NM256: Mapping port 1 from 0x%x - 0x%x\n",
-	    card->port1_start, card->port1_end);
+	    card->port[0].start_offset, card->port[0].end_offset);
 
-    card->ports[0] =
-	ioremap_nocache (port1addr + card->port1_start,
-			 card->port1_end - card->port1_start);
-
-    if (card->ports[0] == NULL) {
-	printk (KERN_ERR "NM256: Unable to remap port 1\n");
-	release_region ((unsigned long) card->ports[1], NM_PORT2_SIZE);
+    if (nm256_remap_ports (card)) {
 	kfree_s (card, sizeof (struct nm256_info));
 	return 0;
     }
@@ -911,9 +1146,7 @@
     card->has_irq = 0;
 
     if (nm256_grabInterrupt (card) != 0) {
-	release_region ((unsigned long) card->ports[0], 
-			card->port1_end - card->port1_start);
-	release_region ((unsigned long) card->ports[1], NM_PORT2_SIZE);
+	nm256_release_ports (card);
 	kfree_s (card, sizeof (struct nm256_info));
 	return 0;
     }
@@ -924,10 +1157,36 @@
      *	Init the board.
      */
 
+    card->playbackBufferSize = 16384;
+    card->recordBufferSize = 16384;
+
+    card->coeffBuf = card->port[0].end_offset - NM_MAX_COEFFICIENT;
+    card->abuf2 = card->coeffBuf - card->recordBufferSize;
+    card->abuf1 = card->abuf2 - card->playbackBufferSize;
+    card->allCoeffBuf = card->abuf2 - (NM_TOTAL_COEFF_COUNT * 4);
+
+    /* Fixed setting. */
+    card->mixer = NM_MIXER_OFFSET;
+    card->mixer_values_init = 0;
+
+    card->is_open_play = 0;
+    card->is_open_record = 0;
+
+    card->coeffsCurrent = 0;
+
+    card->opencnt[0] = 0; card->opencnt[1] = 0;
+
+    /* Reasonable default settings, but largely unnecessary. */
+    for (x = 0; x < 2; x++) {
+	card->sinfo[x].bits = 8;
+	card->sinfo[x].stereo = 0;
+	card->sinfo[x].samplerate = 8000;
+    }
+
     nm256_initHw (card);
 
     for (x = 0; x < 2; x++) {
-	if ((card->dev[x] = 
+	if ((card->dev[x] =
 	     sound_install_audiodrv(AUDIO_DRIVER_VERSION,
 				    "NM256", &nm256_audio_driver,
 				    sizeof(struct audio_driver),
@@ -940,9 +1199,7 @@
 	}
 	else {
 	    printk(KERN_ERR "NM256: Too many PCM devices available\n");
-	    release_region ((unsigned long) card->ports[0], 
-			    card->port1_end - card->port1_start);
-	    release_region ((unsigned long) card->ports[1], NM_PORT2_SIZE);
+	    nm256_release_ports (card);
 	    kfree_s (card, sizeof (struct nm256_info));
 	    return 0;
 	}
@@ -964,6 +1221,48 @@
     return 1;
 }
 
+
+#ifdef CONFIG_APM
+/*
+ * APM event handler, so the card is properly reinitialized after a power
+ * event.
+ */
+static int
+handle_apm_event (apm_event_t event)
+{
+    static int down = 0;
+
+    switch (event)
+	{
+	case APM_SYS_SUSPEND:
+	case APM_USER_SUSPEND:
+	    down++;
+	    break;
+	case APM_NORMAL_RESUME:
+	case APM_CRITICAL_RESUME:
+	    if (down)
+		{
+		    struct nm256_info *crd;
+
+		    down = 0;
+		    for (crd = nmcard_list;  crd != NULL; crd = crd->next_card)
+			{
+			    int playing = crd->playing;
+			    nm256_full_reset (crd);
+			    /*
+			     * A little ugly, but that's ok; pretend the
+			     * block we were playing is done. 
+			     */
+			    if (playing)
+				DMAbuf_outputintr (crd->dev_for_play, 1);
+			}
+		}
+	    break;
+	}
+    return 0;
+}
+#endif
+
 /*
  * 	This loop walks the PCI configuration database and finds where
  *	the sound cards are.
@@ -993,6 +1292,10 @@
     if (count == 0)
 	return -ENODEV;
 
+#ifdef CONFIG_APM
+    apm_register_callback (&handle_apm_event);
+#endif
+
     printk (KERN_INFO "Done installing NM256 audio driver.\n");
     return 0;
 }
@@ -1028,10 +1331,13 @@
     if (! ((mode & OPEN_READ) || (mode & OPEN_WRITE)))
 	return -EIO;
 
-    /* If it's open for both read and write, and the card's currently
-       being read or written to, then do the opposite of what has
-       already been done.  Otherwise, don't specify any mode until the
-       user actually tries to do I/O. */
+    /*
+     * If it's open for both read and write, and the card's currently
+     * being read or written to, then do the opposite of what has
+     * already been done.  Otherwise, don't specify any mode until the
+     * user actually tries to do I/O.  (Some programs open the device
+     * for both read and write, but only actually do reading or writing.)
+     */
 
     if ((mode & OPEN_WRITE) && (mode & OPEN_READ)) {
 	if (card->is_open_play)
@@ -1105,6 +1411,7 @@
     }
 }
 
+/* Standard ioctl handler. */
 static int
 nm256_audio_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
@@ -1122,6 +1429,11 @@
     else
 	w = 1;
 
+    /* 
+     * The code here is messy.  There are probably better ways to do
+     * it.  (It should be possible to handle it the same way the AC97 mixer 
+     * is done.)
+     */
     switch (cmd)
 	{
 	case SOUND_PCM_WRITE_RATE:
@@ -1193,8 +1505,12 @@
     return put_user(ret, (int *) arg);
 }
 
-/* Given the dev DEV and an associated physical buffer PHYSBUF, return
-   a pointer to the actual buffer in kernel space. */
+/*
+ * Given the sound device DEV and an associated physical buffer PHYSBUF, 
+ * return a pointer to the actual buffer in kernel space. 
+ *
+ * This routine should exist as part of the soundcore routines.
+ */
 
 static char *
 nm256_getDMAbuffer (int dev, unsigned long physbuf)
@@ -1238,9 +1554,10 @@
     }
 }
 
+/* Ditto, but do recording instead.  */
 static void
 nm256_audio_start_input(int dev, unsigned long physbuf, int count,
-			  int intrflag)
+			int intrflag)
 {
     struct nm256_info *card = nm256_find_card (dev);
 
@@ -1252,6 +1569,12 @@
     }
 }
 
+/* 
+ * Prepare for inputting samples to DEV. 
+ * Each requested buffer will be BSIZE byes long, with a total of
+ * BCOUNT buffers. 
+ */
+
 static int
 nm256_audio_prepare_for_input(int dev, int bsize, int bcount)
 {
@@ -1278,6 +1601,7 @@
  *  2. We get a write buffer without dma_mode setup     (dmabuf.c:1152)
  *  3. We restart a transfer                            (dmabuf.c:1324)
  */
+
 static int
 nm256_audio_prepare_for_output(int dev, int bsize, int bcount)
 {
@@ -1342,12 +1666,13 @@
 MODULE_PARM (usecache, "i");
 MODULE_PARM (buffertop, "i");
 MODULE_PARM (nm256_debug, "i");
+MODULE_PARM (force_load, "i");
 
 int
 init_module (void)
 {
     nmcard_list = NULL;
-    printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.0\n");
+    printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.1\n");
 
     if (init_nm256 () == 0) {
 	SOUND_LOCK;
@@ -1372,9 +1697,7 @@
 	    stopRecord (card);
 	    if (card->has_irq)
 		free_irq (card->irq, card);
-	    release_region ((unsigned long) card->ports[0], 
-			    card->port1_end - card->port1_start);
-	    release_region ((unsigned long) card->ports[1], NM_PORT2_SIZE);
+	    nm256_release_ports (card);
 	    sound_unload_mixerdev (card->mixer_oss_dev);
 	    sound_unload_audiodev (card->dev[0]);
 	    sound_unload_audiodev (card->dev[1]);
@@ -1383,6 +1706,9 @@
 	}
 	nmcard_list = NULL;
     }
+#ifdef CONFIG_APM
+    apm_unregister_callback (&handle_apm_event);
+#endif
 }
 #endif
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/nm256_coeff.h linux.14p16/drivers/sound/nm256_coeff.h
--- linux.vanilla/drivers/sound/nm256_coeff.h	Wed Oct 20 01:12:48 1999
+++ linux.14p16/drivers/sound/nm256_coeff.h	Mon Dec 13 19:29:12 1999
@@ -4622,7 +4622,8 @@
 }
 
 static void
-nm256_loadOneCoefficient (struct nm256_info *card, u32 port, u16 which)
+nm256_loadOneCoefficient (struct nm256_info *card, int devnum, u32 port, 
+			  u16 which)
 {
     u32 coeffBuf = (which < 8) ? card->coeffBuf : card->allCoeffBuf;
     u16 offset = nm256_getStartOffset (which);
@@ -4631,11 +4632,14 @@
     card->coeffsCurrent = 0;
 
     if (nm256_debug)
-	printk (KERN_INFO "NM256: Loading coefficient buffer 0x%x-0x%x with coefficient %d\n",
-		coeffBuf, coeffBuf + size - 1, which);
+	printk (KERN_INFO "NM256: Loading coefficient buffer 0x%x-0x%x with coefficient %d, size %d, port 0x%x\n",
+		coeffBuf, coeffBuf + size - 1, which, size, port);
     nm256_writeBuffer8 (card, coefficients + offset, 1, coeffBuf, size);
     nm256_writePort32 (card, 2, port + 0, coeffBuf);
-    nm256_writePort32 (card, 2, port + 4, coeffBuf + size - 1);
+    /* ???  Record seems to behave differently than playback.  */
+    if (devnum == 0)
+	size--;
+    nm256_writePort32 (card, 2, port + 4, coeffBuf + size);
 }
 
 static void
@@ -4663,7 +4667,7 @@
 	number += 8;
 
     if (! nm256_cachedCoefficients (card))
-	nm256_loadOneCoefficient (card, addrs[which], number);
+	nm256_loadOneCoefficient (card, which, addrs[which], number);
     else {
 	u32 base = card->allCoeffBuf;
 	u32 offset = nm256_getStartOffset (number);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/opl3.c linux.14p16/drivers/sound/opl3.c
--- linux.vanilla/drivers/sound/opl3.c	Wed Aug 19 22:48:30 1998
+++ linux.14p16/drivers/sound/opl3.c	Thu Dec  9 15:34:01 1999
@@ -32,8 +32,6 @@
 #include "sound_config.h"
 #include "soundmodule.h"
 
-#ifdef CONFIG_YM3812
-
 #include "opl3.h"
 
 #define MAX_VOICE	18
@@ -1223,5 +1221,3 @@
 EXPORT_SYMBOL(opl3_init);
 EXPORT_SYMBOL(opl3_detect);
 MODULE_PARM(io, "i");
-
-#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sb_audio.c linux.14p16/drivers/sound/sb_audio.c
--- linux.vanilla/drivers/sound/sb_audio.c	Fri Jan 15 06:59:47 1999
+++ linux.14p16/drivers/sound/sb_audio.c	Thu Dec  9 15:34:01 1999
@@ -460,7 +460,7 @@
 			speed = 44100;
 		if (devc->opened & OPEN_READ && speed > 15000)
 			speed = 15000;
-		devc->tconst = ((65536 - ((256000000 + s / 2) / s)) >> 8) & 0xff;
+		devc->tconst = (256 - ((1000000 + s / 2) / s)) & 0xff;
 		tmp = 256 - devc->tconst;
 		speed = ((1000000 + tmp / 2) / tmp) / devc->channels;
 
@@ -591,7 +591,7 @@
 		if (speed > 44100)
 			speed = 44100;
 
-		devc->tconst = ((65536 - ((256000000 + s / 2) / s)) >> 8) & 0xff;
+		devc->tconst = (256 - ((1000000 + s / 2) / s)) & 0xff;
 
 		tmp = 256 - devc->tconst;
 		speed = ((1000000 + tmp / 2) / tmp) / devc->channels;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sb_ess.c linux.14p16/drivers/sound/sb_ess.c
--- linux.vanilla/drivers/sound/sb_ess.c	Sat Aug 28 20:00:58 1999
+++ linux.14p16/drivers/sound/sb_ess.c	Thu Dec  9 15:34:01 1999
@@ -10,29 +10,29 @@
  *
  * History:
  *
- * Rolf Fokkens	(Dec 20 1998):	ES188x recording level support on a per
+ * Rolf Fokkens	 (Dec 20 1998):	ES188x recording level support on a per
  * fokkensr@vertis.nl			input basis.
- *				(Dec 24 1998):	Recognition of ES1788, ES1887, ES1888,
+ *				 (Dec 24 1998):	Recognition of ES1788, ES1887, ES1888,
  *								ES1868, ES1869 and ES1878. Could be used for
  *								specific handling in the future. All except
  *								ES1887 and ES1888 and ES688 are handled like
  *								ES1688.
- *				(Dec 27 1998):	RECLEV for all (?) ES1688+ chips. ES188x now
+ *				 (Dec 27 1998):	RECLEV for all (?) ES1688+ chips. ES188x now
  *								have the "Dec 20" support + RECLEV
- *				(Jan  2 1999):	Preparation for Full Duplex. This means
+ *				 (Jan  2 1999):	Preparation for Full Duplex. This means
  *								Audio 2 is now used for playback when dma16
  *								is specified. The next step would be to use
  *								Audio 1 and Audio 2 at the same time.
- *				(Jan  9 1999):	Put all ESS stuff into sb_ess.[ch], this
+ *				 (Jan  9 1999):	Put all ESS stuff into sb_ess.[ch], this
  *								includes both the ESS stuff that has been in
  *								sb_*[ch] before I touched it and the ESS support
  *								I added later
- *				(Jan 23 1999):	Full Duplex seems to work. I wrote a small
+ *				 (Jan 23 1999):	Full Duplex seems to work. I wrote a small
  *								test proggy which works OK. Haven't found
  *								any applications to test it though. So why did
  *								I bother to create it anyway?? :) Just for
  *								fun.
- *				(May  2 1999):	I tried to be too smart by "introducing"
+ *				 (May  2 1999):	I tried to be too smart by "introducing"
  *								ess_calc_best_speed (). The idea was that two
  *								dividers could be used to setup a samplerate,
  *								ess_calc_best_speed () would choose the best.
@@ -40,10 +40,12 @@
  *								recording problems for high samplerates. I
  *								fixed this by removing ess_calc_best_speed ()
  *								and just doing what the documentation says. 
- * Andy Sloane  (June 4 1999):  Stole some code from ALSA to fix the playback
+ * Andy Sloane   (Jun  4 1999): Stole some code from ALSA to fix the playback
  * andy@guildsoftware.com		speed on ES1869, ES1879, ES1887, and ES1888.
  * 								1879's were previously ignored by this driver;
  * 								added (untested) support for those.
+ * Cvetan Ivanov (Oct 27 1999): Fixed ess_dsp_init to call ess_set_dma_hw for
+ * zezo@inet.bg					_ALL_ ESS models, not only ES1887
  *
  * This files contains ESS chip specifics. It's based on the existing ESS
  * handling as it resided in sb_common.c, sb_mixer.c and sb_audio.c. This
@@ -52,7 +54,7 @@
  * - RECLEV support for ES1688 and later
  * - 6 bits playback level support chips later than ES1688
  * - Recording level support on a per-device basis for ES1887
- * - Full-Duplex for ES1887 (under development)
+ * - Full-Duplex for ES1887
  *
  * Full duplex is enabled by specifying dma16. While the normal dma must
  * be one of 0, 1 or 3, dma16 can be one of 0, 1, 3 or 5. DMA 5 is a 16 bit
@@ -1305,6 +1307,13 @@
 int ess_dsp_init (sb_devc *devc, struct address_info *hw_config)
 {
 	/*
+	 * Caller also checks this, but anyway
+	 */
+	if (devc->model != MDL_ESS) {
+		printk (KERN_INFO "ess_dsp_init for non ESS chip\n");
+		return 1;
+	}
+	/*
 	 * This for ES1887 to run Full Duplex. Actually ES1888
 	 * is allowed to do so too. I have no idea yet if this
 	 * will work for ES1888 however.
@@ -1324,15 +1333,12 @@
 		if (devc->dma8 != devc->dma16 && devc->dma16 != -1) {
 			devc->duplex = 1;
 		}
-
-		if (!ess_set_dma_hw (devc)) {
-			free_irq(devc->irq, devc);
-			return 0;
-		}
-		return 1;
-	} else {
-		return -1;
 	}
+	if (!ess_set_dma_hw (devc)) {
+		free_irq(devc->irq, devc);
+		return 0;
+	}
+	return 1;
 }
 
 /****************************************************************************
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sonicvibes.c linux.14p16/drivers/sound/sonicvibes.c
--- linux.vanilla/drivers/sound/sonicvibes.c	Wed Oct 20 01:12:48 1999
+++ linux.14p16/drivers/sound/sonicvibes.c	Thu Dec  9 15:34:02 1999
@@ -71,6 +71,14 @@
  *    15.06.99   0.15  Fix bad allocation bug.
  *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
  *    28.06.99   0.16  Add pci_set_master
+ *    03.08.99   0.17  adapt to Linus' new __setup/__initcall
+ *                     added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr"
+ *    12.08.99   0.18  module_init/__setup fixes
+ *    24.08.99   0.19  get rid of the dmaio kludge, replace with allocate_resource
+ *    31.08.99   0.20  add spin_lock_init
+ *                     __initlocaldata to fix gcc 2.7.x problems
+ *    03.09.99   0.21  change read semantics for MIDI to match
+ *                     OSS more closely; remove possible wakeup race
  *
  */
 
@@ -1265,9 +1273,9 @@
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-		tmo = (count * HZ) / s->ratedac;
+		tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
 		tmo >>= sample_shift[(s->fmt >> SV_CFMT_ASHIFT) & SV_CFMT_MASK];
-		if (!schedule_timeout(tmo ? : 1) && tmo)
+		if (!schedule_timeout(tmo + 1))
 			printk(KERN_DEBUG "sv: dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac.wait, &wait);
@@ -1870,6 +1878,7 @@
 static ssize_t sv_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct sv_state *s = (struct sv_state *)file->private_data;
+	struct wait_queue wait = { current, NULL };
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -1880,7 +1889,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+	add_wait_queue(&s->midi.iwait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.ird;
@@ -1891,15 +1903,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.iwait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+                      if (file->f_flags & O_NONBLOCK) {
+                              if (!ret)
+                                      ret = -EAGAIN;
+                              break;
+                      }
+                      current->state = TASK_INTERRUPTIBLE;
+                      schedule();
+                      if (signal_pending(current)) {
+                              if (!ret)
+                                      ret = -ERESTARTSYS;
+                              break;
+                      }
 			continue;
 		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIINBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.ird = ptr;
@@ -1908,13 +1930,17 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
+		break;
 	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&s->midi.iwait, &wait);
 	return ret;
 }
 
 static ssize_t sv_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct sv_state *s = (struct sv_state *)file->private_data;
+	struct wait_queue wait = { current, NULL };
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -1925,7 +1951,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.owait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.owr;
@@ -1938,15 +1967,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.owait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIOUTBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.owr = ptr;
@@ -1959,6 +1998,8 @@
 		sv_handle_midi(s);
 		spin_unlock_irqrestore(&s->lock, flags);
 	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&s->midi.owait, &wait);
 	return ret;
 }
 
@@ -2324,7 +2365,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "sv: version v0.16 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "sv: version v0.21 time " __TIME__ " " __DATE__ "\n");
 #if 0
 	if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
 		printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
@@ -2353,6 +2394,7 @@
 		init_waitqueue(&s->midi.iwait);
 		init_waitqueue(&s->midi.owait);
 		s->open_sem = MUTEX;
+		spin_lock_init(&s->lock);
 		s->magic = SV_MAGIC;
 		s->iosb = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
 		s->ioenh = pcidev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
@@ -2423,8 +2465,8 @@
 		wrindir(s, SV_CIDRIVECONTROL, 0);  /* drive current 16mA */
 		wrindir(s, SV_CIENABLE, s->enable = 0);  /* disable DMAA and DMAC */
 		outb(~(SV_CINTMASK_DMAA | SV_CINTMASK_DMAC), s->ioenh + SV_CODEC_INTMASK);
-		//outb(0xff, s->iodmaa + SV_DMA_RESET);
-		//outb(0xff, s->iodmac + SV_DMA_RESET);
+		/* outb(0xff, s->iodmaa + SV_DMA_RESET); */
+		/* outb(0xff, s->iodmac + SV_DMA_RESET); */
 		inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
 		wrindir(s, SV_CIADCCLKSOURCE, 0); /* use pll as ADC clock source */
 		wrindir(s, SV_CIANALOGPWRDOWN, 0); /* power up the analog parts of the device */
@@ -2524,8 +2566,8 @@
 		synchronize_irq();
 		inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
 		wrindir(s, SV_CIENABLE, 0);     /* disable DMAA and DMAC */
-		//outb(0, s->iodmaa + SV_DMA_RESET);
-		//outb(0, s->iodmac + SV_DMA_RESET);
+		/*outb(0, s->iodmaa + SV_DMA_RESET);*/
+		/*outb(0, s->iodmac + SV_DMA_RESET);*/
 		free_irq(s->irq, s);
 		release_region(s->iodmac, SV_EXTENT_DMA);
 		release_region(s->iodmaa, SV_EXTENT_DMA);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sound_core.c linux.14p16/drivers/sound/sound_core.c
--- linux.vanilla/drivers/sound/sound_core.c	Sat Aug 28 20:00:58 1999
+++ linux.14p16/drivers/sound/sound_core.c	Thu Dec  9 15:34:01 1999
@@ -55,6 +55,9 @@
 #ifdef CONFIG_SOUND_SONICVIBES
 extern int init_sonicvibes(void);
 #endif
+#ifdef CONFIG_SOUND_MAESTRO
+extern int init_maestro(void);
+#endif
 #ifdef CONFIG_SOUND_ES1370
 extern int init_es1370(void);
 #endif
@@ -409,6 +412,9 @@
 #endif
 #ifdef CONFIG_SOUND_ES1371
 	init_es1371();
+#endif
+#ifdef CONFIG_SOUND_MAESTRO
+	init_maestro();
 #endif
 #ifdef CONFIG_SOUND_MSNDCLAS
 	msnd_classic_init();
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sscape.c linux.14p16/drivers/sound/sscape.c
--- linux.vanilla/drivers/sound/sscape.c	Sat Aug 14 02:25:43 1999
+++ linux.14p16/drivers/sound/sscape.c	Thu Dec  9 15:34:01 1999
@@ -3,7 +3,6 @@
  *
  * Low level driver for Ensoniq SoundScape
  */
-
 /*
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
@@ -11,9 +10,10 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
-
+ 
 /*
- * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ * Thomas Sailer   	: ioctl code reworked (vmalloc/vfree removed)
+ * Sergey Smitienko	: ensoniq p'n'p support
  */
 
 #include <linux/config.h>
@@ -21,6 +21,26 @@
 
 #include "sound_config.h"
 #include "soundmodule.h"
+#include "sound_firmware.h"
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/ctype.h>
+#include <linux/stddef.h>
+#include <linux/kmod.h>
+#ifdef __KERNEL__
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <linux/wait.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#endif				/* __KERNEL__ */
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+
 
 #ifdef CONFIG_SSCAPE
 
@@ -71,10 +91,10 @@
 #define CMD_GET_BOARD_TYPE	0x82
 #define CMD_SET_CONTROL		0x88	/* Old firmware only */
 #define CMD_GET_CONTROL		0x89	/* Old firmware only */
-#define 	CTL_MASTER_VOL		0
-#define 	CTL_MIC_MODE		2
-#define 	CTL_SYNTH_VOL		4
-#define 	CTL_WAVE_VOL		7
+#define CTL_MASTER_VOL		0
+#define CTL_MIC_MODE		2
+#define CTL_SYNTH_VOL		4
+#define CTL_WAVE_VOL		7
 #define CMD_SET_EXTMIDI		0x8a
 #define CMD_GET_EXTMIDI		0x8b
 #define CMD_SET_MT32		0x8c
@@ -82,9 +102,20 @@
 
 #define CMD_ACK			0x80
 
+#define	IC_ODIE			1
+#define	IC_OPUS			2
+
 typedef struct sscape_info
 {
 	int	base, irq, dma;
+	
+	int	codec, codec_irq;	/* required to setup pnp cards*/
+	int	codec_type;
+	int	ic_type;
+	char*	raw_buf;
+	unsigned long	raw_buf_phys;
+	int	buffsize;		/* -------------------------- */
+	
 	int	ok;	/* Properly detected */
 	int	failed;
 	int	dma_allocated;
@@ -152,6 +183,31 @@
 	restore_flags(flags);
 }
 
+static unsigned char sscape_pnp_read_codec(sscape_info* devc, unsigned char reg)
+{
+	unsigned char res;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();	
+	outb( reg, devc -> codec);
+	res = inb (devc -> codec + 1);
+	restore_flags(flags);
+	return res;
+
+}
+
+static void sscape_pnp_write_codec(sscape_info* devc, unsigned char reg, unsigned char data)
+{
+	unsigned long flags;
+	
+	save_flags(flags);
+	cli();
+	outb( reg, devc -> codec);
+	outb( data, devc -> codec + 1);
+	restore_flags(flags);
+}
+
 static void host_open(struct sscape_info *devc)
 {
 	outb((0x00), PORT(HOST_CTRL));	/* Put the board to the host mode */
@@ -218,6 +274,13 @@
 	return data;
 }
 
+static int host_command1(struct sscape_info *devc, int cmd)
+{
+	unsigned char buf[10];
+	buf[0] = (unsigned char) (cmd & 0xff);
+	return host_write(devc, buf, 1);
+}
+
 
 static int host_command2(struct sscape_info *devc, int cmd, int parm1)
 {
@@ -544,6 +607,7 @@
 };
 
 static int sscape_detected = 0;
+static int sscape_is_pnp   = 0;
 
 void attach_sscape(struct address_info *hw_config)
 {
@@ -563,14 +627,14 @@
 	 */
 #define SSCAPE_REGS { \
 /* I0 */	0x00, \
-		0xf0, /* Note! Ignored. Set always to 0xf0 */ \
-		0x20, /* Note! Ignored. Set always to 0x20 */ \
-		0x20, /* Note! Ignored. Set always to 0x20 */ \
-		0xf5, /* Ignored */ \
-		0x10, \
-		0x00, \
-		0x2e, /* I7 MEM config A. Likely to vary between models */ \
-		0x00, /* I8 MEM config B. Likely to vary between models */ \
+/* I1 */	0xf0, /* Note! Ignored. Set always to 0xf0 */ \
+/* I2 */	0x20, /* Note! Ignored. Set always to 0x20 */ \
+/* I3 */	0x20, /* Note! Ignored. Set always to 0x20 */ \
+/* I4 */	0xf5, /* Ignored */ \
+/* I5 */	0x10, \
+/* I6 */	0x00, \
+/* I7 */	0x2e, /* I7 MEM config A. Likely to vary between models */ \
+/* I8 */	0x00, /* I8 MEM config B. Likely to vary between models */ \
 /* I9 */	0x40 /* Ignored */ \
 	}
 #endif
@@ -605,11 +669,13 @@
 		printk(KERN_ERR "Invalid IRQ%d\n", hw_config->irq);
 		return;
 	}
-	save_flags(flags);
-	cli();
-
-	for (i = 1; i < 10; i++)
-	{
+	
+	if (sscape_is_pnp == 0) {
+	
+	    save_flags(flags);
+	    cli();
+	    for (i = 1; i < 10; i++)
+	    {
 		switch (i)
 		{
 			case 1:	/* Host interrupt enable */
@@ -640,9 +706,9 @@
 			default:
 				sscape_write(devc, i, regs[i]);
 		}
+	    }
+	    restore_flags(flags);
 	}
-	restore_flags(flags);
-
 #ifdef SSCAPE_DEBUG2
 	/*
 	 * Temporary debugging aid. Print contents of the registers after
@@ -733,6 +799,452 @@
 	return 1;
 }
 
+static	int sscape_read_host_ctrl(sscape_info* devc)
+{
+	return host_read(devc);
+}
+
+static	void sscape_write_host_ctrl2(sscape_info *devc, int a, int b)
+{
+	host_command2(devc, a, b);
+}
+
+static int sscape_alloc_dma(sscape_info *devc)
+{
+	char *start_addr, *end_addr;
+	int i, dma_pagesize;
+	int sz, size;
+
+	if (devc->raw_buf != NULL) return 0;	/* Already done */
+	dma_pagesize = (devc->dma < 4) ? (64 * 1024) : (128 * 1024);
+	devc->raw_buf = NULL;
+	devc->buffsize = 8192*4;
+	if (devc->buffsize > dma_pagesize) devc->buffsize = dma_pagesize;
+	start_addr = NULL;
+	/*
+	 * Now loop until we get a free buffer. Try to get smaller buffer if
+	 * it fails. Don't accept smaller than 8k buffer for performance
+	 * reasons.
+	 */
+	while (start_addr == NULL && devc->buffsize > PAGE_SIZE) {
+		for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1);
+		devc->buffsize = PAGE_SIZE * (1 << sz);
+		start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA, sz);
+		if (start_addr == NULL) devc->buffsize /= 2;
+	}
+
+	if (start_addr == NULL) {
+		printk(KERN_ERR "sscape pnp init error: Couldn't allocate DMA buffer\n");
+		return 0;
+	} else {
+		/* make some checks */
+		end_addr = start_addr + devc->buffsize - 1;		
+		/* now check if it fits into the same dma-pagesize */
+
+		if (((long) start_addr & ~(dma_pagesize - 1)) != ((long) end_addr & ~(dma_pagesize - 1))
+		    || end_addr >= (char *) (MAX_DMA_ADDRESS)) {
+			printk(KERN_ERR "sscape pnp: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, devc->buffsize);
+			return 0;
+		}
+	}
+	devc->raw_buf = start_addr;
+	devc->raw_buf_phys = virt_to_bus(start_addr);
+
+	for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++)
+		set_bit(PG_reserved, &mem_map[i].flags);;
+	return 1;
+}
+
+static void sscape_free_dma(sscape_info *devc)
+{
+	int sz, size, i;
+	unsigned long start_addr, end_addr;
+
+	if (devc->raw_buf == NULL) return;
+	for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1);
+	start_addr = (unsigned long) devc->raw_buf;
+	end_addr = start_addr + devc->buffsize;
+
+	for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++)
+		clear_bit(PG_reserved, &mem_map[i].flags);;
+
+	free_pages((unsigned long) devc->raw_buf, sz);
+	devc->raw_buf = NULL;
+}
+
+/* Intel version !!!!!!!!! */
+
+static int sscape_start_dma(int chan, unsigned long physaddr, int count, int dma_mode)
+{
+	unsigned long flags;
+
+	flags = claim_dma_lock();
+	disable_dma(chan);
+	clear_dma_ff(chan);
+	set_dma_mode(chan, dma_mode);
+	set_dma_addr(chan, physaddr);
+	set_dma_count(chan, count);
+	enable_dma(chan);
+	release_dma_lock(flags);
+	return 0;
+}
+
+static void sscape_pnp_start_dma(sscape_info* devc, int arg )
+{
+	int reg;
+	if (arg == 0) reg = 2;
+	else reg = 3;
+
+	sscape_write(devc, reg, sscape_read( devc, reg) | 0x01);
+	sscape_write(devc, reg, sscape_read( devc, reg) & 0xFE);
+}
+
+static int sscape_pnp_wait_dma (sscape_info* devc, int arg )
+{
+	int		reg;
+	unsigned long	i;
+	unsigned char	d;
+
+	if (arg == 0) reg = 2;
+	else reg = 3;
+
+	sleep ( 1 );
+	i = 0;
+	do {
+		d = sscape_read(devc, reg) & 1;
+		if ( d == 1)  break;
+		i++;
+	} while (i < 500000);
+	d = sscape_read(devc, reg) & 1; 
+	return d;
+}
+
+static	int	sscape_pnp_alloc_dma(sscape_info* devc)
+{
+	/* printk(KERN_INFO "sscape: requesting dma\n"); */
+	if (request_dma(devc -> dma, "sscape")) return 0;
+	/* printk(KERN_INFO "sscape: dma channel allocated\n"); */
+	if (!sscape_alloc_dma(devc)) {
+		free_dma(devc -> dma);
+		return 0;
+	};
+	return 1;
+}
+
+static	void	sscape_pnp_free_dma(sscape_info* devc)
+{
+	sscape_free_dma( devc);
+	free_dma(devc -> dma );	
+	/* printk(KERN_INFO "sscape: dma released\n"); */
+}
+
+static	int	sscape_pnp_upload_file(sscape_info* devc, char* fn)
+{	
+	int	     	done = 0;
+	int	     	timeout_val;
+	char*	     	data,*dt;
+	int	     	len,l;
+	unsigned long	flags;
+
+	sscape_write( devc, 9, sscape_read(devc, 9 )  & 0x3F );
+	sscape_write( devc, 2, (devc -> dma << 4) | 0x80 );
+	sscape_write( devc, 3, 0x20 );
+	sscape_write( devc, 9, sscape_read( devc, 9 )  | 0x80 );
+	
+	len = mod_firmware_load(fn, &data);
+	if (len == 0) {
+		    printk(KERN_ERR "sscape: file not found: %s\n", fn);
+		    return 0;
+	}
+	dt = data;
+	save_flags(flags);
+	cli();
+	while ( len > 0 ) {
+		if (len > devc -> buffsize) l = devc->buffsize;
+		else l = len;
+		len -= l;		
+		memcpy(devc->raw_buf, dt, l); dt += l;
+		sscape_start_dma(devc->dma, devc->raw_buf_phys, l, 0x48);
+		sscape_pnp_start_dma ( devc, 0 );
+		if (sscape_pnp_wait_dma ( devc, 0 ) == 0) return 0;
+	}
+	
+	restore_flags(flags);	    
+	vfree(data);
+	
+	outb(0, devc -> base + 2);
+	outb(0, devc -> base);
+
+	sscape_write ( devc, 9, sscape_read( devc, 9 ) | 0x40);
+
+	timeout_val = 5 * HZ; 
+	while (!done && timeout_val-- > 0)
+	{
+		unsigned char x;
+		sleep(1);
+		x = inb( devc -> base + 3);
+		if (x == 0xff || x == 0xfe)		/* OBP startup acknowledge */
+		{
+			//printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x);
+			done = 1;
+		}
+	}
+	timeout_val = 5 * HZ;
+	done = 0;
+	while (!done && timeout_val-- > 0)
+	{
+		unsigned char x;
+		sleep(1);
+		x = inb( devc -> base + 3);
+		if (x == 0xfe)		/* OBP startup acknowledge */
+		{
+			//printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x);
+			done = 1;
+		}
+	}
+
+	if ( !done ) printk(KERN_ERR "soundscape: OBP Initialization failed.\n");
+
+	sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40);
+	sscape_write( devc, 3, (devc -> dma << 4) + 0x80);
+	return 1;
+}
+
+static	void	sscape_pnp_init_hw(sscape_info* devc)
+{	
+	unsigned char midi_irq = 0, sb_irq = 0;
+	unsigned i;
+	static	char code_file_name[23] = "/sndscape/sndscape.cox";
+	
+	int sscape_sb_enable		= 0;
+	int sscape_joystic_enable	= 0x7f;
+	int sscape_mic_enable		= 0;
+	int sscape_ext_midi		= 0;		
+
+	if ( !sscape_pnp_alloc_dma(devc) ) {
+		printk(KERN_ERR "sscape: faild to allocate dma\n");
+		return;
+	}
+
+	for (i = 0; i < 4; i++) {
+		if ( devc -> irq   == valid_interrupts[i] ) 
+			midi_irq = i;
+		if ( devc -> codec_irq == valid_interrupts[i] ) 
+			sb_irq = i;
+	}
+
+	sscape_write( devc, 5, 0x50);
+	sscape_write( devc, 7, 0x2e);
+	sscape_write( devc, 8, 0x00);
+
+	sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40);
+	sscape_write( devc, 3, ( devc -> dma << 4) | 0x80);
+
+	if ( sscape_sb_enable )
+		sscape_write (devc, 4, 0xF0 | (sb_irq << 2) | midi_irq);
+	else	
+		sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq);
+
+	i = 0x10; //sscape_read(devc, 9) & (devc->ic_type == IC_ODIE ? 0xf0 : 0xc0);
+	if ( sscape_sb_enable )
+		i |= devc->ic_type == IC_ODIE ? 0x05 : 0x07;	    
+	if (sscape_joystic_enable) i |= 8;
+	
+	sscape_write (devc, 9, i);
+	sscape_write (devc, 6, 0x80);
+	sscape_write (devc, 1, 0x80);
+
+	if (devc -> codec_type == 2) {
+		sscape_pnp_write_codec( devc, 0x0C, 0x50);
+		sscape_pnp_write_codec( devc, 0x10, sscape_pnp_read_codec( devc, 0x10) & 0x3F);
+		sscape_pnp_write_codec( devc, 0x11, sscape_pnp_read_codec( devc, 0x11) | 0xC0);
+		sscape_pnp_write_codec( devc, 29, 0x20);
+	}
+
+	if (sscape_pnp_upload_file(devc, "/sndscape/scope.cod") == 0 ) {
+		printk(KERN_ERR "sscape: faild to upload file /sndscape/scope.cod\n");
+		sscape_pnp_free_dma(devc);
+		return;
+	}
+
+	i = sscape_read_host_ctrl( devc );
+	
+	if ( (i & 0x0F) >  7 ) {
+		printk(KERN_ERR "sscape: scope.cod faild\n");
+		sscape_pnp_free_dma(devc);
+		return;
+	}
+	if ( i & 0x10 ) sscape_write( devc, 7, 0x2F);
+	code_file_name[21] = (char) ( i & 0x0F) + 0x30;
+	if (sscape_pnp_upload_file( devc, code_file_name) == 0) {
+		printk(KERN_ERR "sscape: faild to upload file %s\n", code_file_name);
+		sscape_pnp_free_dma(devc);
+		return;
+	}
+	
+	if (devc->ic_type != IC_ODIE) {
+		sscape_pnp_write_codec( devc, 10, (sscape_pnp_read_codec(devc, 10) & 0x7f) |
+		 ( sscape_mic_enable == 0 ? 0x00 : 0x80) );
+	}
+	sscape_write_host_ctrl2( devc, 0x84, 0x32 );
+	sscape_write_host_ctrl2( devc, 0x86, 0x32 );
+	sscape_write_host_ctrl2( devc, 0x8A, sscape_ext_midi);
+
+	sscape_pnp_write_codec ( devc, 6, 0x3f ); //WAV_VOL
+	sscape_pnp_write_codec ( devc, 7, 0x3f ); //WAV_VOL
+	sscape_pnp_write_codec ( devc, 2, 0x1F ); //WD_CDXVOLL
+	sscape_pnp_write_codec ( devc, 3, 0x1F ); //WD_CDXVOLR
+
+	if (devc -> codec_type == 1) {
+		sscape_pnp_write_codec ( devc, 4, 0x1F );
+		sscape_pnp_write_codec ( devc, 5, 0x1F );
+		sscape_write_host_ctrl2( devc, 0x88, sscape_mic_enable);
+	} else {
+		int t;
+		sscape_pnp_write_codec ( devc, 0x10, 0x1F << 1);
+		sscape_pnp_write_codec ( devc, 0x11, 0xC0 | (0x1F << 1));
+
+		t = sscape_pnp_read_codec( devc, 0x00) & 0xDF;
+		if ( (sscape_mic_enable == 0)) t |= 0;
+		else t |= 0x20;
+		sscape_pnp_write_codec ( devc, 0x00, t);
+		t = sscape_pnp_read_codec( devc, 0x01) & 0xDF;
+		if ( (sscape_mic_enable == 0) ) t |= 0;
+		else t |= 0x20;
+		sscape_pnp_write_codec ( devc, 0x01, t);
+		sscape_pnp_write_codec ( devc, 0x40 | 29 , 0x20);
+		outb(0, devc -> codec);
+	}
+	if (devc -> ic_type == IC_OPUS ) {
+		int i = sscape_read( devc, 9 );
+		sscape_write( devc, 9, i | 3 );
+		sscape_write( devc, 3, 0x40);
+
+		if (check_region(0x228, 1)) {
+		    	    outb(0, 0x228);
+			    release_region(0x228,1);
+		}
+		sscape_write( devc, 3, (devc -> dma << 4) | 0x80);
+		sscape_write( devc, 9, i );
+	}
+	
+	host_close ( devc );
+	sscape_pnp_free_dma(devc);
+}
+
+static int	detect_sscape_pnp(sscape_info* devc)
+{
+	long	 i, irq_bits = 0xff;
+	unsigned int d;
+
+	DDB(printk("Entered detect_sscape_pnp(%x)\n", devc->base));
+
+	if (check_region(devc->base, 8)) {
+		printk(KERN_ERR "detect_sscape_pnp: port %x is not free\n", devc->base);	
+		return 0;
+	}
+		
+	if (check_region(devc->codec, 2)) {
+		printk(KERN_ERR "detect_sscape_pnp: port %x is not free\n", devc->codec);	
+		return 0;
+	}
+
+	if ( (inb( devc -> base + 2) & 0x78) != 0) return 0;
+
+	d = inb ( devc -> base + 4) & 0xF0;
+	if (  (d & 0x80) != 0)  return 0;
+	
+	if (d == 0) {
+			devc->codec_type = 1;
+			devc->ic_type = IC_ODIE;
+	}
+	else if ( (d & 0x60) != 0) {
+			devc->codec_type = 2;
+			devc->ic_type = IC_OPUS;
+	}
+	else if ( (d & 0x40) != 0) {
+			devc->codec_type = 2;
+			devc->ic_type = IC_ODIE;
+	} 
+	else return 0;
+	
+	sscape_is_pnp = 1;
+		
+	outb(0xFA, devc -> base+4);
+	if  ((inb( devc -> base+4) & 0x9F) != 0x0A)
+		return 0;
+	outb(0xFE, devc -> base+4);
+	if  ( (inb(devc -> base+4) & 0x9F) != 0x0E)
+		return 0;
+	if  ( (inb(devc -> base+5) & 0x9F) != 0x0E)
+		return 0;
+
+	if (devc->codec_type == 2) {
+		if (devc -> codec != devc -> base + 8)
+			printk("soundscape warning: incorrect codec port specified\n");
+		devc -> codec = devc -> base + 8;
+		d = 0x10 | (sscape_read(devc, 9)  & 0xCF);
+		sscape_write(devc, 9, d);
+		sscape_write(devc, 6, 0x80);
+	} else {
+		//todo: check codec is not base + 8
+	}
+
+	d  = (sscape_read(devc, 9) & 0x3F) | 0xC0;
+	sscape_write(devc, 9, d);
+
+	for (i = 0; i < 550000; i++)
+		if ( !(inb(devc -> codec) & 0x80) ) break;
+
+	d = inb(devc -> codec);
+	if (d & 0x80)
+		return 0;
+	if ( inb(devc -> codec + 2) == 0xFF)
+		return 0;
+
+	sscape_write(devc, 9, sscape_read(devc, 9)  & 0x3F );
+
+	d  = inb(devc -> codec) & 0x80;
+	if ( d == 0) {
+		printk(KERN_INFO "soundscape: hardware detected\n");
+		valid_interrupts = valid_interrupts_new;
+	} else	{
+		printk(KERN_INFO "soundscape: board looks like media fx\n");
+		valid_interrupts = valid_interrupts_old;
+		old_hardware = 1;
+	}
+
+	sscape_write( devc, 9, 0xC0 | (sscape_read(devc, 9)  & 0x3F) );
+
+	for (i = 0; i < 550000; i++)
+		if ( !(inb(devc -> codec) & 0x80)) 
+			break;
+		
+	sscape_pnp_init_hw(devc);
+
+	for (i = 0; i < sizeof(valid_interrupts); i++)
+	{
+		if (devc->codec_irq == valid_interrupts[i]) {
+			irq_bits = i;
+			break;
+		}
+	}	
+	sscape_write(devc, GA_INTENA_REG, 0x00);
+	sscape_write(devc, GA_DMACFG_REG, 0x50);
+	sscape_write(devc, GA_DMAA_REG, 0x70);
+	sscape_write(devc, GA_DMAB_REG, 0x20);
+	sscape_write(devc, GA_INTCFG_REG, 0xf0);
+	sscape_write(devc, GA_CDCFG_REG, 0x89 | (devc->dma << 4) | (irq_bits << 1));
+
+	sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 0) | 0x20);
+	sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 1) | 0x20);
+	
+	release_region(devc->codec, 2);
+	release_region(devc->base, 8);		
+		
+	return 1;	
+}
+
 int probe_sscape(struct address_info *hw_config)
 {
 
@@ -758,8 +1270,13 @@
 #endif
 	devc->failed = 1;
 
-	if (!detect_ga(devc))
-		return 0;
+	if (!detect_ga(devc)) {
+		if (detect_sscape_pnp(devc)) {		        
+			sscape_detected = hw_config->io_base;
+			return 1;
+		} 
+		else return 0;
+	}
 
 	if (old_hardware)	/* Check that it's really an old Spea/Reveal card. */
 	{
@@ -781,11 +1298,11 @@
 {
 	int i, irq_bits = 0xff;
 	int ad_flags = 0;
-
+	
 	if (devc->failed)
 	{
-		  printk(KERN_ERR "soundscape: Card not detected\n");
-		  return 0;
+		printk(KERN_ERR "soundscape: Card not detected\n");
+		return 0;
 	}
 	if (devc->ok == 0)
 	{
@@ -805,9 +1322,19 @@
 		printk(KERN_ERR "soundscape: Invalid MSS IRQ%d\n", hw_config->irq);
 		return 0;
 	}
-	if (old_hardware)
-		ad_flags = 0x12345677;	/* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */
-	return ad1848_detect(hw_config->io_base, &ad_flags, hw_config->osp);
+	
+	if (!sscape_is_pnp) {
+		if (old_hardware)
+			ad_flags = 0x12345677;	/* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */
+		return ad1848_detect(hw_config->io_base, &ad_flags, hw_config->osp);
+	} 
+	else {
+		if (old_hardware)
+			ad_flags = 0x12345677;	/* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */
+		else
+			ad_flags = 0x87654321;  /* Tell that we have a soundscape pnp with 1845 chip */
+		return ad1848_detect(hw_config->io_base, &ad_flags, hw_config->osp);
+	}
 }
 
 void attach_ss_ms_sound(struct address_info *hw_config)
@@ -820,44 +1347,52 @@
 
 	int i, irq_bits = 0xff;
 
-	hw_config->dma = devc->dma;	/* Share the DMA with the ODIE/OPUS chip */
-
-	/*
-	 * Setup the DMA polarity.
-	 */
-
-	sscape_write(devc, GA_DMACFG_REG, 0x50);
-
-	/*
-	 * Take the gate-array off of the DMA channel.
-	 */
-	
-	sscape_write(devc, GA_DMAB_REG, 0x20);
-
-	/*
-	 * Init the AD1848 (CD-ROM) config reg.
-	 */
-
-	for (i = 0; i < sizeof(valid_interrupts); i++)
-	{
-		if (hw_config->irq == valid_interrupts[i])
-		{
-			irq_bits = i;
-			break;
-		}
-	}
-	sscape_write(devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | (irq_bits << 1));
-
-	if (hw_config->irq == devc->irq)
-		printk(KERN_WARNING "soundscape: Warning! The WSS mode can't share IRQ with MIDI\n");
-
-	hw_config->slots[0] = ad1848_init("SoundScape", hw_config->io_base,
-					  hw_config->irq,
-					  hw_config->dma,
-					  hw_config->dma,
-					  0,
-					  devc->osp);
-
+ 		
+ 	if (!sscape_is_pnp)  /*pnp is already setup*/
+ 	{
+ 		/*
+     		 * Setup the DMA polarity.
+ 	    	 */
+ 		sscape_write(devc, GA_DMACFG_REG, 0x50);
+ 	
+ 		/*
+ 		 * Take the gate-array off of the DMA channel.
+ 		 */
+ 		sscape_write(devc, GA_DMAB_REG, 0x20);
+ 	
+ 		/*
+ 		 * Init the AD1848 (CD-ROM) config reg.
+ 		 */
+ 		for (i = 0; i < sizeof(valid_interrupts); i++)
+ 		{
+ 			if (hw_config->irq == valid_interrupts[i])
+ 			{
+ 				irq_bits = i;
+ 				break;
+ 			}
+ 		}	
+ 		sscape_write(devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | (irq_bits << 1));
+ 	}
+ 	
+ 	if (hw_config->irq == devc->irq)
+ 		printk(KERN_WARNING "soundscape: Warning! The WSS mode can't share IRQ with MIDI\n");
+ 				
+ 	if (! sscape_is_pnp )
+		hw_config->slots[0] = ad1848_init("SoundScape", hw_config->io_base,
+						  hw_config->irq,
+						  hw_config->dma,
+						  hw_config->dma,
+						  0,
+						  devc->osp);
+
+	else 
+		hw_config->slots[0] = ad1848_init("SoundScape PNP", hw_config->io_base,
+	 					  hw_config->irq,
+	 					  hw_config->dma,
+	 					  hw_config->dma,
+	 					  0,
+	 					  devc->osp);
+ 					  
 	if (hw_config->slots[0] != -1)	/* The AD1848 driver installed itself */
 	{
 		audio_devs[hw_config->slots[0]]->coproc = &sscape_coproc_operations;
@@ -867,6 +1402,7 @@
 		/* Set proper routings here (what are they) */
 		AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE);
 	}
+		
 #ifdef SSCAPE_DEBUG5
 	/*
 	 * Temporary debugging aid. Print contents of the registers
@@ -937,6 +1473,13 @@
 		  printk(KERN_ERR "CONFIG_MPU_IRQ must be specified if CONFIG_MPU_IO is set.\n");
 		  return -EINVAL;
 	}
+	
+	devc->codec = io;
+	devc->codec_irq = irq;
+	devc->codec_type = 0;
+	devc->ic_type = 0;
+	devc->raw_buf = NULL;
+	
 	config.irq = irq;
 	config.dma = dma;
 	config.io_base = io;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/telephony/Config.in linux.14p16/drivers/telephony/Config.in
--- linux.vanilla/drivers/telephony/Config.in	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/telephony/Config.in	Fri Dec 17 18:58:15 1999
@@ -0,0 +1,9 @@
+#
+# Telephony device configuration
+#
+mainmenu_option next_comment
+comment 'Telephony Support'
+
+tristate 'Linux telephony support' CONFIG_PHONE
+dep_tristate 'QuickNet Internet LineJack/PhoneJack support' CONFIG_PHONE_IXJ $CONFIG_PHONE
+endmenu
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/telephony/Makefile linux.14p16/drivers/telephony/Makefile
--- linux.vanilla/drivers/telephony/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/telephony/Makefile	Mon Dec 20 21:03:22 1999
@@ -0,0 +1,35 @@
+#
+# Makefile for the kernel miscellaneous drivers.
+#
+# 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 definitions are now inherited from the
+# parent makes..
+
+SUB_DIRS     := 
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+L_TARGET := telephony.a
+MX_OBJS  :=
+M_OBJS  :=
+
+ifeq ($(CONFIG_PHONE),y)
+  LX_OBJS += phonedev.o
+else
+  ifeq ($(CONFIG_PHONE),m)
+    MX_OBJS += phonedev.o
+  endif
+endif
+
+ifeq ($(CONFIG_PHONE_IXJ),y)
+  L_OBJS += ixj.o
+else 
+  ifeq ($(CONFIG_PHONE_IXJ),m)
+    M_OBJS += ixj.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/telephony/ixj.c linux.14p16/drivers/telephony/ixj.c
--- linux.vanilla/drivers/telephony/ixj.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/telephony/ixj.c	Tue Dec 21 01:28:10 1999
@@ -0,0 +1,7790 @@
+/*
+ *    ixj.c
+ *
+ *    Device Driver for the Internet PhoneJACK and
+ *    Internet LineJACK Telephony Cards.
+ *
+ *    (c) Copyright 1999 Quicknet 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.
+ *
+ * Author:          Ed Okerson, <eokerson@quicknet.net>
+ *    
+ * Contributors:    Greg Herlein, <gherlein@quicknet.net>
+ *                  David W. Erhart, <derhart@quicknet.net>
+ *                  John Sellers, <jsellers@quicknet.net>
+ *                  Mike Preston, <mpreston@quicknet.net>
+ *
+ * Fixes:
+ *
+ * More information about the hardware related to this driver can be found
+ * at our website:    http://www.quicknet.net
+ *
+ */
+
+static char ixj_c_rcsid[] = "$Id: ixj.c,v 3.4 1999/12/16 22:18:36 root Exp root $";
+
+//#define PERFMON_STATS
+#define IXJDEBUG 0
+#define MAXRINGS 5
+
+#include <linux/module.h>
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>	/* printk() */
+#include <linux/fs.h>		/* everything... */
+#include <linux/errno.h>	/* error codes */
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/tqueue.h>
+#include <linux/proc_fs.h>
+#include <linux/poll.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_ISAPNP
+#include "../pnp/pnpio.h"
+#include "../pnp/isapnp.h"
+#endif
+
+#include "ixj.h"
+
+#define TYPE(dev) (MINOR(dev) >> 4)
+#define NUM(dev) (MINOR(dev) & 0xf)
+
+static int ixjdebug = 0;
+static int hertz = HZ;
+static int samplerate = 100;
+
+MODULE_PARM(ixjdebug, "i");
+
+static IXJ ixj[IXJMAX];
+
+static struct timer_list ixj_timer;
+
+int ixj_convert_loaded = 0;
+
+/************************************************************************
+*
+* These are function definitions to allow external modules to register
+* enhanced functionality call backs.
+*
+************************************************************************/
+
+static int Stub(IXJ * J, unsigned long arg)
+{
+	return 0;
+}
+
+static IXJ_REGFUNC ixj_DownloadG729 = &Stub;
+static IXJ_REGFUNC ixj_DownloadTS85 = &Stub;
+static IXJ_REGFUNC ixj_PreRead = &Stub;
+static IXJ_REGFUNC ixj_PostRead = &Stub;
+static IXJ_REGFUNC ixj_PreWrite = &Stub;
+static IXJ_REGFUNC ixj_PostWrite = &Stub;
+static IXJ_REGFUNC ixj_PreIoctl = &Stub;
+static IXJ_REGFUNC ixj_PostIoctl = &Stub;
+
+static void ixj_read_frame(int board);
+static void ixj_write_frame(int board);
+static void ixj_init_timer(void);
+static void ixj_add_timer(void);
+static void ixj_del_timer(void);
+static void ixj_timeout(unsigned long ptr);
+static int read_filters(int board);
+static int LineMonitor(int board);
+static int ixj_fasync(int fd, struct file *, int mode);
+static int ixj_hookstate(int board);
+static int ixj_record_start(int board);
+static void ixj_record_stop(int board);
+static int ixj_play_start(int board);
+static void ixj_play_stop(int board);
+static int ixj_set_tone_on(unsigned short arg, int board);
+static int ixj_set_tone_off(unsigned short, int board);
+static int ixj_play_tone(int board, char tone);
+static int idle(int board);
+static void ixj_ring_on(int board);
+static void ixj_ring_off(int board);
+static void aec_stop(int board);
+static void ixj_ringback(int board);
+static void ixj_busytone(int board);
+static void ixj_dialtone(int board);
+static void ixj_cpt_stop(int board);
+static char daa_int_read(int board);
+static int daa_set_mode(int board, int mode);
+static int ixj_linetest(int board);
+static int ixj_daa_cid_read(int board);
+static void DAA_Coeff_US(int board);
+static void DAA_Coeff_UK(int board);
+static void DAA_Coeff_France(int board);
+static void DAA_Coeff_Germany(int board);
+static void DAA_Coeff_Australia(int board);
+static void DAA_Coeff_Japan(int board);
+static int ixj_init_filter(int board, IXJ_FILTER * jf);
+static int ixj_init_tone(int board, IXJ_TONE * ti);
+static int ixj_build_cadence(int board, IXJ_CADENCE * cp);
+// Serial Control Interface funtions
+static int SCI_Control(int board, int control);
+static int SCI_Prepare(int board);
+static int SCI_WaitHighSCI(int board);
+static int SCI_WaitLowSCI(int board);
+static DWORD PCIEE_GetSerialNumber(WORD wAddress);
+
+/************************************************************************
+CT8020/CT8021 Host Programmers Model
+Host address	Function					Access
+DSPbase +
+0-1		Aux Software Status Register (reserved)		Read Only
+2-3		Software Status Register			Read Only
+4-5		Aux Software Control Register (reserved)	Read Write
+6-7		Software Control Register			Read Write
+8-9		Hardware Status Register			Read Only
+A-B		Hardware Control Register			Read Write
+C-D Host Transmit (Write) Data Buffer Access Port (buffer input)Write Only
+E-F Host Recieve (Read) Data Buffer Access Port (buffer input)	Read Only
+************************************************************************/
+
+extern __inline__ void ixj_read_HSR(int board)
+{
+	ixj[board].hsr.bytes.low = inb_p(ixj[board].DSPbase + 8);
+	ixj[board].hsr.bytes.high = inb_p(ixj[board].DSPbase + 9);
+}
+extern __inline__ int IsControlReady(int board)
+{
+	ixj_read_HSR(board);
+	return ixj[board].hsr.bits.controlrdy ? 1 : 0;
+}
+
+extern __inline__ int IsStatusReady(int board)
+{
+	ixj_read_HSR(board);
+	return ixj[board].hsr.bits.statusrdy ? 1 : 0;
+}
+
+extern __inline__ int IsRxReady(int board)
+{
+	ixj_read_HSR(board);
+	return ixj[board].hsr.bits.rxrdy ? 1 : 0;
+}
+
+extern __inline__ int IsTxReady(int board)
+{
+	ixj_read_HSR(board);
+	return ixj[board].hsr.bits.txrdy ? 1 : 0;
+}
+
+extern __inline__ BYTE SLIC_GetState(int board)
+{
+	IXJ *j = &ixj[board];
+
+	j->pld_slicr.byte = inb_p(j->XILINXbase + 0x01);
+
+	return j->pld_slicr.bits.state;
+}
+
+static BOOL SLIC_SetState(BYTE byState, int board)
+{
+	BOOL fRetVal = FALSE;
+	IXJ *j = &ixj[board];
+
+	// Set the C1, C2, C3 & B2EN signals.
+	switch (byState) {
+	case PLD_SLIC_STATE_OC:
+		j->pld_slicw.bits.c1 = 0;
+		j->pld_slicw.bits.c2 = 0;
+		j->pld_slicw.bits.c3 = 0;
+		j->pld_slicw.bits.b2en = 0;
+		outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+		fRetVal = TRUE;
+		break;
+	case PLD_SLIC_STATE_RINGING:
+		j->pld_slicw.bits.c1 = 1;
+		j->pld_slicw.bits.c2 = 0;
+		j->pld_slicw.bits.c3 = 0;
+		j->pld_slicw.bits.b2en = 1;
+		outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+		fRetVal = TRUE;
+		break;
+	case PLD_SLIC_STATE_ACTIVE:
+		j->pld_slicw.bits.c1 = 0;
+		j->pld_slicw.bits.c2 = 1;
+		j->pld_slicw.bits.c3 = 0;
+		j->pld_slicw.bits.b2en = 0;
+		outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+		fRetVal = TRUE;
+		break;
+	case PLD_SLIC_STATE_OHT:	// On-hook transmit
+
+		j->pld_slicw.bits.c1 = 1;
+		j->pld_slicw.bits.c2 = 1;
+		j->pld_slicw.bits.c3 = 0;
+		j->pld_slicw.bits.b2en = 0;
+		outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+		fRetVal = TRUE;
+		break;
+	case PLD_SLIC_STATE_TIPOPEN:
+		j->pld_slicw.bits.c1 = 0;
+		j->pld_slicw.bits.c2 = 0;
+		j->pld_slicw.bits.c3 = 1;
+		j->pld_slicw.bits.b2en = 0;
+		outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+		fRetVal = TRUE;
+		break;
+	case PLD_SLIC_STATE_STANDBY:
+		j->pld_slicw.bits.c1 = 1;
+		j->pld_slicw.bits.c2 = 0;
+		j->pld_slicw.bits.c3 = 1;
+		j->pld_slicw.bits.b2en = 1;
+		outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+		fRetVal = TRUE;
+		break;
+	case PLD_SLIC_STATE_APR:	// Active polarity reversal
+
+		j->pld_slicw.bits.c1 = 0;
+		j->pld_slicw.bits.c2 = 1;
+		j->pld_slicw.bits.c3 = 1;
+		j->pld_slicw.bits.b2en = 0;
+		outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+		fRetVal = TRUE;
+		break;
+	case PLD_SLIC_STATE_OHTPR:	// OHT polarity reversal
+
+		j->pld_slicw.bits.c1 = 1;
+		j->pld_slicw.bits.c2 = 1;
+		j->pld_slicw.bits.c3 = 1;
+		j->pld_slicw.bits.b2en = 0;
+		outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+		fRetVal = TRUE;
+		break;
+	default:
+		fRetVal = FALSE;
+		break;
+	}
+
+	return fRetVal;
+}
+
+int ixj_register(int index, IXJ_REGFUNC regfunc)
+{
+	int cnt;
+	int retval = 0;
+	switch (index) {
+	case G729LOADER:
+		ixj_DownloadG729 = regfunc;
+		for (cnt = 0; cnt < IXJMAX; cnt++)
+			ixj_DownloadG729(&ixj[cnt], 0L);
+		break;
+	case TS85LOADER:
+		ixj_DownloadTS85 = regfunc;
+		for (cnt = 0; cnt < IXJMAX; cnt++)
+			ixj_DownloadTS85(&ixj[cnt], 0L);
+		break;
+	case PRE_READ:
+		ixj_PreRead = regfunc;
+		break;
+	case POST_READ:
+		ixj_PostRead = regfunc;
+		break;
+	case PRE_WRITE:
+		ixj_PreWrite = regfunc;
+		break;
+	case POST_WRITE:
+		ixj_PostWrite = regfunc;
+		break;
+	case PRE_IOCTL:
+		ixj_PreIoctl = regfunc;
+		break;
+	case POST_IOCTL:
+		ixj_PostIoctl = regfunc;
+		break;
+	default:
+		retval = 1;
+	}
+	return retval;
+}
+
+int ixj_unregister(int index)
+{
+	int retval = 0;
+	switch (index) {
+	case G729LOADER:
+		ixj_DownloadG729 = &Stub;
+		break;
+	case TS85LOADER:
+		ixj_DownloadTS85 = &Stub;
+		break;
+	case PRE_READ:
+		ixj_PreRead = &Stub;
+		break;
+	case POST_READ:
+		ixj_PostRead = &Stub;
+		break;
+	case PRE_WRITE:
+		ixj_PreWrite = &Stub;
+		break;
+	case POST_WRITE:
+		ixj_PostWrite = &Stub;
+		break;
+	case PRE_IOCTL:
+		ixj_PreIoctl = &Stub;
+		break;
+	case POST_IOCTL:
+		ixj_PostIoctl = &Stub;
+		break;
+	default:
+		retval = 1;
+	}
+	return retval;
+}
+
+static void ixj_init_timer(void)
+{
+	init_timer(&ixj_timer);
+	ixj_timer.function = ixj_timeout;
+	ixj_timer.data = (int) NULL;
+}
+
+static void ixj_add_timer(void)
+{
+	ixj_timer.expires = jiffies + (hertz / samplerate);
+	add_timer(&ixj_timer);
+}
+
+static void ixj_del_timer(void)
+{
+	del_timer(&ixj_timer);
+}
+
+static void ixj_tone_timeout(int board)
+{
+	IXJ *j = &ixj[board];
+	IXJ_TONE ti;
+	
+	j->tone_state++;
+	if (j->tone_state == 3) {
+		j->tone_state = 0;
+		if (j->cadence_t) {
+			j->tone_cadence_state++;
+			if (j->tone_cadence_state >= j->cadence_t->elements_used) 
+			{
+				switch (j->cadence_t->termination) 
+				{
+					case PLAY_ONCE:
+						ixj_cpt_stop(board);
+							break;
+					case REPEAT_LAST_ELEMENT:
+						j->tone_cadence_state--;
+						ixj_play_tone(board, j->cadence_t->ce[j->tone_cadence_state].index);
+						break;
+					case REPEAT_ALL:
+						j->tone_cadence_state = 0;
+						if (j->cadence_t->ce[j->tone_cadence_state].freq0) 
+						{
+							ti.tone_index = j->cadence_t->ce[j->tone_cadence_state].index;
+							ti.freq0 = j->cadence_t->ce[j->tone_cadence_state].freq0;
+							ti.gain0 = j->cadence_t->ce[j->tone_cadence_state].gain0;
+							ti.freq1 = j->cadence_t->ce[j->tone_cadence_state].freq1;
+							ti.gain1 = j->cadence_t->ce[j->tone_cadence_state].gain1;
+							ixj_init_tone(board, &ti);
+						}
+						ixj_set_tone_on(j->cadence_t->ce[0].tone_on_time, board);
+						ixj_set_tone_off(j->cadence_t->ce[0].tone_off_time, board);
+						ixj_play_tone(board, j->cadence_t->ce[0].index);
+						break;
+				}
+			} else {
+				if (j->cadence_t->ce[j->tone_cadence_state].gain0) 
+				{
+					ti.tone_index = j->cadence_t->ce[j->tone_cadence_state].index;
+					ti.freq0 = j->cadence_t->ce[j->tone_cadence_state].freq0;
+					ti.gain0 = j->cadence_t->ce[j->tone_cadence_state].gain0;
+					ti.freq1 = j->cadence_t->ce[j->tone_cadence_state].freq1;
+					ti.gain1 = j->cadence_t->ce[j->tone_cadence_state].gain1;
+					ixj_init_tone(board, &ti);
+				}
+				ixj_set_tone_on(j->cadence_t->ce[j->tone_cadence_state].tone_on_time, board);
+				ixj_set_tone_off(j->cadence_t->ce[j->tone_cadence_state].tone_off_time, board);
+				ixj_play_tone(board, j->cadence_t->ce[j->tone_cadence_state].index);
+			}
+		}
+	}
+}
+
+static void ixj_timeout(unsigned long ptr)
+{
+	int board;
+	unsigned long jifon;
+	IXJ *j;
+
+	for (board = 0; board < IXJMAX; board++) 
+	{
+		j = &ixj[board];
+
+		if (j->DSPbase) 
+		{
+#ifdef PERFMON_STATS
+			j->timerchecks++;
+#endif
+			if (j->tone_state) 
+			{
+				if (!ixj_hookstate(board)) 
+				{
+					ixj_cpt_stop(board);
+					if (j->m_hook) 
+					{
+						j->m_hook = 0;
+						j->ex.bits.hookstate = 1;
+						if (j->async_queue)
+							kill_fasync(j->async_queue, SIGIO);	// Send apps notice of change
+					}
+					goto timer_end;
+				}
+				if (j->tone_state == 1)
+					jifon = (hertz * j->tone_on_time * 25 / 100000);
+				else
+					jifon = (hertz * j->tone_on_time * 25 / 100000) +
+					    (hertz * j->tone_off_time * 25 / 100000);
+				if (jiffies < j->tone_start_jif + jifon) {
+					if (j->tone_state == 1) {
+						ixj_play_tone(board, j->tone_index);
+						if (j->dsp.low == 0x20) {
+							goto timer_end;
+						}
+					} else {
+						ixj_play_tone(board, 0);
+						if (j->dsp.low == 0x20) {
+							goto timer_end;
+						}
+					}
+				} else {
+					ixj_tone_timeout(board);
+					if (j->flags.dialtone) {
+						ixj_dialtone(board);
+					}
+					if (j->flags.busytone) {
+						ixj_busytone(board);
+						if (j->dsp.low == 0x20) {
+							goto timer_end;
+						}
+					}
+					if (j->flags.ringback) {
+						ixj_ringback(board);
+						if (j->dsp.low == 0x20) {
+							goto timer_end;
+						}
+					}
+					if (!j->tone_state) {
+						if (j->dsp.low == 0x20 || (j->play_mode == -1 && j->rec_mode == -1))
+							idle(board);
+						if (j->dsp.low == 0x20 && j->play_mode != -1)
+							ixj_play_start(board);
+						if (j->dsp.low == 0x20 && j->rec_mode != -1)
+							ixj_record_start(board);
+					}
+				}
+			}
+			if (!j->tone_state || j->dsp.low != 0x20) {
+				if (IsRxReady(board)) {
+					ixj_read_frame(board);
+				}
+				if (IsTxReady(board)) {
+					ixj_write_frame(board);
+				}
+			}
+			if (j->flags.cringing) {
+				if (ixj_hookstate(board) & 1) {
+					j->flags.cringing = 0;
+					ixj_ring_off(board);
+				} else {
+					if (jiffies - j->ring_cadence_jif >= (.5 * hertz)) {
+						j->ring_cadence_t--;
+						if (j->ring_cadence_t == -1)
+							j->ring_cadence_t = 15;
+						j->ring_cadence_jif = jiffies;
+					}
+					if (j->ring_cadence & 1 << j->ring_cadence_t) {
+						ixj_ring_on(board);
+					} else {
+						ixj_ring_off(board);
+					}
+					goto timer_end;
+				}
+			}
+			if (!j->flags.ringing) {
+				if (ixj_hookstate(board)) {
+					if (j->dsp.low == 0x21 &&
+					    j->pld_slicr.bits.state != PLD_SLIC_STATE_ACTIVE)
+               // Internet LineJACK
+					{
+						SLIC_SetState(PLD_SLIC_STATE_ACTIVE, board);
+					}
+					LineMonitor(board);
+					read_filters(board);
+					ixj_WriteDSPCommand(0x511B, board);
+					j->proc_load = j->ssr.high << 8 | j->ssr.low;
+					if (!j->m_hook) {
+						j->m_hook = j->ex.bits.hookstate = 1;
+						if (j->async_queue)
+							kill_fasync(j->async_queue, SIGIO);	// Send apps notice of change
+					}
+				} else {
+					if (j->dsp.low == 0x21 &&
+					    j->pld_slicr.bits.state == PLD_SLIC_STATE_ACTIVE)
+               // Internet LineJACK
+					{
+						SLIC_SetState(PLD_SLIC_STATE_STANDBY, board);
+					}
+					if (j->ex.bits.dtmf_ready) {
+						j->dtmf_wp = j->dtmf_rp = j->ex.bits.dtmf_ready = 0;
+					}
+					if (j->m_hook) {
+						j->m_hook = 0;
+						j->ex.bits.hookstate = 1;
+						if (j->async_queue)
+							kill_fasync(j->async_queue, SIGIO);	// Send apps notice of change
+					}
+				}
+			}
+			if (j->cardtype == 300) {
+				if (j->flags.pstn_present) {
+					j->pld_scrr.byte = inb_p(j->XILINXbase);
+					if (jiffies >= j->pstn_sleeptil && j->pld_scrr.bits.daaflag) {
+						daa_int_read(board);
+						if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.RING) {
+							if (!j->flags.pstn_ringing) {
+								j->flags.pstn_ringing = 1;
+								if (j->daa_mode != SOP_PU_RINGING)
+									daa_set_mode(board, SOP_PU_RINGING);
+							}
+						}
+						if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) {
+							j->pstn_winkstart = 0;
+							if (j->flags.pstn_ringing && !j->pstn_envelope) {
+								j->ex.bits.pstn_ring = 0;
+								j->pstn_envelope = 1;
+								j->pstn_ring_start = jiffies;
+							}
+						} else {
+							if (j->flags.pstn_ringing && j->pstn_envelope &&
+							    jiffies > j->pstn_ring_start + ((hertz * 15) / 10)) {
+								j->ex.bits.pstn_ring = 1;
+								j->pstn_envelope = 0;
+							} else if (j->daa_mode == SOP_PU_CONVERSATION) {
+								if (!j->pstn_winkstart) {
+									j->pstn_winkstart = jiffies;
+								} else if (jiffies > j->pstn_winkstart + (hertz * j->winktime / 1000)) {
+									daa_set_mode(board, SOP_PU_SLEEP);
+									j->pstn_winkstart = 0;
+									j->ex.bits.pstn_wink = 1;
+								}
+							} else {
+								j->ex.bits.pstn_ring = 0;
+							}
+						}
+						if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.Cadence) {
+							if (j->daa_mode == SOP_PU_RINGING) {
+								daa_set_mode(board, SOP_PU_SLEEP);
+								j->flags.pstn_ringing = 0;
+								j->ex.bits.pstn_ring = 0;
+							}
+						}
+						if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.Caller_ID) {
+							if (j->daa_mode == SOP_PU_RINGING && j->flags.pstn_ringing) {
+								j->pstn_cid_intr = 1;
+								j->pstn_cid_recieved = jiffies;
+							}
+						}
+					} else {
+						if (j->pld_scrr.bits.daaflag) {
+							daa_int_read(board);
+						}
+						j->ex.bits.pstn_ring = 0;
+						if (j->pstn_cid_intr && jiffies > j->pstn_cid_recieved + (hertz * 3)) {
+							if (j->daa_mode == SOP_PU_RINGING) {
+								ixj_daa_cid_read(board);
+								j->ex.bits.caller_id = 1;
+							}
+							j->pstn_cid_intr = 0;
+						} else {
+							j->ex.bits.caller_id = 0;
+						}
+						if (!j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) {
+							if (j->flags.pstn_ringing && j->pstn_envelope) {
+								j->ex.bits.pstn_ring = 1;
+								j->pstn_envelope = 0;
+							} else if (j->daa_mode == SOP_PU_CONVERSATION) {
+								if (!j->pstn_winkstart) {
+									j->pstn_winkstart = jiffies;
+								} else if (jiffies > j->pstn_winkstart + (hertz * 320 / 1000)) {
+									daa_set_mode(board, SOP_PU_SLEEP);
+									j->pstn_winkstart = 0;
+									j->ex.bits.pstn_wink = 1;
+								}
+							}
+						}
+					}
+				}
+			}
+			if ((j->ex.bits.f0 || j->ex.bits.f1 || j->ex.bits.f2 || j->ex.bits.f3)
+			    && j->filter_cadence) {
+			}
+			if (j->ex.bytes) {
+				wake_up_interruptible(&j->poll_q);	// Wake any blocked selects
+				if (j->async_queue)
+					kill_fasync(j->async_queue, SIGIO);	// Send apps notice of change
+			}
+		} else {
+			break;
+		}
+	}
+timer_end:
+	ixj_add_timer();
+}
+
+static int ixj_status_wait(int board)
+{
+	unsigned long jif;
+
+	jif = jiffies;
+	while (!IsStatusReady(board)) {
+		if (jiffies - jif > (60 * (hertz / 100))) {
+			return -1;
+		}
+	}
+	return 0;
+}
+
+int ixj_WriteDSPCommand(unsigned short cmd, int board)
+{
+	BYTES bytes;
+	unsigned long jif;
+
+	bytes.high = (cmd & 0xFF00) >> 8;
+	bytes.low = cmd & 0x00FF;
+	jif = jiffies;
+	while (!IsControlReady(board)) {
+		if (jiffies - jif > (60 * (hertz / 100))) {
+			return -1;
+		}
+	}
+	outb_p(bytes.low, ixj[board].DSPbase + 6);
+	outb_p(bytes.high, ixj[board].DSPbase + 7);
+
+	if (ixj_status_wait(board)) {
+		ixj[board].ssr.low = 0xFF;
+		ixj[board].ssr.high = 0xFF;
+		return -1;
+	}
+/* Read Software Status Register */
+	ixj[board].ssr.low = inb_p(ixj[board].DSPbase + 2);
+	ixj[board].ssr.high = inb_p(ixj[board].DSPbase + 3);
+	return 0;
+}
+
+/***************************************************************************
+*
+*  General Purpose IO Register read routine
+*
+***************************************************************************/
+extern __inline__ int ixj_gpio_read(int board)
+{
+	if (ixj_WriteDSPCommand(0x5143, board))
+		return -1;
+
+	ixj[board].gpio.bytes.low = ixj[board].ssr.low;
+	ixj[board].gpio.bytes.high = ixj[board].ssr.high;
+
+	return 0;
+}
+
+extern __inline__ void LED_SetState(int state, int board)
+{
+	if (ixj[board].dsp.low == 0x21) {
+		ixj[board].pld_scrw.bits.led1 = state & 0x1 ? 1 : 0;
+		ixj[board].pld_scrw.bits.led2 = state & 0x2 ? 1 : 0;
+		ixj[board].pld_scrw.bits.led3 = state & 0x4 ? 1 : 0;
+		ixj[board].pld_scrw.bits.led4 = state & 0x8 ? 1 : 0;
+
+		outb_p(ixj[board].pld_scrw.byte, ixj[board].XILINXbase);
+	}
+}
+
+/*********************************************************************
+*  GPIO Pins are configured as follows on the Quicknet Internet
+*  PhoneJACK Telephony Cards
+* 
+* POTS Select        GPIO_6=0 GPIO_7=0
+* Mic/Speaker Select GPIO_6=0 GPIO_7=1
+* Handset Select     GPIO_6=1 GPIO_7=0
+*
+* SLIC Active        GPIO_1=0 GPIO_2=1 GPIO_5=0
+* SLIC Ringing       GPIO_1=1 GPIO_2=1 GPIO_5=0
+* SLIC Open Circuit  GPIO_1=0 GPIO_2=0 GPIO_5=0
+*
+* Hook Switch changes reported on GPIO_3
+*********************************************************************/
+static int ixj_set_port(int board, int arg)
+{
+	IXJ *j = &ixj[board];
+
+	if (j->cardtype == 400) {
+		if (arg != PORT_POTS)
+			return 10;
+		else
+			return 0;
+	}
+	switch (arg) {
+	case PORT_POTS:
+		j->port = PORT_POTS;
+		switch (j->cardtype) {
+		case 500:
+			j->pld_slicw.pcib.mic = 0;
+			j->pld_slicw.pcib.spk = 0;
+			outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+			break;
+		case 300:
+			if (ixj_WriteDSPCommand(0xC528, board))		/* Write CODEC config to
+									   Software Control Register */
+				return 2;
+			j->pld_scrw.bits.daafsyncen = 0;	// Turn off DAA Frame Sync
+
+			outb_p(j->pld_scrw.byte, j->XILINXbase);
+			j->pld_clock.byte = 0;
+			outb_p(j->pld_clock.byte, j->XILINXbase + 0x04);
+			j->pld_slicw.bits.rly1 = 1;
+			j->pld_slicw.bits.spken = 0;
+			outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+			SLIC_SetState(PLD_SLIC_STATE_STANDBY, board);
+			break;
+		case 100:
+			j->gpio.bytes.high = 0x0B;
+			j->gpio.bits.gpio6 = 0;
+			j->gpio.bits.gpio7 = 0;
+			ixj_WriteDSPCommand(j->gpio.word, board);
+			break;
+		}
+		break;
+	case PORT_PSTN:
+		if (j->cardtype == 300) {
+			ixj_WriteDSPCommand(0xC534, board);	/* Write CODEC config to Software Control Register */
+
+			j->pld_slicw.bits.rly3 = 0;
+			j->pld_slicw.bits.rly1 = 1;
+			j->pld_slicw.bits.spken = 0;
+			outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+			j->port = PORT_PSTN;
+		} else {
+			return 4;
+		}
+		break;
+	case PORT_SPEAKER:
+		j->port = PORT_SPEAKER;
+		switch (j->cardtype) {
+		case 500:
+			j->pld_slicw.pcib.mic = 1;
+			j->pld_slicw.pcib.spk = 1;
+			outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+			break;
+		case 300:
+			break;
+		case 100:
+			j->gpio.bytes.high = 0x0B;
+			j->gpio.bits.gpio6 = 0;
+			j->gpio.bits.gpio7 = 1;
+			ixj_WriteDSPCommand(j->gpio.word, board);
+			break;
+		}
+		break;
+	case PORT_HANDSET:
+		if (j->cardtype == 300 || j->cardtype == 500) {
+			return 5;
+		} else {
+			j->gpio.bytes.high = 0x0B;
+			j->gpio.bits.gpio6 = 1;
+			j->gpio.bits.gpio7 = 0;
+			ixj_WriteDSPCommand(j->gpio.word, board);
+			j->port = PORT_HANDSET;
+		}
+		break;
+	default:
+		return 6;
+		break;
+	}
+	return 0;
+}
+
+static int ixj_set_pots(int board, int arg)
+{
+	IXJ *j = &ixj[board];
+
+	if (j->cardtype == 300) {
+		if (arg) {
+			if (j->port == PORT_PSTN) {
+				j->pld_slicw.bits.rly1 = 0;
+				outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+				return 1;
+			} else {
+				return 0;
+			}
+		} else {
+			j->pld_slicw.bits.rly1 = 1;
+			outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+			return 1;
+		}
+	} else {
+		return 0;
+	}
+}
+
+static void ixj_ring_on(int board)
+{
+	IXJ *j = &ixj[board];
+	if (j->dsp.low == 0x20)	// Internet PhoneJACK
+	 {
+		if (ixjdebug > 0)
+			printk(KERN_INFO "IXJ Ring On /dev/phone%d\n", board);
+
+		j->gpio.bytes.high = 0x0B;
+		j->gpio.bytes.low = 0x00;
+		j->gpio.bits.gpio1 = 1;
+		j->gpio.bits.gpio2 = 1;
+		j->gpio.bits.gpio5 = 0;
+		ixj_WriteDSPCommand(j->gpio.word, board);	/* send the ring signal */
+	} else			//  Internet LineJACK, Internet PhoneJACK Lite or
+              //  Internet PhoneJACK PCI
+	 {
+		if (ixjdebug > 0)
+			printk(KERN_INFO "IXJ Ring On /dev/phone%d\n", board);
+
+		SLIC_SetState(PLD_SLIC_STATE_RINGING, board);
+	}
+}
+
+static int ixj_hookstate(int board)
+{
+	unsigned long det;
+	IXJ *j = &ixj[board];
+	int fOffHook = 0;
+
+	switch (j->cardtype) {
+	case 100:
+		ixj_gpio_read(board);
+		fOffHook = j->gpio.bits.gpio3read ? 1 : 0;
+		break;
+	case 300:
+	case 400:
+	case 500:
+		SLIC_GetState(board);
+		if (j->pld_slicr.bits.state == PLD_SLIC_STATE_ACTIVE ||
+		    j->pld_slicr.bits.state == PLD_SLIC_STATE_STANDBY) 
+		{
+			if (j->flags.ringing) 
+			{
+				if(!in_interrupt())
+				{
+					det = jiffies + (hertz / 50);
+					while (time_before(jiffies, det)) {
+						current->state = TASK_INTERRUPTIBLE;
+						schedule_timeout(1);
+					}
+				}
+				SLIC_GetState(board);
+				if (j->pld_slicr.bits.state == PLD_SLIC_STATE_RINGING) {
+					ixj_ring_on(board);
+				}
+			}
+			if (j->cardtype == 500) {
+				j->pld_scrr.byte = inb_p(j->XILINXbase);
+				fOffHook = j->pld_scrr.pcib.det ? 1 : 0;
+			} else
+				fOffHook = j->pld_slicr.bits.det ? 1 : 0;
+		}
+		break;
+	}
+	if (j->r_hook != fOffHook) {
+		j->r_hook = fOffHook;
+		if (j->port != PORT_POTS) {
+			j->ex.bits.hookstate = 1;
+			if (j->async_queue)
+				kill_fasync(j->async_queue, SIGIO);	// Send apps notice of change
+
+		}
+	}
+	if (j->port == PORT_PSTN && j->daa_mode == SOP_PU_CONVERSATION)
+		fOffHook |= 2;
+
+	if (j->port == PORT_SPEAKER)
+		fOffHook |= 2;
+
+	if (j->port == PORT_HANDSET)
+		fOffHook |= 2;
+
+	return fOffHook;
+}
+
+static void ixj_ring_off(board)
+{
+	IXJ *j = &ixj[board];
+
+	if (j->dsp.low == 0x20)	// Internet PhoneJACK
+	 {
+		if (ixjdebug > 0)
+			printk(KERN_INFO "IXJ Ring Off\n");
+		j->gpio.bytes.high = 0x0B;
+		j->gpio.bytes.low = 0x00;
+		j->gpio.bits.gpio1 = 0;
+		j->gpio.bits.gpio2 = 1;
+		j->gpio.bits.gpio5 = 0;
+		ixj_WriteDSPCommand(j->gpio.word, board);
+	} else			// Internet LineJACK
+	 {
+		if (ixjdebug > 0)
+			printk(KERN_INFO "IXJ Ring Off\n");
+
+		SLIC_SetState(PLD_SLIC_STATE_STANDBY, board);	
+
+		SLIC_GetState(board);
+	}
+}
+
+static void ixj_ring_start(int board)
+{
+	IXJ *j = &ixj[board];
+
+	j->flags.cringing = 1;
+	if (ixj_hookstate(board) & 1) {
+		if (j->port == PORT_POTS)
+			ixj_ring_off(board);
+		j->flags.cringing = 0;
+	} else {
+		j->ring_cadence_jif = jiffies;
+		j->ring_cadence_t = 15;
+		if (j->ring_cadence & 1 << j->ring_cadence_t) {
+			ixj_ring_on(board);
+		} else {
+			ixj_ring_off(board);
+		}
+	}
+}
+
+static int ixj_ring(int board)
+{
+	char cntr;
+	unsigned long jif, det;
+	IXJ *j = &ixj[board];
+
+	j->flags.ringing = 1;
+	if (ixj_hookstate(board) & 1) {
+		ixj_ring_off(board);
+		j->flags.ringing = 0;
+		return 1;
+	}
+	det = 0;
+	for (cntr = 0; cntr < j->maxrings; cntr++) {
+		jif = jiffies + (1 * hertz);
+		ixj_ring_on(board);
+		while (time_before(jiffies, jif)) {
+			if (ixj_hookstate(board) & 1) {
+				ixj_ring_off(board);
+				j->flags.ringing = 0;
+				return 1;
+			}
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(1);
+			if(signal_pending(current))
+				break;
+		}
+		jif = jiffies + (3 * hertz);
+		ixj_ring_off(board);
+		while (time_before(jiffies, jif)) {
+			if (ixj_hookstate(board) & 1) {
+				det = jiffies + (hertz / 100);
+				while (time_before(jiffies, det)) {
+					current->state = TASK_INTERRUPTIBLE;
+					schedule_timeout(1);
+					if(signal_pending(current))
+						break;
+				}
+				if (ixj_hookstate(board) & 1) {
+					j->flags.ringing = 0;
+					return 1;
+				}
+			}
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(1);
+			if(signal_pending(current))
+				break;
+		}
+	}
+	ixj_ring_off(board);
+	j->flags.ringing = 0;
+	return 0;
+}
+
+int ixj_open(struct phone_device *p, struct file *file_p)
+{
+	IXJ *j = &ixj[p->board];
+
+	if (!j->DSPbase)
+		return -ENODEV;
+
+	if (file_p->f_mode & FMODE_READ)
+		j->readers++;
+	if (file_p->f_mode & FMODE_WRITE)
+		j->writers++;
+
+	MOD_INC_USE_COUNT;
+
+	if (ixjdebug > 0)
+//    printk(KERN_INFO "Opening board %d\n", NUM(inode->i_rdev));
+		printk(KERN_INFO "Opening board %d\n", p->board);
+
+	return 0;
+}
+
+int ixj_release(struct inode *inode, struct file *file_p)
+{
+	IXJ_TONE ti;
+	int board = NUM(inode->i_rdev);
+	IXJ *j = &ixj[board];
+
+	if (ixjdebug > 0)
+		printk(KERN_INFO "Closing board %d\n", NUM(inode->i_rdev));
+
+	daa_set_mode(board, SOP_PU_SLEEP);
+	ixj_set_port(board, PORT_POTS);
+	aec_stop(board);
+	ixj_play_stop(board);
+	ixj_record_stop(board);
+
+	ti.tone_index = 10;
+	ti.gain0 = 1;
+	ti.freq0 = hz941;
+	ti.gain1 = 0;
+	ti.freq1 = hz1209;
+	ti.tone_index = 11;
+	ti.gain0 = 1;
+	ti.freq0 = hz941;
+	ti.gain1 = 0;
+	ti.freq1 = hz1336;
+	ti.tone_index = 12;
+	ti.gain0 = 1;
+	ti.freq0 = hz941;
+	ti.gain1 = 0;
+	ti.freq1 = hz1477;
+	ti.tone_index = 13;
+	ti.gain0 = 1;
+	ti.freq0 = hz800;
+	ti.gain1 = 0;
+	ti.freq1 = 0;
+	ixj_init_tone(board, &ti);
+	ti.tone_index = 14;
+	ti.gain0 = 1;
+	ti.freq0 = hz1000;
+	ti.gain1 = 0;
+	ti.freq1 = 0;
+	ixj_init_tone(board, &ti);
+	ti.tone_index = 15;
+	ti.gain0 = 1;
+	ti.freq0 = hz1250;
+	ti.gain1 = 0;
+	ti.freq1 = 0;
+	ixj_init_tone(board, &ti);
+	ti.tone_index = 16;
+	ti.gain0 = 1;
+	ti.freq0 = hz950;
+	ti.gain1 = 0;
+	ti.freq1 = 0;
+	ixj_init_tone(board, &ti);
+	ti.tone_index = 17;
+	ti.gain0 = 1;
+	ti.freq0 = hz1100;
+	ti.gain1 = 0;
+	ti.freq1 = 0;
+	ixj_init_tone(board, &ti);
+	ti.tone_index = 18;
+	ti.gain0 = 1;
+	ti.freq0 = hz1400;
+	ti.gain1 = 0;
+	ti.freq1 = 0;
+	ixj_init_tone(board, &ti);
+	ti.tone_index = 19;
+	ti.gain0 = 1;
+	ti.freq0 = hz1500;
+	ti.gain1 = 0;
+	ti.freq1 = 0;
+	ixj_init_tone(board, &ti);
+	ti.tone_index = 20;
+	ti.gain0 = 1;
+	ti.freq0 = hz1600;
+	ti.gain1 = 0;
+	ti.freq1 = 0;
+	ixj_init_tone(board, &ti);
+	ti.tone_index = 21;
+	ti.gain0 = 1;
+	ti.freq0 = hz1800;
+	ti.gain1 = 0;
+	ti.freq1 = 0;
+	ixj_init_tone(board, &ti);
+	ti.tone_index = 22;
+	ti.gain0 = 1;
+	ti.freq0 = hz2100;
+	ti.gain1 = 0;
+	ti.freq1 = 0;
+	ixj_init_tone(board, &ti);
+	ti.tone_index = 23;
+	ti.gain0 = 1;
+	ti.freq0 = hz1300;
+	ti.gain1 = 0;
+	ti.freq1 = 0;
+	ixj_init_tone(board, &ti);
+	ti.tone_index = 24;
+	ti.gain0 = 1;
+	ti.freq0 = hz2450;
+	ti.gain1 = 0;
+	ti.freq1 = 0;
+	ixj_init_tone(board, &ti);
+	ti.tone_index = 25;
+	ti.gain0 = 1;
+	ti.freq0 = hz350;
+	ti.gain1 = 0;
+	ti.freq1 = hz440;
+	ixj_init_tone(board, &ti);
+	ti.tone_index = 26;
+	ti.gain0 = 1;
+	ti.freq0 = hz440;
+	ti.gain1 = 0;
+	ti.freq1 = hz480;
+	ixj_init_tone(board, &ti);
+	ti.tone_index = 27;
+	ti.gain0 = 1;
+	ti.freq0 = hz480;
+	ti.gain1 = 0;
+	ti.freq1 = hz620;
+	ixj_init_tone(board, &ti);
+
+	idle(board);
+
+	if (file_p->f_mode & FMODE_READ)
+		j->readers--;
+	if (file_p->f_mode & FMODE_WRITE)
+		j->writers--;
+
+	if (j->read_buffer && !j->readers) {
+		kfree(j->read_buffer);
+		j->read_buffer = NULL;
+		j->read_buffer_size = 0;
+	}
+	if (j->write_buffer && !j->writers) {
+		kfree(j->write_buffer);
+		j->write_buffer = NULL;
+		j->write_buffer_size = 0;
+	}
+	j->rec_codec = j->play_codec = 0;
+	j->rec_frame_size = j->play_frame_size = 0;
+	ixj_fasync(-1, file_p, 0);	// remove from list of async notification
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int read_filters(int board)
+{
+	unsigned short fc, cnt;
+	IXJ *j = &ixj[board];
+
+	if (ixj_WriteDSPCommand(0x5144, board))
+		return -1;
+
+	fc = j->ssr.high << 8 | j->ssr.low;
+	if (fc == j->frame_count)
+		return 1;
+
+	j->frame_count = fc;
+
+	for (cnt = 0; cnt < 4; cnt++) {
+		if (ixj_WriteDSPCommand(0x5154 + cnt, board))
+			return -1;
+
+		if (ixj_WriteDSPCommand(0x515C, board))
+			return -1;
+
+		j->filter_hist[cnt] = j->ssr.high << 8 | j->ssr.low;
+		if ((j->filter_hist[cnt] & 1 && !(j->filter_hist[cnt] & 2)) ||
+		(j->filter_hist[cnt] & 2 && !(j->filter_hist[cnt] & 1))) {
+			switch (cnt) {
+			case 0:
+				j->ex.bits.f0 = 1;
+				break;
+			case 1:
+				j->ex.bits.f1 = 1;
+				break;
+			case 2:
+				j->ex.bits.f2 = 1;
+				break;
+			case 3:
+				j->ex.bits.f3 = 1;
+				break;
+			}
+		}
+	}
+	return 0;
+}
+
+static int LineMonitor(int board)
+{
+	IXJ *j = &ixj[board];
+
+	if (j->dtmf_proc) {
+		return -1;
+	}
+	j->dtmf_proc = 1;
+
+	if (ixj_WriteDSPCommand(0x7000, board))		// Line Monitor
+
+		return -1;
+
+	j->dtmf.bytes.high = j->ssr.high;
+	j->dtmf.bytes.low = j->ssr.low;
+	if (!j->dtmf_state && j->dtmf.bits.dtmf_valid) {
+		j->dtmf_state = 1;
+		j->dtmf_current = j->dtmf.bits.digit;
+	}
+	if (j->dtmf_state && !j->dtmf.bits.dtmf_valid)	// && j->dtmf_wp != j->dtmf_rp)
+	 {
+		j->dtmfbuffer[j->dtmf_wp] = j->dtmf_current;
+		j->dtmf_wp++;
+		if (j->dtmf_wp == 79)
+			j->dtmf_wp = 0;
+		j->ex.bits.dtmf_ready = 1;
+		j->dtmf_state = 0;
+	}
+	j->dtmf_proc = 0;
+
+	return 0;
+}
+
+ssize_t ixj_read(struct file * file_p, char *buf, size_t length, loff_t * ppos)
+{
+	unsigned long i = *ppos;
+	IXJ *j = &ixj[NUM(file_p->f_dentry->d_inode->i_rdev)];
+	struct wait_queue wait =
+	{current, NULL};
+
+	add_wait_queue(&j->read_q, &wait);
+	current->state = TASK_INTERRUPTIBLE;
+	mb();
+
+	while (!j->read_buffer_ready || (j->dtmf_state && j->flags.dtmf_oob)) {
+		++j->read_wait;
+		if (file_p->f_flags & O_NONBLOCK) {
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&j->read_q, &wait);
+			return -EAGAIN;
+		}
+		if (!ixj_hookstate(NUM(file_p->f_dentry->d_inode->i_rdev))) {
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&j->read_q, &wait);
+			return 0;
+		}
+		interruptible_sleep_on(&j->read_q);
+		if (signal_pending(current)) {
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&j->read_q, &wait);
+			return -EINTR;
+		}
+	}
+
+	remove_wait_queue(&j->read_q, &wait);
+	current->state = TASK_RUNNING;
+	/* Don't ever copy more than the user asks */
+	i = copy_to_user(buf, j->read_buffer, min(length, j->read_buffer_size));
+	j->read_buffer_ready = 0;
+	if (i)
+		return -EFAULT;
+	else
+		return min(length, j->read_buffer_size);
+}
+
+ssize_t ixj_enhanced_read(struct file * file_p, char *buf, size_t length,
+			  loff_t * ppos)
+{
+	int pre_retval;
+	ssize_t read_retval = 0;
+	IXJ *j = &ixj[NUM(file_p->f_dentry->d_inode->i_rdev)];
+
+	pre_retval = ixj_PreRead(j, 0L);
+	switch (pre_retval) {
+	case NORMAL:
+		read_retval = ixj_read(file_p, buf, length, ppos);
+		ixj_PostRead(j, 0L);
+		break;
+	case NOPOST:
+		read_retval = ixj_read(file_p, buf, length, ppos);
+		break;
+	case POSTONLY:
+		ixj_PostRead(j, 0L);
+		break;
+	default:
+		read_retval = pre_retval;
+	}
+	return read_retval;
+}
+
+ssize_t ixj_write(struct file * file_p, const char *buf, size_t count, loff_t * ppos)
+{
+	unsigned long i = *ppos;
+	int board = NUM(file_p->f_dentry->d_inode->i_rdev);
+	IXJ *j = &ixj[board];
+	struct wait_queue wait =
+	{current, NULL};
+
+	add_wait_queue(&j->read_q, &wait);
+	current->state = TASK_INTERRUPTIBLE;
+	mb();
+
+
+	while (!j->write_buffers_empty) {
+		++j->write_wait;
+		if (file_p->f_flags & O_NONBLOCK) {
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&j->read_q, &wait);
+			return -EAGAIN;
+		}
+		if (!ixj_hookstate(NUM(file_p->f_dentry->d_inode->i_rdev))) {
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&j->read_q, &wait);
+			return 0;
+		}
+		interruptible_sleep_on(&j->write_q);
+		if (signal_pending(current)) {
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&j->read_q, &wait);
+			return -EINTR;
+		}
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&j->read_q, &wait);
+	if (j->write_buffer_wp + count >= j->write_buffer_end)
+		j->write_buffer_wp = j->write_buffer;
+	i = copy_from_user(j->write_buffer_wp, buf, min(count, j->write_buffer_size));
+	if (i)
+		return -EFAULT;
+
+	return min(count, j->write_buffer_size);
+}
+
+ssize_t ixj_enhanced_write(struct file * file_p, const char *buf, size_t count,
+			   loff_t * ppos)
+{
+	int pre_retval;
+	ssize_t write_retval = 0;
+	IXJ *j = &ixj[NUM(file_p->f_dentry->d_inode->i_rdev)];
+
+	pre_retval = ixj_PreWrite(j, 0L);
+	switch (pre_retval) {
+	case NORMAL:
+		write_retval = ixj_write(file_p, buf, count, ppos);
+		if (write_retval != -EFAULT) {
+			ixj_PostWrite(j, 0L);
+			j->write_buffer_wp += count;
+			j->write_buffers_empty--;
+		}
+		break;
+	case NOPOST:
+		write_retval = ixj_write(file_p, buf, count, ppos);
+		if (write_retval != -EFAULT) {
+			j->write_buffer_wp += count;
+			j->write_buffers_empty--;
+		}
+		break;
+	case POSTONLY:
+		ixj_PostWrite(j, 0L);
+		break;
+	default:
+		write_retval = pre_retval;
+	}
+	return write_retval;
+}
+
+static void ixj_read_frame(int board)
+{
+	int cnt, dly;
+	IXJ *j = &ixj[board];
+
+	if (j->read_buffer) {
+		for (cnt = 0; cnt < j->rec_frame_size * 2; cnt += 2) {
+			if (!(cnt % 16) && !IsRxReady(board)) {
+				dly = 0;
+				while (!IsRxReady(board)) {
+					if (dly++ > 5) {
+						dly = 0;
+						break;
+					}
+					udelay(10);
+				}
+			}
+			// Throw away word 0 of the 8021 compressed format to get standard G.729.
+			if (j->rec_codec == G729 && (cnt == 0 || cnt == 5 || cnt == 10)) {
+				inb_p(j->DSPbase + 0x0E);
+				inb_p(j->DSPbase + 0x0F);
+			}
+			*(j->read_buffer + cnt) = inb_p(j->DSPbase + 0x0E);
+			*(j->read_buffer + cnt + 1) = inb_p(j->DSPbase + 0x0F);
+		}
+#ifdef PERFMON_STATS
+		++j->framesread;
+#endif
+		if (j->intercom != -1) {
+			if (IsTxReady(j->intercom)) {
+				for (cnt = 0; cnt < j->rec_frame_size * 2; cnt += 2) {
+					if (!(cnt % 16) && !IsTxReady(board)) {
+						dly = 0;
+						while (!IsTxReady(board)) {
+							if (dly++ > 5) {
+								dly = 0;
+								break;
+							}
+							udelay(10);
+						}
+					}
+					outb_p(*(j->read_buffer + cnt), ixj[j->intercom].DSPbase + 0x0C);
+					outb_p(*(j->read_buffer + cnt + 1), ixj[j->intercom].DSPbase + 0x0D);
+				}
+#ifdef PERFMON_STATS
+				++ixj[j->intercom].frameswritten;
+#endif
+			}
+		} else {
+			j->read_buffer_ready = 1;
+			wake_up_interruptible(&j->read_q);	// Wake any blocked readers
+
+			wake_up_interruptible(&j->poll_q);	// Wake any blocked selects
+
+			if (j->async_queue)
+				kill_fasync(j->async_queue, SIGIO);	// Send apps notice of frame
+
+		}
+	}
+}
+
+static void ixj_write_frame(int board)
+{
+	int cnt, frame_count, dly;
+	BYTES blankword;
+	IXJ *j = &ixj[board];
+
+	frame_count = 0;
+	if (j->write_buffer && j->write_buffers_empty < 2) {
+		if (j->write_buffer_wp > j->write_buffer_rp) {
+			frame_count =
+			    (j->write_buffer_wp - j->write_buffer_rp) / (j->play_frame_size * 2);
+		}
+		if (j->write_buffer_rp > j->write_buffer_wp) {
+			frame_count =
+			    (j->write_buffer_wp - j->write_buffer) / (j->play_frame_size * 2) +
+			    (j->write_buffer_end - j->write_buffer_rp) / (j->play_frame_size * 2);
+		}
+		if (frame_count >= 1) {
+			if (j->ver.low == 0x12 && j->play_mode && j->flags.play_first_frame) {
+				switch (j->play_mode) {
+				case PLAYBACK_MODE_ULAW:
+				case PLAYBACK_MODE_ALAW:
+					blankword.low = blankword.high = 0xFF;
+					break;
+				case PLAYBACK_MODE_8LINEAR:
+				case PLAYBACK_MODE_16LINEAR:
+					blankword.low = blankword.high = 0x00;
+					break;
+				case PLAYBACK_MODE_8LINEAR_WSS:
+					blankword.low = blankword.high = 0x80;
+					break;
+				}
+				for (cnt = 0; cnt < 16; cnt++) {
+					if (!(cnt % 16) && !IsTxReady(board)) {
+						dly = 0;
+						while (!IsTxReady(board)) {
+							if (dly++ > 5) {
+								dly = 0;
+								break;
+							}
+							udelay(10);
+						}
+					}
+					outb_p((blankword.low), j->DSPbase + 0x0C);
+					outb_p((blankword.high), j->DSPbase + 0x0D);
+				}
+				j->flags.play_first_frame = 0;
+			}
+			for (cnt = 0; cnt < j->play_frame_size * 2; cnt += 2) {
+				if (!(cnt % 16) && !IsTxReady(board)) {
+					dly = 0;
+					while (!IsTxReady(board)) {
+						if (dly++ > 5) {
+							dly = 0;
+							break;
+						}
+						udelay(10);
+					}
+				}
+// Add word 0 to G.729 frames for the 8021.  Right now we don't do VAD/CNG 
+				// so all frames are type 1.
+				if (j->play_codec == G729 && (cnt == 0 || cnt == 5 || cnt == 10)) {
+					outb_p(0x01, j->DSPbase + 0x0C);
+					outb_p(0x00, j->DSPbase + 0x0D);
+				}
+				outb_p(*(j->write_buffer_rp + cnt), j->DSPbase + 0x0C);
+				outb_p(*(j->write_buffer_rp + cnt + 1), j->DSPbase + 0x0D);
+				*(j->write_buffer_rp + cnt) = 0;
+				*(j->write_buffer_rp + cnt + 1) = 0;
+			}
+			j->write_buffer_rp += j->play_frame_size * 2;
+			if (j->write_buffer_rp >= j->write_buffer_end) {
+				j->write_buffer_rp = j->write_buffer;
+			}
+			j->write_buffers_empty++;
+			wake_up_interruptible(&(j->write_q));	// Wake any blocked writers
+
+			wake_up_interruptible(&j->poll_q);	// Wake any blocked selects
+
+			if (j->async_queue)
+				kill_fasync(j->async_queue, SIGIO);	// Send apps notice of empty buffer
+#ifdef PERFMON_STATS
+			++j->frameswritten;
+#endif
+		}
+	} else {
+		j->drybuffer++;
+	}
+}
+
+static int idle(int board)
+{
+	IXJ *j = &ixj[board];
+
+	if (ixj_WriteDSPCommand(0x0000, board))		// DSP Idle
+
+		return 0;
+	if (j->ssr.high || j->ssr.low)
+		return 0;
+	else
+		return 1;
+}
+
+static int set_base_frame(int board, int size)
+{
+	unsigned short cmd;
+	int cnt;
+	IXJ *j = &ixj[board];
+
+	aec_stop(board);
+	for (cnt = 0; cnt < 10; cnt++) {
+		if (idle(board))
+			break;
+	}
+	if (j->ssr.high || j->ssr.low)
+		return -1;
+	if (j->dsp.low != 0x20) {
+		switch (size) {
+		case 30:
+			cmd = 0x07F0;
+			/* Set Base Frame Size to 240 pg9-10 8021 */
+			break;
+		case 20:
+			cmd = 0x07A0;
+			/* Set Base Frame Size to 160 pg9-10 8021 */
+			break;
+		case 10:
+			cmd = 0x0750;
+			/* Set Base Frame Size to 80 pg9-10 8021 */
+			break;
+		default:
+			return -1;
+		}
+	} else {
+		if (size == 30)
+			return size;
+		else
+			return -1;
+	}
+	if (ixj_WriteDSPCommand(cmd, board)) {
+		j->baseframe.high = j->baseframe.low = 0xFF;
+		return -1;
+	} else {
+		j->baseframe.high = j->ssr.high;
+		j->baseframe.low = j->ssr.low;
+	}
+	return size;
+}
+
+static int set_rec_codec(int board, int rate)
+{
+	int retval = 0;
+	IXJ *j = &ixj[board];
+
+	j->rec_codec = rate;
+
+	switch (rate) {
+	case G723_63:
+		if (j->ver.low != 0x12 || ixj_convert_loaded) {
+			j->rec_frame_size = 12;
+			j->rec_mode = 0;
+		} else {
+			retval = 1;
+		}
+		break;
+	case G723_53:
+		if (j->ver.low != 0x12 || ixj_convert_loaded) {
+			j->rec_frame_size = 10;
+			j->rec_mode = 0;
+		} else {
+			retval = 1;
+		}
+		break;
+	case TS85:
+		if (j->dsp.low == 0x20 || j->flags.ts85_loaded) {
+			j->rec_frame_size = 16;
+			j->rec_mode = 0;
+		} else {
+			retval = 1;
+		}
+		break;
+	case TS48:
+		if (j->ver.low != 0x12 || ixj_convert_loaded) {
+			j->rec_frame_size = 9;
+			j->rec_mode = 0;
+		} else {
+			retval = 1;
+		}
+		break;
+	case TS41:
+		if (j->ver.low != 0x12 || ixj_convert_loaded) {
+			j->rec_frame_size = 8;
+			j->rec_mode = 0;
+		} else {
+			retval = 1;
+		}
+		break;
+	case G728:
+		if (j->dsp.low != 0x20) {
+			j->rec_frame_size = 48;
+			j->rec_mode = 0;
+		} else {
+			retval = 1;
+		}
+		break;
+	case G729:
+		if (j->dsp.low != 0x20) {
+			if (!j->flags.g729_loaded) {
+				retval = 1;
+				break;
+			}
+			switch (j->baseframe.low) {
+			case 0xA0:
+				j->rec_frame_size = 10;
+				break;
+			case 0x50:
+				j->rec_frame_size = 5;
+				break;
+			default:
+				j->rec_frame_size = 15;
+				break;
+			}
+			j->rec_mode = 0;
+		} else {
+			retval = 1;
+		}
+		break;
+	case ULAW:
+		switch (j->baseframe.low) {
+		case 0xA0:
+			j->rec_frame_size = 80;
+			break;
+		case 0x50:
+			j->rec_frame_size = 40;
+			break;
+		default:
+			j->rec_frame_size = 120;
+			break;
+		}
+		j->rec_mode = 4;
+		break;
+	case ALAW:
+		switch (j->baseframe.low) {
+		case 0xA0:
+			j->rec_frame_size = 80;
+			break;
+		case 0x50:
+			j->rec_frame_size = 40;
+			break;
+		default:
+			j->rec_frame_size = 120;
+			break;
+		}
+		j->rec_mode = 4;
+		break;
+	case LINEAR16:
+		switch (j->baseframe.low) {
+		case 0xA0:
+			j->rec_frame_size = 160;
+			break;
+		case 0x50:
+			j->rec_frame_size = 80;
+			break;
+		default:
+			j->rec_frame_size = 240;
+			break;
+		}
+		j->rec_mode = 5;
+		break;
+	case LINEAR8:
+		switch (j->baseframe.low) {
+		case 0xA0:
+			j->rec_frame_size = 80;
+			break;
+		case 0x50:
+			j->rec_frame_size = 40;
+			break;
+		default:
+			j->rec_frame_size = 120;
+			break;
+		}
+		j->rec_mode = 6;
+		break;
+	case WSS:
+		switch (j->baseframe.low) {
+		case 0xA0:
+			j->rec_frame_size = 80;
+			break;
+		case 0x50:
+			j->rec_frame_size = 40;
+			break;
+		default:
+			j->rec_frame_size = 120;
+			break;
+		}
+		j->rec_mode = 7;
+		break;
+	default:
+		j->rec_frame_size = 0;
+		j->rec_mode = -1;
+		if (j->read_buffer) {
+			kfree(j->read_buffer);
+			j->read_buffer = NULL;
+			j->read_buffer_size = 0;
+		}
+		retval = 1;
+		break;
+	}
+	return retval;
+}
+
+static int ixj_record_start(int board)
+{
+	unsigned short cmd = 0x0000;
+	IXJ *j = &ixj[board];
+
+	if (!j->rec_mode) {
+		switch (j->rec_codec) {
+		case G723_63:
+			cmd = 0x5131;
+			break;
+		case G723_53:
+			cmd = 0x5132;
+			break;
+		case TS85:
+			cmd = 0x5130;	// TrueSpeech 8.5
+
+			break;
+		case TS48:
+			cmd = 0x5133;	// TrueSpeech 4.8
+
+			break;
+		case TS41:
+			cmd = 0x5134;	// TrueSpeech 4.1
+
+			break;
+		case G728:
+			cmd = 0x5135;
+			break;
+		case G729:
+			cmd = 0x5136;
+			break;
+		default:
+			return 1;
+		}
+		if (ixj_WriteDSPCommand(cmd, board))
+			return -1;
+	}
+	if (!j->read_buffer) {
+		if (!j->read_buffer)
+			j->read_buffer = kmalloc(j->rec_frame_size * 2, GFP_ATOMIC);
+		if (!j->read_buffer) {
+			printk("Read buffer allocation for ixj board %d failed!\n", board);
+			return -ENOMEM;
+		}
+	}
+	j->read_buffer_size = j->rec_frame_size * 2;
+
+	if (ixj_WriteDSPCommand(0x5102, board))		// Set Poll sync mode
+
+		return -1;
+
+	switch (j->rec_mode) {
+	case 0:
+		cmd = 0x1C03;	// Record C1
+
+		break;
+	case 4:
+		if (j->ver.low == 0x12) {
+			cmd = 0x1E03;	// Record C1
+
+		} else {
+			cmd = 0x1E01;	// Record C1
+
+		}
+		break;
+	case 5:
+		if (j->ver.low == 0x12) {
+			cmd = 0x1E83;	// Record C1
+
+		} else {
+			cmd = 0x1E81;	// Record C1
+
+		}
+		break;
+	case 6:
+		if (j->ver.low == 0x12) {
+			cmd = 0x1F03;	// Record C1
+
+		} else {
+			cmd = 0x1F01;	// Record C1
+
+		}
+		break;
+	case 7:
+		if (j->ver.low == 0x12) {
+			cmd = 0x1F83;	// Record C1
+
+		} else {
+			cmd = 0x1F81;	// Record C1
+
+		}
+		break;
+	}
+	if (ixj_WriteDSPCommand(cmd, board))
+		return -1;
+
+	return 0;
+}
+
+static void ixj_record_stop(int board)
+{
+	IXJ *j = &ixj[board];
+
+	if (j->rec_mode > -1) {
+		ixj_WriteDSPCommand(0x5120, board);
+		j->rec_mode = -1;
+	}
+}
+
+static void set_rec_depth(int board, int depth)
+{
+	if (depth > 60)
+		depth = 60;
+	if (depth < 0)
+		depth = 0;
+	ixj_WriteDSPCommand(0x5180 + depth, board);
+}
+
+static void set_rec_volume(int board, int volume)
+{
+	ixj_WriteDSPCommand(0xCF03, board);
+	ixj_WriteDSPCommand(volume, board);
+}
+
+static int get_rec_level(int board)
+{
+	IXJ *j = &ixj[board];
+
+	ixj_WriteDSPCommand(0xCF88, board);
+
+	return j->ssr.high << 8 | j->ssr.low;
+}
+
+static void ixj_aec_start(int board, int level)
+{
+	IXJ *j = &ixj[board];
+
+	j->aec_level = level;
+	if (!level) {
+		ixj_WriteDSPCommand(0xB002, board);
+	} else {
+		if (j->rec_codec == G729 || j->play_codec == G729) {
+			ixj_WriteDSPCommand(0xE022, board);	// Move AEC filter buffer
+
+			ixj_WriteDSPCommand(0x0300, board);
+		}
+		ixj_WriteDSPCommand(0xB001, board);	// AEC On
+
+		ixj_WriteDSPCommand(0xE013, board);	// Advanced AEC C1
+
+		switch (level) {
+		case 1:
+			ixj_WriteDSPCommand(0x0000, board);	// Advanced AEC C2 = off
+
+			ixj_WriteDSPCommand(0xE011, board);
+			ixj_WriteDSPCommand(0xFFFF, board);
+			break;
+
+		case 2:
+			ixj_WriteDSPCommand(0x0600, board);	// Advanced AEC C2 = on medium
+
+			ixj_WriteDSPCommand(0xE011, board);
+			ixj_WriteDSPCommand(0x0080, board);
+			break;
+
+		case 3:
+			ixj_WriteDSPCommand(0x0C00, board);	// Advanced AEC C2 = on high
+
+			ixj_WriteDSPCommand(0xE011, board);
+			ixj_WriteDSPCommand(0x0080, board);
+			break;
+		}
+	}
+}
+
+static void aec_stop(int board)
+{
+	IXJ *j = &ixj[board];
+
+	if (j->rec_codec == G729 || j->play_codec == G729) {
+		ixj_WriteDSPCommand(0xE022, board);	// Move AEC filter buffer back
+
+		ixj_WriteDSPCommand(0x0700, board);
+	}
+	if (ixj[board].play_mode != -1 && ixj[board].rec_mode != -1);
+	{
+		ixj_WriteDSPCommand(0xB002, board);	// AEC Stop
+
+	}
+}
+
+static int set_play_codec(int board, int rate)
+{
+	int retval = 0;
+	IXJ *j = &ixj[board];
+
+	j->play_codec = rate;
+
+	switch (rate) {
+	case G723_63:
+		if (j->ver.low != 0x12 || ixj_convert_loaded) {
+			j->play_frame_size = 12;
+			j->play_mode = 0;
+		} else {
+			retval = 1;
+		}
+		break;
+	case G723_53:
+		if (j->ver.low != 0x12 || ixj_convert_loaded) {
+			j->play_frame_size = 10;
+			j->play_mode = 0;
+		} else {
+			retval = 1;
+		}
+		break;
+	case TS85:
+		if (j->dsp.low == 0x20 || j->flags.ts85_loaded) {
+			j->play_frame_size = 16;
+			j->play_mode = 0;
+		} else {
+			retval = 1;
+		}
+		break;
+	case TS48:
+		if (j->ver.low != 0x12 || ixj_convert_loaded) {
+			j->play_frame_size = 9;
+			j->play_mode = 0;
+		} else {
+			retval = 1;
+		}
+		break;
+	case TS41:
+		if (j->ver.low != 0x12 || ixj_convert_loaded) {
+			j->play_frame_size = 8;
+			j->play_mode = 0;
+		} else {
+			retval = 1;
+		}
+		break;
+	case G728:
+		if (j->dsp.low != 0x20) {
+			j->play_frame_size = 48;
+			j->play_mode = 0;
+		} else {
+			retval = 1;
+		}
+		break;
+	case G729:
+		if (j->dsp.low != 0x20) {
+			if (!j->flags.g729_loaded) {
+				retval = 1;
+				break;
+			}
+			switch (j->baseframe.low) {
+			case 0xA0:
+				j->play_frame_size = 10;
+				break;
+			case 0x50:
+				j->play_frame_size = 5;
+				break;
+			default:
+				j->play_frame_size = 15;
+				break;
+			}
+			j->play_mode = 0;
+		} else {
+			retval = 1;
+		}
+		break;
+	case ULAW:
+		switch (j->baseframe.low) {
+		case 0xA0:
+			j->play_frame_size = 80;
+			break;
+		case 0x50:
+			j->play_frame_size = 40;
+			break;
+		default:
+			j->play_frame_size = 120;
+			break;
+		}
+		j->play_mode = 2;
+		break;
+	case ALAW:
+		switch (j->baseframe.low) {
+		case 0xA0:
+			j->play_frame_size = 80;
+			break;
+		case 0x50:
+			j->play_frame_size = 40;
+			break;
+		default:
+			j->play_frame_size = 120;
+			break;
+		}
+		j->play_mode = 2;
+		break;
+	case LINEAR16:
+		switch (j->baseframe.low) {
+		case 0xA0:
+			j->play_frame_size = 160;
+			break;
+		case 0x50:
+			j->play_frame_size = 80;
+			break;
+		default:
+			j->play_frame_size = 240;
+			break;
+		}
+		j->play_mode = 6;
+		break;
+	case LINEAR8:
+		switch (j->baseframe.low) {
+		case 0xA0:
+			j->play_frame_size = 80;
+			break;
+		case 0x50:
+			j->play_frame_size = 40;
+			break;
+		default:
+			j->play_frame_size = 120;
+			break;
+		}
+		j->play_mode = 4;
+		break;
+	case WSS:
+		switch (j->baseframe.low) {
+		case 0xA0:
+			j->play_frame_size = 80;
+			break;
+		case 0x50:
+			j->play_frame_size = 40;
+			break;
+		default:
+			j->play_frame_size = 120;
+			break;
+		}
+		j->play_mode = 5;
+		break;
+	default:
+		j->play_frame_size = 0;
+		j->play_mode = -1;
+		if (j->write_buffer) {
+			kfree(j->write_buffer);
+			j->write_buffer = NULL;
+			j->write_buffer_size = 0;
+		}
+		retval = 1;
+		break;
+	}
+	return retval;
+}
+
+static int ixj_play_start(int board)
+{
+	unsigned short cmd = 0x0000;
+	IXJ *j = &ixj[board];
+
+	j->flags.play_first_frame = 1;
+	j->drybuffer = 0;
+
+	if (!j->play_mode) {
+		switch (j->play_codec) {
+		case G723_63:
+			cmd = 0x5231;
+			break;
+		case G723_53:
+			cmd = 0x5232;
+			break;
+		case TS85:
+			cmd = 0x5230;	// TrueSpeech 8.5
+
+			break;
+		case TS48:
+			cmd = 0x5233;	// TrueSpeech 4.8
+
+			break;
+		case TS41:
+			cmd = 0x5234;	// TrueSpeech 4.1
+
+			break;
+		case G728:
+			cmd = 0x5235;
+			break;
+		case G729:
+			cmd = 0x5236;
+			break;
+		default:
+			return 1;
+		}
+		if (ixj_WriteDSPCommand(cmd, board))
+			return -1;
+	}
+	if (!j->write_buffer) {
+		j->write_buffer = kmalloc(j->play_frame_size * 2, GFP_ATOMIC);
+		if (!j->write_buffer) {
+			printk("Write buffer allocation for ixj board %d failed!\n", board);
+			return -ENOMEM;
+		}
+	}
+	j->write_buffers_empty = 2;
+	j->write_buffer_size = j->play_frame_size * 2;
+	j->write_buffer_end = j->write_buffer + j->play_frame_size * 2;
+	j->write_buffer_rp = j->write_buffer_wp = j->write_buffer;
+
+	if (ixj_WriteDSPCommand(0x5202, board))		// Set Poll sync mode
+
+		return -1;
+
+	switch (j->play_mode) {
+	case 0:
+		cmd = 0x2C03;
+		break;
+	case 2:
+		if (j->ver.low == 0x12) {
+			cmd = 0x2C23;
+		} else {
+			cmd = 0x2C21;
+		}
+		break;
+	case 4:
+		if (j->ver.low == 0x12) {
+			cmd = 0x2C43;
+		} else {
+			cmd = 0x2C41;
+		}
+		break;
+	case 5:
+		if (j->ver.low == 0x12) {
+			cmd = 0x2C53;
+		} else {
+			cmd = 0x2C51;
+		}
+		break;
+	case 6:
+		if (j->ver.low == 0x12) {
+			cmd = 0x2C63;
+		} else {
+			cmd = 0x2C61;
+		}
+		break;
+	}
+	if (ixj_WriteDSPCommand(cmd, board))
+		return -1;
+
+	if (ixj_WriteDSPCommand(0x2000, board))		// Playback C2
+
+		return -1;
+
+	if (ixj_WriteDSPCommand(0x2000 + ixj[board].play_frame_size, board))	// Playback C3
+
+		return -1;
+
+	return 0;
+}
+
+static void ixj_play_stop(int board)
+{
+	IXJ *j = &ixj[board];
+
+	if (j->play_mode > -1) {
+		ixj_WriteDSPCommand(0x5221, board);	// Stop playback
+
+		j->play_mode = -1;
+	}
+}
+
+extern __inline__ void set_play_depth(int board, int depth)
+{
+	if (depth > 60)
+		depth = 60;
+	if (depth < 0)
+		depth = 0;
+	ixj_WriteDSPCommand(0x5280 + depth, board);
+}
+
+extern __inline__ void set_play_volume(int board, int volume)
+{
+	ixj_WriteDSPCommand(0xCF02, board);
+	ixj_WriteDSPCommand(volume, board);
+}
+
+extern __inline__ int get_play_level(int board)
+{
+	ixj_WriteDSPCommand(0xCF8F, board);
+	return ixj[board].ssr.high << 8 | ixj[board].ssr.low;
+}
+
+static unsigned int ixj_poll(struct file *file_p, poll_table * wait)
+{
+	unsigned int mask = 0;
+	IXJ *j = &ixj[NUM(file_p->f_dentry->d_inode->i_rdev)];
+
+	poll_wait(file_p, &(j->poll_q), wait);
+	if (j->read_buffer_ready > 0)
+		mask |= POLLIN | POLLRDNORM;	/* readable */
+	if (j->write_buffers_empty > 0)
+		mask |= POLLOUT | POLLWRNORM;	/* writable */
+	if (j->ex.bytes)
+		mask |= POLLPRI;
+	return mask;
+}
+
+static int ixj_play_tone(int board, char tone)
+{
+	IXJ *j = &ixj[board];
+
+	if (!j->tone_state)
+		idle(board);
+
+	j->tone_index = tone;
+	if (ixj_WriteDSPCommand(0x6000 + j->tone_index, board))
+		return -1;
+
+	if (!j->tone_state) {
+		j->tone_start_jif = jiffies;
+
+		j->tone_state = 1;
+	}
+	return 0;
+}
+
+static int ixj_set_tone_on(unsigned short arg, int board)
+{
+	IXJ *j = &ixj[board];
+
+	j->tone_on_time = arg;
+
+	if (ixj_WriteDSPCommand(0x6E04, board))		// Set Tone On Period
+
+		return -1;
+
+	if (ixj_WriteDSPCommand(arg, board))
+		return -1;
+
+	return 0;
+}
+
+static int SCI_WaitHighSCI(int board)
+{
+	int cnt;
+	IXJ *j = &ixj[board];
+
+	j->pld_scrr.byte = inb_p(j->XILINXbase);
+	if (!j->pld_scrr.bits.sci) {
+		for (cnt = 0; cnt < 10; cnt++) {
+			udelay(32);
+			j->pld_scrr.byte = inb_p(j->XILINXbase);
+
+			if ((j->pld_scrr.bits.sci))
+				return 1;
+		}
+		if (ixjdebug > 1)
+			printk(KERN_INFO "SCI Wait High failed %x\n", j->pld_scrr.byte);
+		return 0;
+	} else
+		return 1;
+}
+
+static int SCI_WaitLowSCI(int board)
+{
+	int cnt;
+	IXJ *j = &ixj[board];
+
+	j->pld_scrr.byte = inb_p(j->XILINXbase);
+	if (j->pld_scrr.bits.sci) {
+		for (cnt = 0; cnt < 10; cnt++) {
+			udelay(32);
+			j->pld_scrr.byte = inb_p(j->XILINXbase);
+
+			if (!(j->pld_scrr.bits.sci))
+				return 1;
+		}
+		if (ixjdebug > 1)
+			printk(KERN_INFO "SCI Wait Low failed %x\n", j->pld_scrr.byte);
+		return 0;
+	} else
+		return 1;
+}
+
+static int SCI_Control(int board, int control)
+{
+	IXJ *j = &ixj[board];
+
+	switch (control) {
+	case SCI_End:
+		j->pld_scrw.bits.c0 = 0;	// Set PLD Serial control interface
+
+		j->pld_scrw.bits.c1 = 0;	// to no selection 
+
+		break;
+	case SCI_Enable_DAA:
+		j->pld_scrw.bits.c0 = 1;	// Set PLD Serial control interface
+
+		j->pld_scrw.bits.c1 = 0;	// to write to DAA
+
+		break;
+	case SCI_Enable_Mixer:
+		j->pld_scrw.bits.c0 = 0;	// Set PLD Serial control interface
+
+		j->pld_scrw.bits.c1 = 1;	// to write to mixer 
+
+		break;
+	case SCI_Enable_EEPROM:
+		j->pld_scrw.bits.c0 = 1;	// Set PLD Serial control interface
+
+		j->pld_scrw.bits.c1 = 1;	// to write to EEPROM 
+
+		break;
+	default:
+		return 0;
+		break;
+	}
+	outb_p(j->pld_scrw.byte, j->XILINXbase);
+
+	switch (control) {
+	case SCI_End:
+		return 1;
+		break;
+	case SCI_Enable_DAA:
+	case SCI_Enable_Mixer:
+	case SCI_Enable_EEPROM:
+		if (!SCI_WaitHighSCI(board))
+			return 0;
+		break;
+	default:
+		return 0;
+		break;
+	}
+	return 1;
+}
+
+static int SCI_Prepare(int board)
+{
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+
+	if (!SCI_WaitLowSCI(board))
+		return 0;
+
+	return 1;
+}
+
+static int ixj_mixer(long val, int board)
+{
+	BYTES bytes;
+	IXJ *j = &ixj[board];
+
+	bytes.high = (val & 0xFF00) >> 8;
+	bytes.low = val & 0x00FF;
+
+	outb_p(bytes.high & 0x1F, j->XILINXbase + 0x03);	// Load Mixer Address
+
+	outb_p(bytes.low, j->XILINXbase + 0x02);	// Load Mixer Data
+
+	SCI_Control(board, SCI_Enable_Mixer);
+
+	SCI_Control(board, SCI_End);
+
+	return 0;
+}
+
+static int daa_load(BYTES * p_bytes, int board)
+{
+	IXJ *j = &ixj[board];
+
+	outb_p(p_bytes->high, j->XILINXbase + 0x03);
+	outb_p(p_bytes->low, j->XILINXbase + 0x02);
+	if (!SCI_Control(board, SCI_Enable_DAA))
+		return 0;
+	else
+		return 1;
+}
+
+static int ixj_daa_cr4(int board, char reg)
+{
+	IXJ *j = &ixj[board];
+	BYTES bytes;
+
+	switch (j->daa_mode) {
+	case SOP_PU_SLEEP:
+		bytes.high = 0x14;
+		break;
+	case SOP_PU_RINGING:
+		bytes.high = 0x54;
+		break;
+	case SOP_PU_CONVERSATION:
+		bytes.high = 0x94;
+		break;
+	case SOP_PU_PULSEDIALING:
+		bytes.high = 0xD4;
+		break;
+	}
+
+	switch (j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGX) {
+	case 0:
+		j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGR_Z = 0;
+		break;
+	case 1:
+		j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGR_Z = 2;
+		break;
+	case 2:
+		j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGR_Z = 1;
+		break;
+	case 3:
+		j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGR_Z = 3;
+		break;
+	}
+
+	bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg;
+
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Prepare(board))
+		return 0;
+
+	return 1;
+}
+
+static char daa_int_read(int board)
+{
+	BYTES bytes;
+	IXJ *j = &ixj[board];
+
+	if (!SCI_Prepare(board))
+		return 0;
+
+	bytes.high = 0x38;
+	bytes.low = 0x00;
+	outb_p(bytes.high, j->XILINXbase + 0x03);
+	outb_p(bytes.low, j->XILINXbase + 0x02);
+
+	if (!SCI_Control(board, SCI_Enable_DAA))
+		return 0;
+
+	bytes.high = inb_p(j->XILINXbase + 0x03);
+	bytes.low = inb_p(j->XILINXbase + 0x02);
+	if (bytes.low != ALISDAA_ID_BYTE) {
+		if (ixjdebug > 0)
+			printk("Cannot read DAA ID Byte high = %d low = %d\n", bytes.high, bytes.low);
+		return 0;
+	}
+	if (!SCI_Control(board, SCI_Enable_DAA))
+		return 0;
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+
+	bytes.high = inb_p(j->XILINXbase + 0x03);
+	bytes.low = inb_p(j->XILINXbase + 0x02);
+
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.reg = bytes.high;
+	return 1;
+}
+
+static int ixj_daa_cid_reset(int board)
+{
+	int i;
+	BYTES bytes;
+	IXJ *j = &ixj[board];
+
+	if (!SCI_Prepare(board))
+		return 0;
+
+	bytes.high = 0x58;
+	bytes.low = 0x00;
+	outb_p(bytes.high, j->XILINXbase + 0x03);
+	outb_p(bytes.low, j->XILINXbase + 0x02);
+
+	if (!SCI_Control(board, SCI_Enable_DAA))
+		return 0;
+
+	if (!SCI_WaitHighSCI(board))
+		return 0;
+
+	for (i = 0; i < ALISDAA_CALLERID_SIZE - 1; i += 2) {
+		bytes.high = bytes.low = 0x00;
+		outb_p(bytes.high, j->XILINXbase + 0x03);
+
+		if (i < ALISDAA_CALLERID_SIZE - 1)
+			outb_p(bytes.low, j->XILINXbase + 0x02);
+
+		if (!SCI_Control(board, SCI_Enable_DAA))
+			return 0;
+
+		if (!SCI_WaitHighSCI(board))
+			return 0;
+
+	}
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+
+	return 1;
+}
+
+static int ixj_daa_cid_read(int board)
+{
+	int i;
+	BYTES bytes;
+	char CID[ALISDAA_CALLERID_SIZE], mContinue;
+	char *pIn, *pOut;
+	IXJ *j = &ixj[board];
+
+	if (!SCI_Prepare(board))
+		return 0;
+
+	bytes.high = 0x78;
+	bytes.low = 0x00;
+	outb_p(bytes.high, j->XILINXbase + 0x03);
+	outb_p(bytes.low, j->XILINXbase + 0x02);
+
+	if (!SCI_Control(board, SCI_Enable_DAA))
+		return 0;
+
+	if (!SCI_WaitHighSCI(board))
+		return 0;
+
+	bytes.high = inb_p(j->XILINXbase + 0x03);
+	bytes.low = inb_p(j->XILINXbase + 0x02);
+	if (bytes.low != ALISDAA_ID_BYTE) {
+		if (ixjdebug > 0)
+			printk("DAA Get Version Cannot read DAA ID Byte high = %d low = %d\n", bytes.high, bytes.low);
+		return 0;
+	}
+	for (i = 0; i < ALISDAA_CALLERID_SIZE; i += 2) {
+		bytes.high = bytes.low = 0x00;
+		outb_p(bytes.high, j->XILINXbase + 0x03);
+		outb_p(bytes.low, j->XILINXbase + 0x02);
+
+		if (!SCI_Control(board, SCI_Enable_DAA))
+			return 0;
+
+		if (!SCI_WaitHighSCI(board))
+			return 0;
+
+		CID[i + 0] = inb_p(j->XILINXbase + 0x03);
+		CID[i + 1] = inb_p(j->XILINXbase + 0x02);
+	}
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+
+	pIn = CID;
+	pOut = j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID;
+	mContinue = 1;
+	while (mContinue) {
+		if ((pIn[1] & 0x03) == 0x01) {
+			pOut[0] = pIn[0];
+		}
+		if ((pIn[2] & 0x0c) == 0x04) {
+			pOut[1] = ((pIn[2] & 0x03) << 6) | ((pIn[1] & 0xfc) >> 2);
+		}
+		if ((pIn[3] & 0x30) == 0x10) {
+			pOut[2] = ((pIn[3] & 0x0f) << 4) | ((pIn[2] & 0xf0) >> 4);
+		}
+		if ((pIn[4] & 0xc0) == 0x40) {
+			pOut[3] = ((pIn[4] & 0x3f) << 2) | ((pIn[3] & 0xc0) >> 6);
+		} else {
+			mContinue = FALSE;
+		}
+		pIn += 5, pOut += 4;
+	}
+	memset(&j->cid, 0, sizeof(IXJ_CID));
+	pOut = j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID;
+	pOut += 4;
+	strncpy(j->cid.month, pOut, 2);
+	pOut += 2;
+	strncpy(j->cid.day, pOut, 2);
+	pOut += 2;
+	strncpy(j->cid.hour, pOut, 2);
+	pOut += 2;
+	strncpy(j->cid.min, pOut, 2);
+	pOut += 3;
+	j->cid.numlen = *pOut;
+	pOut += 1;
+	strncpy(j->cid.number, pOut, j->cid.numlen);
+	pOut += j->cid.numlen + 1;
+	j->cid.namelen = *pOut;
+	pOut += 1;
+	strncpy(j->cid.name, pOut, j->cid.namelen);
+
+	ixj_daa_cid_reset(board);
+	return 1;
+}
+
+static char daa_get_version(int board)
+{
+	BYTES bytes;
+	IXJ *j = &ixj[board];
+
+	if (!SCI_Prepare(board))
+		return 0;
+
+	bytes.high = 0x35;
+	bytes.low = 0x00;
+	outb_p(bytes.high, j->XILINXbase + 0x03);
+	outb_p(bytes.low, j->XILINXbase + 0x02);
+
+	if (!SCI_Control(board, SCI_Enable_DAA))
+		return 0;
+
+	bytes.high = inb_p(j->XILINXbase + 0x03);
+	bytes.low = inb_p(j->XILINXbase + 0x02);
+	if (bytes.low != ALISDAA_ID_BYTE) {
+		if (ixjdebug > 0)
+			printk("DAA Get Version Cannot read DAA ID Byte high = %d low = %d\n", bytes.high, bytes.low);
+		return 0;
+	}
+	if (!SCI_Control(board, SCI_Enable_DAA))
+		return 0;
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+
+	bytes.high = inb_p(j->XILINXbase + 0x03);
+	bytes.low = inb_p(j->XILINXbase + 0x02);
+	if (ixjdebug > 0)
+		printk("DAA CR5 Byte high = 0x%x low = 0x%x\n", bytes.high, bytes.low);
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr5.reg = bytes.high;
+	return bytes.high;
+}
+
+static int daa_set_mode(int board, int mode)
+{
+	// NOTE:
+	//      The DAA *MUST* be in the conversation mode if the
+	//      PSTN line is to be seized (PSTN line off-hook).
+	//      Taking the PSTN line off-hook while the DAA is in
+	//      a mode other than conversation mode will cause a
+	//      hardware failure of the ALIS-A part.
+
+	// NOTE:
+	//      The DAA can only go to SLEEP, RINGING or PULSEDIALING modes
+	//      if the PSTN line is on-hook.  Failure to have the PSTN line
+	//      in the on-hook state WILL CAUSE A HARDWARE FAILURE OF THE
+	//      ALIS-A part.
+	//
+
+
+	BYTES bytes;
+	IXJ *j = &ixj[board];
+
+	if (!SCI_Prepare(board))
+		return 0;
+
+	switch (mode) {
+	case SOP_PU_SLEEP:
+		j->pld_scrw.bits.daafsyncen = 0;	// Turn off DAA Frame Sync
+
+		outb_p(j->pld_scrw.byte, j->XILINXbase);
+		j->pld_slicw.bits.rly2 = 0;
+		outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+		bytes.high = 0x10;
+		bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg;
+		daa_load(&bytes, board);
+		if (!SCI_Prepare(board))
+			return 0;
+		j->daa_mode = SOP_PU_SLEEP;
+		j->flags.pstn_ringing = 0;
+		j->pstn_sleeptil = jiffies + (hertz * 3);
+		break;
+	case SOP_PU_RINGING:
+		j->pld_scrw.bits.daafsyncen = 0;	// Turn off DAA Frame Sync
+
+		outb_p(j->pld_scrw.byte, j->XILINXbase);
+		j->pld_slicw.bits.rly2 = 0;
+		outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+		bytes.high = 0x50;
+		bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg;
+		daa_load(&bytes, board);
+		if (!SCI_Prepare(board))
+			return 0;
+		j->daa_mode = SOP_PU_RINGING;
+		break;
+	case SOP_PU_CONVERSATION:
+		bytes.high = 0x90;
+		bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg;
+		daa_load(&bytes, board);
+		if (!SCI_Prepare(board))
+			return 0;
+		j->pld_slicw.bits.rly2 = 1;
+		outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+		j->pld_scrw.bits.daafsyncen = 1;	// Turn on DAA Frame Sync
+
+		outb_p(j->pld_scrw.byte, j->XILINXbase);
+		j->daa_mode = SOP_PU_CONVERSATION;
+		j->flags.pstn_ringing = 0;
+		j->ex.bits.pstn_ring = 0;
+		break;
+	case SOP_PU_PULSEDIALING:
+		j->pld_scrw.bits.daafsyncen = 0;	// Turn off DAA Frame Sync
+
+		outb_p(j->pld_scrw.byte, j->XILINXbase);
+		j->pld_slicw.bits.rly2 = 0;
+		outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+		bytes.high = 0xD0;
+		bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg;
+		daa_load(&bytes, board);
+		if (!SCI_Prepare(board))
+			return 0;
+		j->daa_mode = SOP_PU_PULSEDIALING;
+		break;
+	default:
+		break;
+	}
+	return 1;
+}
+
+static int ixj_daa_write(int board)
+{
+	BYTES bytes;
+	IXJ *j = &ixj[board];
+
+	if (!SCI_Prepare(board))
+		return 0;
+
+	bytes.high = 0x14;
+	bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg;
+	bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg;
+	bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Prepare(board))
+		return 0;
+
+	bytes.high = 0x1F;
+	bytes.low = j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.XOP_xr6_W.reg;
+	bytes.low = j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg;
+	bytes.low = j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg;
+	bytes.low = j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.XOP_xr0_W.reg;
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Prepare(board))
+		return 0;
+
+	bytes.high = 0x00;
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0];
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+	if (!SCI_WaitLowSCI(board))
+		return 0;
+
+	bytes.high = 0x01;
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0];
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+	if (!SCI_WaitLowSCI(board))
+		return 0;
+
+	bytes.high = 0x02;
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0];
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+	if (!SCI_WaitLowSCI(board))
+		return 0;
+
+	bytes.high = 0x03;
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0];
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+	if (!SCI_WaitLowSCI(board))
+		return 0;
+
+	bytes.high = 0x04;
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0];
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+	if (!SCI_WaitLowSCI(board))
+		return 0;
+
+	bytes.high = 0x05;
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0];
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+	if (!SCI_WaitLowSCI(board))
+		return 0;
+
+	bytes.high = 0x06;
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0];
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+	if (!SCI_WaitLowSCI(board))
+		return 0;
+
+	bytes.high = 0x07;
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0];
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+	if (!SCI_WaitLowSCI(board))
+		return 0;
+
+	bytes.high = 0x08;
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0];
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+	if (!SCI_WaitLowSCI(board))
+		return 0;
+
+	bytes.high = 0x09;
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0];
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+	if (!SCI_WaitLowSCI(board))
+		return 0;
+
+	bytes.high = 0x0A;
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0];
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+	if (!SCI_WaitLowSCI(board))
+		return 0;
+
+	bytes.high = 0x0B;
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0];
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+	if (!SCI_WaitLowSCI(board))
+		return 0;
+
+	bytes.high = 0x0C;
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0];
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+	if (!SCI_WaitLowSCI(board))
+		return 0;
+
+	bytes.high = 0x0D;
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0];
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+	if (!SCI_WaitLowSCI(board))
+		return 0;
+
+	bytes.high = 0x0E;
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0];
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+	if (!SCI_WaitLowSCI(board))
+		return 0;
+
+	bytes.high = 0x0F;
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2];
+	bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1];
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0];
+	bytes.low = 0x00;
+	if (!daa_load(&bytes, board))
+		return 0;
+
+	udelay(32);
+	j->pld_scrr.byte = inb_p(j->XILINXbase);
+	if (!SCI_Control(board, SCI_End))
+		return 0;
+
+	return 1;
+}
+
+int ixj_set_tone_off(unsigned short arg, int board)
+{
+	ixj[board].tone_off_time = arg;
+
+	if (ixj_WriteDSPCommand(0x6E05, board))		// Set Tone Off Period
+
+		return -1;
+
+	if (ixj_WriteDSPCommand(arg, board))
+		return -1;
+
+	return 0;
+}
+
+static int ixj_get_tone_on(int board)
+{
+	if (ixj_WriteDSPCommand(0x6E06, board))		// Get Tone On Period
+
+		return -1;
+
+	return 0;
+}
+
+static int ixj_get_tone_off(int board)
+{
+	if (ixj_WriteDSPCommand(0x6E07, board))		// Get Tone Off Period
+
+		return -1;
+
+	return 0;
+}
+
+static void ixj_busytone(int board)
+{
+	ixj[board].flags.ringback = 0;
+	ixj[board].flags.dialtone = 0;
+	ixj[board].flags.busytone = 1;
+
+	ixj_set_tone_on(0x07D0, board);
+	ixj_set_tone_off(0x07D0, board);
+	ixj_play_tone(board, 27);
+}
+
+static void ixj_dialtone(int board)
+{
+	ixj[board].flags.ringback = 0;
+	ixj[board].flags.dialtone = 1;
+	ixj[board].flags.busytone = 0;
+
+	if (ixj[board].dsp.low == 0x20) {
+		return;
+	} else {
+		ixj_set_tone_on(0xFFFF, board);
+		ixj_set_tone_off(0x0000, board);
+
+		ixj_play_tone(board, 25);
+	}
+}
+
+static void ixj_cpt_stop(board)
+{
+	IXJ *j = &ixj[board];
+
+	j->flags.dialtone = 0;
+	j->flags.busytone = 0;
+	j->flags.ringback = 0;
+
+	ixj_set_tone_on(0x0001, board);
+	ixj_set_tone_off(0x0000, board);
+
+	ixj_play_tone(board, 0);
+
+	j->tone_state = 0;
+
+	ixj_del_timer();
+	if (j->cadence_t) {
+		if (j->cadence_t->ce) {
+			kfree(j->cadence_t->ce);
+		}
+		kfree(j->cadence_t);
+		j->cadence_t = NULL;
+	}
+	ixj_add_timer();
+	if (j->dsp.low == 0x20 || (j->play_mode == -1 && j->rec_mode == -1))
+		idle(board);
+	if (j->play_mode != -1)
+		ixj_play_start(board);
+	if (j->rec_mode != -1)
+		ixj_record_start(board);
+}
+
+static void ixj_ringback(int board)
+{
+	ixj[board].flags.busytone = 0;
+	ixj[board].flags.dialtone = 0;
+	ixj[board].flags.ringback = 1;
+
+	ixj_set_tone_on(0x0FA0, board);
+	ixj_set_tone_off(0x2EE0, board);
+	ixj_play_tone(board, 26);
+}
+
+static void ixj_testram(int board)
+{
+	ixj_WriteDSPCommand(0x3001, board);	/* Test External SRAM */
+}
+
+static int ixj_build_cadence(int board, IXJ_CADENCE * cp)
+{
+	IXJ_CADENCE *lcp;
+	IXJ_CADENCE_ELEMENT *lcep;
+	IXJ_TONE ti;
+	IXJ *j = &ixj[board];
+
+	lcp = kmalloc(sizeof(IXJ_CADENCE), GFP_KERNEL);
+	if (lcp == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_CADENCE)))
+		return -EFAULT;
+
+	lcep = kmalloc(sizeof(IXJ_CADENCE_ELEMENT) * lcp->elements_used, GFP_KERNEL);
+	if (lcep == NULL) {
+		kfree(lcp);
+		return -ENOMEM;
+	}
+	if (copy_from_user(lcep, lcp->ce, sizeof(IXJ_CADENCE_ELEMENT) * lcp->elements_used))
+		return -EFAULT;
+
+	if(j->cadence_t)
+	{
+		kfree(j->cadence_t->ce);
+		kfree(j->cadence_t);
+	}
+	
+	lcp->ce = (void *) lcep;
+	j->cadence_t = lcp;
+	j->tone_cadence_state = 0;
+	ixj_set_tone_on(lcp->ce[0].tone_on_time, board);
+	ixj_set_tone_off(lcp->ce[0].tone_off_time, board);
+	if (j->cadence_t->ce[j->tone_cadence_state].freq0) {
+		ti.tone_index = j->cadence_t->ce[j->tone_cadence_state].index;
+		ti.freq0 = j->cadence_t->ce[j->tone_cadence_state].freq0;
+		ti.gain0 = j->cadence_t->ce[j->tone_cadence_state].gain0;
+		ti.freq1 = j->cadence_t->ce[j->tone_cadence_state].freq1;
+		ti.gain1 = j->cadence_t->ce[j->tone_cadence_state].gain1;
+		ixj_init_tone(board, &ti);
+	}
+	ixj_play_tone(board, lcp->ce[0].index);
+
+	return 1;
+}
+
+static void add_caps(int board)
+{
+	IXJ *j = &ixj[board];
+	j->caps = 0;
+
+	j->caplist[j->caps].cap = vendor;
+	strcpy(j->caplist[j->caps].desc, "Quicknet Technologies, Inc. (www.quicknet.net)");
+	j->caplist[j->caps].captype = vendor;
+	j->caplist[j->caps].handle = j->caps++;
+	j->caplist[j->caps].captype = device;
+	switch (j->cardtype) {
+	case 100:
+		strcpy(j->caplist[j->caps].desc, "Quicknet Internet PhoneJACK");
+		j->caplist[j->caps].cap = 100;
+		break;
+	case 300:
+		strcpy(j->caplist[j->caps].desc, "Quicknet Internet LineJACK");
+		j->caplist[j->caps].cap = 300;
+		break;
+	case 400:
+		strcpy(j->caplist[j->caps].desc, "Quicknet Internet PhoneJACK Lite");
+		j->caplist[j->caps].cap = 400;
+		break;
+	case 500:
+		strcpy(j->caplist[j->caps].desc, "Quicknet Internet PhoneJACK PCI");
+		j->caplist[j->caps].cap = 500;
+		break;
+	}
+	j->caplist[j->caps].handle = j->caps++;
+	strcpy(j->caplist[j->caps].desc, "POTS");
+	j->caplist[j->caps].captype = port;
+	j->caplist[j->caps].cap = pots;
+	j->caplist[j->caps].handle = j->caps++;
+	switch (ixj[board].cardtype) {
+	case 100:
+		strcpy(j->caplist[j->caps].desc, "SPEAKER");
+		j->caplist[j->caps].captype = port;
+		j->caplist[j->caps].cap = speaker;
+		j->caplist[j->caps].handle = j->caps++;
+		strcpy(j->caplist[j->caps].desc, "HANDSET");
+		j->caplist[j->caps].captype = port;
+		j->caplist[j->caps].cap = handset;
+		j->caplist[j->caps].handle = j->caps++;
+		break;
+	case 300:
+		strcpy(j->caplist[j->caps].desc, "SPEAKER");
+		j->caplist[j->caps].captype = port;
+		j->caplist[j->caps].cap = speaker;
+		j->caplist[j->caps].handle = j->caps++;
+		strcpy(j->caplist[j->caps].desc, "PSTN");
+		j->caplist[j->caps].captype = port;
+		j->caplist[j->caps].cap = pstn;
+		j->caplist[j->caps].handle = j->caps++;
+		break;
+	}
+	strcpy(j->caplist[j->caps].desc, "ULAW");
+	j->caplist[j->caps].captype = codec;
+	j->caplist[j->caps].cap = ULAW;
+	j->caplist[j->caps].handle = j->caps++;
+	strcpy(j->caplist[j->caps].desc, "LINEAR 16 bit");
+	j->caplist[j->caps].captype = codec;
+	j->caplist[j->caps].cap = LINEAR16;
+	j->caplist[j->caps].handle = j->caps++;
+	strcpy(j->caplist[j->caps].desc, "LINEAR 8 bit");
+	j->caplist[j->caps].captype = codec;
+	j->caplist[j->caps].cap = LINEAR8;
+	j->caplist[j->caps].handle = j->caps++;
+	strcpy(j->caplist[j->caps].desc, "Windows Sound System");
+	j->caplist[j->caps].captype = codec;
+	j->caplist[j->caps].cap = WSS;
+	j->caplist[j->caps].handle = j->caps++;
+	if (j->ver.low != 0x12) {
+		strcpy(j->caplist[j->caps].desc, "G.723.1 6.3Kbps");
+		j->caplist[j->caps].captype = codec;
+		j->caplist[j->caps].cap = G723_63;
+		j->caplist[j->caps].handle = j->caps++;
+		strcpy(j->caplist[j->caps].desc, "G.723.1 5.3Kbps");
+		j->caplist[j->caps].captype = codec;
+		j->caplist[j->caps].cap = G723_53;
+		j->caplist[j->caps].handle = j->caps++;
+		strcpy(j->caplist[j->caps].desc, "TrueSpeech 4.8Kbps");
+		j->caplist[j->caps].captype = codec;
+		j->caplist[j->caps].cap = TS48;
+		j->caplist[j->caps].handle = j->caps++;
+		strcpy(j->caplist[j->caps].desc, "TrueSpeech 4.1Kbps");
+		j->caplist[j->caps].captype = codec;
+		j->caplist[j->caps].cap = TS41;
+		j->caplist[j->caps].handle = j->caps++;
+	}
+	if (j->cardtype == 100) {
+		strcpy(j->caplist[j->caps].desc, "TrueSpeech 8.5Kbps");
+		j->caplist[j->caps].captype = codec;
+		j->caplist[j->caps].cap = TS85;
+		j->caplist[j->caps].handle = j->caps++;
+	}
+}
+static int capabilities_check(int board, struct phone_capability *pcreq)
+{
+	int cnt;
+	IXJ *j = &ixj[board];
+	int retval = 0;
+
+	for (cnt = 0; cnt < j->caps; cnt++) {
+		if (pcreq->captype == j->caplist[cnt].captype &&
+		    pcreq->cap == j->caplist[cnt].cap) {
+			retval = 1;
+			break;
+		}
+	}
+	return retval;
+}
+
+int ixj_ioctl(struct inode *inode, struct file *file_p,
+	      unsigned int cmd, unsigned long arg)
+{
+	IXJ_TONE ti;
+	IXJ_FILTER jf;
+	unsigned int minor = MINOR(inode->i_rdev);
+	int board = NUM(inode->i_rdev);
+	IXJ *j = &ixj[NUM(inode->i_rdev)];
+	int retval = 0;
+
+	if (ixjdebug > 1)
+		printk(KERN_DEBUG "phone%d ioctl, cmd: 0x%x, arg: 0x%lx\n", minor, cmd, arg);
+	if (minor >= IXJMAX)
+		return -ENODEV;
+
+	/*
+	 *    Check ioctls only root can use.
+	 */
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		switch (cmd) {
+		case IXJCTL_TESTRAM:
+		case IXJCTL_HZ:
+			return -EPERM;
+		}
+	}
+	switch (cmd) {
+	case IXJCTL_TESTRAM:
+		ixj_testram(board);
+		retval = (j->ssr.high << 8) + j->ssr.low;
+		break;
+	case IXJCTL_CARDTYPE:
+		retval = j->cardtype;
+		break;
+	case IXJCTL_SERIAL:
+		retval = j->serial;
+		break;
+	case PHONE_RING_CADENCE:
+		j->ring_cadence = arg;
+		break;
+	case PHONE_RING_START:
+		ixj_ring_start(board);
+		break;
+	case PHONE_RING_STOP:
+		j->flags.cringing = 0;
+		ixj_ring_off(board);
+		break;
+	case PHONE_RING:
+		retval = ixj_ring(board);
+		break;
+	case PHONE_EXCEPTION:
+		retval = j->ex.bytes;
+		j->ex.bytes &= 0x03;
+		break;
+	case PHONE_HOOKSTATE:
+		j->ex.bits.hookstate = 0;
+		retval = j->r_hook;
+		break;
+	case IXJCTL_SET_LED:
+		LED_SetState(arg, board);
+		break;
+	case PHONE_FRAME:
+		retval = set_base_frame(board, arg);
+		break;
+	case PHONE_REC_CODEC:
+		retval = set_rec_codec(board, arg);
+		break;
+	case PHONE_REC_START:
+		ixj_record_start(board);
+		break;
+	case PHONE_REC_STOP:
+		ixj_record_stop(board);
+		break;
+	case PHONE_REC_DEPTH:
+		set_rec_depth(board, arg);
+		break;
+	case PHONE_REC_VOLUME:
+		set_rec_volume(board, arg);
+		break;
+	case PHONE_REC_LEVEL:
+		retval = get_rec_level(board);
+		break;
+	case IXJCTL_AEC_START:
+		ixj_aec_start(board, arg);
+		break;
+	case IXJCTL_AEC_STOP:
+		aec_stop(board);
+		break;
+	case IXJCTL_AEC_GET_LEVEL:
+		retval = j->aec_level;
+		break;
+	case PHONE_PLAY_CODEC:
+		retval = set_play_codec(board, arg);
+		break;
+	case PHONE_PLAY_START:
+		ixj_play_start(board);
+		break;
+	case PHONE_PLAY_STOP:
+		ixj_play_stop(board);
+		break;
+	case PHONE_PLAY_DEPTH:
+		set_play_depth(board, arg);
+		break;
+	case PHONE_PLAY_VOLUME:
+		set_play_volume(board, arg);
+		break;
+	case PHONE_PLAY_LEVEL:
+		retval = get_play_level(board);
+		break;
+	case IXJCTL_DSP_TYPE:
+		retval = (j->dsp.high << 8) + j->dsp.low;
+		break;
+	case IXJCTL_DSP_VERSION:
+		retval = (j->ver.high << 8) + j->ver.low;
+		break;
+	case IXJCTL_HZ:
+		hertz = arg;
+		break;
+	case IXJCTL_RATE:
+		if (arg > hertz)
+			retval = -1;
+		else
+			samplerate = arg;
+		break;
+	case IXJCTL_DRYBUFFER_READ:
+		put_user(j->drybuffer, (unsigned long *) arg);
+		break;
+	case IXJCTL_DRYBUFFER_CLEAR:
+		j->drybuffer = 0;
+		break;
+	case IXJCTL_FRAMES_READ:
+		put_user(j->framesread, (unsigned long *) arg);
+		break;
+	case IXJCTL_FRAMES_WRITTEN:
+		put_user(j->frameswritten, (unsigned long *) arg);
+		break;
+	case IXJCTL_READ_WAIT:
+		put_user(j->read_wait, (unsigned long *) arg);
+		break;
+	case IXJCTL_WRITE_WAIT:
+		put_user(j->write_wait, (unsigned long *) arg);
+		break;
+	case PHONE_MAXRINGS:
+		j->maxrings = arg;
+		break;
+	case PHONE_SET_TONE_ON_TIME:
+		ixj_set_tone_on(arg, board);
+		break;
+	case PHONE_SET_TONE_OFF_TIME:
+		ixj_set_tone_off(arg, board);
+		break;
+	case PHONE_GET_TONE_ON_TIME:
+		if (ixj_get_tone_on(board)) {
+			retval = -1;
+		} else {
+			retval = (j->ssr.high << 8) + j->ssr.low;
+		}
+		break;
+	case PHONE_GET_TONE_OFF_TIME:
+		if (ixj_get_tone_off(board)) {
+			retval = -1;
+		} else {
+			retval = (j->ssr.high << 8) + j->ssr.low;
+		}
+		break;
+	case PHONE_PLAY_TONE:
+		if (!j->tone_state)
+			ixj_play_tone(board, arg);
+		break;
+	case PHONE_GET_TONE_STATE:
+		retval = j->tone_state;
+		break;
+	case PHONE_DTMF_READY:
+		retval = j->ex.bits.dtmf_ready;
+		break;
+	case PHONE_GET_DTMF:
+		if (ixj_hookstate(board)) {
+			if (j->dtmf_rp != j->dtmf_wp) {
+				retval = j->dtmfbuffer[j->dtmf_rp];
+				j->dtmf_rp++;
+				if (j->dtmf_rp == 79)
+					j->dtmf_rp = 0;
+				if (j->dtmf_rp == j->dtmf_wp) {
+					j->ex.bits.dtmf_ready = j->dtmf_rp = j->dtmf_wp = 0;
+				}
+			}
+		}
+		break;
+	case PHONE_GET_DTMF_ASCII:
+		if (ixj_hookstate(board)) {
+			if (j->dtmf_rp != j->dtmf_wp) {
+				switch (j->dtmfbuffer[j->dtmf_rp]) {
+				case 10:
+					retval = 42;	//'*';
+
+					break;
+				case 11:
+					retval = 48;	//'0';
+
+					break;
+				case 12:
+					retval = 35;	//'#';
+
+					break;
+				case 28:
+					retval = 65;	//'A';
+
+					break;
+				case 29:
+					retval = 66;	//'B';
+
+					break;
+				case 30:
+					retval = 67;	//'C';
+
+					break;
+				case 31:
+					retval = 68;	//'D';
+
+					break;
+				default:
+					retval = 48 + j->dtmfbuffer[j->dtmf_rp];
+					break;
+				}
+				j->dtmf_rp++;
+				if (j->dtmf_rp == 79)
+					j->dtmf_rp = 0;
+//          if(j->dtmf_rp == j->dtmf_wp)
+				{
+					j->ex.bits.dtmf_ready = j->dtmf_rp = j->dtmf_wp = 0;
+				}
+			}
+		}
+		break;
+	case PHONE_DTMF_OOB:
+		j->flags.dtmf_oob = arg;
+		break;
+	case PHONE_DIALTONE:
+		ixj_dialtone(board);
+		break;
+	case PHONE_BUSY:
+		ixj_busytone(board);
+		break;
+	case PHONE_RINGBACK:
+		ixj_ringback(board);
+		break;
+	case PHONE_CPT_STOP:
+		ixj_cpt_stop(board);
+		break;
+	case IXJCTL_DSP_IDLE:
+		idle(board);
+		break;
+	case IXJCTL_MIXER:
+		ixj_mixer(arg, board);
+		break;
+	case IXJCTL_DAA_COEFF_SET:
+		switch (arg) {
+		case DAA_US:
+			DAA_Coeff_US(board);
+			ixj_daa_write(board);
+			break;
+		case DAA_UK:
+			DAA_Coeff_UK(board);
+			ixj_daa_write(board);
+			break;
+		case DAA_FRANCE:
+			DAA_Coeff_France(board);
+			ixj_daa_write(board);
+			break;
+		case DAA_GERMANY:
+			DAA_Coeff_Germany(board);
+			ixj_daa_write(board);
+			break;
+		case DAA_AUSTRALIA:
+			DAA_Coeff_Australia(board);
+			ixj_daa_write(board);
+			break;
+		case DAA_JAPAN:
+			DAA_Coeff_Japan(board);
+			ixj_daa_write(board);
+			break;
+		default:
+			break;
+		}
+		break;
+	case IXJCTL_DAA_AGAIN:
+		ixj_daa_cr4(board, arg | 0x02);
+		break;
+	case IXJCTL_PSTN_LINETEST:
+		retval = ixj_linetest(board);
+		break;
+	case IXJCTL_CID:
+		if (copy_to_user((char *) arg, &j->cid, sizeof(IXJ_CID)))
+			return -EFAULT;
+		j->ex.bits.caller_id = 0;
+		break;
+	case IXJCTL_WINK_DURATION:
+		j->winktime = arg;
+		break;
+	case IXJCTL_PORT:
+		if (arg)
+			retval = ixj_set_port(board, arg);
+		else
+			retval = j->port;
+		break;
+	case IXJCTL_POTS_PSTN:
+		retval = ixj_set_pots(board, arg);
+		break;
+	case PHONE_CAPABILITIES:
+		retval = j->caps;
+		break;
+	case PHONE_CAPABILITIES_LIST:
+		if (copy_to_user((char *) arg, j->caplist, sizeof(struct phone_capability) * j->caps))
+			return -EFAULT;
+		break;
+	case PHONE_CAPABILITIES_CHECK:
+		retval = capabilities_check(board, (struct phone_capability *) arg);
+		break;
+	case PHONE_PSTN_SET_STATE:
+		daa_set_mode(board, arg);
+		break;
+	case PHONE_PSTN_GET_STATE:
+		retval = j->daa_mode;
+		j->ex.bits.pstn_ring = 0;
+		break;
+	case IXJCTL_SET_FILTER:
+		if (copy_from_user(&jf, (char *) arg, sizeof(ti)))
+			return -EFAULT;
+		retval = ixj_init_filter(board, &jf);
+		break;
+	case IXJCTL_GET_FILTER_HIST:
+		retval = j->filter_hist[arg];
+		break;
+	case IXJCTL_INIT_TONE:
+		copy_from_user(&ti, (char *) arg, sizeof(ti));
+		retval = ixj_init_tone(board, &ti);
+		break;
+	case IXJCTL_TONE_CADENCE:
+		retval = ixj_build_cadence(board, (IXJ_CADENCE *) arg);
+		break;
+	case IXJCTL_INTERCOM_STOP:
+		ixj[board].intercom = -1;
+		ixj[arg].intercom = -1;
+		ixj_record_stop(board);
+		ixj_record_stop(arg);
+		ixj_play_stop(board);
+		ixj_play_stop(arg);
+		idle(board);
+		idle(arg);
+		break;
+	case IXJCTL_INTERCOM_START:
+		ixj[board].intercom = arg;
+		ixj[arg].intercom = board;
+		ixj_play_start(arg);
+		ixj_record_start(board);
+		ixj_play_start(board);
+		ixj_record_start(arg);
+		idle(board);
+		idle(arg);
+		break;
+	}
+	return retval;
+}
+
+static int ixj_fasync(int fd, struct file *file_p, int mode)
+{
+	IXJ *j = &ixj[NUM(file_p->f_dentry->d_inode->i_rdev)];
+	return fasync_helper(fd, file_p, mode, &j->async_queue);
+}
+
+struct file_operations ixj_fops =
+{
+	NULL,			/* ixj_lseek */
+	ixj_enhanced_read,
+	ixj_enhanced_write,
+	NULL,			/* ixj_readdir */
+	ixj_poll,
+	ixj_ioctl,
+	NULL,			/* ixj_mmap */
+//  ixj_open,
+	NULL,			/* ixj_open */
+	NULL,			/* ixj_flush */
+	ixj_release,
+	NULL,			/* ixj_fsync */
+	ixj_fasync,		/* ixj_fasync */
+	NULL,			/* media change */
+	NULL,			/* revalidate */
+	NULL			/* lock */
+};
+
+static int ixj_linetest(int board)
+{
+	unsigned long jifwait;
+	IXJ *j = &ixj[board];
+
+	if (!j->flags.pots_correct) {
+		j->flags.pots_correct = 1;	// Testing
+
+		daa_int_read(board);	//Clear DAA Interrupt flags
+		//
+		// Hold all relays in the normally de-energized position.
+		//
+
+		j->pld_slicw.bits.rly1 = 0;
+		j->pld_slicw.bits.rly2 = 0;
+		j->pld_slicw.bits.rly3 = 0;
+		outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+		j->pld_scrw.bits.daafsyncen = 0;	// Turn off DAA Frame Sync
+
+		outb_p(j->pld_scrw.byte, j->XILINXbase);
+		j->pld_slicr.byte = inb_p(j->XILINXbase + 0x01);
+		if (j->pld_slicr.bits.potspstn) {
+			j->flags.pots_pstn = 1;
+			j->flags.pots_correct = 0;
+			LED_SetState(0x4, board);
+		} else {
+			j->flags.pots_pstn = 0;
+			j->pld_slicw.bits.rly1 = 0;
+			j->pld_slicw.bits.rly2 = 0;
+			j->pld_slicw.bits.rly3 = 1;
+			outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+			j->pld_scrw.bits.daafsyncen = 0;	// Turn off DAA Frame Sync
+
+			outb_p(j->pld_scrw.byte, j->XILINXbase);
+			daa_set_mode(board, SOP_PU_CONVERSATION);
+			jifwait = jiffies + hertz;
+			while (time_before(jiffies, jifwait)) {
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout(1);
+			}
+			daa_int_read(board);
+			daa_set_mode(board, SOP_PU_SLEEP);
+			if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) {
+				j->flags.pots_correct = 0;	// Should not be line voltage on POTS port.
+
+				LED_SetState(0x4, board);
+				j->pld_slicw.bits.rly3 = 0;
+				outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+			} else {
+				j->flags.pots_correct = 1;
+				LED_SetState(0x8, board);
+				j->pld_slicw.bits.rly1 = 1;
+				j->pld_slicw.bits.rly2 = 0;
+				j->pld_slicw.bits.rly3 = 0;
+				outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+			}
+		}
+	}
+	if (!j->flags.pstn_present) {
+		j->pld_slicw.bits.rly3 = 0;
+		outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+		daa_set_mode(board, SOP_PU_CONVERSATION);
+		jifwait = jiffies + hertz;
+		while (time_before(jiffies, jifwait)) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(1);
+		}
+		daa_int_read(board);
+		daa_set_mode(board, SOP_PU_SLEEP);
+		if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) {
+			j->flags.pstn_present = 1;
+		} else {
+			j->flags.pstn_present = 0;
+		}
+	}
+	if (j->flags.pstn_present) {
+		if (j->flags.pots_correct) {
+			LED_SetState(0xA, board);
+		} else {
+			LED_SetState(0x6, board);
+		}
+	} else {
+		if (j->flags.pots_correct) {
+			LED_SetState(0x9, board);
+		} else {
+			LED_SetState(0x5, board);
+		}
+	}
+	return j->flags.pstn_present;
+}
+
+static int ixj_selfprobe(int board)
+{
+	unsigned short cmd;
+	unsigned long jif;
+	BYTES bytes;
+	IXJ *j = &ixj[board];
+
+	if (ixjdebug > 0)
+		printk(KERN_INFO "Write IDLE to Software Control Register\n");
+
+	if (ixj_WriteDSPCommand(0x0000, board))		/* Write IDLE to Software Control Register */
+		return -1;
+
+// The read values of the SSR should be 0x00 for the IDLE command
+	if (j->ssr.low || j->ssr.high)
+		return -1;
+
+	if (ixjdebug > 0)
+		printk(KERN_INFO "Get Device ID Code\n");
+
+	if (ixj_WriteDSPCommand(0x3400, board))		/* Get Device ID Code */
+		return -1;
+
+	j->dsp.low = j->ssr.low;
+	j->dsp.high = j->ssr.high;
+
+	if (ixjdebug > 0)
+		printk(KERN_INFO "Get Device Version Code\n");
+
+	if (ixj_WriteDSPCommand(0x3800, board))		/* Get Device Version Code */
+		return -1;
+
+	j->ver.low = j->ssr.low;
+	j->ver.high = j->ssr.high;
+
+	if (!j->cardtype) {
+		if (j->dsp.low == 0x21) {
+//      j->XILINXbase = j->DSPbase + 0x10;
+			bytes.high = bytes.low = inb_p(j->XILINXbase + 0x02);
+			outb_p(bytes.low ^ 0xFF, j->XILINXbase + 0x02);
+      // Test for Internet LineJACK or Internet PhoneJACK Lite
+			bytes.low = inb_p(j->XILINXbase + 0x02);
+			if (bytes.low == bytes.high)	//  Register is read only on
+                                    //  Internet PhoneJack Lite
+			 {
+				j->cardtype = 400;	// Internet PhoneJACK Lite
+
+				if (check_region(j->XILINXbase, 4)) {
+					printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase);
+					return -1;
+				}
+				request_region(j->XILINXbase, 4, "ixj control");
+				j->pld_slicw.pcib.e1 = 1;
+				outb_p(j->pld_slicw.byte, j->XILINXbase);
+			} else {
+				j->cardtype = 300;	// Internet LineJACK
+
+				if (check_region(j->XILINXbase, 8)) {
+					printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase);
+					return -1;
+				}
+				request_region(j->XILINXbase, 8, "ixj control");
+			}
+		} else if (j->dsp.low == 0x22) {
+			j->cardtype = 500;	// Internet PhoneJACK PCI
+
+			request_region(j->XILINXbase, 4, "ixj control");
+			j->pld_slicw.pcib.e1 = 1;
+			outb_p(j->pld_slicw.byte, j->XILINXbase);
+		} else
+			j->cardtype = 100;	// Internet PhoneJACK
+
+	} else {
+		switch (j->cardtype) {
+		case 100:	// Internet PhoneJACK
+
+			if (!j->dsp.low != 0x20) {
+				j->dsp.high = 0x80;
+				j->dsp.low = 0x20;
+				ixj_WriteDSPCommand(0x3800, board);
+				j->ver.low = j->ssr.low;
+				j->ver.high = j->ssr.high;
+			}
+			break;
+		case 300:	// Internet LineJACK
+
+			if (check_region(j->XILINXbase, 8)) {
+				printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase);
+				return -1;
+			}
+			request_region(j->XILINXbase, 8, "ixj control");
+			break;
+		case 400:	//Internet PhoneJACK Lite
+
+		case 500:	//Internet PhoneJACK PCI
+
+			if (check_region(j->XILINXbase, 4)) {
+				printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase);
+				return -1;
+			}
+			request_region(j->XILINXbase, 4, "ixj control");
+			j->pld_slicw.pcib.e1 = 1;
+			outb_p(j->pld_slicw.byte, j->XILINXbase);
+			break;
+		}
+	}
+	if (j->dsp.low == 0x20 || j->cardtype == 400 || j->cardtype == 500) {
+		if (ixjdebug > 0)
+			printk(KERN_INFO "Write CODEC config to Software Control Register\n");
+
+		if (ixj_WriteDSPCommand(0xC462, board))		/* Write CODEC config to Software Control Register */
+			return -1;
+
+		if (ixjdebug > 0)
+			printk(KERN_INFO "Write CODEC timing to Software Control Register\n");
+
+		if (j->cardtype == 100) {
+			cmd = 0x9FF2;
+		} else {
+			cmd = 0x9FF5;
+		}
+		if (ixj_WriteDSPCommand(cmd, board))	/* Write CODEC timing to Software Control Register */
+			return -1;
+	} else {
+		if (set_base_frame(board, 30) != 30)
+			return -1;
+
+		if (j->cardtype == 300) {
+			if (ixjdebug > 0)
+				printk(KERN_INFO "Write CODEC config to Software Control Register\n");
+
+			if (ixj_WriteDSPCommand(0xC528, board))		/* Write CODEC config to Software Control Register */
+				return -1;
+
+			if (ixjdebug > 0)
+				printk(KERN_INFO "Turn on the PLD Clock at 8Khz\n");
+
+			j->pld_clock.byte = 0;
+			outb_p(j->pld_clock.byte, j->XILINXbase + 0x04);
+		}
+	}
+
+	if (j->dsp.low == 0x20) {
+		if (ixjdebug > 0)
+			printk(KERN_INFO "Configure GPIO pins\n");
+
+		j->gpio.bytes.high = 0x09;
+/*  bytes.low = 0xEF;  0xF7 */
+		j->gpio.bits.gpio1 = 1;
+		j->gpio.bits.gpio2 = 1;
+		j->gpio.bits.gpio3 = 0;
+		j->gpio.bits.gpio4 = 1;
+		j->gpio.bits.gpio5 = 1;
+		j->gpio.bits.gpio6 = 1;
+		j->gpio.bits.gpio7 = 1;
+		ixj_WriteDSPCommand(ixj[board].gpio.word, board);	/* Set GPIO pin directions */
+
+		if (ixjdebug > 0)
+			printk(KERN_INFO "Enable SLIC\n");
+
+		j->gpio.bytes.high = 0x0B;
+		j->gpio.bytes.low = 0x00;
+		j->gpio.bits.gpio1 = 0;
+		j->gpio.bits.gpio2 = 1;
+		j->gpio.bits.gpio5 = 0;
+		ixj_WriteDSPCommand(ixj[board].gpio.word, board);	/* send the ring stop signal */
+		j->port = PORT_POTS;
+	} else {
+		if (j->cardtype == 300) {
+			LED_SetState(0x1, board);
+			jif = jiffies + (hertz / 10);
+			while (time_before(jiffies, jif)) {
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout(1);
+			}
+			LED_SetState(0x2, board);
+			jif = jiffies + (hertz / 10);
+			while (time_before(jiffies, jif)) {
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout(1);
+			}
+			LED_SetState(0x4, board);
+			jif = jiffies + (hertz / 10);
+			while (time_before(jiffies, jif)) {
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout(1);
+			}
+			LED_SetState(0x8, board);
+			jif = jiffies + (hertz / 10);
+			while (time_before(jiffies, jif)) {
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout(1);
+			}
+			LED_SetState(0x0, board);
+
+			daa_get_version(board);
+
+			if (ixjdebug > 0)
+				printk("Loading DAA Coefficients\n");
+
+			DAA_Coeff_US(board);
+			if (!ixj_daa_write(board))
+				printk("DAA write failed on board %d\n", board);
+
+			ixj_daa_cid_reset(board);
+
+			j->flags.pots_correct = 0;
+			j->flags.pstn_present = 0;
+
+			ixj_linetest(board);
+
+			if (j->flags.pots_correct) {
+				j->pld_scrw.bits.daafsyncen = 0;	// Turn off DAA Frame Sync
+
+				outb_p(j->pld_scrw.byte, j->XILINXbase);
+				j->pld_slicw.bits.rly1 = 1;
+				j->pld_slicw.bits.spken = 1;
+				outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+				SLIC_SetState(PLD_SLIC_STATE_STANDBY, board);
+				j->port = PORT_POTS;
+			}
+			if (ixjdebug > 0)
+				printk(KERN_INFO "Enable Mixer\n");
+
+			ixj_mixer(0x0000, board);	//Master Volume Left unmute 0db
+
+			ixj_mixer(0x0100, board);	//Master Volume Right unmute 0db
+
+			ixj_mixer(0x0F00, board);	//Mono Out Volume unmute 0db
+
+			ixj_mixer(0x0C00, board);	//Mono1 Volume unmute 0db
+
+			ixj_mixer(0x0200, board);	//Voice Left Volume unmute 0db
+
+			ixj_mixer(0x0300, board);	//Voice Right Volume unmute 0db
+
+			ixj_mixer(0x110C, board);	//Voice Left and Right out
+
+			ixj_mixer(0x1401, board);	//Mono1 switch on mixer left
+
+			ixj_mixer(0x1501, board);	//Mono1 switch on mixer right
+
+			ixj_mixer(0x1700, board);	//Clock select
+
+			ixj_mixer(0x1800, board);	//ADC Source select
+
+		} else {
+			j->port = PORT_POTS;
+			SLIC_SetState(PLD_SLIC_STATE_STANDBY, board);
+		}
+	}
+
+	j->intercom = -1;
+	j->framesread = j->frameswritten = 0;
+	j->rxreadycheck = j->txreadycheck = 0;
+
+	if (ixj_WriteDSPCommand(0x0000, board))		/* Write IDLE to Software Control Register */
+		return -1;
+
+// The read values of the SSR should be 0x00 for the IDLE command
+	if (j->ssr.low || j->ssr.high)
+		return -1;
+
+	if (ixjdebug > 0)
+		printk(KERN_INFO "Enable Line Monitor\n");
+
+	if (ixjdebug > 0)
+		printk(KERN_INFO "Set Line Monitor to Asyncronous Mode\n");
+
+	if (ixj_WriteDSPCommand(0x7E01, board))		// Asynchronous Line Monitor
+
+		return -1;
+
+	if (ixjdebug > 0)
+		printk(KERN_INFO "Enable DTMF Detectors\n");
+
+	if (ixj_WriteDSPCommand(0x5151, board))		// Enable DTMF detection
+
+		return -1;
+
+	if (ixj_WriteDSPCommand(0x6E01, board))		// Set Asyncronous Tone Generation
+
+		return -1;
+
+	set_rec_depth(board, 2);	// Set Record Channel Limit to 2 frames
+
+	set_play_depth(board, 2);	// Set Playback Channel Limit to 2 frames
+
+	j->ex.bits.dtmf_ready = 0;
+	j->dtmf_state = 0;
+	j->dtmf_wp = ixj[board].dtmf_rp = 0;
+
+	j->rec_mode = ixj[board].play_mode = -1;
+	j->flags.ringing = 0;
+	j->maxrings = MAXRINGS;
+	j->ring_cadence = USA_RING_CADENCE;
+	j->drybuffer = 0;
+	j->winktime = 320;
+	j->flags.dtmf_oob = 0;
+
+	/* must be a device on the specified address */
+	/* Register with the Telephony for Linux subsystem */
+	j->p.f_op = &ixj_fops;
+	j->p.open = ixj_open;
+	phone_register_device(&j->p, PHONE_UNIT_ANY);
+
+	add_caps(board);
+
+	return 0;
+}
+
+int ixj_read_proc(char *buf, char **start, off_t offset, int len, int unused)
+{
+	int cnt;
+	IXJ *j;
+	len = 0;
+
+	len += sprintf(buf + len, "\n%s", ixj_c_rcsid);
+	len += sprintf(buf + len, "\n%s", ixj_h_rcsid);
+	len += sprintf(buf + len, "\n%s", ixjuser_h_rcsid);
+
+	for (cnt = 0; cnt < IXJMAX; cnt++) {
+		j = &ixj[cnt];
+		if (j->DSPbase) {
+			len += sprintf(buf + len, "\nCard Num %d", cnt);
+			len += sprintf(buf + len, "\nDSP Base Address 0x%4.4x", j->DSPbase);
+			if (j->cardtype != 100)
+				len += sprintf(buf + len, "\nXILINX Base Address 0x%4.4x", j->XILINXbase);
+			len += sprintf(buf + len, "\nDSP Type %2.2x%2.2x", j->dsp.high, j->dsp.low);
+			len += sprintf(buf + len, "\nDSP Version %2.2x.%2.2x", j->ver.high, j->ver.low);
+			len += sprintf(buf + len, "\nSerial Number %8.8x", j->serial);
+			switch (j->cardtype) {
+			case (100):
+				len += sprintf(buf + len, "\nCard Type = Internet PhoneJACK");
+				break;
+			case (300):
+				len += sprintf(buf + len, "\nCard Type = Internet LineJACK");
+				if (j->flags.g729_loaded)
+					len += sprintf(buf + len, " w/G.729 A/B");
+				break;
+			case (400):
+				len += sprintf(buf + len, "\nCard Type = Internet PhoneJACK Lite");
+				if (j->flags.g729_loaded)
+					len += sprintf(buf + len, " w/G.729 A/B");
+				break;
+			case (500):
+				len += sprintf(buf + len, "\nCard Type = Internet PhoneJACK PCI");
+				if (j->flags.g729_loaded)
+					len += sprintf(buf + len, " w/G.729 A/B");
+				break;
+			default:
+				len += sprintf(buf + len, "\nCard Type = %d", j->cardtype);
+				break;
+			}
+			len += sprintf(buf + len, "\nCapabilities %d", j->caps);
+			if (j->dsp.low != 0x20)
+				len += sprintf(buf + len, "\nDSP Processor load %d", j->proc_load);
+//    if(j->intercom != -1)
+			//      len += sprintf(buf+len, "\nIntercom call to board %2.2x", j->intercom);
+
+//    len += sprintf(buf+len, "\nRead buffer size %d", j->read_buffer_size);
+			//    len += sprintf(buf+len, "\nWrite buffer size %d", j->write_buffer_size);
+			len += sprintf(buf + len, "\nPlay CODEC ");
+			switch (j->play_codec) {
+			case G723_63:
+				len += sprintf(buf + len, "G.723.1 6.3");
+				break;
+			case G723_53:
+				len += sprintf(buf + len, "G.723.1 5.3");
+				break;
+			case TS85:
+				len += sprintf(buf + len, "TrueSpeech 8.5");
+				break;
+			case TS48:
+				len += sprintf(buf + len, "TrueSpeech 4.8");
+				break;
+			case TS41:
+				len += sprintf(buf + len, "TrueSpeech 4.1");
+				break;
+			case G728:
+				len += sprintf(buf + len, "G.728");
+				break;
+			case G729:
+				len += sprintf(buf + len, "G.729");
+				break;
+			case ULAW:
+				len += sprintf(buf + len, "uLaw");
+				break;
+			case ALAW:
+				len += sprintf(buf + len, "aLaw");
+				break;
+			case LINEAR16:
+				len += sprintf(buf + len, "16 bit Linear");
+				break;
+			case LINEAR8:
+				len += sprintf(buf + len, "8 bit Linear");
+				break;
+			case WSS:
+				len += sprintf(buf + len, "Windows Sound System");
+				break;
+			default:
+				len += sprintf(buf + len, "NO CODEC CHOSEN");
+				break;
+			}
+//    len += sprintf(buf+len, "\nPlay Frame Size %d", j->play_frame_size);
+			//    len += sprintf(buf+len, "\nInfo_write.convert_mode = %d", j->Info_write.convert_mode);
+			//    len += sprintf(buf+len, "\nInfo_write.convert_dir = %d", j->Info_write.convert_dir);
+			len += sprintf(buf + len, "\nRecord CODEC ");
+			switch (j->rec_codec) {
+			case G723_63:
+				len += sprintf(buf + len, "G.723.1 6.3");
+				break;
+			case G723_53:
+				len += sprintf(buf + len, "G.723.1 5.3");
+				break;
+			case TS85:
+				len += sprintf(buf + len, "TrueSpeech 8.5");
+				break;
+			case TS48:
+				len += sprintf(buf + len, "TrueSpeech 4.8");
+				break;
+			case TS41:
+				len += sprintf(buf + len, "TrueSpeech 4.1");
+				break;
+			case G728:
+				len += sprintf(buf + len, "G.728");
+				break;
+			case G729:
+				len += sprintf(buf + len, "G.729");
+				break;
+			case ULAW:
+				len += sprintf(buf + len, "uLaw");
+				break;
+			case ALAW:
+				len += sprintf(buf + len, "aLaw");
+				break;
+			case LINEAR16:
+				len += sprintf(buf + len, "16 bit Linear");
+				break;
+			case LINEAR8:
+				len += sprintf(buf + len, "8 bit Linear");
+				break;
+			case WSS:
+				len += sprintf(buf + len, "Windows Sound System");
+				break;
+			default:
+				len += sprintf(buf + len, "NO CODEC CHOSEN");
+				break;
+			}
+//    len += sprintf(buf+len, "\nRecord Frame Size %d", j->rec_frame_size);
+			switch (j->aec_level) {
+			case AEC_OFF:
+				len += sprintf(buf + len, "\n AEC OFF");
+				break;
+			case AEC_LOW:
+				len += sprintf(buf + len, "\n AEC LOW");
+				break;
+			case AEC_MED:
+				len += sprintf(buf + len, "\n AEC MED");
+				break;
+			case AEC_HIGH:
+				len += sprintf(buf + len, "\n AEC HIGH");
+				break;
+			}
+//    len += sprintf(buf+len, "\nInfo_read.convert_mode = %d", j->Info_read.convert_mode);
+			//    len += sprintf(buf+len, "\nInfo_read.convert_dir = %d", j->Info_read.convert_dir);
+			len += sprintf(buf + len, "\nHook state %d", j->r_hook);	// ixj_hookstate(cnt));
+
+			if (j->cardtype == 300) {
+				len += sprintf(buf + len, "\nPOTS Correct %d", j->flags.pots_correct);
+				len += sprintf(buf + len, "\nPSTN Present %d", j->flags.pstn_present);
+				len += sprintf(buf + len, "\nPOTS to PSTN %d", j->flags.pots_pstn);
+//      len += sprintf(buf+len, "\nDAA Interrupt flags %d", j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.reg);
+				//      len += sprintf(buf+len, "\nDAA version %d", j->m_DAAShadowRegs.SOP_REGS.SOP.cr5.reg);
+				switch (j->daa_mode) {
+				case SOP_PU_SLEEP:
+					len += sprintf(buf + len, "\nDAA PSTN On Hook");
+					break;
+				case SOP_PU_RINGING:
+					len += sprintf(buf + len, "\nDAA PSTN Ringing");
+					break;
+				case SOP_PU_CONVERSATION:
+					len += sprintf(buf + len, "\nDAA PSTN Off Hook");
+					break;
+				case SOP_PU_PULSEDIALING:
+					len += sprintf(buf + len, "\nDAA PSTN Pulse Dialing");
+					break;
+				}
+//      len += sprintf(buf+len, "\nDAA PSTN Ring flag = %d", j->pstn_ringing);
+			}
+			switch (j->port) {
+			case PORT_POTS:
+				len += sprintf(buf + len, "\nPort POTS");
+				break;
+			case PORT_PSTN:
+				len += sprintf(buf + len, "\nPort PSTN");
+				break;
+			case PORT_SPEAKER:
+				len += sprintf(buf + len, "\nPort SPEAKER/MIC");
+				break;
+			case PORT_HANDSET:
+				len += sprintf(buf + len, "\nPort HANDSET");
+				break;
+			}
+			if (j->dsp.low == 0x21 || j->dsp.low == 0x22) {
+				len += sprintf(buf + len, "\nSLIC state ");
+				switch (SLIC_GetState(cnt)) {
+				case PLD_SLIC_STATE_OC:
+					len += sprintf(buf + len, "OC");
+					break;
+				case PLD_SLIC_STATE_RINGING:
+					len += sprintf(buf + len, "RINGING");
+					break;
+				case PLD_SLIC_STATE_ACTIVE:
+					len += sprintf(buf + len, "ACTIVE");
+					break;
+				case PLD_SLIC_STATE_OHT:	// On-hook transmit
+
+					len += sprintf(buf + len, "OHT");
+					break;
+				case PLD_SLIC_STATE_TIPOPEN:
+					len += sprintf(buf + len, "TIPOPEN");
+					break;
+				case PLD_SLIC_STATE_STANDBY:
+					len += sprintf(buf + len, "STANDBY");
+					break;
+				case PLD_SLIC_STATE_APR:	// Active polarity reversal
+
+					len += sprintf(buf + len, "APR");
+					break;
+				case PLD_SLIC_STATE_OHTPR:	// OHT polarity reversal
+
+					len += sprintf(buf + len, "OHTPR");
+					break;
+				default:
+					len += sprintf(buf + len, "%d", SLIC_GetState(cnt));
+					break;
+				}
+			}
+//    len += sprintf(buf+len, "\nRead buffers ready %d", j->read_buffer_ready);
+			//    len += sprintf(buf+len, "\nWrite buffers empty %d",j->write_buffers_empty);
+
+//    len += sprintf(buf+len, "\nDTMF ready %d", j->ex.bits.dtmf_ready);
+			//    len += sprintf(buf+len, "\nDTMF proc %d", j->dtmf_proc);
+			//    len += sprintf(buf+len, "\nDTMF wp %d", j->dtmf_wp);
+			//    len += sprintf(buf+len, "\nDTMF rp %d", j->dtmf_rp);
+			//    len += sprintf(buf+len, "\nDTMF digits ");
+			//    for(x=j->dtmf_rp; x <j->dtmf_wp; x++)
+			//    {
+			//      if(x == 79)
+			//        x = 0;
+			//      len += sprintf(buf+len, "%x", j->dtmfbuffer[x]);
+			//    }
+#ifdef PERFMON_STATS
+			len += sprintf(buf + len, "\nTimer Checks %ld", j->timerchecks);
+
+			len += sprintf(buf + len, "\nRX Ready Checks %ld", j->rxreadycheck);
+			len += sprintf(buf + len, "\nTX Ready Checks %ld", j->txreadycheck);
+			len += sprintf(buf + len, "\nBase Frame %2.2x.%2.2x", j->baseframe.high, j->baseframe.low);
+			len += sprintf(buf + len, "\nFrames Read %ld", j->framesread);
+			len += sprintf(buf + len, "\nFrames Written %ld", j->frameswritten);
+			len += sprintf(buf + len, "\nDry Buffer %ld", j->drybuffer);
+			len += sprintf(buf + len, "\nRead Waits %ld", j->read_wait);
+			len += sprintf(buf + len, "\nWrite Waits %ld", j->write_wait);
+#endif
+			len += sprintf(buf + len, "\n");
+		}
+	}
+	return len;
+}
+
+static struct proc_dir_entry ixj_proc_entry =
+{
+	0,
+	3, "ixj",
+	S_IFREG | S_IRUGO,
+	1, 0, 0,
+	0,
+	NULL,
+	&ixj_read_proc
+};
+
+static void cleanup(void)
+{
+	int cnt;
+
+	del_timer(&ixj_timer);
+//  if (ixj_major)
+	//    unregister_chrdev(ixj_major, "ixj");
+	for (cnt = 0; cnt < IXJMAX; cnt++) {
+		if (ixj[cnt].cardtype == 300) {
+			ixj[cnt].pld_scrw.bits.daafsyncen = 0;	// Turn off DAA Frame Sync
+
+			outb_p(ixj[cnt].pld_scrw.byte, ixj[cnt].XILINXbase);
+			ixj[cnt].pld_slicw.bits.rly1 = 0;
+			ixj[cnt].pld_slicw.bits.rly2 = 0;
+			ixj[cnt].pld_slicw.bits.rly3 = 0;
+			outb_p(ixj[cnt].pld_slicw.byte, ixj[cnt].XILINXbase + 0x01);
+			LED_SetState(0x0, cnt);
+
+			release_region(ixj[cnt].XILINXbase, 8);
+		}
+		if (ixj[cnt].cardtype == 400 || ixj[cnt].cardtype == 500) {
+			release_region(ixj[cnt].XILINXbase, 4);
+		}
+		if (ixj[cnt].DSPbase) {
+			release_region(ixj[cnt].DSPbase, 16);
+			phone_unregister_device(&ixj[cnt].p);
+		}
+		if (ixj[cnt].read_buffer)
+			kfree(ixj[cnt].read_buffer);
+		if (ixj[cnt].write_buffer)
+			kfree(ixj[cnt].write_buffer);
+#ifdef CONFIG_ISAPNP
+		if (ixj[cnt].dev)
+			ixj[cnt].dev->deactivate(ixj[cnt].dev);
+#endif
+	}
+	proc_unregister(&proc_root, ixj_proc_entry.low_ino);
+}
+
+
+// Typedefs
+typedef struct {
+	BYTE length;
+	DWORD bits;
+} DATABLOCK;
+
+static void PCIEE_WriteBit(WORD wEEPROMAddress, BYTE lastLCC, BYTE byData)
+{
+	lastLCC = lastLCC & 0xfb;
+	lastLCC = lastLCC | (byData ? 4 : 0);
+	outb(lastLCC, wEEPROMAddress);	//set data out bit as appropriate
+
+	udelay(1000);
+	lastLCC = lastLCC | 0x01;
+	outb(lastLCC, wEEPROMAddress);	//SK rising edge
+
+	byData = byData << 1;
+	lastLCC = lastLCC & 0xfe;
+
+	udelay(1000);
+	outb(lastLCC, wEEPROMAddress);	//after delay, SK falling edge
+
+}
+
+static BYTE PCIEE_ReadBit(WORD wEEPROMAddress, BYTE lastLCC)
+{
+	udelay(1000);
+	lastLCC = lastLCC | 0x01;
+	outb(lastLCC, wEEPROMAddress);	//SK rising edge
+
+	lastLCC = lastLCC & 0xfe;
+	udelay(1000);
+	outb(lastLCC, wEEPROMAddress);	//after delay, SK falling edge
+
+	return ((inb(wEEPROMAddress) >> 3) & 1);
+}
+
+static BOOL PCIEE_ReadWord(WORD wAddress, WORD wLoc, WORD * pwResult)
+{
+	BYTE lastLCC;
+	WORD wEEPROMAddress = wAddress + 3;
+	DWORD i;
+	BYTE byResult;
+
+	*pwResult = 0;
+
+	lastLCC = inb(wEEPROMAddress);
+
+	lastLCC = lastLCC | 0x02;
+	lastLCC = lastLCC & 0xfe;
+	outb(lastLCC, wEEPROMAddress);	// CS hi, SK lo
+
+	udelay(1000);		// delay
+
+	PCIEE_WriteBit(wEEPROMAddress, lastLCC, 1);
+	PCIEE_WriteBit(wEEPROMAddress, lastLCC, 1);
+	PCIEE_WriteBit(wEEPROMAddress, lastLCC, 0);
+
+	for (i = 0; i < 8; i++) {
+		PCIEE_WriteBit(wEEPROMAddress, lastLCC, wLoc & 0x80 ? 1 : 0);
+		wLoc <<= 1;
+	}
+
+	for (i = 0; i < 16; i++) {
+		byResult = PCIEE_ReadBit(wEEPROMAddress, lastLCC);
+		*pwResult = (*pwResult << 1) | byResult;
+	}
+
+	udelay(1000);		// another delay
+
+	lastLCC = lastLCC & 0xfd;
+	outb(lastLCC, wEEPROMAddress);	// negate CS
+
+	return 0;
+}
+
+static DWORD PCIEE_GetSerialNumber(WORD wAddress)
+{
+	WORD wLo, wHi;
+
+	if (PCIEE_ReadWord(wAddress, 62, &wLo))
+		return 0;
+
+	if (PCIEE_ReadWord(wAddress, 63, &wHi))
+		return 0;
+
+	return (((DWORD) wHi << 16) | wLo);
+}
+
+static int dspio[IXJMAX + 1] = {0,};
+static int xio[IXJMAX + 1] = {0,};
+
+MODULE_DESCRIPTION("Internet PhoneJACK/Internet LineJACK module - www.quicknet.net");
+MODULE_AUTHOR("Ed Okerson <eokerson@quicknet.net>");
+
+MODULE_PARM(dspio, "1-" __MODULE_STRING(IXJMAX) "i");
+MODULE_PARM(xio, "1-" __MODULE_STRING(IXJMAX) "i");
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+	cleanup();
+}
+
+int init_module(void)
+#else
+int __init ixj_init(void)
+#endif
+{
+	int result;
+
+	int func = 0x110, i = 0;
+	int cnt = 0;
+	int probe = 0;
+	struct pnp_dev *dev = NULL, *old_dev = NULL;
+	struct pci_dev *pci = NULL;
+
+#ifdef CONFIG_ISAPNP
+	while (1) {
+		do {
+			old_dev = dev;
+			dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('Q', 'T', 'I'),
+					 ISAPNP_FUNCTION(func), old_dev);
+//(old_dev==NULL?NULL:old_dev));
+			if (!dev)
+				break;
+			printk("preparing %x\n", func);
+			result = dev->prepare(dev);
+			if (result < 0) {
+				printk("preparing failed %d \n", result);
+				break;
+			}
+			if (!(dev->resource[0].flags & IORESOURCE_IO))
+				return -ENODEV;
+			dev->resource[0].flags |= IORESOURCE_AUTO;
+			if (func != 0x110)
+				dev->resource[1].flags |= IORESOURCE_AUTO;
+			if (dev->activate(dev) < 0) {
+				printk("isapnp configure failed (out of resources?)\n");
+				return -ENOMEM;
+			}
+			ixj[cnt].DSPbase = dev->resource[0].start;	/* get real port */
+			if (func != 0x110)
+				ixj[cnt].XILINXbase = dev->resource[1].start;	/* get real port */
+
+			result = check_region(ixj[cnt].DSPbase, 16);
+			if (result) {
+				printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", ixj[cnt].DSPbase);
+				cleanup();
+				return result;
+			}
+			request_region(ixj[cnt].DSPbase, 16, "ixj DSP");
+			switch (func) {
+			case (0x110):
+				ixj[cnt].cardtype = 100;
+				break;
+			case (0x310):
+				ixj[cnt].cardtype = 300;
+				break;
+			case (0x410):
+				ixj[cnt].cardtype = 400;
+				break;
+			}
+			probe = ixj_selfprobe(cnt);
+
+			ixj[cnt].serial = dev->bus->serial;
+			ixj[cnt].dev = dev;
+			printk(KERN_INFO "ixj: found card at 0x%x\n", ixj[cnt].DSPbase);
+			cnt++;
+		} while (dev);
+
+		if (func == 0x410)
+			break;
+		if (func == 0x310)
+			func = 0x410;
+		if (func == 0x110)
+			func = 0x310;
+		dev = NULL;
+	}
+#else				//CONFIG_ISAPNP
+	/* Use passed parameters for older kernels without PnP */
+
+	for (cnt = 0; cnt < IXJMAX; cnt++) {
+		if (dspio[cnt]) {
+			ixj[cnt].DSPbase = dspio[cnt];
+			ixj[cnt].XILINXbase = xio[cnt];
+			ixj[cnt].cardtype = 0;
+			result = check_region(ixj[cnt].DSPbase, 16);
+			if (result) {
+				printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", ixj[cnt].DSPbase);
+				cleanup();
+				return result;
+			}
+			request_region(ixj[cnt].DSPbase, 16, "ixj DSP");
+			probe = ixj_selfprobe(cnt);
+			ixj[cnt].dev = NULL;
+		}
+	}
+#endif
+#ifdef CONFIG_PCI
+	if (pci_present()) {
+		for (i = 0; i < IXJMAX - cnt; i++) {
+			pci = pci_find_device(0x15E2, 0x0500, pci);
+			if (!pci)
+				break;
+			{
+				ixj[cnt].DSPbase = pci->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+				ixj[cnt].XILINXbase = ixj[cnt].DSPbase + 0x10;
+				ixj[cnt].serial = PCIEE_GetSerialNumber(pci->base_address[2] & PCI_BASE_ADDRESS_IO_MASK);
+
+				result = check_region(ixj[cnt].DSPbase, 16);
+				if (result) {
+					printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", ixj[cnt].DSPbase);
+					cleanup();
+					return result;
+				}
+				request_region(ixj[cnt].DSPbase, 16, "ixj DSP");
+				ixj[cnt].cardtype = 500;
+				probe = ixj_selfprobe(cnt);
+				cnt++;
+			}
+		}
+	}
+#endif
+	printk("%s\n", ixj_c_rcsid);
+
+//  result = register_chrdev(ixj_major, "ixj", &ixj_fops);
+	//  if (result < 0) {
+	//    printk(KERN_INFO "ixj: can't get major number\n");
+	//    cleanup();
+	//    return result;
+	//  }
+	//  if (ixj_major == 0)
+	//    ixj_major = result;               /* dynamic */
+
+	proc_register(&proc_root, &ixj_proc_entry);
+
+	ixj_init_timer();
+	ixj_add_timer();	
+	return probe;
+}
+
+static void DAA_Coeff_US(int board)
+{
+	IXJ *j = &ixj[board];
+
+	int i;
+
+	//-----------------------------------------------
+	// CAO
+	for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+		j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+	}
+
+	// Bytes for IM-filter part 1 (04): 0E,32,E2,2F,C2,5A,C0,00
+	    j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x0E;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xE2;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0x2F;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0xC2;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0x5A;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xC0;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+// Bytes for IM-filter part 2 (05): 72,85,00,0E,2B,3A,D0,08
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x72;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0x85;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x0E;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0x2B;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x3A;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xD0;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter       (08): 03,8F,48,F2,8F,48,70,08
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x03;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x8F;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0x48;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0xF2;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0x8F;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x48;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0x70;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter       (07): 04,8F,38,7F,9B,EA,B0,08
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x04;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x8F;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0x38;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0x7F;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x9B;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xEA;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0xB0;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter        (0A): 16,55,DD,CA
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x16;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0x55;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter        (09): 52,D3,11,42
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0x52;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0xD3;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x11;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0x42;
+
+// Bytes for TH-filter part 1 (00): 00,42,48,81,B3,80,00,98
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x42;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x48;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x81;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xB3;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,F2,33,A0,68,AB,8A,AD
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0xF2;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x33;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0xA0;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0x68;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0xAB;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x8A;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0xAD;
+
+// Bytes for TH-filter part 3 (02): 00,88,DA,54,A4,BA,2D,BB
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0xDA;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0x54;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0xA4;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0x2D;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0xBB;
+
+// ;  (10K, 0.68uF)
+	// 
+	// Bytes for Ringing part 1 (03):1B,3B,9B,BA,D4,1C,B3,23
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3B;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x9B;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0xD4;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x1C;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xB3;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):13,42,A6,BA,D4,73,CA,D5
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x13;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0x42;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0xD4;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x73;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0xCA;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// 
+	// Levelmetering Ringing        (0D):B2,45,0F,8E      
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0xB2;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x45;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0x0F;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x8E;
+
+// Caller ID 1st Tone           (0E):CA,0E,CA,09,99,99,99,99
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone           (0F):FD,B5,BA,07,DA,00,00,00
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// 
+	// ;CR Registers
+	// Config. Reg. 0 (filters)       (cr0):FE ; CLK gen. by crystal
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFE;
+
+// Config. Reg. 1 (dialing)       (cr1):05
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID)     (cr2):04
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops)     (cr3):03 ; SEL Bit==0, HP-disabled
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x03;
+
+// Config. Reg. 4 (analog gain)   (cr4):01
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02;		//0x01;
+
+// Config. Reg. 5 (Version)       (cr5):02
+	// Config. Reg. 6 (Reserved)      (cr6):00
+	// Config. Reg. 7 (Reserved)      (cr7):00
+	// 
+
+// ;xr Registers
+	// Ext. Reg. 0 (Interrupt Reg.)   (xr0):02
+	j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02;	// SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable) (xr1):1C // Cadence, RING, Caller ID, VDD_OK
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x3C;
+
+// Ext. Reg. 2 (Cadence Time Out) (xr2):7D
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char)          (xr3):32 ; B-Filter Off == 1
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x12;		//0x32;
+
+// Ext. Reg. 4 (Cadence)          (xr4):00
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer)       (xr5):22
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State)      (xr6):00
+	j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd)              (xr7):40
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x40;		// 0x40 ??? Should it be 0x00?
+
+// 
+	// DTMF Tone 1                     (0B): 11,B3,5A,2C ;   697 Hz  
+	//                                       12,33,5A,C3 ;  770 Hz  
+	//                                       13,3C,5B,32 ;  852 Hz  
+	//                                       1D,1B,5C,CC ;  941 Hz  
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2                     (0C): 32,32,52,B3 ;  1209 Hz  
+	//                                       EC,1D,52,22 ;  1336 Hz  
+	//                                       AA,AC,51,D2 ;  1477 Hz  
+	//                                       9B,3B,51,25 ;  1633 Hz  
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+static void DAA_Coeff_UK(int board)
+{
+	IXJ *j = &ixj[board];
+
+	int i;
+
+	//-----------------------------------------------
+	// CAO
+	for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+		j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+	}
+
+	//  Bytes for IM-filter part 1 (04): 00,C2,BB,A8,CB,81,A0,00
+	    j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xC2;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xBB;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0xA8;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0xCB;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0x81;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xA0;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+	// Bytes for IM-filter part 2 (05): 40,00,00,0A,A4,33,E0,08
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x40;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x0A;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0xA4;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x33;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xE0;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter       (08): 07,9B,ED,24,B2,A2,A0,08
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x07;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x9B;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0xED;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0x24;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0xB2;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0xA2;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0xA0;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter       (07): 0F,92,F2,B2,87,D2,30,08
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x0F;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x92;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0xF2;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0xB2;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x87;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xD2;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0x30;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter        (0A): 1B,A5,DD,CA
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x1B;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0xA5;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter        (09): E2,27,10,D6
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0xE2;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0x27;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x10;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0xD6;
+
+// Bytes for TH-filter part 1 (00): 80,2D,38,8B,D0,00,00,98
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x80;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x2D;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x38;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x8B;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xD0;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,5A,53,F0,0B,5F,84,D4
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0x5A;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x53;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0xF0;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0x0B;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0x5F;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x84;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0xD4;
+
+// Bytes for TH-filter part 3 (02): 00,88,6A,A4,8F,52,F5,32
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0x6A;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0xA4;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0x8F;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0x52;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0xF5;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0x32;
+
+// ; idle
+
+// Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3C;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x93;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0x3A;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0x22;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x12;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xA3;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):12,A2,A6,BA,22,7A,0A,D5
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x12;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0xA2;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0x22;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x7A;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0x0A;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// Levelmetering Ringing           (0D):AA,35,0F,8E     ; 25Hz 30V less possible?
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0xAA;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x35;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0x0F;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x8E;
+
+// Caller ID 1st Tone              (0E):CA,0E,CA,09,99,99,99,99
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone              (0F):FD,B5,BA,07,DA,00,00,00
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// ;CR Registers
+	// Config. Reg. 0 (filters)        (cr0):FF
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF;		//0xFE;
+
+// Config. Reg. 1 (dialing)        (cr1):05
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID)      (cr2):04
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops)      (cr3):00        ; 
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00;
+
+// Config. Reg. 4 (analog gain)    (cr4):01
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02;		//0x01;
+
+// Config. Reg. 5 (Version)        (cr5):02
+	// Config. Reg. 6 (Reserved)       (cr6):00
+	// Config. Reg. 7 (Reserved)       (cr7):00
+
+// ;xr Registers
+	// Ext. Reg. 0 (Interrupt Reg.)    (xr0):02
+	j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02;	// SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable)  (xr1):1C
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C;		// RING, Caller ID, VDD_OK
+
+// Ext. Reg. 2 (Cadence Time Out)  (xr2):7D
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char)           (xr3):36        ; 
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x36;
+
+// Ext. Reg. 4 (Cadence)           (xr4):00
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer)        (xr5):22
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State)       (xr6):00
+	j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd)               (xr7):46
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x46;		// 0x46 ??? Should it be 0x00?
+
+// DTMF Tone 1                     (0B): 11,B3,5A,2C    ;   697 Hz  
+	//                                       12,33,5A,C3    ;  770 Hz  
+	//                                       13,3C,5B,32    ;  852 Hz  
+	//                                       1D,1B,5C,CC    ;  941 Hz  
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2                     (0C): 32,32,52,B3    ;  1209 Hz  
+	//                                       EC,1D,52,22    ;  1336 Hz  
+	//                                       AA,AC,51,D2    ;  1477 Hz  
+	//                                       9B,3B,51,25    ;  1633 Hz  
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+
+static void DAA_Coeff_France(int board)
+{
+	IXJ *j = &ixj[board];
+
+	int i;
+
+	//-----------------------------------------------
+	// CAO
+	for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+		j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+	}
+
+	// Bytes for IM-filter part 1 (04): 02,A2,43,2C,22,AF,A0,00
+	    j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x02;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xA2;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0x43;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0x2C;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0x22;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0xAF;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xA0;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+// Bytes for IM-filter part 2 (05): 67,CE,00,0C,22,33,E0,08
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x67;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0xCE;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x2C;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0x22;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x33;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xE0;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter       (08): 07,9A,28,F6,23,4A,B0,08
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x07;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x9A;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0x28;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0xF6;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0x23;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x4A;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0xB0;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter       (07): 03,8F,F9,2F,9E,FA,20,08
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x03;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x8F;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0xF9;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0x2F;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x9E;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xFA;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0x20;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter        (0A): 16,B5,DD,CA
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x16;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0xB5;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter        (09): 52,C7,10,D6
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0xE2;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0xC7;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x10;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0xD6;
+
+// Bytes for TH-filter part 1 (00): 00,42,48,81,A6,80,00,98
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x42;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x48;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x81;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xA6;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,AC,2A,30,78,AC,8A,2C
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0xAC;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x2A;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0x30;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0x78;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0xAC;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x8A;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0x2C;
+
+// Bytes for TH-filter part 3 (02): 00,88,DA,A5,22,BA,2C,45
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0xDA;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0xA5;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0x22;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0x2C;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0x45;
+
+// ; idle
+
+// Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3C;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x93;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0x3A;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0x22;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x12;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xA3;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):12,A2,A6,BA,22,7A,0A,D5
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x12;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0xA2;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0x22;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x7A;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0x0A;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// Levelmetering Ringing           (0D):32,45,B5,84     ; 50Hz 20V
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x45;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0xB5;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x84;
+
+// Caller ID 1st Tone              (0E):CA,0E,CA,09,99,99,99,99
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone              (0F):FD,B5,BA,07,DA,00,00,00
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// ;CR Registers
+	// Config. Reg. 0 (filters)        (cr0):FF
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF;
+
+// Config. Reg. 1 (dialing)        (cr1):05
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID)      (cr2):04
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops)      (cr3):00        ; 
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00;
+
+// Config. Reg. 4 (analog gain)    (cr4):01
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02;		//0x01;
+
+// Config. Reg. 5 (Version)        (cr5):02
+	// Config. Reg. 6 (Reserved)       (cr6):00
+	// Config. Reg. 7 (Reserved)       (cr7):00
+
+// ;xr Registers
+	// Ext. Reg. 0 (Interrupt Reg.)    (xr0):02
+	j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02;	// SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable)  (xr1):1C
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C;		// RING, Caller ID, VDD_OK
+
+// Ext. Reg. 2 (Cadence Time Out)  (xr2):7D
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char)           (xr3):36        ; 
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x36;
+
+// Ext. Reg. 4 (Cadence)           (xr4):00
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer)        (xr5):22
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State)       (xr6):00
+	j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd)               (xr7):46
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x46;		// 0x46 ??? Should it be 0x00?
+
+// DTMF Tone 1                     (0B): 11,B3,5A,2C    ;   697 Hz  
+	//                                       12,33,5A,C3    ;  770 Hz  
+	//                                       13,3C,5B,32    ;  852 Hz  
+	//                                       1D,1B,5C,CC    ;  941 Hz  
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2                     (0C): 32,32,52,B3    ;  1209 Hz  
+	//                                       EC,1D,52,22    ;  1336 Hz  
+	//                                       AA,AC,51,D2    ;  1477 Hz  
+	//                                       9B,3B,51,25    ;  1633 Hz  
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+
+static void DAA_Coeff_Germany(int board)
+{
+	IXJ *j = &ixj[board];
+
+	int i;
+
+	//-----------------------------------------------
+	// CAO
+	for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+		j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+	}
+
+	// Bytes for IM-filter part 1 (04): 00,CE,BB,B8,D2,81,B0,00
+	    j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xCE;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xBB;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0xB8;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0xD2;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0x81;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xB0;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+// Bytes for IM-filter part 2 (05): 45,8F,00,0C,D2,3A,D0,08
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x45;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0x8F;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x0C;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0xD2;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x3A;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xD0;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter       (08): 07,AA,E2,34,24,89,20,08
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x07;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0xAA;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0xE2;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0x34;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0x24;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x89;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0x20;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter       (07): 02,87,FA,37,9A,CA,B0,08
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x02;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x87;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0xFA;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0x37;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x9A;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xCA;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0xB0;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter        (0A): 72,D5,DD,CA
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x72;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0xD5;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter        (09): 72,42,13,4B
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0x72;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0x42;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x13;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0x4B;
+
+// Bytes for TH-filter part 1 (00): 80,52,48,81,AD,80,00,98
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x80;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x52;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x48;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x81;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xAD;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,42,5A,20,E8,1A,81,27
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0x42;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x5A;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0x20;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0xE8;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0x1A;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x81;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0x27;
+
+// Bytes for TH-filter part 3 (02): 00,88,63,26,BD,4B,A3,C2
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0x63;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0x26;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0xBD;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0x4B;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0xA3;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0xC2;
+
+// ;  (10K, 0.68uF)
+
+// Bytes for Ringing part 1 (03):1B,3B,9B,BA,D4,1C,B3,23
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3B;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x9B;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0xD4;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x1C;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xB3;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):13,42,A6,BA,D4,73,CA,D5
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x13;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0x42;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0xD4;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x73;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0xCA;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// Levelmetering Ringing        (0D):B2,45,0F,8E      
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0xB2;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x45;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0x0F;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x8E;
+
+// Caller ID 1st Tone           (0E):CA,0E,CA,09,99,99,99,99
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone           (0F):FD,B5,BA,07,DA,00,00,00
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// ;CR Registers
+	// Config. Reg. 0 (filters)        (cr0):FF ; all Filters enabled, CLK from ext. source
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF;
+
+// Config. Reg. 1 (dialing)        (cr1):05 ; Manual Ring, Ring metering enabled
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID)      (cr2):04 ; Analog Gain 0dB, FSC internal
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops)      (cr3):00 ; SEL Bit==0, HP-enabled
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00;
+
+// Config. Reg. 4 (analog gain)    (cr4):01
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02;		//0x01;
+
+// Config. Reg. 5 (Version)        (cr5):02
+	// Config. Reg. 6 (Reserved)       (cr6):00
+	// Config. Reg. 7 (Reserved)       (cr7):00
+
+// ;xr Registers
+	// Ext. Reg. 0 (Interrupt Reg.)    (xr0):02
+	j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02;	// SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable)  (xr1):1C ; Ring, CID, VDDOK Interrupts enabled
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C;		// RING, Caller ID, VDD_OK
+
+// Ext. Reg. 2 (Cadence Time Out)  (xr2):7D
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char)           (xr3):32 ; B-Filter Off==1, U0=3.5V, R=200Ohm
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x32;
+
+// Ext. Reg. 4 (Cadence)           (xr4):00
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer)        (xr5):22
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State)       (xr6):00
+	j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd)               (xr7):40 ; VDD=4.25 V
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x40;		// 0x40 ??? Should it be 0x00?
+
+// DTMF Tone 1                     (0B): 11,B3,5A,2C    ;   697 Hz  
+	//                                       12,33,5A,C3    ;  770 Hz  
+	//                                       13,3C,5B,32    ;  852 Hz  
+	//                                       1D,1B,5C,CC    ;  941 Hz  
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2                     (0C): 32,32,52,B3    ;  1209 Hz  
+	//                                       EC,1D,52,22    ;  1336 Hz  
+	//                                       AA,AC,51,D2    ;  1477 Hz  
+	//                                       9B,3B,51,25    ;  1633 Hz  
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+
+static void DAA_Coeff_Australia(int board)
+{
+	IXJ *j = &ixj[board];
+
+	int i;
+
+	//-----------------------------------------------
+	// CAO
+	for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+		j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+	}
+
+	// Bytes for IM-filter part 1 (04): 00,A3,AA,28,B3,82,D0,00
+	    j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xA3;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xAA;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0x28;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0xB3;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0x82;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xD0;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+// Bytes for IM-filter part 2 (05): 70,96,00,09,32,6B,C0,08
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x70;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0x96;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x09;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x6B;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xC0;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter       (08): 07,96,E2,34,32,9B,30,08
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x07;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x96;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0xE2;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0x34;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x9B;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0x30;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter       (07): 0F,9A,E9,2F,22,CC,A0,08
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x0F;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x9A;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0xE9;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0x2F;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x22;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xCC;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0xA0;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter        (0A): CB,45,DD,CA
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0xCB;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0x45;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter        (09): 1B,67,10,D6
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0x1B;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0x67;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x10;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0xD6;
+
+// Bytes for TH-filter part 1 (00): 80,52,48,81,AF,80,00,98
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x80;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x52;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x48;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x81;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xAF;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,DB,52,B0,38,01,82,AC
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0xDB;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x52;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0xB0;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0x38;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0x01;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x82;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0xAC;
+
+// Bytes for TH-filter part 3 (02): 00,88,4A,3E,2C,3B,24,46
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0x4A;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0x3E;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0x2C;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0x3B;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0x24;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0x46;
+
+// ;  idle
+
+// Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3C;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x93;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0x3A;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0x22;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x12;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xA3;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):12,A2,A6,BA,22,7A,0A,D5
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x12;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0xA2;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0x22;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x7A;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0x0A;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// Levelmetering Ringing           (0D):32,45,B5,84   ; 50Hz 20V
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x45;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0xB5;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x84;
+
+// Caller ID 1st Tone              (0E):CA,0E,CA,09,99,99,99,99
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone              (0F):FD,B5,BA,07,DA,00,00,00
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// ;CR Registers
+	// Config. Reg. 0 (filters)        (cr0):FF
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF;
+
+// Config. Reg. 1 (dialing)        (cr1):05
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID)      (cr2):04
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops)      (cr3):00        ; 
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00;
+
+// Config. Reg. 4 (analog gain)    (cr4):01
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02;		//0x01;
+
+// Config. Reg. 5 (Version)        (cr5):02
+	// Config. Reg. 6 (Reserved)       (cr6):00
+	// Config. Reg. 7 (Reserved)       (cr7):00
+
+// ;xr Registers
+	// Ext. Reg. 0 (Interrupt Reg.)    (xr0):02
+	j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02;	// SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable)  (xr1):1C
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C;		// RING, Caller ID, VDD_OK
+
+// Ext. Reg. 2 (Cadence Time Out)  (xr2):7D
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char)           (xr3):2B      ; 
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x2B;
+
+// Ext. Reg. 4 (Cadence)           (xr4):00
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer)        (xr5):22
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State)       (xr6):00
+	j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd)               (xr7):40
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x40;		// 0x40 ??? Should it be 0x00?
+
+// DTMF Tone 1                     (0B): 11,B3,5A,2C    ;   697 Hz  
+	//                                       12,33,5A,C3    ;  770 Hz  
+	//                                       13,3C,5B,32    ;  852 Hz  
+	//                                       1D,1B,5C,CC    ;  941 Hz  
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2                     (0C): 32,32,52,B3    ;  1209 Hz  
+	//                                       EC,1D,52,22    ;  1336 Hz  
+	//                                       AA,AC,51,D2    ;  1477 Hz  
+	//                                       9B,3B,51,25    ;  1633 Hz  
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+static void DAA_Coeff_Japan(int board)
+{
+	IXJ *j = &ixj[board];
+
+	int i;
+
+	//-----------------------------------------------
+	// CAO
+	for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+		j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+	}
+
+	// Bytes for IM-filter part 1 (04): 06,BD,E2,2D,BA,F9,A0,00
+	    j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x06;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xBD;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xE2;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0x2D;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0xF9;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xA0;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+// Bytes for IM-filter part 2 (05): 6F,F7,00,0E,34,33,E0,08
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x6F;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0xF7;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x0E;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0x34;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x33;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xE0;
+	j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter       (08): 02,8F,68,77,9C,58,F0,08
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x02;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x8F;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0x68;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0x77;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0x9C;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x58;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0xF0;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter       (07): 03,8F,38,73,87,EA,20,08
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x03;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x8F;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0x38;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0x73;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x87;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xEA;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0x20;
+	j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter        (0A): 51,C5,DD,CA
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x51;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0xC5;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+	j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter        (09): 25,A7,10,D6
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0x25;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0xA7;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x10;
+	j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0xD6;
+
+// Bytes for TH-filter part 1 (00): 00,42,48,81,AE,80,00,98
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x42;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x48;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x81;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xAE;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,AB,2A,20,99,5B,89,28
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0xAB;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x2A;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0x20;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0x5B;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x89;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0x28;
+
+// Bytes for TH-filter part 3 (02): 00,88,DA,25,34,C5,4C,BA
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0xDA;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0x25;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0x34;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0xC5;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0x4C;
+	j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0xBA;
+
+// ;  idle
+
+// Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3C;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x93;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0x3A;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0x22;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x12;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xA3;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):12,A2,A6,BA,22,7A,0A,D5
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x12;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0xA2;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0x22;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x7A;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0x0A;
+	j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// Levelmetering Ringing           (0D):AA,35,0F,8E    ; 25Hz 30V ?????????
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0xAA;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x35;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0x0F;
+	j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x8E;
+
+// Caller ID 1st Tone              (0E):CA,0E,CA,09,99,99,99,99
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone              (0F):FD,B5,BA,07,DA,00,00,00
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+	j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// ;CR Registers
+	// Config. Reg. 0 (filters)        (cr0):FF
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF;
+
+// Config. Reg. 1 (dialing)        (cr1):05
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID)      (cr2):04
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops)      (cr3):00        ; 
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00;
+
+// Config. Reg. 4 (analog gain)    (cr4):01
+	j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02;		//0x01;
+
+// Config. Reg. 5 (Version)        (cr5):02
+	// Config. Reg. 6 (Reserved)       (cr6):00
+	// Config. Reg. 7 (Reserved)       (cr7):00
+
+// ;xr Registers
+	// Ext. Reg. 0 (Interrupt Reg.)    (xr0):02
+	j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02;	// SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable)  (xr1):1C
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C;		// RING, Caller ID, VDD_OK
+
+// Ext. Reg. 2 (Cadence Time Out)  (xr2):7D
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char)           (xr3):22        ; 
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x22;
+
+// Ext. Reg. 4 (Cadence)           (xr4):00
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer)        (xr5):22
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State)       (xr6):00
+	j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd)               (xr7):40
+	j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x40;		// 0x40 ??? Should it be 0x00?
+
+// DTMF Tone 1                     (0B): 11,B3,5A,2C    ;   697 Hz  
+	//                                       12,33,5A,C3    ;  770 Hz  
+	//                                       13,3C,5B,32    ;  852 Hz  
+	//                                       1D,1B,5C,CC    ;  941 Hz  
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2                     (0C): 32,32,52,B3    ;  1209 Hz  
+	//                                       EC,1D,52,22    ;  1336 Hz  
+	//                                       AA,AC,51,D2    ;  1477 Hz  
+	//                                       9B,3B,51,25    ;  1633 Hz  
+
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+	j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+static s16 tone_table[][19] =
+{
+	{			// f20_50[]
+		32538,		// A1 = 1.985962
+		 -32325,	// A2 = -0.986511
+		 -343,		// B2 = -0.010493
+		 0,		// B1 = 0
+		 343,		// B0 = 0.010493
+		 32619,		// A1 = 1.990906
+		 -32520,	// A2 = -0.992462
+		 19179,		// B2 = 0.585327
+		 -19178,	// B1 = -1.170593
+		 19179,		// B0 = 0.585327
+		 32723,		// A1 = 1.997314
+		 -32686,	// A2 = -0.997528
+		 9973,		// B2 = 0.304352
+		 -9955,		// B1 = -0.607605
+		 9973,		// B0 = 0.304352
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f133_200[]
+		32072,		// A1 = 1.95752
+		 -31896,	// A2 = -0.973419
+		 -435,		// B2 = -0.013294
+		 0,		// B1 = 0
+		 435,		// B0 = 0.013294
+		 32188,		// A1 = 1.9646
+		 -32400,	// A2 = -0.98877
+		 15139,		// B2 = 0.462036
+		 -14882,	// B1 = -0.908356
+		 15139,		// B0 = 0.462036
+		 32473,		// A1 = 1.981995
+		 -32524,	// A2 = -0.992584
+		 23200,		// B2 = 0.708008
+		 -23113,	// B1 = -1.410706
+		 23200,		// B0 = 0.708008
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 300.txt
+		31769,		// A1 = -1.939026
+		 -32584,	// A2 = 0.994385
+		 -475,		// B2 = -0.014522
+		 0,		// B1 = 0.000000
+		 475,		// B0 = 0.014522
+		 31789,		// A1 = -1.940247
+		 -32679,	// A2 = 0.997284
+		 17280,		// B2 = 0.527344
+		 -16865,	// B1 = -1.029358
+		 17280,		// B0 = 0.527344
+		 31841,		// A1 = -1.943481
+		 -32681,	// A2 = 0.997345
+		 543,		// B2 = 0.016579
+		 -525,		// B1 = -0.032097
+		 543,		// B0 = 0.016579
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f300_420[]
+		30750,		// A1 = 1.876892
+		 -31212,	// A2 = -0.952515
+		 -804,		// B2 = -0.024541
+		 0,		// B1 = 0
+		 804,		// B0 = 0.024541
+		 30686,		// A1 = 1.872925
+		 -32145,	// A2 = -0.980988
+		 14747,		// B2 = 0.450043
+		 -13703,	// B1 = -0.836395
+		 14747,		// B0 = 0.450043
+		 31651,		// A1 = 1.931824
+		 -32321,	// A2 = -0.986389
+		 24425,		// B2 = 0.745422
+		 -23914,	// B1 = -1.459595
+		 24427,		// B0 = 0.745483
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 330.txt
+		31613,		// A1 = -1.929565
+		 -32646,	// A2 = 0.996277
+		 -185,		// B2 = -0.005657
+		 0,		// B1 = 0.000000
+		 185,		// B0 = 0.005657
+		 31620,		// A1 = -1.929932
+		 -32713,	// A2 = 0.998352
+		 19253,		// B2 = 0.587585
+		 -18566,	// B1 = -1.133179
+		 19253,		// B0 = 0.587585
+		 31674,		// A1 = -1.933228
+		 -32715,	// A2 = 0.998413
+		 2575,		// B2 = 0.078590
+		 -2495,		// B1 = -0.152283
+		 2575,		// B0 = 0.078590
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f300_425[]
+		30741,		// A1 = 1.876282
+		 -31475,	// A2 = -0.960541
+		 -703,		// B2 = -0.021484
+		 0,		// B1 = 0
+		 703,		// B0 = 0.021484
+		 30688,		// A1 = 1.873047
+		 -32248,	// A2 = -0.984161
+		 14542,		// B2 = 0.443787
+		 -13523,	// B1 = -0.825439
+		 14542,		// B0 = 0.443817
+		 31494,		// A1 = 1.922302
+		 -32366,	// A2 = -0.987762
+		 21577,		// B2 = 0.658508
+		 -21013,	// B1 = -1.282532
+		 21577,		// B0 = 0.658508
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f330_440[]
+		30627,		// A1 = 1.869324
+		 -31338,	// A2 = -0.95636
+		 -843,		// B2 = -0.025749
+		 0,		// B1 = 0
+		 843,		// B0 = 0.025749
+		 30550,		// A1 = 1.864685
+		 -32221,	// A2 = -0.983337
+		 13594,		// B2 = 0.414886
+		 -12589,	// B1 = -0.768402
+		 13594,		// B0 = 0.414886
+		 31488,		// A1 = 1.921936
+		 -32358,	// A2 = -0.987518
+		 24684,		// B2 = 0.753296
+		 -24029,	// B1 = -1.466614
+		 24684,		// B0 = 0.753296
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 340.txt
+		31546,		// A1 = -1.925476
+		 -32646,	// A2 = 0.996277
+		 -445,		// B2 = -0.013588
+		 0,		// B1 = 0.000000
+		 445,		// B0 = 0.013588
+		 31551,		// A1 = -1.925781
+		 -32713,	// A2 = 0.998352
+		 23884,		// B2 = 0.728882
+		 -22979,	// B1 = -1.402527
+		 23884,		// B0 = 0.728882
+		 31606,		// A1 = -1.929138
+		 -32715,	// A2 = 0.998413
+		 863,		// B2 = 0.026367
+		 -835,		// B1 = -0.050985
+		 863,		// B0 = 0.026367
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f350_400[]
+		31006,		// A1 = 1.892517
+		 -32029,	// A2 = -0.977448
+		 -461,		// B2 = -0.014096
+		 0,		// B1 = 0
+		 461,		// B0 = 0.014096
+		 30999,		// A1 = 1.892029
+		 -32487,	// A2 = -0.991455
+		 11325,		// B2 = 0.345612
+		 -10682,	// B1 = -0.651978
+		 11325,		// B0 = 0.345612
+		 31441,		// A1 = 1.919067
+		 -32526,	// A2 = -0.992615
+		 24324,		// B2 = 0.74231
+		 -23535,	// B1 = -1.436523
+		 24324,		// B0 = 0.74231
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f350_440[]
+		30634,		// A1 = 1.869751
+		 -31533,	// A2 = -0.962341
+		 -680,		// B2 = -0.020782
+		 0,		// B1 = 0
+		 680,		// B0 = 0.020782
+		 30571,		// A1 = 1.865906
+		 -32277,	// A2 = -0.985016
+		 12894,		// B2 = 0.393524
+		 -11945,	// B1 = -0.729065
+		 12894,		// B0 = 0.393524
+		 31367,		// A1 = 1.91449
+		 -32379,	// A2 = -0.988129
+		 23820,		// B2 = 0.726929
+		 -23104,	// B1 = -1.410217
+		 23820,		// B0 = 0.726929
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f350_450[]
+		30552,		// A1 = 1.864807
+		 -31434,	// A2 = -0.95929
+		 -690,		// B2 = -0.021066
+		 0,		// B1 = 0
+		 690,		// B0 = 0.021066
+		 30472,		// A1 = 1.859924
+		 -32248,	// A2 = -0.984161
+		 13385,		// B2 = 0.408478
+		 -12357,	// B1 = -0.754242
+		 13385,		// B0 = 0.408478
+		 31358,		// A1 = 1.914001
+		 -32366,	// A2 = -0.987732
+		 26488,		// B2 = 0.80835
+		 -25692,	// B1 = -1.568176
+		 26490,		// B0 = 0.808411
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 360.txt
+		31397,		// A1 = -1.916321
+		 -32623,	// A2 = 0.995605
+		 -117,		// B2 = -0.003598
+		 0,		// B1 = 0.000000
+		 117,		// B0 = 0.003598
+		 31403,		// A1 = -1.916687
+		 -32700,	// A2 = 0.997925
+		 3388,		// B2 = 0.103401
+		 -3240,		// B1 = -0.197784
+		 3388,		// B0 = 0.103401
+		 31463,		// A1 = -1.920410
+		 -32702,	// A2 = 0.997986
+		 13346,		// B2 = 0.407288
+		 -12863,	// B1 = -0.785126
+		 13346,		// B0 = 0.407288
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f380_420[]
+		30831,		// A1 = 1.881775
+		 -32064,	// A2 = -0.978546
+		 -367,		// B2 = -0.01122
+		 0,		// B1 = 0
+		 367,		// B0 = 0.01122
+		 30813,		// A1 = 1.880737
+		 -32456,	// A2 = -0.990509
+		 11068,		// B2 = 0.337769
+		 -10338,	// B1 = -0.631042
+		 11068,		// B0 = 0.337769
+		 31214,		// A1 = 1.905212
+		 -32491,	// A2 = -0.991577
+		 16374,		// B2 = 0.499695
+		 -15781,	// B1 = -0.963196
+		 16374,		// B0 = 0.499695
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 392.txt
+		31152,		// A1 = -1.901428
+		 -32613,	// A2 = 0.995300
+		 -314,		// B2 = -0.009605
+		 0,		// B1 = 0.000000
+		 314,		// B0 = 0.009605
+		 31156,		// A1 = -1.901672
+		 -32694,	// A2 = 0.997742
+		 28847,		// B2 = 0.880371
+		 -2734,		// B1 = -0.166901
+		 28847,		// B0 = 0.880371
+		 31225,		// A1 = -1.905823
+		 -32696,	// A2 = 0.997803
+		 462,		// B2 = 0.014108
+		 -442,		// B1 = -0.027019
+		 462,		// B0 = 0.014108
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f400_425[]
+		30836,		// A1 = 1.882141
+		 -32296,	// A2 = -0.985596
+		 -324,		// B2 = -0.009903
+		 0,		// B1 = 0
+		 324,		// B0 = 0.009903
+		 30825,		// A1 = 1.881409
+		 -32570,	// A2 = -0.993958
+		 16847,		// B2 = 0.51416
+		 -15792,	// B1 = -0.963898
+		 16847,		// B0 = 0.51416
+		 31106,		// A1 = 1.89856
+		 -32584,	// A2 = -0.994415
+		 9579,		// B2 = 0.292328
+		 -9164,		// B1 = -0.559357
+		 9579,		// B0 = 0.292328
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f400_440[]
+		30702,		// A1 = 1.873962
+		 -32134,	// A2 = -0.980682
+		 -517,		// B2 = -0.015793
+		 0,		// B1 = 0
+		 517,		// B0 = 0.015793
+		 30676,		// A1 = 1.872375
+		 -32520,	// A2 = -0.992462
+		 8144,		// B2 = 0.24855
+		 -7596,		// B1 = -0.463684
+		 8144,		// B0 = 0.24855
+		 31084,		// A1 = 1.897217
+		 -32547,	// A2 = -0.993256
+		 22713,		// B2 = 0.693176
+		 -21734,	// B1 = -1.326599
+		 22713,		// B0 = 0.693176
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f400_450[]
+		30613,		// A1 = 1.86853
+		 -32031,	// A2 = -0.977509
+		 -618,		// B2 = -0.018866
+		 0,		// B1 = 0
+		 618,		// B0 = 0.018866
+		 30577,		// A1 = 1.866272
+		 -32491,	// A2 = -0.991577
+		 9612,		// B2 = 0.293335
+		 -8935,		// B1 = -0.54541
+		 9612,		// B0 = 0.293335
+		 31071,		// A1 = 1.896484
+		 -32524,	// A2 = -0.992584
+		 21596,		// B2 = 0.659058
+		 -20667,	// B1 = -1.261414
+		 21596,		// B0 = 0.659058
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 420.txt
+		30914,		// A1 = -1.886841
+		 -32584,	// A2 = 0.994385
+		 -426,		// B2 = -0.013020
+		 0,		// B1 = 0.000000
+		 426,		// B0 = 0.013020
+		 30914,		// A1 = -1.886841
+		 -32679,	// A2 = 0.997314
+		 17520,		// B2 = 0.534668
+		 -16471,	// B1 = -1.005310
+		 17520,		// B0 = 0.534668
+		 31004,		// A1 = -1.892334
+		 -32683,	// A2 = 0.997406
+		 819,		// B2 = 0.025023
+		 -780,		// B1 = -0.047619
+		 819,		// B0 = 0.025023
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 425.txt
+		30881,		// A1 = -1.884827
+		 -32603,	// A2 = 0.994965
+		 -496,		// B2 = -0.015144
+		 0,		// B1 = 0.000000
+		 496,		// B0 = 0.015144
+		 30880,		// A1 = -1.884766
+		 -32692,	// A2 = 0.997711
+		 24767,		// B2 = 0.755859
+		 -23290,	// B1 = -1.421509
+		 24767,		// B0 = 0.755859
+		 30967,		// A1 = -1.890076
+		 -32694,	// A2 = 0.997772
+		 728,		// B2 = 0.022232
+		 -691,		// B1 = -0.042194
+		 728,		// B0 = 0.022232
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f425_450[]
+		30646,		// A1 = 1.870544
+		 -32327,	// A2 = -0.986572
+		 -287,		// B2 = -0.008769
+		 0,		// B1 = 0
+		 287,		// B0 = 0.008769
+		 30627,		// A1 = 1.869324
+		 -32607,	// A2 = -0.995087
+		 13269,		// B2 = 0.404968
+		 -12376,	// B1 = -0.755432
+		 13269,		// B0 = 0.404968
+		 30924,		// A1 = 1.887512
+		 -32619,	// A2 = -0.995453
+		 19950,		// B2 = 0.608826
+		 -18940,	// B1 = -1.156006
+		 19950,		// B0 = 0.608826
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f425_475[]
+		30396,		// A1 = 1.855225
+		 -32014,	// A2 = -0.97699
+		 -395,		// B2 = -0.012055
+		 0,		// B1 = 0
+		 395,		// B0 = 0.012055
+		 30343,		// A1 = 1.85199
+		 -32482,	// A2 = -0.991302
+		 17823,		// B2 = 0.543945
+		 -16431,	// B1 = -1.002869
+		 17823,		// B0 = 0.543945
+		 30872,		// A1 = 1.884338
+		 -32516,	// A2 = -0.99231
+		 18124,		// B2 = 0.553101
+		 -17246,	// B1 = -1.052673
+		 18124,		// B0 = 0.553101
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 435.txt
+		30796,		// A1 = -1.879639
+		 -32603,	// A2 = 0.994965
+		 -254,		// B2 = -0.007762
+		 0,		// B1 = 0.000000
+		 254,		// B0 = 0.007762
+		 30793,		// A1 = -1.879456
+		 -32692,	// A2 = 0.997711
+		 18934,		// B2 = 0.577820
+		 -17751,	// B1 = -1.083496
+		 18934,		// B0 = 0.577820
+		 30882,		// A1 = -1.884888
+		 -32694,	// A2 = 0.997772
+		 1858,		// B2 = 0.056713
+		 -1758,		// B1 = -0.107357
+		 1858,		// B0 = 0.056713
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f440_450[]
+		30641,		// A1 = 1.870239
+		 -32458,	// A2 = -0.99057
+		 -155,		// B2 = -0.004735
+		 0,		// B1 = 0
+		 155,		// B0 = 0.004735
+		 30631,		// A1 = 1.869568
+		 -32630,	// A2 = -0.995789
+		 11453,		// B2 = 0.349548
+		 -10666,	// B1 = -0.651001
+		 11453,		// B0 = 0.349548
+		 30810,		// A1 = 1.880554
+		 -32634,	// A2 = -0.995941
+		 12237,		// B2 = 0.373474
+		 -11588,	// B1 = -0.707336
+		 12237,		// B0 = 0.373474
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f440_480[]
+		30367,		// A1 = 1.853455
+		 -32147,	// A2 = -0.981079
+		 -495,		// B2 = -0.015113
+		 0,		// B1 = 0
+		 495,		// B0 = 0.015113
+		 30322,		// A1 = 1.850769
+		 -32543,	// A2 = -0.993134
+		 10031,		// B2 = 0.306152
+		 -9252,		// B1 = -0.564728
+		 10031,		// B0 = 0.306152
+		 30770,		// A1 = 1.878052
+		 -32563,	// A2 = -0.993774
+		 22674,		// B2 = 0.691956
+		 -21465,	// B1 = -1.31012
+		 22674,		// B0 = 0.691956
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 445.txt
+		30709,		// A1 = -1.874329
+		 -32603,	// A2 = 0.994965
+		 -83,		// B2 = -0.002545
+		 0,		// B1 = 0.000000
+		 83,		// B0 = 0.002545
+		 30704,		// A1 = -1.874084
+		 -32692,	// A2 = 0.997711
+		 10641,		// B2 = 0.324738
+		 -9947,		// B1 = -0.607147
+		 10641,		// B0 = 0.324738
+		 30796,		// A1 = -1.879639
+		 -32694,	// A2 = 0.997772
+		 10079,		// B2 = 0.307587
+		 9513,		// B1 = 0.580688
+		 10079,		// B0 = 0.307587
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 450.txt
+		30664,		// A1 = -1.871643
+		 -32603,	// A2 = 0.994965
+		 -164,		// B2 = -0.005029
+		 0,		// B1 = 0.000000
+		 164,		// B0 = 0.005029
+		 30661,		// A1 = -1.871399
+		 -32692,	// A2 = 0.997711
+		 15294,		// B2 = 0.466736
+		 -14275,	// B1 = -0.871307
+		 15294,		// B0 = 0.466736
+		 30751,		// A1 = -1.876953
+		 -32694,	// A2 = 0.997772
+		 3548,		// B2 = 0.108284
+		 -3344,		// B1 = -0.204155
+		 3548,		// B0 = 0.108284
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 452.txt
+		30653,		// A1 = -1.870911
+		 -32615,	// A2 = 0.995361
+		 -209,		// B2 = -0.006382
+		 0,		// B1 = 0.000000
+		 209,		// B0 = 0.006382
+		 30647,		// A1 = -1.870605
+		 -32702,	// A2 = 0.997986
+		 18971,		// B2 = 0.578979
+		 -17716,	// B1 = -1.081299
+		 18971,		// B0 = 0.578979
+		 30738,		// A1 = -1.876099
+		 -32702,	// A2 = 0.998016
+		 2967,		// B2 = 0.090561
+		 -2793,		// B1 = -0.170502
+		 2967,		// B0 = 0.090561
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 475.txt
+		30437,		// A1 = -1.857727
+		 -32603,	// A2 = 0.994965
+		 -264,		// B2 = -0.008062
+		 0,		// B1 = 0.000000
+		 264,		// B0 = 0.008062
+		 30430,		// A1 = -1.857300
+		 -32692,	// A2 = 0.997711
+		 21681,		// B2 = 0.661682
+		 -20082,	// B1 = -1.225708
+		 21681,		// B0 = 0.661682
+		 30526,		// A1 = -1.863220
+		 -32694,	// A2 = 0.997742
+		 1559,		// B2 = 0.047600
+		 -1459,		// B1 = -0.089096
+		 1559,		// B0 = 0.047600
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f480_620[]
+		28975,		// A1 = 1.768494
+		 -30955,	// A2 = -0.944672
+		 -1026,		// B2 = -0.03133
+		 0,		// B1 = 0
+		 1026,		// B0 = 0.03133
+		 28613,		// A1 = 1.746399
+		 -32089,	// A2 = -0.979309
+		 14214,		// B2 = 0.433807
+		 -12202,	// B1 = -0.744812
+		 14214,		// B0 = 0.433807
+		 30243,		// A1 = 1.845947
+		 -32238,	// A2 = -0.983856
+		 24825,		// B2 = 0.757629
+		 -23402,	// B1 = -1.428345
+		 24825,		// B0 = 0.757629
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 494.txt
+		30257,		// A1 = -1.846741
+		 -32605,	// A2 = 0.995056
+		 -249,		// B2 = -0.007625
+		 0,		// B1 = 0.000000
+		 249,		// B0 = 0.007625
+		 30247,		// A1 = -1.846191
+		 -32694,	// A2 = 0.997772
+		 18088,		// B2 = 0.552002
+		 -16652,	// B1 = -1.016418
+		 18088,		// B0 = 0.552002
+		 30348,		// A1 = -1.852295
+		 -32696,	// A2 = 0.997803
+		 2099,		// B2 = 0.064064
+		 -1953,		// B1 = -0.119202
+		 2099,		// B0 = 0.064064
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 500.txt
+		30202,		// A1 = -1.843431
+		 -32624,	// A2 = 0.995622
+		 -413,		// B2 = -0.012622
+		 0,		// B1 = 0.000000
+		 413,		// B0 = 0.012622
+		 30191,		// A1 = -1.842721
+		 -32714,	// A2 = 0.998364
+		 25954,		// B2 = 0.792057
+		 -23890,	// B1 = -1.458131
+		 25954,		// B0 = 0.792057
+		 30296,		// A1 = -1.849172
+		 -32715,	// A2 = 0.998397
+		 2007,		// B2 = 0.061264
+		 -1860,		// B1 = -0.113568
+		 2007,		// B0 = 0.061264
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 520.txt
+		30001,		// A1 = -1.831116
+		 -32613,	// A2 = 0.995270
+		 -155,		// B2 = -0.004750
+		 0,		// B1 = 0.000000
+		 155,		// B0 = 0.004750
+		 29985,		// A1 = -1.830200
+		 -32710,	// A2 = 0.998260
+		 6584,		// B2 = 0.200928
+		 -6018,		// B1 = -0.367355
+		 6584,		// B0 = 0.200928
+		 30105,		// A1 = -1.837524
+		 -32712,	// A2 = 0.998291
+		 23812,		// B2 = 0.726685
+		 -21936,	// B1 = -1.338928
+		 23812,		// B0 = 0.726685
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 523.txt
+		29964,		// A1 = -1.828918
+		 -32601,	// A2 = 0.994904
+		 -101,		// B2 = -0.003110
+		 0,		// B1 = 0.000000
+		 101,		// B0 = 0.003110
+		 29949,		// A1 = -1.827942
+		 -32700,	// A2 = 0.997925
+		 11041,		// B2 = 0.336975
+		 -10075,	// B1 = -0.614960
+		 11041,		// B0 = 0.336975
+		 30070,		// A1 = -1.835388
+		 -32702,	// A2 = 0.997986
+		 16762,		// B2 = 0.511536
+		 -15437,	// B1 = -0.942230
+		 16762,		// B0 = 0.511536
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 525.txt
+		29936,		// A1 = -1.827209
+		 -32584,	// A2 = 0.994415
+		 -91,		// B2 = -0.002806
+		 0,		// B1 = 0.000000
+		 91,		// B0 = 0.002806
+		 29921,		// A1 = -1.826233
+		 -32688,	// A2 = 0.997559
+		 11449,		// B2 = 0.349396
+		 -10426,	// B1 = -0.636383
+		 11449,		// B0 = 0.349396
+		 30045,		// A1 = -1.833862
+		 -32688,	// A2 = 0.997589
+		 13055,		// B2 = 0.398407
+		 -12028,	// B1 = -0.734161
+		 13055,		// B0 = 0.398407
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f540_660[]
+		28499,		// A1 = 1.739441
+		 -31129,	// A2 = -0.949982
+		 -849,		// B2 = -0.025922
+		 0,		// B1 = 0
+		 849,		// B0 = 0.025922
+		 28128,		// A1 = 1.716797
+		 -32130,	// A2 = -0.98056
+		 14556,		// B2 = 0.444214
+		 -12251,	// B1 = -0.747772
+		 14556,		// B0 = 0.444244
+		 29667,		// A1 = 1.81073
+		 -32244,	// A2 = -0.984039
+		 23038,		// B2 = 0.703064
+		 -21358,	// B1 = -1.303589
+		 23040,		// B0 = 0.703125
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 587.txt
+		29271,		// A1 = -1.786560
+		 -32599,	// A2 = 0.994873
+		 -490,		// B2 = -0.014957
+		 0,		// B1 = 0.000000
+		 490,		// B0 = 0.014957
+		 29246,		// A1 = -1.785095
+		 -32700,	// A2 = 0.997925
+		 28961,		// B2 = 0.883850
+		 -25796,	// B1 = -1.574463
+		 28961,		// B0 = 0.883850
+		 29383,		// A1 = -1.793396
+		 -32700,	// A2 = 0.997955
+		 1299,		// B2 = 0.039650
+		 -1169,		// B1 = -0.071396
+		 1299,		// B0 = 0.039650
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 590.txt
+		29230,		// A1 = -1.784058
+		 -32584,	// A2 = 0.994415
+		 -418,		// B2 = -0.012757
+		 0,		// B1 = 0.000000
+		 418,		// B0 = 0.012757
+		 29206,		// A1 = -1.782593
+		 -32688,	// A2 = 0.997559
+		 36556,		// B2 = 1.115601
+		 -32478,	// B1 = -1.982300
+		 36556,		// B0 = 1.115601
+		 29345,		// A1 = -1.791077
+		 -32688,	// A2 = 0.997589
+		 897,		// B2 = 0.027397
+		 -808,		// B1 = -0.049334
+		 897,		// B0 = 0.027397
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 600.txt
+		29116,		// A1 = -1.777100
+		 -32603,	// A2 = 0.994965
+		 -165,		// B2 = -0.005039
+		 0,		// B1 = 0.000000
+		 165,		// B0 = 0.005039
+		 29089,		// A1 = -1.775452
+		 -32708,	// A2 = 0.998199
+		 6963,		// B2 = 0.212494
+		 -6172,		// B1 = -0.376770
+		 6963,		// B0 = 0.212494
+		 29237,		// A1 = -1.784485
+		 -32710,	// A2 = 0.998230
+		 24197,		// B2 = 0.738464
+		 -21657,	// B1 = -1.321899
+		 24197,		// B0 = 0.738464
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 660.txt
+		28376,		// A1 = -1.731934
+		 -32567,	// A2 = 0.993896
+		 -363,		// B2 = -0.011102
+		 0,		// B1 = 0.000000
+		 363,		// B0 = 0.011102
+		 28337,		// A1 = -1.729614
+		 -32683,	// A2 = 0.997434
+		 21766,		// B2 = 0.664246
+		 -18761,	// B1 = -1.145081
+		 21766,		// B0 = 0.664246
+		 28513,		// A1 = -1.740356
+		 -32686,	// A2 = 0.997498
+		 2509,		// B2 = 0.076584
+		 -2196,		// B1 = -0.134041
+		 2509,		// B0 = 0.076584
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 700.txt
+		27844,		// A1 = -1.699463
+		 -32563,	// A2 = 0.993744
+		 -366,		// B2 = -0.011187
+		 0,		// B1 = 0.000000
+		 366,		// B0 = 0.011187
+		 27797,		// A1 = -1.696655
+		 -32686,	// A2 = 0.997498
+		 22748,		// B2 = 0.694214
+		 -19235,	// B1 = -1.174072
+		 22748,		// B0 = 0.694214
+		 27995,		// A1 = -1.708740
+		 -32688,	// A2 = 0.997559
+		 2964,		// B2 = 0.090477
+		 -2546,		// B1 = -0.155449
+		 2964,		// B0 = 0.090477
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 740.txt
+		27297,		// A1 = -1.666077
+		 -32551,	// A2 = 0.993408
+		 -345,		// B2 = -0.010540
+		 0,		// B1 = 0.000000
+		 345,		// B0 = 0.010540
+		 27240,		// A1 = -1.662598
+		 -32683,	// A2 = 0.997406
+		 22560,		// B2 = 0.688477
+		 -18688,	// B1 = -1.140625
+		 22560,		// B0 = 0.688477
+		 27461,		// A1 = -1.676147
+		 -32684,	// A2 = 0.997467
+		 3541,		// B2 = 0.108086
+		 -2985,		// B1 = -0.182220
+		 3541,		// B0 = 0.108086
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 750.txt
+		27155,		// A1 = -1.657410
+		 -32551,	// A2 = 0.993408
+		 -462,		// B2 = -0.014117
+		 0,		// B1 = 0.000000
+		 462,		// B0 = 0.014117
+		 27097,		// A1 = -1.653870
+		 -32683,	// A2 = 0.997406
+		 32495,		// B2 = 0.991699
+		 -26776,	// B1 = -1.634338
+		 32495,		// B0 = 0.991699
+		 27321,		// A1 = -1.667542
+		 -32684,	// A2 = 0.997467
+		 1835,		// B2 = 0.056007
+		 -1539,		// B1 = -0.093948
+		 1835,		// B0 = 0.056007
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f750_1450[]
+		19298,		// A1 = 1.177917
+		 -24471,	// A2 = -0.746796
+		 -4152,		// B2 = -0.126709
+		 0,		// B1 = 0
+		 4152,		// B0 = 0.126709
+		 12902,		// A1 = 0.787476
+		 -29091,	// A2 = -0.887817
+		 12491,		// B2 = 0.38121
+		 -1794,		// B1 = -0.109528
+		 12494,		// B0 = 0.381317
+		 26291,		// A1 = 1.604736
+		 -30470,	// A2 = -0.929901
+		 28859,		// B2 = 0.880737
+		 -26084,	// B1 = -1.592102
+		 28861,		// B0 = 0.880798
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 770.txt
+		26867,		// A1 = -1.639832
+		 -32551,	// A2 = 0.993408
+		 -123,		// B2 = -0.003755
+		 0,		// B1 = 0.000000
+		 123,		// B0 = 0.003755
+		 26805,		// A1 = -1.636108
+		 -32683,	// A2 = 0.997406
+		 17297,		// B2 = 0.527863
+		 -14096,	// B1 = -0.860382
+		 17297,		// B0 = 0.527863
+		 27034,		// A1 = -1.650085
+		 -32684,	// A2 = 0.997467
+		 12958,		// B2 = 0.395477
+		 -10756,	// B1 = -0.656525
+		 12958,		// B0 = 0.395477
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 800.txt
+		26413,		// A1 = -1.612122
+		 -32547,	// A2 = 0.993286
+		 -223,		// B2 = -0.006825
+		 0,		// B1 = 0.000000
+		 223,		// B0 = 0.006825
+		 26342,		// A1 = -1.607849
+		 -32686,	// A2 = 0.997498
+		 6391,		// B2 = 0.195053
+		 -5120,		// B1 = -0.312531
+		 6391,		// B0 = 0.195053
+		 26593,		// A1 = -1.623108
+		 -32688,	// A2 = 0.997559
+		 23681,		// B2 = 0.722717
+		 -19328,	// B1 = -1.179688
+		 23681,		// B0 = 0.722717
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 816.txt
+		26168,		// A1 = -1.597209
+		 -32528,	// A2 = 0.992706
+		 -235,		// B2 = -0.007182
+		 0,		// B1 = 0.000000
+		 235,		// B0 = 0.007182
+		 26092,		// A1 = -1.592590
+		 -32675,	// A2 = 0.997192
+		 20823,		// B2 = 0.635498
+		 -16510,	// B1 = -1.007751
+		 20823,		// B0 = 0.635498
+		 26363,		// A1 = -1.609070
+		 -32677,	// A2 = 0.997253
+		 6739,		// B2 = 0.205688
+		 -5459,		// B1 = -0.333206
+		 6739,		// B0 = 0.205688
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 850.txt
+		25641,		// A1 = -1.565063
+		 -32536,	// A2 = 0.992950
+		 -121,		// B2 = -0.003707
+		 0,		// B1 = 0.000000
+		 121,		// B0 = 0.003707
+		 25560,		// A1 = -1.560059
+		 -32684,	// A2 = 0.997437
+		 18341,		// B2 = 0.559753
+		 -14252,	// B1 = -0.869904
+		 18341,		// B0 = 0.559753
+		 25837,		// A1 = -1.577026
+		 -32684,	// A2 = 0.997467
+		 16679,		// B2 = 0.509003
+		 -13232,	// B1 = -0.807648
+		 16679,		// B0 = 0.509003
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f857_1645[]
+		16415,		// A1 = 1.001953
+		 -23669,	// A2 = -0.722321
+		 -4549,		// B2 = -0.138847
+		 0,		// B1 = 0
+		 4549,		// B0 = 0.138847
+		 8456,		// A1 = 0.516174
+		 -28996,	// A2 = -0.884918
+		 13753,		// B2 = 0.419724
+		 -12,		// B1 = -0.000763
+		 13757,		// B0 = 0.419846
+		 24632,		// A1 = 1.503418
+		 -30271,	// A2 = -0.923828
+		 29070,		// B2 = 0.887146
+		 -25265,	// B1 = -1.542114
+		 29073,		// B0 = 0.887268
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 900.txt
+		24806,		// A1 = -1.514099
+		 -32501,	// A2 = 0.991852
+		 -326,		// B2 = -0.009969
+		 0,		// B1 = 0.000000
+		 326,		// B0 = 0.009969
+		 24709,		// A1 = -1.508118
+		 -32659,	// A2 = 0.996674
+		 20277,		// B2 = 0.618835
+		 -15182,	// B1 = -0.926636
+		 20277,		// B0 = 0.618835
+		 25022,		// A1 = -1.527222
+		 -32661,	// A2 = 0.996735
+		 4320,		// B2 = 0.131836
+		 -3331,		// B1 = -0.203339
+		 4320,		// B0 = 0.131836
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f900_1300[]
+		19776,		// A1 = 1.207092
+		 -27437,	// A2 = -0.837341
+		 -2666,		// B2 = -0.081371
+		 0,		// B1 = 0
+		 2666,		// B0 = 0.081371
+		 16302,		// A1 = 0.995026
+		 -30354,	// A2 = -0.926361
+		 10389,		// B2 = 0.317062
+		 -3327,		// B1 = -0.203064
+		 10389,		// B0 = 0.317062
+		 24299,		// A1 = 1.483154
+		 -30930,	// A2 = -0.943909
+		 25016,		// B2 = 0.763428
+		 -21171,	// B1 = -1.292236
+		 25016,		// B0 = 0.763428
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f935_1215[]
+		20554,		// A1 = 1.254517
+		 -28764,	// A2 = -0.877838
+		 -2048,		// B2 = -0.062515
+		 0,		// B1 = 0
+		 2048,		// B0 = 0.062515
+		 18209,		// A1 = 1.11145
+		 -30951,	// A2 = -0.94458
+		 9390,		// B2 = 0.286575
+		 -3955,		// B1 = -0.241455
+		 9390,		// B0 = 0.286575
+		 23902,		// A1 = 1.458923
+		 -31286,	// A2 = -0.954803
+		 23252,		// B2 = 0.709595
+		 -19132,	// B1 = -1.167725
+		 23252,		// B0 = 0.709595
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f941_1477[]
+		17543,		// A1 = 1.07074
+		 -26220,	// A2 = -0.800201
+		 -3298,		// B2 = -0.100647
+		 0,		// B1 = 0
+		 3298,		// B0 = 0.100647
+		 12423,		// A1 = 0.75827
+		 -30036,	// A2 = -0.916626
+		 12651,		// B2 = 0.386078
+		 -2444,		// B1 = -0.14917
+		 12653,		// B0 = 0.386154
+		 23518,		// A1 = 1.435425
+		 -30745,	// A2 = -0.938293
+		 27282,		// B2 = 0.832581
+		 -22529,	// B1 = -1.375122
+		 27286,		// B0 = 0.832703
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 942.txt
+		24104,		// A1 = -1.471252
+		 -32507,	// A2 = 0.992065
+		 -351,		// B2 = -0.010722
+		 0,		// B1 = 0.000000
+		 351,		// B0 = 0.010722
+		 23996,		// A1 = -1.464600
+		 -32671,	// A2 = 0.997040
+		 22848,		// B2 = 0.697266
+		 -16639,	// B1 = -1.015564
+		 22848,		// B0 = 0.697266
+		 24332,		// A1 = -1.485168
+		 -32673,	// A2 = 0.997101
+		 4906,		// B2 = 0.149727
+		 -3672,		// B1 = -0.224174
+		 4906,		// B0 = 0.149727
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 950.txt
+		23967,		// A1 = -1.462830
+		 -32507,	// A2 = 0.992065
+		 -518,		// B2 = -0.015821
+		 0,		// B1 = 0.000000
+		 518,		// B0 = 0.015821
+		 23856,		// A1 = -1.456055
+		 -32671,	// A2 = 0.997040
+		 26287,		// B2 = 0.802246
+		 -19031,	// B1 = -1.161560
+		 26287,		// B0 = 0.802246
+		 24195,		// A1 = -1.476746
+		 -32673,	// A2 = 0.997101
+		 2890,		// B2 = 0.088196
+		 -2151,		// B1 = -0.131317
+		 2890,		// B0 = 0.088196
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f950_1400[]
+		18294,		// A1 = 1.116638
+		 -26962,	// A2 = -0.822845
+		 -2914,		// B2 = -0.088936
+		 0,		// B1 = 0
+		 2914,		// B0 = 0.088936
+		 14119,		// A1 = 0.861786
+		 -30227,	// A2 = -0.922455
+		 11466,		// B2 = 0.349945
+		 -2833,		// B1 = -0.172943
+		 11466,		// B0 = 0.349945
+		 23431,		// A1 = 1.430115
+		 -30828,	// A2 = -0.940796
+		 25331,		// B2 = 0.773071
+		 -20911,	// B1 = -1.276367
+		 25331,		// B0 = 0.773071
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 975.txt
+		23521,		// A1 = -1.435608
+		 -32489,	// A2 = 0.991516
+		 -193,		// B2 = -0.005915
+		 0,		// B1 = 0.000000
+		 193,		// B0 = 0.005915
+		 23404,		// A1 = -1.428467
+		 -32655,	// A2 = 0.996582
+		 17740,		// B2 = 0.541412
+		 -12567,	// B1 = -0.767029
+		 17740,		// B0 = 0.541412
+		 23753,		// A1 = -1.449829
+		 -32657,	// A2 = 0.996613
+		 9090,		// B2 = 0.277405
+		 -6662,		// B1 = -0.406647
+		 9090,		// B0 = 0.277405
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 1000.txt
+		23071,		// A1 = -1.408203
+		 -32489,	// A2 = 0.991516
+		 -293,		// B2 = -0.008965
+		 0,		// B1 = 0.000000
+		 293,		// B0 = 0.008965
+		 22951,		// A1 = -1.400818
+		 -32655,	// A2 = 0.996582
+		 5689,		// B2 = 0.173645
+		 -3951,		// B1 = -0.241150
+		 5689,		// B0 = 0.173645
+		 23307,		// A1 = -1.422607
+		 -32657,	// A2 = 0.996613
+		 18692,		// B2 = 0.570435
+		 -13447,	// B1 = -0.820770
+		 18692,		// B0 = 0.570435
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 1020.txt
+		22701,		// A1 = -1.385620
+		 -32474,	// A2 = 0.991058
+		 -292,		// B2 = -0.008933
+		 0,		//163840      , // B1 = 10.000000
+		 292,		// B0 = 0.008933
+		 22564,		// A1 = -1.377258
+		 -32655,	// A2 = 0.996552
+		 20756,		// B2 = 0.633423
+		 -14176,	// B1 = -0.865295
+		 20756,		// B0 = 0.633423
+		 22960,		// A1 = -1.401428
+		 -32657,	// A2 = 0.996613
+		 6520,		// B2 = 0.198990
+		 -4619,		// B1 = -0.281937
+		 6520,		// B0 = 0.198990
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 1050.txt
+		22142,		// A1 = -1.351501
+		 -32474,	// A2 = 0.991058
+		 -147,		// B2 = -0.004493
+		 0,		// B1 = 0.000000
+		 147,		// B0 = 0.004493
+		 22000,		// A1 = -1.342834
+		 -32655,	// A2 = 0.996552
+		 15379,		// B2 = 0.469360
+		 -10237,	// B1 = -0.624847
+		 15379,		// B0 = 0.469360
+		 22406,		// A1 = -1.367554
+		 -32657,	// A2 = 0.996613
+		 17491,		// B2 = 0.533783
+		 -12096,	// B1 = -0.738312
+		 17491,		// B0 = 0.533783
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f1100_1750[]
+		12973,		// A1 = 0.79184
+		 -24916,	// A2 = -0.760376
+		 6655,		// B2 = 0.203102
+		 367,		// B1 = 0.0224
+		 6657,		// B0 = 0.203171
+		 5915,		// A1 = 0.361053
+		 -29560,	// A2 = -0.90213
+		 -7777,		// B2 = -0.23735
+		 0,		// B1 = 0
+		 7777,		// B0 = 0.23735
+		 20510,		// A1 = 1.251892
+		 -30260,	// A2 = -0.923462
+		 26662,		// B2 = 0.81366
+		 -20573,	// B1 = -1.255737
+		 26668,		// B0 = 0.813843
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 1140.txt
+		20392,		// A1 = -1.244629
+		 -32460,	// A2 = 0.990601
+		 -270,		// B2 = -0.008240
+		 0,		// B1 = 0.000000
+		 270,		// B0 = 0.008240
+		 20218,		// A1 = -1.234009
+		 -32655,	// A2 = 0.996582
+		 21337,		// B2 = 0.651154
+		 -13044,	// B1 = -0.796143
+		 21337,		// B0 = 0.651154
+		 20684,		// A1 = -1.262512
+		 -32657,	// A2 = 0.996643
+		 8572,		// B2 = 0.261612
+		 -5476,		// B1 = -0.334244
+		 8572,		// B0 = 0.261612
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 1200.txt
+		19159,		// A1 = -1.169373
+		 -32456,	// A2 = 0.990509
+		 -335,		// B2 = -0.010252
+		 0,		// B1 = 0.000000
+		 335,		// B0 = 0.010252
+		 18966,		// A1 = -1.157593
+		 -32661,	// A2 = 0.996735
+		 6802,		// B2 = 0.207588
+		 -3900,		// B1 = -0.238098
+		 6802,		// B0 = 0.207588
+		 19467,		// A1 = -1.188232
+		 -32661,	// A2 = 0.996765
+		 25035,		// B2 = 0.764008
+		 -15049,	// B1 = -0.918579
+		 25035,		// B0 = 0.764008
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 1209.txt
+		18976,		// A1 = -1.158264
+		 -32439,	// A2 = 0.989990
+		 -183,		// B2 = -0.005588
+		 0,		// B1 = 0.000000
+		 183,		// B0 = 0.005588
+		 18774,		// A1 = -1.145874
+		 -32650,	// A2 = 0.996429
+		 15468,		// B2 = 0.472076
+		 -8768,		// B1 = -0.535217
+		 15468,		// B0 = 0.472076
+		 19300,		// A1 = -1.177979
+		 -32652,	// A2 = 0.996490
+		 19840,		// B2 = 0.605499
+		 -11842,	// B1 = -0.722809
+		 19840,		// B0 = 0.605499
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 1330.txt
+		16357,		// A1 = -0.998413
+		 -32368,	// A2 = 0.987793
+		 -217,		// B2 = -0.006652
+		 0,		// B1 = 0.000000
+		 217,		// B0 = 0.006652
+		 16107,		// A1 = -0.983126
+		 -32601,	// A2 = 0.994904
+		 11602,		// B2 = 0.354065
+		 -5555,		// B1 = -0.339111
+		 11602,		// B0 = 0.354065
+		 16722,		// A1 = -1.020630
+		 -32603,	// A2 = 0.994965
+		 15574,		// B2 = 0.475311
+		 -8176,		// B1 = -0.499069
+		 15574,		// B0 = 0.475311
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 1336.txt
+		16234,		// A1 = -0.990875
+		 32404,		// A2 = -0.988922
+		 -193,		// B2 = -0.005908
+		 0,		// B1 = 0.000000
+		 193,		// B0 = 0.005908
+		 15986,		// A1 = -0.975769
+		 -32632,	// A2 = 0.995880
+		 18051,		// B2 = 0.550903
+		 -8658,		// B1 = -0.528473
+		 18051,		// B0 = 0.550903
+		 16591,		// A1 = -1.012695
+		 -32634,	// A2 = 0.995941
+		 15736,		// B2 = 0.480240
+		 -8125,		// B1 = -0.495926
+		 15736,		// B0 = 0.480240
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 1366.txt
+		15564,		// A1 = -0.949982
+		 -32404,	// A2 = 0.988922
+		 -269,		// B2 = -0.008216
+		 0,		// B1 = 0.000000
+		 269,		// B0 = 0.008216
+		 15310,		// A1 = -0.934479
+		 -32632,	// A2 = 0.995880
+		 10815,		// B2 = 0.330063
+		 -4962,		// B1 = -0.302887
+		 10815,		// B0 = 0.330063
+		 15924,		// A1 = -0.971924
+		 -32634,	// A2 = 0.995941
+		 18880,		// B2 = 0.576172
+		 -9364,		// B1 = -0.571594
+		 18880,		// B0 = 0.576172
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 1380.txt
+		15247,		// A1 = -0.930603
+		 -32397,	// A2 = 0.988708
+		 -244,		// B2 = -0.007451
+		 0,		// B1 = 0.000000
+		 244,		// B0 = 0.007451
+		 14989,		// A1 = -0.914886
+		 -32627,	// A2 = 0.995697
+		 18961,		// B2 = 0.578644
+		 -8498,		// B1 = -0.518707
+		 18961,		// B0 = 0.578644
+		 15608,		// A1 = -0.952667
+		 -32628,	// A2 = 0.995758
+		 11145,		// B2 = 0.340134
+		 -5430,		// B1 = -0.331467
+		 11145,		// B0 = 0.340134
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 1400.txt
+		14780,		// A1 = -0.902130
+		 -32393,	// A2 = 0.988586
+		 -396,		// B2 = -0.012086
+		 0,		// B1 = 0.000000
+		 396,		// B0 = 0.012086
+		 14510,		// A1 = -0.885651
+		 -32630,	// A2 = 0.995819
+		 6326,		// B2 = 0.193069
+		 -2747,		// B1 = -0.167671
+		 6326,		// B0 = 0.193069
+		 15154,		// A1 = -0.924957
+		 -32632,	// A2 = 0.995850
+		 23235,		// B2 = 0.709076
+		 -10983,	// B1 = -0.670380
+		 23235,		// B0 = 0.709076
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 1477.txt
+		13005,		// A1 = -0.793793
+		 -32368,	// A2 = 0.987823
+		 -500,		// B2 = -0.015265
+		 0,		// B1 = 0.000000
+		 500,		// B0 = 0.015265
+		 12708,		// A1 = -0.775665
+		 -32615,	// A2 = 0.995331
+		 11420,		// B2 = 0.348526
+		 -4306,		// B1 = -0.262833
+		 11420,		// B0 = 0.348526
+		 13397,		// A1 = -0.817688
+		 -32615,	// A2 = 0.995361
+		 9454,		// B2 = 0.288528
+		 -3981,		// B1 = -0.243027
+		 9454,		// B0 = 0.288528
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 1600.txt
+		10046,		// A1 = -0.613190
+		 -32331,	// A2 = 0.986694
+		 -455,		// B2 = -0.013915
+		 0,		// B1 = 0.000000
+		 455,		// B0 = 0.013915
+		 9694,		// A1 = -0.591705
+		 -32601,	// A2 = 0.994934
+		 6023,		// B2 = 0.183815
+		 -1708,		// B1 = -0.104279
+		 6023,		// B0 = 0.183815
+		 10478,		// A1 = -0.639587
+		 -32603,	// A2 = 0.994965
+		 22031,		// B2 = 0.672333
+		 -7342,		// B1 = -0.448151
+		 22031,		// B0 = 0.672333
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// f1633_1638[]
+		9181,		// A1 = 0.560394
+		 -32256,	// A2 = -0.984375
+		 -556,		// B2 = -0.016975
+		 0,		// B1 = 0
+		 556,		// B0 = 0.016975
+		 8757,		// A1 = 0.534515
+		 -32574,	// A2 = -0.99408
+		 8443,		// B2 = 0.25769
+		 -2135,		// B1 = -0.130341
+		 8443,		// B0 = 0.25769
+		 9691,		// A1 = 0.591522
+		 -32574,	// A2 = -0.99411
+		 15446,		// B2 = 0.471375
+		 -4809,		// B1 = -0.293579
+		 15446,		// B0 = 0.471375
+		 7,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 1800.txt
+		5076,		// A1 = -0.309875
+		 -32304,	// A2 = 0.985840
+		 -508,		// B2 = -0.015503
+		 0,		// B1 = 0.000000
+		 508,		// B0 = 0.015503
+		 4646,		// A1 = -0.283600
+		 -32605,	// A2 = 0.995026
+		 6742,		// B2 = 0.205780
+		 -878,		// B1 = -0.053635
+		 6742,		// B0 = 0.205780
+		 5552,		// A1 = -0.338928
+		 -32605,	// A2 = 0.995056
+		 23667,		// B2 = 0.722260
+		 -4297,		// B1 = -0.262329
+		 23667,		// B0 = 0.722260
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},
+	{			// 1860.txt
+		3569,		// A1 = -0.217865
+		 -32292,	// A2 = 0.985504
+		 -239,		// B2 = -0.007322
+		 0,		// B1 = 0.000000
+		 239,		// B0 = 0.007322
+		 3117,		// A1 = -0.190277
+		 -32603,	// A2 = 0.994965
+		 18658,		// B2 = 0.569427
+		 -1557,		// B1 = -0.095032
+		 18658,		// B0 = 0.569427
+		 4054,		// A1 = -0.247437
+		 -32603,	// A2 = 0.994965
+		 18886,		// B2 = 0.576385
+		 -2566,		// B1 = -0.156647
+		 18886,		// B0 = 0.576385
+		 5,		// Internal filter scaling
+		 159,		// Minimum in-band energy threshold
+		 21,		// 21/32 in-band to broad-band ratio
+		 0x0FF5		// shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+	},};
+
+static int ixj_init_filter(int board, IXJ_FILTER * jf)
+{
+	unsigned short cmd;
+	int cnt, max;
+	IXJ *j = &ixj[board];
+
+	if (jf->filter > 3) {
+		return -1;
+	}
+	if (ixj_WriteDSPCommand(0x5154 + jf->filter, board))	// Select Filter
+
+		return -1;
+
+	if (!jf->enable) {
+		if (ixj_WriteDSPCommand(0x5152, board))		// Disable Filter
+
+			return -1;
+		else
+			return 0;
+	} else {
+		if (ixj_WriteDSPCommand(0x5153, board))		// Enable Filter
+
+			return -1;
+
+		// Select the filter (f0 - f3) to use.
+		if (ixj_WriteDSPCommand(0x5154 + jf->filter, board))
+			return -1;
+	}
+	if (jf->freq < 12 && jf->freq > 3) {
+		// Select the frequency for the selected filter.
+		if (ixj_WriteDSPCommand(0x5170 + jf->freq, board))
+			return -1;
+	} else if (jf->freq > 11) {
+		// We need to load a programmable filter set for undefined
+		// frequencies.  So we will point the filter to a programmable set.
+		// Since there are only 4 filters and 4 programmable sets, we will
+		// just point the filter to the same number set and program it for the
+		// frequency we want.
+		if (ixj_WriteDSPCommand(0x5170 + jf->filter, board))
+			return -1;
+
+		if (j->ver.low != 0x12) {
+			cmd = 0x515B;
+			max = 19;
+		} else {
+			cmd = 0x515E;
+			max = 15;
+		}
+		if (ixj_WriteDSPCommand(cmd, board))
+			return -1;
+
+		for (cnt = 0; cnt < max; cnt++) {
+			if (ixj_WriteDSPCommand(tone_table[jf->freq][cnt], board))
+				return -1;
+		}
+/*    if(j->ver.low != 0x12)
+   {
+   if(ixj_WriteDSPCommand(7, board))
+   return -1;
+   if(ixj_WriteDSPCommand(159, board))
+   return -1;
+   if(ixj_WriteDSPCommand(21, board))
+   return -1;
+   if(ixj_WriteDSPCommand(0x0FF5, board))
+   return -1;
+   } */
+	}
+	return 0;
+}
+
+static int ixj_init_tone(int board, IXJ_TONE * ti)
+{
+	int freq0, freq1;
+	unsigned short data;
+
+	if (ti->freq0) {
+		freq0 = ti->freq0;
+	} else {
+		freq0 = 0x7FFF;
+	}
+
+	if (ti->freq1) {
+		freq1 = ti->freq1;
+	} else {
+		freq1 = 0x7FFF;
+	}
+
+//  if(ti->tone_index > 12 && ti->tone_index < 28)
+	{
+		if (ixj_WriteDSPCommand(0x6800 + ti->tone_index, board))
+			return -1;
+
+		if (ixj_WriteDSPCommand(0x6000 + (ti->gain0 << 4) + ti->gain1, board))
+			return -1;
+
+		data = freq0;
+		if (ixj_WriteDSPCommand(data, board))
+			return -1;
+
+		data = freq1;
+		if (ixj_WriteDSPCommand(data, board))
+			return -1;
+	}
+	return freq0;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/telephony/ixj.h linux.14p16/drivers/telephony/ixj.h
--- linux.vanilla/drivers/telephony/ixj.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/telephony/ixj.h	Tue Dec 21 01:11:40 1999
@@ -0,0 +1,973 @@
+/*
+ *    ixj.h
+ *
+ *    Device Driver for the Internet PhoneJACK and
+ *    Internet LineJACK Telephony Cards.
+ *
+ *    (c) Copyright 1999 Quicknet 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.
+ *
+ * Author:          Ed Okerson, <eokerson@quicknet.net>
+ *    
+ * Contributors:    Greg Herlein, <gherlein@quicknet.net>
+ *                  David W. Erhart, <derhart@quicknet.net>
+ *                  John Sellers, <jsellers@quicknet.net>
+ *                  Mike Preston, <mpreston@quicknet.net>
+ *
+ * More information about the hardware related to this driver can be found
+ * at our website:    http://www.quicknet.net
+ *
+ * Fixes:
+ */
+static char ixj_h_rcsid[] = "$Id: ixj.h,v 3.4 1999/12/16 22:18:36 root Exp root $";
+
+#ifndef _I386_TYPES_H
+#include <asm/types.h>
+#endif
+
+#include "ixjuser.h"
+#include <linux/phonedev.h>
+
+typedef __u16 WORD;
+typedef __u32 DWORD;
+typedef __u8 BYTE;
+typedef __u8 BOOL;
+
+#define IXJMAX 16
+
+#define TRUE 1
+#define FALSE 0
+
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+/******************************************************************************
+*
+*  This structure when unioned with the structures below makes simple byte
+*  access to the registers easier.
+*
+******************************************************************************/
+typedef struct {
+	unsigned char low;
+	unsigned char high;
+} BYTES;
+
+int ixj_WriteDSPCommand(unsigned short, int board);
+
+/******************************************************************************
+*
+*  This structure represents the Hardware Control Register of the CT8020/8021
+*  The CT8020 is used in the Internet PhoneJACK, and the 8021 in the
+*  Internet LineJACK
+*
+******************************************************************************/
+typedef struct {
+	unsigned int rxrdy:1;
+	unsigned int txrdy:1;
+	unsigned int status:1;
+	unsigned int auxstatus:1;
+	unsigned int rxdma:1;
+	unsigned int txdma:1;
+	unsigned int rxburst:1;
+	unsigned int txburst:1;
+	unsigned int dmadir:1;
+	unsigned int cont:1;
+	unsigned int irqn:1;
+	unsigned int t:5;
+} HCRBIT;
+
+typedef union {
+	HCRBIT bits;
+	BYTES bytes;
+} HCR;
+
+/******************************************************************************
+*
+*  This structure represents the Hardware Status Register of the CT8020/8021
+*  The CT8020 is used in the Internet PhoneJACK, and the 8021 in the
+*  Internet LineJACK
+*
+******************************************************************************/
+typedef struct {
+	unsigned int controlrdy:1;
+	unsigned int auxctlrdy:1;
+	unsigned int statusrdy:1;
+	unsigned int auxstatusrdy:1;
+	unsigned int rxrdy:1;
+	unsigned int txrdy:1;
+	unsigned int restart:1;
+	unsigned int irqn:1;
+	unsigned int rxdma:1;
+	unsigned int txdma:1;
+	unsigned int cohostshutdown:1;
+	unsigned int t:5;
+} HSRBIT;
+
+typedef union {
+	HSRBIT bits;
+	BYTES bytes;
+} HSR;
+
+/******************************************************************************
+*
+*  This structure represents the General Purpose IO Register of the CT8020/8021
+*  The CT8020 is used in the Internet PhoneJACK, and the 8021 in the
+*  Internet LineJACK
+*
+******************************************************************************/
+typedef struct {
+	unsigned int x:1;
+	unsigned int gpio1:1;
+	unsigned int gpio2:1;
+	unsigned int gpio3:1;
+	unsigned int gpio4:1;
+	unsigned int gpio5:1;
+	unsigned int gpio6:1;
+	unsigned int gpio7:1;
+	unsigned int xread:1;
+	unsigned int gpio1read:1;
+	unsigned int gpio2read:1;
+	unsigned int gpio3read:1;
+	unsigned int gpio4read:1;
+	unsigned int gpio5read:1;
+	unsigned int gpio6read:1;
+	unsigned int gpio7read:1;
+} GPIOBIT;
+
+typedef union {
+	GPIOBIT bits;
+	BYTES bytes;
+	unsigned short word;
+} GPIO;
+
+/******************************************************************************
+*
+*  This structure represents the Line Monitor status response
+*
+******************************************************************************/
+typedef struct {
+	unsigned int digit:4;
+	unsigned int cpf_valid:1;
+	unsigned int dtmf_valid:1;
+	unsigned int peak:1;
+	unsigned int z:1;
+	unsigned int f0:1;
+	unsigned int f1:1;
+	unsigned int f2:1;
+	unsigned int f3:1;
+	unsigned int frame:4;
+} LMON;
+
+typedef union {
+	LMON bits;
+	BYTES bytes;
+} DTMF;
+
+typedef struct {
+	unsigned int z:7;
+	unsigned int dtmf_en:1;
+	unsigned int y:4;
+	unsigned int F3:1;
+	unsigned int F2:1;
+	unsigned int F1:1;
+	unsigned int F0:1;
+} CP;
+
+typedef union {
+	CP bits;
+	BYTES bytes;
+} CPTF;
+
+/******************************************************************************
+*
+*  This structure represents the Status Control Register on the Internet
+*  LineJACK
+*
+******************************************************************************/
+typedef struct {
+	unsigned int c0:1;
+	unsigned int c1:1;
+	unsigned int stereo:1;
+	unsigned int daafsyncen:1;
+	unsigned int led1:1;
+	unsigned int led2:1;
+	unsigned int led3:1;
+	unsigned int led4:1;
+} PSCRWI;			// Internet LineJACK and Internet PhoneJACK Lite
+
+typedef struct {
+	unsigned int eidp:1;
+	unsigned int eisd:1;
+	unsigned int x:6;
+} PSCRWP;			// Internet PhoneJACK PCI
+
+typedef union {
+	PSCRWI bits;
+	PSCRWP pcib;
+	char byte;
+} PLD_SCRW;
+
+typedef struct {
+	unsigned int c0:1;
+	unsigned int c1:1;
+	unsigned int x:1;
+	unsigned int d0ee:1;
+	unsigned int mixerbusy:1;
+	unsigned int sci:1;
+	unsigned int dspflag:1;
+	unsigned int daaflag:1;
+} PSCRRI;
+
+typedef struct {
+	unsigned int eidp:1;
+	unsigned int eisd:1;
+	unsigned int x:4;
+	unsigned int dspflag:1;
+	unsigned int det:1;
+} PSCRRP;
+
+typedef union {
+	PSCRRI bits;
+	PSCRRP pcib;
+	char byte;
+} PLD_SCRR;
+
+/******************************************************************************
+*
+*  These structures represents the SLIC Control Register on the
+*  Internet LineJACK
+*
+******************************************************************************/
+typedef struct {
+	unsigned int c1:1;
+	unsigned int c2:1;
+	unsigned int c3:1;
+	unsigned int b2en:1;
+	unsigned int spken:1;
+	unsigned int rly1:1;
+	unsigned int rly2:1;
+	unsigned int rly3:1;
+} PSLICWRITE;
+
+typedef struct {
+	unsigned int state:3;
+	unsigned int b2en:1;
+	unsigned int spken:1;
+	unsigned int c3:1;
+	unsigned int potspstn:1;
+	unsigned int det:1;
+} PSLICREAD;
+
+typedef struct {
+	unsigned int c1:1;
+	unsigned int c2:1;
+	unsigned int c3:1;
+	unsigned int b2en:1;
+	unsigned int e1:1;
+	unsigned int mic:1;
+	unsigned int spk:1;
+	unsigned int x:1;
+} PSLICPCI;
+
+typedef union {
+	PSLICPCI pcib;
+	PSLICWRITE bits;
+	PSLICREAD slic;
+	char byte;
+} PLD_SLICW;
+
+typedef union {
+	PSLICPCI pcib;
+	PSLICREAD bits;
+	char byte;
+} PLD_SLICR;
+
+/******************************************************************************
+*
+*  These structures represents the Clock Control Register on the
+*  Internet LineJACK
+*
+******************************************************************************/
+typedef struct {
+	unsigned int clk0:1;
+	unsigned int clk1:1;
+	unsigned int clk2:1;
+	unsigned int x0:1;
+	unsigned int slic_e1:1;
+	unsigned int x1:1;
+	unsigned int x2:1;
+	unsigned int x3:1;
+} PCLOCK;
+
+typedef union {
+	PCLOCK bits;
+	char byte;
+} PLD_CLOCK;
+
+/******************************************************************************
+*
+*  These structures deal with the mixer on the Internet LineJACK
+*
+******************************************************************************/
+
+typedef struct {
+	unsigned short vol[10];
+	unsigned int recsrc;
+	unsigned int modcnt;
+	unsigned short micpreamp;
+} MIX;
+
+/******************************************************************************
+*
+*  These structures deal with the DAA on the Internet LineJACK
+*
+******************************************************************************/
+
+typedef struct _DAA_REGS {
+	//-----------------------------------------------
+	// SOP Registers
+	//
+	BYTE bySOP;
+
+	union _SOP_REGS {
+		struct _SOP {
+			union	// SOP - CR0 Register
+			 {
+				BYTE reg;
+				struct _CR0_BITREGS {
+					BYTE CLK_EXT:1;		// cr0[0:0]
+
+					BYTE RIP:1;	// cr0[1:1]
+
+					BYTE AR:1;	// cr0[2:2]
+
+					BYTE AX:1;	// cr0[3:3]
+
+					BYTE FRR:1;	// cr0[4:4]
+
+					BYTE FRX:1;	// cr0[5:5]
+
+					BYTE IM:1;	// cr0[6:6]
+
+					BYTE TH:1;	// cr0[7:7]
+
+				} bitreg;
+			} cr0;
+
+			union	// SOP - CR1 Register
+			 {
+				BYTE reg;
+				struct _CR1_REGS {
+					BYTE RM:1;	// cr1[0:0]
+
+					BYTE RMR:1;	// cr1[1:1]
+
+					BYTE No_auto:1;		// cr1[2:2]
+
+					BYTE Pulse:1;	// cr1[3:3]
+
+					BYTE P_Tone1:1;		// cr1[4:4]
+
+					BYTE P_Tone2:1;		// cr1[5:5]
+
+					BYTE E_Tone1:1;		// cr1[6:6]
+
+					BYTE E_Tone2:1;		// cr1[7:7]
+
+				} bitreg;
+			} cr1;
+
+			union	// SOP - CR2 Register
+			 {
+				BYTE reg;
+				struct _CR2_REGS {
+					BYTE Call_II:1;		// CR2[0:0]
+
+					BYTE Call_I:1;	// CR2[1:1]
+
+					BYTE Call_en:1;		// CR2[2:2]
+
+					BYTE Call_pon:1;	// CR2[3:3]
+
+					BYTE IDR:1;	// CR2[4:4]
+
+					BYTE COT_R:3;	// CR2[5:7]
+
+				} bitreg;
+			} cr2;
+
+			union	// SOP - CR3 Register
+			 {
+				BYTE reg;
+				struct _CR3_REGS {
+					BYTE DHP_X:1;	// CR3[0:0]
+
+					BYTE DHP_R:1;	// CR3[1:1]
+
+					BYTE Cal_pctl:1;	// CR3[2:2]
+
+					BYTE SEL:1;	// CR3[3:3]
+
+					BYTE TestLoops:4;	// CR3[4:7]
+
+				} bitreg;
+			} cr3;
+
+			union	// SOP - CR4 Register
+			 {
+				BYTE reg;
+				struct _CR4_REGS {
+					BYTE Fsc_en:1;	// CR4[0:0]
+
+					BYTE Int_en:1;	// CR4[1:1]
+
+					BYTE AGX:2;	// CR4[2:3]
+
+					BYTE AGR_R:2;	// CR4[4:5]
+
+					BYTE AGR_Z:2;	// CR4[6:7]
+
+				} bitreg;
+			} cr4;
+
+			union	// SOP - CR5 Register
+			 {
+				BYTE reg;
+				struct _CR5_REGS {
+					BYTE V_0:1;	// CR5[0:0]
+
+					BYTE V_1:1;	// CR5[1:1]
+
+					BYTE V_2:1;	// CR5[2:2]
+
+					BYTE V_3:1;	// CR5[3:3]
+
+					BYTE V_4:1;	// CR5[4:4]
+
+					BYTE V_5:1;	// CR5[5:5]
+
+					BYTE V_6:1;	// CR5[6:6]
+
+					BYTE V_7:1;	// CR5[7:7]
+
+				} bitreg;
+			} cr5;
+
+			union	// SOP - CR6 Register
+			 {
+				BYTE reg;
+				struct _CR6_REGS {
+					BYTE reserved:8;	// CR6[0:7]
+
+				} bitreg;
+			} cr6;
+
+			union	// SOP - CR7 Register
+			 {
+				BYTE reg;
+				struct _CR7_REGS {
+					BYTE reserved:8;	// CR7[0:7]
+
+				} bitreg;
+			} cr7;
+		} SOP;
+
+		BYTE ByteRegs[sizeof(struct _SOP)];
+
+	} SOP_REGS;
+
+	// DAA_REGS.SOP_REGS.SOP.CR5.reg
+	// DAA_REGS.SOP_REGS.SOP.CR5.bitreg
+	// DAA_REGS.SOP_REGS.SOP.CR5.bitreg.V_2
+	// DAA_REGS.SOP_REGS.ByteRegs[5]
+
+	//-----------------------------------------------
+	// XOP Registers
+	//
+	BYTE byXOP;
+
+	union _XOP_REGS {
+		struct _XOP {
+			union	// XOP - XR0 Register - Read values
+			 {
+				BYTE reg;
+				struct _XR0_BITREGS {
+					BYTE SI_0:1;	// XR0[0:0] - Read
+
+					BYTE SI_1:1;	// XR0[1:1] - Read
+
+					BYTE VDD_OK:1;	// XR0[2:2] - Read
+
+					BYTE Caller_ID:1;	// XR0[3:3] - Read
+
+					BYTE RING:1;	// XR0[4:4] - Read
+
+					BYTE Cadence:1;		// XR0[5:5] - Read
+
+					BYTE Wake_up:1;		// XR0[6:6] - Read
+
+					BYTE unused:1;	// XR0[7:7] - Read
+
+				} bitreg;
+			} xr0;
+
+			union	// XOP - XR1 Register
+			 {
+				BYTE reg;
+				struct _XR1_BITREGS {
+					BYTE M_SI_0:1;	// XR1[0:0]
+
+					BYTE M_SI_1:1;	// XR1[1:1]
+
+					BYTE M_VDD_OK:1;	// XR1[2:2]
+
+					BYTE M_Caller_ID:1;	// XR1[3:3]
+
+					BYTE M_RING:1;	// XR1[4:4]
+
+					BYTE M_Cadence:1;	// XR1[5:5]
+
+					BYTE M_Wake_up:1;	// XR1[6:6]
+
+					BYTE unused:1;	// XR1[7:7]
+
+				} bitreg;
+			} xr1;
+
+			union	// XOP - XR2 Register
+			 {
+				BYTE reg;
+				struct _XR2_BITREGS {
+					BYTE CTO0:1;	// XR2[0:0]
+
+					BYTE CTO1:1;	// XR2[1:1]
+
+					BYTE CTO2:1;	// XR2[2:2]
+
+					BYTE CTO3:1;	// XR2[3:3]
+
+					BYTE CTO4:1;	// XR2[4:4]
+
+					BYTE CTO5:1;	// XR2[5:5]
+
+					BYTE CTO6:1;	// XR2[6:6]
+
+					BYTE CTO7:1;	// XR2[7:7]
+
+				} bitreg;
+			} xr2;
+
+			union	// XOP - XR3 Register
+			 {
+				BYTE reg;
+				struct _XR3_BITREGS {
+					BYTE DCR0:1;	// XR3[0:0]
+
+					BYTE DCR1:1;	// XR3[1:1]
+
+					BYTE DCI:1;	// XR3[2:2]
+
+					BYTE DCU0:1;	// XR3[3:3]
+
+					BYTE DCU1:1;	// XR3[4:4]
+
+					BYTE B_off:1;	// XR3[5:5]
+
+					BYTE AGB0:1;	// XR3[6:6]
+
+					BYTE AGB1:1;	// XR3[7:7]
+
+				} bitreg;
+			} xr3;
+
+			union	// XOP - XR4 Register
+			 {
+				BYTE reg;
+				struct _XR4_BITREGS {
+					BYTE C_0:1;	// XR4[0:0]
+
+					BYTE C_1:1;	// XR4[1:1]
+
+					BYTE C_2:1;	// XR4[2:2]
+
+					BYTE C_3:1;	// XR4[3:3]
+
+					BYTE C_4:1;	// XR4[4:4]
+
+					BYTE C_5:1;	// XR4[5:5]
+
+					BYTE C_6:1;	// XR4[6:6]
+
+					BYTE C_7:1;	// XR4[7:7]
+
+				} bitreg;
+			} xr4;
+
+			union	// XOP - XR5 Register
+			 {
+				BYTE reg;
+				struct _XR5_BITREGS {
+					BYTE T_0:1;	// XR5[0:0]
+
+					BYTE T_1:1;	// XR5[1:1]
+
+					BYTE T_2:1;	// XR5[2:2]
+
+					BYTE T_3:1;	// XR5[3:3]
+
+					BYTE T_4:1;	// XR5[4:4]
+
+					BYTE T_5:1;	// XR5[5:5]
+
+					BYTE T_6:1;	// XR5[6:6]
+
+					BYTE T_7:1;	// XR5[7:7]
+
+				} bitreg;
+			} xr5;
+
+			union	// XOP - XR6 Register - Read Values
+			 {
+				BYTE reg;
+				struct _XR6_BITREGS {
+					BYTE CPS0:1;	// XR6[0:0]
+
+					BYTE CPS1:1;	// XR6[1:1]
+
+					BYTE unused1:2;		// XR6[2:3]
+
+					BYTE CLK_OFF:1;		// XR6[4:4]
+
+					BYTE unused2:3;		// XR6[5:7]
+
+				} bitreg;
+			} xr6;
+
+			union	// XOP - XR7 Register
+			 {
+				BYTE reg;
+				struct _XR7_BITREGS {
+					BYTE unused1:1;		// XR7[0:0]
+
+					BYTE Vdd0:1;	// XR7[1:1]
+
+					BYTE Vdd1:1;	// XR7[2:2]
+
+					BYTE unused2:5;		// XR7[3:7]
+
+				} bitreg;
+			} xr7;
+		} XOP;
+
+		BYTE ByteRegs[sizeof(struct _XOP)];
+
+	} XOP_REGS;
+
+	// DAA_REGS.XOP_REGS.XOP.XR7.reg
+	// DAA_REGS.XOP_REGS.XOP.XR7.bitreg
+	// DAA_REGS.XOP_REGS.XOP.XR7.bitreg.Vdd0
+	// DAA_REGS.XOP_REGS.ByteRegs[7]
+
+	//-----------------------------------------------
+	// COP Registers
+	//
+	BYTE byCOP;
+
+	union _COP_REGS {
+		struct _COP {
+			BYTE THFilterCoeff_1[8];	// COP - TH Filter Coefficients,      CODE=0, Part 1
+
+			BYTE THFilterCoeff_2[8];	// COP - TH Filter Coefficients,      CODE=1, Part 2
+
+			BYTE THFilterCoeff_3[8];	// COP - TH Filter Coefficients,      CODE=2, Part 3
+
+			BYTE RingerImpendance_1[8];	// COP - Ringer Impendance Coefficients,  CODE=3, Part 1
+
+			BYTE IMFilterCoeff_1[8];	// COP - IM Filter Coefficients,      CODE=4, Part 1
+
+			BYTE IMFilterCoeff_2[8];	// COP - IM Filter Coefficients,      CODE=5, Part 2
+
+			BYTE RingerImpendance_2[8];	// COP - Ringer Impendance Coefficients,  CODE=6, Part 2
+
+			BYTE FRRFilterCoeff[8];		// COP - FRR Filter Coefficients,      CODE=7
+
+			BYTE FRXFilterCoeff[8];		// COP - FRX Filter Coefficients,      CODE=8
+
+			BYTE ARFilterCoeff[4];	// COP - AR Filter Coefficients,      CODE=9
+
+			BYTE AXFilterCoeff[4];	// COP - AX Filter Coefficients,      CODE=10 
+
+			BYTE Tone1Coeff[4];	// COP - Tone1 Coefficients,        CODE=11
+
+			BYTE Tone2Coeff[4];	// COP - Tone2 Coefficients,        CODE=12
+
+			BYTE LevelmeteringRinging[4];	// COP - Levelmetering Ringing,        CODE=13
+
+			BYTE CallerID1stTone[8];	// COP - Caller ID 1st Tone,        CODE=14
+
+			BYTE CallerID2ndTone[8];	// COP - Caller ID 2nd Tone,        CODE=15
+
+		} COP;
+
+		BYTE ByteRegs[sizeof(struct _COP)];
+
+	} COP_REGS;
+
+	// DAA_REGS.COP_REGS.COP.XR7.Tone1Coeff[3]
+	// DAA_REGS.COP_REGS.COP.XR7.bitreg
+	// DAA_REGS.COP_REGS.COP.XR7.bitreg.Vdd0
+	// DAA_REGS.COP_REGS.ByteRegs[57]
+
+	//-----------------------------------------------
+	// CAO Registers
+	//
+	BYTE byCAO;
+
+	union _CAO_REGS {
+		struct _CAO {
+			BYTE CallerID[512];	// CAO - Caller ID Bytes
+
+		} CAO;
+
+		BYTE ByteRegs[sizeof(struct _CAO)];
+	} CAO_REGS;
+
+	union			// XOP - XR0 Register - Write values
+	 {
+		BYTE reg;
+		struct _XR0_BITREGSW {
+			BYTE SO_0:1;	// XR1[0:0] - Write
+
+			BYTE SO_1:1;	// XR1[1:1] - Write
+
+			BYTE SO_2:1;	// XR1[2:2] - Write
+
+			BYTE unused:5;	// XR1[3:7] - Write
+
+		} bitreg;
+	} XOP_xr0_W;
+
+	union			// XOP - XR6 Register - Write values
+	 {
+		BYTE reg;
+		struct _XR6_BITREGSW {
+			BYTE unused1:4;		// XR6[0:3]
+
+			BYTE CLK_OFF:1;		// XR6[4:4]
+
+			BYTE unused2:3;		// XR6[5:7]
+
+		} bitreg;
+	} XOP_xr6_W;
+
+} DAA_REGS;
+
+#define ALISDAA_ID_BYTE      0x81
+#define ALISDAA_CALLERID_SIZE  512
+
+//------------------------------
+//
+//  Misc definitions
+//
+
+// Power Up Operation
+#define SOP_PU_SLEEP    0
+#define SOP_PU_RINGING    1
+#define SOP_PU_CONVERSATION  2
+#define SOP_PU_PULSEDIALING  3
+
+#define ALISDAA_CALLERID_SIZE 512
+
+#define PLAYBACK_MODE_COMPRESSED	0	//        Selects: Compressed modes, TrueSpeech 8.5-4.1, G.723.1, G.722, G.728, G.729
+#define PLAYBACK_MODE_TRUESPEECH_V40	0	//        Selects: TrueSpeech 8.5, 6.3, 5.3, 4.8 or 4.1 Kbps
+#define PLAYBACK_MODE_TRUESPEECH	8	//        Selects: TrueSpeech 8.5, 6.3, 5.3, 4.8 or 4.1 Kbps Version 5.1
+#define PLAYBACK_MODE_ULAW		2	//        Selects: 64 Kbit/sec MuA-law PCM
+#define PLAYBACK_MODE_ALAW		10	//        Selects: 64 Kbit/sec A-law PCM
+#define PLAYBACK_MODE_16LINEAR		6	//        Selects: 128 Kbit/sec 16-bit linear
+#define PLAYBACK_MODE_8LINEAR		4	//        Selects: 64 Kbit/sec 8-bit signed linear
+#define PLAYBACK_MODE_8LINEAR_WSS	5	//        Selects: 64 Kbit/sec WSS 8-bit unsigned linear
+
+#define RECORD_MODE_COMPRESSED		0	//        Selects: Compressed modes, TrueSpeech 8.5-4.1, G.723.1, G.722, G.728, G.729
+#define RECORD_MODE_TRUESPEECH		0	//        Selects: TrueSpeech 8.5, 6.3, 5.3, 4.8 or 4.1 Kbps
+#define RECORD_MODE_ULAW		4	//        Selects: 64 Kbit/sec Mu-law PCM
+#define RECORD_MODE_ALAW		12	//        Selects: 64 Kbit/sec A-law PCM
+#define RECORD_MODE_16LINEAR		5	//        Selects: 128 Kbit/sec 16-bit linear
+#define RECORD_MODE_8LINEAR		6	//        Selects: 64 Kbit/sec 8-bit signed linear
+#define RECORD_MODE_8LINEAR_WSS		7	//        Selects: 64 Kbit/sec WSS 8-bit unsigned linear
+
+enum SLIC_STATES {
+	PLD_SLIC_STATE_OC = 0,
+	PLD_SLIC_STATE_RINGING,
+	PLD_SLIC_STATE_ACTIVE,
+	PLD_SLIC_STATE_OHT,
+	PLD_SLIC_STATE_TIPOPEN,
+	PLD_SLIC_STATE_STANDBY,
+	PLD_SLIC_STATE_APR,
+	PLD_SLIC_STATE_OHTPR
+};
+
+enum SCI_CONTROL {
+	SCI_End = 0,
+	SCI_Enable_DAA,
+	SCI_Enable_Mixer,
+	SCI_Enable_EEPROM
+};
+
+enum Mode {
+	T63, T53, T48, T40
+};
+enum Dir {
+	V3_TO_V4, V4_TO_V3, V4_TO_V5, V5_TO_V4
+};
+
+typedef struct Proc_Info_Tag {
+	enum Mode convert_mode;
+	enum Dir convert_dir;
+	int Prev_Frame_Type;
+	int Current_Frame_Type;
+} Proc_Info_Type;
+
+enum PREVAL {
+	NORMAL = 0,
+	NOPOST,
+	POSTONLY,
+	PREERROR
+};
+
+enum IXJ_EXTENSIONS {
+	G729LOADER = 0,
+	TS85LOADER,
+	PRE_READ,
+	POST_READ,
+	PRE_WRITE,
+	POST_WRITE,
+	PRE_IOCTL,
+	POST_IOCTL
+};
+
+typedef struct {
+	unsigned int busytone:1;
+	unsigned int dialtone:1;
+	unsigned int ringback:1;
+	unsigned int ringing:1;
+	unsigned int cringing:1;
+	unsigned int play_first_frame:1;
+	unsigned int pstn_present:1;
+	unsigned int pstn_ringing:1;
+	unsigned int pots_correct:1;
+	unsigned int pots_pstn:1;
+	unsigned int g729_loaded:1;
+	unsigned int ts85_loaded:1;
+	unsigned int dtmf_oob:1;	// DTMF Out-Of-Band
+
+} IXJ_FLAGS;
+
+/******************************************************************************
+*
+*  This structure represents the Internet PhoneJACK and Internet LineJACK
+*
+******************************************************************************/
+
+typedef struct {
+	struct phone_device p;
+	unsigned int board;
+	unsigned int DSPbase;
+	unsigned int XILINXbase;
+	unsigned int serial;
+	struct phone_capability caplist[30];
+	unsigned int caps;
+	struct pnp_dev *dev;
+	unsigned int cardtype;
+	unsigned int rec_codec;
+	char rec_mode;
+	unsigned int play_codec;
+	char play_mode;
+	IXJ_FLAGS flags;
+	unsigned int rec_frame_size;
+	unsigned int play_frame_size;
+	int aec_level;
+	int readers, writers;
+	struct wait_queue *poll_q;
+	struct wait_queue *read_q;
+	char *read_buffer, *read_buffer_end;
+	char *read_convert_buffer;
+	unsigned int read_buffer_size;
+	unsigned int read_buffer_ready;
+	struct wait_queue *write_q;
+	char *write_buffer, *write_buffer_end;
+	char *write_convert_buffer;
+	unsigned int write_buffer_size;
+	unsigned int write_buffers_empty;
+	unsigned long drybuffer;
+	char *write_buffer_rp, *write_buffer_wp;
+	char dtmfbuffer[80];
+	char dtmf_current;
+	int dtmf_wp, dtmf_rp, dtmf_state, dtmf_proc;
+	int tone_off_time, tone_on_time;
+	struct fasync_struct *async_queue;
+	unsigned long tone_start_jif;
+	char tone_index;
+	char tone_state;
+	char maxrings;
+	IXJ_CADENCE *cadence_t;
+	int tone_cadence_state;
+	DTMF dtmf;
+	CPTF cptf;
+	BYTES dsp;
+	BYTES ver;
+	BYTES scr;
+	BYTES ssr;
+	BYTES baseframe;
+	HSR hsr;
+	GPIO gpio;
+	PLD_SCRR pld_scrr;
+	PLD_SCRW pld_scrw;
+	PLD_SLICW pld_slicw;
+	PLD_SLICR pld_slicr;
+	PLD_CLOCK pld_clock;
+	MIX mix;
+	unsigned short ring_cadence;
+	int ring_cadence_t;
+	unsigned long ring_cadence_jif;
+	int intercom;
+	int m_hook;
+	int r_hook;
+	char pstn_envelope;
+	char pstn_cid_intr;
+	unsigned pstn_cid_recieved;
+	IXJ_CID cid;
+	unsigned long pstn_ring_start;
+	unsigned long pstn_winkstart;
+	unsigned int winktime;
+	char port;
+	union telephony_exception ex;
+	char daa_mode;
+	unsigned long pstn_sleeptil;
+	DAA_REGS m_DAAShadowRegs;
+	Proc_Info_Type Info_read;
+	Proc_Info_Type Info_write;
+	unsigned short frame_count;
+	unsigned int filter_cadence;
+	unsigned int filter_hist[4];
+	unsigned short proc_load;
+	unsigned long framesread;
+	unsigned long frameswritten;
+	unsigned long read_wait;
+	unsigned long write_wait;
+	unsigned long timerchecks;
+	unsigned long txreadycheck;
+	unsigned long rxreadycheck;
+} IXJ;
+
+typedef int (*IXJ_REGFUNC) (IXJ * j, unsigned long arg);
+
+int ixj_register(int index, IXJ_REGFUNC regfunc);
+int ixj_unregister(int index);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/telephony/ixjuser.h linux.14p16/drivers/telephony/ixjuser.h
--- linux.vanilla/drivers/telephony/ixjuser.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/telephony/ixjuser.h	Fri Dec 17 23:23:08 1999
@@ -0,0 +1,629 @@
+/*
+ *    ixjuser.h
+ *
+ *    User-space include file for the Internet PhoneJACK and
+ *    Internet LineJACK Telephony Cards.
+ *
+ *    (c) Copyright 1999 Quicknet 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.
+ *
+ * Author:          Ed Okerson, <eokerson@quicknet.net>
+ *    
+ * Contributors:    Greg Herlein, <gherlein@quicknet.net>
+ *                  David W. Erhart, <derhart@quicknet.net>
+ *                  John Sellers, <jsellers@quicknet.net>
+ *                  Mike Preston, <mpreston@quicknet.net>
+ *
+ * More information about the hardware related to this driver can be found
+ * at our website:    http://www.quicknet.net
+ *
+ * Fixes:
+ */
+
+static char ixjuser_h_rcsid[] = "$Id: ixjuser.h,v 3.4 1999/12/16 22:18:36 root Exp root $";
+
+#include <linux/telephony.h>
+
+/***************************************************************************
+
+  If you use the IXJCTL_TESTRAM command, the card must be power
+  cycled to reset the SRAM values before futher use.
+
+***************************************************************************/
+#define IXJCTL_DSP_RESET 		_IO  ('q', 0xC0)
+
+#define IXJCTL_RING         PHONE_RING
+#define IXJCTL_HOOKSTATE    PHONE_HOOKSTATE
+#define IXJCTL_MAXRINGS			PHONE_MAXRINGS
+#define IXJCTL_RING_CADENCE	PHONE_RING_CADENCE
+#define IXJCTL_RING_START		PHONE_RING_START
+#define IXJCTL_RING_STOP		PHONE_RING_STOP
+
+#define IXJCTL_CARDTYPE			_IOR ('q', 0xC1, int)
+#define IXJCTL_SERIAL			  _IOR ('q', 0xC2, int)
+#define IXJCTL_DSP_TYPE     _IOR ('q', 0xC3, int)
+#define IXJCTL_DSP_VERSION  _IOR ('q', 0xC4, int)
+#define IXJCTL_DSP_IDLE			_IO  ('q', 0xC5)
+#define IXJCTL_TESTRAM			_IO  ('q', 0xC6)
+
+/******************************************************************************
+*
+* This group of IOCTLs deal with the record settings of the DSP
+*
+* The IXJCTL_REC_DEPTH command sets the internal buffer depth of the DSP.
+* Setting a lower depth reduces latency, but increases the demand of the
+* application to service the driver without frame loss.  The DSP has 480
+* bytes of physical buffer memory for the record channel so the true
+* maximum limit is determined by how many frames will fit in the buffer.
+*
+* 1 uncompressed (480 byte) 16-bit linear frame.
+* 2 uncompressed (240 byte) 8-bit A-law/mu-law frames.
+* 15 TrueSpeech 8.5 frames.
+* 20 TrueSpeech 6.3,5.3,4.8 or 4.1 frames.
+*
+* The default in the driver is currently set to 2 frames.
+*
+* The IXJCTL_REC_VOLUME and IXJCTL_PLAY_VOLUME commands both use a Q8
+* number as a parameter, 0x100 scales the signal by 1.0, 0x200 scales the
+* signal by 2.0, 0x80 scales the signal by 0.5.  No protection is given
+* against over-scaling, if the multiplication factor times the input
+* signal exceeds 16 bits, overflow distortion will occur.  The default
+* setting is 0x100 (1.0).
+*
+* The IXJCTL_REC_LEVEL returns the average signal level (not r.m.s.) on
+* the most recently recorded frame as a 16 bit value.
+******************************************************************************/
+
+#define IXJCTL_REC_CODEC                PHONE_REC_CODEC
+#define IXJCTL_REC_START                PHONE_REC_START
+#define IXJCTL_REC_STOP                 PHONE_REC_STOP
+#define IXJCTL_REC_DEPTH		PHONE_REC_DEPTH
+#define IXJCTL_FRAME			PHONE_FRAME
+#define IXJCTL_REC_VOLUME		PHONE_REC_VOLUME
+#define IXJCTL_REC_LEVEL		PHONE_REC_LEVEL
+
+typedef enum {
+	f300_640 = 4, f300_500, f1100, f350, f400, f480, f440, f620, f20_50,
+	f133_200, f300, f300_420, f330, f300_425, f330_440, f340, f350_400,
+	f350_440, f350_450, f360, f380_420, f392, f400_425, f400_440, f400_450,
+	f420, f425, f425_450, f425_475, f435, f440_450, f440_480, f445, f450,
+	f452, f475, f480_620, f494, f500, f520, f523, f525, f540_660, f587,
+	f590, f600, f660, f700, f740, f750, f750_1450, f770, f800, f816, f850,
+	f857_1645, f900, f900_1300, f935_1215, f941_1477, f942, f950, f950_1400,
+	f975, f1000, f1020, f1050, f1100_1750, f1140, f1200, f1209, f1330, f1336,
+	lf1366, f1380, f1400, f1477, f1600, f1633_1638, f1800, f1860
+} IXJ_FILTER_FREQ;
+
+typedef struct {
+	unsigned int filter;
+	IXJ_FILTER_FREQ freq;
+	char enable;
+} IXJ_FILTER;
+
+#define IXJCTL_SET_FILTER		_IOW ('q', 0xC7, IXJ_FILTER *)
+#define IXJCTL_GET_FILTER_HIST		_IOW ('q', 0xC8, int)
+/******************************************************************************
+*
+* This IOCTL allows you to reassign values in the tone index table.  The
+* tone table has 32 entries (0 - 31), but the driver only allows entries
+* 13 - 27 to be modified, entry 0 is reserved for silence and 1 - 12 are
+* the standard DTMF digits and 28 - 31 are the DTMF tones for A, B, C & D.
+* The positions used internally for Call Progress Tones are as follows:
+*    Dial Tone   - 25
+*    Ring Back   - 26
+*    Busy Signal - 27
+*
+* The freq values are calculated as:
+* freq = cos(2 * PI * frequency / 8000)
+*
+* The most commonly needed values are already calculated and listed in the
+* enum IXJ_TONE_FREQ.  Each tone index can have two frequencies with
+* different gains, if you are only using a single frequency set the unused
+* one to 0.
+*
+* The gain values range from 0 to 15 indicating +6dB to -24dB in 2dB
+* increments.
+*
+******************************************************************************/
+
+typedef enum {
+	hz20 = 0x7ffa,
+	hz50 = 0x7fe5,
+	hz133 = 0x7f4c,
+	hz200 = 0x7e6b,
+	hz261 = 0x7d50,		/* .63 C1  */
+	hz277 = 0x7cfa,		/* .18 CS1 */
+	hz293 = 0x7c9f,		/* .66 D1  */
+	hz300 = 0x7c75,
+	hz311 = 0x7c32,		/* .13 DS1 */
+	hz329 = 0x7bbf,		/* .63 E1  */
+	hz330 = 0x7bb8,
+	hz340 = 0x7b75,
+	hz349 = 0x7b37,		/* .23 F1  */
+	hz350 = 0x7b30,
+	hz360 = 0x7ae9,
+	hz369 = 0x7aa8,		/* .99 FS1 */
+	hz380 = 0x7a56,
+	hz392 = 0x79fa,		/* .00 G1  */
+	hz400 = 0x79bb,
+	hz415 = 0x7941,		/* .30 GS1 */
+	hz420 = 0x7918,
+	hz425 = 0x78ee,
+	hz435 = 0x7899,
+	hz440 = 0x786d,		/* .00 A1  */
+	hz445 = 0x7842,
+	hz450 = 0x7815,
+	hz452 = 0x7803,
+	hz466 = 0x7784,		/* .16 AS1 */
+	hz475 = 0x7731,
+	hz480 = 0x7701,
+	hz493 = 0x7685,		/* .88 B1  */
+	hz494 = 0x767b,
+	hz500 = 0x7640,
+	hz520 = 0x7578,
+	hz523 = 0x7559,		/* .25 C2  */
+	hz525 = 0x7544,
+	hz540 = 0x74a7,
+	hz554 = 0x7411,		/* .37 CS2 */
+	hz587 = 0x72a1,		/* .33 D2  */
+	hz590 = 0x727f,
+	hz600 = 0x720b,
+	hz620 = 0x711e,
+	hz622 = 0x7106,		/* .25 DS2 */
+	hz659 = 0x6f3b,		/* .26 E2  */
+	hz660 = 0x6f2e,
+	hz698 = 0x6d3d,		/* .46 F2  */
+	hz700 = 0x6d22,
+	hz739 = 0x6b09,		/* .99 FS2 */
+	hz740 = 0x6afa,
+	hz750 = 0x6a6c,
+	hz770 = 0x694b,
+	hz783 = 0x688b,		/* .99 G2  */
+	hz800 = 0x678d,
+	hz816 = 0x6698,
+	hz830 = 0x65bf,		/* .61 GS2 */
+	hz850 = 0x6484,
+	hz857 = 0x6414,
+	hz880 = 0x629f,		/* .00 A2  */
+	hz900 = 0x6154,
+	hz932 = 0x5f35,		/* .33 AS2 */
+	hz935 = 0x5f01,
+	hz941 = 0x5e9a,
+	hz942 = 0x5e88,
+	hz950 = 0x5dfd,
+	hz975 = 0x5c44,
+	hz1000 = 0x5a81,
+	hz1020 = 0x5912,
+	hz1050 = 0x56e2,
+	hz1100 = 0x5320,
+	hz1140 = 0x5007,
+	hz1200 = 0x4b3b,
+	hz1209 = 0x4a80,
+	hz1215 = 0x4a02,
+	hz1250 = 0x471c,
+	hz1300 = 0x42e0,
+	hz1330 = 0x4049,
+	hz1336 = 0x3fc4,
+	hz1366 = 0x3d22,
+	hz1380 = 0x3be4,
+	hz1400 = 0x3a1b,
+	hz1450 = 0x3596,
+	hz1477 = 0x331c,
+	hz1500 = 0x30fb,
+	hz1600 = 0x278d,
+	hz1633 = 0x2462,
+	hz1638 = 0x23e7,
+	hz1645 = 0x233a,
+	hz1750 = 0x18f8,
+	hz1800 = 0x1405,
+	hz1860 = 0xe0b,
+	hz2100 = 0xf5f6,
+	hz2450 = 0xd3b3
+} IXJ_FREQ;
+
+typedef enum {
+	C1 = hz261,
+	CS1 = hz277,
+	D1 = hz293,
+	DS1 = hz311,
+	E1 = hz329,
+	F1 = hz349,
+	FS1 = hz369,
+	G1 = hz392,
+	GS1 = hz415,
+	A1 = hz440,
+	AS1 = hz466,
+	B1 = hz493,
+	C2 = hz523,
+	CS2 = hz554,
+	D2 = hz587,
+	DS2 = hz622,
+	E2 = hz659,
+	F2 = hz698,
+	FS2 = hz739,
+	G2 = hz783,
+	GS2 = hz830,
+	A2 = hz880,
+	AS2 = hz932,
+} IXJ_NOTE;
+
+typedef struct {
+	int tone_index;
+	int freq0;
+	int gain0;
+	int freq1;
+	int gain1;
+} IXJ_TONE;
+
+#define IXJCTL_INIT_TONE		_IOW ('q', 0xC9, IXJ_TONE *)
+
+/******************************************************************************
+*
+* The IXJCTL_TONE_CADENCE ioctl defines tone sequences used for various
+* Call Progress Tones (CPT).  This is accomplished by setting up an array of
+* IXJ_CADENCE_ELEMENT structures that sequentially define the states of
+* the tone sequence.  The tone_on_time and tone_off time are in
+* 250 microsecond intervals.  A pointer to this array is passed to the
+* driver as the ce element of an IXJ_CADENCE structure.  The elements_used
+* must be set to the number of IXJ_CADENCE_ELEMENTS in the array.  The
+* termination variable defines what to do at the end of a cadence, the
+* options are to play the cadence once and stop, to repeat the last
+* element of the cadence indefinatly, or to repeat the entire cadence
+* indefinatly.  The ce variable is a pointer to the array of IXJ_TONE
+* structures.  If the freq0 variable is non-zero, the tone table contents
+* for the tone_index are updated to the frequencies and gains defined.  It
+* should be noted that DTMF tones cannot be reassigned, so if DTMF tone
+* table indexs are used in a cadence the frequency and gain variables will
+* be ignored.
+*
+* If the array elements contain frequency parameters the driver will
+* initialize the needed tone table elements and begin playing the tone,
+* there is no preset limit on the number of elements in the cadence.  If
+* there is more than one frequency used in the cadence, sequential elements
+* of different frequencies MUST use different tone table indexes.  Only one
+* cadence can be played at a time.  It is possible to build complex
+* cadences with multiple frequencies using 2 tone table indexes by
+* alternating between them.
+*
+******************************************************************************/
+
+typedef struct {
+	int index;
+	int tone_on_time;
+	int tone_off_time;
+	int freq0;
+	int gain0;
+	int freq1;
+	int gain1;
+} IXJ_CADENCE_ELEMENT;
+
+typedef enum {
+	PLAY_ONCE,
+	REPEAT_LAST_ELEMENT,
+	REPEAT_ALL
+} IXJ_CADENCE_TERM;
+
+typedef struct {
+	int elements_used;
+	IXJ_CADENCE_TERM termination;
+	IXJ_CADENCE_ELEMENT *ce;
+} IXJ_CADENCE;
+
+#define IXJCTL_TONE_CADENCE		_IOW ('q', 0xCA, IXJ_CADENCE *)
+/******************************************************************************
+*
+* This group of IOCTLs deal with the playback settings of the DSP
+*
+******************************************************************************/
+
+#define IXJCTL_PLAY_CODEC               PHONE_PLAY_CODEC
+#define IXJCTL_PLAY_START               PHONE_PLAY_START
+#define IXJCTL_PLAY_STOP                PHONE_PLAY_STOP
+#define IXJCTL_PLAY_DEPTH		PHONE_PLAY_DEPTH
+#define IXJCTL_PLAY_VOLUME		PHONE_PLAY_VOLUME
+#define IXJCTL_PLAY_LEVEL		PHONE_PLAY_LEVEL
+
+/******************************************************************************
+*
+* This group of IOCTLs deal with the Acoustic Echo Cancellation settings
+* of the DSP
+*
+* Issueing the IXJCTL_AEC_START command with a value of AEC_OFF has the
+* same effect as IXJCTL_AEC_STOP.  This is to simplify slider bar
+* controls.  IXJCTL_AEC_GET_LEVEL returns the current setting of the AEC.
+******************************************************************************/
+#define IXJCTL_AEC_START		_IOW ('q', 0xCB, int)
+#define IXJCTL_AEC_STOP			_IO  ('q', 0xCC)
+#define IXJCTL_AEC_GET_LEVEL		_IO  ('q', 0xCD)
+
+#define AEC_OFF   0
+#define AEC_LOW   1
+#define AEC_MED   2
+#define AEC_HIGH  3
+/******************************************************************************
+*
+* Call Progress Tones, DTMF, etc.
+* IXJCTL_DTMF_OOB determines if dtmf signaling is sent as Out-Of-Band
+* only.  If you pass a 1, dtmf is suppressed from the audio stream.
+* Tone on and off times are in 250 microsecond intervals so
+* ioctl(ixj1, IXJCTL_SET_TONE_ON_TIME, 360);
+* will set the tone on time of board ixj1 to 360 * 250us = 90ms
+* the default values of tone on and off times is 840 or 210ms
+******************************************************************************/
+
+#define IXJCTL_DTMF_READY		PHONE_DTMF_READY
+#define IXJCTL_GET_DTMF                 PHONE_GET_DTMF
+#define IXJCTL_GET_DTMF_ASCII           PHONE_GET_DTMF_ASCII
+#define IXJCTL_DTMF_OOB			PHONE_DTMF_OOB
+#define IXJCTL_EXCEPTION		PHONE_EXCEPTION
+#define IXJCTL_PLAY_TONE		PHONE_PLAY_TONE
+#define IXJCTL_SET_TONE_ON_TIME		PHONE_SET_TONE_ON_TIME
+#define IXJCTL_SET_TONE_OFF_TIME	PHONE_SET_TONE_OFF_TIME
+#define IXJCTL_GET_TONE_ON_TIME		PHONE_GET_TONE_ON_TIME
+#define IXJCTL_GET_TONE_OFF_TIME	PHONE_GET_TONE_OFF_TIME
+#define IXJCTL_GET_TONE_STATE		PHONE_GET_TONE_STATE
+#define IXJCTL_BUSY			PHONE_BUSY
+#define IXJCTL_RINGBACK			PHONE_RINGBACK
+#define IXJCTL_DIALTONE			PHONE_DIALTONE
+#define IXJCTL_CPT_STOP			PHONE_CPT_STOP
+
+/******************************************************************************
+* LineJack specific IOCTLs
+*
+* The lsb 4 bits of the LED argument represent the state of each of the 4
+* LED's on the LineJack
+******************************************************************************/
+
+#define IXJCTL_SET_LED			_IOW ('q', 0xCE, int)
+#define IXJCTL_MIXER			_IOW ('q', 0xCF, int)
+
+/******************************************************************************
+* 
+* The master volume controls use attenuation with 32 levels from 0 to -62dB
+* with steps of 2dB each, the defines should be OR'ed together then sent
+* as the parameter to the mixer command to change the mixer settings.
+* 
+******************************************************************************/
+#define MIXER_MASTER_L		0x0100
+#define MIXER_MASTER_R		0x0200
+#define ATT00DB			0x00
+#define ATT02DB			0x01
+#define ATT04DB			0x02
+#define ATT06DB			0x03
+#define ATT08DB			0x04
+#define ATT10DB			0x05
+#define ATT12DB			0x06
+#define ATT14DB			0x07
+#define ATT16DB			0x08
+#define ATT18DB			0x09
+#define ATT20DB			0x0A
+#define ATT22DB			0x0B
+#define ATT24DB			0x0C
+#define ATT26DB			0x0D
+#define ATT28DB			0x0E
+#define ATT30DB			0x0F
+#define ATT32DB			0x10
+#define ATT34DB			0x11
+#define ATT36DB			0x12
+#define ATT38DB			0x13
+#define ATT40DB			0x14
+#define ATT42DB			0x15
+#define ATT44DB			0x16
+#define ATT46DB			0x17
+#define ATT48DB			0x18
+#define ATT50DB			0x19
+#define ATT52DB			0x1A
+#define ATT54DB			0x1B
+#define ATT56DB			0x1C
+#define ATT58DB			0x1D
+#define ATT60DB			0x1E
+#define ATT62DB			0x1F
+#define MASTER_MUTE		0x80
+
+/******************************************************************************
+* 
+* The input volume controls use gain with 32 levels from +12dB to -50dB
+* with steps of 2dB each, the defines should be OR'ed together then sent
+* as the parameter to the mixer command to change the mixer settings.
+* 
+******************************************************************************/
+#define MIXER_PORT_CD_L		0x0600
+#define MIXER_PORT_CD_R		0x0700
+#define MIXER_PORT_LINE_IN_L	0x0800
+#define MIXER_PORT_LINE_IN_R	0x0900
+#define MIXER_PORT_POTS_REC	0x0C00
+#define MIXER_PORT_MIC		0x0E00
+
+#define GAIN12DB		0x00
+#define GAIN10DB		0x01
+#define GAIN08DB		0x02
+#define GAIN06DB		0x03
+#define GAIN04DB		0x04
+#define GAIN02DB		0x05
+#define GAIN00DB		0x06
+#define GAIN_02DB		0x07
+#define GAIN_04DB		0x08
+#define GAIN_06DB		0x09
+#define GAIN_08DB		0x0A
+#define GAIN_10DB		0x0B
+#define GAIN_12DB		0x0C
+#define GAIN_14DB		0x0D
+#define GAIN_16DB		0x0E
+#define GAIN_18DB		0x0F
+#define GAIN_20DB		0x10
+#define GAIN_22DB		0x11
+#define GAIN_24DB		0x12
+#define GAIN_26DB		0x13
+#define GAIN_28DB		0x14
+#define GAIN_30DB		0x15
+#define GAIN_32DB		0x16
+#define GAIN_34DB		0x17
+#define GAIN_36DB		0x18
+#define GAIN_38DB		0x19
+#define GAIN_40DB		0x1A
+#define GAIN_42DB		0x1B
+#define GAIN_44DB		0x1C
+#define GAIN_46DB		0x1D
+#define GAIN_48DB		0x1E
+#define GAIN_50DB		0x1F
+#define INPUT_MUTE		0x80
+
+/******************************************************************************
+* 
+* The POTS volume control use attenuation with 8 levels from 0dB to -28dB
+* with steps of 4dB each, the defines should be OR'ed together then sent
+* as the parameter to the mixer command to change the mixer settings.
+* 
+******************************************************************************/
+#define MIXER_PORT_POTS_PLAY	0x0F00
+
+#define POTS_ATT_00DB		0x00
+#define POTS_ATT_04DB		0x01
+#define POTS_ATT_08DB		0x02
+#define POTS_ATT_12DB		0x03
+#define POTS_ATT_16DB		0x04
+#define POTS_ATT_20DB		0x05
+#define POTS_ATT_24DB		0x06
+#define POTS_ATT_28DB		0x07
+#define POTS_MUTE		0x80
+
+/******************************************************************************
+* 
+* The DAA controls the interface to the PSTN port.  The driver loads the
+* US coefficients by default, so if you live in a different country you
+* need to load the set for your countries phone system.
+* 
+******************************************************************************/
+#define IXJCTL_DAA_COEFF_SET		_IOW ('q', 0xD0, int)
+
+#define DAA_US 		1	//PITA 8kHz
+#define DAA_UK 		2	//ISAR34 8kHz
+#define DAA_FRANCE 	3	//
+#define DAA_GERMANY	4
+#define DAA_AUSTRALIA	5
+#define DAA_JAPAN	6
+
+/******************************************************************************
+* 
+* Use IXJCTL_PORT to set or query the port the card is set to.  If the
+* argument is set to PORT_QUERY, the return value of the ioctl will
+* indicate which port is currently in use, otherwise it will change the
+* port.
+* 
+******************************************************************************/
+#define IXJCTL_PORT			_IOW ('q', 0xD1, int)
+
+#define PORT_QUERY	0
+#define PORT_POTS	1
+#define PORT_PSTN	2
+#define PORT_SPEAKER	3
+#define PORT_HANDSET	4
+
+#define IXJCTL_PSTN_SET_STATE		PHONE_PSTN_SET_STATE
+#define IXJCTL_PSTN_GET_STATE		PHONE_PSTN_GET_STATE
+
+#define PSTN_ON_HOOK	0
+#define PSTN_RINGING	1
+#define PSTN_OFF_HOOK	2
+#define PSTN_PULSE_DIAL	3
+
+/******************************************************************************
+* 
+* The DAA Analog GAIN sets 2 parameters at one time, the receive gain (AGRR), 
+* and the transmit gain (AGX).  OR together the components and pass them
+* as the parameter to IXJCTL_DAA_AGAIN.  The default setting is both at 0dB.
+* 
+******************************************************************************/
+#define IXJCTL_DAA_AGAIN		_IOW ('q', 0xD2, int)
+
+#define AGRR00DB	0x00	// Analog gain in receive direction 0dB
+#define AGRR3_5DB	0x10	// Analog gain in receive direction 3.5dB
+#define AGRR06DB	0x30	// Analog gain in receive direction 6dB
+
+#define AGX00DB		0x00	// Analog gain in transmit direction 0dB
+#define AGX_6DB		0x04	// Analog gain in transmit direction -6dB
+#define AGX3_5DB	0x08	// Analog gain in transmit direction 3.5dB
+#define AGX_2_5B	0x0C	// Analog gain in transmit direction -2.5dB
+
+#define IXJCTL_PSTN_LINETEST		_IO  ('q', 0xD3)
+
+typedef struct {
+	char month[3];
+	char day[3];
+	char hour[3];
+	char min[3];
+	int numlen;
+	char number[11];
+	int namelen;
+	char name[80];
+} IXJ_CID;
+
+#define IXJCTL_CID			_IOR ('q', 0xD4, IXJ_CID *)
+/******************************************************************************
+* 
+* The wink duration is tunable with this ioctl.  The default wink duration  
+* is 320ms.  You do not need to use this ioctl if you do not require a
+* different wink duration.
+* 
+******************************************************************************/
+#define IXJCTL_WINK_DURATION		PHONE_WINK_DURATION
+
+/******************************************************************************
+* 
+* This ioctl will connect the POTS port to the PSTN port on the LineJACK
+* In order for this to work properly the port selection should be set to
+* the PSTN port with IXJCTL_PORT prior to calling this ioctl.  This will
+* enable conference calls between PSTN callers and network callers.
+* Passing a 1 to this ioctl enables the POTS<->PSTN connection while
+* passing a 0 turns it back off.
+* 
+******************************************************************************/
+#define IXJCTL_POTS_PSTN		_IOW ('q', 0xD5, int)
+
+/******************************************************************************
+*
+* IOCTLs added by request.
+*
+* IXJCTL_HZ sets the value your Linux kernel uses for HZ as defined in
+*           /usr/include/asm/param.h, this determines the fundamental
+*           frequency of the clock ticks on your Linux system.  The kernel
+*           must be rebuilt if you change this value, also all modules you
+*           use (except this one) must be recompiled.  The default value
+*           is 100, and you only need to use this IOCTL if you use some
+*           other value.
+*
+*
+* IXJCTL_RATE sets the number of times per second that the driver polls
+*             the DSP.  This value cannot be larger than HZ.  By
+*             increasing both of these values, you may be able to reduce
+*             latency because the max hang time that can exist between the
+*             driver and the DSP will be reduced.
+*
+******************************************************************************/
+
+#define IXJCTL_HZ                       _IOW ('q', 0xE0, int)
+#define IXJCTL_RATE                     _IOW ('q', 0xE1, int)
+#define IXJCTL_FRAMES_READ		_IOR ('q', 0xE2, unsigned long)
+#define IXJCTL_FRAMES_WRITTEN		_IOR ('q', 0xE3, unsigned long)
+#define IXJCTL_READ_WAIT		_IOR ('q', 0xE4, unsigned long)
+#define IXJCTL_WRITE_WAIT		_IOR ('q', 0xE5, unsigned long)
+#define IXJCTL_DRYBUFFER_READ		_IOR ('q', 0xE6, unsigned long)
+#define IXJCTL_DRYBUFFER_CLEAR		_IO  ('q', 0xE7)
+
+/******************************************************************************
+*
+* The intercom IOCTL's short the output from one card to the input of the
+* other and vice versa (actually done in the DSP read function).  It is only
+* necessary to execute the IOCTL on one card, but it is necessary to have
+* both devices open to be able to detect hook switch changes.  The record
+* codec and rate of each card must match the playback codec and rate of
+* the other card for this to work properly.
+*
+******************************************************************************/
+
+#define IXJCTL_INTERCOM_START 		_IOW ('q', 0xFD, int)
+#define IXJCTL_INTERCOM_STOP  		_IOW ('q', 0xFE, int)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/telephony/phonedev.c linux.14p16/drivers/telephony/phonedev.c
--- linux.vanilla/drivers/telephony/phonedev.c	Thu Jan  1 01:00:00 1970
+++ linux.14p16/drivers/telephony/phonedev.c	Fri Dec 17 23:21:09 1999
@@ -0,0 +1,167 @@
+/*
+ *            Telephony registration for Linux
+ *
+ *              (c) Copyright 1999 Red Hat Software 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.
+ *
+ * Author:      Alan Cox, <alan@redhat.com>
+ *
+ * Fixes:
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/phonedev.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/kmod.h>
+
+
+#define PHONE_NUM_DEVICES	256
+
+/*
+ *    Active devices 
+ */
+
+static struct phone_device *phone_device[PHONE_NUM_DEVICES];
+
+/*
+ *    Open a phone device.
+ */
+
+static int phone_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor = MINOR(inode->i_rdev);
+	int err;
+	struct phone_device *p;
+
+	if (minor >= PHONE_NUM_DEVICES)
+		return -ENODEV;
+
+	p = phone_device[minor];
+	if (p == NULL) {
+		char modname[32];
+
+		sprintf(modname, "char-major-%d-%d", PHONE_MAJOR, minor);
+		request_module(modname);
+		p = phone_device[minor];
+		if (p == NULL)
+			return -ENODEV;
+	}
+	if (p->open) {
+		err = p->open(p, file);	/* Tell the device it is open */
+		if (err)
+			return err;
+	}
+	file->f_op = p->f_op;
+	return 0;
+}
+
+/*
+ *    Telephony For Linux device drivers request registration here.
+ */
+
+int phone_register_device(struct phone_device *p, int unit)
+{
+	int base;
+	int end;
+	int i;
+
+	base = 0;
+	end = PHONE_NUM_DEVICES - 1;
+
+	if (unit != PHONE_UNIT_ANY) {
+		base = unit;
+		end = unit;
+	}
+	for (i = base; i < end; i++) {
+		if (phone_device[i] == NULL) {
+			phone_device[i] = p;
+			p->minor = i;
+			MOD_INC_USE_COUNT;
+			return 0;
+		}
+	}
+	return -ENFILE;
+}
+
+/*
+ *    Unregister an unused Telephony for linux device
+ */
+
+void phone_unregister_device(struct phone_device *pfd)
+{
+	if (phone_device[pfd->minor] != pfd)
+		panic("phone: bad unregister");
+	phone_device[pfd->minor] = NULL;
+	MOD_DEC_USE_COUNT;
+}
+
+
+static struct file_operations phone_fops =
+{
+	NULL,
+	NULL,
+	NULL,
+	NULL,			/* readdir */
+	NULL,
+	NULL,
+	NULL,
+	phone_open,
+	NULL,			/* flush */
+	NULL
+};
+
+/*
+ *	Board init functions
+ */
+ 
+extern int ixj_init(void);
+
+/*
+ *    Initialise Telephony for linux
+ */
+
+int telephony_init(void)
+{
+	printk(KERN_INFO "Linux telephony interface: v1.00\n");
+	if (register_chrdev(PHONE_MAJOR, "telephony", &phone_fops)) {
+		printk("phonedev: unable to get major %d\n", PHONE_MAJOR);
+		return -EIO;
+	}
+	/*
+	 *    Init kernel installed drivers
+	 */
+#ifdef CONFIG_PHONE_IXJ
+	ixj_init();	 
+#endif
+	return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return telephony_init();
+}
+
+void cleanup_module(void)
+{
+	unregister_chrdev(PHONE_MAJOR, "telephony");
+}
+
+#endif
+
+EXPORT_SYMBOL(phone_register_device);
+EXPORT_SYMBOL(phone_unregister_device);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/Config.in linux.14p16/drivers/video/Config.in
--- linux.vanilla/drivers/video/Config.in	Sat Aug 28 20:00:58 1999
+++ linux.14p16/drivers/video/Config.in	Thu Dec  9 15:34:12 1999
@@ -57,7 +57,6 @@
       bool 'Apple "control" display support' CONFIG_FB_CONTROL
       bool 'Apple "platinum" display support' CONFIG_FB_PLATINUM
       bool 'Apple "valkyrie" display support' CONFIG_FB_VALKYRIE
-      bool 'ATI Mach64 display support' CONFIG_FB_ATY
       bool 'IMS Twin Turbo display support' CONFIG_FB_IMSTT
       bool 'Chips 65550 display support' CONFIG_FB_CT65550
       bool 'S3 Trio display support' CONFIG_FB_S3TRIO
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/atyfb.c linux.14p16/drivers/video/atyfb.c
--- linux.vanilla/drivers/video/atyfb.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/drivers/video/atyfb.c	Thu Dec  9 15:34:13 1999
@@ -1,4 +1,4 @@
-/*  $Id: atyfb.c,v 1.106.2.4 1999/09/02 06:34:46 paulus Exp $
+/*  $Id: atyfb.c,v 1.106.2.6 1999/10/14 08:44:47 davem Exp $
  *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
  *
  *	Copyright (C) 1997-1998  Geert Uytterhoeven
@@ -89,7 +89,6 @@
  */
 #undef DEBUG
 
-
 #define GUI_RESERVE	0x00001000
 
 
@@ -227,8 +226,8 @@
     } fbcon_cmap;
     u8 blitter_may_be_busy;
 #ifdef __sparc__
-    u8 open;
     u8 mmaped;
+    int open;
     int vtconsole;
     int consolecnt;
 #endif
@@ -1896,10 +1895,8 @@
     struct fb_info_aty *fb = (struct fb_info_aty *)info;
 
     if (user) {
-	if (fb->open)
-	    return -EBUSY;
+	fb->open++;
 	fb->mmaped = 0;
-	fb->open = 1;
 	fb->vtconsole = -1;
     } else {
 	fb->consolecnt++;
@@ -1909,17 +1906,54 @@
     return(0);
 }
 
+struct fb_var_screeninfo default_var = {
+    /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+    640, 480, 640, 480, 0, 0, 8, 0,
+    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
+    0, FB_VMODE_NONINTERLACED
+};
+
 static int atyfb_release(struct fb_info *info, int user)
 {
 #ifdef __sparc__
     struct fb_info_aty *fb = (struct fb_info_aty *)info;
 
     if (user) {
-	if (fb->vtconsole != -1)
-	    vt_cons[fb->vtconsole]->vc_mode = KD_TEXT;
-	fb->open = 0;
-	fb->mmaped = 0;
-	fb->vtconsole = -1;
+	fb->open--;
+	udelay(1000);
+	wait_for_idle(fb);
+	if (!fb->open) {
+		int was_mmaped = fb->mmaped;
+
+		fb->mmaped = 0;
+		if (fb->vtconsole != -1)
+			vt_cons[fb->vtconsole]->vc_mode = KD_TEXT;
+		fb->vtconsole = -1;
+
+		if (was_mmaped) {
+			struct fb_var_screeninfo var;
+
+			/* Now reset the default display config, we have no
+			 * idea what the program(s) which mmap'd the chip did
+			 * to the configuration, nor whether it restored it
+			 * correctly.
+			 */
+			var = default_var;
+			if (noaccel)
+				var.accel_flags &= ~FB_ACCELF_TEXT;
+			else
+				var.accel_flags |= FB_ACCELF_TEXT;
+			if (var.yres == var.yres_virtual) {
+				u32 vram = (fb->total_vram - (PAGE_SIZE << 2));
+				var.yres_virtual = ((vram * 8) / var.bits_per_pixel) /
+					var.xres_virtual;
+				if (var.yres_virtual < var.yres)
+					var.yres_virtual = var.yres;
+			}
+			atyfb_set_var(&var, -1, &fb->fb_info);
+		}
+	}
     } else {
 	fb->consolecnt--;
     }
@@ -1982,15 +2016,6 @@
 }
 
 
-struct fb_var_screeninfo default_var = {
-    /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
-    640, 480, 640, 480, 0, 0, 8, 0,
-    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-    0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
-    0, FB_VMODE_NONINTERLACED
-};
-
-
     /*
      *  Get the Fixed Part of the Display
      */
@@ -3909,47 +3934,65 @@
 {
 	struct fb_info_aty *info;
  	unsigned int pm;
- 	
+
 	for (info = first_display; info != NULL; info = info->next) {
 		struct fb_fix_screeninfo fix;
 		int nb;
-		
+
 		atyfb_get_fix(&fix, fg_console, (struct fb_info *)info);
 		nb = fb_display[fg_console].var.yres * fix.line_length;
 
 		switch (when) {
+		case PBOOK_SLEEP_REQUEST:
+			info->save_framebuffer = vmalloc(nb);
+			break;
+		case PBOOK_SLEEP_REJECT:
+			if (info->save_framebuffer) {
+				vfree(info->save_framebuffer);
+				info->save_framebuffer = 0;
+			}
+			break;
 		case PBOOK_SLEEP_NOW:
+			if (info->blitter_may_be_busy)
+				wait_for_idle(info);
 			/* Stop accel engine (stop bus mastering) */
 			if (info->current_par.accel_flags & FB_ACCELF_TEXT)
 				reset_engine(info);
-#if 1
+
 			/* Backup fb content */	
-			info->save_framebuffer = vmalloc(nb);
 			if (info->save_framebuffer)
 				memcpy(info->save_framebuffer,
 				       (void *)info->frame_buffer, nb);
-#endif
-			/* Blank display and LCD */				       
-			atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info);			
-			
-			/* Set chip to "suspend" mode. Note: There's an HW bug in the
-			   chip which prevents proper resync on wakeup with automatic
-			   power management, we handle suspend manually using the
-			   following (weird) sequence described by ATI. Note2:
+
+			/* Blank display and LCD */
+			atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info);
+
+			/* Set chip to "suspend" mode. Note: There's a HW bug
+			   in the chip which prevents proper resync on wakeup
+			   with automatic power management, we handle suspend
+			   manually using the following (weird) sequence
+			   described by ATI.
+			   Note2:
 			   We could enable this for all Rage LT Pro chip ids */
-			if ((Gx == LG_CHIP_ID) || (Gx == LT_CHIP_ID) || (Gx == LP_CHIP_ID)) {
+			if ((Gx == LG_CHIP_ID) || (Gx == LT_CHIP_ID)
+			    || (Gx == LP_CHIP_ID)) {
 				pm = aty_ld_le32(POWER_MANAGEMENT, info);
 				pm &= ~PWR_MGT_ON;
 				aty_st_le32(POWER_MANAGEMENT, pm, info);
 				pm = aty_ld_le32(POWER_MANAGEMENT, info);
+				mdelay(1);
 				pm &= ~(PWR_BLON | AUTO_PWR_UP);
 				pm |= SUSPEND_NOW;
 				aty_st_le32(POWER_MANAGEMENT, pm, info);
 				pm = aty_ld_le32(POWER_MANAGEMENT, info);
+				mdelay(1);
 				pm |= PWR_MGT_ON;
 				aty_st_le32(POWER_MANAGEMENT, pm, info);
 				do {
 					pm = aty_ld_le32(POWER_MANAGEMENT, info);
+					/* Fix a problem with revision 4c50 of the chip */
+					if (Gx == LP_CHIP_ID)
+						break;
 				} while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
 				mdelay(500);
 			}
@@ -3961,18 +4004,23 @@
 				pm &= ~PWR_MGT_ON;
 				aty_st_le32(POWER_MANAGEMENT, pm, info);
 				pm = aty_ld_le32(POWER_MANAGEMENT, info);
+				mdelay(1);
 				pm |=  (PWR_BLON | AUTO_PWR_UP);
 				pm &= ~SUSPEND_NOW;
 				aty_st_le32(POWER_MANAGEMENT, pm, info);
 				pm = aty_ld_le32(POWER_MANAGEMENT, info);
+				mdelay(1);
 				pm |= PWR_MGT_ON;
 				aty_st_le32(POWER_MANAGEMENT, pm, info);
 				do {
 					pm = aty_ld_le32(POWER_MANAGEMENT, info);
+					/* Fix a problem with revision 4c50 of the chip */
+					if (Gx == LP_CHIP_ID)
+						break;
 				} while ((pm & PWR_MGT_STATUS_MASK) != 0);
 				mdelay(500);
 			}
-#if 1
+
 			/* Restore fb content */			
 			if (info->save_framebuffer) {
 				memcpy((void *)info->frame_buffer,
@@ -3980,7 +4028,7 @@
 				vfree(info->save_framebuffer);
 				info->save_framebuffer = 0;
 			}
-#endif
+
 			/* Restore display */			
 			atyfb_set_par(&info->current_par, info);
 			atyfbcon_blank(0, (struct fb_info *)info);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/bwtwofb.c linux.14p16/drivers/video/bwtwofb.c
--- linux.vanilla/drivers/video/bwtwofb.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/drivers/video/bwtwofb.c	Thu Dec  9 15:34:13 1999
@@ -1,4 +1,4 @@
-/* $Id: bwtwofb.c,v 1.7.2.1 1999/08/26 05:21:13 shadow Exp $
+/* $Id: bwtwofb.c,v 1.7.2.3 1999/10/06 10:52:36 anton Exp $
  * bwtwofb.c: BWtwo frame buffer driver
  *
  * Copyright (C) 1998 Jakub Jelinek   (jj@ultra.linux.cz)
@@ -224,7 +224,9 @@
 #endif
 	fb->margins = bw2_margins;
 	
+#ifndef CONFIG_SUN4
 	fb->physbase = __get_phys(fb->sbdp->sbus_vaddrs[0]);
+#endif
 	fb->mmap_map = bw2_mmap_map;
 
 #ifdef __sparc_v9__
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/cgfourteenfb.c linux.14p16/drivers/video/cgfourteenfb.c
--- linux.vanilla/drivers/video/cgfourteenfb.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/drivers/video/cgfourteenfb.c	Thu Dec  9 15:34:13 1999
@@ -1,4 +1,4 @@
-/* $Id: cgfourteenfb.c,v 1.4 1999/01/26 10:55:03 jj Exp $
+/* $Id: cgfourteenfb.c,v 1.4.2.1 1999/09/28 15:59:58 davem Exp $
  * cgfourteenfb.c: CGfourteen frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/cgsixfb.c linux.14p16/drivers/video/cgsixfb.c
--- linux.vanilla/drivers/video/cgsixfb.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/drivers/video/cgsixfb.c	Thu Dec  9 15:34:13 1999
@@ -1,4 +1,4 @@
-/* $Id: cgsixfb.c,v 1.16.2.1 1999/05/25 00:59:35 davem Exp $
+/* $Id: cgsixfb.c,v 1.16.2.2 1999/09/28 15:59:55 davem Exp $
  * cgsixfb.c: CGsix (GX,GXplus) frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/cgthreefb.c linux.14p16/drivers/video/cgthreefb.c
--- linux.vanilla/drivers/video/cgthreefb.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/drivers/video/cgthreefb.c	Thu Dec  9 15:34:13 1999
@@ -1,4 +1,4 @@
-/* $Id: cgthreefb.c,v 1.4 1999/01/26 10:55:01 jj Exp $
+/* $Id: cgthreefb.c,v 1.4.2.1 1999/09/28 16:00:08 davem Exp $
  * cgthreefb.c: CGthree frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/chipsfb.c linux.14p16/drivers/video/chipsfb.c
--- linux.vanilla/drivers/video/chipsfb.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/drivers/video/chipsfb.c	Thu Dec  9 15:34:13 1999
@@ -726,9 +726,18 @@
 		int nb = p->var.yres * p->fix.line_length;
 
 		switch (when) {
+		case PBOOK_SLEEP_REQUEST:
+			p->save_framebuffer = vmalloc(nb);
+			break;
+		case PBOOK_SLEEP_REJECT:
+			if (p->save_framebuffer) {
+				vfree(p->save_framebuffer);
+				p->save_framebuffer = 0;
+			}
+			break;
+
 		case PBOOK_SLEEP_NOW:
 			chipsfb_blank(1, (struct fb_info *)p);
-			p->save_framebuffer = vmalloc(nb);
 			if (p->save_framebuffer)
 				memcpy(p->save_framebuffer,
 				       p->frame_buffer, nb);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/creatorfb.c linux.14p16/drivers/video/creatorfb.c
--- linux.vanilla/drivers/video/creatorfb.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/drivers/video/creatorfb.c	Thu Dec  9 15:34:13 1999
@@ -1,4 +1,4 @@
-/* $Id: creatorfb.c,v 1.27 1999/03/28 12:37:12 jj Exp $
+/* $Id: creatorfb.c,v 1.27.2.2 1999/11/05 09:07:56 davem Exp $
  * creatorfb.c: Creator/Creator3D frame buffer driver
  *
  * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
@@ -539,6 +539,36 @@
 	/* Not used if hw cursor */
 }
 
+#if 0
+static void ffb_blank(struct fb_info_sbusfb *fb)
+{
+	struct ffb_dac *dac = fb->s.ffb.dac;
+	unsigned long flags;
+	u32 tmp;
+
+	spin_lock_irqsave(&fb->lock, flags);
+	dac->type = 0x6000;
+	tmp = (dac->value & ~0x1);
+	dac->type = 0x6000;
+	dac->value = tmp;
+	spin_unlock_irqrestore(&fb->lock, flags);
+}
+#endif
+
+static void ffb_unblank(struct fb_info_sbusfb *fb)
+{
+	struct ffb_dac *dac = fb->s.ffb.dac;
+	unsigned long flags;
+	u32 tmp;
+
+	spin_lock_irqsave(&fb->lock, flags);
+	dac->type = 0x6000;
+	tmp = (dac->value | 0x1);
+	dac->type = 0x6000;
+	dac->value = tmp;
+	spin_unlock_irqrestore(&fb->lock, flags);
+}
+
 static void ffb_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count)
 {
 	struct ffb_dac *dac = fb->s.ffb.dac;
@@ -726,6 +756,16 @@
 	fb->setcurshape = ffb_setcurshape;
 	fb->switch_from_graph = ffb_switch_from_graph;
 	fb->fill = ffb_fill;
+#if 0
+	/* XXX Can't enable this for now, I've seen cases
+	 * XXX where the VC was blanked, and Xsun24 was started
+	 * XXX via a remote login, the sunfb code did not
+	 * XXX unblank creator when it was mmap'd for some
+	 * XXX reason, investigate later... -DaveM
+	 */
+	fb->blank = ffb_blank;
+	fb->unblank = ffb_unblank;
+#endif
 	
 	/* If there are any read errors or fifo overflow conditions,
 	 * clear them now.
@@ -755,5 +795,12 @@
 	if (afb)
 		fb->s.ffb.dac_rev = 10;
 	
+	/* Unblank it just to be sure.  When there are multiple
+	 * FFB/AFB cards in the system, or it is not the OBP
+	 * chosen console, it will have video outputs off in
+	 * the DAC.
+	 */
+	ffb_unblank(fb);
+
 	return idstring;
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/fbmem.c linux.14p16/drivers/video/fbmem.c
--- linux.vanilla/drivers/video/fbmem.c	Sat Aug 14 02:27:34 1999
+++ linux.14p16/drivers/video/fbmem.c	Thu Dec  9 15:34:14 1999
@@ -217,7 +217,7 @@
 static int PROC_CONSOLE(struct fb_info *info)
 {
 	int fgc;
-	
+
 	if (info->display_fg != NULL)
 		fgc = info->display_fg->vc_num;
 	else
@@ -353,6 +353,20 @@
        /* tell console var has changed */
        if (newfb->changevar)
 	   newfb->changevar(unit);
+       /* fixme: this really needs lock protection */
+       conp->vc_display_fg = &newfb->display_fg;
+       if (!newfb->display_fg)
+	   newfb->display_fg = conp;
+       if (oldfb != newfb && oldfb->display_fg == conp) {
+	   int i;
+	   for (i = 0; i < MAX_NR_CONSOLES; i++)
+	       if (fb_display[i].conp && con2fb_map[i] == oldidx) {
+		   oldfb->display_fg = fb_display[i].conp;
+		   break;
+	       }
+	   if (i == MAX_NR_CONSOLES)
+	       oldfb->display_fg = NULL;
+       }
     }
 }
 
@@ -447,6 +461,11 @@
 		    for (i = 0; i < MAX_NR_CONSOLES; i++)
 			set_con2fb_map(i, con2fb.framebuffer);
 		return 0;
+	case FBIOBLANK:
+		if (info->blank == 0)
+			return -EINVAL;
+		(*info->blank)(arg, info);
+		return 0;
 	default:
 		return fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE(info),
 				    info);
@@ -468,12 +487,16 @@
 		return -ENODEV;
 	if (fb->fb_mmap)
 		return fb->fb_mmap(info, file, vma);
+#if defined(__sparc__) && !defined(__sparc_v9__)
+	/* Should never get here, all fb drivers should have their own
+	   mmap routines */
+	return -EINVAL;
+#else
 	fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);
 
 	/* frame buffer memory */
 	start = (unsigned long)fix.smem_start;
 	len = (start & ~PAGE_MASK)+fix.smem_len;
-	start &= PAGE_MASK;
 	len = (len+~PAGE_MASK) & PAGE_MASK;
 	if (vma->vm_offset >= len) {
 		/* memory mapped io */
@@ -483,14 +506,37 @@
 			return -EINVAL;
 		start = (unsigned long)fix.mmio_start;
 		len = (start & ~PAGE_MASK)+fix.mmio_len;
-		start &= PAGE_MASK;
 		len = (len+~PAGE_MASK) & PAGE_MASK;
 	}
+	start &= PAGE_MASK;
 	if ((vma->vm_end - vma->vm_start + vma->vm_offset) > len)
 		return -EINVAL;
 	vma->vm_offset += start;
 	if (vma->vm_offset & ~PAGE_MASK)
 		return -ENXIO;
+#if defined(__sparc_v9__)
+	vma->vm_flags |= (VM_SHM | VM_LOCKED);
+	{
+		unsigned long align, j;
+		for (align = 0x400000; align > PAGE_SIZE; align >>= 3)
+			if (len >= align && !((start & ~PAGE_MASK) & (align - 1)))
+				break;
+		if (align > PAGE_SIZE && vma->vm_start & (align - 1)) {
+			/* align as much as possible */
+			struct vm_area_struct *vmm;
+			j = (-vma->vm_start) & (align - 1);
+			vmm = find_vma(current->mm, vma->vm_start);
+			if (!vmm || vmm->vm_start >= vma->vm_end + j) {
+				vma->vm_start += j;
+				vma->vm_end += j;
+			}
+		}
+	}
+	if (io_remap_page_range(vma->vm_start, vma->vm_offset,
+				vma->vm_end - vma->vm_start, vma->vm_page_prot, 0))
+		return -EAGAIN;
+	vma->vm_flags |= VM_IO;
+#else
 #if defined(__mc68000__)
 	if (CPU_IS_020_OR_030)
 		pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
@@ -503,9 +549,6 @@
 	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
 #elif defined(__alpha__)
 	/* Caching is off in the I/O space quadrant by design.  */
-#elif defined(__sparc__)
-	/* Should never get here, all fb drivers should have their own
-	   mmap routines */
 #elif defined(__i386__)
 	if (boot_cpu_data.x86 > 3)
 		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
@@ -525,7 +568,9 @@
 	if (remap_page_range(vma->vm_start, vma->vm_offset,
 			     vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
+#endif /* !__sparc_v9__ */
 	return 0;
+#endif /* ! sparc32 */
 }
 
 static int
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/leofb.c linux.14p16/drivers/video/leofb.c
--- linux.vanilla/drivers/video/leofb.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/drivers/video/leofb.c	Thu Dec  9 15:34:13 1999
@@ -1,4 +1,4 @@
-/* $Id: leofb.c,v 1.6 1999/04/01 13:03:25 jj Exp $
+/* $Id: leofb.c,v 1.6.2.1 1999/09/28 16:00:03 davem Exp $
  * leofb.c: Leo (ZX) 24/8bit frame buffer driver
  *
  * Copyright (C) 1996-1999 Jakub Jelinek (jj@ultra.linux.cz)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/matroxfb.c linux.14p16/drivers/video/matroxfb.c
--- linux.vanilla/drivers/video/matroxfb.c	Sat Aug 14 02:26:17 1999
+++ linux.14p16/drivers/video/matroxfb.c	Thu Dec  9 15:34:14 1999
@@ -1,10 +1,10 @@
 /*
  *
- * Hardware accelerated Matrox Millennium I, II, Mystique and G200
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
  *
  * (c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
- * Version: 1.15 1999/04/19
+ * Version: 1.19a 1999/08/12 (2.2.x branch)
  *
  * MTRR stuff: 1998 Tom Rini <tmrini@ntplx.net>
  *
@@ -14,8 +14,8 @@
  *               "Kurt Garloff" <garloff@kg1.ping.de>
  *                     Betatesting, fixes, ideas, videomodes, videomodes timmings
  *
- *               "Tom Rini" <tmrini@ntplx.net>
- *                     MTRR stuff, betatesting, fixes, ideas
+ *               "Tom Rini" <trini@disparity.net>
+ *                     MTRR stuff, PPC cleanups, betatesting, fixes, ideas
  *
  *               "Bibek Sahu" <scorpio@dodds.net>
  *                     Access device through readb|w|l and write b|w|l
@@ -60,6 +60,9 @@
  *               "Cort Dougan" <cort@cs.nmt.edu>
  *                     CHRP fixes and PReP cleanup
  *
+ *               "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ *                     G400 support
+ *
  * (following author is not in any relation with this code, but his code
  *  is included in this driver)
  *
@@ -87,6 +90,11 @@
 /* Debug register calls, too? */
 #undef MATROXFB_DEBUG_REG
 
+/* Log reentrancy attempts - you must have printstate() patch applied */
+#undef MATROXFB_DEBUG_REENTER
+/* you must define DEBUG_REENTER to get debugged CONSOLEBH... */
+#undef MATROXFB_DEBUG_CONSOLEBH
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -127,12 +135,15 @@
 #include <video/macmodes.h>
 #endif
 
+/* always compile support for 32MB... It cost almost nothing */
+#define CONFIG_FB_MATROX_32MB
+
 #define FBCON_HAS_VGATEXT
 
 #ifdef MATROXFB_DEBUG
 
 #define DEBUG
-#define DBG(x)		printk("matroxfb: %s\n", (x));
+#define DBG(x)		printk(KERN_DEBUG "matroxfb: %s\n", (x));
 
 #ifdef MATROXFB_DEBUG_HEAVY
 #define DBG_HEAVY(x)	DBG(x)
@@ -217,6 +228,9 @@
 #ifndef PCI_DEVICE_ID_MATROX_G100_AGP
 #define PCI_DEVICE_ID_MATROX_G100_AGP	0x1001
 #endif
+#ifndef PCI_DEVICE_ID_MATROX_G400_AGP
+#define PCI_DEVICE_ID_MATROX_G400_AGP	0x0525
+#endif
 
 #ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP
 #define PCI_SS_ID_MATROX_GENERIC		0xFF00
@@ -422,7 +436,7 @@
 	unsigned char	MiscOutReg;
 	unsigned char	DACpal[768];
 	unsigned char	CRTC[25];
-	unsigned char	CRTCEXT[6];
+	unsigned char	CRTCEXT[9];
 	unsigned char	SEQ[5];
 	/* unused for MGA mode, but who knows... */
 	unsigned char	GCTL[9];
@@ -453,7 +467,8 @@
 }
 
 #define PMXINFO(p) mxinfo(p),
-#define MINFO_FROM_DISP(x) struct matrox_fb_info* minfo = mxinfo(x)
+#define MINFO_FROM(x)	   struct matrox_fb_info* minfo = x
+#define MINFO_FROM_DISP(x) MINFO_FROM(mxinfo(x))
 
 #else
 
@@ -476,6 +491,7 @@
 #endif
 
 #define PMXINFO(p)
+#define MINFO_FROM(x)
 #define MINFO_FROM_DISP(x)
 
 #endif
@@ -563,12 +579,14 @@
 		int		hwcursor;
 		int		blink;
 		int		sgram;
+#ifdef CONFIG_FB_MATROX_32MB
+		int		support32MB;
+#endif
 
 		int		accelerator;
 		int		text_type_aux;
 		int		video64bits;
 		unsigned int	vgastep;
-		unsigned int	vgastepdisp;
 		unsigned int	textmode;
 		unsigned int	textstep;
 		unsigned int	textvram;	/* character cells */
@@ -609,6 +627,8 @@
 #if defined(CONFIG_FB_OF)
 unsigned char nvram_read_byte(int);
 int matrox_of_init(struct device_node *dp);
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
 #endif
 
 #define curr_ydstorg(x)	ACCESS_FBINFO2(x, curr.ydstorg.pixels)
@@ -678,6 +698,8 @@
 
 #define M_RESET		0x1E40
 
+#define M_AGP2PLL	0x1E4C
+
 #define M_OPMODE	0x1E54
 #define     M_OPMODE_DMA_GEN_WRITE	0x00
 #define     M_OPMODE_DMA_BLIT		0x04
@@ -713,6 +735,9 @@
 #define M_EXTVGA_INDEX	0x1FDE
 #define M_EXTVGA_DATA	0x1FDF
 
+/* G200 only */
+#define M_SRCORG	0x2CB4
+
 #define M_RAMDAC_BASE	0x3C00
 
 /* fortunately, same on TVP3026 and MGA1064 */
@@ -723,6 +748,9 @@
 #define M_X_INDEX	0x00
 #define M_X_DATAREG	0x0A
 
+#define DAC_XGENIOCTRL		0x2A
+#define DAC_XGENIODATA		0x2B
+
 #ifdef CONFIG_FB_MATROX_MILLENIUM
 #define TVP3026_INDEX		0x00
 #define TVP3026_PALWRADD	0x00
@@ -1054,6 +1082,48 @@
 #define isMilleniumII(x) (0)
 #endif
 
+#ifdef MATROXFB_DEBUG_REENTER
+static atomic_t guard_counter = ATOMIC_INIT(1);
+static atomic_t guard_printing = ATOMIC_INIT(1);
+static void guard_start(void) {
+	if (atomic_dec_and_test(&guard_counter)) {	/* first level */
+		if (!(bh_mask & (1 << CONSOLE_BH)))	/* and CONSOLE_BH disabled */
+			return;				/* is OK */
+		/* otherwise it is first level with CONSOLE_BH enabled -
+		   - if we are __sti or SMP, reentering from console_bh possible */
+		atomic_dec(&guard_printing);	/* disable reentrancy warning */
+		printk(KERN_DEBUG "matroxfb entered without CONSOLE_BH disabled\n");
+#ifdef printstate
+		printstate();
+#endif
+		atomic_inc(&guard_printing);
+		return;
+	}
+	/* real reentering... You should be already warned by code above */
+	if (atomic_dec_and_test(&guard_printing)) {
+#ifdef printstate
+		printstate();
+#endif
+	}
+	atomic_inc(&guard_printing);
+}
+
+static inline void guard_end(void) {
+	atomic_inc(&guard_counter);
+}
+
+#define CRITBEGIN guard_start();
+#define CRITEND   guard_end();
+
+#else
+
+#define CRITBEGIN
+#define CRITEND
+
+#endif
+
+#define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
+
 static void matrox_cfbX_init(WPMINFO struct display* p) {
 	u_int32_t maccess;
 	u_int32_t mpitch;
@@ -1101,7 +1171,7 @@
 	mga_outl(M_OPMODE, mopmode);
 	mga_outl(M_CXBNDRY, 0xFFFF0000);
 	mga_outl(M_YTOP, 0);
-	mga_outl(M_YBOT, 0x007FFFFF);
+	mga_outl(M_YBOT, 0x01FFFFFF);
 	mga_outl(M_MACCESS, maccess);
 	ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
 	if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC;
@@ -1113,7 +1183,9 @@
 	MINFO_FROM_DISP(p);
 
 	DBG("matrox_cfbX_bmove")
-	
+
+	CRITBEGIN
+
 	sx *= fontwidth(p);
 	dx *= fontwidth(p);
 	width *= fontwidth(p);
@@ -1142,8 +1214,10 @@
 	mga_outl(M_AR0, end);
 	mga_outl(M_AR3, start);
 	mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
-	mga_outl(M_YDSTLEN | M_EXEC, ((dy)<<16) | height);
+	mga_ydstlen(dy, height);
 	WaitTillIdle();
+
+	CRITEND
 }
 
 #ifdef FBCON_HAS_CFB4
@@ -1154,7 +1228,9 @@
 	   also odd, that means that we cannot use acceleration */
 	
 	DBG("matrox_cfb4_bmove")
-	
+
+	CRITBEGIN
+
 	if ((sx | dx | width) & fontwidth(p) & 1) {
 		fbcon_cfb4_bmove(p, sy, sx, dy, dx, height, width);
 		return;
@@ -1194,6 +1270,8 @@
 	mga_outl(M_YDST, dy*pixx >> 5);
 	mga_outl(M_LEN | M_EXEC, height);
 	WaitTillIdle();
+
+	CRITEND
 }
 #endif
 
@@ -1201,13 +1279,17 @@
 		int width) {
 	
 	DBG("matroxfb_accel_clear")
-	
-	mga_fifo(4);
+
+	CRITBEGIN
+
+	mga_fifo(5);
 	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE);
 	mga_outl(M_FCOL, color);
 	mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
-	mga_outl(M_YDSTLEN | M_EXEC, (sy << 16) | height);
+	mga_ydstlen(sy, height);
 	WaitTillIdle();
+
+	CRITEND
 }
 
 static void matrox_cfbX_clear(u_int32_t color, struct display* p, int sy, int sx, int height, int width) {
@@ -1225,7 +1307,9 @@
 	MINFO_FROM_DISP(p);
 
 	DBG("matrox_cfb4_clear")
-	
+
+	CRITBEGIN
+
 	whattodo = 0; 
 	bgx = attr_bgcol_ec(p, conp);
 	bgx |= bgx << 4;
@@ -1277,6 +1361,8 @@
 			}
 		}
 	}
+
+	CRITEND
 }
 #endif
 
@@ -1323,7 +1409,10 @@
 	charcell = fontwidth(p) * fontheight(p);
 	yy *= fontheight(p);
 	xx *= fontwidth(p);
-	mga_fifo(7);
+
+	CRITBEGIN
+
+	mga_fifo(8);
 	mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
 	
 	mga_outl(M_FCOL, fgx);
@@ -1332,8 +1421,10 @@
 	ar3 = ACCESS_FBINFO(fastfont.mgabase) + (c & p->charmask) * charcell;
 	mga_outl(M_AR3, ar3);
 	mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF);
-	mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+	mga_ydstlen(yy, fontheight(p));
 	WaitTillIdle();
+
+	CRITEND
 }
 	
 static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) {
@@ -1345,6 +1436,9 @@
 	
 	yy *= fontheight(p);
 	xx *= fontwidth(p);
+
+	CRITBEGIN
+
 #ifdef __BIG_ENDIAN
 	WaitTillIdle();
 	mga_outl(M_OPMODE, M_OPMODE_8BPP);
@@ -1367,7 +1461,7 @@
 		mga_outl(M_BCOL, bgx);
 		mga_outl(M_AR3, 0);
 		mga_outl(M_AR0, fontheight(p)*fontwidth(p)-1);
-		mga_outl(M_YDSTLEN | M_EXEC, (yy<<16) | fontheight(p));
+		mga_ydstlen(yy, fontheight(p));
 		mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, p->fontdata+(c&p->charmask)*charcell, charcell);
 	} else {
 		u8* chardata = p->fontdata+(c&p->charmask)*fontheight(p)*step;
@@ -1379,7 +1473,7 @@
 		mga_outl(M_AR5, 0);
 		mga_outl(M_AR3, 0);
 		mga_outl(M_AR0, ar0);
-		mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+		mga_ydstlen(yy, fontheight(p));
 
 		switch (step) {
 		case 1:	
@@ -1410,6 +1504,7 @@
 #ifdef __BIG_ENDIAN
 	mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
 #endif
+	CRITEND
 }
 
 #ifdef FBCON_HAS_CFB8
@@ -1464,6 +1559,9 @@
 	yy *= fontheight(p);
 	xx *= fontwidth(p);
 	charcell = fontwidth(p) * fontheight(p);
+
+	CRITBEGIN
+
 	mga_fifo(3);
 	mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
 	mga_outl(M_FCOL, fgx);
@@ -1475,10 +1573,12 @@
 		mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx);
 		mga_outl(M_AR3, ar3);
 		mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF);
-		mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+		mga_ydstlen(yy, fontheight(p));
 		xx += fontwidth(p);
 	}
 	WaitTillIdle();
+
+	CRITEND
 }
 
 static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) {
@@ -1504,7 +1604,7 @@
 		step = 4;
 	charcell = fontheight(p)*step;
 	xlen = (charcell + 3) & ~3;
-	ydstlen = (yy<<16) | fontheight(p);
+	ydstlen = (yy << 16) | fontheight(p);
 	if (fontwidth(p) == step << 3) {
 		ar0 = fontheight(p)*fontwidth(p) - 1;
 		easy = 1;
@@ -1512,6 +1612,9 @@
 		ar0 = fontwidth(p) - 1;
 		easy = 0;
 	}
+
+	CRITBEGIN
+
 #ifdef __BIG_ENDIAN
 	WaitTillIdle();
 	mga_outl(M_OPMODE, M_OPMODE_8BPP);
@@ -1529,7 +1632,7 @@
 	while (count--) {
 		u_int8_t* chardata = p->fontdata + (scr_readw(s++) & p->charmask)*charcell;
 
-		mga_fifo(5);
+		mga_fifo(6);
 		mga_writel(mmio, M_FXBNDRY, fxbndry);
 		mga_writel(mmio, M_AR0, ar0);
 		mga_writel(mmio, M_AR3, 0);
@@ -1573,6 +1676,7 @@
 #ifdef __BIG_ENDIAN
 	mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
 #endif
+	CRITEND
 }
 
 #ifdef FBCON_HAS_CFB8
@@ -1635,6 +1739,8 @@
 	xx |= (xx + fontwidth(p)) << 16;
 	xx >>= 1;
 
+	CRITBEGIN
+	
 	mga_fifo(5);
 	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
 	mga_outl(M_FCOL, 0xFFFFFFFF);
@@ -1642,6 +1748,8 @@
 	mga_outl(M_YDST, yy * p->var.xres_virtual >> 6);
 	mga_outl(M_LEN | M_EXEC, fontheight(p));
 	WaitTillIdle();
+
+	CRITEND
 } 
 #endif
 
@@ -1654,12 +1762,16 @@
 	yy *= fontheight(p);
 	xx *= fontwidth(p);
 
+	CRITBEGIN
+	
 	mga_fifo(4);
 	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
 	mga_outl(M_FCOL, 0x0F0F0F0F);
 	mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
-	mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+	mga_ydstlen(yy, fontheight(p));
 	WaitTillIdle();
+
+	CRITEND
 }
 #endif
 
@@ -1671,12 +1783,16 @@
 	yy *= fontheight(p);
 	xx *= fontwidth(p);
 
+	CRITBEGIN
+	
 	mga_fifo(4);
 	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
 	mga_outl(M_FCOL, 0xFFFFFFFF);
 	mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
-	mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+	mga_ydstlen(yy, fontheight(p));
 	WaitTillIdle();
+
+	CRITEND
 }
 
 static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) {
@@ -1840,6 +1956,9 @@
 
 	DBG("matroxfb_ti3026_cursor")
 	
+	if (ACCESS_FBINFO(currcon_display) != p)
+		return;
+
 	if (mode == CM_ERASE) {
 		if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
 			spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
@@ -1914,6 +2033,9 @@
 	xline = (~0) << (32 - ACCESS_FBINFO(cursor.w));
 	cursorbase = ACCESS_FBINFO(video.vbase);
 	h = ACCESS_FBINFO(features.DAC1064.cursorimage);
+
+	CRITBEGIN
+
 #ifdef __BIG_ENDIAN
 	WaitTillIdle();
 	mga_outl(M_OPMODE, M_OPMODE_32BPP);
@@ -1944,12 +2066,17 @@
 #ifdef __BIG_ENDIAN
 	mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
 #endif
+
+	CRITEND
 }
 	
 static void matroxfb_DAC1064_cursor(struct display* p, int mode, int x, int y) {
 	unsigned long flags;
 	MINFO_FROM_DISP(p);
 
+	if (ACCESS_FBINFO(currcon_display) != p)
+		return;
+
 	if (mode == CM_ERASE) {
 		if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
 			spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
@@ -2010,6 +2137,9 @@
 	fsize = (p->userfont?FNTCHARCNT(p->fontdata):256) * fontheight(p);
 	if (((fsize * width + 31) / 32) * 4 > ACCESS_FBINFO(fastfont.size))
 		return 0;
+
+	CRITBEGIN
+
 	mga_outl(M_OPMODE, M_OPMODE_8BPP);
 	if (width <= 8) {
 		if (width == 8)
@@ -2100,6 +2230,9 @@
 		}
 	}
 	mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
+
+	CRITEND
+
 	return 1;
 }
 
@@ -2117,6 +2250,8 @@
 	unsigned int step;
 	MINFO_FROM_DISP(p);
 
+	CRITBEGIN
+
 	step = ACCESS_FBINFO(devflags.textstep);
 	srcoff = (sy * p->next_line) + (sx * step);
 	dstoff = (dy * p->next_line) + (dx * step);
@@ -2144,6 +2279,7 @@
 			height--;
 		}
 	}
+	CRITEND
 }
 
 static void matrox_text_clear(struct vc_data* conp, struct display* p, int sy, int sx,
@@ -2156,6 +2292,9 @@
 	step = ACCESS_FBINFO(devflags.textstep);
 	offs = sy * p->next_line + sx * step;
 	val = ntohs((attr_bgcol(p, conp->vc_video_erase_char) << 4) | attr_fgcol(p, conp->vc_video_erase_char) | (' ' << 8));
+
+	CRITBEGIN
+	
 	while (height > 0) {
 		int i;
 		for (i = width; i > 0; offs += step, i--)
@@ -2163,6 +2302,7 @@
 		offs += p->next_line - width * step;
 		height--;
 	}
+	CRITEND
 }
 
 static void matrox_text_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
@@ -2175,7 +2315,12 @@
 	offs = yy * p->next_line + xx * step;
 	chr = attr_fgcol(p,c) | (attr_bgcol(p,c) << 4) | ((c & p->charmask) << 8);
 	if (chr & 0x10000) chr |= 0x08;
+
+	CRITBEGIN
+	
 	mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(chr));
+
+	CRITEND
 }
 
 static void matrox_text_putcs(struct vc_data* conp, struct display* p, const unsigned short* s,
@@ -2188,12 +2333,17 @@
 	step = ACCESS_FBINFO(devflags.textstep);
 	offs = yy * p->next_line + xx * step;
 	attr = attr_fgcol(p, scr_readw(s)) | (attr_bgcol(p, scr_readw(s)) << 4);
+
+	CRITBEGIN
+	
 	while (count-- > 0) {
 		unsigned int chr = ((scr_readw(s++)) & p->charmask) << 8;
 		if (chr & 0x10000) chr ^= 0x10008;
 		mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(attr|chr));
 		offs += step;
 	}
+
+	CRITEND
 }
 
 static void matrox_text_revc(struct display* p, int xx, int yy) {
@@ -2203,7 +2353,12 @@
 
 	step = ACCESS_FBINFO(devflags.textstep);
 	offs = yy * p->next_line + xx * step + 1;
+	
+	CRITBEGIN
+	
 	mga_writeb(ACCESS_FBINFO(video.vbase), offs, mga_readb(ACCESS_FBINFO(video.vbase), offs) ^ 0x77);
+
+	CRITEND
 }
 
 static int matrox_text_loadfont(WPMINFO struct display* p) {
@@ -2221,6 +2376,9 @@
 	dst = ACCESS_FBINFO(video.vbase);
 	i = 2;
 	font = (u_int8_t*)p->fontdata;
+
+	CRITBEGIN
+
 	mga_setr(M_SEQ_INDEX, 0x02, 0x04);
 	while (fsize--) {
 		int l;
@@ -2233,6 +2391,9 @@
 		i += (32 - fontheight(p)) * ACCESS_FBINFO(devflags.vgastep);
 	}
 	mga_setr(M_SEQ_INDEX, 0x02, 0x03);
+
+	CRITEND
+
 	return 1;
 }
 
@@ -2242,17 +2403,31 @@
 		return;
 
 	matroxfb_createcursorshape(PMINFO p, 0);
+
+	CRITBEGIN
+	
 	mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u));
 	mga_setr(M_CRTC_INDEX, 0x0B, ACCESS_FBINFO(cursor.d) - 1);
+
+	CRITEND
 }
 
 static void matrox_text_cursor(struct display* p, int mode, int x, int y) {
 	unsigned int pos;
 	MINFO_FROM_DISP(p);
 
+	if (ACCESS_FBINFO(currcon_display) != p)
+		return;
+
 	if (mode == CM_ERASE) {
 		if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
+
+			CRITBEGIN
+			
 			mga_setr(M_CRTC_INDEX, 0x0A, 0x20);
+
+			CRITEND
+
 			ACCESS_FBINFO(cursor.state) = CM_ERASE;
 		}
 		return;
@@ -2264,10 +2439,16 @@
 	ACCESS_FBINFO(cursor.x) = x;
 	ACCESS_FBINFO(cursor.y) = y;
 	pos = p->next_line / ACCESS_FBINFO(devflags.textstep) * y + x;
+
+	CRITBEGIN
+	
 	mga_setr(M_CRTC_INDEX, 0x0F, pos);
 	mga_setr(M_CRTC_INDEX, 0x0E, pos >> 8);
 
 	mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u));
+
+	CRITEND
+
 	ACCESS_FBINFO(cursor.state) = CM_DRAW;
 }
 
@@ -2523,6 +2704,9 @@
 static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
 	unsigned int pos;
 	unsigned short p0, p1, p2;
+#ifdef CONFIG_FB_MATROX_32MB
+	unsigned int p3;
+#endif
 	struct display *disp;
 
 	DBG("matrox_pan_var")
@@ -2536,10 +2720,22 @@
 	}
 	p0 = ACCESS_FBINFO(currenthw)->CRTC[0x0D] = pos & 0xFF;
 	p1 = ACCESS_FBINFO(currenthw)->CRTC[0x0C] = (pos & 0xFF00) >> 8;
-	p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F);
+	p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
+#ifdef CONFIG_FB_MATROX_32MB
+	p3 = ACCESS_FBINFO(currenthw)->CRTCEXT[8] = pos >> 21;
+#endif	
+
+	CRITBEGIN
+
 	mga_setr(M_CRTC_INDEX, 0x0D, p0);
 	mga_setr(M_CRTC_INDEX, 0x0C, p1);
+#ifdef CONFIG_FB_MATROX_32MB
+	if (ACCESS_FBINFO(devflags.support32MB))
+		mga_setr(M_EXTVGA_INDEX, 0x08, p3);
+#endif
 	mga_setr(M_EXTVGA_INDEX, 0x00, p2);
+
+	CRITEND
 }
 
 	/*
@@ -2627,13 +2823,16 @@
 		case 0:		return xres;
 		case 4:		rounding = 128;
 				break;
-		case 8:		rounding = 64;
+		case 8:		rounding = 64;	/* doc says 64; 32 is OK for G400 */
 				break;
 		case 16:	rounding = 32;
 				break;
-		case 24:	rounding = 64;
+		case 24:	rounding = 64;	/* doc says 64; 32 is OK for G400 */
 				break;
 		default:	rounding = 16;
+				/* on G400, 16 really does not work */
+				if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
+					rounding = 32;
 				break;
 	}
 	if (isInterleave(MINFO)) {
@@ -3140,7 +3339,7 @@
 	hw->DACclk[2] = p;
 }
 
-__initfunc(static void DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem)) {
+static void __init DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem){
 	u_int32_t mx;
 
 	DBG("DAC1064_setmclk")
@@ -3288,6 +3487,8 @@
 static void DAC1064_restore_1(CPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) {
 	
 	DBG("DAC1064_restore_1")
+
+	CRITBEGIN
 	
 	outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]);
 	outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]);
@@ -3298,6 +3499,8 @@
 		for (i = 0; i < sizeof(MGA1064_DAC_regs); i++)
 			outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]);
 	}
+
+	CRITEND
 }
 
 static void DAC1064_restore_2(WPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw, struct display* p) {
@@ -3305,6 +3508,8 @@
 	unsigned int tmout;
 	
 	DBG("DAC1064_restore_2")
+
+	CRITBEGIN
 	
 	for (i = 0; i < 3; i++)
 		outDAC1064(PMINFO M1064_XPIXPLLCM + i, hw->DACclk[i]);
@@ -3313,6 +3518,9 @@
 			break;
 		udelay(10);
 	};
+
+	CRITEND
+
 	if (!tmout)
 		printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
 
@@ -3585,7 +3793,9 @@
 			var->pixclock = 15000;	/* limit for "normal" gclk & mclk */
 #endif
 	}
-
+	/* YDSTLEN contains only signed 16bit value */
+	if (var->yres_virtual > 32767)
+		var->yres_virtual = 32767;
 	if (var->yres_virtual < var->yres)
 		var->yres = var->yres_virtual;
 	if (var->xres_virtual < var->xres)
@@ -3684,7 +3894,7 @@
 }
 
 #ifdef CONFIG_FB_MATROX_MILLENIUM
-__initfunc(static void ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout)) {
+static void __init ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout){
 	unsigned int f_pll;
 	unsigned int pclk_m, pclk_n, pclk_p;
 	unsigned int mclk_m, mclk_n, mclk_p;
@@ -3783,7 +3993,7 @@
 		printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
 }
 
-__initfunc(static void ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw)) {
+static void __init ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw){
 
 	DBG("ti3026_ramdac_init")
 
@@ -3800,7 +4010,7 @@
 }
 #endif
 
-__initfunc(static void matroxfb_fastfont_init(struct matrox_fb_info* minfo)) {
+static void matroxfb_fastfont_init(struct matrox_fb_info* minfo){
 	unsigned int size;
 
 	size = ACCESS_FBINFO(fastfont.size);
@@ -3824,7 +4034,7 @@
 }
 
 #ifdef CONFIG_FB_MATROX_MYSTIQUE
-__initfunc(static void MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw)) {
+static void __init MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw){
 
 	DBG("MGA1064_ramdac_init");
 
@@ -3841,7 +4051,7 @@
 	DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
 }
 
-__initfunc(static int MGA1064_preinit(WPMINFO struct matrox_hw_state* hw)) {
+static int __init MGA1064_preinit(WPMINFO struct matrox_hw_state* hw){
 	static const int vxres_mystique[] = { 512,        640, 768,  800,  832,  960, 
 					     1024, 1152, 1280,      1600, 1664, 1920, 
 					     2048,    0};
@@ -3873,7 +4083,7 @@
 	return 0;
 }
 
-__initfunc(static void MGA1064_reset(WPMINFO struct matrox_hw_state* hw)) {
+static void __init MGA1064_reset(WPMINFO struct matrox_hw_state* hw){
 
 	DBG("MGA1064_reset");
 
@@ -3893,7 +4103,7 @@
 static int def50 = 0;	/* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */
 #endif
 
-__initfunc(static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p)) {
+static void __init MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p){
 	int reg;
 	int selClk;
 	int clk;
@@ -3937,7 +4147,7 @@
 	outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS);
 }
 
-__initfunc(static void MGAG100_setPixClock(CPMINFO int flags, int freq)) {
+static void __init MGAG100_setPixClock(CPMINFO int flags, int freq){
 	unsigned int m, n, p;
 
 	DBG("MGAG100_setPixClock")
@@ -3946,7 +4156,7 @@
 	MGAG100_progPixClock(PMINFO flags, m, n, p);
 }
 
-__initfunc(static int MGAG100_preinit(WPMINFO struct matrox_hw_state* hw)) {
+static int __init MGAG100_preinit(WPMINFO struct matrox_hw_state* hw){
 	static const int vxres_g100[] = {  512,        640, 768,  800,  832,  960, 
                                           1024, 1152, 1280,      1600, 1664, 1920, 
                                           2048, 0};
@@ -4036,7 +4246,7 @@
 	return 0;
 }
 	
-__initfunc(static void MGAG100_reset(WPMINFO struct matrox_hw_state* hw)) {
+static void __init MGAG100_reset(WPMINFO struct matrox_hw_state* hw){
 	u_int8_t b;
 
 	DBG("MGAG100_reset")
@@ -4104,6 +4314,8 @@
 		dprintk("%02X:", hw->ATTR[i]);
 	dprintk("\n");
 
+	CRITBEGIN
+
 	mga_inb(M_ATTR_RESET);
 	mga_outb(M_ATTR_INDEX, 0);
 	mga_outb(M_MISC_REG, hw->MiscOutReg);
@@ -4125,6 +4337,8 @@
 		mga_outb(M_DAC_VAL, hw->DACpal[i]);
 	mga_inb(M_ATTR_RESET);
 	mga_outb(M_ATTR_INDEX, 0x20);
+
+	CRITEND
 }
 
 static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green,
@@ -4227,10 +4441,15 @@
 	int i;
 
 	DBG("MGA1064_restore")
+
+	CRITBEGIN
 	
 	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
 	mga_outb(M_IEN, 0x00);
 	mga_outb(M_CACHEFLUSH, 0x00);
+
+	CRITEND
+
 	DAC1064_restore_1(PMINFO hw, oldhw);
 	vgaHWrestore(PMINFO hw, oldhw);
 	for (i = 0; i < 6; i++)
@@ -4244,10 +4463,18 @@
 	int i;
 
 	DBG("MGAG100_restore")
-	
+
+	CRITBEGIN
+
 	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+	CRITEND
+
 	DAC1064_restore_1(PMINFO hw, oldhw);
 	vgaHWrestore(PMINFO hw, oldhw);
+#ifdef CONFIG_FB_MATROX_32MB
+	if (ACCESS_FBINFO(devflags.support32MB))
+		mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]);
+#endif
 	for (i = 0; i < 6; i++)
 		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
 	DAC1064_restore_2(PMINFO hw, oldhw, p);
@@ -4265,9 +4492,16 @@
 		dprintk("%02X:", hw->CRTCEXT[i]);
 	dprintk("\n");
 
+	CRITBEGIN
+
 	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
 
+	CRITEND
+
 	vgaHWrestore(PMINFO hw, oldhw);
+
+	CRITBEGIN
+
 	for (i = 0; i < 6; i++)
 		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
 
@@ -4285,11 +4519,13 @@
 		oldhw->DACclk[2] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
 		oldhw->DACclk[5] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
 	}
+	CRITEND
 	if (!oldhw || memcmp(hw->DACclk, oldhw->DACclk, 6)) {
 		/* agrhh... setting up PLL is very slow on Millenium... */
 		/* Mystique PLL is locked in few ms, but Millenium PLL lock takes about 0.15 s... */
 		/* Maybe even we should call schedule() ? */
 
+		CRITBEGIN
 		outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]);
 		outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
 		outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0);
@@ -4307,24 +4543,31 @@
 					break;
 				udelay(10);
 			}
+
+			CRITEND
+
 			if (!tmout)
 				printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
 			else
 				dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout);
+			CRITBEGIN
 		}
 		outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]);
 		outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
 		for (i = 3; i < 6; i++)
 			outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]);
+		CRITEND
 		if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) {
 			int tmout;
 
+			CRITBEGIN
 			outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
 			for (tmout = 500000; tmout; --tmout) {
 				if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40) 
 					break;
 				udelay(10);
 			}
+			CRITEND
 			if (!tmout)
 				printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n");
 			else
@@ -4379,7 +4622,7 @@
 	strcpy(fix->id,"MATROX");
 
 	fix->smem_start = (void*)ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
-	fix->smem_len = ACCESS_FBINFO(video.len) - ACCESS_FBINFO(curr.ydstorg.bytes);
+	fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes);
 	fix->type = p->type;
 	fix->type_aux = p->type_aux;
 	fix->visual = p->visual;
@@ -4531,7 +4774,8 @@
 
 			hw->CRTC[0x0D] = pos & 0xFF;
 			hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
-			hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F);
+			hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
+			hw->CRTCEXT[8] = pos >> 21;
 			ACCESS_FBINFO(hw_switch->restore(PMINFO hw, ohw, display));
 			ACCESS_FBINFO(cursor.redraw) = 1;
 			ACCESS_FBINFO(currenthw) = hw;
@@ -4717,10 +4961,16 @@
 		case 4:  seq = 0x20; crtc = 0x30; break;
 		default: seq = 0x00; crtc = 0x00; break;
 	}
+
+	CRITBEGIN
+	
 	mga_outb(M_SEQ_INDEX, 1);
 	mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
 	mga_outb(M_EXTVGA_INDEX, 1);
 	mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
+
+	CRITEND
+
 #undef minfo
 }
 
@@ -4739,7 +4989,8 @@
 #define RS1056x344	12	/* 132 x 43 text */
 #define RS1056x400	13	/* 132 x 50 text */
 #define RS1056x480	14	/* 132 x 60 text */
-/* 0F-FF */
+#define RSNoxNo		2	/* FIXME! change it to 15 after modedb patch (2.3 only) */
+/* 10-FF */
 static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = {
 	{  640,  400,  48, 16, 39,  8,  96, 2, 70 },
 	{  640,  480,  48, 16, 33, 10,  96, 2, 60 },
@@ -4754,7 +5005,8 @@
 	{  640,  350,  48, 16, 39,  8,  96, 2, 70 },
 	{ 1056,  344,  96, 24, 59, 44, 160, 2, 70 },
 	{ 1056,  400,  96, 24, 39,  8, 160, 2, 70 },
-	{ 1056,  480,  96, 24, 36, 12, 160, 3, 60 }
+	{ 1056,  480,  96, 24, 36, 12, 160, 3, 60 },
+	{    0,    0,  ~0, ~0, ~0, ~0,   0, 0,  0 }
 };
 
 #define RSDepth(X)	(((X) >> 8) & 0x0F)
@@ -4775,13 +5027,14 @@
 	{ {  0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, {  0, 0, 0},  4 },
 	{ { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, {  0, 0, 0}, 24 },
 	{ {  0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, {  0, 0, 0},  0 },	/* textmode with (default) VGA8x16 */
-	{ {  0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, {  0, 0, 0},  0 }	/* textmode hardwired to VGA8x8 */
+	{ {  0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, {  0, 0, 0},  0 },	/* textmode hardwired to VGA8x8 */
 };
 
 #define RSCreate(X,Y)	((X) | ((Y) << 8))
 static struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = {
 /* default must be first */
 #ifdef FBCON_HAS_CFB8
+	{    ~0, RSCreate(RSNoxNo,     RS8bpp ) },
 	{ 0x101, RSCreate(RS640x480,   RS8bpp ) },
 	{ 0x100, RSCreate(RS640x400,   RS8bpp ) },
 	{ 0x180, RSCreate(RS768x576,   RS8bpp ) },
@@ -4793,14 +5046,8 @@
 	{ 0x198, RSCreate(RS1408x1056, RS8bpp ) },
 	{ 0x11C, RSCreate(RS1600x1200, RS8bpp ) },
 #endif
-#ifdef FBCON_HAS_CFB4
-	{ 0x010, RSCreate(RS640x350,   RS4bpp ) },
-	{ 0x012, RSCreate(RS640x480,   RS4bpp ) },
-	{ 0x102, RSCreate(RS800x600,   RS4bpp ) },
-	{ 0x104, RSCreate(RS1024x768,  RS4bpp ) },
-	{ 0x106, RSCreate(RS1280x1024, RS4bpp ) },
-#endif
 #ifdef FBCON_HAS_CFB16
+	{    ~0, RSCreate(RSNoxNo,     RS15bpp) },
 	{ 0x110, RSCreate(RS640x480,   RS15bpp) },
 	{ 0x181, RSCreate(RS768x576,   RS15bpp) },
 	{ 0x113, RSCreate(RS800x600,   RS15bpp) },
@@ -4821,6 +5068,7 @@
 	{ 0x11E, RSCreate(RS1600x1200, RS16bpp) },
 #endif
 #ifdef FBCON_HAS_CFB24
+	{    ~0, RSCreate(RSNoxNo,     RS24bpp) },
 	{ 0x1B2, RSCreate(RS640x480,   RS24bpp) },
 	{ 0x184, RSCreate(RS768x576,   RS24bpp) },
 	{ 0x1B5, RSCreate(RS800x600,   RS24bpp) },
@@ -4832,6 +5080,7 @@
 	{ 0x1BF, RSCreate(RS1600x1200, RS24bpp) },
 #endif
 #ifdef FBCON_HAS_CFB32
+	{    ~0, RSCreate(RSNoxNo,     RS32bpp) },
 	{ 0x112, RSCreate(RS640x480,   RS32bpp) },
 	{ 0x183, RSCreate(RS768x576,   RS32bpp) },
 	{ 0x115, RSCreate(RS800x600,   RS32bpp) },
@@ -4843,6 +5092,7 @@
 	{ 0x11F, RSCreate(RS1600x1200, RS32bpp) },
 #endif
 #ifdef FBCON_HAS_VGATEXT
+	{    ~0, RSCreate(RSNoxNo,     RSText)  },
 	{ 0x002, RSCreate(RS640x400,   RSText)  },	/* 80x25 */
 	{ 0x003, RSCreate(RS640x400,   RSText)  },	/* 80x25 */
 	{ 0x007, RSCreate(RS640x400,   RSText)  },	/* 80x25 */
@@ -4853,6 +5103,14 @@
 	{ 0x10B, RSCreate(RS1056x400,  RSText8) },	/* 132x50 */
 	{ 0x10C, RSCreate(RS1056x480,  RSText8) },	/* 132x60 */
 #endif
+#ifdef FBCON_HAS_CFB4
+	{    ~0, RSCreate(RSNoxNo,     RS4bpp ) },
+	{ 0x010, RSCreate(RS640x350,   RS4bpp ) },
+	{ 0x012, RSCreate(RS640x480,   RS4bpp ) },
+	{ 0x102, RSCreate(RS800x600,   RS4bpp ) },
+	{ 0x104, RSCreate(RS1024x768,  RS4bpp ) },
+	{ 0x106, RSCreate(RS1280x1024, RS4bpp ) },
+#endif
 	{     0, 0                                 }};
 
 /* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */
@@ -4871,19 +5129,21 @@
 static int hwcursor = 1;		/* "matrox:nohwcursor" */
 static int blink = 1;			/* "matrox:noblink" */
 static int sgram = 0;			/* "matrox:sgram" */
+#ifdef CONFIG_MTRR
 static int mtrr = 1;			/* "matrox:nomtrr" */
+#endif
 static int grayscale = 0;		/* "matrox:grayscale" */
 static unsigned int fastfont = 0;	/* "matrox:fastfont:xxxxx" */
 static int dev = -1;			/* "matrox:dev:xxxxx" */
-static unsigned int vesa = 0x101;	/* "matrox:vesa:xxxxx" */
+static unsigned int vesa = ~0;		/* "matrox:vesa:xxxxx" */
 static int depth = -1;			/* "matrox:depth:xxxxx" */
 static unsigned int xres = 0;		/* "matrox:xres:xxxxx" */
 static unsigned int yres = 0;		/* "matrox:yres:xxxxx" */
-static unsigned int upper = 0;		/* "matrox:upper:xxxxx" */
-static unsigned int lower = 0;		/* "matrox:lower:xxxxx" */
+static unsigned int upper = ~0;		/* "matrox:upper:xxxxx" */
+static unsigned int lower = ~0;		/* "matrox:lower:xxxxx" */
 static unsigned int vslen = 0;		/* "matrox:vslen:xxxxx" */
-static unsigned int left = 0;		/* "matrox:left:xxxxx" */
-static unsigned int right = 0;		/* "matrox:right:xxxxx" */
+static unsigned int left = ~0;		/* "matrox:left:xxxxx" */
+static unsigned int right = ~0;		/* "matrox:right:xxxxx" */
 static unsigned int hslen = 0;		/* "matrox:hslen:xxxxx" */
 static unsigned int pixclock = 0;	/* "matrox:pixclock:xxxxx" */
 static int sync = -1;			/* "matrox:sync:xxxxx" */
@@ -4891,6 +5151,7 @@
 static unsigned int fh = 0;		/* "matrox:fh:xxxxxk" */
 static unsigned int maxclk = 0;		/* "matrox:maxclk:xxxxM" */
 static char fontname[64];		/* "matrox:font:xxxxx" */
+static char videomode[64];		/* "matrox:mode:xxxxx" or "matrox:xxxxx" */
 
 #ifndef MODULE
 __initfunc(void matroxfb_setup(char *options, int *ints)) {
@@ -4954,6 +5215,31 @@
 			fv = simple_strtoul(this_opt+3, NULL, 0);
 		else if (!strncmp(this_opt, "mem:", 4)) 
 			mem = simple_strtoul(this_opt+4, NULL, 0);
+		else if (!strncmp(this_opt, "mode:", 5))
+			strcpy(videomode, this_opt+5);
+#ifdef CONFIG_FB_OF
+		else if (!strncmp(this_opt, "vmode:", 6)) {
+			unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
+            		if (vmode > 0 && vmode <= VMODE_MAX)
+				default_vmode = vmode;
+		} else if (!strncmp(this_opt, "cmode:", 6)) {
+			unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
+			switch (cmode) {
+				case 0:
+				case 8:
+					default_cmode = CMODE_8;
+					break;
+				case 15:
+				case 16:
+					default_cmode = CMODE_16;
+					break;
+				case 24:
+				case 32:
+					default_cmode = CMODE_32;
+					break;
+			}
+		}
+#endif
 		else if (!strncmp(this_opt, "fastfont:", 9))
 			fastfont = simple_strtoul(this_opt+9, NULL, 0);
 		else if (!strcmp(this_opt, "nofastfont"))	/* fastfont:N and nofastfont (nofastfont = fastfont:0) */
@@ -4987,8 +5273,10 @@
 				nobios = !value;
 			else if (!strcmp(this_opt, "init"))
 				noinit = !value;
+#ifdef CONFIG_MTRR
 			else if (!strcmp(this_opt, "mtrr"))
 				mtrr = value;
+#endif
 			else if (!strcmp(this_opt, "inv24"))
 				inv24 = value;
 			else if (!strcmp(this_opt, "cross4MB"))
@@ -5004,6 +5292,7 @@
 			}
 		}
 	}
+	return;
 }
 #endif
 
@@ -5012,7 +5301,7 @@
 	unsigned int offs;
 	unsigned int offs2;
 	unsigned char store;
-	unsigned char bytes[16];
+	unsigned char bytes[32];
 	unsigned char* tmp;
 	unsigned long cbase;
 	unsigned long mbase;
@@ -5025,7 +5314,7 @@
 	maxSize &= ~0x1FFFFF;	/* must be X*2MB (really it must be 2 or X*4MB) */
 	/* at least 2MB */
 	if (maxSize < 0x0200000) return 0;
-	if (maxSize > 0x1000000) maxSize = 0x1000000;
+	if (maxSize > 0x2000000) maxSize = 0x2000000;
 
 	mga_outb(M_EXTVGA_INDEX, 0x03);
 	mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80);
@@ -5163,20 +5452,28 @@
 
 struct video_board {
 	int maxvram;
+	int maxdisplayable;
 	int accelID;
 	struct matrox_switch* lowlevel;
 		 };
 #ifdef CONFIG_FB_MATROX_MILLENIUM
-static struct video_board vbMillenium __initdata	= {0x0800000,	FB_ACCEL_MATROX_MGA2064W,	&matrox_millenium};
-static struct video_board vbMillenium2 __initdata	= {0x1000000,	FB_ACCEL_MATROX_MGA2164W,	&matrox_millenium};
-static struct video_board vbMillenium2A __initdata	= {0x1000000,	FB_ACCEL_MATROX_MGA2164W_AGP,	&matrox_millenium};
+static struct video_board vbMillenium __initdata   = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA2064W,	  &matrox_millenium};
+static struct video_board vbMillenium2 __initdata  = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W,	  &matrox_millenium};
+static struct video_board vbMillenium2A __initdata = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W_AGP, &matrox_millenium};
 #endif	/* CONFIG_FB_MATROX_MILLENIUM */
 #ifdef CONFIG_FB_MATROX_MYSTIQUE
-static struct video_board vbMystique __initdata		= {0x0800000,	FB_ACCEL_MATROX_MGA1064SG,	&matrox_mystique};
+static struct video_board vbMystique __initdata    = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA1064SG,	  &matrox_mystique};
 #endif	/* CONFIG_FB_MATROX_MYSTIQUE */
 #ifdef CONFIG_FB_MATROX_G100
-static struct video_board vbG100 __initdata		= {0x0800000,	FB_ACCEL_MATROX_MGAG100,	&matrox_G100};
-static struct video_board vbG200 __initdata		= {0x1000000,	FB_ACCEL_MATROX_MGAG200,	&matrox_G100};
+static struct video_board vbG100 __initdata	   = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGAG100,	  &matrox_G100};
+static struct video_board vbG200 __initdata	   = {0x1000000, 0x1000000, FB_ACCEL_MATROX_MGAG200,	  &matrox_G100};
+#ifdef CONFIG_FB_MATROX_32MB
+/* from doc it looks like that accelerator can draw only to low 16MB :-( Direct accesses & displaying are OK for
+   whole 32MB */
+static struct video_board vbG400 __initdata	   = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400,	  &matrox_G100};
+#else
+static struct video_board vbG400 __initdata	   = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400,	  &matrox_G100};
+#endif
 #endif
 
 #define DEVF_VIDEO64BIT	0x01
@@ -5185,6 +5482,16 @@
 #define	DEVF_MILLENIUM2	0x08
 #define DEVF_CROSS4MB	0x10
 #define DEVF_TEXT4B	0x20
+#define DEVF_DDC_8_2	0x40
+#define DEVF_DMA	0x80
+#define DEVF_SUPPORT32MB	0x100
+#define DEVF_ANY_VXRES		0x200
+#define DEVF_TEXT16B		0x400
+
+#define DEVF_G100	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2) /* no doc, no vxres... */
+#define DEVF_G200	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2 | DEVF_ANY_VXRES)
+#define DEVF_G400	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2 | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B)
+
 static struct board {
 	unsigned short vendor, device, rev, svid, sid;
 	unsigned int flags;
@@ -5229,88 +5536,94 @@
 #ifdef CONFIG_FB_MATROX_G100
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MGA_G100_PCI,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"MGA-G100 (PCI)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100,	0xFF,
 		0,			0,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"unknown G100 (PCI)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_GENERIC,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"MGA-G100 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MGA_G100_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"MGA-G100 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_SIEMENS_NIXDORF,	PCI_SS_ID_SIEMENS_MGA_G100_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"MGA-G100 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"Productiva G100 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
 		0,			0,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"unknown G100 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_PCI,	0xFF,
 		0,			0,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		250000,
 		&vbG200,
 		"unknown G200 (PCI)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_GENERIC,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		220000,
 		&vbG200,
 		"MGA-G200 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		230000,
 		&vbG200,
 		"Mystique G200 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MILLENIUM_G200_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		250000,
 		&vbG200,
 		"Millennium G200 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MARVEL_G200_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		230000,
 		&vbG200,
 		"Marvel G200 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_SIEMENS_NIXDORF,	PCI_SS_ID_SIEMENS_MGA_G200_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		230000,
 		&vbG200,
 		"MGA-G200 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		0,			0,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		230000,
 		&vbG200,
 		"unknown G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G400_AGP,	0xFF,
+		0,			0,
+		DEVF_G400,
+		360000,
+		&vbG400,
+		"unknown G400 (AGP)"},
 #endif
 	{0,			0,				0xFF,
 		0,			0,
@@ -5340,14 +5653,20 @@
 	if (b->flags & DEVF_TEXT4B) {
 		ACCESS_FBINFO(devflags.vgastep) = 4;
 		ACCESS_FBINFO(devflags.textmode) = 4;
-		ACCESS_FBINFO(devflags.vgastepdisp) = 16;
+		ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16;
+	} else if (b->flags & DEVF_TEXT16B) {
+		ACCESS_FBINFO(devflags.vgastep) = 16;
+		ACCESS_FBINFO(devflags.textmode) = 1;
 		ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16;
 	} else {
 		ACCESS_FBINFO(devflags.vgastep) = 8;
 		ACCESS_FBINFO(devflags.textmode) = 1;
-		ACCESS_FBINFO(devflags.vgastepdisp) = 64;
 		ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8;
 	}
+#ifdef CONFIG_FB_MATROX_32MB
+	ACCESS_FBINFO(devflags.support32MB) = b->flags & DEVF_SUPPORT32MB;
+#endif
+	ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES);
 	ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode);
 	ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
 
@@ -5472,8 +5791,8 @@
 		return -ENOMEM;
 	}
 	ACCESS_FBINFO(video.len_usable) = ACCESS_FBINFO(video.len);
-	if (ACCESS_FBINFO(video.len_usable) > 0x08000000)
-		ACCESS_FBINFO(video.len_usable) = 0x08000000;
+	if (ACCESS_FBINFO(video.len_usable) > b->base->maxdisplayable)
+		ACCESS_FBINFO(video.len_usable) = b->base->maxdisplayable;
 #ifdef CONFIG_MTRR
 	if (mtrr) {
 		ACCESS_FBINFO(mtrr.vram) = mtrr_add(video_base_phys, ACCESS_FBINFO(video.len), MTRR_TYPE_WRCOMB, 1);
@@ -5482,11 +5801,16 @@
 	}
 #endif	/* CONFIG_MTRR */
 
+	if (!ACCESS_FBINFO(devflags.novga))
+		request_region(0x3C0, 32, "matrox");
+	ACCESS_FBINFO(hw_switch->reset(PMINFO hw));
+
 /* validate params, autodetect k, M */
 	if (fh < 1000) fh *= 1000;	/* 1kHz minimum */
 	if (maxclk < 1000) maxclk *= 1000;	/* kHz -> Hz, MHz -> kHz */
 	if (maxclk < 1000000) maxclk *= 1000;	/* kHz -> Hz, 1MHz minimum */
-	vesa &= 0x1DFF;		/* mask out clearscreen, acceleration and so on */
+	if (vesa != ~0)
+		vesa &= 0x1DFF;		/* mask out clearscreen, acceleration and so on */
 
 	ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
 	ACCESS_FBINFO(fbcon.monspecs.hfmax) = fh;
@@ -5504,19 +5828,19 @@
 	}
 	{
 		int res = RSResolution(RSptr->info)-1;
-		if (!left)
+		if (left == ~0)
 			left = timmings[res].left;
 		if (!xres)
 			xres = timmings[res].xres;
-		if (!right)
+		if (right == ~0)
 			right = timmings[res].right;
 		if (!hslen)
 			hslen = timmings[res].hslen;
-		if (!upper)
+		if (upper == ~0)
 			upper = timmings[res].upper;
 		if (!yres)
 			yres = timmings[res].yres;
-		if (!lower)
+		if (lower == ~0)
 			lower = timmings[res].lower;
 		if (!vslen)
 			vslen = timmings[res].vslen;
@@ -5525,38 +5849,6 @@
 		if (depth == -1)
 			depth = RSDepth(RSptr->info);
 	}
-	if (sync == -1) {
-		sync = 0;
-		if (yres < 400)
-			sync |= FB_SYNC_HOR_HIGH_ACT;
-		else if (yres < 480)
-			sync |= FB_SYNC_VERT_HIGH_ACT;
-	}
-	if (xres < 320)
-		xres = 320;
-	if (xres > 2048)
-		xres = 2048;
-	if (yres < 200)
-		yres = 200;
-	if (yres > 2048)
-		yres = 2048;
-	{
-		unsigned int tmp;
-
-		if (fv) {
-			tmp = fv * (upper + yres + lower + vslen);
-			if ((tmp < fh) || (fh == 0)) fh = tmp;
-		}
-		if (fh) {
-			tmp = fh * (left + xres + right + hslen);
-			if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
-		}
-		maxclk = (maxclk + 499) / 500;
-		if (maxclk) {
-			tmp = (2000000000 + maxclk) / maxclk;
-			if (tmp > pixclock) pixclock = tmp;
-		}
-	}
 	if ((depth == RSText8) && (!*ACCESS_FBINFO(fbcon.fontname))) {
 		strcpy(ACCESS_FBINFO(fbcon.fontname), "VGA8x8");
 	}
@@ -5564,27 +5856,9 @@
 	vesafb_defined.green = colors[depth-1].green;
 	vesafb_defined.blue = colors[depth-1].blue;
 	vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel;
-	if (pixclock < 2000)		/* > 500MHz */
-		pixclock = 4000;	/* 250MHz */
-	if (pixclock > 1000000)
-		pixclock = 1000000;	/* 1MHz */
-	vesafb_defined.xres = xres;
-	vesafb_defined.yres = yres;
-	vesafb_defined.xoffset = 0;
-	vesafb_defined.yoffset = 0;
 	vesafb_defined.grayscale = grayscale;
-	vesafb_defined.pixclock = pixclock;
-	vesafb_defined.left_margin = left;
-	vesafb_defined.right_margin = right;
-	vesafb_defined.hsync_len = hslen;
-	vesafb_defined.upper_margin = upper;
-	vesafb_defined.lower_margin = lower;
-	vesafb_defined.vsync_len = vslen;
-	vesafb_defined.sync = sync;
 	vesafb_defined.vmode = 0;
-
-	if (!ACCESS_FBINFO(devflags.novga))
-		request_region(0x3C0, 32, "matrox");
+	vesafb_defined.sync = -1;
 	if (noaccel)
 		vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT;
 
@@ -5597,8 +5871,67 @@
 	ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar;
 	ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank;
 	ACCESS_FBINFO(fbcon.flags) = FBINFO_FLAG_DEFAULT;
-	ACCESS_FBINFO(hw_switch->reset(PMINFO hw));
 	ACCESS_FBINFO(video.len_usable) &= PAGE_MASK;
+
+#if 0
+	fb_find_mode(&vesafb_defined, &ACCESS_FBINFO(fbcon), videomode[0]?videomode:NULL,
+		NULL, 0, NULL, vesafb_defined.bits_per_pixel);
+#endif
+	/* mode modifiers */
+	if (hslen)
+		vesafb_defined.hsync_len = hslen;
+	if (vslen)
+		vesafb_defined.vsync_len = vslen;
+	if (left != ~0)
+		vesafb_defined.left_margin = left;
+	if (right != ~0)
+		vesafb_defined.right_margin = right;
+	if (upper != ~0)
+		vesafb_defined.upper_margin = upper;
+	if (lower != ~0)
+		vesafb_defined.lower_margin = lower;
+	if (xres)
+		vesafb_defined.xres = xres;
+	if (yres)
+		vesafb_defined.yres = yres;
+	if (sync != -1)
+		vesafb_defined.sync = sync;
+	else if (vesafb_defined.sync == -1) {
+		vesafb_defined.sync = 0;
+		if (vesafb_defined.yres < 400)
+			vesafb_defined.sync |= FB_SYNC_HOR_HIGH_ACT;
+		else if (vesafb_defined.yres < 480)
+			vesafb_defined.sync |= FB_SYNC_VERT_HIGH_ACT;
+	}
+	/* fv, fh, maxclk limits was specified */
+	{
+		unsigned int tmp;
+
+		if (fv) {
+			tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres 
+			          + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
+			if ((tmp < fh) || (fh == 0)) fh = tmp;
+		}
+		if (fh) {
+			tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres 
+			          + vesafb_defined.right_margin + vesafb_defined.hsync_len);
+			if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
+		}
+		maxclk = (maxclk + 499) / 500;
+		if (maxclk) {
+			tmp = (2000000000 + maxclk) / maxclk;
+			if (tmp > pixclock) pixclock = tmp;
+		}
+	}
+	if (pixclock) {
+		if (pixclock < 2000)		/* > 500MHz */
+			pixclock = 4000;	/* 250MHz */
+		if (pixclock > 1000000)
+			pixclock = 1000000;	/* 1MHz */
+		vesafb_defined.pixclock = pixclock;
+	}
+		
+	/* FIXME: Where to move this?! */
 #if defined(CONFIG_FB_OF)
 #if defined(CONFIG_FB_COMPAT_XPMAC)
 	strcpy(ACCESS_FBINFO(matrox_name), "MTRX,");	/* OpenFirmware naming convension */
@@ -5608,30 +5941,30 @@
 #endif
 	if ((xres <= 640) && (yres <= 480)) {
 		struct fb_var_screeninfo var;
-		int default_vmode = nvram_read_byte(NV_VMODE);
-		int default_cmode = nvram_read_byte(NV_CMODE);
-
-		if ((default_vmode <= 0) || (default_vmode > VMODE_MAX))
+		if (default_vmode == VMODE_NVRAM) {
+			default_vmode = nvram_read_byte(NV_VMODE);
+			if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+				default_vmode = VMODE_CHOOSE;
+		}
+		if (default_vmode <= 0 || default_vmode > VMODE_MAX)
 			default_vmode = VMODE_640_480_60;
-		if ((default_cmode < CMODE_8) || (default_cmode > CMODE_32))
+		if (default_cmode == CMODE_NVRAM)
+			default_cmode = nvram_read_byte(NV_CMODE);
+		if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
 			default_cmode = CMODE_8;
 		if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) {
 			var.accel_flags = vesafb_defined.accel_flags;
 			var.xoffset = var.yoffset = 0;
 			vesafb_defined = var; /* Note: mac_vmode_to_var() doesnot set all parameters */
-		}
+              }
 	}
 #endif
-	{
-		int pixel_size = vesafb_defined.bits_per_pixel;
-
-		vesafb_defined.xres_virtual = matroxfb_pitch_adjust(PMINFO vesafb_defined.xres, pixel_size);
-		if (nopan) {
-			vesafb_defined.yres_virtual = vesafb_defined.yres;
-		} else {
-			vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough
-			                                        to yres_virtual * xres_virtual < 2^32 */
-		}
+	vesafb_defined.xres_virtual = vesafb_defined.xres;
+	if (nopan) {
+		vesafb_defined.yres_virtual = vesafb_defined.yres;
+	} else {
+		vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough
+		                                        to yres_virtual * xres_virtual < 2^32 */
 	}
 	if (matroxfb_set_var(&vesafb_defined, -2, &ACCESS_FBINFO(fbcon))) {
 		printk(KERN_ERR "matroxfb: cannot set required parameters\n");
@@ -5647,8 +5980,9 @@
 /* We do not have to set currcon to 0... register_framebuffer do it for us on first console
  * and we do not want currcon == 0 for subsequent framebuffers */
 
-	if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0)
+	if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0) {
 		return -EINVAL;
+	}
 	printk("fb%d: %s frame buffer device\n",
 	       GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), ACCESS_FBINFO(fbcon.modename));
 	if (ACCESS_FBINFO(currcon) < 0) {
@@ -5781,8 +6115,8 @@
 
 #else
 
-MODULE_AUTHOR("(c) 1998 Petr Vandrovec <vandrove@vc.cvut.cz>");
-MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200");
+MODULE_AUTHOR("(c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400");
 MODULE_PARM(mem, "i");
 MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)");
 MODULE_PARM(disabled, "i");
@@ -5802,7 +6136,7 @@
 MODULE_PARM(mtrr, "i");
 MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)");
 MODULE_PARM(sgram, "i");
-MODULE_PARM_DESC(sgram, "Indicates that G200 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
+MODULE_PARM_DESC(sgram, "Indicates that G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
 MODULE_PARM(inv24, "i");
 MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)");
 MODULE_PARM(inverse, "i");
@@ -5855,6 +6189,12 @@
 MODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)");
 MODULE_PARM(cross4MB, "i");
 MODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. (default=autodetected)");
+#ifdef CONFIG_FB_OF
+MODULE_PARM(vmode, "i");
+MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)");
+MODULE_PARM(cmode, "i");
+MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit default)");
+#endif
 
 __initfunc(int init_module(void)) {
 
@@ -5862,7 +6202,7 @@
 
 #ifdef DEBUG
 	if( disabled )
-		return 0;
+		return -ENXIO;
 #endif /* DEBUG */
 
 	if (depth == 0)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/pm2fb.c linux.14p16/drivers/video/pm2fb.c
--- linux.vanilla/drivers/video/pm2fb.c	Tue Mar 16 00:11:31 1999
+++ linux.14p16/drivers/video/pm2fb.c	Thu Dec  9 15:34:14 1999
@@ -1,6 +1,7 @@
 /*
  * Permedia2 framebuffer driver.
  * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
+ * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com)
  * Based on linux/drivers/video/skeletonfb.c by Geert Uytterhoeven.
  * --------------------------------------------------------------------------
  * $Id: pm2fb.c,v 1.163 1999/02/21 14:06:49 illo Exp $
@@ -38,17 +39,28 @@
 #include <video/fbcon-cfb32.h>
 #include "pm2fb.h"
 #include "cvisionppc.h"
+#ifdef __sparc__
+#include <asm/pbm.h>
+#include <asm/fbio.h>
+#endif
 
 #if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
 #error	"The endianness of the target host has not been defined."
 #endif
 
+#if defined(__BIG_ENDIAN) && !defined(__sparc__)
+#define PM2FB_BE_APERTURE
+#endif
+
+/* Need to debug this some more */
+#undef PM2FB_HW_CURSOR
+
 #if defined(CONFIG_FB_PM2_PCI) && !defined(CONFIG_PCI)
 #undef CONFIG_FB_PM2_PCI
 #warning "support for Permedia2 PCI boards with no generic PCI support!"
 #endif
 
-#define PM2FB_MASTER_DEBUG
+#undef PM2FB_MASTER_DEBUG
 #ifdef PM2FB_MASTER_DEBUG
 #define DPRINTK(a,b...)	printk("pm2fb: %s: " a, __FUNCTION__ , ## b)
 #else
@@ -102,12 +114,20 @@
 #define OPTF_OLD_MEM		(1L<<0)
 #define OPTF_YPAN		(1L<<1)
 #define OPTF_VIRTUAL		(1L<<2)
+#define OPTF_USER		(1L<<3)
 static struct {
 	char font[40];
 	u32 flags;
 	struct pm2fb_par user_mode;
 } pm2fb_options =
+#ifdef __sparc__
+	/* For some reason Raptor is not happy with the low-end mode */
+	{"\0", 0L, {31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121}};
+#else
 	{"\0", 0L, {25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121}};
+#endif
+
+static char curblink __initdata = 1;
 
 static const struct {
 	char name[16];
@@ -185,12 +205,30 @@
 };
 #endif
 
+#define DEFAULT_CURSOR_BLINK_RATE       (20)
+#define CURSOR_DRAW_DELAY               (2)
+
+struct pm2_cursor {
+    int	enable;
+    int on;
+    int vbl_cnt;
+    int blink_rate;
+    struct {
+        u16 x, y;
+    } pos, hot, size;
+    u8 color[6];
+    u8 bits[8][64];
+    u8 mask[8][64];
+    struct timer_list *timer;
+};
+
 static const char permedia2_name[16]="Permedia2";
 
 static struct pm2fb_info {
 	struct fb_info_gen gen;
 	int board;			/* Permedia2 board index (see
 					   board_table[] below) */
+	pm2type_t type;
 	struct {
 		unsigned char* fb_base;	/* framebuffer memory base */
 		u32 fb_size;		/* framebuffer memory size */
@@ -233,6 +271,7 @@
 		u32 cmap32[16];
 #endif
 	} cmap;
+	struct pm2_cursor *cursor;
 } fb_info;
 
 #ifdef CONFIG_FB_PM2_CVPPC
@@ -245,6 +284,18 @@
 static void pm2pci_init(struct pm2fb_info*);
 #endif
 
+#ifdef PM2FB_HW_CURSOR
+static void pm2fb_cursor(struct display *p, int mode, int x, int y);
+static int pm2fb_set_font(struct display *d, int width, int height);
+static struct pm2_cursor *pm2_init_cursor(struct pm2fb_info *fb);
+static void pm2v_set_cursor_color(struct pm2fb_info *fb, u8 *red, u8 *green, u8 *blue);
+static void pm2v_set_cursor_shape(struct pm2fb_info *fb);
+static u8 cursor_color_map[2] = { 0, 0xff };
+#else
+#define pm2fb_cursor NULL
+#define pm2fb_set_font NULL
+#endif
+
 /*
  * Table of the supported Permedia2 based boards.
  * Three hooks are defined for each board:
@@ -334,7 +385,7 @@
 static struct fb_ops pm2fb_ops={
 	pm2fb_open, pm2fb_release, fbgen_get_fix, fbgen_get_var,
 	fbgen_set_var, fbgen_get_cmap, fbgen_set_cmap, fbgen_pan_display,
-	NULL /* fb_ioctl() */, NULL /* fb_mmap() */
+	NULL /* fb_ioctl() */, NULL /* fb_mmap() */, NULL /* fb_rasterimg */,
 };
 
 /***************************************************************************
@@ -363,17 +414,50 @@
 
 inline static u32 pm2_RDAC_RD(struct pm2fb_info* p, s32 idx) {
 
-	pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
+	int index = PM2R_RD_INDEXED_DATA;
+	switch (p->type) {
+	case PM2_TYPE_PERMEDIA2:
+		pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
+		break;
+	case PM2_TYPE_PERMEDIA2V:
+		pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
+		index = PM2VR_RD_INDEXED_DATA;
+		break;
+	}	
 	DEFRW();
-	return pm2_RD(p, PM2R_RD_INDEXED_DATA);
+	return pm2_RD(p, index);
 }
 
 inline static void pm2_RDAC_WR(struct pm2fb_info* p, s32 idx,
 						u32 v) {
 
-	pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
-	DEFW();
-	pm2_WR(p, PM2R_RD_INDEXED_DATA, v);
+	int index = PM2R_RD_INDEXED_DATA;
+	switch (p->type) {
+	case PM2_TYPE_PERMEDIA2:
+		pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
+		break;
+	case PM2_TYPE_PERMEDIA2V:
+		pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
+		index = PM2VR_RD_INDEXED_DATA;
+		break;
+	}	
+	DEFRW();
+	pm2_WR(p, index, v);
+}
+
+inline static u32 pm2v_RDAC_RD(struct pm2fb_info* p, s32 idx) {
+
+	pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
+	DEFRW();
+	return pm2_RD(p, PM2VR_RD_INDEXED_DATA);
+}
+
+inline static void pm2v_RDAC_WR(struct pm2fb_info* p, s32 idx,
+						u32 v) {
+
+	pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
+	DEFRW();
+	pm2_WR(p, PM2VR_RD_INDEXED_DATA, v);
 }
 
 #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
@@ -435,8 +519,8 @@
 	return timing;
 }
 
-static void mnp(u32 clk, unsigned char* mm, unsigned char* nn,
-							unsigned char* pp) {
+static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
+		unsigned char* pp) {
 	unsigned char m;
 	unsigned char n;
 	unsigned char p;
@@ -463,6 +547,30 @@
 	}
 }
 
+static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
+		unsigned char* pp) {
+	unsigned char m;
+	unsigned char n;
+	unsigned char p;
+	u32 f;
+	s32 delta=1000;
+
+	*mm=*nn=*pp=0;
+	for (n=1; n; n++) {
+		for (m=1; m; m++) {
+			for (p=0; p<2; p++) {
+				f=PM2_REFERENCE_CLOCK*n/(m * (1<<(p+1)));
+				if (clk>f-delta && clk<f+delta) {
+					delta=clk>f?clk-f:f-clk;
+					*mm=m;
+					*nn=n;
+					*pp=p;
+				}
+			}
+		}
+	}
+}
+
 static void wait_pm2(struct pm2fb_info* i) {
 
 	WAIT_FIFO(i, 1);
@@ -474,12 +582,12 @@
 	} while (pm2_RD(i, PM2R_OUT_FIFO)!=PM2TAG(PM2R_SYNC));
 }
 
-static void set_memclock(struct pm2fb_info* info, u32 clk) {
+static void pm2_set_memclock(struct pm2fb_info* info, u32 clk) {
 	int i;
 	unsigned char m, n, p;
 
-	mnp(clk, &m, &n, &p);
-	WAIT_FIFO(info, 5);
+	pm2_mnp(clk, &m, &n, &p);
+	WAIT_FIFO(info, 10);
 	pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_3, 6);
 	DEFW();
 	pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_1, m);
@@ -493,23 +601,36 @@
 		!(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--);
 }
 
-static void set_pixclock(struct pm2fb_info* info, u32 clk) {
+static void pm2_set_pixclock(struct pm2fb_info* info, u32 clk) {
 	int i;
 	unsigned char m, n, p;
 
-	mnp(clk, &m, &n, &p);
-	WAIT_FIFO(info, 5);
-	pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 0);
-	DEFW();
-	pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A1, m);
-	pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A2, n);
-	DEFW();
-	pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 8|p);
-	DEFW();
-	pm2_RDAC_RD(info, PM2I_RD_PIXEL_CLOCK_STATUS);
-	DEFR();
-	for (i=256; i &&
-		!(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--);
+	switch (info->type) {
+	case PM2_TYPE_PERMEDIA2:
+		pm2_mnp(clk, &m, &n, &p);
+		WAIT_FIFO(info, 10);
+		pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 0);
+		DEFW();
+		pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A1, m);
+		pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A2, n);
+		DEFW();
+		pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 8|p);
+		DEFW();
+		pm2_RDAC_RD(info, PM2I_RD_PIXEL_CLOCK_STATUS);
+		DEFR();
+		for (i=256; i &&
+		     !(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--);
+		break;
+	case PM2_TYPE_PERMEDIA2V:
+		pm2v_mnp(clk/2, &m, &n, &p);
+		WAIT_FIFO(info, 8);
+		pm2_WR(info, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CLK0_PRESCALE >> 8);
+		pm2v_RDAC_WR(info, PM2VI_RD_CLK0_PRESCALE, m);
+		pm2v_RDAC_WR(info, PM2VI_RD_CLK0_FEEDBACK, n);
+		pm2v_RDAC_WR(info, PM2VI_RD_CLK0_POSTSCALE, p);
+		pm2_WR(info, PM2VR_RD_INDEX_HIGH, 0);
+		break;
+	}
 }
 
 static void clear_palette(struct pm2fb_info* p) {
@@ -543,7 +664,7 @@
 
 	WAIT_FIFO(i, 2);
 #ifdef __LITTLE_ENDIAN
-	pm2_WR(i, PM2R_APERTURE_ONE, 0);	/* FIXME */
+	pm2_WR(i, PM2R_APERTURE_ONE, 0);
 	pm2_WR(i, PM2R_APERTURE_TWO, 0);
 #else
 	switch (p->depth) {
@@ -567,32 +688,46 @@
 static void set_screen(struct pm2fb_info* i, struct pm2fb_par* p) {
 	u32 clrmode=0;
 	u32 txtmap=0;
+	u32 pixsize=0;
+	u32 clrformat=0;
 	u32 xres;
+	u32 video, tmp;
 
+	if (i->type == PM2_TYPE_PERMEDIA2V) {
+		WAIT_FIFO(i, 1);
+		pm2_WR(i, PM2VR_RD_INDEX_HIGH, 0);
+	}
 	xres=(p->width+31)&~31;
 	set_aperture(i, p);
 	DEFRW();
-	WAIT_FIFO(i, 22);
+	WAIT_FIFO(i, 27);
 	pm2_RDAC_WR(i, PM2I_RD_COLOR_KEY_CONTROL, p->depth==8?0:
 						PM2F_COLOR_KEY_TEST_OFF);
 	switch (p->depth) {
 		case 8:
 			pm2_WR(i, PM2R_FB_READ_PIXEL, 0);
+			clrformat=0x0e;
 			break;
 		case 16:
 			pm2_WR(i, PM2R_FB_READ_PIXEL, 1);
 			clrmode=PM2F_RD_TRUECOLOR|0x06;
 			txtmap=PM2F_TEXTEL_SIZE_16;
+			pixsize=1;
+			clrformat=0x70;
 			break;
 		case 32:
 			pm2_WR(i, PM2R_FB_READ_PIXEL, 2);
 			clrmode=PM2F_RD_TRUECOLOR|0x08;
 			txtmap=PM2F_TEXTEL_SIZE_32;
+			pixsize=2;
+			clrformat=0x20;
 			break;
 		case 24:
 			pm2_WR(i, PM2R_FB_READ_PIXEL, 4);
 			clrmode=PM2F_RD_TRUECOLOR|0x09;
 			txtmap=PM2F_TEXTEL_SIZE_24;
+			pixsize=4;
+			clrformat=0x20;
 			break;
 	}
 	pm2_WR(i, PM2R_SCREEN_SIZE, (p->height<<16)|p->width);
@@ -613,10 +748,34 @@
 	pm2_WR(i, PM2R_SCREEN_STRIDE, p->stride);
 	DEFW();
 	pm2_WR(i, PM2R_SCREEN_BASE, p->base);
-	pm2_RDAC_WR(i, PM2I_RD_COLOR_MODE, PM2F_RD_COLOR_MODE_RGB|
-						PM2F_RD_GUI_ACTIVE|clrmode);
-	pm2_WR(i, PM2R_VIDEO_CONTROL, p->video);
-	set_pixclock(i, p->pixclock);
+	/* HW cursor needs /VSYNC for recognizing vert retrace */
+	video=p->video & ~(PM2F_HSYNC_ACT_LOW|PM2F_VSYNC_ACT_LOW);
+	video|=PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH;
+	switch (i->type) {
+	case PM2_TYPE_PERMEDIA2:
+		tmp = PM2F_RD_PALETTE_WIDTH_8;
+		pm2_RDAC_WR(i, PM2I_RD_COLOR_MODE, PM2F_RD_COLOR_MODE_RGB|
+						   PM2F_RD_GUI_ACTIVE|clrmode);
+		if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
+			tmp |= 4; /* invert hsync */
+		if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
+			tmp |= 8; /* invert vsync */
+		pm2_RDAC_WR(i, PM2I_RD_MISC_CONTROL, tmp);
+		break;
+	case PM2_TYPE_PERMEDIA2V:
+		tmp = 0;
+		pm2v_RDAC_WR(i, PM2VI_RD_PIXEL_SIZE, pixsize);
+		pm2v_RDAC_WR(i, PM2VI_RD_COLOR_FORMAT, clrformat);
+		if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
+			tmp |= 1; /* invert hsync */
+		if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
+			tmp |= 4; /* invert vsync */
+		pm2v_RDAC_WR(i, PM2VI_RD_SYNC_CONTROL, tmp);
+		pm2v_RDAC_WR(i, PM2VI_RD_MISC_CONTROL, 1);
+		break;
+	}
+	pm2_WR(i, PM2R_VIDEO_CONTROL, video);
+	pm2_set_pixclock(i, p->pixclock);
 };
 
 /*
@@ -682,6 +841,8 @@
 
 static void pm2fb_reset(struct pm2fb_info* p) {
 
+	if (p->type == PM2_TYPE_PERMEDIA2V)
+		pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
 	pm2_WR(p, PM2R_RESET_STATUS, 0);
 	DEFRW();
 	while (pm2_RD(p, PM2R_RESET_STATUS)&PM2F_BEING_RESET);
@@ -729,8 +890,16 @@
 	pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0);
 	pm2_WR(p, PM2R_STATISTICS_MODE, 0);
 	pm2_WR(p, PM2R_SCISSOR_MODE, 0);
-	pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0);
-	pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8);
+	switch (p->type) {
+	case PM2_TYPE_PERMEDIA2:
+		pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */
+		pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0);
+		pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8);
+		break;
+	case PM2_TYPE_PERMEDIA2V:
+		pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */
+		break;
+	}
 	pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0);
 	pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0);
 	pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
@@ -738,7 +907,7 @@
 	pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
 	clear_palette(p);
 	if (p->memclock)
-		set_memclock(p, p->memclock);
+		pm2_set_memclock(p, p->memclock);
 }
 
 __initfunc(static int pm2fb_conf(struct pm2fb_info* p)) {
@@ -752,12 +921,16 @@
 	DPRINTK("found board: %s\n", board_table[p->board].name);
 	p->regions.p_fb=p->regions.fb_base;
 	p->regions.v_fb=MMAP(p->regions.p_fb, p->regions.fb_size);
-#ifdef __LITTLE_ENDIAN
+#ifndef PM2FB_BE_APERTURE
 	p->regions.p_regs=p->regions.rg_base;
 #else
 	p->regions.p_regs=p->regions.rg_base+PM2_REGS_SIZE;
 #endif
 	p->regions.v_regs=MMAP(p->regions.p_regs, PM2_REGS_SIZE);
+
+#ifdef PM2FB_HW_CURSOR
+	p->cursor = pm2_init_cursor(p);
+#endif
 	return 1;
 }
 
@@ -805,10 +978,11 @@
 	return 1;
 }
 
-static int cvppc_detect(struct pm2fb_info* p) {
+static int __init cvppc_detect(struct pm2fb_info* p) {
 
 	if (!cvppc_PCI_init(&p->board_par.cvppc))
 		return 0;
+	p->type = PM2_TYPE_PERMEDIA2;
 	p->regions.fb_base=(unsigned char* )CVPPC_FB_APERTURE_ONE;
 	p->regions.fb_size=CVPPC_FB_SIZE;
 	p->regions.rg_base=(unsigned char* )CVPPC_REGS_REGION;
@@ -833,9 +1007,25 @@
  * Generic PCI detection routines
  */
 #ifdef CONFIG_FB_PM2_PCI
-static int pm2pci_detect(struct pm2fb_info* p) {
+struct {
+	unsigned short vendor, device;
+	char *name;
+	pm2type_t type;
+} pm2pci_cards[] __initdata = {
+{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, "Texas Instruments TVP4020", PM2_TYPE_PERMEDIA2 },
+{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, "3dLabs Permedia 2", PM2_TYPE_PERMEDIA2 },
+{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, "3dLabs Permedia 2v", PM2_TYPE_PERMEDIA2V },
+{ 0, 0 }
+};
+
+static int __init pm2pci_detect(struct pm2fb_info* p) {
 	struct pm2pci_par* pci=&p->board_par.pci;
+	struct pci_dev* dev;
+	int i;
 	unsigned char* m;
+#ifdef __sparc__
+	struct pcidev_cookie *pcp;
+#endif
 
 	memset(pci, 0, sizeof(struct pm2pci_par));
 	if (!pci_present()) {
@@ -843,9 +1033,16 @@
 		return 0;
 	}
 	DPRINTK("scanning PCI bus for known chipsets...\n");
-	if ((pci->dev=pci_find_device(PCI_VENDOR_ID_TI,
-					PCI_DEVICE_ID_TI_TVP4020, NULL))) {
-		DPRINTK("... found Texas Instruments TVP4020\n");
+
+	for (dev = pci_devices; !pci->dev && dev; dev = dev->next) {
+		for (i = 0; pm2pci_cards[i].vendor; i++)
+			if (pm2pci_cards[i].vendor == dev->vendor &&
+			    pm2pci_cards[i].device == dev->device) {
+				pci->dev = dev;
+				p->type = pm2pci_cards[i].type;
+				DPRINTK("... found %s\n", pm2pci_cards[i].name);
+				break;
+			}
 	}
 	if (!pci->dev) {
 		DPRINTK("no PCI board found.\n");
@@ -861,6 +1058,41 @@
 		__pa(pci->dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK);
 	p->regions.fb_base=(unsigned char* )
 		__pa(pci->dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK);
+	pcp = pci->dev->sysdata;
+	/* If the user has not asked for a particular mode, lets guess */
+	if (pcp->prom_node && !(pm2fb_options.flags & OPTF_USER)) {
+		char timing[256], *q, *r;
+		unsigned long w, h;
+		int i;
+		prom_getstring(pcp->prom_node, "timing-numbers", timing, 256);
+		/* FIXME: Find out what the actual pixclock is and other values as well */
+		if (timing[0]) {
+			w = simple_strtoul(timing, &q, 0);
+			h = 0;
+			if (q == timing) w = 0;
+			if (w) {
+				for (i = 0; i < 3; i++) {
+					for (r = q; *r && (*r < '0' || *r > '9'); r++);
+					simple_strtoul(r, &q, 0);
+					if (r == q) break;
+				}
+				if (i < 3) w = 0;
+			}
+			if (w) {
+				for (r = q; *r && (*r < '0' || *r > '9'); r++);
+				h = simple_strtoul(r, &q, 0);
+				if (r == q) w = 0;
+			}
+			if (w == 640 && h == 480) w = 0;
+			if (w) {
+				for (i=0; user_mode[i].name[0] &&
+					  (w != user_mode[i].par.width ||
+					   h != user_mode[i].par.height); i++);
+				if (user_mode[i].name[0])
+					memcpy(&p->current_par, &user_mode[i].par, sizeof(user_mode[i].par));
+			}
+		}
+	}
 #else
 	if (pm2fb_options.flags & OPTF_VIRTUAL) {
 		p->regions.rg_base=(unsigned char* )
@@ -875,7 +1107,7 @@
 			(pci->dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK);
 	}
 #endif
-#ifdef __BIG_ENDIAN
+#ifdef PM2FB_BE_APERTURE
 	p->regions.rg_base += PM2_REGS_SIZE;
 #endif
 	if ((m=MMAP(p->regions.rg_base, PM2_REGS_SIZE))) {
@@ -1042,7 +1274,7 @@
 static struct display_switch pm2_cfb8 = {
 	fbcon_cfb8_setup, pm2fb_pp_bmove, pm2fb_clear8,
 	fbcon_cfb8_putc, fbcon_cfb8_putcs, fbcon_cfb8_revc,
-	NULL /* cursor() */, NULL /* set_font() */,
+	pm2fb_cursor, pm2fb_set_font,
 	pm2fb_clear_margins8,
 	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) };
 #endif /* FBCON_HAS_CFB8 */
@@ -1082,7 +1314,7 @@
 static struct display_switch pm2_cfb16 = {
 	fbcon_cfb16_setup, pm2fb_pp_bmove, pm2fb_clear16,
 	fbcon_cfb16_putc, fbcon_cfb16_putcs, fbcon_cfb16_revc,
-	NULL /* cursor() */, NULL /* set_font() */,
+	pm2fb_cursor, pm2fb_set_font,
 	pm2fb_clear_margins16,
 	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) };
 #endif /* FBCON_HAS_CFB16 */
@@ -1140,7 +1372,7 @@
 static struct display_switch pm2_cfb24 = {
 	fbcon_cfb24_setup, pm2fb_bmove, pm2fb_clear24,
 	fbcon_cfb24_putc, fbcon_cfb24_putcs, fbcon_cfb24_revc,
-	NULL /* cursor() */, NULL /* set_font() */,
+	pm2fb_cursor, pm2fb_set_font,
 	pm2fb_clear_margins24,
 	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) };
 #endif /* FBCON_HAS_CFB24 */
@@ -1178,7 +1410,7 @@
 static struct display_switch pm2_cfb32 = {
 	fbcon_cfb32_setup, pm2fb_bmove, pm2fb_clear32,
 	fbcon_cfb32_putc, fbcon_cfb32_putcs, fbcon_cfb32_revc,
-	NULL /* cursor() */, NULL /* set_font() */,
+	pm2fb_cursor, pm2fb_set_font,
 	pm2fb_clear_margins32,
 	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) };
 #endif /* FBCON_HAS_CFB32 */
@@ -1258,7 +1490,7 @@
 	p.height=var->yres_virtual;
 	p.depth=(var->bits_per_pixel+7)&~7;
 	p.depth=p.depth>32?32:p.depth;
-	data64=p.depth>8;
+	data64=p.depth>8 || i->type == PM2_TYPE_PERMEDIA2V;
 	xres=(var->xres+31)&~31;
 	if (p.width<xres+var->xoffset)
 		p.width=xres+var->xoffset;
@@ -1417,14 +1649,12 @@
 
 static void set_user_mode(struct pm2fb_info* i) {
 
-	memcpy(&i->current_par, &pm2fb_options.user_mode,
-						sizeof(i->current_par));
 	if (pm2fb_options.flags & OPTF_YPAN) {
+		int h = i->current_par.height;
 		i->current_par.height=i->regions.fb_size/
 			(i->current_par.width*i->current_par.depth/8);
 		i->current_par.height=MIN(i->current_par.height,2047);
-		i->current_par.height=MAX(i->current_par.height,
-						pm2fb_options.user_mode.height);
+		i->current_par.height=MAX(i->current_par.height,h);
 	}
 }
 
@@ -1456,6 +1686,12 @@
 	set_screen(i, p);
 	i->current_par=*p;
 	i->current_par_valid=1;
+#ifdef PM2FB_HW_CURSOR	
+	if (i->cursor) {
+		pm2v_set_cursor_color(i, cursor_color_map, cursor_color_map, cursor_color_map);
+		pm2v_set_cursor_shape(i);
+	}
+#endif
 }
 
 static int pm2fb_getcolreg(unsigned regno,
@@ -1577,6 +1813,210 @@
 	return 0;
 }
 
+#ifdef PM2FB_HW_CURSOR
+/***************************************************************************
+ * Hardware cursor support
+ ***************************************************************************/
+ 
+static u8 cursor_bits_lookup[16] = {
+	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
+	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
+};
+
+static u8 cursor_mask_lookup[16] = {
+	0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8,
+	0x02, 0x82, 0x22, 0xa2, 0x0a, 0x8a, 0x2a, 0xaa
+};
+
+static void pm2v_set_cursor_color(struct pm2fb_info *fb, u8 *red, u8 *green, u8 *blue)
+{
+	struct pm2_cursor *c = fb->cursor;
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		c->color[3*i] = red[i];
+		c->color[3*i+1] = green[i];
+		c->color[3*i+2] = blue[i];
+	}
+
+	WAIT_FIFO(fb, 14);
+	pm2_WR(fb, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8);
+	for (i = 0; i < 6; i++)
+		pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PALETTE+i, c->color[i]);
+	pm2_WR(fb, PM2VR_RD_INDEX_HIGH, 0);
+}
+
+static void pm2v_set_cursor_shape(struct pm2fb_info *fb)
+{
+	struct pm2_cursor *c = fb->cursor;
+	u8 m, b;
+	int i, x, y;
+
+	WAIT_FIFO(fb, 1);
+	pm2_WR(fb, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PATTERN >> 8);
+	for (y = 0, i = 0; y < c->size.y; y++) {
+		WAIT_FIFO(fb, 32);
+		for (x = 0; x < c->size.x >> 3; x++) {
+			m = c->mask[x][y];
+			b = c->bits[x][y];
+			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i,
+				     cursor_mask_lookup[m >> 4] |
+				     cursor_bits_lookup[(b & m) >> 4]);
+			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1,
+				     cursor_mask_lookup[m & 0x0f] |
+				     cursor_bits_lookup[(b & m) & 0x0f]);
+			i+=2;
+		}
+		for ( ; x < 8; x++) {
+			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 0);
+			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 0);
+			i+=2;
+		}
+	}
+	for (; y < 64; y++) {
+		WAIT_FIFO(fb, 32);
+		for (x = 0; x < 8; x++) {
+			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 0);
+			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 0);
+			i+=2;
+		}
+	}
+	WAIT_FIFO(fb, 1);
+	pm2_WR(fb, PM2VR_RD_INDEX_HIGH, 0);
+}
+
+static void pm2v_set_cursor(struct pm2fb_info *fb, int on)
+{
+	struct pm2_cursor *c = fb->cursor;
+	int x = c->pos.x;
+
+	if (!on) x = 4000;
+	WAIT_FIFO(fb, 14);
+	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_LOW, x & 0xff);
+	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0x0f);
+	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_LOW, c->pos.y & 0xff);
+	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_HIGH, (c->pos.y >> 8) & 0x0f);
+	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_HOT, c->hot.x & 0x3f);
+	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_HOT, c->hot.y & 0x3f);
+	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_MODE, 0x11);
+}
+
+static void pm2_cursor_timer_handler(unsigned long dev_addr)
+{
+	struct pm2fb_info *fb = (struct pm2fb_info *)dev_addr;
+
+	if (!fb->cursor->enable)
+		goto out;
+
+	if (fb->cursor->vbl_cnt && --fb->cursor->vbl_cnt == 0) {
+		fb->cursor->on ^= 1;
+		pm2v_set_cursor(fb, fb->cursor->on);
+		fb->cursor->vbl_cnt = fb->cursor->blink_rate;
+	}
+
+out:
+	fb->cursor->timer->expires = jiffies + (HZ / 50);
+	add_timer(fb->cursor->timer);
+}
+
+static void pm2fb_cursor(struct display *p, int mode, int x, int y)
+{
+	struct pm2fb_info *fb = (struct pm2fb_info *)p->fb_info;
+	struct pm2_cursor *c = fb->cursor;
+
+	if (!c) return;
+
+	x *= fontwidth(p);
+	y *= fontheight(p);
+	if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->enable)
+		return;
+
+	c->enable = 0;
+	if (c->on)
+		pm2v_set_cursor(fb, 0);
+	c->pos.x = x;
+	c->pos.y = y;
+
+	switch (mode) {
+	case CM_ERASE:
+		c->on = 0;
+		break;
+
+	case CM_DRAW:
+	case CM_MOVE:
+		if (c->on)
+			pm2v_set_cursor(fb, 1);
+		else
+			c->vbl_cnt = CURSOR_DRAW_DELAY;
+		c->enable = 1;
+		break;
+	}
+}
+
+static struct pm2_cursor * __init pm2_init_cursor(struct pm2fb_info *fb)
+{
+	struct pm2_cursor *cursor;
+
+	if (fb->type != PM2_TYPE_PERMEDIA2V)
+		return 0; /* FIXME: Support hw cursor everywhere */
+
+	cursor = kmalloc(sizeof(struct pm2_cursor), GFP_ATOMIC);
+	if (!cursor)
+		return 0;
+	memset(cursor, 0, sizeof(*cursor));
+
+	cursor->timer = kmalloc(sizeof(*cursor->timer), GFP_KERNEL);
+	if (!cursor->timer) {
+		kfree(cursor);
+		return 0;
+	}
+	memset(cursor->timer, 0, sizeof(*cursor->timer));
+
+	cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE;
+
+	if (curblink) {
+		init_timer(cursor->timer);
+		cursor->timer->expires = jiffies + (HZ / 50);
+		cursor->timer->data = (unsigned long)fb;
+		cursor->timer->function = pm2_cursor_timer_handler;
+		add_timer(cursor->timer);
+	}
+
+	return cursor;
+}
+
+static int pm2fb_set_font(struct display *d, int width, int height)
+{
+	struct pm2fb_info *fb = (struct pm2fb_info *)d->fb_info;
+	struct pm2_cursor *c = fb->cursor;
+	int i, j;
+
+	if (c) {
+		if (!width || !height) {
+			width = 8;
+			height = 16;
+		}
+
+		c->hot.x = 0;
+		c->hot.y = 0;
+		c->size.x = width;
+		c->size.y = height;
+
+		memset(c->bits, 0xff, sizeof(c->bits));
+		memset(c->mask, 0, sizeof(c->mask));
+
+		for (i = 0, j = width; j >= 0; j -= 8, i++) {
+			c->mask[i][height-2] = (j >= 8) ? 0xff : (0xff << (8 - j));
+			c->mask[i][height-1] = (j >= 8) ? 0xff : (0xff << (8 - j));
+		}
+
+		pm2v_set_cursor_color(fb, cursor_color_map, cursor_color_map, cursor_color_map);
+		pm2v_set_cursor_shape(fb);
+	}
+	return 1;
+}
+#endif /* PM2FB_HW_CURSOR */
+
 /***************************************************************************
  * Begin of public functions
  ***************************************************************************/
@@ -1594,6 +2034,7 @@
 __initfunc(void pm2fb_init(void)) {
 
 	memset(&fb_info, 0, sizeof(fb_info));
+	memcpy(&fb_info.current_par, &pm2fb_options.user_mode, sizeof(fb_info.current_par));
 	if (!pm2fb_conf(&fb_info))
 		return;
 	pm2fb_reset(&fb_info);
@@ -1624,23 +2065,25 @@
 	MOD_INC_USE_COUNT;
 }
 
-__initfunc(void pm2fb_mode_setup(char* options)) {
+static void __init pm2fb_mode_setup(char* options) {
 	int i;
 
 	for (i=0; user_mode[i].name[0] &&
 		strcmp(options, user_mode[i].name); i++);
-	if (user_mode[i].name[0])
+	if (user_mode[i].name[0]) {
 		memcpy(&pm2fb_options.user_mode, &user_mode[i].par,
 					sizeof(pm2fb_options.user_mode));
+		pm2fb_options.flags |= OPTF_USER;
+	}
 }
 
-__initfunc(void pm2fb_font_setup(char* options)) {
+static void __init pm2fb_font_setup(char* options) {
 
 	strncpy(pm2fb_options.font, options, sizeof(pm2fb_options.font));
 	pm2fb_options.font[sizeof(pm2fb_options.font)-1]='\0';
 }
 
-__initfunc(void pm2fb_setup(char* options, int* ints)) {
+void __init pm2fb_setup(char* options, int* ints) {
 	char* next;
 
 	while (options) {
@@ -1656,6 +2099,8 @@
 			pm2fb_options.flags |= OPTF_OLD_MEM;
 		else if (!strcmp(options, "virtual"))
 			pm2fb_options.flags |= OPTF_VIRTUAL;
+		else if (!strcmp(options, "noblink"))
+			curblink = 0;
 		options=next;
 	}
 }
@@ -1665,9 +2110,14 @@
  ***************************************************************************/
 
 #ifdef MODULE
-int init_module(void) {
 
-	pm2fb_init();
+static char *mode = NULL;
+
+MODULE_PARM(mode, "s");
+
+int init_module(void) {
+	if (mode) pm2fb_mode_setup(mode);
+  	pm2fb_init();
 }
 
 void cleanup_module(void) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/pm2fb.h linux.14p16/drivers/video/pm2fb.h
--- linux.vanilla/drivers/video/pm2fb.h	Thu Feb 25 18:02:12 1999
+++ linux.14p16/drivers/video/pm2fb.h	Thu Dec  9 15:34:14 1999
@@ -108,6 +108,11 @@
 #define PM2R_FB_SOURCE_DELTA				0x8d88
 #define PM2R_CONFIG					0x8d90
 
+/* Permedia2v */
+#define PM2VR_RD_INDEX_LOW				0x4020
+#define PM2VR_RD_INDEX_HIGH				0x4028
+#define PM2VR_RD_INDEXED_DATA				0x4030
+
 /* Permedia2 RAMDAC indexed registers */
 #define PM2I_RD_CURSOR_CONTROL				0x06
 #define PM2I_RD_COLOR_MODE				0x18
@@ -127,6 +132,28 @@
 #define PM2I_RD_GREEN_KEY				0x43
 #define PM2I_RD_BLUE_KEY				0x44
 
+/* Permedia2v extensions */
+#define PM2VI_RD_MISC_CONTROL				0x000
+#define PM2VI_RD_SYNC_CONTROL				0x001
+#define PM2VI_RD_DAC_CONTROL				0x002
+#define PM2VI_RD_PIXEL_SIZE				0x003
+#define PM2VI_RD_COLOR_FORMAT				0x004
+#define PM2VI_RD_CURSOR_MODE				0x005
+#define PM2VI_RD_CURSOR_X_LOW				0x007
+#define PM2VI_RD_CURSOR_X_HIGH				0x008
+#define PM2VI_RD_CURSOR_Y_LOW				0x009
+#define PM2VI_RD_CURSOR_Y_HIGH				0x00A
+#define PM2VI_RD_CURSOR_X_HOT				0x00B
+#define PM2VI_RD_CURSOR_Y_HOT				0x00C
+#define PM2VI_RD_CLK0_PRESCALE				0x201
+#define PM2VI_RD_CLK0_FEEDBACK				0x202
+#define PM2VI_RD_CLK0_POSTSCALE				0x203
+#define PM2VI_RD_CLK1_PRESCALE				0x204
+#define PM2VI_RD_CLK1_FEEDBACK				0x205
+#define PM2VI_RD_CLK1_POSTSCALE				0x206
+#define PM2VI_RD_CURSOR_PALETTE				0x303
+#define PM2VI_RD_CURSOR_PATTERN				0x400
+
 /* Fields and flags */
 #define PM2F_RENDER_AREASTIPPLE				(1L<<0)
 #define PM2F_RENDER_FASTFILL				(1L<<3)
@@ -178,6 +205,11 @@
 #define PM2F_MEM_BANKS_2				(1L<<29)
 #define PM2F_MEM_BANKS_3				(2L<<29)
 #define PM2F_MEM_BANKS_4				(3L<<29)
+
+typedef enum {
+	PM2_TYPE_PERMEDIA2,
+	PM2_TYPE_PERMEDIA2V
+} pm2type_t;
 
 #endif /* PM2FB_H */
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/tcxfb.c linux.14p16/drivers/video/tcxfb.c
--- linux.vanilla/drivers/video/tcxfb.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/drivers/video/tcxfb.c	Thu Dec  9 15:34:13 1999
@@ -1,4 +1,4 @@
-/* $Id: tcxfb.c,v 1.7 1999/01/26 10:55:03 jj Exp $
+/* $Id: tcxfb.c,v 1.7.2.1 1999/09/28 16:00:14 davem Exp $
  * tcxfb.c: TCX 24/8bit frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/vga16fb.c linux.14p16/drivers/video/vga16fb.c
--- linux.vanilla/drivers/video/vga16fb.c	Sat Aug 14 02:27:35 1999
+++ linux.14p16/drivers/video/vga16fb.c	Thu Dec  9 15:34:14 1999
@@ -295,10 +295,14 @@
 	display->can_soft_blank = 1;
 	display->inverse = 0;
 
+#ifdef CONFIG_FBCON_VGA_PLANES
 	if (info->isVGA)
 		display->dispsw = &fbcon_vga_planes;
-	else
+	else	
 		display->dispsw = &fbcon_ega_planes;
+#else
+		display->dispsw = &fbcon_dummy;
+#endif	
 	display->scrollmode = SCROLL_YREDRAW;
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/adfs/inode.c linux.14p16/fs/adfs/inode.c
--- linux.vanilla/fs/adfs/inode.c	Fri Mar 26 21:57:41 1999
+++ linux.14p16/fs/adfs/inode.c	Mon Dec 13 20:57:15 1999
@@ -166,7 +166,7 @@
 	sb = inode->i_sb;
 	inode->i_uid = sb->u.adfs_sb.s_uid;
 	inode->i_gid = sb->u.adfs_sb.s_gid;
-	inode->i_version = ++event;
+	inode->i_version = ++global_event;
 
 	if (adfs_inode_validate_no (sb, inode->i_ino & 0xffffff00)) {
 		adfs_error (sb, "adfs_read_inode",
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/affs/inode.c linux.14p16/fs/affs/inode.c
--- linux.vanilla/fs/affs/inode.c	Sun Mar  7 23:25:23 1999
+++ linux.14p16/fs/affs/inode.c	Mon Dec 13 20:57:32 1999
@@ -379,13 +379,13 @@
 						FILE_END(link_bh->b_data,link)->link_chain;
 		FILE_END(link_bh->b_data,link)->link_chain   = cpu_to_be32(inode->i_ino);
 		affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5);
-		link->i_version = ++event;
+		link->i_version = ++global_event;
 		mark_inode_dirty(link);
 		mark_buffer_dirty(link_bh,1);
 	}
 	affs_fix_checksum(AFFS_I2BSIZE(inode),inode_bh->b_data,5);
 	affs_fix_checksum(AFFS_I2BSIZE(dir),dir_bh->b_data,5);
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	dir->i_mtime   = dir->i_atime = dir->i_ctime = CURRENT_TIME;
 	unlock_super(inode->i_sb);
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/affs/namei.c linux.14p16/fs/affs/namei.c
--- linux.vanilla/fs/affs/namei.c	Sat Aug 14 02:25:57 1999
+++ linux.14p16/fs/affs/namei.c	Mon Dec 13 20:57:54 1999
@@ -247,7 +247,7 @@
 	
 	inode->i_nlink = retval;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_inode_dirty(inode);
 	d_delete(dentry);
 	mark_inode_dirty(dir);
@@ -285,7 +285,7 @@
 	inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
 	d_instantiate(dentry,inode);
 	mark_inode_dirty(inode);
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_inode_dirty(dir);
 out:
 	return error;
@@ -319,7 +319,7 @@
 	inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
 	d_instantiate(dentry,inode);
 	mark_inode_dirty(inode);
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_inode_dirty(dir);
 out:
 	return error;
@@ -372,7 +372,7 @@
 	inode->i_nlink = retval;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	retval         = 0;
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_inode_dirty(dir);
 	mark_inode_dirty(inode);
 	d_delete(dentry);
@@ -450,7 +450,7 @@
 	if (error)
 		goto out_release;
 	d_instantiate(dentry,inode);
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_inode_dirty(dir);
 
 out:
@@ -504,7 +504,7 @@
 	if (error)
 		inode->i_nlink = 0;
 	else {
-		dir->i_version = ++event;
+		dir->i_version = ++global_event;
 		mark_inode_dirty(dir);
 		mark_inode_dirty(oldinode);
 		oldinode->i_count++;
@@ -579,8 +579,8 @@
 
 	new_dir->i_ctime   = new_dir->i_mtime = old_dir->i_ctime
 			   = old_dir->i_mtime = CURRENT_TIME;
-	new_dir->i_version = ++event;
-	old_dir->i_version = ++event;
+	new_dir->i_version = ++global_event;
+	old_dir->i_version = ++global_event;
 	retval             = 0;
 	mark_inode_dirty(new_dir);
 	mark_inode_dirty(old_dir);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/binfmt_aout.c linux.14p16/fs/binfmt_aout.c
--- linux.vanilla/fs/binfmt_aout.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/fs/binfmt_aout.c	Thu Dec  9 15:32:41 1999
@@ -296,6 +296,8 @@
 	return sp;
 }
 
+static int warnings = 0;
+
 /*
  * These are the functions used to load a.out style executables and shared
  * libraries.  There is no binary dependent code anywhere else.
@@ -322,6 +324,14 @@
 
 	fd_offset = N_TXTOFF(ex);
 
+#ifdef __i386__
+	if (N_MAGIC(ex) == ZMAGIC && fd_offset != BLOCK_SIZE) {
+		if(warnings++<10)
+			printk(KERN_NOTICE "N_TXTOFF != BLOCK_SIZE. See a.out.h.\n");
+		return -ENOEXEC;
+	}
+#endif
+
 	/* Check initial limits. This avoids letting people circumvent
 	 * size limits imposed on them by creating programs with large
 	 * arrays in the data or bss.
@@ -389,30 +399,22 @@
 		flush_icache_range((unsigned long) 0,
 				   (unsigned long) ex.a_text+ex.a_data);
 	} else {
-		static unsigned long error_time, error_time2;
 		if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
-		    (N_MAGIC(ex) != NMAGIC) && (jiffies-error_time2) > 5*HZ)
-		{
-			printk(KERN_NOTICE "executable not page aligned\n");
-			error_time2 = jiffies;
-		}
+		    (N_MAGIC(ex) != NMAGIC))
+			if(warnings++<10)
+				printk(KERN_NOTICE "executable not page aligned\n");
 
 		fd = open_dentry(bprm->dentry, O_RDONLY);
 		if (fd < 0)
 			return fd;
 		file = fget(fd);
 
-		if ((fd_offset & ~PAGE_MASK) != 0 &&
-		    (jiffies-error_time) > 5*HZ)
-		{
-			printk(KERN_WARNING 
-			       "fd_offset is not page aligned. Please convert program: %s\n",
-			       file->f_dentry->d_name.name
-			       );
-			error_time = jiffies;
-		}
-
-		if (!file->f_op || !file->f_op->mmap || ((fd_offset & ~PAGE_MASK) != 0)) {
+		if (!file->f_op || !file->f_op->mmap ||
+		    fd_offset & (bprm->dentry->d_inode->i_sb->s_blocksize-1)) {
+			if (warnings++<10)
+				printk(KERN_NOTICE
+				       "fd_offset is not blocksize aligned. Loading %s in anonymous memory.\n",
+				       file->f_dentry->d_name.name);
 			fput(file);
 			sys_close(fd);
 			do_mmap(NULL, N_TXTADDR(ex), ex.a_text+ex.a_data,
@@ -530,16 +532,11 @@
 
 	start_addr =  ex.a_entry & 0xfffff000;
 
-	if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
-		static unsigned long error_time;
-
-		if ((jiffies-error_time) > 5*HZ)
-		{
-			printk(KERN_WARNING 
-			       "N_TXTOFF is not page aligned. Please convert library: %s\n",
+	if (N_TXTOFF(ex) & (inode->i_sb->s_blocksize-1)) {
+		if (warnings++<10)
+			printk(KERN_NOTICE
+			       "N_TXTOFF is not blocksize aligned. Loading library %s in anonymous memory.\n",
 			       file->f_dentry->d_name.name);
-			error_time = jiffies;
-		}
 		do_mmap(NULL, start_addr, ex.a_text + ex.a_data,
 			PROT_READ | PROT_WRITE | PROT_EXEC,
 			MAP_FIXED| MAP_PRIVATE, 0);
@@ -547,8 +544,7 @@
 			  (char *)start_addr, ex.a_text + ex.a_data, 0);
 		flush_icache_range((unsigned long) start_addr,
 				   (unsigned long) start_addr + ex.a_text + ex.a_data);
-		retval = 0;
-		goto out_putf;
+		goto map_bss;
 	}
 	/* Now use mmap to map the library into memory. */
 	error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
@@ -559,6 +555,7 @@
 	if (error != start_addr)
 		goto out_putf;
 
+ map_bss:
 	len = PAGE_ALIGN(ex.a_text + ex.a_data);
 	bss = ex.a_text + ex.a_data + ex.a_bss;
 	if (bss > len) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/block_dev.c linux.14p16/fs/block_dev.c
--- linux.vanilla/fs/block_dev.c	Sat Aug 14 02:26:50 1999
+++ linux.14p16/fs/block_dev.c	Fri Dec 17 18:47:40 1999
@@ -67,39 +67,50 @@
 			if (chars != blocksize)
 				fn = bread;
 			bh = fn(dev, block, blocksize);
+			if (!bh)
+				return written ? written : -EIO;
+			if (!buffer_uptodate(bh))
+				wait_on_buffer(bh);
 		}
 #else
 		bh = getblk(dev, block, blocksize);
+		if (!bh)
+			return written ? written : -EIO;
 
-		if (chars != blocksize && !buffer_uptodate(bh)) {
-		  if(!filp->f_reada ||
-		     !read_ahead[MAJOR(dev)]) {
-		    /* We do this to force the read of a single buffer */
-		    brelse(bh);
-		    bh = bread(dev,block,blocksize);
-		  } else {
-		    /* Read-ahead before write */
-		    blocks = read_ahead[MAJOR(dev)] / (blocksize >> 9) / 2;
-		    if (block + blocks > size) blocks = size - block;
-		    if (blocks > NBUF) blocks=NBUF;
+		if (!buffer_uptodate(bh))
+		{
+		  if (chars == blocksize)
+		    wait_on_buffer(bh);
+		  else
+		  {
 		    bhlist[0] = bh;
-		    for(i=1; i<blocks; i++){
-		      bhlist[i] = getblk (dev, block+i, blocksize);
-		      if(!bhlist[i]){
-			while(i >= 0) brelse(bhlist[i--]);
-			return written ? written : -EIO;
-		      };
-		    };
+		    if (!filp->f_reada || !read_ahead[MAJOR(dev)]) {
+		      /* We do this to force the read of a single buffer */
+		      blocks = 1;
+		    } else {
+		      /* Read-ahead before write */
+		      blocks = read_ahead[MAJOR(dev)] / (blocksize >> 9) / 2;
+		      if (block + blocks > size) blocks = size - block;
+		      if (blocks > NBUF) blocks=NBUF;
+		      for(i=1; i<blocks; i++)
+		      {
+		        bhlist[i] = getblk (dev, block+i, blocksize);
+		        if (!bhlist[i])
+			{
+			  while(i >= 0) brelse(bhlist[i--]);
+			  return written ? written : -EIO;
+		        }
+		      }
+		    }
 		    ll_rw_block(READ, blocks, bhlist);
 		    for(i=1; i<blocks; i++) brelse(bhlist[i]);
 		    wait_on_buffer(bh);
-		      
+		    if (!buffer_uptodate(bh))
+			  return written ? written : -EIO;
 		  };
 		};
 #endif
 		block++;
-		if (!bh)
-			return written ? written : -EIO;
 		p = offset + bh->b_data;
 		offset = 0;
 		*ppos += chars;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/buffer.c linux.14p16/fs/buffer.c
--- linux.vanilla/fs/buffer.c	Sat Aug 14 02:27:35 1999
+++ linux.14p16/fs/buffer.c	Thu Dec  9 15:32:38 1999
@@ -24,6 +24,9 @@
  * - RMK
  */
 
+/* invalidate_buffers/set_blocksize/sync_dev race conditions and
+   fs corruption fixes, 1999, Andrea Arcangeli <andrea@suse.de> */
+
 #include <linux/malloc.h>
 #include <linux/locks.h>
 #include <linux/errno.h>
@@ -58,11 +61,12 @@
 /*
  * Hash table mask..
  */
-static unsigned long bh_hash_mask = 0;
+static unsigned int bh_hash_mask = 0;
+static unsigned int bh_hash_shift = 0;
+static struct buffer_head ** hash_table = NULL;
 
 static int grow_buffers(int size);
 
-static struct buffer_head ** hash_table;
 static struct buffer_head * lru_list[NR_LIST] = {NULL, };
 static struct buffer_head * free_list[NR_SIZES] = {NULL, };
 
@@ -79,7 +83,7 @@
 static int nr_hashed_buffers = 0;
 
 /* This is used by some architectures to estimate available memory. */
-int buffermem = 0;
+long buffermem = 0;
 
 /* Here is the parameter block for the bdflush process. If you add or
  * remove any of the parameters, make sure to update kernel/sysctl.c.
@@ -262,11 +266,14 @@
 
 void sync_dev(kdev_t dev)
 {
-	sync_buffers(dev, 0);
 	sync_supers(dev);
 	sync_inodes(dev);
-	sync_buffers(dev, 0);
 	DQUOT_SYNC(dev);
+	/* sync all the dirty buffers out to disk only _after_ all the
+	   high level layers finished generated buffer dirty data
+	   (or we'll return with some buffer still dirty on the blockdevice
+	   so breaking the semantics of this call) */
+	sync_buffers(dev, 0);
 	/*
 	 * FIXME(eric) we need to sync the physical devices here.
 	 * This is because some (scsi) controllers have huge amounts of
@@ -395,33 +402,13 @@
 	return err;
 }
 
-void invalidate_buffers(kdev_t dev)
-{
-	int i;
-	int nlist;
-	struct buffer_head * bh;
-
-	for(nlist = 0; nlist < NR_LIST; nlist++) {
-		bh = lru_list[nlist];
-		for (i = nr_buffers_type[nlist]*2 ; --i > 0 ; bh = bh->b_next_free) {
-			if (bh->b_dev != dev)
-				continue;
-			wait_on_buffer(bh);
-			if (bh->b_dev != dev)
-				continue;
-			if (bh->b_count)
-				continue;
-			bh->b_flushtime = 0;
-			clear_bit(BH_Protected, &bh->b_state);
-			clear_bit(BH_Uptodate, &bh->b_state);
-			clear_bit(BH_Dirty, &bh->b_state);
-			clear_bit(BH_Req, &bh->b_state);
-		}
-	}
-}
-
-#define _hashfn(dev,block) (((unsigned)(HASHDEV(dev)^block)) & bh_hash_mask)
-#define hash(dev,block) hash_table[_hashfn(dev,block)]
+/* After several hours of tedious analysis, the following hash
+ * function won.  Do not mess with it... -DaveM
+ */
+#define _hashfn(dev,block)	\
+	((((dev)<<(bh_hash_shift - 6)) ^ ((dev)<<(bh_hash_shift - 9))) ^ \
+	 (((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ ((block) << (bh_hash_shift - 12))))
+#define hash(dev,block) hash_table[_hashfn(dev,block) & bh_hash_mask]
 
 static inline void remove_from_hash_queue(struct buffer_head * bh)
 {
@@ -434,8 +421,8 @@
 		}
 		*pprev = next;
 		bh->b_pprev = NULL;
+		nr_hashed_buffers--;
 	}
-	nr_hashed_buffers--;
 }
 
 static inline void remove_from_lru_list(struct buffer_head * bh)
@@ -486,11 +473,14 @@
 	remove_from_lru_list(bh);
 }
 
-static inline void put_last_free(struct buffer_head * bh)
+static void put_last_free(struct buffer_head * bh)
 {
 	if (bh) {
 		struct buffer_head **bhp = &free_list[BUFSIZE_INDEX(bh->b_size)];
 
+		bh->b_count = 0;
+		bh->b_state = 0;
+		remove_from_queues(bh);
 		bh->b_dev = B_FREE;  /* So it is obvious we are on the free list. */
 
 		/* Add to back of free list. */
@@ -510,7 +500,7 @@
 {
 	/* put at end of free list */
 	if(bh->b_dev == B_FREE) {
-		put_last_free(bh);
+		panic("B_FREE inserted into queues");
 	} else {
 		struct buffer_head **bhp = &lru_list[bh->b_list];
 
@@ -542,8 +532,8 @@
 			}
 			*bhp = bh;
 			bh->b_pprev = bhp;
+			nr_hashed_buffers++;
 		}
-		nr_hashed_buffers++;
 	}
 }
 
@@ -600,10 +590,61 @@
 	return 0;
 }
 
+/* If invalidate_buffers() will trash dirty buffers, it means some kind
+   of fs corruption is going on. Trashing dirty data always imply losing
+   information that was supposed to be just stored on the physical layer
+   by the user.
+
+   Thus invalidate_buffers in general usage is not allwowed to trash dirty
+   buffers. For example ioctl(FLSBLKBUF) expects dirty data to be preserved.
+
+   NOTE: In the case where the user removed a removable-media-disk even if
+   there's still dirty data not synced on disk (due a bug in the device driver
+   or due an error of the user), by not destroying the dirty buffers we could
+   generate corruption also on the next media inserted, thus a parameter is
+   necessary to handle this case in the most safe way possible (trying
+   to not corrupt also the new disk inserted with the data belonging to
+   the old now corrupted disk). Also for the ramdisk the natural thing
+   to do in order to release the ramdisk memory is to destroy dirty buffers.
+
+   These are two special cases. Normal usage imply the device driver
+   to issue a sync on the device (without waiting I/O completation) and
+   then an invalidate_buffers call that doesn't trashes dirty buffers. */
+void __invalidate_buffers(kdev_t dev, int destroy_dirty_buffers)
+{
+	int i, nlist, slept;
+	struct buffer_head * bh, * bhnext;
+
+ again:
+	slept = 0;
+	for(nlist = 0; nlist < NR_LIST; nlist++) {
+		bh = lru_list[nlist];
+		if (!bh)
+			continue;
+		for (i = nr_buffers_type[nlist] ; i > 0 ;
+		     bh = bhnext, i--)
+		{
+			bhnext = bh->b_next_free;
+			if (bh->b_dev != dev)
+				continue;
+			if (buffer_locked(bh))
+			{
+				slept = 1;
+				__wait_on_buffer(bh);
+			}
+			if (!bh->b_count &&
+			    (destroy_dirty_buffers || !buffer_dirty(bh)))
+				put_last_free(bh);
+			if (slept)
+				goto again;
+		}
+	}
+}
+
 void set_blocksize(kdev_t dev, int size)
 {
 	extern int *blksize_size[];
-	int i, nlist;
+	int i, nlist, slept;
 	struct buffer_head * bh, *bhnext;
 
 	if (!blksize_size[MAJOR(dev)])
@@ -625,27 +666,35 @@
 	/* We need to be quite careful how we do this - we are moving entries
 	 * around on the free list, and we can get in a loop if we are not careful.
 	 */
-	for(nlist = 0; nlist < NR_LIST; nlist++) {
+ again:
+	slept = 0;
+ 	for(nlist = 0; nlist < NR_LIST; nlist++) {
 		bh = lru_list[nlist];
-		for (i = nr_buffers_type[nlist]*2 ; --i > 0 ; bh = bhnext) {
-			if(!bh)
-				break;
-
-			bhnext = bh->b_next_free; 
-			if (bh->b_dev != dev)
-				 continue;
-			if (bh->b_size == size)
-				 continue;
-			bhnext->b_count++;
-			wait_on_buffer(bh);
-			bhnext->b_count--;
-			if (bh->b_dev == dev && bh->b_size != size) {
-				clear_bit(BH_Dirty, &bh->b_state);
-				clear_bit(BH_Uptodate, &bh->b_state);
-				clear_bit(BH_Req, &bh->b_state);
-				bh->b_flushtime = 0;
+		if (!bh)
+			continue;
+		for (i = nr_buffers_type[nlist] ; i > 0 ;
+		     bh = bhnext, i--)
+		{
+			bhnext = bh->b_next_free;
+			if (bh->b_dev != dev || bh->b_size == size)
+				continue;
+			if (buffer_dirty(bh))
+				printk(KERN_ERR "set_blocksize: dev %s buffer_dirty %lu size %lu\n", kdevname(dev), bh->b_blocknr, bh->b_size);
+			if (buffer_locked(bh))
+			{
+				slept = 1;
+				wait_on_buffer(bh);
 			}
-			remove_from_hash_queue(bh);
+			if (!bh->b_count)
+				put_last_free(bh);
+			else
+				printk(KERN_ERR
+				       "set_blocksize: "
+				       "b_count %d, dev %s, block %lu!\n",
+				       bh->b_count, bdevname(bh->b_dev),
+				       bh->b_blocknr);
+			if (slept)
+				goto again;
 		}
 	}
 }
@@ -825,9 +874,6 @@
 		__brelse(buf);
 		return;
 	}
-	buf->b_count = 0;
-	buf->b_state = 0;
-	remove_from_queues(buf);
 	put_last_free(buf);
 }
 
@@ -1459,7 +1505,7 @@
 	int nlist;
 	static char *buf_types[NR_LIST] = {"CLEAN","LOCKED","DIRTY"};
 
-	printk("Buffer memory:   %6dkB\n",buffermem>>10);
+	printk("Buffer memory:   %8ldkB\n",buffermem>>10);
 	printk("Buffer heads:    %6d\n",nr_buffer_heads);
 	printk("Buffer blocks:   %6d\n",nr_buffers);
 	printk("Buffer hashed:   %6d\n",nr_hashed_buffers);
@@ -1506,22 +1552,32 @@
 	   fsync times (ext2) manageable, is the following */
 
 	memory_size >>= 20;
-	for (order = 5; (1UL << order) < memory_size; order++);
+	for (order = 0; (1UL << order) < memory_size; order++);
 
 	/* try to allocate something until we get it or we're asking
            for something that is really too small */
 
 	do {
+		unsigned long tmp;
+
 		nr_hash = (1UL << order) * PAGE_SIZE /
 		    sizeof(struct buffer_head *);
+		bh_hash_mask = (nr_hash - 1);
+
+		tmp = nr_hash;
+		bh_hash_shift = 0;
+		while((tmp >>= 1UL) != 0UL)
+			bh_hash_shift++;
+
 		hash_table = (struct buffer_head **)
 		    __get_free_pages(GFP_ATOMIC, order);
-	} while (hash_table == NULL && --order > 4);
+	} while (hash_table == NULL && --order >= 0);
+	printk("Buffer cache hash table entries: %d (order %d, %ldk)\n",
+	       nr_hash, order, (1UL<<order) * PAGE_SIZE / 1024);
 	
 	if (!hash_table)
 		panic("Failed to allocate buffer hash table\n");
 	memset(hash_table, 0, nr_hash * sizeof(struct buffer_head *));
-	bh_hash_mask = nr_hash-1;
 
 	bh_cachep = kmem_cache_create("buffer_head",
 				      sizeof(struct buffer_head),
@@ -1563,7 +1619,6 @@
 		return;
 	wake_up(&bdflush_wait);
 	if (wait) {
-		run_task_queue(&tq_disk);
 		sleep_on(&bdflush_done);
 	}
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/dcache.c linux.14p16/fs/dcache.c
--- linux.vanilla/fs/dcache.c	Sat Aug 14 02:25:58 1999
+++ linux.14p16/fs/dcache.c	Mon Dec 13 18:41:46 1999
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 
 #include <asm/uaccess.h>
+#include <asm/cache.h>
 
 #define DCACHE_PARANOIA 1
 /* #define DCACHE_DEBUG 1 */
@@ -41,11 +42,12 @@
  * This hash-function tries to avoid losing too many bits of hash
  * information, yet avoid using a prime hash-size or similar.
  */
-#define D_HASHBITS     10
-#define D_HASHSIZE     (1UL << D_HASHBITS)
-#define D_HASHMASK     (D_HASHSIZE-1)
+#define D_HASHBITS     d_hash_shift
+#define D_HASHMASK     d_hash_mask
 
-static struct list_head dentry_hashtable[D_HASHSIZE];
+static unsigned int d_hash_mask;
+static unsigned int d_hash_shift;
+static struct list_head *dentry_hashtable;
 static LIST_HEAD(dentry_unused);
 
 struct {
@@ -69,18 +71,23 @@
  * Release the dentry's inode, using the fileystem
  * d_iput() operation if defined.
  */
-static inline void dentry_iput(struct dentry * dentry)
+static inline int dentry_iput(struct dentry * dentry)
 {
 	struct inode *inode = dentry->d_inode;
+	int ret = 0;
+
 	if (inode) {
 		dentry->d_inode = NULL;
 		list_del(&dentry->d_alias);
 		INIT_LIST_HEAD(&dentry->d_alias);
+		ret = inode->i_count == 1;
 		if (dentry->d_op && dentry->d_op->d_iput)
 			dentry->d_op->d_iput(dentry, inode);
 		else
 			iput(inode);
 	}
+
+	return ret;
 }
 
 /*
@@ -168,6 +175,11 @@
 int d_invalidate(struct dentry * dentry)
 {
 	/*
+	 * If it's already been dropped, return OK.
+	 */
+	if (list_empty(&dentry->d_hash))
+		return 0;
+	/*
 	 * Check whether to do a partial shrink_dcache
 	 * to get rid of unused child entries.
 	 */
@@ -195,86 +207,24 @@
 }
 
 /*
- * Select less valuable dentries to be pruned when we need
- * inodes or memory. The selected dentries are moved to the
- * old end of the list where prune_dcache() can find them.
- * 
- * Negative dentries are included in the selection so that
- * they don't accumulate at the end of the list. The count
- * returned is the total number of dentries selected, which
- * may be much larger than the requested number of inodes.
- */
-int select_dcache(int inode_count, int page_count)
-{
-	struct list_head *next, *tail = &dentry_unused;
-	int found = 0;
-	int depth = dentry_stat.nr_unused >> 1;
-	unsigned long max_value = 4;
-
-	if (page_count)
-		max_value = -1;
-
-	next = tail->prev;
-	while (next != &dentry_unused && depth--) {
-		struct list_head *tmp = next;
-		struct dentry *dentry = list_entry(tmp, struct dentry, d_lru);
-		struct inode *inode = dentry->d_inode;
-		unsigned long value = 0;	
-
-		next = tmp->prev;
-		if (dentry->d_count) {
-			dentry_stat.nr_unused--;
-			list_del(tmp);
-			INIT_LIST_HEAD(tmp);
-			continue;
-		}
-
-		/*
-		 * Select dentries based on the page cache count ...
-		 * should factor in number of uses as well. We take
-		 * all negative dentries so that they don't accumulate.
-		 * (We skip inodes that aren't immediately available.)
-		 */
-		if (inode) {
-			value = inode->i_nrpages;	
-			if (value >= max_value)
-				continue;
-			if (inode->i_state || inode->i_count > 1)
-				continue;
-		}
-
-		/*
-		 * Move the selected dentries behind the tail.
-		 */
-		if (tmp != tail->prev) {
-			list_del(tmp);
-			list_add(tmp, tail->prev);
-		}
-		tail = tmp;
-		found++;
-		if (inode && --inode_count <= 0)
-			break;
-		if (page_count && (page_count -= value) <= 0)
-			break;
-	}
-	return found;
-}
-
-/*
  * Throw away a dentry - free the inode, dput the parent.
  * This requires that the LRU list has already been
  * removed.
  */
-static inline void prune_one_dentry(struct dentry * dentry)
+static inline int prune_one_dentry(struct dentry * dentry)
 {
 	struct dentry * parent;
+	int ret;
 
 	list_del(&dentry->d_hash);
 	list_del(&dentry->d_child);
-	dentry_iput(dentry);
+	ret = dentry_iput(dentry);
 	parent = dentry->d_parent;
 	d_free(dentry);
-	dput(parent);
+	if (parent != dentry)
+		dput(parent);
+
+	return ret;
 }
 
 /*
@@ -282,9 +232,21 @@
  * more memory, or simply when we need to unmount
  * something (at which point we need to unuse
  * all dentries).
+ *
+ * If you don't want a limit on the number of
+ * inodes that will be released then call
+ * with i_nr = -1.
+ *
+ * If you don't want a limit on the number of
+ * dentries that will be released then call
+ * with d_nr = 0.
+ *
+ * Returns the number of inodes released.
  */
-void prune_dcache(int count)
+int prune_dcache(int d_nr, int i_nr)
 {
+	int __i_nr = i_nr;
+
 	for (;;) {
 		struct dentry *dentry;
 		struct list_head *tmp = dentry_unused.prev;
@@ -296,11 +258,15 @@
 		INIT_LIST_HEAD(tmp);
 		dentry = list_entry(tmp, struct dentry, d_lru);
 		if (!dentry->d_count) {
-			prune_one_dentry(dentry);
-			if (!--count)
+			i_nr -= prune_one_dentry(dentry);
+			if (!i_nr)
+				break;
+			if (!--d_nr)
 				break;
 		}
 	}
+
+	return __i_nr - i_nr;
 }
 
 /*
@@ -396,6 +362,43 @@
 }
 
 /*
+ * Search for at least 1 mount point in the dentry's subdirs.
+ * We descend to the next level whenever the d_subdirs
+ * list is non-empty and continue searching.
+ */
+int have_submounts(struct dentry *parent)
+{
+	struct dentry *this_parent = parent;
+	struct list_head *next;
+
+	if (parent->d_mounts != parent)
+		return 1;
+repeat:
+	next = this_parent->d_subdirs.next;
+resume:
+	while (next != &this_parent->d_subdirs) {
+		struct list_head *tmp = next;
+		struct dentry *dentry = list_entry(tmp, struct dentry, d_child);		next = tmp->next;
+		/* Have we found a mount point ? */
+		if (dentry->d_mounts != dentry)
+			return 1;
+		if (!list_empty(&dentry->d_subdirs)) {
+			this_parent = dentry;
+			goto repeat;
+		}
+	}
+	/*
+	 * All done at this level ... ascend and resume the search.
+	 */
+	if (this_parent != parent) {
+		next = this_parent->d_child.next;
+		this_parent = this_parent->d_parent;
+		goto resume;
+	}
+	return 0; /* No mount points found in tree */
+}
+
+/*
  * Search the dentry child list for the specified parent,
  * and move any unused dentries to the end of the unused
  * list for prune_dcache(). We descend to the next level
@@ -455,7 +458,7 @@
 	int found;
 
 	while ((found = select_parent(parent)) != 0)
-		prune_dcache(found);
+		prune_dcache(found, -1);
 }
 
 /*
@@ -475,7 +478,7 @@
 		int count = 0;
 		if (priority)
 			count = dentry_stat.nr_unused / priority;
-		prune_dcache(count);
+		prune_dcache(count, -1);
 	}
 }
 
@@ -563,7 +566,7 @@
 
 static inline struct list_head * d_hash(struct dentry * parent, unsigned long hash)
 {
-	hash += (unsigned long) parent;
+	hash += (unsigned long) parent / L1_CACHE_BYTES;
 	hash = hash ^ (hash >> D_HASHBITS) ^ (hash >> D_HASHBITS*2);
 	return dentry_hashtable + (hash & D_HASHMASK);
 }
@@ -902,8 +905,10 @@
 
 void __init dcache_init(void)
 {
-	int i;
-	struct list_head *d = dentry_hashtable;
+	int i, order;
+	struct list_head *d;
+	unsigned int nr_hash;
+	unsigned long memory_size;
 
 	/* 
 	 * A constructor could be added for stable state like the lists,
@@ -921,7 +926,34 @@
 	if (!dentry_cache)
 		panic("Cannot create dentry cache");
 
-	i = D_HASHSIZE;
+	memory_size = num_physpages << PAGE_SHIFT;
+	memory_size >>= 13;
+	memory_size *= 2 * sizeof(void *);
+	for (order = 0; ((1UL << order) << PAGE_SHIFT) < memory_size; order++);
+
+	do {
+		unsigned long tmp;
+
+		nr_hash = (1UL << order) * PAGE_SIZE /
+			sizeof(struct list_head);
+		d_hash_mask = (nr_hash - 1);
+
+		tmp = nr_hash;
+		d_hash_shift = 0;
+		while((tmp >>= 1UL) != 0UL)
+			d_hash_shift++;
+
+		dentry_hashtable = (struct list_head *)
+			__get_free_pages(GFP_ATOMIC, order);
+	} while(dentry_hashtable == NULL && --order >= 0);
+	printk("Dentry hash table entries: %d (order %d, %ldk)\n",
+	       nr_hash, order, (1UL<<order) * PAGE_SIZE / 1024);
+
+	if (!dentry_hashtable)
+		panic("Failed to allocate dcache hash table\n");
+
+	d = dentry_hashtable;
+	i = nr_hash;
 	do {
 		INIT_LIST_HEAD(d);
 		d++;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/devices.c linux.14p16/fs/devices.c
--- linux.vanilla/fs/devices.c	Wed Dec 23 19:39:49 1998
+++ linux.14p16/fs/devices.c	Thu Dec  9 15:32:39 1999
@@ -216,7 +216,8 @@
 	if (sb && invalidate_inodes(sb))
 		printk("VFS: busy inodes on changed media.\n");
 
-	invalidate_buffers(dev);
+	/* special: trash all dirty data as well as the media is changed */
+	destroy_buffers(dev);
 
 	if (fops->revalidate)
 		fops->revalidate(dev);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/dquot.c linux.14p16/fs/dquot.c
--- linux.vanilla/fs/dquot.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/fs/dquot.c	Thu Dec  9 15:32:40 1999
@@ -31,6 +31,9 @@
  *		add_dquot_ref() restarts after blocking
  *		Added check for bogus uid and fixed check for group in quotactl.
  *		Jan Kara, <jack@atrey.karlin.mff.cuni.cz>, 4-6/99
+ *		Definitely (hopefully) fixed deadlock in write_dquot(). We no
+ *		longer account quota files.
+ *		Jan Kara, <jack@suse.cz>, 11/99, sposored by SuSE CR
  *
  * (C) Copyright 1994 - 1997 Marco van Wieringen 
  */
@@ -245,6 +248,9 @@
 	wake_up(&dquot->dq_wait);
 }
 
+/*
+ *	We don't have to be afraid of deadlocks as we never have quotas on quota files...
+ */
 static void write_dquot(struct dquot *dquot)
 {
 	short type = dquot->dq_type;
@@ -252,20 +258,14 @@
 	mm_segment_t fs;
 	loff_t offset;
 	ssize_t ret;
-	struct dqblk data;
 	struct semaphore *sem = &dquot->dq_mnt->mnt_dquot.dqio_sem;
 
-	/*
-	 * We copy our data to preserve consistency when dquot is not locked.
-	 * We can't lock it because it can cause deadlocks - think about
-	 * growing the quota file...
-	 */
-	memcpy(&data, &dquot->dq_dqb, sizeof(struct dqblk));
-	down(sem);
+	lock_dquot(dquot);
 	if (!dquot->dq_mnt) {	/* Invalidated quota? */
-		up(sem);
+		unlock_dquot(dquot);
 		return;
 	}
+	down(sem);
 	filp = dquot->dq_mnt->mnt_dquot.files[type];
 	offset = dqoff(dquot->dq_id);
 	fs = get_fs();
@@ -278,18 +278,15 @@
 	dquot->dq_flags &= ~DQ_MOD;
 	ret = 0;
 	if (filp)
-		ret = filp->f_op->write(filp, (char *)&data, 
+		ret = filp->f_op->write(filp, (char *)&dquot->dq_dqb, 
 					sizeof(struct dqblk), &offset);
 	if (ret != sizeof(struct dqblk))
 		printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
 			kdevname(dquot->dq_dev));
 
-	/*
-	 * Be sure that anybody didn't invalidated the dquot in the mean time...
-	 * Nasty but I don't see other choice when we don't want to lock dquot.
-	 */
-	up(sem);
 	set_fs(fs);
+	up(sem);
+	unlock_dquot(dquot);
 
 	dqstats.writes++;
 }
@@ -572,10 +569,9 @@
 	/*
 	 * Try pruning the dcache to free up some dquots ...
 	 */
-	count = select_dcache(128, 0);
-	if (count) {
-		printk(KERN_DEBUG "get_empty_dquot: pruning %d\n", count);
-		prune_dcache(count);
+	printk(KERN_DEBUG "get_empty_dquot: pruning %d\n", count);
+	if (prune_dcache(0, 128))
+	{
 		free_inode_memory(count);
 		goto repeat;
 	}
@@ -652,12 +648,31 @@
 	return dquot;
 }
 
+/* Check whether this inode is quota file */
+static inline int is_quotafile(struct inode *inode)
+{
+	int cnt;
+	struct vfsmount *vfsmnt;
+	struct file **files;
+
+	vfsmnt = lookup_vfsmnt(inode->i_dev);
+	if (!vfsmnt)
+		return 0;
+	files = vfsmnt->mnt_dquot.files;
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+		if (files[cnt] && files[cnt]->f_dentry->d_inode == inode)
+			return 1;
+	return 0;
+}
+
 static int dqinit_needed(struct inode *inode, short type)
 {
 	int cnt;
 
         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)))
                 return 0;
+	if (is_quotafile(inode))
+		return 0;
 	if (type != -1)
 		return inode->i_dquot[type] == NODQUOT;
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
@@ -717,7 +732,7 @@
 	}
 	inode->i_flags &= ~S_QUOTA;
 put_it:
-	if (dquot != NODQUOT)
+	if (dquot != NODQUOT) {
 		if (dqput_blocks(dquot)) {
 			spin_unlock(&inode_lock);	/* We may block so drop the lock... */
 			dqput(dquot);
@@ -727,6 +742,8 @@
 		}
 		else
 			dqput(dquot);	/* dqput() won't block so we can hold locks... */
+	}
+
 	return 0;
 }
 
@@ -1070,6 +1087,9 @@
 	if (S_ISREG(inode->i_mode) ||
             S_ISDIR(inode->i_mode) ||
             S_ISLNK(inode->i_mode)) {
+		/* We don't want to have quotas on quota files - nasty deadlocks possible */
+		if (is_quotafile(inode))
+			return;
 		for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 			if (type != -1 && cnt != type)
 				continue;
@@ -1341,7 +1361,6 @@
 		dquot_incr_blocks(transfer_to[cnt], blocks);
 
 		unlock_dquot(transfer_from[cnt]);
-		dqput(transfer_from[cnt]);
 		if (inode->i_dquot[cnt] != NODQUOT) {
 			struct dquot *temp = inode->i_dquot[cnt];
 			inode->i_dquot[cnt] = transfer_to[cnt];
@@ -1351,20 +1370,20 @@
 			unlock_dquot(transfer_to[cnt]);
 			dqput(transfer_to[cnt]);
 		}
+		dqput(transfer_from[cnt]);
 	}
 
 	return 0;
 put_all:
 	for (disc = 0; disc < cnt; disc++) {
 		/* There should be none or both pointers set but... */
-		if (transfer_to[disc] != NODQUOT) {
+		if (transfer_to[disc] != NODQUOT)
 			unlock_dquot(transfer_to[disc]);
-			dqput(transfer_to[disc]);
-		}
-		if (transfer_from[disc] != NODQUOT) {
+		if (transfer_from[disc] != NODQUOT)
 			unlock_dquot(transfer_from[disc]);
-			dqput(transfer_from[disc]);
-		}
+		/* dqput() tests for NODQUOT itself... */
+		dqput(transfer_from[disc]);
+		dqput(transfer_to[disc]);
 	}
 	return error;
 }
@@ -1513,6 +1532,7 @@
 	error = -EINVAL;
 	if (inode->i_size == 0 || (inode->i_size % sizeof(struct dqblk)) != 0)
 		goto out_f;
+	dquot_drop(inode);	/* We don't want quota on quota files */
 
 	set_enable_flags(vfsmnt, type);
 	mnt_dquot->files[type] = f;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ext2/balloc.c linux.14p16/fs/ext2/balloc.c
--- linux.vanilla/fs/ext2/balloc.c	Sat Aug 14 02:27:37 1999
+++ linux.14p16/fs/ext2/balloc.c	Thu Dec  9 15:32:40 1999
@@ -603,6 +603,8 @@
 		unlock_super (sb);
 		return 0;
 	}
+	if (!buffer_uptodate(bh))
+		wait_on_buffer(bh);
 	memset(bh->b_data, 0, sb->s_blocksize);
 	mark_buffer_uptodate(bh, 1);
 	mark_buffer_dirty(bh, 1);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ext2/file.c linux.14p16/fs/ext2/file.c
--- linux.vanilla/fs/ext2/file.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/fs/ext2/file.c	Mon Dec 13 21:10:58 1999
@@ -131,7 +131,7 @@
 	if (offset != file->f_pos) {
 		file->f_pos = offset;
 		file->f_reada = 0;
-		file->f_version = ++event;
+		file->f_version = ++global_event;
 	}
 	return offset;
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ext2/fsync.c linux.14p16/fs/ext2/fsync.c
--- linux.vanilla/fs/ext2/fsync.c	Wed May 20 21:09:12 1998
+++ linux.14p16/fs/ext2/fsync.c	Thu Dec  9 15:32:40 1999
@@ -45,10 +45,21 @@
 	if (!bh)
 		return 0;
 	if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
-		brelse (bh);
-		return -1;
+		/* There can be a parallell read(2) that started read-I/O
+		   on the buffer so we can't assume that there's been
+		   an I/O error without first waiting I/O completation. */
+		wait_on_buffer(bh);
+		if (!buffer_uptodate(bh))
+		{
+			brelse (bh);
+			return -1;
+		}
 	}
 	if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
+		if (wait)
+			/* when we return from fsync all the blocks
+			   must be _just_ stored on disk */
+			wait_on_buffer(bh);
 		brelse (bh);
 		return 0;
 	}
@@ -68,10 +79,21 @@
 	if (!bh)
 		return 0;
 	if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
-		brelse (bh);
-		return -1;
+		/* There can be a parallell read(2) that started read-I/O
+		   on the buffer so we can't assume that there's been
+		   an I/O error without first waiting I/O completation. */
+		wait_on_buffer(bh);
+		if (!buffer_uptodate(bh))
+		{
+			brelse (bh);
+			return -1;
+		}
 	}
 	if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
+		if (wait)
+			/* when we return from fsync all the blocks
+			   must be _just_ stored on disk */
+			wait_on_buffer(bh);
 		brelse (bh);
 		return 0;
 	}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ext2/ialloc.c linux.14p16/fs/ext2/ialloc.c
--- linux.vanilla/fs/ext2/ialloc.c	Tue Oct 20 22:08:14 1998
+++ linux.14p16/fs/ext2/ialloc.c	Thu Dec  9 15:32:40 1999
@@ -268,21 +268,6 @@
 }
 
 /*
- * This function increments the inode version number
- *
- * This may be used one day by the NFS server
- */
-static void inc_inode_version (struct inode * inode,
-			       struct ext2_group_desc *gdp,
-			       int mode)
-{
-	inode->u.ext2_i.i_version++;
-	mark_inode_dirty(inode);
-
-	return;
-}
-
-/*
  * There are two policies for allocating an inode.  If the new inode is
  * a directory, then a forward search is made for a block group with both
  * free space and a low directory-to-inode ratio; if that fails, then of
@@ -493,8 +478,9 @@
 	if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
 		inode->i_flags |= MS_SYNCHRONOUS;
 	insert_inode_hash(inode);
+	inode->i_generation = inode_generation_count++;
+	inode->u.ext2_i.i_version = inode->i_generation;
 	mark_inode_dirty(inode);
-	inc_inode_version (inode, gdp, mode);
 
 	unlock_super (sb);
 	if(DQUOT_ALLOC_INODE(sb, inode)) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ext2/inode.c linux.14p16/fs/ext2/inode.c
--- linux.vanilla/fs/ext2/inode.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/fs/ext2/inode.c	Mon Dec 13 20:58:38 1999
@@ -51,6 +51,10 @@
 	    inode->i_ino == EXT2_ACL_DATA_INO)
 		return;
 	inode->u.ext2_i.i_dtime	= CURRENT_TIME;
+	/* When we delete an inode, we increment its i_version. If it
+	   is ever read in from disk again, it will have a different
+	   i_version. */
+	inode->u.ext2_i.i_version++;
 	mark_inode_dirty(inode);
 	ext2_update_inode(inode, IS_SYNC(inode));
 	inode->i_size = 0;
@@ -121,6 +125,8 @@
 				    "cannot get block %lu", result);
 			return 0;
 		}
+		if (!buffer_uptodate(bh))
+			wait_on_buffer(bh);
 		memset(bh->b_data, 0, inode->i_sb->s_blocksize);
 		mark_buffer_uptodate(bh, 1);
 		mark_buffer_dirty(bh, 1);
@@ -515,7 +521,7 @@
 	inode->u.ext2_i.i_dtime = le32_to_cpu(raw_inode->i_dtime);
 	inode->i_blksize = PAGE_SIZE;	/* This is the optimal IO size (for stat), not the fs block size */
 	inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
-	inode->i_version = ++event;
+	inode->i_version = ++global_event;
 	inode->u.ext2_i.i_new_inode = 0;
 	inode->u.ext2_i.i_flags = le32_to_cpu(raw_inode->i_flags);
 	inode->u.ext2_i.i_faddr = le32_to_cpu(raw_inode->i_faddr);
@@ -538,6 +544,7 @@
 #endif
 	}
 	inode->u.ext2_i.i_version = le32_to_cpu(raw_inode->i_version);
+	inode->i_generation = inode->u.ext2_i.i_version;
 	inode->u.ext2_i.i_block_group = block_group;
 	inode->u.ext2_i.i_next_alloc_block = 0;
 	inode->u.ext2_i.i_next_alloc_goal = 0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ext2/ioctl.c linux.14p16/fs/ext2/ioctl.c
--- linux.vanilla/fs/ext2/ioctl.c	Sat Aug 14 02:27:37 1999
+++ linux.14p16/fs/ext2/ioctl.c	Thu Dec  9 15:32:40 1999
@@ -76,6 +76,7 @@
 			return -EROFS;
 		if (get_user(inode->u.ext2_i.i_version, (int *) arg))
 			return -EFAULT;	
+		inode->i_generation = inode->u.ext2_i.i_version;
 		inode->i_ctime = CURRENT_TIME;
 		mark_inode_dirty(inode);
 		return 0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ext2/namei.c linux.14p16/fs/ext2/namei.c
--- linux.vanilla/fs/ext2/namei.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/fs/ext2/namei.c	Mon Dec 13 21:11:46 1999
@@ -301,7 +301,7 @@
 			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 			dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
 			mark_inode_dirty(dir);
-			dir->i_version = ++event;
+			dir->i_version = ++global_event;
 			mark_buffer_dirty(bh, 1);
 			*res_dir = de;
 			*err = 0;
@@ -383,7 +383,7 @@
 	if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
 				      EXT2_FEATURE_INCOMPAT_FILETYPE))
 		de->file_type = EXT2_FT_REG_FILE;
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -412,7 +412,7 @@
 	if (!bh)
 		goto out_no_entry;
 	de->inode = cpu_to_le32(inode->i_ino);
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	if (S_ISREG(inode->i_mode)) {
 		inode->i_op = &ext2_file_inode_operations;
 		if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
@@ -511,7 +511,7 @@
 	if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
 				      EXT2_FEATURE_INCOMPAT_FILETYPE))
 		de->file_type = EXT2_FT_DIR;
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -619,7 +619,7 @@
 		goto end_rmdir;
 
 	retval = ext2_delete_entry (de, bh);
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	if (retval)
 		goto end_rmdir;
 	mark_buffer_dirty(bh, 1);
@@ -631,7 +631,7 @@
 		ext2_warning (inode->i_sb, "ext2_rmdir",
 			      "empty directory has nlink!=2 (%d)",
 			      inode->i_nlink);
-	inode->i_version = ++event;
+	inode->i_version = ++global_event;
 	inode->i_nlink = 0;
 	inode->i_size = 0;
 	mark_inode_dirty(inode);
@@ -674,7 +674,7 @@
 	retval = ext2_delete_entry (de, bh);
 	if (retval)
 		goto end_unlink;
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -747,7 +747,7 @@
 	if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
 				      EXT2_FEATURE_INCOMPAT_FILETYPE))
 		de->file_type = EXT2_FT_SYMLINK;
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -800,7 +800,7 @@
 		else if (S_ISFIFO(inode->i_mode))  
 			de->file_type = EXT2_FT_FIFO;
 	}
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -880,7 +880,7 @@
 		if (!new_bh)
 			goto end_rename;
 	}
-	new_dir->i_version = ++event;
+	new_dir->i_version = ++global_event;
 
 	/*
 	 * Like most other Unix systems, set the ctime for inodes on a
@@ -899,7 +899,7 @@
 	
 	ext2_delete_entry (old_de, old_bh);
 
-	old_dir->i_version = ++event;
+	old_dir->i_version = ++global_event;
 	if (new_inode) {
 		new_inode->i_nlink--;
 		new_inode->i_ctime = CURRENT_TIME;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/fat/dir.c linux.14p16/fs/fat/dir.c
--- linux.vanilla/fs/fat/dir.c	Sat Aug 14 02:27:37 1999
+++ linux.14p16/fs/fat/dir.c	Tue Dec 21 00:28:18 1999
@@ -265,12 +265,12 @@
 	}
 
 Found:
-	fat_brelse(sb, bh);
 	res = long_slots + 1;
 	*spos = cpos - sizeof(struct msdos_dir_entry);
 	*lpos = cpos - res*sizeof(struct msdos_dir_entry);
 	MSDOS_I(inode)->i_last_pos = cpos;
 exit:
+	fat_brelse(sb, bh);
 	if (unicode) {
 		free_page((unsigned long) unicode);
 	}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/fat/inode.c linux.14p16/fs/fat/inode.c
--- linux.vanilla/fs/fat/inode.c	Sat Aug 28 20:00:58 1999
+++ linux.14p16/fs/fat/inode.c	Mon Dec 13 21:33:23 1999
@@ -370,7 +370,7 @@
 	MSDOS_I(inode)->i_fat_inode = inode;
 	inode->i_uid = MSDOS_SB(sb)->options.fs_uid;
 	inode->i_gid = MSDOS_SB(sb)->options.fs_gid;
-	inode->i_version = ++event;
+	inode->i_version = ++global_event;
 	MSDOS_I(inode)->i_last_pos = 0;
 	inode->i_mode = (S_IRWXUGO & ~MSDOS_SB(sb)->options.fs_umask) | S_IFDIR;
 	inode->i_op = MSDOS_SB(sb)->dir_ops;
@@ -759,7 +759,7 @@
 	MSDOS_I(inode)->i_fat_inode = inode;
 	inode->i_uid = MSDOS_SB(sb)->options.fs_uid;
 	inode->i_gid = MSDOS_SB(sb)->options.fs_gid;
-	inode->i_version = ++event;
+	inode->i_version = ++global_event;
 	if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) {
 		MSDOS_I(inode)->i_last_pos = 0;
 		inode->i_mode = MSDOS_MKMODE(de->attr,S_IRWXUGO &
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/file_table.c linux.14p16/fs/file_table.c
--- linux.vanilla/fs/file_table.c	Tue Feb 23 23:30:59 1999
+++ linux.14p16/fs/file_table.c	Mon Dec 13 20:54:09 1999
@@ -80,7 +80,7 @@
 	new_one:
 		memset(f, 0, sizeof(*f));
 		f->f_count = 1;
-		f->f_version = ++event;
+		f->f_version = ++global_event;
 		f->f_uid = current->fsuid;
 		f->f_gid = current->fsgid;
 		put_inuse(f);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/filesystems.c linux.14p16/fs/filesystems.c
--- linux.vanilla/fs/filesystems.c	Sat Aug 14 02:27:37 1999
+++ linux.14p16/fs/filesystems.c	Thu Dec  9 15:32:39 1999
@@ -37,6 +37,7 @@
 #endif
 #include <linux/lockd/bind.h>
 #include <linux/lockd/xdr.h>
+#include <linux/lockd/syscall.h>
 #include <linux/init.h>
 #include <linux/nls.h>
 
@@ -159,28 +160,48 @@
 #ifdef CONFIG_NFSD_MODULE
 int (*do_nfsservctl)(int, void *, void *) = NULL;
 #endif
+
+#ifdef CONFIG_LOCKD_MODULE
+int (*do_lockdctl)(int, void *, void *) = NULL;
+#endif
+
 int
 asmlinkage sys_nfsservctl(int cmd, void *argp, void *resp)
 {
-#ifndef CONFIG_NFSD_MODULE
-	return -ENOSYS;
-#else
 	int ret = -ENOSYS;
 	
+	if (cmd >= NFSCTL_LOCKD) {
+#if defined(CONFIG_LOCKD) || defined(CONFIG_LOCKD_MODULE)
+		lock_kernel();
+#ifdef CONFIG_LOCKD
+		ret = lockdctl(cmd, argp, resp);
+#else
+		if (do_lockdctl) 
+			ret = do_lockdctl(cmd, argp, resp);
+#ifdef CONFIG_KMOD
+		else if (request_module ("lockd") == 0) {
+			if (do_lockdctl)
+				ret = do_lockdctl(cmd, argp, resp);
+		}
+#endif
+#endif
+		unlock_kernel();
+#endif
+		return ret;
+	}
+
+#ifdef CONFIG_NFSD_MODULE
 	lock_kernel();
-	if (do_nfsservctl) {
+	if (do_nfsservctl)
 		ret = do_nfsservctl(cmd, argp, resp);
-		goto out;
-	}
 #ifdef CONFIG_KMOD
-	if (request_module ("nfsd") == 0) {
+	else if (request_module ("nfsd") == 0) {
 		if (do_nfsservctl)
 			ret = do_nfsservctl(cmd, argp, resp);
 	}
 #endif /* CONFIG_KMOD */
-out:
 	unlock_kernel();
-	return ret;
 #endif /* CONFIG_NFSD_MODULE */
+	return ret;
 }
 #endif /* CONFIG_NFSD */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/hfs/dir.c linux.14p16/fs/hfs/dir.c
--- linux.vanilla/fs/hfs/dir.c	Sat Aug 14 02:25:43 1999
+++ linux.14p16/fs/hfs/dir.c	Mon Dec 13 21:36:19 1999
@@ -88,7 +88,7 @@
 					++(tmp->i_nlink);
 				}
 				tmp->i_size += HFS_I(tmp)->dir_size;
-				tmp->i_version = ++event;
+				tmp->i_version = ++global_event;
 			}
 			tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;
 			mark_inode_dirty(tmp);
@@ -118,7 +118,7 @@
 					--(tmp->i_nlink);
 				}
 				tmp->i_size -= HFS_I(tmp)->dir_size;
-				tmp->i_version = ++event;
+				tmp->i_version = ++global_event;
 			}
 			tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;
 			mark_inode_dirty(tmp);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/hfs/file_hdr.c linux.14p16/fs/hfs/file_hdr.c
--- linux.vanilla/fs/hfs/file_hdr.c	Sat Aug 14 02:26:32 1999
+++ linux.14p16/fs/hfs/file_hdr.c	Thu Dec  9 15:32:44 1999
@@ -164,10 +164,10 @@
 	__constant_htonl(HFS_HDR_VERSION_1),	/* version */
 	5,					/* entries */
 	{					/* descr[] */
-		{HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
-		{HFS_HDR_COMNT, offsetof(struct hfs_dbl_hdr, comment),      0},
-		{HFS_HDR_OLDI,  offsetof(struct hfs_dbl_hdr, create_time), 16},
-		{HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
+		{HFS_HDR_FNAME, offsetof(struct hfs_nat_hdr, real_name),   ~0},
+		{HFS_HDR_COMNT, offsetof(struct hfs_nat_hdr, comment),      0},
+		{HFS_HDR_OLDI,  offsetof(struct hfs_nat_hdr, old_info),    16},
+		{HFS_HDR_FINFO, offsetof(struct hfs_nat_hdr, finderinfo),  32},
 		{HFS_HDR_RSRC,  HFS_NAT_HDR_LEN,                           ~0},
 	},
 	{					/* order[] */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/inode.c linux.14p16/fs/inode.c
--- linux.vanilla/fs/inode.c	Sat Aug 14 02:27:37 1999
+++ linux.14p16/fs/inode.c	Thu Dec  9 15:32:39 1999
@@ -10,6 +10,7 @@
 #include <linux/dcache.h>
 #include <linux/init.h>
 #include <linux/quotaops.h>
+#include <linux/random.h>
 
 /*
  * New inode.c implementation.
@@ -48,6 +49,8 @@
 static LIST_HEAD(inode_unused);
 static struct list_head inode_hashtable[HASH_SIZE];
 
+__u32 inode_generation_count = 0;
+
 /*
  * A simple spinlock to protect the list manipulations.
  *
@@ -340,12 +343,11 @@
 	(((inode)->i_count | (inode)->i_state) == 0)
 #define INODE(entry)	(list_entry(entry, struct inode, i_list))
 
-static int free_inodes(void)
+static int __free_inodes(struct list_head * freeable)
 {
-	struct list_head list, *entry, *freeable = &list;
+	struct list_head *entry;
 	int found = 0;
 
-	INIT_LIST_HEAD(freeable);
 	entry = inode_in_use.next;
 	while (entry != &inode_in_use) {
 		struct list_head *tmp = entry;
@@ -358,15 +360,19 @@
 		INIT_LIST_HEAD(&INODE(tmp)->i_hash);
 		list_add(tmp, freeable);
 		list_entry(tmp, struct inode, i_list)->i_state = I_FREEING;
-		found = 1;
+		found++;
 	}
 
-	if (found)
-		dispose_list(freeable);
-
 	return found;
 }
 
+static void free_inodes(void)
+{
+	LIST_HEAD(throw_away);
+	if (__free_inodes(&throw_away))
+		dispose_list(&throw_away);
+}
+
 /*
  * Searches the inodes list for freeable inodes,
  * shrinking the dcache before (and possible after,
@@ -374,6 +380,36 @@
  */
 static void try_to_free_inodes(int goal)
 {
+	static int block;
+	static struct wait_queue * wait_inode_freeing;
+	LIST_HEAD(throw_away);
+	
+	/* We must make sure to not eat the inodes
+	   while the blocker task sleeps otherwise
+	   the blocker task may find none inode
+	   available. */
+	if (block)
+	{
+		struct wait_queue __wait;
+
+		__wait.task = current;
+		add_wait_queue(&wait_inode_freeing, &__wait);
+		for (;;)
+		{
+			/* NOTE: we rely only on the inode_lock to be sure
+			   to not miss the unblock event */
+			current->state = TASK_UNINTERRUPTIBLE;
+			spin_unlock(&inode_lock);
+			schedule();
+			spin_lock(&inode_lock);
+			if (!block)
+				break;
+		}
+		remove_wait_queue(&wait_inode_freeing, &__wait);
+		current->state = TASK_RUNNING;
+	}
+
+	block = 1;
 	/*
 	 * First stry to just get rid of unused inodes.
 	 *
@@ -381,16 +417,18 @@
 	 * to try to shrink the dcache and sync existing
 	 * inodes..
 	 */
-	free_inodes();
-	goal -= inodes_stat.nr_free_inodes;
+	goal -= __free_inodes(&throw_away);
 	if (goal > 0) {
 		spin_unlock(&inode_lock);
-		select_dcache(goal, 0);
-		prune_dcache(goal);
+		prune_dcache(0, goal);
 		spin_lock(&inode_lock);
 		sync_all_inodes();
-		free_inodes();
+		__free_inodes(&throw_away);
 	}
+	if (!list_empty(&throw_away))
+		dispose_list(&throw_away);
+	block = 0;
+	wake_up(&wait_inode_freeing);
 }
 
 /*
@@ -435,6 +473,10 @@
 			inode = list_entry(tmp, struct inode, i_list);
 			return inode;
 		}
+		spin_unlock(&inode_lock);
+		printk(KERN_WARNING
+		       "grow_inodes: inode-max limit reached\n");
+		return NULL;
 	}
 		
 	spin_unlock(&inode_lock);
@@ -465,7 +507,7 @@
 	 * If the allocation failed, do an extensive pruning of 
 	 * the dcache and then try again to free some inodes.
 	 */
-	prune_dcache(inodes_stat.nr_inodes >> 2);
+	prune_dcache(0, inodes_stat.nr_inodes >> 2);
 
 	spin_lock(&inode_lock);
 	free_inodes();
@@ -809,6 +851,10 @@
 	if (max > MAX_INODE)
 		max = MAX_INODE;
 	max_inodes = max;
+
+	/* Get a random number. */
+	get_random_bytes (&inode_generation_count,
+			  sizeof (inode_generation_count));
 }
 
 /* This belongs in file_table.c, not here... */
@@ -844,3 +890,48 @@
     inode->i_atime = CURRENT_TIME;
     mark_inode_dirty (inode);
 }   /*  End Function update_atime  */
+
+/* This function is called by nfsd. */
+struct inode *iget_in_use(struct super_block *sb, unsigned long ino)
+{
+	struct list_head * head = inode_hashtable + hash(sb,ino);
+	struct inode * inode;
+
+	spin_lock(&inode_lock);
+	inode = find_inode(sb, ino, head);
+	if (inode) {
+		spin_unlock(&inode_lock);
+		wait_on_inode(inode);
+	}
+	else
+		inode = get_new_inode (sb, ino, head);
+
+	/* When we get the inode, we have to check if it is in use. We
+	   have to release it if it is not. */
+	if (inode) {
+		spin_lock(&inode_lock);
+		if (inode->i_nlink == 0 && inode->i_count == 1) {
+			--inode->i_count;
+			list_del(&inode->i_hash);
+			INIT_LIST_HEAD(&inode->i_hash);
+			list_del(&inode->i_list);
+			INIT_LIST_HEAD(&inode->i_list);
+			if (list_empty(&inode->i_hash)) {
+				list_del(&inode->i_list);
+				INIT_LIST_HEAD(&inode->i_list);
+				spin_unlock(&inode_lock);
+				clear_inode(inode);
+				spin_lock(&inode_lock);
+				list_add(&inode->i_list, &inode_unused);
+				inodes_stat.nr_free_inodes++;
+			}
+			else if (!(inode->i_state & I_DIRTY)) {
+				list_del(&inode->i_list);
+				list_add(&inode->i_list, &inode_in_use);
+			}
+			inode = NULL;
+		}
+		spin_unlock(&inode_lock);
+	}
+	return inode;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/isofs/inode.c linux.14p16/fs/isofs/inode.c
--- linux.vanilla/fs/isofs/inode.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/fs/isofs/inode.c	Thu Dec  9 15:32:39 1999
@@ -954,7 +954,7 @@
 	printk("isofs_bmap: mapped inode:block %x:%d to block %lu\n",
 		inode->i_ino, block, (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode));
 #endif
-	return (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode);
+	return firstext + ((b_off - offset) >> ISOFS_BUFFER_BITS(inode));
 }
 
 
@@ -1162,8 +1162,7 @@
 	  iso_date(raw_inode->date, high_sierra);
 
 	inode->u.isofs_i.i_first_extent = (isonum_733 (raw_inode->extent) +
-					   isonum_711 (raw_inode->ext_attr_length))
-	  << inode -> i_sb -> u.isofs_sb.s_log_zone_size;
+					   isonum_711 (raw_inode->ext_attr_length));
 
 /* Now test for possible Rock Ridge extensions which will override some of
    these numbers in the inode structure. */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/isofs/rock.c linux.14p16/fs/isofs/rock.c
--- linux.vanilla/fs/isofs/rock.c	Sat Sep 26 00:27:13 1998
+++ linux.14p16/fs/isofs/rock.c	Thu Dec  9 15:32:39 1999
@@ -358,9 +358,10 @@
 #ifdef DEBUG
 	printk("RR CL (%x)\n",inode->i_ino);
 #endif
-	inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location) <<
-		inode -> i_sb -> u.isofs_sb.s_log_zone_size;
-	reloc = iget(inode->i_sb, inode->u.isofs_i.i_first_extent);
+	inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location);
+	reloc = iget(inode->i_sb,
+		     (inode->u.isofs_i.i_first_extent <<
+		      inode -> i_sb -> u.isofs_sb.s_log_zone_size));
 	if (!reloc)
 		goto out;
 	inode->i_mode = reloc->i_mode;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/lockd/lockd_syms.c linux.14p16/fs/lockd/lockd_syms.c
--- linux.vanilla/fs/lockd/lockd_syms.c	Mon Apr  7 19:35:30 1997
+++ linux.14p16/fs/lockd/lockd_syms.c	Thu Dec  9 15:32:43 1999
@@ -23,6 +23,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/lockd.h>
+#include <linux/lockd/syscall.h>
 
 /* Start/stop the daemon */
 EXPORT_SYMBOL(lockd_up);
@@ -34,6 +35,7 @@
 /* NFS server entry points/hooks */
 EXPORT_SYMBOL(nlmsvc_invalidate_client);
 EXPORT_SYMBOL(nlmsvc_ops);
+EXPORT_SYMBOL(lockdctl);
 
 /* Configuration at insmod time */
 EXPORT_SYMBOL(nlmsvc_grace_period);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/lockd/mon.c linux.14p16/fs/lockd/mon.c
--- linux.vanilla/fs/lockd/mon.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/fs/lockd/mon.c	Thu Dec  9 15:32:43 1999
@@ -195,6 +195,12 @@
 #define SM_my_id_sz	(3+1+SM_my_name_sz)
 #define SM_mon_id_sz	(1+XDR_QUADLEN(20)+SM_my_id_sz)
 #define SM_mon_sz	(SM_mon_id_sz+4)
+#define SM_monres_sz	2
+#define SM_unmonres_sz	1
+
+#ifndef MAX
+# define MAX(a, b)	(((a) > (b))? (a) : (b))
+#endif
 
 static struct rpc_procinfo	nsm_procedures[] = {
         { "sm_null",
@@ -205,10 +211,10 @@
 		(kxdrproc_t) xdr_error, 0, 0 },
         { "sm_mon",
 		(kxdrproc_t) xdr_encode_mon,
-		(kxdrproc_t) xdr_decode_stat_res, SM_mon_sz, 2 },
+		(kxdrproc_t) xdr_decode_stat_res, MAX(SM_mon_sz, SM_monres_sz) << 2, 0 },
         { "sm_unmon",
 		(kxdrproc_t) xdr_encode_mon,
-		(kxdrproc_t) xdr_decode_stat, SM_mon_id_sz, 1 },
+		(kxdrproc_t) xdr_decode_stat, MAX(SM_mon_id_sz, SM_unmonres_sz) << 2, 0 },
         { "sm_unmon_all",
 		(kxdrproc_t) xdr_error,
 		(kxdrproc_t) xdr_error, 0, 0 },
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/lockd/svc.c linux.14p16/fs/lockd/svc.c
--- linux.vanilla/fs/lockd/svc.c	Sat Feb  6 20:46:21 1999
+++ linux.14p16/fs/lockd/svc.c	Thu Dec  9 15:32:43 1999
@@ -32,6 +32,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/svcsock.h>
 #include <linux/lockd/lockd.h>
+#include <linux/lockd/syscall.h>
 #include <linux/nfs.h>
 
 #define NLMDBG_FACILITY		NLMDBG_SVC
@@ -315,6 +316,9 @@
   MODULE_PARM(nlm_grace_period, "10-240l");
   MODULE_PARM(nlm_timeout, "3-20l");
 #endif
+
+extern int (*do_lockdctl)(int, void *, void *);
+
 int
 init_module(void)
 {
@@ -324,6 +328,7 @@
 	nlmsvc_pid = 0;
 	lockd_exit = NULL;
 	nlmxdr_init();
+	do_lockdctl = lockdctl;
 	return 0;
 }
 
@@ -332,6 +337,7 @@
 {
 	/* FIXME: delete all NLM clients */
 	nlm_shutdown_hosts();
+	do_lockdctl = NULL;
 }
 #endif
 
@@ -370,3 +376,23 @@
 	"lockd",		/* service name */
 	&nlmsvc_stats,		/* stats table */
 };
+
+int
+lockdctl(int cmd, void *opaque_argp, void *opaque_resp)
+{
+	int err;
+
+	MOD_INC_USE_COUNT;
+
+	switch(cmd) {
+	case LOCKDCTL_SVC:
+		err = lockd_up ();
+		break;
+	default:
+		err = -EINVAL;
+	}
+
+	MOD_DEC_USE_COUNT;
+
+	return err;
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/locks.c linux.14p16/fs/locks.c
--- linux.vanilla/fs/locks.c	Sat Aug 14 02:27:37 1999
+++ linux.14p16/fs/locks.c	Thu Dec  9 15:32:39 1999
@@ -688,8 +688,11 @@
 
 	if (((start += l->l_start) < 0) || (l->l_len < 0))
 		return (0);
+	fl->fl_end = start + l->l_len - 1;
+	if (l->l_len > 0 && fl->fl_end < 0)
+		return (0);
 	fl->fl_start = start;	/* we record the absolute position */
-	if ((l->l_len == 0) || ((fl->fl_end = start + l->l_len - 1) < 0))
+	if (l->l_len == 0)
 		fl->fl_end = OFFSET_MAX;
 	
 	fl->fl_file = filp;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/minix/namei.c linux.14p16/fs/minix/namei.c
--- linux.vanilla/fs/minix/namei.c	Sat Aug 14 02:26:51 1999
+++ linux.14p16/fs/minix/namei.c	Mon Dec 13 20:57:06 1999
@@ -194,7 +194,7 @@
 			mark_inode_dirty(dir);
 			for (i = 0; i < info->s_namelen ; i++)
 				de->name[i] = (i < namelen) ? name[i] : 0;
-			dir->i_version = ++event;
+			dir->i_version = ++global_event;
 			mark_buffer_dirty(bh, 1);
 			*res_dir = de;
 			break;
@@ -415,7 +415,7 @@
 	if (inode->i_nlink != 2)
 		printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
 	de->inode = 0;
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_buffer_dirty(bh, 1);
 	inode->i_nlink=0;
 	mark_inode_dirty(inode);
@@ -449,7 +449,7 @@
 		inode->i_nlink=1;
 	}
 	de->inode = 0;
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_buffer_dirty(bh, 1);
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(dir);
@@ -601,10 +601,10 @@
 	new_de->inode = old_inode->i_ino;
 	old_de->inode = 0;
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
-	old_dir->i_version = ++event;
+	old_dir->i_version = ++global_event;
 	mark_inode_dirty(old_dir);
 	new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
-	new_dir->i_version = ++event;
+	new_dir->i_version = ++global_event;
 	mark_inode_dirty(new_dir);
 	if (new_inode) {
 		new_inode->i_nlink--;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/msdos/namei.c linux.14p16/fs/msdos/namei.c
--- linux.vanilla/fs/msdos/namei.c	Sat Aug 14 02:27:37 1999
+++ linux.14p16/fs/msdos/namei.c	Mon Dec 13 20:56:40 1999
@@ -517,7 +517,7 @@
 		if (error)
 			goto out;
 	}
-	new_dir->i_version = ++event;
+	new_dir->i_version = ++global_event;
 
 	/* There we go */
 
@@ -532,7 +532,7 @@
 	else
 		MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
 	mark_inode_dirty(old_inode);
-	old_dir->i_version = ++event;
+	old_dir->i_version = ++global_event;
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(old_dir);
 	if (new_inode) {
@@ -569,7 +569,7 @@
 	else
 		MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
 	mark_inode_dirty(old_inode);
-	old_dir->i_version = ++event;
+	old_dir->i_version = ++global_event;
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(old_dir);
 	return 0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/namei.c linux.14p16/fs/namei.c
--- linux.vanilla/fs/namei.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/fs/namei.c	Thu Dec  9 15:32:39 1999
@@ -246,7 +246,7 @@
 	 * FIXME! This could use version numbering or similar to
 	 * avoid unnecessary cache lookups.
 	 */
-	result = cached_lookup(parent, name, flags);
+	result = d_lookup(parent, name);
 	if (!result) {
 		struct dentry * dentry = d_alloc(parent, name);
 		result = ERR_PTR(-ENOMEM);
@@ -257,8 +257,19 @@
 			else
 				result = dentry;
 		}
+		up(&dir->i_sem);
+		return result;
 	}
+
+	/*
+	 * Uhhuh! Nasty case: the cache was re-populated while
+	 * we waited on the semaphore. Need to revalidate, but
+	 * we're going to return this entry regardless (same
+	 * as if it was busy).
+	 */
 	up(&dir->i_sem);
+	if (result->d_op && result->d_op->d_revalidate)
+		result->d_op->d_revalidate(result, flags);
 	return result;
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfs/dir.c linux.14p16/fs/nfs/dir.c
--- linux.vanilla/fs/nfs/dir.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/fs/nfs/dir.c	Mon Dec 13 18:41:46 1999
@@ -395,13 +395,14 @@
  * If mtime is close to present time, we revalidate
  * more often.
  */
+#define NFS_REVALIDATE_NEGATIVE (1 * HZ)
 static inline int nfs_neg_need_reval(struct dentry *dentry)
 {
-	unsigned long timeout = 30 * HZ;
+	unsigned long timeout = NFS_ATTRTIMEO(dentry->d_parent->d_inode);
 	long diff = CURRENT_TIME - dentry->d_parent->d_inode->i_mtime;
 
-	if (diff < 5*60)
-		timeout = 1 * HZ;
+	if (diff < 5*60 && timeout > NFS_REVALIDATE_NEGATIVE)
+		timeout = NFS_REVALIDATE_NEGATIVE;
 
 	return time_after(jiffies, dentry->d_time + timeout);
 }
@@ -462,12 +463,8 @@
 		goto out_bad;
 
 	/* Filehandle matches? */
-	if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) {
-		if (!list_empty(&dentry->d_subdirs))
-			shrink_dcache_parent(dentry);
-		if (dentry->d_count < 2)
-			goto out_bad;
-	}
+	if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh)))
+		goto out_bad;
 
 	/* Ok, remeber that we successfully checked it.. */
 	nfs_renew_times(dentry);
@@ -476,6 +473,12 @@
 out_valid:
 	return 1;
 out_bad:
+	if (!list_empty(&dentry->d_subdirs))
+		shrink_dcache_parent(dentry);
+	/* If we have submounts, don't unhash ! */
+	if (have_submounts(dentry))
+		goto out_valid;
+	d_drop(dentry);
 	if (dentry->d_parent->d_inode)
 		nfs_invalidate_dircache(dentry->d_parent->d_inode);
 	if (inode && S_ISDIR(inode->i_mode))
@@ -526,29 +529,6 @@
 	NULL			/* d_iput */
 };
 
-#ifdef NFS_PARANOIA
-/*
- * Display all dentries holding the specified inode.
- */
-static void show_dentry(struct list_head * dlist)
-{
-	struct list_head *tmp = dlist;
-
-	while ((tmp = tmp->next) != dlist) {
-		struct dentry * dentry = list_entry(tmp, struct dentry, d_alias);
-		const char * unhashed = "";
-
-		if (list_empty(&dentry->d_hash))
-			unhashed = "(unhashed)";
-
-		printk("show_dentry: %s/%s, d_count=%d%s\n",
-			dentry->d_parent->d_name.name,
-			dentry->d_name.name, dentry->d_count,
-			unhashed);
-	}
-}
-#endif
-
 static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
 {
 	struct inode *inode;
@@ -697,6 +677,8 @@
 	nfs_invalidate_dircache(dir);
 	error = nfs_proc_mkdir(NFS_DSERVER(dentry), NFS_FH(dentry->d_parent),
 				dentry->d_name.name, &sattr, &fhandle, &fattr);
+	if (!error)
+		dir->i_nlink++;
 	return error;
 }
 
@@ -714,8 +696,8 @@
 	/* Update i_nlink and invalidate dentry. */
 	if (!error) {
 		d_drop(dentry);
-		if (dentry->d_inode->i_nlink)
-			dentry->d_inode->i_nlink --;
+		if (dir->i_nlink)
+			dir->i_nlink--;
 	}
 
 	return error;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfs/inode.c linux.14p16/fs/nfs/inode.c
--- linux.vanilla/fs/nfs/inode.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/fs/nfs/inode.c	Mon Dec 13 18:41:46 1999
@@ -134,8 +134,10 @@
 	if ((rpc = server->client) != NULL)
 		rpc_shutdown_client(rpc);
 
+#if 0
 	if (!(server->flags & NFS_MOUNT_NONLM))
 		lockd_down();	/* release rpc.lockd */
+#endif
 	rpciod_down();		/* release rpciod */
 	/*
 	 * Invalidate the dircache for this superblock.
@@ -311,9 +313,11 @@
 	/* We're airborne */
 	unlock_super(sb);
 
+#if 0
 	/* Check whether to start the lockd process */
 	if (!(server->flags & NFS_MOUNT_NONLM))
 		lockd_up();
+#endif
 	return sb;
 
 	/* Yargs. It didn't work out. */
@@ -494,6 +498,48 @@
 }
 
 /*
+ * The following may seem pretty minimal, but the stateless nature
+ * of NFS means that we can't do too much more. Previous attempts to use
+ * fattr->nlink to determine how well the cached state matches the
+ * server suffer from races with stale dentries. You also risk killing
+ * off processes by just doing 'mv file newdir' on the server.
+ *
+ * FIXME: Of course, if 2 exported files have the same fileid (but
+ * different fsid which makes it legal) you're still buggered...
+ *                                      Trond, August 1999.
+ */
+static int
+nfs_inode_is_stale(struct inode *inode, struct nfs_fattr *fattr)
+{
+	int unhashed;
+	int is_stale = 0;
+
+	if (inode->i_mode &&
+	    (fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
+		is_stale = 1;
+
+	if (is_bad_inode(inode))
+		is_stale = 1;
+
+	/*
+	 * Free up unused cached dentries to see if it's wise to unhash
+	 * the inode (which we can do if all the dentries have been unhashed).
+	 */
+	unhashed = nfs_free_dentries(inode);
+
+	/* Assume we're holding 1 lock on the inode from 'iget'
+	 *
+	 * NB: sockets sometimes have volatile file handles
+	 *     don't invalidate their inodes even if all dentries are
+	 *     unhashed. */
+	if (unhashed && inode->i_count == unhashed + 1
+	    && !S_ISSOCK(inode->i_mode) && !S_ISFIFO(inode->i_mode))
+		is_stale = 1;
+
+	return is_stale;
+}
+
+/*
  * This is our own version of iget that looks up inodes by file handle
  * instead of inode number.  We use this technique instead of using
  * the vfs read_inode function because there is no way to pass the
@@ -552,53 +598,26 @@
 static struct inode *
 __nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
 {
-	struct inode *inode;
-	int max_count, stale_inode, unhashed = 0;
+	struct inode *inode = NULL;
 
-retry:
-	inode = iget(sb, fattr->fileid);
-	if (!inode)
+	if (!fattr)
 		goto out_no_inode;
-	/* N.B. This should be impossible ... */
-	if (inode->i_ino != fattr->fileid)
-		goto out_bad_id;
 
-	/*
-	 * Check for busy inodes, and attempt to get rid of any
-	 * unused local references. If successful, we release the
-	 * inode and try again.
-	 *
-	 * Note that the busy test uses the values in the fattr,
-	 * as the inode may have become a different object.
-	 * (We can probably handle modes changes here, too.)
-	 */
-	stale_inode = inode->i_mode &&
-		      ((fattr->mode ^ inode->i_mode) & S_IFMT);
-	stale_inode |= inode->i_count && inode->i_count == unhashed;
-	max_count = S_ISDIR(fattr->mode) ? 1 : fattr->nlink;
-	if (stale_inode || inode->i_count > max_count + unhashed) {
-		dprintk("__nfs_fhget: inode %ld busy, i_count=%d, i_nlink=%d\n",
-			inode->i_ino, inode->i_count, inode->i_nlink);
-		unhashed = nfs_free_dentries(inode);
-		if (stale_inode || inode->i_count > max_count + unhashed) {
-			printk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
-				inode->i_ino, inode->i_count);
-			if (!list_empty(&inode->i_dentry)) {
-				struct dentry *dentry;
-				dentry = list_entry(inode->i_dentry.next,
-						 struct dentry, d_alias);
-				printk("__nfs_fhget: killing %s/%s filehandle\n",
-					dentry->d_parent->d_name.name,
-					dentry->d_name.name);
-				memset(dentry->d_fsdata, 0,
-					sizeof(struct nfs_fh));
-			}
-			remove_inode_hash(inode);
-			nfs_invalidate_inode(inode);
-			unhashed = 0;
-		}
+	while (!inode) {
+		inode = iget(sb, fattr->fileid);
+		if (!inode)
+			goto out_no_inode;
+		/* N.B. This should be impossible ... */
+		if (inode->i_ino != fattr->fileid)
+			goto out_bad_id;
+
+		if (!nfs_inode_is_stale(inode,fattr))
+			break;
+
+		remove_inode_hash(inode);
+		nfs_invalidate_inode(inode);
 		iput(inode);
-		goto retry;
+		inode = NULL;
 	}
 	nfs_fill_inode(inode, fattr);
 	dprintk("NFS: __nfs_fhget(%x/%ld ct=%d)\n",
@@ -753,6 +772,8 @@
 		fh = (u32 *) &fhandle;
 		dfprintk(PAGECACHE, "            %08x%08x%08x%08x%08x%08x%08x%08x\n",
 			fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
+		if (!IS_ROOT(dentry) && !have_submounts(dentry))
+			d_drop(dentry);
 		goto out;
 	}
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfs/mount_clnt.c linux.14p16/fs/nfs/mount_clnt.c
--- linux.vanilla/fs/nfs/mount_clnt.c	Wed Aug 26 18:10:33 1998
+++ linux.14p16/fs/nfs/mount_clnt.c	Thu Dec  9 15:32:40 1999
@@ -23,6 +23,11 @@
 # define NFSDBG_FACILITY	NFSDBG_ROOT
 #endif
 
+#ifndef MAX
+# define MAX(a, b)	(((a) > (b))? (a) : (b))
+#endif
+
+
 /*
 #define MOUNT_PROGRAM		100005
 #define MOUNT_VERSION		1
@@ -119,7 +124,7 @@
 	{ "mnt_mount",
 		(kxdrproc_t) xdr_encode_dirpath,	
 		(kxdrproc_t) xdr_decode_fhstatus,
-		MNT_dirpath_sz, MNT_fhstatus_sz },
+		MAX(MNT_dirpath_sz, MNT_fhstatus_sz)<<2, 0},
 };
 
 static struct rpc_version	mnt_version1 = {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfsd/nfsctl.c linux.14p16/fs/nfsd/nfsctl.c
--- linux.vanilla/fs/nfsd/nfsctl.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/fs/nfsd/nfsctl.c	Thu Dec  9 15:32:43 1999
@@ -11,7 +11,7 @@
 #include <linux/module.h>
 #include <linux/version.h>
 
-#include <linux/linkage.h>
+#include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -29,6 +29,7 @@
 #include <linux/nfsd/cache.h>
 #include <linux/nfsd/xdr.h>
 #include <linux/nfsd/syscall.h>
+#include <linux/lockd/syscall.h>
 
 #if LINUX_VERSION_CODE >= 0x020100
 #include <asm/uaccess.h>
@@ -40,7 +41,6 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 
-extern void nfsd_fh_init(void);
 extern long sys_call_table[];
 
 static int	nfsctl_svc(struct nfsctl_svc *data);
@@ -57,15 +57,72 @@
 int exp_procfs_exports(char *buffer, char **start, off_t offset,
                              int length, int *eof, void *data);
 
-void proc_export_init(void)
+struct long_maxmin
 {
-	struct proc_dir_entry *nfs_export_ent = NULL;
+	long *value;
+	long min_value;
+	long max_value;
+};
+
+/* In seconds. */
+#define TIME_DIFF_MARGIN	10
+#define MIN_TIME_DIFF_MARGIN	0
+#define MAX_TIME_DIFF_MARGIN	600
+
+long nfsd_time_diff_margin = TIME_DIFF_MARGIN;
+
+static struct long_maxmin time_diff_margin =
+{
+	&nfsd_time_diff_margin,
+	MIN_TIME_DIFF_MARGIN,
+	MAX_TIME_DIFF_MARGIN
+};
+
+static int
+nfsd_proc_read_long_maxmin(char *buffer, char **start, off_t offset,
+			  int length, int *eof, void *data)
+{
+	int len;
+	struct long_maxmin *x = (struct long_maxmin *) data;
+	len = sprintf(buffer, "%ld\n", *x->value) - offset;
+	if (len < length) {
+		*eof = 1;
+		if (len <= 0)
+			 return 0;
+	} else
+		len = length;
+	*start = buffer + offset;
+	return len;
+}
+
+static int
+nfsd_proc_write_long_maxmin(struct file *file, const char *buffer,
+			   unsigned long count, void *data)
+{
+	long v;
+	struct long_maxmin *x = (struct long_maxmin *) data;
+	v = simple_strtoul(buffer, NULL, 10);
+	if (v < x->min_value || v > x->max_value)
+		return -EINVAL;
+	*x->value = v;
+	return count;
+}
+
+static void nfsd_proc_init(void)
+{
+	struct proc_dir_entry *nfsd_ent = NULL;
 
-	if (!(nfs_export_ent = create_proc_entry("fs/nfs", S_IFDIR, 0)))
+	if (!(nfsd_ent = create_proc_entry("fs/nfs", S_IFDIR, 0)))
 		return;
-	if (!(nfs_export_ent = create_proc_entry("fs/nfs/exports", 0, 0)))
+	if (!(nfsd_ent = create_proc_entry("fs/nfs/exports", 0, 0)))
 		return;
-	nfs_export_ent->read_proc = exp_procfs_exports;
+	nfsd_ent->read_proc = exp_procfs_exports;
+	if (!(nfsd_ent = create_proc_entry("fs/nfs/time-diff-margin",
+					   S_IFREG|S_IRUGO|S_IWUSR, 0)))
+		return;
+	nfsd_ent->read_proc = nfsd_proc_read_long_maxmin;
+	nfsd_ent->write_proc = nfsd_proc_write_long_maxmin;
+	nfsd_ent->data = (void *) &time_diff_margin;
 }
 
 
@@ -80,8 +137,7 @@
 	nfsd_cache_init();	/* RPC reply cache */
 	nfsd_export_init();	/* Exports table */
 	nfsd_lockd_init();	/* lockd->nfsd callbacks */
-	nfsd_fh_init();		/* FH table */
-	proc_export_init();
+	nfsd_proc_init();
 	initialized = 1;
 }
 
@@ -209,6 +265,11 @@
 		goto done;
 	}
 
+	if (cmd >= NFSCTL_LOCKD) {
+		err = lockdctl(cmd, argp, resp);
+		goto done;
+	}
+
 	switch(cmd) {
 	case NFSCTL_SVC:
 		err = nfsctl_svc(&arg->ca_svc);
@@ -303,6 +364,7 @@
 	nfsd_export_shutdown();
 	nfsd_cache_shutdown();
 	nfsd_fh_free();
+	remove_proc_entry("fs/nfs/time-diff-margin", NULL);
 	remove_proc_entry("fs/nfs/exports", NULL);
 	remove_proc_entry("fs/nfs", NULL);
 	nfsd_stat_shutdown();
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfsd/nfsfh.c linux.14p16/fs/nfsd/nfsfh.c
--- linux.vanilla/fs/nfsd/nfsfh.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/fs/nfsd/nfsfh.c	Thu Dec  9 15:32:43 1999
@@ -22,6 +22,7 @@
 #define NFSDDBG_FACILITY		NFSDDBG_FH
 #define NFSD_PARANOIA 1
 /* #define NFSD_DEBUG_VERBOSE 1 */
+/* #define NFSD_DEBUG_VERY_VERBOSE 1 */
 
 extern unsigned long max_mapnr;
 
@@ -34,16 +35,16 @@
 	kdev_t	dev;
 };
 
-#define NFSD_MAXFH PAGE_SIZE/sizeof(struct fh_entry)
-static struct fh_entry filetable[NFSD_MAXFH];
-static struct fh_entry dirstable[NFSD_MAXFH];
+#define NFSD_MAXFH \
+  (((nfsd_nservers + 1) >> 1) * PAGE_SIZE/sizeof(struct fh_entry))
+static struct fh_entry *filetable = NULL;
+static struct fh_entry *dirstable = NULL;
 
 static int nfsd_nr_verified = 0;
 static int nfsd_nr_put = 0;
 static unsigned long nfsd_next_expire = 0;
 
 static int add_to_fhcache(struct dentry *, int);
-static int nfsd_d_validate(struct dentry *);
 struct dentry * lookup_inode(kdev_t, ino_t, ino_t);
 
 static LIST_HEAD(fixup_head);
@@ -51,15 +52,16 @@
 static int nfsd_nr_fixups = 0;
 static int nfsd_nr_paths = 0;
 #define NFSD_MAX_PATHS 500
-#define NFSD_MAX_FIXUPAGE 60*HZ
+#define NFSD_MAX_FIXUPS 500
+#define NFSD_MAX_FIXUP_AGE 30*HZ
 
 struct nfsd_fixup {
 	struct list_head lru;
-	ino_t	dir;
+	unsigned long reftime;
+	ino_t	dirino;
 	ino_t	ino;
 	kdev_t	dev;
-	struct dentry *dentry;
-	unsigned long reftime;
+	ino_t	new_dirino;
 };
 
 struct nfsd_path {
@@ -71,7 +73,8 @@
 	char	name[1];
 };
 
-static struct nfsd_fixup * find_cached_lookup(kdev_t dev, ino_t dir, ino_t ino)
+static struct nfsd_fixup *
+find_cached_lookup(kdev_t dev, ino_t dirino, ino_t ino)
 {
 	struct list_head *tmp = fixup_head.next;
 
@@ -79,32 +82,43 @@
 		struct nfsd_fixup *fp;
 
 		fp = list_entry(tmp, struct nfsd_fixup, lru);
+#ifdef NFSD_DEBUG_VERY_VERBOSE
+printk("fixup %lu %lu, %lu %lu %s %s\n",
+        fp->ino, ino,
+	fp->dirino, dirino,
+	kdevname(fp->dev), kdevname(dev));
+#endif
 		if (fp->ino != ino)
 			continue;
-		if (fp->dir != dir)
+		if (fp->dirino != dirino)
 			continue;
 		if (fp->dev != dev)
 			continue;
+		fp->reftime = jiffies;	
 		list_del(tmp);
 		list_add(tmp, &fixup_head);
-		fp->reftime = jiffies;
 		return fp;
 	}
 	return NULL;
 }
 
 /*
- * Save the dentry pointer from a successful lookup.
+ * Save the dirino from a rename.
  */
-static void add_to_lookup_cache(struct dentry *dentry, struct knfs_fh *fh)
+void
+add_to_rename_cache(ino_t new_dirino,
+                    kdev_t dev, ino_t dirino, ino_t ino)
 {
 	struct nfsd_fixup *fp;
 
-	fp = find_cached_lookup(u32_to_kdev_t(fh->fh_dev), 
-				u32_to_ino_t(fh->fh_dirino),
-				u32_to_ino_t(fh->fh_ino));
+	if (dirino == new_dirino)
+		return;
+
+	fp = find_cached_lookup(dev, 
+				dirino,
+				ino);
 	if (fp) {
-		fp->dentry = dentry;
+		fp->new_dirino = new_dirino;
 		return;
 	}
 
@@ -115,19 +129,30 @@
 	 */
 	fp = kmalloc(sizeof(struct nfsd_fixup), GFP_KERNEL);
 	if (fp) {
-		fp->dir = u32_to_kdev_t(fh->fh_dirino);
-		fp->ino = u32_to_ino_t(fh->fh_ino);
-		fp->dev = u32_to_ino_t(fh->fh_dev);
-		fp->dentry = dentry;
-		fp->reftime = jiffies;
+		fp->dirino = dirino;
+		fp->ino = ino;
+		fp->dev = dev;
+		fp->new_dirino = new_dirino;
 		list_add(&fp->lru, &fixup_head);
 		nfsd_nr_fixups++;
 	}
 }
 
+/*
+ * Save the dentry pointer from a successful lookup.
+ */
+
 static void free_fixup_entry(struct nfsd_fixup *fp)
 {
 	list_del(&fp->lru);
+#ifdef NFSD_DEBUG_VERY_VERBOSE
+printk("free_rename_entry: %lu->%lu %lu/%s\n",
+		fp->dirino,
+		fp->new_dirino,
+		fp->ino,
+		kdevname(fp->dev),
+		(jiffies - fp->reftime));
+#endif
 	kfree(fp);
 	nfsd_nr_fixups--;
 }
@@ -212,9 +237,9 @@
 	if (new) {
 		new->users = 0;	
 		new->reftime = jiffies;	
-		new->ino = inode->i_ino;	
-		new->dev = inode->i_dev;	
-		result = copy_path(new->name, dentry, len);	
+		new->ino = inode->i_ino;
+		new->dev = inode->i_dev;
+		result = copy_path(new->name, dentry, len);
 		if (!result)
 			goto retry;
 		list_add(&new->lru, &path_inuse);
@@ -301,8 +326,8 @@
 	int result = 0;
 
 	buf->sequence++;
-#ifdef NFSD_DEBUG_VERBOSE
-printk("filldir_one: seq=%d, ino=%ld, name=%s\n", buf->sequence, ino, name);
+#ifdef NFSD_DEBUG_VERY_VERBOSE
+printk("filldir_one: seq=%d, ino=%lu, name=%s\n", buf->sequence, ino, name);
 #endif
 	if (buf->sequence == 2) {
 		buf->dirino = ino;
@@ -311,7 +336,7 @@
 	if (dirent->ino == ino) {
 		dirent->len = len;
 		memcpy(dirent->name, name, len);
-		dirent->name[len] = 0;
+		dirent->name[len] = '\0';
 		buf->found = 1;
 		result = -1;
 	}
@@ -431,7 +456,7 @@
 		}
 
 		result = ERR_PTR(-ENOENT);
-		dir = iget(sb, dirino);
+		dir = iget_in_use(sb, dirino);
 		if (!dir)
 			goto out_root;
 		dentry = d_alloc_root(dir, NULL);
@@ -483,7 +508,7 @@
 	iput(dir);
 out_root:
 	dput(root);
-	goto out;
+	goto out_page;
 }
 
 /*
@@ -521,7 +546,8 @@
 	struct dentry *dentry = empty->dentry;
 
 #ifdef NFSD_DEBUG_VERBOSE
-printk("expire_fhe: expiring %s/%s, d_count=%d, ino=%ld\n",
+printk("expire_fhe: expiring %s %s/%s, d_count=%d, ino=%lu\n",
+(cache == NFSD_FILE_CACHE) ? "file" : "dir",
 dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count,empty->ino);
 #endif
 	empty->dentry = NULL;	/* no dentry */
@@ -576,11 +602,10 @@
  */
 static void expire_old(int cache, int age)
 {
-	struct list_head *tmp;
 	struct fh_entry *fhe;
 	int i;
 
-#ifdef NFSD_DEBUG_VERBOSE
+#ifdef NFSD_DEBUG_VERY_VERBOSE
 printk("expire_old: expiring %s older than %d\n",
 (cache == NFSD_FILE_CACHE) ? "file" : "dir", age);
 #endif
@@ -593,12 +618,12 @@
 	}
 
 	/*
-	 * Remove old entries from the patch-up cache.
+	 * Trim the fixup cache ...
 	 */
-	while ((tmp = fixup_head.prev) != &fixup_head) {
+	while (nfsd_nr_fixups > NFSD_MAX_FIXUPS) {
 		struct nfsd_fixup *fp;
-		fp = list_entry(tmp, struct nfsd_fixup, lru);
-		if ((jiffies - fp->reftime) < NFSD_MAX_FIXUPAGE)
+		fp = list_entry(fixup_head.prev, struct nfsd_fixup, lru);
+		if ((jiffies - fp->reftime) < NFSD_MAX_FIXUP_AGE)
 			break;
 		free_fixup_entry(fp);
 	}
@@ -736,15 +761,21 @@
 					dget(dentry);
 					nfsd_nr_verified++;
 				}
+				put_path(pe);
 			} else {
 				dput(res);
+				put_path(pe);
+				/* We should delete it from the cache. */
+				free_path_entry(pe);
 			}
 		} else {
 #ifdef NFSD_PARANOIA
 printk("find_dentry_by_ino: %s lookup failed\n", pe->name);
 #endif
+			put_path(pe);
+			/* We should delete it from the cache. */
+			free_path_entry(pe);
 		}
-		put_path(pe);
 	}
 out:
 	return dentry;
@@ -757,6 +788,8 @@
  */
 static struct dentry *find_dentry_in_fhcache(struct knfs_fh *fh)
 {
+/* FIXME: this must use the dev/ino/dir_ino triple. */ 
+#if 0
 	struct fh_entry * fhe;
 
 	fhe = find_fhe(fh->fh_dcookie, NFSD_FILE_CACHE, NULL);
@@ -794,6 +827,7 @@
 		return dentry;
 	}
 out:
+#endif
 	return NULL;
 }
 
@@ -822,7 +856,7 @@
 printk("lookup_by_inode: found %s\n", dirent.name);
 #endif
 
-	dentry = lookup_dentry(dirent.name, dget(parent), 0);
+	dentry = lookup_dentry(dirent.name, parent, 0);
 	if (!IS_ERR(dentry)) {
 		if (dentry->d_inode && dentry->d_inode->i_ino == ino)
 			goto out;
@@ -842,13 +876,12 @@
 	dentry = NULL;
 out:
 	return dentry;
-
 }
 
 /*
  * Search the fix-up list for a dentry from a prior lookup.
  */
-static struct dentry *nfsd_cached_lookup(struct knfs_fh *fh)
+static ino_t nfsd_cached_lookup(struct knfs_fh *fh)
 {
 	struct nfsd_fixup *fp;
 
@@ -856,8 +889,8 @@
 				u32_to_ino_t(fh->fh_dirino),
 				u32_to_ino_t(fh->fh_ino));
 	if (fp)
-		return fp->dentry;
-	return NULL;
+		return fp->new_dirino;
+	return 0;
 }
 
 void
@@ -916,8 +949,12 @@
 static struct dentry *
 find_fh_dentry(struct knfs_fh *fh)
 {
+	struct super_block *sb;
 	struct dentry *dentry, *parent;
+	struct inode * inode;
+	struct list_head *lst;
 	int looked_up = 0, retry = 0;
+	ino_t dirino;
 
 	/*
 	 * Stage 1: Look for the dentry in the short-term fhcache.
@@ -927,50 +964,73 @@
 		nfsdstats.fh_cached++;
 		goto out;
 	}
-
 	/*
-	 * Stage 2: Attempt to validate the dentry in the file handle.
+	 * Stage 2: Attempt to find the inode.
 	 */
-	dentry = fh->fh_dcookie;
+	sb = get_super(fh->fh_dev);
+	if (NULL == sb) {
+		printk("find_fh_dentry: No SuperBlock for device %s.",
+		       kdevname(fh->fh_dev));
+		dentry = NULL;
+		goto out;
+	}
+
+	dirino = u32_to_ino_t(fh->fh_dirino);
+	inode = iget_in_use(sb, fh->fh_ino);
+	if (!inode) {
+		dprintk("find_fh_dentry: No inode found.\n");
+		goto out_five;
+	}
+	goto check;
 recheck:
-	if (nfsd_d_validate(dentry)) {
-		struct inode * dir = dentry->d_parent->d_inode;
+	if (!inode) {
+		dprintk("find_fh_dentry: No inode found.\n");
+		goto out_three;
+	}
+check:
+	for (lst = inode->i_dentry.next;
+	     lst != &inode->i_dentry;
+	     lst = lst->next) {
+		dentry = list_entry(lst, struct dentry, d_alias);
+
+/* if we are looking up a directory then we don't need the parent! */
+		if (!dentry ||
+		    !dentry->d_parent ||
+		    !dentry->d_parent->d_inode) {
+printk("find_fh_dentry: Found a useless inode %lu\n", inode->i_ino);
+			continue;
+		}
+		if (dentry->d_parent->d_inode->i_ino != dirino)
+			continue;
 
-		if (dir->i_ino == u32_to_ino_t(fh->fh_dirino) && 
-		    dir->i_dev == u32_to_kdev_t(fh->fh_dev)) {
-			struct inode * inode = dentry->d_inode;
-			/*
-			 * NFS file handles must always have an inode,
-			 * so we won't accept a negative dentry.
-			 */
-			if (inode && inode->i_ino == u32_to_ino_t(fh->fh_ino)) {
-				dget(dentry);
-#ifdef NFSD_DEBUG_VERBOSE
-printk("find_fh_dentry: validated %s/%s, ino=%ld\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino);
-#endif
-				if (!retry)
-					nfsdstats.fh_valid++;
-				else {
-					nfsdstats.fh_fixup++;
+		dget(dentry);
+		iput(inode);
 #ifdef NFSD_DEBUG_VERBOSE
-printk("find_fh_dentry: retried validation successful\n");
+		printk("find_fh_dentry: Found%s %s/%s filehandle dirino = %lu, %lu\n",
+		       retry ? " Renamed" : "",
+		       dentry->d_parent->d_name.name,
+		       dentry->d_name.name,
+		       dentry->d_parent->d_inode->i_ino,
+		       dirino);
 #endif
-				}
-				goto out;
-			}
-		}
-	}
+		goto out;
+	} /* for inode->i_dentry */
 
 	/*
-	 * Before proceeding to a lookup, check whether we cached a
-	 * prior lookup. If so, try to validate that dentry ...
+	 * Before proceeding to a lookup, check for a rename
 	 */
-	if (!retry && (dentry = nfsd_cached_lookup(fh)) != NULL) {
+	if (!retry && (dirino = nfsd_cached_lookup(fh))) {
+		dprintk("find_fh_dentry: retry with %lu\n", dirino);
 		retry = 1;
 		goto recheck;
 	}
 
+	iput(inode);
+
+	dprintk("find_fh_dentry: dirino not found %lu\n", dirino);
+
+out_three:
+
 	/*
 	 * Stage 3: Look up the dentry based on the inode and parent inode
 	 * numbers. This should work for all Unix-like filesystems.
@@ -983,7 +1043,7 @@
 		struct inode * inode = dentry->d_inode;
 #ifdef NFSD_DEBUG_VERBOSE
 printk("find_fh_dentry: looked up %s/%s\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
+       dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
 		if (inode && inode->i_ino == u32_to_ino_t(fh->fh_ino)) {
 			nfsdstats.fh_lookup++;
@@ -991,7 +1051,7 @@
 		}
 #ifdef NFSD_PARANOIA
 printk("find_fh_dentry: %s/%s lookup mismatch!\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
+       dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
 		dput(dentry);
 	}
@@ -1005,29 +1065,27 @@
 		/*
 		 * ... then search for the inode in the parent directory.
 		 */
+		dget(parent);
 		dentry = lookup_by_inode(parent, u32_to_ino_t(fh->fh_ino));
 		dput(parent);
 		if (dentry)
 			goto out;
 	}
 
+out_five:
+
 	/*
-	 * Stage 5: Search the whole volume.
+	 * Stage 5: Search the whole volume, Yea Right.
 	 */
 #ifdef NFSD_PARANOIA
-printk("find_fh_dentry: %s, %u/%u not found -- need full search!\n",
-kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_dirino, fh->fh_ino);
+printk("find_fh_dentry: %s/%u dir/%u not found!\n",
+       kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_ino, fh->fh_dirino);
 #endif
 	dentry = NULL;
 	nfsdstats.fh_stale++;
 	
 out:
-	if (looked_up && dentry) {
-		add_to_lookup_cache(dentry, fh);
-	}
-
 	expire_all();
-
 	return dentry;
 }
 
@@ -1046,8 +1104,12 @@
 	struct inode	*inode;
 	u32		error = 0;
 
-	dprintk("nfsd: fh_verify(exp %x/%u cookie %p)\n",
-		fh->fh_xdev, fh->fh_xino, fh->fh_dcookie);
+	dprintk("nfsd: fh_verify(exp %s/%u file (%s/%u dir %u)\n",
+		kdevname(fh->fh_xdev),
+		fh->fh_xino,
+		kdevname(fh->fh_dev),
+		fh->fh_ino,
+		fh->fh_dirino);
 
 	if (fhp->fh_dverified)
 		goto check_type;
@@ -1056,10 +1118,13 @@
 	 */
 	error = nfserr_stale;
 	exp = exp_get(rqstp->rq_client,
-			u32_to_kdev_t(fh->fh_xdev),
-			u32_to_ino_t(fh->fh_xino));
-	if (!exp) /* export entry revoked */
+		      u32_to_kdev_t(fh->fh_xdev),
+		      u32_to_ino_t(fh->fh_xino));
+	if (!exp) {
+		/* export entry revoked */
+		nfsdstats.fh_stale++;
 		goto out;
+	}
 
 	/* Check if the request originated from a secure port. */
 	error = nfserr_perm;
@@ -1079,8 +1144,13 @@
 	 */
 	error = nfserr_noent;
 	dentry = find_fh_dentry(fh);
-	if (!dentry)
+	if (!dentry) {
+		goto out;
+	}
+	if (IS_ERR(dentry)) {
+		error = nfserrno(-PTR_ERR(dentry));
 		goto out;
+	}
 
 	/*
 	 * Note:  it's possible the returned dentry won't be the one in the
@@ -1102,6 +1172,35 @@
 check_type:
 	dentry = fhp->fh_dentry;
 	inode = dentry->d_inode;
+	error = nfserr_stale;
+	/* On a heavily loaded SMP machine, more than one identical
+	   requests may run at the same time on different processors.
+	   One thread may get here with unfinished fh after another
+	   thread just fetched the inode. It doesn't make any senses
+	   to check fh->fh_generation here since it has not been set
+	   yet. In that case, we shouldn't send back the stale
+	   filehandle to the client. We use fh->fh_dcookie to indicate
+	   if fh->fh_generation is set or not. If fh->fh_dcookie is
+	   not set, don't return stale filehandle. */
+	if (inode->i_generation != fh->fh_generation) {
+		if (fh->fh_dcookie) {
+			dprintk("fh_verify: Bad version %lu %u %u: 0x%x, 0x%x\n",
+				inode->i_ino,
+				inode->i_generation,
+				fh->fh_generation,
+				type, access);
+			nfsdstats.fh_stale++;
+			goto out;
+		}
+		else {
+			/* We get here when inode is fetched by other
+			   threads. We just use what is in there. */
+			fh->fh_ino = ino_t_to_u32(inode->i_ino);
+			fh->fh_generation = inode->i_generation;
+			fh->fh_dcookie = (struct dentry *)0xfeebbaca;
+			nfsdstats.fh_concurrent++;
+		}
+	}
 	exp = fhp->fh_export;
 	if (type > 0 && (inode->i_mode & S_IFMT) != type) {
 		error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
@@ -1117,9 +1216,10 @@
 	 */
 	error = 0;
 	if (fh->fh_dev != fh->fh_xdev) {
-		printk("fh_verify: Security: export on other device"
-		       " (%d, %d).\n", fh->fh_dev, fh->fh_xdev);
+		printk("fh_verify: Security: export on other device (%s, %s).\n",
+		       kdevname(fh->fh_dev), kdevname(fh->fh_xdev));
 		error = nfserr_stale;
+		nfsdstats.fh_stale++;
 	} else if (exp->ex_dentry != dentry) {
 		struct dentry *tdentry = dentry;
 
@@ -1128,19 +1228,21 @@
 			if (exp->ex_dentry == tdentry)
 				break;
 			/* executable only by root and we can't be root */
-			if (current->fsuid &&
-			    !(tdentry->d_inode->i_uid  &&
-			        (tdentry->d_inode->i_mode & S_IXUSR)) &&
-			    !(tdentry->d_inode->i_gid &&
-			        (tdentry->d_inode->i_mode & S_IXGRP)) &&
-			    !(tdentry->d_inode->i_mode & S_IXOTH) && 
-			    (exp->ex_flags & NFSEXP_ROOTSQUASH)) {
+			if (current->fsuid
+			    && !(tdentry->d_inode->i_uid
+			         && (tdentry->d_inode->i_mode & S_IXUSR))
+			    && !(tdentry->d_inode->i_gid
+				 && (tdentry->d_inode->i_mode & S_IXGRP))
+			    && !(tdentry->d_inode->i_mode & S_IXOTH)
+			    && (exp->ex_flags & NFSEXP_ROOTSQUASH)) {
 				error = nfserr_stale;
+				nfsdstats.fh_stale++;
 dprintk("fh_verify: no root_squashed access.\n");
 			}
 		} while ((tdentry != tdentry->d_parent));
 		if (exp->ex_dentry != tdentry) {
 			error = nfserr_stale;
+			nfsdstats.fh_stale++;
 			printk("nfsd Security: %s/%s bad export.\n",
 			       dentry->d_parent->d_name.name,
 			       dentry->d_name.name);
@@ -1194,6 +1296,7 @@
 	if (inode) {
 		fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
 		fhp->fh_handle.fh_generation = inode->i_generation;
+		fhp->fh_handle.fh_dcookie = (struct dentry *)0xfeebbaca;
 	}
 	fhp->fh_handle.fh_dirino = ino_t_to_u32(parent->d_inode->i_ino);
 	fhp->fh_handle.fh_dev	 = kdev_t_to_u32(parent->d_inode->i_dev);
@@ -1226,7 +1329,8 @@
 		goto out_negative;
 	fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
 	fhp->fh_handle.fh_generation = inode->i_generation;
-out:
+	fhp->fh_handle.fh_dcookie = (struct dentry *)0xfeebbaca;
+ out:
 	return;
 
 out_bad:
@@ -1265,51 +1369,6 @@
 }
 
 /*
- * Verify that the FH dentry is still a valid dentry pointer.
- * After making some preliminary checks, we ask VFS to verify
- * that it is indeed a dentry.
- */
-static int nfsd_d_validate(struct dentry *dentry)
-{
-	unsigned long dent_addr = (unsigned long) dentry;
-	unsigned long min_addr = PAGE_OFFSET;
-	unsigned long max_addr = min_addr + (max_mapnr << PAGE_SHIFT);
-	unsigned long align_mask = 0x0F;
-	unsigned int len;
-	int valid = 0;
-
-	if (dent_addr < min_addr)
-		goto bad_addr;
-	if (dent_addr > max_addr - sizeof(struct dentry))
-		goto bad_addr;
-	if ((dent_addr & ~align_mask) != dent_addr)
-		goto bad_align;
-	if (!kern_addr_valid(dent_addr))
-		goto bad_addr;
-	/*
-	 * Looks safe enough to dereference ...
-	 */
-	len = dentry->d_name.len;
-	if (len > NFS_MAXNAMLEN)
-		goto out;
-	/*
-	 * Note: d_validate doesn't dereference the parent pointer ...
-	 * just combines it with the name hash to find the hash chain.
-	 */
-	valid = d_validate(dentry, dentry->d_parent, dentry->d_name.hash, len);
-
-out:
-	return valid;
-
-bad_addr:
-	printk(KERN_DEBUG "nfsd_d_validate: invalid address %lx\n", dent_addr);
-	goto out;
-bad_align:
-	printk(KERN_DEBUG "nfsd_d_validate: unaligned address %lx\n", dent_addr);
-	goto out;
-}
-
-/*
  * Flush any cached dentries for the specified device
  * or for all devices.
  *
@@ -1338,7 +1397,7 @@
 }
 
 /*
- * Free the dentry and path caches.
+ * Free the rename and path caches.
  */
 void nfsd_fh_free(void)
 {
@@ -1375,18 +1434,33 @@
 
 void nfsd_fh_init(void)
 {
-	/* Sanity check */ 
 	extern void __my_nfsfh_is_too_big(void); 
+
+	if (filetable)
+		return;
+
+	/* Sanity check */ 
 	if (sizeof(struct nfs_fhbase) > 32) 
 		__my_nfsfh_is_too_big(); 
 
+	filetable = kmalloc(sizeof(struct fh_entry) * NFSD_MAXFH,
+			    GFP_KERNEL);
+	dirstable = kmalloc(sizeof(struct fh_entry) * NFSD_MAXFH,
+			    GFP_KERNEL);
+
+	if (filetable == NULL || dirstable == NULL) {
+		printk(KERN_WARNING "nfsd_fh_init : Could not allocate fhcache\n");
+		nfsd_nservers = 0;
+		return;
+	}
+
 	memset(filetable, 0, NFSD_MAXFH*sizeof(struct fh_entry));
 	memset(dirstable, 0, NFSD_MAXFH*sizeof(struct fh_entry));
 	INIT_LIST_HEAD(&path_inuse);
 	INIT_LIST_HEAD(&fixup_head);
 
 	printk(KERN_DEBUG 
-		"nfsd_init: initialized fhcache, entries=%lu\n", NFSD_MAXFH);
+		"nfsd_fh_init : initialized fhcache, entries=%lu\n", NFSD_MAXFH);
 	/*
 	 * Display a warning if the ino_t is larger than 32 bits.
 	 */
@@ -1394,4 +1468,16 @@
 		printk(KERN_INFO 
 			"NFSD: ino_t is %d bytes, using lower 4 bytes\n",
 			sizeof(ino_t));
+}
+
+void
+nfsd_fh_shutdown(void)
+{
+	if (!filetable)
+		return;
+	printk(KERN_DEBUG 
+		"nfsd_fh_shutdown : freeing %ld fhcache entries.\n", NFSD_MAXFH);
+	kfree(filetable);
+	kfree(dirstable);
+	filetable = dirstable = NULL;
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfsd/nfsproc.c linux.14p16/fs/nfsd/nfsproc.c
--- linux.vanilla/fs/nfsd/nfsproc.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/fs/nfsd/nfsproc.c	Thu Dec  9 15:32:43 1999
@@ -270,7 +270,7 @@
 		rdev = (dev_t) size;
 		if (type != S_IFBLK && type != S_IFCHR) {
 			rdev = 0;
-		} else if (type == S_IFCHR && size == ~(u32) 0) {
+		} else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
 			/* If you think you've seen the worst, grok this. */
 			attr->ia_mode = S_IFIFO | mode;
 			type = S_IFIFO;
@@ -288,6 +288,10 @@
 		if (inode && (type != (inode->i_mode & S_IFMT) || 
 		    (is_borc && inode->i_rdev != rdev)))
 			goto out_unlock;
+
+		/* invalidate size because only (type == S_IFREG) has
+		   size. */
+		attr->ia_valid &= ~ATTR_SIZE;
 	}
 	
 	nfserr = 0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfsd/nfssvc.c linux.14p16/fs/nfsd/nfssvc.c
--- linux.vanilla/fs/nfsd/nfssvc.c	Sat Mar 20 20:28:14 1999
+++ linux.14p16/fs/nfsd/nfssvc.c	Thu Dec  9 15:32:43 1999
@@ -5,7 +5,7 @@
  *
  * Authors:	Olaf Kirch (okir@monad.swb.de)
  *
- * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1995-1999 Olaf Kirch <okir@monad.swb.de>
  */
 
 #define __NO_VERSION__
@@ -64,6 +64,11 @@
 	nfsd_nservers = nrservs;
 
 	error = -ENOMEM;
+	nfsd_fh_init();		/* NFS dentry cache */
+	if (nfsd_nservers == 0)
+		goto out;
+	  
+	error = -ENOMEM;
 	nfsd_racache_init();     /* Readahead param cache */
 	if (nfsd_nservers == 0)
 		goto out;
@@ -119,7 +124,9 @@
 		nfssvc_boot = xtime;		/* record boot time */
 		first = 1;
 	}
+#if 0
 	lockd_up();				/* start lockd */
+#endif
 
 	/*
 	 * The main request loop
@@ -177,12 +184,16 @@
 		printk(KERN_WARNING "nfsd: terminating on signal %d\n", signo);
 	}
 
+#if 0
 	/* Release lockd */
 	lockd_down();
+#endif
 	if (!--nfsd_active) {
 		printk("nfsd: last server exiting\n");
 		/* revoke all exports */
 		nfsd_export_shutdown();
+		/* release fhcache */
+		nfsd_fh_shutdown ();
 		/* release read-ahead cache */
 	        nfsd_racache_shutdown();
 	}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfsd/stats.c linux.14p16/fs/nfsd/stats.c
--- linux.vanilla/fs/nfsd/stats.c	Thu Jan  7 17:28:47 1999
+++ linux.14p16/fs/nfsd/stats.c	Thu Dec  9 15:32:43 1999
@@ -32,7 +32,7 @@
 {
 	int	len;
 
-	len = sprintf(buffer, "rc %d %d %d  %d %d %d %d %d\n",
+	len = sprintf(buffer, "rc %d %d %d  %d %d %d %d %d %d\n",
 			nfsdstats.rchits,
 			nfsdstats.rcmisses,
 			nfsdstats.rcnocache,
@@ -40,7 +40,8 @@
 			nfsdstats.fh_valid,
 			nfsdstats.fh_fixup,
 			nfsdstats.fh_lookup,
-			nfsdstats.fh_stale);
+			nfsdstats.fh_stale,
+			nfsdstats.fh_concurrent);
 
 	/* Assume we haven't hit EOF yet. Will be set by svc_proc_read. */
 	*eof = 0;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/nfsd/vfs.c linux.14p16/fs/nfsd/vfs.c
--- linux.vanilla/fs/nfsd/vfs.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/fs/nfsd/vfs.c	Thu Dec  9 15:32:43 1999
@@ -21,7 +21,6 @@
 #include <linux/locks.h>
 #include <linux/fs.h>
 #include <linux/major.h>
-#include <linux/ext2_fs.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
@@ -48,9 +47,15 @@
 
 /* Hack until we have a macro check for mandatory locks. */
 #ifndef IS_ISMNDLK
-#define IS_ISMNDLK(i)	(((i)->i_mode & (S_ISGID|S_IXGRP)) == S_ISGID)
+#define IS_ISMNDLK(i)	(((i)->i_mode & (S_ISGID|S_IXGRP|S_IFMT)) \
+			 == (S_ISGID|S_IFREG))
 #endif
 
+/* Time difference margin in seconds for comparison. It is a
+   dynamically-tunable parameter via /proc/fs/nfs/time-diff-margin.
+ */
+extern long nfsd_time_diff_margin;
+
 /* Check for dir entries '.' and '..' */
 #define isdotent(n, l)	(l < 3 && n[0] == '.' && (l == 1 || n[1] == '.'))
 
@@ -236,8 +241,30 @@
 	inode = dentry->d_inode;
 
 	err = inode_change_ok(inode, iap);
-	if (err)
+	if (err) {
+		/* It is very tricky. When you are not the file owner,
+		   but have the write permission, you should be allowed
+		   to set atime and mtime to the current time on the
+		   server. However, the NFS V2 protocol doesn't support
+		   it. It has been fixed in V3. Here we do this: if the
+		   current server time and atime/mtime are close enough,
+		   we use the current server time. */
+#define CURRENT_TIME_SET	(ATTR_ATIME_SET | ATTR_MTIME_SET)
+		if (iap->ia_mtime == iap->ia_atime
+		    && ((iap->ia_valid & (CURRENT_TIME_SET))
+			== CURRENT_TIME_SET)) {
+			time_t now = CURRENT_TIME;
+			time_t delta = iap->ia_atime - now;
+			if (delta < 0) delta = -delta;
+			if (delta <= nfsd_time_diff_margin) {
+				iap->ia_valid &= ~CURRENT_TIME_SET;
+				goto current_time_ok;
+			}
+		}
 		goto out_nfserr;
+	}
+
+current_time_ok:
 
 	/* The size case is special... */
 	if (iap->ia_valid & ATTR_SIZE) {
@@ -248,15 +275,19 @@
 			if (err)
 				goto out;
 		}
+		DQUOT_INIT(inode);
 		err = get_write_access(inode);
-		if (err)
+		if (err) {
+			DQUOT_DROP(inode);
 			goto out_nfserr;
+		}
 		/* N.B. Should we update the inode cache here? */
 		inode->i_size = iap->ia_size;
 		if (inode->i_op && inode->i_op->truncate)
 			inode->i_op->truncate(inode);
 		mark_inode_dirty(inode);
 		put_write_access(inode);
+		DQUOT_DROP(inode);
 		iap->ia_valid &= ~ATTR_SIZE;
 		iap->ia_valid |= ATTR_MTIME;
 		iap->ia_mtime = CURRENT_TIME;
@@ -554,7 +585,7 @@
 	/* clear setuid/setgid flag after write */
 	if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) {
 		struct iattr	ia;
-		kernel_cap_t	saved_cap;
+		kernel_cap_t	saved_cap = 0;
 
 		ia.ia_valid = ATTR_MODE;
 		ia.ia_mode  = inode->i_mode & ~(S_ISUID | S_ISGID);
@@ -658,10 +689,6 @@
 		if (IS_ERR(dchild))
 			goto out_nfserr;
 		fh_compose(resfhp, fhp->fh_export, dchild);
-		/* Lock the parent and check for errors ... */
-		err = fh_lock_parent(fhp, dchild);
-		if (err)
-			goto out;
 	} else {
 		dchild = resfhp->fh_dentry;
 		if (!fhp->fh_locked)
@@ -670,6 +697,15 @@
 				dentry->d_parent->d_name.name,
 				dentry->d_name.name);
 	}
+	err = nfserr_exist;
+	if (dchild->d_inode)
+		goto out;
+	if (!fhp->fh_locked) {
+		/* Lock the parent and check for errors ... */
+		err = fh_lock_parent(fhp, dchild);
+		if (err)
+			goto out;
+	}
 	/*
 	 * Make sure the child dentry is still negative ...
 	 */
@@ -695,8 +731,7 @@
 	case S_IFCHR:
 	case S_IFBLK:
 		/* The client is _NOT_ required to do security enforcement */
-		if(!capable(CAP_SYS_ADMIN))
-		{
+		if(!capable(CAP_SYS_ADMIN)) {
 			err = -EPERM;
 			goto out;
 		}
@@ -759,7 +794,7 @@
 	struct inode	*inode;
 	struct iattr	newattrs;
 	int		err;
-	kernel_cap_t	saved_cap;
+	kernel_cap_t	saved_cap = 0;
 
 	err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE | MAY_TRUNC);
 	if (err)
@@ -899,6 +934,7 @@
 	/* Compose the fh so the dentry will be freed ... */
 out_compose:
 	fh_compose(resfhp, fhp->fh_export, dnew);
+
 out:
 	return err;
 
@@ -1091,6 +1127,15 @@
 	DQUOT_DROP(tdir);
 
 	nfsd_double_up(&tdir->i_sem, &fdir->i_sem);
+
+	if (!err && odentry->d_inode) {
+		add_to_rename_cache(tdir->i_ino,
+				    odentry->d_inode->i_dev,
+				    fdir->i_ino,
+				    odentry->d_inode->i_ino);
+	} else {
+		printk(": no inode in rename or err: %d.\n", err);
+	}
 	dput(ndentry);
 
 out_dput_old:
@@ -1132,7 +1177,6 @@
 	err = PTR_ERR(rdentry);
 	if (IS_ERR(rdentry))
 		goto out_nfserr;
-
 	if (!rdentry->d_inode) {
 		dput(rdentry);
 		err = nfserr_noent;
@@ -1154,7 +1198,7 @@
 		fh_unlock(fhp);
 
 		dput(rdentry);
-
+		expire_by_dentry(rdentry);
 	} else {
 		/* It's RMDIR */
 		/* See comments in fs/namei.c:do_rmdir */
@@ -1183,6 +1227,7 @@
 		goto out_nfserr;
 	if (EX_ISSYNC(fhp->fh_export))
 		write_inode_now(dirp);
+
 out:
 	return err;
 
@@ -1314,7 +1359,7 @@
 {
 	struct inode	*inode = dentry->d_inode;
 	int		err;
-	kernel_cap_t	saved_cap;
+	kernel_cap_t	saved_cap = 0;
 
 	if (acc == MAY_NOP)
 		return 0;
@@ -1334,7 +1379,7 @@
 		inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
 #endif
 #ifndef CONFIG_NFSD_SUN
-        if (dentry->d_mounts != dentry) {
+	if (dentry->d_mounts != dentry) {
 		return nfserr_perm;
 	}
 #endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ntfs/inode.c linux.14p16/fs/ntfs/inode.c
--- linux.vanilla/fs/ntfs/inode.c	Sat Aug 14 02:25:59 1999
+++ linux.14p16/fs/ntfs/inode.c	Tue Dec 14 16:19:42 1999
@@ -612,7 +612,7 @@
 		return 0;
 
 	for(rnum=0;rnum<data->d.r.len && 
-		    vcn>data->d.r.runlist[rnum].len;rnum++)
+		    vcn>=data->d.r.runlist[rnum].len;rnum++)
 		vcn-=data->d.r.runlist[rnum].len;
 	
 	return data->d.r.runlist[rnum].cluster+vcn;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/open.c linux.14p16/fs/open.c
--- linux.vanilla/fs/open.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/fs/open.c	Thu Dec  9 15:32:39 1999
@@ -712,7 +712,7 @@
 
 	/* Do we need to expand the fdset array? */
 	if (fd >= current->files->max_fdset) {
-		error = expand_fdset(files, 0);
+		error = expand_fdset(files, fd + 1);
 		if (!error)
 			goto repeat;
 		goto out;
@@ -722,7 +722,7 @@
 	 * Check whether we need to expand the fd array.
 	 */
 	if (fd >= files->max_fds) {
-		error = expand_fd_array(files, 0);
+		error = expand_fd_array(files, fd + 1);
 		if (!error)
 			goto repeat;
 		goto out;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/proc/array.c linux.14p16/fs/proc/array.c
--- linux.vanilla/fs/proc/array.c	Wed Oct 20 01:12:49 1999
+++ linux.14p16/fs/proc/array.c	Wed Dec 15 22:20:52 1999
@@ -680,6 +680,9 @@
 #define KSTK_TOS(tsk) ((unsigned long)(tsk) + KERNEL_STACK_SIZE - 32)
 # define KSTK_EIP(tsk)	(*(unsigned long *)(KSTK_TOS(tsk) + PT_REG(cp0_epc)))
 # define KSTK_ESP(tsk)	(*(unsigned long *)(KSTK_TOS(tsk) + PT_REG(regs[29])))
+#elif defined(__s390__)
+#define KSTK_EIP(tsk)   ((tsk)->tss.regs->psw.addr)
+#define KSTK_ESP(tsk)   ((tsk)->tss.ksp)
 #endif
 
 /* Gcc optimizes away "strlen(x)" for constant x */
@@ -874,6 +877,9 @@
 {
 	char * orig = buffer;
 	struct task_struct *tsk;
+#ifdef  CONFIG_ARCH_S390
+	int line,len;
+#endif
 
 	read_lock(&tasklist_lock);
 	tsk = find_task_by_pid(pid);
@@ -885,6 +891,10 @@
 	buffer = task_mem(tsk, buffer);
 	buffer = task_sig(tsk, buffer);
 	buffer = task_cap(tsk, buffer);
+#ifdef CONFIG_ARCH_S390
+	for(line=0;(len=sprintf_regs(line,buffer,tsk,NULL,NULL))!=0;line++)
+		buffer+=len;
+#endif
 	return buffer - orig;
 }
 
@@ -1362,10 +1372,10 @@
 
 		case PROC_FILESYSTEMS:
 			return get_filesystem_list(page);
-
+#ifndef CONFIG_ARCH_S390
 		case PROC_DMA:
 			return get_dma_list(page);
-
+#endif
 		case PROC_IOPORTS:
 			return get_ioport_list(page);
 #ifdef CONFIG_BLK_DEV_MD
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/proc/mem.c linux.14p16/fs/proc/mem.c
--- linux.vanilla/fs/proc/mem.c	Wed Sep 23 23:24:37 1998
+++ linux.14p16/fs/proc/mem.c	Thu Dec  9 15:32:39 1999
@@ -288,11 +288,15 @@
 		if (!dest_table)
 			return -ENOMEM;
 
-		if (!pte_present(*src_table))
-			handle_mm_fault(tsk, src_vma, stmp, 1);
+		if (!pte_present(*src_table)) {
+			if (handle_mm_fault(tsk, src_vma, stmp, 1) < 0)
+				return -ENOMEM;
+		}
 
-		if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table))
-			handle_mm_fault(tsk, src_vma, stmp, 1);
+		if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table)) {
+			if (handle_mm_fault(tsk, src_vma, stmp, 1) < 0)
+				return -ENOMEM;
+		}
 
 		set_pte(src_table, pte_mkdirty(*src_table));
 		set_pte(dest_table, *src_table);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/read_write.c linux.14p16/fs/read_write.c
--- linux.vanilla/fs/read_write.c	Sun Dec 27 18:52:09 1998
+++ linux.14p16/fs/read_write.c	Mon Dec 13 20:53:50 1999
@@ -29,7 +29,7 @@
 		if (offset != file->f_pos) {
 			file->f_pos = offset;
 			file->f_reada = 0;
-			file->f_version = ++event;
+			file->f_version = ++global_event;
 		}
 		retval = offset;
 	}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/smbfs/proc.c linux.14p16/fs/smbfs/proc.c
--- linux.vanilla/fs/smbfs/proc.c	Sat Aug 14 02:26:51 1999
+++ linux.14p16/fs/smbfs/proc.c	Thu Dec  9 15:32:41 1999
@@ -7,6 +7,11 @@
  *  28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per
  *  28/09/97 - Fixed smb_d_path [now smb_build_path()] to be non-recursive
  *             by Riccardo Facchetti
+ *  16/11/99 (tridge) 
+ *           - use level 260 for most conns, or level 1 for <NT1
+ *           - don't sleep every time with win95 on a FINDNEXT
+ *           - fixed loop_count bug
+ *           - got rid of resume_key
  */
 
 #include <linux/types.h>
@@ -1449,13 +1454,12 @@
 
 /*
  * Interpret a long filename structure using the specified info level:
- *   level 1   -- Win NT, Win 95, OS/2
- *   level 259 -- File name and length only, Win NT, Win 95
+ *   level 1 for anything below NT1 protocol
+ *   level 260 for NT1 protocol
  *
  * We return a reference to the name string to avoid copying, and perform
- * any needed upper/lower casing in place.  Note!! Level 259 entries may
- * not have any space beyond the name, so don't try to write a null byte!
- *
+ * any needed upper/lower casing in place.  
+
  * Bugs Noted:
  * (1) Win NT 4.0 appends a null byte to names and counts it in the length!
  */
@@ -1474,30 +1478,24 @@
 	switch (level)
 	{
 	case 1:
-		len = *((unsigned char *) p + 26);
+		len = *((unsigned char *) p + 22);
 		entry->len = len;
-		entry->name = p + 27;
-		result = p + 28 + len;
+		entry->name = p + 23;
+		result = p + 24 + len;
 		break;
 
-	case 259: /* SMB_FIND_FILE_NAMES_INFO = 0x103 */
-		result = p + DVAL(p, 0);
-		/* DVAL(p, 4) should be resume key? Seems to be 0 .. */
-		len = DVAL(p, 8);
-		if (len > 255)
-			len = 255;
-		entry->name = p + 12;
-		/*
-		 * Kludge alert: Win NT 4.0 adds a trailing null byte and
-		 * counts it in the name length, but Win 95 doesn't.  Hence
-		 * we test for a trailing null and decrement the length ...
-		 */
+	case 260: /* SMB_FIND_FILE_BOTH_DIRECTORY_INFO = 0x104 */
+		result = p + WVAL(p, 0);
+		len = DVAL(p, 60);
+		if (len > 255) len = 255;
+		/* NT4 null terminates */
+		entry->name = p + 94;
 		if (len && entry->name[len-1] == '\0')
 			len--;
 		entry->len = len;
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_decode_long_dirent: info 259 at %p, len=%d, name=%s\n",
-p, len, entry->name);
+printk("smb_decode_long_dirent: info 260 at %p, len=%d, name=%s\n",
+       p, entry->len, entry->name);
 #endif
 		break;
 
@@ -1528,40 +1526,40 @@
  * is completely reproducible and can be toggled by the creation of a
  * single file. (E.g. echo hi >foo breaks, rm -f foo works.)
  */
+
+#define SMB_CLOSE_AFTER_FIRST (1<<0)
+#define SMB_CLOSE_IF_END (1<<1)
+#define SMB_REQUIRE_RESUME_KEY (1<<2)
+#define SMB_CONTINUE_BIT (1<<3)
+
 static int
 smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
 		      void *cachep)
 {
-	char *p, *mask, *lastname, *param = server->temp_buf;
+	char *p, *mask, *param = server->temp_buf;
 	__u16 command;
 	int first, entries, entries_seen;
 
 	/* Both NT and OS/2 accept info level 1 (but see note below). */
-	int info_level = 1;
+	int info_level = 260;
 	const int max_matches = 512;
 
 	unsigned char *resp_data = NULL;
 	unsigned char *resp_param = NULL;
 	int resp_data_len = 0;
 	int resp_param_len = 0;
-	int ff_resume_key = 0; /* this isn't being used */
 	int ff_searchcount = 0;
 	int ff_eos = 0;
-	int ff_lastname = 0;
 	int ff_dir_handle = 0;
 	int loop_count = 0;
 	int mask_len, i, result;
 	static struct qstr star = { "*", 1, 0 };
 
 	/*
-	 * Check whether to change the info level.  There appears to be
-	 * a bug in Win NT 4.0's handling of info level 1, whereby it
-	 * truncates the directory scan for certain patterns of files.
-	 * Hence we use level 259 for NT.
+	 * use info level 1 for older servers that don't do 260
 	 */
-	if (server->opt.protocol >= SMB_PROTOCOL_NT1 &&
-	    !(server->mnt->version & SMB_FIX_WIN95))
-		info_level = 259;
+	if (server->opt.protocol < SMB_PROTOCOL_NT1)
+		info_level = 1;
 
 	smb_lock_server(server);
 
@@ -1586,7 +1584,7 @@
 	while (ff_eos == 0)
 	{
 		loop_count += 1;
-		if (loop_count > 200)
+		if (loop_count > 10)
 		{
 			printk(KERN_WARNING "smb_proc_readdir_long: "
 			       "Looping in FIND_NEXT??\n");
@@ -1599,33 +1597,27 @@
 			command = TRANSACT2_FINDFIRST;
 			WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
 			WSET(param, 2, max_matches);	/* max count */
-			WSET(param, 4, 8 + 4 + 2);	/* resume required +
-							   close on end +
-							   continue */
+			WSET(param, 4, 
+			     SMB_CONTINUE_BIT|SMB_CLOSE_IF_END); 
 			WSET(param, 6, info_level);
 			DSET(param, 8, 0);
 		} else
 		{
+			/* we don't need the mask after the first bit */
+			mask_len = 0;
+			mask[0] = 0;
+
 			command = TRANSACT2_FINDNEXT;
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_readdir_long: handle=0x%X, resume=%d, lastname=%d, mask=%s\n",
-ff_dir_handle, ff_resume_key, ff_lastname, mask);
+printk("smb_proc_readdir_long: handle=0x%X, mask=%s\n",
+ff_dir_handle, mask);
 #endif
 			WSET(param, 0, ff_dir_handle);	/* search handle */
 			WSET(param, 2, max_matches);	/* max count */
 			WSET(param, 4, info_level);
-			DSET(param, 6, ff_resume_key);	/* ff_resume_key */
-			WSET(param, 10, 8 + 4 + 2);	/* resume required +
-							   close on end +
-							   continue */
-			if (server->mnt->version & SMB_FIX_WIN95)
-			{
-				/* Windows 95 is not able to deliver answers
-				 * to FIND_NEXT fast enough, so sleep 0.2 sec
-				 */
-				current->state = TASK_INTERRUPTIBLE;
-				schedule_timeout(HZ/5);
-			}
+			DSET(param, 6, 0);       	/* ff_resume_key */
+			WSET(param, 10,
+			     SMB_CONTINUE_BIT|SMB_CLOSE_IF_END); 
 		}
 
 		result = smb_trans2_request(server, command,
@@ -1648,6 +1640,16 @@
 			entries = result;
 			break;
 		}
+
+
+		if (server->rcls == ERRSRV && server->err == ERRerror) {
+			/* a damn Win95 bug - sometimes it clags if you 
+			   ask it too fast */
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(HZ/5);
+			continue;
+		}
+
 		if (server->rcls != 0)
 		{ 
 #ifdef SMBFS_PARANOIA
@@ -1664,12 +1666,10 @@
 			ff_dir_handle = WVAL(resp_param, 0);
 			ff_searchcount = WVAL(resp_param, 2);
 			ff_eos = WVAL(resp_param, 4);
-			ff_lastname = WVAL(resp_param, 8);
 		} else
 		{
 			ff_searchcount = WVAL(resp_param, 0);
 			ff_eos = WVAL(resp_param, 2);
-			ff_lastname = WVAL(resp_param, 6);
 		}
 
 		if (ff_searchcount == 0)
@@ -1677,38 +1677,6 @@
 			break;
 		}
 
-		/* we might need the lastname for continuations */
-		mask_len = 0;
-		if (ff_lastname > 0)
-		{
-			lastname = resp_data + ff_lastname;
-			switch (info_level)
-			{
-			case 259:
- 				if (ff_lastname < resp_data_len)
-					mask_len = resp_data_len - ff_lastname;
-				break;
-			case 1:
-				/* Win NT 4.0 doesn't set the length byte */
-				lastname++;
- 				if (ff_lastname + 2 < resp_data_len)
-					mask_len = strlen(lastname);
-				break;
-			}
-			/*
-			 * Update the mask string for the next message.
-			 */
-			if (mask_len > 255)
-				mask_len = 255;
-			if (mask_len)
-				strncpy(mask, lastname, mask_len);
-			ff_resume_key = 0;
-		}
-		mask[mask_len] = 0;
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_readdir_long: new mask, len=%d@%d, mask=%s\n",
-mask_len, ff_lastname, mask);
-#endif
 		/* Now we are ready to parse smb directory entries. */
 
 		/* point to the data bytes */
@@ -1720,8 +1688,6 @@
 			p = smb_decode_long_dirent(server, p, entry,
 							info_level);
 
-			pr_debug("smb_readdir_long: got %s\n", entry->name);
-
 			/* ignore . and .. from the server */
 			if (entries_seen == 2 && entry->name[0] == '.')
 			{
@@ -1739,10 +1705,11 @@
 		}
 
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_readdir_long: received %d entries, eos=%d, resume=%d\n",
-ff_searchcount, ff_eos, ff_resume_key);
+printk("smb_proc_readdir_long: received %d entries, eos=%d\n",
+       ff_searchcount, ff_eos);
 #endif
 		first = 0;
+		loop_count = 0;
 	}
 
 	smb_unlock_server(server);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/super.c linux.14p16/fs/super.c
--- linux.vanilla/fs/super.c	Sat Aug 14 02:27:37 1999
+++ linux.14p16/fs/super.c	Tue Dec 21 00:26:02 1999
@@ -983,6 +983,12 @@
 	if (!data)
 		return 0;
 
+	/* If this is the kernel, just trust the pointer. */
+	if (segment_eq(get_fs(), KERNEL_DS)) {
+		*where = (unsigned long) data;
+		return 0;
+	}
+
 	vma = find_vma(current->mm, (unsigned long) data);
 	if (!vma || (unsigned long) data < vma->vm_start)
 		return -EFAULT;
@@ -1002,6 +1008,13 @@
 	return 0;
 }
 
+static void free_mount_page(unsigned long page)
+{
+	if (segment_eq(get_fs(), KERNEL_DS))
+		return;
+	free_page(page);
+}
+
 /*
  * Flags is a 16-bit value that allows up to 16 non-fs dependent flags to
  * be given to the mount() call (ie: read-only, no-dev, no-suid etc).
@@ -1039,7 +1052,7 @@
 		retval = do_remount(dir_name,
 				    new_flags & ~MS_MGC_MSK & ~MS_REMOUNT,
 				    (char *) page);
-		free_page(page);
+		free_mount_page(page);
 		goto out;
 	}
 
@@ -1047,7 +1060,7 @@
 	if (retval < 0)
 		goto out;
 	fstype = get_fs_type((char *) page);
-	free_page(page);
+	free_mount_page(page);
 	retval = -ENODEV;
 	if (!fstype)		
 		goto out;
@@ -1101,7 +1114,7 @@
 	}
 	retval = do_mount(dev, dev_name, dir_name, fstype->name, flags,
 				(void *) page);
-	free_page(page);
+	free_mount_page(page);
 	if (retval)
 		goto clean_up;
 
@@ -1276,7 +1289,10 @@
 		umount_error = do_umount(old_root_dev,1, 0);
 		if (!umount_error) {
 			printk("okay\n");
-			invalidate_buffers(old_root_dev);
+			/* special: the old device driver is going to be
+			   a ramdisk and the point of this call is to free its
+			   protected memory (even if dirty). */
+			destroy_buffers(old_root_dev);
 			return 0;
 		}
 		printk(KERN_ERR "error %d\n",umount_error);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ufs/file.c linux.14p16/fs/ufs/file.c
--- linux.vanilla/fs/ufs/file.c	Thu Jan 14 18:31:41 1999
+++ linux.14p16/fs/ufs/file.c	Mon Dec 13 20:56:01 1999
@@ -111,7 +111,7 @@
 		if (offset != file->f_pos) {
 			file->f_pos = offset;
 			file->f_reada = 0;
-			file->f_version = ++event;
+			file->f_version = ++global_event;
 		}
 		retval = offset;
 	}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ufs/inode.c linux.14p16/fs/ufs/inode.c
--- linux.vanilla/fs/ufs/inode.c	Mon Jan 18 02:32:26 1999
+++ linux.14p16/fs/ufs/inode.c	Mon Dec 13 20:56:15 1999
@@ -509,7 +509,7 @@
 	inode->i_mtime = SWAB32(ufs_inode->ui_mtime.tv_sec);
 	inode->i_blocks = SWAB32(ufs_inode->ui_blocks);
 	inode->i_blksize = PAGE_SIZE;   /* This is the optimal IO size (for stat) */
-	inode->i_version = ++event;
+	inode->i_version = ++global_event;
 
 	inode->u.ufs_i.i_flags = SWAB32(ufs_inode->ui_flags);
 	inode->u.ufs_i.i_gen = SWAB32(ufs_inode->ui_gen);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/ufs/namei.c linux.14p16/fs/ufs/namei.c
--- linux.vanilla/fs/ufs/namei.c	Sat Aug 14 02:26:18 1999
+++ linux.14p16/fs/ufs/namei.c	Mon Dec 13 20:55:08 1999
@@ -330,7 +330,7 @@
 			 */
 			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 			mark_inode_dirty(dir);
-			dir->i_version = ++event;
+			dir->i_version = ++global_event;
 			mark_buffer_dirty(bh, 1);
 			*res_dir = de;
 			*err = 0;
@@ -435,7 +435,7 @@
 	}
 	de->d_ino = SWAB32(inode->i_ino);
 	ufs_set_de_type (de, inode->i_mode);
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -485,7 +485,7 @@
 		goto out_no_entry;
 	de->d_ino = SWAB32(inode->i_ino);
 	ufs_set_de_type (de, inode->i_mode);
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -559,7 +559,7 @@
 		goto out_no_entry;
 	de->d_ino = SWAB32(inode->i_ino);
 	ufs_set_de_type (de, inode->i_mode);
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -672,7 +672,7 @@
 		goto end_rmdir;
 
 	retval = ufs_delete_entry (dir, de, bh);
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	if (retval)
 		goto end_rmdir;
 	mark_buffer_dirty(bh, 1);
@@ -684,7 +684,7 @@
 		ufs_warning (inode->i_sb, "ufs_rmdir",
 			      "empty directory has nlink!=2 (%d)",
 			      inode->i_nlink);
-	inode->i_version = ++event;
+	inode->i_version = ++global_event;
 	inode->i_nlink = 0;
 	inode->i_size = 0;
 	mark_inode_dirty(inode);
@@ -736,7 +736,7 @@
 	retval = ufs_delete_entry (dir, de, bh);
 	if (retval)
 		goto end_unlink;
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -817,7 +817,7 @@
 	if (!bh)
 		goto out_no_entry;
 	de->d_ino = SWAB32(inode->i_ino);
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -861,7 +861,7 @@
 		return err;
 
 	de->d_ino = SWAB32(inode->i_ino);
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -949,7 +949,7 @@
 					 &retval);
 	if (!new_bh)
 		goto end_rename;
-	new_dir->i_version = ++event;
+	new_dir->i_version = ++global_event;
 
 	/*
 	 * ok, that's it
@@ -957,7 +957,7 @@
 	new_de->d_ino = SWAB32(old_inode->i_ino);
 	ufs_delete_entry (old_dir, old_de, old_bh);
 
-	old_dir->i_version = ++event;
+	old_dir->i_version = ++global_event;
 	if (new_inode) {
 		new_inode->i_nlink--;
 		new_inode->i_ctime = CURRENT_TIME;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/umsdos/README-WIP.txt linux.14p16/fs/umsdos/README-WIP.txt
--- linux.vanilla/fs/umsdos/README-WIP.txt	Sat Aug 14 02:27:37 1999
+++ linux.14p16/fs/umsdos/README-WIP.txt	Tue Dec 21 00:23:30 1999
@@ -11,6 +11,10 @@
 come and test it! See notes below for some more information, or if
 you are trying to use UMSDOS as root partition.
 
+Userland NOTE: new umsdos_progs (umssync, umssetup, udosctl & friends) that
+will compile and work on 2.2.x kernels and glibc based systems may be found
+at http://cvs.linux.hr/
+
 Legend: those lines marked with '+' on the beggining of line indicates it
 passed all of my tests, and performed perfect in all of them.
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/umsdos/inode.c linux.14p16/fs/umsdos/inode.c
--- linux.vanilla/fs/umsdos/inode.c	Sat Aug 14 02:27:37 1999
+++ linux.14p16/fs/umsdos/inode.c	Tue Dec 21 00:23:31 1999
@@ -168,7 +168,14 @@
 	} else if (S_ISBLK (inode->i_mode)) {
 		inode->i_op = &blkdev_inode_operations;
 	} else if (S_ISFIFO (inode->i_mode)) {
-		init_fifo (inode);
+	/* if someone is using FIFO, we must not reinitialize it, because
+	   we will destroy its locks, and sleep_on in fifo_open() will
+	   hardlock/oops our kernel! this started happening with
+	   patch-2.2.7. Why did it not happen before ? Maybe we were
+	   never called with i_count > 1 ?
+	*/
+		if (inode->i_count < 2)	
+			init_fifo (inode);
 	}
 }
 
@@ -349,7 +356,7 @@
 	if (!res)
 		goto out_fail;
 
-	printk (KERN_INFO "UMSDOS 0.85 "
+	printk (KERN_INFO "UMSDOS 0.85b "
 		"(compatibility level %d.%d, fast msdos)\n", 
 		UMSDOS_VERSION, UMSDOS_RELEASE);
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/umsdos/ioctl.c linux.14p16/fs/umsdos/ioctl.c
--- linux.vanilla/fs/umsdos/ioctl.c	Sat Sep 26 00:30:07 1998
+++ linux.14p16/fs/umsdos/ioctl.c	Tue Dec 21 00:23:31 1999
@@ -280,6 +280,8 @@
 old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
 new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
 			ret = msdos_rename (dir, old_dentry, dir, new_dentry);
+			d_drop(new_dentry);
+			d_drop(old_dentry);
 			dput(new_dentry);
 		}
 		dput(old_dentry);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/vfat/namei.c linux.14p16/fs/vfat/namei.c
--- linux.vanilla/fs/vfat/namei.c	Sat Aug 14 02:27:37 1999
+++ linux.14p16/fs/vfat/namei.c	Mon Dec 13 20:55:41 1999
@@ -975,8 +975,8 @@
 		return res;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(inode);
-	inode->i_version = ++event;
-	dir->i_version = event;
+	inode->i_version = ++global_event;
+	dir->i_version = global_event;
 	MSDOS_I(dir)->i_last_pos = 0;
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
 	d_instantiate(dentry,inode);
@@ -1022,7 +1022,7 @@
 	/* remove the shortname */
 	dir->i_mtime = CURRENT_TIME;
 	dir->i_atime = CURRENT_TIME;
-	dir->i_version = ++event;
+	dir->i_version = ++global_event;
 	MSDOS_I(dir)->i_last_pos = 0;
 	mark_inode_dirty(dir);
 	de->name[0] = DELETED_FLAG;
@@ -1108,8 +1108,8 @@
 		goto out;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(inode);
-	inode->i_version = ++event;
-	dir->i_version = event;
+	inode->i_version = ++global_event;
+	dir->i_version = global_event;
 	MSDOS_I(dir)->i_last_pos = 0;
 	dir->i_nlink++;
 	inode->i_nlink = 2; /* no need to mark them dirty */
@@ -1181,7 +1181,7 @@
 		if (res < 0) goto rename_done;
 	}
 
-	new_dir->i_version = ++event;
+	new_dir->i_version = ++global_event;
 	MSDOS_I(new_dir)->i_last_pos = 0;
 
 	/* releases old_bh */
@@ -1191,7 +1191,7 @@
 	fat_attach(old_inode, sinfo.ino);
 	mark_inode_dirty(old_inode);
 
-	old_dir->i_version = ++event;
+	old_dir->i_version = ++global_event;
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(old_dir);
 	if (new_inode) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/asm_offsets.h linux.14p16/include/asm-alpha/asm_offsets.h
--- linux.vanilla/include/asm-alpha/asm_offsets.h	Mon Oct 12 19:40:12 1998
+++ linux.14p16/include/asm-alpha/asm_offsets.h	Thu Dec  9 15:32:51 1999
@@ -6,7 +6,7 @@
 #define TASK_ADDR_LIMIT 24
 #define TASK_EXEC_DOMAIN 32
 #define TASK_NEED_RESCHED 40
-#define TASK_SIZE 1096
+#define TASK_SIZE 1064
 #define STACK_SIZE 16384
 #define HAE_CACHE 0
 #define HAE_REG 8
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/core_irongate.h linux.14p16/include/asm-alpha/core_irongate.h
--- linux.vanilla/include/asm-alpha/core_irongate.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-alpha/core_irongate.h	Tue Dec 14 16:16:13 1999
@@ -0,0 +1,588 @@
+#ifndef __ALPHA_IRONGATE__H__
+#define __ALPHA_IRONGATE__H__
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/compiler.h>
+
+/*
+ * IRONGATE is the internal name for the AMD-751 K7 core logic chipset
+ * which provides memory controller and PCI access for NAUTILUS-based
+ * EV6 (21264) systems.
+ *
+ * This file is based on:
+ *
+ * IronGate management library, (c) 1999 Alpha Processor, Inc.
+ * Copyright (C) 1999 Alpha Processor, Inc., (David Daniel, Stig Telfer, Soohoon Lee)
+ */
+
+/*
+ * The 21264 supports, and internally recognizes, a 44-bit physical
+ * address space that is divided equally between memory address space
+ * and I/O address space. Memory address space resides in the lower
+ * half of the physical address space (PA[43]=0) and I/O address space
+ * resides in the upper half of the physical address space (PA[43]=1).
+ *
+ */
+
+
+#define IRONGATE_DMA_WIN_BASE_DEFAULT	 (0U)
+#define IRONGATE_DMA_WIN_SIZE_DEFAULT	 (0U)
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP)
+#define IRONGATE_DMA_WIN_BASE		alpha_mv.dma_win_base
+#define IRONGATE_DMA_WIN_SIZE		alpha_mv.dma_win_size
+#else
+#define IRONGATE_DMA_WIN_BASE		IRONGATE_DMA_WIN_BASE_DEFAULT
+#define IRONGATE_DMA_WIN_SIZE		IRONGATE_DMA_WIN_SIZE_DEFAULT
+#endif
+
+/*
+ * Irongate CSR map.  Some of the CSRs are 8 or 16 bits, but all access
+ * through the routines given is 32-bit.
+ *
+ * The first 0x40 bytes are standard as per the PCI spec.
+ */
+
+typedef volatile __u32	igcsr32;
+
+typedef struct {
+	igcsr32 dev_vendor;		/* 0x00 - device ID, vendor ID */
+	igcsr32 stat_cmd;		/* 0x04 - status, command */
+	igcsr32 class;			/* 0x08 - class code, rev ID */
+	igcsr32 latency;		/* 0x0C - header type, PCI latency */
+	igcsr32 bar0;			/* 0x10 - BAR0 - AGP */
+	igcsr32 bar1;			/* 0x14 - BAR1 - GART */
+	igcsr32 bar2;			/* 0x18 - Power Management reg block */
+
+	igcsr32 rsrvd0[6];		/* 0x1C-0x33 reserved */
+
+	igcsr32 capptr;			/* 0x34 - Capabilities pointer */
+
+	igcsr32 rsrvd1[2];		/* 0x38-0x3F reserved */
+
+	igcsr32 bacsr10;		/* 0x40 - base address chip selects */
+	igcsr32 bacsr32;		/* 0x44 - base address chip selects */
+	igcsr32 bacsr54;		/* 0x48 - base address chip selects */
+
+	igcsr32 rsrvd2[1];		/* 0x4C-0x4F reserved */
+
+	igcsr32 drammap;		/* 0x50 - address mapping control */
+	igcsr32 dramtm;			/* 0x54 - timing, driver strength */
+	igcsr32 dramms;			/* 0x58 - ECC, mode/status */
+
+	igcsr32 rsrvd3[1];		/* 0x5C-0x5F reserved */
+
+	igcsr32 biu0;			/* 0x60 - bus interface unit */
+	igcsr32 biusip;			/* 0x64 - Serial initialisation pkt */
+
+	igcsr32 rsrvd4[2];		/* 0x68-0x6F reserved */
+
+	igcsr32 mro;			/* 0x70 - memory request optimiser */
+
+	igcsr32 rsrvd5[3];		/* 0x74-0x7F reserved */
+
+	igcsr32 whami;			/* 0x80 - who am I */
+	igcsr32 pciarb;			/* 0x84 - PCI arbitration control */
+	igcsr32 pcicfg;			/* 0x88 - PCI config status */
+
+	igcsr32 rsrvd6[5];		/* 0x8C-0x9F reserved */
+
+	/* AGP (bus 1) control registers */
+	igcsr32 agpcap;			/* 0xA0 - AGP Capability Identifier */
+	igcsr32 agpstat;		/* 0xA4 - AGP status register */
+	igcsr32 agpcmd;			/* 0xA8 - AGP control register */
+	igcsr32 agpva;			/* 0xAC - AGP Virtual Address Space */
+	igcsr32 agpmode;		/* 0xB0 - AGP/GART mode control */
+
+} Irongate0;
+
+/*----------------------------------------------------------------------*/
+/* Bitfield and mask register definitions */
+
+/* Device, vendor IDs - offset 0x00 */
+
+typedef union {
+	igcsr32 i;			/* integer value of CSR */
+	struct {
+		unsigned v : 16;
+		unsigned d : 16;
+	} r;				/* structured interpretation */
+} ig_dev_vendor_t;
+
+
+/* Status, command registers - offset 0x04 */
+
+typedef union {
+
+	igcsr32 i;
+	struct {
+		unsigned command;
+		unsigned status;
+	} s;
+	struct {
+		/* command register fields */
+		unsigned iospc : 1;		/* always reads zero */
+		unsigned memspc	 : 1;		/* PCI memory space accesses? */
+		unsigned iten : 1;		/* always 1: can be bus initiator */
+		unsigned scmon : 1;		/* always 0 special cycles not chckd */
+		unsigned mwic : 1;		/* always 0 - no mem write & invalid */
+		unsigned vgaps : 1;		/* always 0 - palette rds not special */
+		unsigned per : 1;		/* parity error resp: always 0 */
+		unsigned step : 1;		/* address/data stepping : always 0 */
+		unsigned serre : 1;		/* 1 = sys err output driver enable */
+		unsigned fbbce : 1;		/* fast back-back cycle : always 0 */
+		unsigned zero1 : 6;		/* must be zero */
+
+		/* status register fields */
+		unsigned zero2 : 4;	     /* must be zero */
+		unsigned cl : 1;	    /* config space capa list: always 1 */
+		unsigned pci66 : 1;	    /* 66 MHz PCI support - always 0 */
+		unsigned udf : 1;	    /* user defined features - always 0 */
+		unsigned fbbc : 1;	    /* back-back transactions - always 0 */
+		unsigned ppe : 1;	    /* PCI parity error detected (0) */
+		unsigned devsel : 2;	    /* DEVSEL timing (always 01) */
+		unsigned sta : 1;	    /* signalled target abort (0) */
+		unsigned rta : 1;	    /* recvd target abort */
+		unsigned ria : 1;	    /* recvd initiator abort */
+		unsigned serr : 1;	    /* SERR has been asserted */
+		unsigned dpe : 1;	    /* DRAM parity error (0) */
+	} r;
+} ig_stat_cmd_t;
+
+
+/* Revision ID, Programming interface, subclass, baseclass - offset 0x08 */
+
+typedef union {
+
+	igcsr32 i;
+	struct {
+		/* revision ID */
+		unsigned step : 4;		/* stepping Revision ID */
+		unsigned die : 4;		/* die Revision ID */
+		unsigned pif : 8;		/* programming interface (0x00) */
+		unsigned sub : 8;		/* subclass code (0x00) */
+		unsigned base: 8;		/* baseclass code (0x06) */
+	} r;
+} ig_class_t;
+
+
+/* Latency Timer, PCI Header type - offset 0x0C */
+
+typedef union {
+
+	igcsr32 i;
+	struct {
+		unsigned zero1:8;		/* reserved */
+		unsigned lat : 8;		/* latency in PCI bus clocks */
+		unsigned hdr : 8;		/* PCI header type */
+		unsigned zero2:8;		/* reserved */
+	} r;
+} ig_latency_t;
+
+
+/* Base Address Register 0 - offset 0x10 */
+
+typedef union {
+
+	igcsr32 i;
+	struct {
+		unsigned mem : 1;		/* Reg pts to memory (always 0) */
+		unsigned type: 2;		/* 32 bit register = 0b00 */
+		unsigned pref: 1;		/* graphics mem prefetchable=1 */
+		unsigned baddrl : 21;		/* 32M = minimum alloc -> all zero */
+		unsigned size : 6;		/* size requirements for AGP */
+		unsigned zero : 1;		/* reserved=0 */
+	} r;
+} ig_bar0_t;
+
+
+/* Base Address Register 1 - offset 0x14 */
+
+typedef union {
+
+	igcsr32 i;
+	struct {
+		unsigned mem : 1;		/* BAR0 maps to memory -> 0 */
+		unsigned type : 2;		/* BAR1 is 32-bit -> 0b00 */
+		unsigned pref : 1;		/* graphics mem prefetchable=1 */
+		unsigned baddrl : 8;		/* 4K alloc for AGP CSRs -> 0b00 */
+		unsigned baddrh : 20;		/* base addr of AGP CSRs A[30:11] */
+	} r;
+} ig_bar1_t;
+
+
+/* Base Address Register 2 - offset 0x18 */
+
+typedef union {
+
+	igcsr32 i;
+	struct {
+		unsigned io  : 1;		/* BAR2 maps to I/O space -> 1 */
+		unsigned zero1: 1;		/* reserved */
+		unsigned addr : 22;		/* BAR2[31:10] - PM2_BLK base */
+		unsigned zero2: 8;		/* reserved */
+	} r;
+} ig_bar2_t;
+
+
+/* Capabilities Pointer - offset 0x34 */
+
+typedef union {
+
+	igcsr32 i;
+	struct {
+		unsigned cap : 8;		/* =0xA0, offset of AGP ctrl regs */
+		unsigned zero: 24;		/* reserved */
+	} r;
+} ig_capptr_t;
+
+
+/* Base Address Chip Select Register 1,0 - offset 0x40 */
+/* Base Address Chip Select Register 3,2 - offset 0x44 */
+/* Base Address Chip Select Register 5,4 - offset 0x48 */
+
+typedef union {
+
+	igcsr32 i;
+	struct {
+		/* lower bank */
+		unsigned en0 : 1;		/* memory bank enabled */
+		unsigned mask0 : 6;		/* Address mask for A[28:23] */
+		unsigned base0 : 9;		/* Bank Base Address A[31:23] */
+
+		/* upper bank */
+		unsigned en1 : 1;		/* memory bank enabled */
+		unsigned mask1 : 6;		/* Address mask for A[28:23] */
+		unsigned base1 : 9;		/* Bank Base Address A[31:23] */
+	} r;
+} ig_bacsr_t, ig_bacsr10_t, ig_bacsr32_t, ig_bacsr54_t;
+
+
+/* SDRAM Address Mapping Control Register - offset 0x50 */
+
+typedef union {
+
+	igcsr32 i;
+	struct {
+		unsigned z1 : 1;		/* reserved */
+		unsigned bnks0: 1;		/* 0->2 banks in chip select 0 */
+		unsigned am0 : 1;		/* row/column addressing */
+		unsigned z2 : 1;		/* reserved */
+
+		unsigned z3 : 1;		/* reserved */
+		unsigned bnks1: 1;		/* 0->2 banks in chip select 1 */
+		unsigned am1 : 1;		/* row/column addressing */
+		unsigned z4 : 1;		/* reserved */
+
+		unsigned z5 : 1;		/* reserved */
+		unsigned bnks2: 1;		/* 0->2 banks in chip select 2 */
+		unsigned am2 : 1;		/* row/column addressing */
+		unsigned z6 : 1;		/* reserved */
+
+		unsigned z7 : 1;		/* reserved */
+		unsigned bnks3: 1;		/* 0->2 banks in chip select 3 */
+		unsigned am3 : 1;		/* row/column addressing */
+		unsigned z8 : 1;		/* reserved */
+
+		unsigned z9 : 1;		/* reserved */
+		unsigned bnks4: 1;		/* 0->2 banks in chip select 4 */
+		unsigned am4 : 1;		/* row/column addressing */
+		unsigned z10 : 1;		/* reserved */
+
+		unsigned z11 : 1;		/* reserved */
+		unsigned bnks5: 1;		/* 0->2 banks in chip select 5 */
+		unsigned am5 : 1;		/* row/column addressing */
+		unsigned z12 : 1;		/* reserved */
+
+		unsigned rsrvd: 8;		/* reserved */
+	} r;
+} ig_drammap_t;
+
+
+/* DRAM timing and driver strength register - offset 0x54 */
+
+typedef union {
+
+	igcsr32 i;
+	struct {
+		/* DRAM timing parameters */
+		unsigned trcd : 2;
+		unsigned tcl : 2;
+		unsigned tras: 3;
+		unsigned trp : 2;
+		unsigned trc : 3;
+		unsigned icl: 2;
+		unsigned ph : 2;
+
+		/* Chipselect driver strength */
+		unsigned adra : 1;
+		unsigned adrb : 1;
+		unsigned ctrl : 3;
+		unsigned dqm : 1;
+		unsigned cs : 1;
+		unsigned clk: 1;
+		unsigned rsrvd:8;
+	} r;
+} ig_dramtm_t;
+
+
+/* DRAM Mode / Status and ECC Register - offset 0x58 */
+
+typedef union {
+
+	igcsr32 i;
+	struct {
+		unsigned chipsel : 6;		/* failing ECC chip select */
+		unsigned zero1 : 2;		/* always reads zero */
+		unsigned status : 2;		/* ECC Detect logic status */
+		unsigned zero2 : 6;		/* always reads zero */
+
+		unsigned cycles : 2;		/* cycles per refresh, see table */
+		unsigned en : 1;		/* ECC enable */
+		unsigned r : 1;			/* Large burst enable (=0) */
+		unsigned bre : 1;		/* Burst refresh enable */
+		unsigned zero3 : 2;		/* reserved = 0 */
+		unsigned mwe : 1;		/* Enable writes to DRAM mode reg */
+		unsigned type : 1;		/* SDRAM = 0, default */
+		unsigned sdraminit : 1;		/* SDRAM init - set params first! */
+		unsigned zero4 : 6;		/* reserved = 0 */
+	} r;
+} ig_dramms_t;
+
+/*----------------------------------------------------------------------*/
+
+
+/*
+ * Memory spaces:
+ */
+
+/* Irongate is consistent with a subset of the Tsunami memory map */
+#ifdef USE_48_BIT_KSEG
+#define IRONGATE_BIAS 0x80000000000UL
+#else
+#define IRONGATE_BIAS 0x10000000000UL
+#endif
+
+
+#define IRONGATE_MEM		(IDENT_ADDR | IRONGATE_BIAS | 0x000000000UL)
+#define IRONGATE_IACK_SC	(IDENT_ADDR | IRONGATE_BIAS | 0x1F8000000UL)
+#define IRONGATE_IO		(IDENT_ADDR | IRONGATE_BIAS | 0x1FC000000UL)
+#define IRONGATE_CONF		(IDENT_ADDR | IRONGATE_BIAS | 0x1FE000000UL)
+
+
+#define IRONGATE0	( (Irongate0 *) IRONGATE_CONF )
+
+/*
+ * Data structure for handling IRONGATE machine checks:
+ * This is the standard OSF logout frame
+ */
+
+#define SCB_Q_SYSERR	0x620			/* OSF definitions */
+#define SCB_Q_PROCERR	0x630
+#define SCB_Q_SYSMCHK	0x660
+#define SCB_Q_PROCMCHK	0x670
+
+struct el_IRONGATE_sysdata_mcheck {
+  __u32 FrameSize;                 /* Bytes, including this field */
+  __u32 FrameFlags;                /* <31> = Retry, <30> = Second Error */
+  __u32 CpuOffset;                 /* Offset to CPU-specific into */
+  __u32 SystemOffset;              /* Offset to system-specific info */
+  __u32 MCHK_Code;
+  __u32 MCHK_Frame_Rev;
+  __u64 I_STAT;
+  __u64 DC_STAT;
+  __u64 C_ADDR;
+  __u64 DC1_SYNDROME;
+  __u64 DC0_SYNDROME;
+  __u64 C_STAT;
+  __u64 C_STS;
+  __u64 RESERVED0;
+  __u64 EXC_ADDR;
+  __u64 IER_CM;
+  __u64 ISUM;
+  __u64 MM_STAT;
+  __u64 PAL_BASE;
+  __u64 I_CTL;
+  __u64 PCTX;
+};
+
+/*----------------------------------------------------------------------*/
+
+#ifdef __KERNEL__
+
+#ifndef __EXTERN_INLINE
+#define __EXTERN_INLINE extern inline
+#define __IO_EXTERN_INLINE
+#endif
+
+/*
+ * Translate physical memory address as seen on (PCI) bus into
+ * a kernel virtual address and vv.
+ */
+
+__EXTERN_INLINE unsigned long irongate_virt_to_bus(void * address)
+{
+	return virt_to_phys(address) + IRONGATE_DMA_WIN_BASE;
+}
+
+__EXTERN_INLINE void * irongate_bus_to_virt(unsigned long address)
+{
+	return phys_to_virt(address - IRONGATE_DMA_WIN_BASE);
+}
+
+/*
+ * I/O functions:
+ *
+ * IRONGATE (AMD-751) PCI/memory support chip for the EV6 (21264) and
+ * K7 can only use linear accesses to get at PCI memory and I/O spaces
+ */
+
+#define vucp	volatile unsigned char *
+#define vusp	volatile unsigned short *
+#define vuip	volatile unsigned int *
+#define vulp	volatile unsigned long *
+
+#define XADDR	((addr) & 0xffffffffUL)
+
+__EXTERN_INLINE unsigned int irongate_inb(unsigned long addr)
+{
+	return __kernel_ldbu(*(vucp)(XADDR + IRONGATE_IO));
+}
+
+__EXTERN_INLINE void irongate_outb(unsigned char b, unsigned long addr)
+{
+        __kernel_stb(b, *(vucp)(XADDR + IRONGATE_IO));
+	mb();
+}
+
+__EXTERN_INLINE unsigned int irongate_inw(unsigned long addr)
+{
+	return __kernel_ldwu(*(vusp)(XADDR + IRONGATE_IO));
+}
+
+__EXTERN_INLINE void irongate_outw(unsigned short b, unsigned long addr)
+{
+        __kernel_stw(b, *(vusp)(XADDR + IRONGATE_IO));
+	mb();
+}
+
+__EXTERN_INLINE unsigned int irongate_inl(unsigned long addr)
+{
+	return *(vuip)(XADDR + IRONGATE_IO);
+}
+
+__EXTERN_INLINE void irongate_outl(unsigned int b, unsigned long addr)
+{
+        *(vuip)(XADDR + IRONGATE_IO) = b;
+	mb();
+}
+
+/*
+ * Memory functions.  all accesses are done through linear space.
+ */
+
+__EXTERN_INLINE unsigned long irongate_readb(unsigned long addr)
+{
+	return __kernel_ldbu(*(vucp)(XADDR + IRONGATE_MEM));
+}
+
+__EXTERN_INLINE unsigned long irongate_readw(unsigned long addr)
+{
+	return __kernel_ldwu(*(vusp)(XADDR + IRONGATE_MEM));
+}
+
+__EXTERN_INLINE unsigned long irongate_readl(unsigned long addr)
+{
+	return *(vuip)(XADDR + IRONGATE_MEM);
+}
+
+__EXTERN_INLINE unsigned long irongate_readq(unsigned long addr)
+{
+	return *(vulp)(XADDR + IRONGATE_MEM);
+}
+
+__EXTERN_INLINE void irongate_writeb(unsigned char b, unsigned long addr)
+{
+	__kernel_stb(b, *(vucp)(XADDR + IRONGATE_MEM));
+}
+
+__EXTERN_INLINE void irongate_writew(unsigned short b, unsigned long addr)
+{
+	__kernel_stw(b, *(vusp)(XADDR + IRONGATE_MEM));
+}
+
+__EXTERN_INLINE void irongate_writel(unsigned int b, unsigned long addr)
+{
+	*(vuip)(XADDR + IRONGATE_MEM) = b;
+}
+
+__EXTERN_INLINE void irongate_writeq(unsigned long b, unsigned long addr)
+{
+	*(vulp)(XADDR + IRONGATE_MEM) = b;
+}
+
+/* Find the DENSE memory area for a given bus address.	*/
+
+__EXTERN_INLINE unsigned long irongate_dense_mem(unsigned long addr)
+{
+	return IRONGATE_MEM;
+}
+
+#undef vucp
+#undef vusp
+#undef vuip
+#undef vulp
+
+#undef XADDR
+
+#ifdef __WANT_IO_DEF
+
+#define virt_to_bus	irongate_virt_to_bus
+#define bus_to_virt	irongate_bus_to_virt
+
+#define __inb		irongate_inb
+#define __inw		irongate_inw
+#define __inl		irongate_inl
+#define __outb		irongate_outb
+#define __outw		irongate_outw
+#define __outl		irongate_outl
+#define __readb		irongate_readb
+#define __readw		irongate_readw
+#define __writeb	irongate_writeb
+#define __writew	irongate_writew
+#define __readl		irongate_readl
+#define __readq		irongate_readq
+#define __writel	irongate_writel
+#define __writeq	irongate_writeq
+#define dense_mem	irongate_dense_mem
+
+#define inb(port) __inb((port))
+#define inw(port) __inw((port))
+#define inl(port) __inl((port))
+
+#define outb(v, port) __outb((v),(port))
+#define outw(v, port) __outw((v),(port))
+#define outl(v, port) __outl((v),(port))
+
+#define readb(a)	__readb((unsigned long)(a))
+#define readw(a)	__readw((unsigned long)(a))
+#define readl(a)	__readl((unsigned long)(a))
+#define readq(a)	__readq((unsigned long)(a))
+
+#define writeb(v,a)	__writeb((v),(unsigned long)(a))
+#define writew(v,a)	__writew((v),(unsigned long)(a))
+#define writel(v,a)	__writel((v),(unsigned long)(a))
+#define writeq(v,a)	__writeq((v),(unsigned long)(a))
+
+#endif /* __WANT_IO_DEF */
+
+#ifdef __IO_EXTERN_INLINE
+#undef __EXTERN_INLINE
+#undef __IO_EXTERN_INLINE
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* __ALPHA_IRONGATE__H__ */
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/core_mcpcia.h linux.14p16/include/asm-alpha/core_mcpcia.h
--- linux.vanilla/include/asm-alpha/core_mcpcia.h	Sun Jan 10 17:59:59 1999
+++ linux.14p16/include/asm-alpha/core_mcpcia.h	Thu Dec  9 15:32:51 1999
@@ -215,41 +215,6 @@
 #define vuip	volatile unsigned int *
 #define vulp	volatile unsigned long *
 
-#if 0 /* BWIO */
-__EXTERN_INLINE unsigned int mcpcia_bw_inb(unsigned long addr)
-{
-	return __kernel_ldbu(*(vucp)(addr+MCPCIA_BW_IO));
-}
-
-__EXTERN_INLINE void mcpcia_bw_outb(unsigned char b, unsigned long addr)
-{
-	__kernel_stb(b, *(vucp)(addr+MCPCIA_BW_IO));
-	mb();
-}
-
-__EXTERN_INLINE unsigned int mcpcia_bw_inw(unsigned long addr)
-{
-	return __kernel_ldwu(*(vusp)(addr+MCPCIA_BW_IO));
-}
-
-__EXTERN_INLINE void mcpcia_bw_outw(unsigned short b, unsigned long addr)
-{
-	__kernel_stw(b, *(vusp)(addr+MCPCIA_BW_IO));
-	mb();
-}
-
-__EXTERN_INLINE unsigned int mcpcia_bw_inl(unsigned long addr)
-{
-	return *(vuip)(addr+MCPCIA_BW_IO);
-}
-
-__EXTERN_INLINE void mcpcia_bw_outl(unsigned int b, unsigned long addr)
-{
-	*(vuip)(addr+MCPCIA_BW_IO) = b;
-	mb();
-}
-#endif
-
 __EXTERN_INLINE unsigned int mcpcia_inb(unsigned long in_addr)
 {
 	unsigned long addr = in_addr & 0xffffffffUL;
@@ -336,48 +301,6 @@
  * 
  */
 
-#if 0 /* BWIO */
-__EXTERN_INLINE unsigned long mcpcia_bw_readb(unsigned long addr)
-{
-	return __kernel_ldbu(*(vucp)(addr+MCPCIA_BW_MEM));
-}
-
-__EXTERN_INLINE unsigned long mcpcia_bw_readw(unsigned long addr)
-{
-	return __kernel_ldbw(*(vusp)(addr+MCPCIA_BW_MEM));
-}
-
-__EXTERN_INLINE unsigned long mcpcia_bw_readl(unsigned long addr)
-{
-	return *(vuip)(addr + MCPCIA_BW_MEM);
-}
-
-__EXTERN_INLINE unsigned long mcpcia_bw_readq(unsigned long addr)
-{
-	return *(vulp)(addr + MCPCIA_BW_MEM);
-}
-
-__EXTERN_INLINE void mcpcia_bw_writeb(unsigned char b, unsigned long addr)
-{
-	__kernel_stb(b, *(vucp)(addr+MCPCIA_BW_MEM));
-}
-
-__EXTERN_INLINE void mcpcia_bw_writew(unsigned short b, unsigned long addr)
-{
-	__kernel_stw(b, *(vusp)(addr+MCPCIA_BW_MEM));
-}
-
-__EXTERN_INLINE void mcpcia_bw_writel(unsigned int b, unsigned long addr)
-{
-	*(vuip)(addr+MCPCIA_BW_MEM) = b;
-}
-
-__EXTERN_INLINE void mcpcia_bw_writeq(unsigned long b, unsigned long addr)
-{
-	*(vulp)(addr+MCPCIA_BW_MEM) = b;
-}
-#endif
-
 __EXTERN_INLINE unsigned long mcpcia_srm_base(unsigned long addr)
 {
 	unsigned long mask, base;
@@ -543,64 +466,34 @@
 #define virt_to_bus	mcpcia_virt_to_bus
 #define bus_to_virt	mcpcia_bus_to_virt
 
-#if 0 /* BWIO */
-# define __inb		mcpcia_bw_inb
-# define __inw		mcpcia_bw_inw
-# define __inl		mcpcia_bw_inl
-# define __outb		mcpcia_bw_outb
-# define __outw		mcpcia_bw_outw
-# define __outl		mcpcia_bw_outl
-# define __readb	mcpcia_bw_readb
-# define __readw	mcpcia_bw_readw
-# define __writeb	mcpcia_bw_writeb
-# define __writew	mcpcia_bw_writew
-# define __readl	mcpcia_bw_readl
-# define __readq	mcpcia_bw_readq
-# define __writel	mcpcia_bw_writel
-# define __writeq	mcpcia_bw_writeq
+#define __inb		mcpcia_inb
+#define __inw		mcpcia_inw
+#define __inl		mcpcia_inl
+#define __outb		mcpcia_outb
+#define __outw		mcpcia_outw
+#define __outl		mcpcia_outl
+#ifdef CONFIG_ALPHA_SRM_SETUP
+# define __readb	mcpcia_srm_readb
+# define __readw	mcpcia_srm_readw
+# define __writeb	mcpcia_srm_writeb
+# define __writew	mcpcia_srm_writew
 #else
-# define __inb		mcpcia_inb
-# define __inw		mcpcia_inw
-# define __inl		mcpcia_inl
-# define __outb		mcpcia_outb
-# define __outw		mcpcia_outw
-# define __outl		mcpcia_outl
-# ifdef CONFIG_ALPHA_SRM_SETUP
-#  define __readb	mcpcia_srm_readb
-#  define __readw	mcpcia_srm_readw
-#  define __writeb	mcpcia_srm_writeb
-#  define __writew	mcpcia_srm_writew
-# else
-#  define __readb	mcpcia_readb
-#  define __readw	mcpcia_readw
-#  define __writeb	mcpcia_writeb
-#  define __writew	mcpcia_writew
-# endif
-# define __readl	mcpcia_readl
-# define __readq	mcpcia_readq
-# define __writel	mcpcia_writel
-# define __writeq	mcpcia_writeq
-#endif /* BWIO */
+# define __readb	mcpcia_readb
+# define __readw	mcpcia_readw
+# define __writeb	mcpcia_writeb
+# define __writew	mcpcia_writew
+#endif
+#define __readl		mcpcia_readl
+#define __readq		mcpcia_readq
+#define __writel	mcpcia_writel
+#define __writeq	mcpcia_writeq
 
 #define dense_mem	mcpcia_dense_mem
 
-#if 0 /* BWIO */
-# define inb(port) __inb((port))
-# define inw(port) __inw((port))
-# define inl(port) __inl((port))
-# define outb(x, port) __outb((x),(port))
-# define outw(x, port) __outw((x),(port))
-# define outl(x, port) __outl((x),(port))
-# define readb(addr) __readb((addr))
-# define readw(addr) __readw((addr))
-# define writeb(b, addr) __writeb((b),(addr))
-# define writew(b, addr) __writew((b),(addr))
-#else
-# define inb(port) \
-  (__builtin_constant_p((port))?__inb(port):_inb(port))
-# define outb(x, port) \
-  (__builtin_constant_p((port))?__outb((x),(port)):_outb((x),(port)))
-#endif /* BWIO */
+#define inb(port) \
+ (__builtin_constant_p((port))?__inb(port):_inb(port))
+#define outb(x, port) \
+ (__builtin_constant_p((port))?__outb((x),(port)):_outb((x),(port)))
 
 #define readl(a)	__readl((unsigned long)(a))
 #define readq(a)	__readq((unsigned long)(a))
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/core_pyxis.h linux.14p16/include/asm-alpha/core_pyxis.h
--- linux.vanilla/include/asm-alpha/core_pyxis.h	Sat Aug 14 02:27:37 1999
+++ linux.14p16/include/asm-alpha/core_pyxis.h	Thu Dec  9 15:32:51 1999
@@ -602,7 +602,7 @@
 #define virt_to_bus	pyxis_virt_to_bus
 #define bus_to_virt	pyxis_bus_to_virt
 
-#if defined(BWIO_ENABLED) && !defined(CONFIG_ALPHA_RUFFIAN)
+#if defined(BWIO_ENABLED)
 # define __inb		pyxis_bw_inb
 # define __inw		pyxis_bw_inw
 # define __inl		pyxis_bw_inl
@@ -643,7 +643,7 @@
 
 #define dense_mem	pyxis_dense_mem
 
-#if defined(BWIO_ENABLED) && !defined(CONFIG_ALPHA_RUFFIAN)
+#if defined(BWIO_ENABLED)
 # define inb(port) __inb((port))
 # define inw(port) __inw((port))
 # define inl(port) __inl((port))
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/delay.h linux.14p16/include/asm-alpha/delay.h
--- linux.vanilla/include/asm-alpha/delay.h	Tue Dec 29 21:56:15 1998
+++ linux.14p16/include/asm-alpha/delay.h	Thu Dec  9 15:32:51 1999
@@ -9,12 +9,18 @@
  * Delay routines, using a pre-computed "loops_per_second" value.
  */
 
+/* We can make the delay loop inline, but we have to be very careful
+ * WRT scheduling for EV6 machines, to keep it consistent for all locations
+ * of invocations. This is a reasonable compromise.
+ */
+
 extern __inline__ void
 __delay(unsigned long loops)
 {
-	__asm__ __volatile__(".align 3\n"
-		"1:\tsubq %0,1,%0\n\t"
-		"bge %0,1b": "=r" (loops) : "0" (loops));
+	__asm__ __volatile__(".align 4\n"
+		     "1:\tsubq %0,1,%0\n\t"
+		     "bge %0,1b\n\t"
+		     "nop": "=r" (loops) : "0" (loops));
 }
 
 /*
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/dma.h linux.14p16/include/asm-alpha/dma.h
--- linux.vanilla/include/asm-alpha/dma.h	Thu Dec 31 20:03:48 1998
+++ linux.14p16/include/asm-alpha/dma.h	Thu Dec  9 15:32:51 1999
@@ -91,6 +91,7 @@
 */
 #define ALPHA_XL_MAX_DMA_ADDRESS	(IDENT_ADDR+0x3000000UL)
 #define ALPHA_RUFFIAN_MAX_DMA_ADDRESS	(IDENT_ADDR+0x1000000UL)
+#define ALPHA_NAUTILUS_MAX_DMA_ADDRESS	(IDENT_ADDR+0x1000000UL)
 #define ALPHA_MAX_DMA_ADDRESS		(~0UL)
 
 #ifdef CONFIG_ALPHA_GENERIC
@@ -100,6 +101,8 @@
 #  define MAX_DMA_ADDRESS		ALPHA_XL_MAX_DMA_ADDRESS
 # elif defined(CONFIG_ALPHA_RUFFIAN)
 #  define MAX_DMA_ADDRESS		ALPHA_RUFFIAN_MAX_DMA_ADDRESS
+# elif defined(CONFIG_ALPHA_NAUTILUS)
+#  define MAX_DMA_ADDRESS		ALPHA_NAUTILUS_MAX_DMA_ADDRESS
 # else
 #  define MAX_DMA_ADDRESS		ALPHA_MAX_DMA_ADDRESS
 # endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/floppy.h linux.14p16/include/asm-alpha/floppy.h
--- linux.vanilla/include/asm-alpha/floppy.h	Sun Sep  6 18:34:33 1998
+++ linux.14p16/include/asm-alpha/floppy.h	Thu Dec  9 15:32:51 1999
@@ -64,7 +64,7 @@
 #ifdef CONFIG_ALPHA_GENERIC
 # define CROSS_64KB(a,s)   (__CROSS_64KB(a,s) && ~alpha_mv.max_dma_address)
 #else
-# if defined(CONFIG_ALPHA_XL) || defined(CONFIG_ALPHA_RUFFIAN)
+# if defined(CONFIG_ALPHA_XL) || defined(CONFIG_ALPHA_RUFFIAN) || defined(CONFIG_ALPHA_NAUTILUS)
 #  define CROSS_64KB(a,s)  __CROSS_64KB(a,s)
 # else
 #  define CROSS_64KB(a,s)  (0)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/hardirq.h linux.14p16/include/asm-alpha/hardirq.h
--- linux.vanilla/include/asm-alpha/hardirq.h	Mon Oct 12 19:40:13 1998
+++ linux.14p16/include/asm-alpha/hardirq.h	Thu Dec  9 15:32:51 1999
@@ -5,27 +5,26 @@
 
 #include <linux/tasks.h>
 
-extern unsigned int local_irq_count[NR_CPUS];
-extern unsigned long hardirq_no[NR_CPUS];
+#ifndef __SMP__
+extern unsigned long local_irq_count;
+#else
+#define local_irq_count         (cpu_data[smp_processor_id()].irq_count)
+#endif
 
 /*
  * Are we in an interrupt context? Either doing bottom half
  * or hardware interrupt processing?
  */
 
-#define in_interrupt()						\
-({								\
-	int __cpu = smp_processor_id();				\
-	(local_irq_count[__cpu] + local_bh_count[__cpu]) != 0;	\
-})
+#define in_interrupt()	((local_irq_count + local_bh_count) != 0)
 
 #ifndef __SMP__
 
-#define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
+#define hardirq_trylock(cpu)	(local_irq_count == 0)
 #define hardirq_endlock(cpu)	((void) 0)
 
-#define hardirq_enter(cpu, irq)	(local_irq_count[cpu]++)
-#define hardirq_exit(cpu, irq)	(local_irq_count[cpu]--)
+#define hardirq_enter(cpu, irq)	(local_irq_count++)
+#define hardirq_exit(cpu, irq)	(local_irq_count--)
 
 #define synchronize_irq()	barrier()
 
@@ -50,24 +49,23 @@
 
 static inline void hardirq_enter(int cpu, int irq)
 {
-	++local_irq_count[cpu];
+	++(cpu_data[cpu].irq_count);
         atomic_inc(&global_irq_count);
-	hardirq_no[cpu] |= 1L << irq;		/* debugging only */
 }
 
 static inline void hardirq_exit(int cpu, int irq)
 {
-	hardirq_no[cpu] &= ~(1L << irq);	/* debugging only */
 	atomic_dec(&global_irq_count);
-        --local_irq_count[cpu];
+	--(cpu_data[cpu].irq_count);
 }
 
 static inline int hardirq_trylock(int cpu)
 {
-	return !atomic_read(&global_irq_count) && !global_irq_lock.lock;
+	return  ! atomic_read(&global_irq_count) &&
+		! spin_is_locked(&global_irq_lock);
 }
 
-#define hardirq_endlock(cpu)  ((void)0)
+#define hardirq_endlock(cpu)	((void) 0)
 
 extern void synchronize_irq(void);
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/hwrpb.h linux.14p16/include/asm-alpha/hwrpb.h
--- linux.vanilla/include/asm-alpha/hwrpb.h	Mon Oct 12 19:40:13 1998
+++ linux.14p16/include/asm-alpha/hwrpb.h	Thu Dec  9 15:32:51 1999
@@ -55,10 +55,15 @@
 #define ST_DEC_TSUNAMI		 34	/* Tsunami systype	*/
 #define ST_DEC_WILDFIRE		 35	/* Wildfire systype	*/
 #define ST_DEC_CUSCO		 36	/* CUSCO systype	*/
+#define ST_DEC_EIGER		 37	/* Eiger systype	*/
 
 /* UNOFFICIAL!!! */
 #define ST_UNOFFICIAL_BIAS	100
 #define ST_DTI_RUFFIAN		101	/* RUFFIAN systype	*/
+
+/* Alpha Processor, Inc. systems */
+#define ST_API_BIAS		200			/* Offset for API systems */
+#define ST_API_NAUTILUS		(ST_API_BIAS + 1)	/* Nautilus systype */
 
 struct pcb_struct {
 	unsigned long ksp;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/io.h linux.14p16/include/asm-alpha/io.h
--- linux.vanilla/include/asm-alpha/io.h	Sat Aug 14 02:27:37 1999
+++ linux.14p16/include/asm-alpha/io.h	Thu Dec  9 15:32:51 1999
@@ -146,6 +146,8 @@
 # include <asm/core_polaris.h>
 #elif defined(CONFIG_ALPHA_LX164)
 # include <asm/core_pyxis.h>
+#elif defined(CONFIG_ALPHA_IRONGATE)
+# include <asm/core_irongate.h>
 #else
 #error "What system is this?"
 #endif
@@ -260,6 +262,8 @@
 static inline void iounmap(void *addr)
 {
 }
+
+#define ioremap_nocache(offset, size) ioremap((offset),(size))
 
 #ifndef readb
 # define readb(a)	_readb((unsigned long)(a))
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/irq.h linux.14p16/include/asm-alpha/irq.h
--- linux.vanilla/include/asm-alpha/irq.h	Sat Aug 14 02:26:51 1999
+++ linux.14p16/include/asm-alpha/irq.h	Thu Dec  9 15:32:51 1999
@@ -16,7 +16,7 @@
    many places throughout the kernel to size static arrays.  That's ok,
    we'll use alpha_mv.nr_irqs when we want the real thing.  */
 
-# define NR_IRQS	64
+# define NR_IRQS	128
 
 #elif defined(CONFIG_ALPHA_CABRIOLET) || \
       defined(CONFIG_ALPHA_EB66P)     || \
@@ -42,45 +42,17 @@
       defined(CONFIG_ALPHA_SX164)
 # define NR_IRQS	40
 
-#elif defined(CONFIG_ALPHA_DP264) || \
-      defined(CONFIG_ALPHA_RAWHIDE)
+#elif defined(CONFIG_ALPHA_DP264)     || \
+      defined(CONFIG_ALPHA_EIGER)
 # define NR_IRQS	64
 
-#elif defined(CONFIG_ALPHA_TAKARA)
-# define NR_IRQS	20
+#elif defined(CONFIG_ALPHA_RAWHIDE)   || \
+      defined(CONFIG_ALPHA_TAKARA)
+# define NR_IRQS	128
 
 #else /* everyone else */
 # define NR_IRQS	16
 #endif
-
-/*
- * PROBE_MASK is the bitset of irqs that we consider for autoprobing.
- */
-
-/* The normal mask includes all the IRQs except the timer.  */
-#define _PROBE_MASK(nr_irqs)	(((1UL << (nr_irqs & 63)) - 1) & ~1UL)
-
-/* Mask out unused timer irq 0 and RTC irq 8. */
-#define P2K_PROBE_MASK		(_PROBE_MASK(16) & ~0x101UL)
-
-/* Mask out unused timer irq 0, "irqs" 20-30, and the EISA cascade. */
-#define ALCOR_PROBE_MASK	(_PROBE_MASK(48) & ~0xfff000000001UL)
-
-/* Leave timer irq 0 in the mask.  */
-#define RUFFIAN_PROBE_MASK	(_PROBE_MASK(48) | 1UL)
-
-#if defined(CONFIG_ALPHA_GENERIC)
-# define PROBE_MASK	alpha_mv.irq_probe_mask
-#elif defined(CONFIG_ALPHA_P2K)
-# define PROBE_MASK	P2K_PROBE_MASK
-#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
-# define PROBE_MASK	ALCOR_PROBE_MASK
-#elif defined(CONFIG_ALPHA_RUFFIAN)
-# define PROBE_MASK	RUFFIAN_PROBE_MASK
-#else
-# define PROBE_MASK	_PROBE_MASK(NR_IRQS)
-#endif
-
 
 static __inline__ int irq_cannonicalize(int irq)
 {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/smp.h linux.14p16/include/asm-alpha/smp.h
--- linux.vanilla/include/asm-alpha/smp.h	Sat Aug 14 02:27:37 1999
+++ linux.14p16/include/asm-alpha/smp.h	Thu Dec  9 15:32:51 1999
@@ -7,6 +7,7 @@
 #include <asm/init.h>
 #include <asm/pal.h>
 
+/* make a multiple of 64-bytes */
 struct cpuinfo_alpha {
 	unsigned long loops_per_sec;
 	unsigned long last_asn;
@@ -16,6 +17,10 @@
 	unsigned long ipi_count;
 	unsigned long prof_multiplier;
 	unsigned long prof_counter;
+  /* start of second 64-bytes */
+	unsigned long irq_count;
+	unsigned long bh_count;
+	unsigned long __pad[6];
 } __cacheline_aligned;
 
 extern struct cpuinfo_alpha cpu_data[NR_CPUS];
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/softirq.h linux.14p16/include/asm-alpha/softirq.h
--- linux.vanilla/include/asm-alpha/softirq.h	Sun Dec 27 23:20:32 1998
+++ linux.14p16/include/asm-alpha/softirq.h	Thu Dec  9 15:32:51 1999
@@ -5,7 +5,11 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-extern unsigned int local_bh_count[NR_CPUS];
+#ifndef __SMP__
+extern unsigned long local_bh_count;
+#else
+#define local_bh_count          (cpu_data[smp_processor_id()].bh_count)
+#endif
 
 #define get_active_bhs()	(bh_mask & bh_active)
 
@@ -70,7 +74,7 @@
 {
 	if (!test_and_set_bit(0,&global_bh_count)) {
 		if (atomic_read(&global_bh_lock) == 0) {
-			++local_bh_count[cpu];
+			++local_bh_count;
 			return 1;
 		}
 		clear_bit(0,&global_bh_count);
@@ -80,7 +84,7 @@
 
 static inline void softirq_endlock(int cpu)
 {
-	local_bh_count[cpu]--;
+	local_bh_count--;
 	clear_bit(0,&global_bh_count);
 }
 
@@ -88,22 +92,22 @@
 
 extern inline void start_bh_atomic(void)
 {
-	local_bh_count[smp_processor_id()]++;
+	local_bh_count++;
 	barrier();
 }
 
 extern inline void end_bh_atomic(void)
 {
 	barrier();
-	local_bh_count[smp_processor_id()]--;
+	local_bh_count--;
 }
 
 /* These are for the irq's testing the lock */
 #define softirq_trylock(cpu) \
-  (local_bh_count[cpu] ? 0 : (local_bh_count[cpu] = 1))
+  (local_bh_count ? 0 : (local_bh_count = 1))
 
 #define softirq_endlock(cpu) \
-  (local_bh_count[cpu] = 0)
+  (local_bh_count = 0)
 
 #define synchronize_bh()	do { } while (0)
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/spinlock.h linux.14p16/include/asm-alpha/spinlock.h
--- linux.vanilla/include/asm-alpha/spinlock.h	Sat Aug 14 02:27:37 1999
+++ linux.14p16/include/asm-alpha/spinlock.h	Thu Dec  9 15:32:51 1999
@@ -25,6 +25,7 @@
 #define spin_unlock(lock)			((void) 0)
 #define spin_lock_irq(lock)			cli()
 #define spin_unlock_irq(lock)			sti()
+#define spin_is_locked(lock)			(0)
 
 #define spin_lock_irqsave(lock, flags)		save_and_cli(flags)
 #define spin_unlock_irqrestore(lock, flags)	restore_flags(flags)
@@ -97,6 +98,9 @@
 #define SPIN_LOCK_UNLOCKED	(spinlock_t) { 0 }
 #define spin_lock_init(x)	((x)->lock = 0)
 #endif
+
+#define spin_is_locked(lp) \
+	(*((volatile unsigned int *)(&((lp)->lock))) != 0)
 
 #define spin_unlock_wait(x) \
 	({ do { barrier(); } while(((volatile spinlock_t *)x)->lock); })
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/system.h linux.14p16/include/asm-alpha/system.h
--- linux.vanilla/include/asm-alpha/system.h	Sat Aug 14 02:27:37 1999
+++ linux.14p16/include/asm-alpha/system.h	Thu Dec  9 15:32:51 1999
@@ -86,6 +86,30 @@
         unsigned long   ld_lock;          /* Contents of EV5 LD_LOCK register*/
 };
 
+struct el_common_EV6_mcheck {
+	unsigned int FrameSize;		/* Bytes, including this field */
+	unsigned int FrameFlags;	/* <31> = Retry, <30> = Second Error */
+	unsigned int CpuOffset;		/* Offset to CPU-specific info */
+	unsigned int SystemOffset;	/* Offset to system-specific info */
+	unsigned int MCHK_Code;
+	unsigned int MCHK_Frame_Rev;
+	unsigned long I_STAT;		/* EV6 Internal Processor Registers */
+	unsigned long DC_STAT;		/* (See the 21264 Spec) */
+	unsigned long C_ADDR;
+	unsigned long DC1_SYNDROME;
+	unsigned long DC0_SYNDROME;
+	unsigned long C_STAT;
+	unsigned long C_STS;
+	unsigned long RESERVED0;
+	unsigned long EXC_ADDR;
+	unsigned long IER_CM;
+	unsigned long ISUM;
+	unsigned long MM_STAT;
+	unsigned long PAL_BASE;
+	unsigned long I_CTL;
+	unsigned long PCTX;
+};
+
 extern void halt(void) __attribute__((noreturn));
 
 #define switch_to(prev,next,last)			\
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/vga.h linux.14p16/include/asm-alpha/vga.h
--- linux.vanilla/include/asm-alpha/vga.h	Thu Feb 25 18:02:12 1999
+++ linux.14p16/include/asm-alpha/vga.h	Thu Dec  9 15:32:51 1999
@@ -11,6 +11,7 @@
 
 #define VT_BUF_HAVE_RW
 #define VT_BUF_HAVE_MEMSETW
+#define VT_BUF_HAVE_MEMCPYW
 #define VT_BUF_HAVE_MEMCPYF
 
 extern inline void scr_writew(u16 val, u16 *addr)
@@ -37,16 +38,28 @@
 		memsetw_io(s, c, count);
 }
 
-extern inline void scr_memcpyw_from(u16 *d, const u16 *s, unsigned int count)
+/* Try to do this the optimal way for the given destination and source. */
+extern inline void scr_memcpyw(u16 *d, const u16 *s, unsigned int count)
 {
-	memcpy_fromio(d, s, count);
-}
-
-extern inline void scr_memcpyw_to(u16 *d, const u16 *s, unsigned int count)
-{
-	memcpy_toio(d, s, count);
+    if ((long)s < 0) {	/* source is memory */
+	if ((long)d < 0) memcpy(d, s, count);		/* dest is memory */
+        else memcpy_toio(d, s, count);			/* dest is screen */
+    } else {		/* source is screen */
+	if ((long)d < 0) memcpy_fromio(d, s, count);	/* dest is memory */
+	else {						/* dest is screen */
+	    /* Right now, we do this the slow way,
+	       as we cannot handle screen unaligned ops...
+	    */
+	    count /= 2;
+	    while (count--)
+                scr_writew(scr_readw(s++), d++);
+	}
+    }
 }
 
+/* Do not trust that the usage will be correct; analyze the arguments. */
+#define scr_memcpyw_from scr_memcpyw
+#define scr_memcpyw_to   scr_memcpyw
 
 #define vga_readb readb
 #define vga_writeb writeb
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-i386/fixmap.h linux.14p16/include/asm-i386/fixmap.h
--- linux.vanilla/include/asm-i386/fixmap.h	Sun Mar 28 19:03:26 1999
+++ linux.14p16/include/asm-i386/fixmap.h	Mon Dec 13 19:35:54 1999
@@ -45,7 +45,10 @@
 	FIX_APIC_BASE,	/* local (CPU) APIC) -- required for SMP or not */
 #endif
 #ifdef CONFIG_X86_IO_APIC
-	FIX_IO_APIC_BASE,
+	FIX_IO_APIC_BASE_0,	/* IF YOU CHANGE THIS, PLEASE ALSO CHANGE */
+	FIX_IO_APIC_BASE_1,     /* MAX_IO_APICS in arch/i386/irq.h        */
+	FIX_IO_APIC_BASE_2,
+	FIX_IO_APIC_BASE_3,
 #endif
 #ifdef CONFIG_X86_VISWS_APIC
 	FIX_CO_CPU,	/* Cobalt timer */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-i386/sgi-cobalt.h linux.14p16/include/asm-i386/sgi-cobalt.h
--- linux.vanilla/include/asm-i386/sgi-cobalt.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-i386/sgi-cobalt.h	Thu Dec  9 15:32:50 1999
@@ -0,0 +1,119 @@
+#include <linux/config.h>
+#ifndef __I386_SGI_COBALT_H
+#define __I386_SGI_COBALT_H
+
+/*
+ * Cobalt SGI Visual Workstation system ASIC
+ */ 
+
+#define	CO_CPU_PHYS		0xc2000000
+#define	CO_APIC_PHYS		0xc4000000
+
+/* see set_fixmap() and asm/fixmap.h */
+#define	CO_CPU_VADDR		(fix_to_virt(FIX_CO_CPU))
+#define	CO_APIC_VADDR		(fix_to_virt(FIX_CO_APIC))
+
+/* Cobalt CPU registers -- relative to CO_CPU_VADDR, use co_cpu_*() */
+#define	CO_CPU_REV		0x08
+#define	CO_CPU_CTRL		0x10
+#define	CO_CPU_STAT		0x20
+#define	CO_CPU_TIMEVAL		0x30
+
+/* CO_CPU_CTRL bits */
+#define	CO_CTRL_TIMERUN		0x04		/* 0 == disabled */
+#define	CO_CTRL_TIMEMASK	0x08		/* 0 == unmasked */
+
+/* CO_CPU_STATUS bits */
+#define	CO_STAT_TIMEINTR	0x02	/* (r) 1 == int pend, (w) 0 == clear */
+
+/* CO_CPU_TIMEVAL value */
+#define	CO_TIME_HZ		100000000	/* Cobalt core rate */
+
+/* Cobalt APIC registers -- relative to CO_APIC_VADDR, use co_apic_*() */
+#define	CO_APIC_HI(n)		(((n) * 0x10) + 4)
+#define	CO_APIC_LO(n)		((n) * 0x10)
+#define	CO_APIC_ID		0x0ffc
+
+/* CO_APIC_ID bits */
+#define	CO_APIC_ENABLE		0x00000100
+
+/* CO_APIC_LO bits */
+#define	CO_APIC_MASK		0x00010000	/* 0 = enabled */
+#define	CO_APIC_LEVEL		0x00008000	/* 0 = edge */
+
+/*
+ * Where things are physically wired to Cobalt
+ * #defines with no board _<type>_<rev>_ are common to all (thus far)
+ */
+#define	CO_APIC_IDE0		4
+#define CO_APIC_IDE1		2		/* Only on 320 */
+
+#define	CO_APIC_8259		12		/* serial, floppy, par-l-l */
+
+/* Lithium PCI Bridge A -- "the one with 82557 Ethernet" */
+#define	CO_APIC_PCIA_BASE0	0 /* and 1 */	/* slot 0, line 0 */
+#define	CO_APIC_PCIA_BASE123	5 /* and 6 */	/* slot 0, line 1 */
+
+#define	CO_APIC_PIIX4_USB	7		/* this one is wierd */
+
+/* Lithium PCI Bridge B -- "the one with PIIX4" */
+#define	CO_APIC_PCIB_BASE0	8 /* and 9-12 *//* slot 0, line 0 */
+#define	CO_APIC_PCIB_BASE123	13 /* 14.15 */	/* slot 0, line 1 */
+
+#define	CO_APIC_VIDOUT0		16
+#define	CO_APIC_VIDOUT1		17
+#define	CO_APIC_VIDIN0		18
+#define	CO_APIC_VIDIN1		19
+
+#define	CO_APIC_LI_AUDIO	22
+
+#define	CO_APIC_AS		24
+#define	CO_APIC_RE		25
+
+#define CO_APIC_CPU		28		/* Timer and Cache interrupt */
+#define	CO_APIC_NMI		29
+#define	CO_APIC_LAST		CO_APIC_NMI
+
+/*
+ * This is how irqs are assigned on the Visual Workstation.
+ * Legacy devices get irq's 1-15 (system clock is 0 and is CO_APIC_CPU).
+ * All other devices (including PCI) go to Cobalt and are irq's 16 on up.
+ */
+#define	CO_IRQ_APIC0	16			/* irq of apic entry 0 */
+#define	IS_CO_APIC(irq)	((irq) >= CO_IRQ_APIC0)
+#define	CO_IRQ(apic)	(CO_IRQ_APIC0 + (apic))	/* apic ent to irq */
+#define	CO_APIC(irq)	((irq) - CO_IRQ_APIC0)	/* irq to apic ent */
+#define CO_IRQ_IDE0	14			/* knowledge of... */
+#define CO_IRQ_IDE1	15			/* ... ide driver defaults! */
+#define	CO_IRQ_8259	CO_IRQ(CO_APIC_8259)
+
+#ifdef CONFIG_X86_VISWS_APIC
+extern __inline void co_cpu_write(unsigned long reg, unsigned long v)
+{
+	*((volatile unsigned long *)(CO_CPU_VADDR+reg))=v;
+}
+
+extern __inline unsigned long co_cpu_read(unsigned long reg)
+{
+	return *((volatile unsigned long *)(CO_CPU_VADDR+reg));
+}            
+             
+extern __inline void co_apic_write(unsigned long reg, unsigned long v)
+{
+	*((volatile unsigned long *)(CO_APIC_VADDR+reg))=v;
+}            
+             
+extern __inline unsigned long co_apic_read(unsigned long reg)
+{
+	return *((volatile unsigned long *)(CO_APIC_VADDR+reg));
+}
+#endif
+
+extern char visws_board_type;
+
+#define	VISWS_320	0
+#define	VISWS_540	1
+
+extern char visws_board_rev;
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-ppc/gemini.h linux.14p16/include/asm-ppc/gemini.h
--- linux.vanilla/include/asm-ppc/gemini.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-ppc/gemini.h	Thu Dec  9 15:32:53 1999
@@ -0,0 +1,166 @@
+/*
+ *  include/asm-ppc/gemini.h
+ *
+ *
+ *  Onboard registers and descriptions for Synergy Microsystems' 
+ *  "Gemini" boards.
+ *
+ */
+#ifndef __PPC_GEMINI_H
+#define __PPC_GEMINI_H
+
+/*  Registers  */
+
+#define GEMINI_SERIAL_B     (0xffeffb00)
+#define GEMINI_SERIAL_A     (0xffeffb08)
+#define GEMINI_USWITCH      (0xffeffd00)
+#define GEMINI_BREV         (0xffeffe00)
+#define GEMINI_BECO         (0xffeffe08)
+#define GEMINI_FEAT         (0xffeffe10)
+#define GEMINI_BSTAT        (0xffeffe18)
+#define GEMINI_CPUSTAT      (0xffeffe20)
+#define GEMINI_L2CFG        (0xffeffe30)
+#define GEMINI_MEMCFG       (0xffeffe38)
+#define GEMINI_FLROM        (0xffeffe40)
+#define GEMINI_P0PCI        (0xffeffe48)
+#define GEMINI_FLWIN        (0xffeffe50)
+#define GEMINI_P0INTMASK    (0xffeffe60)
+#define GEMINI_P0INTAP      (0xffeffe68)
+#define GEMINI_PCIERR       (0xffeffe70)
+#define GEMINI_LEDBASE      (0xffeffe80)
+#define GEMINI_RTC          (0xffe9fff8)
+#define GEMINI_LEDS         8
+#define GEMINI_SWITCHES     8
+
+
+/* Flash ROM bit definitions */
+#define GEMINI_FLS_WEN      (1<<0)
+#define GEMINI_FLS_JMP      (1<<6)
+#define GEMINI_FLS_BOOT     (1<<7)
+
+/* Memory bit definitions */
+#define GEMINI_MEM_TYPE_MASK 0xc0
+#define GEMINI_MEM_SIZE_MASK 0x38
+#define GEMINI_MEM_BANK_MASK 0x07
+
+/* L2 cache bit definitions */
+#define GEMINI_L2_SIZE_MASK  0xc0
+#define GEMINI_L2_RATIO_MASK 0x03
+
+/* Timebase register bit definitons */
+#define GEMINI_TIMEB0_EN     (1<<0)
+#define GEMINI_TIMEB1_EN     (1<<1)
+#define GEMINI_TIMEB2_EN     (1<<2)
+#define GEMINI_TIMEB3_EN     (1<<3)
+
+/* CPU status bit definitions */
+#define GEMINI_CPU_ID_MASK   0x03
+#define GEMINI_CPU_COUNT_MASK 0x0c
+#define GEMINI_CPU0_HALTED   (1<<4)
+#define GEMINI_CPU1_HALTED   (1<<5)
+#define GEMINI_CPU2_HALTED   (1<<6)
+#define GEMINI_CPU3_HALTED   (1<<7)
+
+/* Board status bit definitions */
+#define GEMINI_BRD_FAIL      (1<<0)   /* FAIL led is lit */
+#define GEMINI_BRD_BUS_MASK  0x0c     /* PowerPC bus speed */
+
+/* Board family/feature bit descriptions */
+#define GEMINI_FEAT_HAS_FLASH (1<<0)
+#define GEMINI_FEAT_HAS_ETH   (1<<1)
+#define GEMINI_FEAT_HAS_SCSI  (1<<2)
+#define GEMINI_FEAT_HAS_P0    (1<<3)
+#define GEMINI_FEAT_FAM_MASK  0xf0
+
+/* Mod/ECO bit definitions */
+#define GEMINI_ECO_LEVEL_MASK 0x0f
+#define GEMINI_MOD_MASK       0xf0
+
+/* Type/revision bit definitions */
+#define GEMINI_REV_MASK       0x0f
+#define GEMINI_TYPE_MASK      0xf0
+
+/* User switch definitions */
+#define GEMINI_SWITCH_VERBOSE    1     /* adds "debug" to boot cmd line */
+#define GEMINI_SWITCH_SINGLE_USER 7    /* boots into "single-user" mode */
+
+#define SGS_RTC_CONTROL  0
+#define SGS_RTC_SECONDS  1
+#define SGS_RTC_MINUTES  2
+#define SGS_RTC_HOURS    3
+#define SGS_RTC_DAY      4
+#define SGS_RTC_DAY_OF_MONTH 5
+#define SGS_RTC_MONTH    6
+#define SGS_RTC_YEAR     7
+
+#define SGS_RTC_SET  0x80
+#define SGS_RTC_IS_STOPPED 0x80
+
+#define GRACKLE_CONFIG_ADDR_ADDR  (0xfec00000)
+#define GRACKLE_CONFIG_DATA_ADDR  (0xfee00000)
+
+#define GEMINI_BOOT_INIT  (0xfff00100)
+
+#ifndef __ASSEMBLY__
+
+static inline void grackle_write( unsigned long addr, unsigned long data )
+{
+  __asm__ __volatile__(
+  " stwbrx %1, 0, %0\n \
+    sync\n \
+    stwbrx %3, 0, %2\n \
+    sync "
+  : /* no output */
+  : "r" (GRACKLE_CONFIG_ADDR_ADDR), "r" (addr),
+    "r" (GRACKLE_CONFIG_DATA_ADDR), "r" (data));
+}
+
+static inline unsigned long grackle_read( unsigned long addr )
+{
+  unsigned long val;
+
+  __asm__ __volatile__(
+  " stwbrx %1, 0, %2\n \
+    sync\n \
+    lwbrx %0, 0, %3\n \
+    sync "
+  : "=r" (val)
+  : "r" (addr), "r" (GRACKLE_CONFIG_ADDR_ADDR),
+    "r" (GRACKLE_CONFIG_DATA_ADDR));
+
+  return val;
+}
+
+static inline void gemini_led_on( int led )
+{
+  if (led >= 0 && led < GEMINI_LEDS)
+    *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 1;
+}
+
+static inline void gemini_led_off(int led)
+{
+  if (led >= 0 && led < GEMINI_LEDS)
+    *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 0;
+}
+
+static inline int gemini_led_val(int led)
+{
+  int val = 0;
+  if (led >= 0 && led < GEMINI_LEDS)
+    val = *(unsigned char *)(GEMINI_LEDBASE + (led<<3));
+  return (val & 0x1);
+}
+
+/* returns processor id from the board */
+static inline int gemini_processor(void)
+{
+  unsigned char cpu = *(unsigned char *)(GEMINI_CPUSTAT);
+  return (int) ((cpu == 0) ? 4 : (cpu & GEMINI_CPU_ID_MASK));
+}
+
+
+extern void _gemini_reboot(void);
+extern void gemini_prom_init(void);
+extern void gemini_init_l2(void);
+#endif /* __ASSEMBLY__ */
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-ppc/gemini_serial.h linux.14p16/include/asm-ppc/gemini_serial.h
--- linux.vanilla/include/asm-ppc/gemini_serial.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-ppc/gemini_serial.h	Thu Dec  9 15:32:53 1999
@@ -0,0 +1,32 @@
+#ifndef __ASMPPC_GEMINI_SERIAL_H
+#define __ASMPPC_GEMINI_SERIAL_H
+
+#include <asm/gemini.h>
+
+/* Rate for the 24.576 Mhz clock for the onboard serial chip */
+#define BASE_BAUD  (24576000 / 16)
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF)
+#endif
+
+#define STD_SERIAL_PORT_DEFNS \
+        { 0, BASE_BAUD, GEMINI_SERIAL_A, 15, STD_COM_FLAGS }, /* ttyS0 */ \
+        { 0, BASE_BAUD, GEMINI_SERIAL_B, 14, STD_COM_FLAGS }, /* ttyS1 */ \
+
+#ifdef CONFIG_GEMINI_PU32
+#define PU32_SERIAL_PORT_DEFNS \
+        { 0, BASE_BAUD, NULL, 0, STD_COM_FLAGS },
+#else
+#define PU32_SERIAL_PORT_DEFNS
+#endif
+
+#define SERIAL_PORT_DFNS \
+        STD_SERIAL_PORT_DEFNS \
+        PU32_SERIAL_PORT_DEFNS
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-ppc/keyboard.h linux.14p16/include/asm-ppc/keyboard.h
--- linux.vanilla/include/asm-ppc/keyboard.h	Sat Aug 28 20:00:58 1999
+++ linux.14p16/include/asm-ppc/keyboard.h	Thu Dec  9 15:32:52 1999
@@ -15,73 +15,68 @@
 
 #ifdef __KERNEL__
 
-#include <linux/ioport.h>
-#include <asm/io.h>
-
 #include <linux/config.h>
-#include <asm/adb.h>
 #include <asm/machdep.h>
-#ifdef CONFIG_APUS
-#include <asm-m68k/keyboard.h>
-#else
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
 
 #define KEYBOARD_IRQ			1
 #define DISABLE_KBD_DURING_INTERRUPTS	0
 #define INIT_KBD
 
-#ifdef CONFIG_PREP
-extern int prep_kbd_present;
-#endif /* CONFIG_PREP */
-
 static inline int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
 {
-	return ppc_md.kbd_setkeycode(scancode, keycode);
+	if ( ppc_md.kbd_setkeycode )
+		return ppc_md.kbd_setkeycode(scancode, keycode);
+	else
+		return 0;
 }
   
 static inline int kbd_getkeycode(unsigned int scancode)
 {
-	return ppc_md.kbd_getkeycode(scancode);
+	if ( ppc_md.kbd_getkeycode )
+		return ppc_md.kbd_getkeycode(scancode);
+	else
+		return 0;
 }
   
 static inline int kbd_translate(unsigned char keycode, unsigned char *keycodep,
 				char raw_mode)
 {
-	return ppc_md.kbd_translate(keycode, keycodep, raw_mode);
+	if ( ppc_md.kbd_translate )
+		return ppc_md.kbd_translate(keycode, keycodep, raw_mode);
+	else
+		return 0;
 }
   
 static inline int kbd_unexpected_up(unsigned char keycode)
 {
-	return ppc_md.kbd_unexpected_up(keycode);
+	if ( ppc_md.kbd_unexpected_up )
+		return ppc_md.kbd_unexpected_up(keycode);
+	else
+		return 0;
 }
   
 static inline void kbd_leds(unsigned char leds)
 {
-#ifdef CONFIG_PREP
-	if (prep_kbd_present)
-#endif /* CONFIG_PREP */
+	if ( ppc_md.kbd_leds )
 		ppc_md.kbd_leds(leds);
 }
   
 static inline void kbd_init_hw(void)
 {
-#ifdef CONFIG_PREP
-	if (prep_kbd_present)
-#endif /* CONFIG_PREP */
+	if ( ppc_md.kbd_init_hw )
 		ppc_md.kbd_init_hw();
 }
 
-#define kbd_sysrq_xlate	(ppc_md.kbd_sysrq_xlate)
-
-#ifdef CONFIG_MAC_KEYBOARD
-# define SYSRQ_KEY 0x69
-#else
-# define SYSRQ_KEY 0x54
-#endif
+#define kbd_sysrq_xlate	(ppc_md.ppc_kbd_sysrq_xlate)
 
-#endif /* CONFIG_APUS */
+extern unsigned long SYSRQ_KEY;
 
 /* resource allocation */
-#define kbd_request_region() request_region(0x60, 16, "keyboard")
+#define kbd_request_region()
 #define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
                                              "keyboard", NULL)
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-ppc/m48t35.h linux.14p16/include/asm-ppc/m48t35.h
--- linux.vanilla/include/asm-ppc/m48t35.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-ppc/m48t35.h	Thu Dec  9 15:32:53 1999
@@ -0,0 +1,30 @@
+/*
+ *  Registers for the SGS-Thomson M48T35 Timekeeper RAM chip
+ */
+
+#ifndef __PPC_M48T35_H
+#define __PPC_M48T35_H
+
+/* RTC offsets */
+#define M48T35_RTC_CONTROL  0
+#define M48T35_RTC_SECONDS  1
+#define M48T35_RTC_MINUTES  2
+#define M48T35_RTC_HOURS    3
+#define M48T35_RTC_DAY      4
+#define M48T35_RTC_DOM      5
+#define M48T35_RTC_MONTH    6
+#define M48T35_RTC_YEAR     7
+
+#define M48T35_RTC_SET      0x80
+#define M48T35_RTC_STOPPED  0x80
+#define M48T35_RTC_READ     0x40
+
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(x)   ((x)=((x)&15) + ((x)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(x)   ((x)=(((x)/10)<<4) + (x)%10)
+#endif
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-ppc/processor.h linux.14p16/include/asm-ppc/processor.h
--- linux.vanilla/include/asm-ppc/processor.h	Sat Aug 28 20:00:58 1999
+++ linux.14p16/include/asm-ppc/processor.h	Thu Dec  9 15:32:52 1999
@@ -69,6 +69,7 @@
 #define _MACH_rpxlite 64  /* RPCG RPX-Lite 8xx board */
 #define _MACH_bseip   128 /* Bright Star Engineering ip-Engine */
 #define _MACH_yk      256 /* Motorola Yellowknife */
+#define _MACH_gemini  512 /* Synergy Microsystems gemini board */
 
 /* see residual.h for these */
 #define _PREP_Motorola 0x01  /* motorola prep */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-ppc/prom.h linux.14p16/include/asm-ppc/prom.h
--- linux.vanilla/include/asm-ppc/prom.h	Wed Oct 20 01:12:50 1999
+++ linux.14p16/include/asm-ppc/prom.h	Thu Dec  9 15:32:53 1999
@@ -63,7 +63,7 @@
 
 /* Prototypes */
 extern void abort(void);
-extern void prom_init(int, int, prom_entry);
+extern unsigned long prom_init(int, int, prom_entry);
 extern void prom_print(const char *msg);
 extern void relocate_nodes(void);
 extern void finish_device_tree(void);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-ppc/serial.h linux.14p16/include/asm-ppc/serial.h
--- linux.vanilla/include/asm-ppc/serial.h	Wed Aug  5 00:06:36 1998
+++ linux.14p16/include/asm-ppc/serial.h	Thu Dec  9 15:32:53 1999
@@ -4,7 +4,10 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_APUS
+#if defined(CONFIG_GEMINI)
+#include <asm/gemini_serial.h>
+#else
+#if defined(CONFIG_APUS)
 #include <asm-m68k/serial.h>
 #else
 
@@ -119,5 +122,5 @@
 	EXTRA_SERIAL_PORT_DEFNS		\
 	HUB6_SERIAL_PORT_DFNS		\
 	MCA_SERIAL_PORT_DFNS
-
-#endif /* CONFIG_APUS */
+#endif
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-ppc/smp.h linux.14p16/include/asm-ppc/smp.h
--- linux.vanilla/include/asm-ppc/smp.h	Sat Aug 14 02:26:21 1999
+++ linux.14p16/include/asm-ppc/smp.h	Thu Dec  9 15:32:52 1999
@@ -27,7 +27,8 @@
 
 extern void smp_message_pass(int target, int msg, unsigned long data, int wait);
 extern void smp_store_cpu_info(int id);
-extern void smp_message_recv(void);
+extern void smp_message_recv(int);
+extern void smp_send_tlb_invalidate(int);
 
 #define NO_PROC_ID		0xFF            /* No processor magic marker */
 #define PROC_CHANGE_PENALTY	20
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/a.out.h linux.14p16/include/asm-s390/a.out.h
--- linux.vanilla/include/asm-s390/a.out.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/a.out.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,38 @@
+/*
+ *  include/asm-s390/a.out.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *
+ *  Derived from "include/asm-i386/a.out.h"
+ *    Copyright (C) 1992, Linus Torvalds
+ *
+ * I don't think we'll ever need a.out ...
+ */
+
+#ifndef __S390_A_OUT_H__
+#define __S390_A_OUT_H__
+
+struct exec
+{
+  unsigned long a_info;		/* Use macros N_MAGIC, etc for access */
+  unsigned a_text;		/* length of text, in bytes */
+  unsigned a_data;		/* length of data, in bytes */
+  unsigned a_bss;		/* length of uninitialized data area for file, in bytes */
+  unsigned a_syms;		/* length of symbol table data in file, in bytes */
+  unsigned a_entry;		/* start address */
+  unsigned a_trsize;		/* length of relocation info for text, in bytes */
+  unsigned a_drsize;		/* length of relocation info for data, in bytes */
+};
+
+#define N_TRSIZE(a)	((a).a_trsize)
+#define N_DRSIZE(a)	((a).a_drsize)
+#define N_SYMSIZE(a)	((a).a_syms)
+
+#ifdef __KERNEL__
+
+#define STACK_TOP	TASK_SIZE
+
+#endif
+
+#endif /* __A_OUT_GNU_H__ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/atomic.h linux.14p16/include/asm-s390/atomic.h
--- linux.vanilla/include/asm-s390/atomic.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/atomic.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,191 @@
+#ifndef __ARCH_S390_ATOMIC__
+#define __ARCH_S390_ATOMIC__
+
+/*
+ *  include/asm-s390/atomic.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *               Denis Joseph Barrow
+ *
+ *  Derived from "include/asm-i386/bitops.h"
+ *    Copyright (C) 1992, Linus Torvalds
+ *
+ */
+
+/*
+ * Atomic operations that C can't guarantee us.  Useful for
+ * resource counting etc..
+ * S390 uses 'Compare And Swap' for atomicity in SMP enviroment
+ */
+
+typedef struct { volatile int counter; } atomic_t __attribute__ ((aligned (4)));
+#define ATOMIC_INIT(i)  { (i) }
+
+#define atomic_eieio()          __asm__ __volatile__ ("BCR 15,0")
+
+static __inline__ int atomic_read(atomic_t *v)
+{
+        int retval;
+        __asm__ __volatile("bcr      15,0\n\t"
+                           "l        %0,%1"
+                           : "=d" (retval) : "m" (*v) );
+        return retval;
+}
+
+static __inline__ void atomic_set(atomic_t *v, int i)
+{
+        __asm__ __volatile__("st  %1,%0\n\t"
+                             "bcr 15,0"
+                             : : "m" (*v), "d" (i) : "memory");
+}
+
+static __inline__ void atomic_add(int i, atomic_t *v)
+{
+        __asm__ __volatile__("   l     0,%0\n"
+                             "0: lr    1,0\n"
+                             "   ar    1,%1\n"
+                             "   cs    0,1,%0\n"
+                             "   jl    0b"
+                             : "+m" (*v) : "d" (i) : "0", "1" );
+}
+
+static __inline__ void atomic_sub(int i, atomic_t *v)
+{
+        __asm__ __volatile__("   l     0,%0\n"
+                             "0: lr    1,0\n"
+                             "   sr    1,%1\n"
+                             "   cs    0,1,%0\n"
+                             "   jl    0b"
+                             : "+m" (*v) : "d" (i) : "0", "1" );
+}
+
+static __inline__ void atomic_inc(volatile atomic_t *v)
+{
+        __asm__ __volatile__("   l     0,%0\n"
+                             "0: lr    1,0\n"
+                             "   ahi   1,1\n"
+                             "   cs    0,1,%0\n"
+                             "   jl    0b"
+                             : "+m" (*v) : : "0", "1" );
+}
+
+static __inline__ int atomic_inc_return(volatile atomic_t *v)
+{
+        int i;
+        __asm__ __volatile__("   l     0,%0\n"
+                             "0: lr    %1,0\n"
+                             "   ahi   %1,1\n"
+                             "   cs    0,%1,%0\n"
+                             "   jl    0b"
+                             : "+m" (*v), "=&d" (i) : : "0" );
+        return i;
+}
+
+static __inline__ void atomic_dec(volatile atomic_t *v)
+{
+        __asm__ __volatile__("   l     0,%0\n"
+                             "0: lr    1,0\n"
+                             "   ahi   1,-1\n"
+                             "   cs    0,1,%0\n"
+                             "   jl    0b"
+                             : "+m" (*v) : : "0", "1" );
+}
+
+static __inline__ int atomic_dec_return(volatile atomic_t *v)
+{
+        int i;
+        __asm__ __volatile__("   l     0,%0\n"
+                             "0: lr    %1,0\n"
+                             "   ahi   %1,-1\n"
+                             "   cs    0,%1,%0\n"
+                             "   jl    0b"
+                             : "+m" (*v), "=&d" (i) : : "0" );
+        return i;
+}
+
+static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
+{
+        int i;
+        __asm__ __volatile__("   l     0,%0\n"
+                             "0: lr    %1,0\n"
+                             "   ahi   %1,-1\n"
+                             "   cs    0,%1,%0\n"
+                             "   jl    0b"
+                             : "+m" (*v), "=&d" (i) : : "0");
+        return i == 0;
+}
+
+static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v)
+{
+        __asm__ __volatile__("   l     0,%0\n"
+                             "0: lr    1,0\n"
+                             "   nr    1,%1\n"
+                             "   cs    0,1,%0\n"
+                             "   jl    0b"
+                             : "+m" (*v) : "d" (~(mask)) : "0", "1" );
+}
+
+static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
+{
+        __asm__ __volatile__("   l     0,%0\n"
+                             "0: lr    1,0\n"
+                             "   or    1,%1\n"
+                             "   cs    0,1,%0\n"
+                             "   jl    0b"
+                             : "+m" (*v) : "d" (mask) : "0", "1" );
+}
+
+/*
+  returns 0  if expected_oldval==value in *v ( swap was successful )
+  returns 1  if unsuccessful.
+*/
+static __inline__ int
+atomic_compare_and_swap(int expected_oldval,int new_val,atomic_t *v)
+{
+        int retval;
+
+        __asm__ __volatile__(
+                "  cs   %2,%3,%1\n"
+                "  ipm  %0\n"
+                "  srl  %0,28\n"
+                "0:"
+                : "=&r" (retval), "+m" (*v)
+                : "d" (expected_oldval) , "d" (new_val)
+                : "memory", "cc");
+        return retval;
+}
+
+/*
+  Spin till *v = expected_oldval then swap with newval.
+ */
+static __inline__ void
+atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v)
+{
+        __asm__ __volatile__(
+                "0: lr  1,%1\n"
+                "   cs  1,%2,%0\n"
+                "   jl  0b\n"
+                : "+m" (*v)
+                : "d" (expected_oldval) , "d" (new_val)
+                : "memory", "cc", "1");
+}
+
+/*
+ * Increase and test if atomic counter > 0
+ */
+extern __inline__ int atomic_inc_and_test_greater_zero(volatile atomic_t *v)
+{
+        int i;
+        __asm__ __volatile__("   l     0,%0\n"
+                             "0: lr    %1,0\n"
+                             "   ahi   %1,1\n"
+                             "   cs    0,%1,%0\n"
+                             "   jl    0b"
+                             : "+m" (*v), "=&d" (i) : : "0" );
+        return i > 0;
+}
+
+#endif                                 /* __ARCH_S390_ATOMIC __            */
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/bitops.h linux.14p16/include/asm-s390/bitops.h
--- linux.vanilla/include/asm-s390/bitops.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/bitops.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,887 @@
+#ifndef _S390_BITOPS_H
+#define _S390_BITOPS_H
+
+/*
+ *  include/asm-s390/bitops.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *  Derived from "include/asm-i386/bitops.h"
+ *    Copyright (C) 1992, Linus Torvalds
+ *
+ */
+
+/*
+ * bit 0 is the LSB of *addr; bit 31 is the MSB of *addr;
+ * bit 32 is the LSB of *(addr+4). That combined with the
+ * big endian byte order on S390 give the following bit
+ * order in memory:
+ *    1f 1e 1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10 \
+ *    0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00
+ * after that follows the next long with bit numbers
+ *    3f 3e 3d 3c 3b 3a 39 38 37 36 35 34 33 32 31 30
+ *    2f 2e 2d 2c 2b 2a 29 28 27 26 25 24 23 22 21 20
+ * The reason for this bit ordering is the fact that
+ * in the architecture independent code bits operations
+ * of the form "flags |= (1 << bitnr)" are used INTERMIXED
+ * with operation of the form "set_bit(bitnr, flags)".
+ */
+
+/* set ALIGN_CS to 1 if the SMP safe bit operations should
+ * align the address to 4 byte boundary. It seems to work
+ * without the alignment. 
+ */
+#define ALIGN_CS 0
+
+/* bitmap tables from arch/S390/kernel/bitmap.S */
+extern const char _oi_bitmap[];
+extern const char _ni_bitmap[];
+extern const char _zb_findmap[];
+
+/*
+ * Function prototypes to keep gcc -Wall happy
+ */
+extern void __set_bit(int nr, volatile void * addr);
+extern void __constant_set_bit(int nr, volatile void * addr);
+extern int __test_bit(int nr, volatile void * addr);
+extern int __constant_test_bit(int nr, volatile void * addr);
+extern void __clear_bit(int nr, volatile void * addr);
+extern void __constant_clear_bit(int nr, volatile void * addr);
+extern void __change_bit(int nr, volatile void * addr);
+extern void __constant_change_bit(int nr, volatile void * addr);
+extern int test_and_set_bit(int nr, volatile void * addr);
+extern int test_and_clear_bit(int nr, volatile void * addr);
+extern int test_and_change_bit(int nr, volatile void * addr);
+extern int test_and_set_bit_simple(int nr, volatile void * addr);
+extern int test_and_clear_bit_simple(int nr, volatile void * addr);
+extern int test_and_change_bit_simple(int nr, volatile void * addr);
+extern int find_first_zero_bit(void * addr, unsigned size);
+extern int find_next_zero_bit (void * addr, int size, int offset);
+extern unsigned long ffz(unsigned long word);
+
+#ifdef __SMP__
+/*
+ * SMP save set_bit routine based on compare and swap (CS)
+ */
+extern __inline__ void set_bit_cs(int nr, volatile void * addr)
+{
+        __asm__ __volatile__(
+#if ALIGN_CS == 1
+             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
+             "   nr    1,%1\n"         /* isolate last 2 bits of address */
+             "   xr    %1,1\n"         /* make addr % 4 == 0 */
+             "   sll   1,3\n"
+             "   ar    %0,1\n"         /* add alignement to bitnr */
+#endif
+             "   lhi   1,31\n"
+             "   nr    1,%0\n"         /* make shift value */
+             "   xr    %0,1\n"
+             "   srl   %0,3\n"
+             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
+             "   lhi   2,1\n"
+             "   sll   2,0(1)\n"       /* make OR mask */
+             "   l     %0,0(%1)\n"
+             "0: lr    1,%0\n"         /* CS loop starts here */
+             "   or    1,2\n"          /* set bit */
+             "   cs    %0,1,0(%1)\n"
+             "   jl    0b"
+             : "+a" (nr), "+a" (addr) :
+             : "cc", "memory", "1", "2" );
+}
+
+/*
+ * SMP save clear_bit routine based on compare and swap (CS)
+ */
+extern __inline__ void clear_bit_cs(int nr, volatile void * addr)
+{
+        static const int mask = -1;
+        __asm__ __volatile__(
+#if ALIGN_CS == 1
+             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
+             "   nr    1,%1\n"         /* isolate last 2 bits of address */
+             "   xr    %1,1\n"         /* make addr % 4 == 0 */
+             "   sll   1,3\n"
+             "   ar    %0,1\n"         /* add alignement to bitnr */
+#endif
+             "   lhi   1,31\n"
+             "   nr    1,%0\n"         /* make shift value */
+             "   xr    %0,1\n"
+             "   srl   %0,3\n"
+             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
+             "   lhi   2,1\n"
+             "   sll   2,0(1)\n"
+             "   x     2,%2\n"         /* make AND mask */
+             "   l     %0,0(%1)\n"
+             "0: lr    1,%0\n"         /* CS loop starts here */
+             "   nr    1,2\n"          /* clear bit */
+             "   cs    %0,1,0(%1)\n"
+             "   jl    0b"
+             : "+a" (nr), "+a" (addr) : "m" (mask)
+             : "cc", "memory", "1", "2" );
+}
+
+/*
+ * SMP save change_bit routine based on compare and swap (CS)
+ */
+extern __inline__ void change_bit_cs(int nr, volatile void * addr)
+{
+        __asm__ __volatile__(
+#if ALIGN_CS == 1
+             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
+             "   nr    1,%1\n"         /* isolate last 2 bits of address */
+             "   xr    %1,1\n"         /* make addr % 4 == 0 */
+             "   sll   1,3\n"
+             "   ar    %0,1\n"         /* add alignement to bitnr */
+#endif
+             "   lhi   1,31\n"
+             "   nr    1,%0\n"         /* make shift value */
+             "   xr    %0,1\n"
+             "   srl   %0,3\n"
+             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
+             "   lhi   2,1\n"
+             "   sll   2,0(1)\n"       /* make XR mask */
+             "   l     %0,0(%1)\n"
+             "0: lr    1,%0\n"         /* CS loop starts here */
+             "   xr    1,2\n"          /* change bit */
+             "   cs    %0,1,0(%1)\n"
+             "   jl    0b"
+             : "+a" (nr), "+a" (addr) : 
+             : "cc", "memory", "1", "2" );
+}
+
+/*
+ * SMP save test_and_set_bit routine based on compare and swap (CS)
+ */
+extern __inline__ int test_and_set_bit_cs(int nr, volatile void * addr)
+{
+        __asm__ __volatile__(
+#if ALIGN_CS == 1
+             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
+             "   nr    1,%1\n"         /* isolate last 2 bits of address */
+             "   xr    %1,1\n"         /* make addr % 4 == 0 */
+             "   sll   1,3\n"
+             "   ar    %0,1\n"         /* add alignement to bitnr */
+#endif
+             "   lhi   1,31\n"
+             "   nr    1,%0\n"         /* make shift value */
+             "   xr    %0,1\n"
+             "   srl   %0,3\n"
+             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
+             "   lhi   2,1\n"
+             "   sll   2,0(1)\n"       /* make OR mask */
+             "   l     %0,0(%1)\n"
+             "0: lr    1,%0\n"         /* CS loop starts here */
+             "   or    1,2\n"          /* set bit */
+             "   cs    %0,1,0(%1)\n"
+             "   jl    0b\n"
+             "   nr    %0,2\n"         /* isolate old bit */
+             : "+a" (nr), "+a" (addr) :
+             : "cc", "memory", "1", "2" );
+        return nr;
+}
+
+/*
+ * SMP save test_and_clear_bit routine based on compare and swap (CS)
+ */
+extern __inline__ int test_and_clear_bit_cs(int nr, volatile void * addr)
+{
+        static const int mask = -1;
+        __asm__ __volatile__(
+#if ALIGN_CS == 1
+             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
+             "   nr    1,%1\n"         /* isolate last 2 bits of address */
+             "   xr    %1,1\n"         /* make addr % 4 == 0 */
+             "   sll   1,3\n"
+             "   ar    %0,1\n"         /* add alignement to bitnr */
+#endif
+             "   lhi   1,31\n"
+             "   nr    1,%0\n"         /* make shift value */
+             "   xr    %0,1\n"
+             "   srl   %0,3\n"
+             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
+             "   lhi   2,1\n"
+             "   sll   2,0(1)\n"
+             "   x     2,%2\n"         /* make AND mask */
+             "   l     %0,0(%1)\n"
+             "0: lr    1,%0\n"         /* CS loop starts here */
+             "   nr    1,2\n"          /* clear bit */
+             "   cs    %0,1,0(%1)\n"
+             "   jl    0b\n"
+             "   x     2,%2\n"
+             "   nr    %0,2\n"         /* isolate old bit */
+             : "+a" (nr), "+a" (addr) : "m" (mask)
+             : "cc", "memory", "1", "2" );
+        return nr;
+}
+
+/*
+ * SMP save test_and_change_bit routine based on compare and swap (CS) 
+ */
+extern __inline__ int test_and_change_bit_cs(int nr, volatile void * addr)
+{
+        __asm__ __volatile__(
+#if ALIGN_CS == 1
+             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
+             "   nr    1,%1\n"         /* isolate last 2 bits of address */
+             "   xr    %1,1\n"         /* make addr % 4 == 0 */
+             "   sll   1,3\n"
+             "   ar    %0,1\n"         /* add alignement to bitnr */
+#endif
+             "   lhi   1,31\n"
+             "   nr    1,%0\n"         /* make shift value */
+             "   xr    %0,1\n"
+             "   srl   %0,3\n"
+             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
+             "   lhi   2,1\n"
+             "   sll   2,0(1)\n"       /* make OR mask */
+             "   l     %0,0(%1)\n"
+             "0: lr    1,%0\n"         /* CS loop starts here */
+             "   xr    1,2\n"          /* change bit */
+             "   cs    %0,1,0(%1)\n"
+             "   jl    0b\n"
+             "   nr    %0,2\n"         /* isolate old bit */
+             : "+a" (nr), "+a" (addr) :
+             : "cc", "memory", "1", "2" );
+        return nr;
+}
+#endif /* __SMP__ */
+
+/*
+ * fast, non-SMP set_bit routine
+ */
+extern __inline__ void __set_bit(int nr, volatile void * addr)
+{
+        __asm__ __volatile__(
+             "   lhi   2,24\n"
+             "   lhi   1,7\n"
+             "   xr    2,%0\n"
+             "   nr    1,%0\n"
+             "   srl   2,3\n"
+             "   la    2,0(2,%1)\n"
+             "   la    1,0(1,%2)\n"
+             "   oc    0(1,2),0(1)"
+             :  : "r" (nr), "a" (addr), "a" (&_oi_bitmap)
+             : "cc", "memory", "1", "2" );
+}
+
+extern __inline__ void 
+__constant_set_bit(const int nr, volatile void * addr)
+{
+  switch (nr&7) {
+  case 0:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "oi 0(1),0x01"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3))) 
+                          : : "1", "cc", "memory");
+    break;
+  case 1:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "oi 0(1),0x02"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  case 2:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "oi 0(1),0x04"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  case 3:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "oi 0(1),0x08"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  case 4:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "oi 0(1),0x10"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  case 5:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "oi 0(1),0x20"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  case 6:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "oi 0(1),0x40"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  case 7:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "oi 0(1),0x80"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  }
+}
+
+#define set_bit_simple(nr,addr) \
+(__builtin_constant_p((nr)) ? \
+ __constant_set_bit((nr),(addr)) : \
+ __set_bit((nr),(addr)) )
+
+/*
+ * fast, non-SMP clear_bit routine
+ */
+extern __inline__ void 
+__clear_bit(int nr, volatile void * addr)
+{
+        __asm__ __volatile__(
+             "   lhi   2,24\n"
+             "   lhi   1,7\n"
+             "   xr    2,%0\n"
+             "   nr    1,%0\n"
+             "   srl   2,3\n"
+             "   la    2,0(2,%1)\n"
+             "   la    1,0(1,%2)\n"
+             "   nc    0(1,2),0(1)"
+             :  : "r" (nr), "a" (addr), "a" (&_ni_bitmap)
+             : "cc", "memory", "1", "2" );
+}
+
+extern __inline__ void 
+__constant_clear_bit(const int nr, volatile void * addr)
+{
+  switch (nr&7) {
+  case 0:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "ni 0(1),0xFE"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  case 1:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "ni 0(1),0xFD"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  case 2:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "ni 0(1),0xFB"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  case 3:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "ni 0(1),0xF7"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  case 4:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "ni 0(1),0xEF"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "cc", "memory" );
+    break;
+  case 5:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "ni 0(1),0xDF"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  case 6:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "ni 0(1),0xBF"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  case 7:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "ni 0(1),0x7F"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  }
+}
+
+#define clear_bit_simple(nr,addr) \
+(__builtin_constant_p((nr)) ? \
+ __constant_clear_bit((nr),(addr)) : \
+ __clear_bit((nr),(addr)) )
+
+/* 
+ * fast, non-SMP change_bit routine 
+ */
+extern __inline__ void __change_bit(int nr, volatile void * addr)
+{
+        __asm__ __volatile__(
+             "   lhi   2,24\n"
+             "   lhi   1,7\n"
+             "   xr    2,%0\n"
+             "   nr    1,%0\n"
+             "   srl   2,3\n"
+             "   la    2,0(2,%1)\n"
+             "   la    1,0(1,%2)\n"
+             "   xc    0(1,2),0(1)"
+             :  : "r" (nr), "a" (addr), "a" (&_oi_bitmap)
+             : "cc", "memory", "1", "2" );
+}
+
+extern __inline__ void 
+__constant_change_bit(const int nr, volatile void * addr) 
+{
+  switch (nr&7) {
+  case 0:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "xi 0(1),0x01"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "cc", "memory" );
+    break;
+  case 1:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "xi 0(1),0x02"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "cc", "memory" );
+    break;
+  case 2:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "xi 0(1),0x04"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "cc", "memory" );
+    break;
+  case 3:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "xi 0(1),0x08"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "cc", "memory" );
+    break;
+  case 4:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "xi 0(1),0x10"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "cc", "memory" );
+    break;
+  case 5:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "xi 0(1),0x20"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  case 6:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "xi 0(1),0x40"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  case 7:
+    __asm__ __volatile__ ("la 1,%0\n\t"
+                          "xi 0(1),0x80"
+                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
+                          : : "1", "cc", "memory" );
+    break;
+  }
+}
+
+#define change_bit_simple(nr,addr) \
+(__builtin_constant_p((nr)) ? \
+ __constant_change_bit((nr),(addr)) : \
+ __change_bit((nr),(addr)) )
+
+/*
+ * fast, non-SMP test_and_set_bit routine
+ */
+extern __inline__ int test_and_set_bit_simple(int nr, volatile void * addr)
+{
+        static const int mask = 1;
+        int oldbit;
+        __asm__ __volatile__(
+             "   lhi   1,24\n"
+             "   lhi   2,7\n"
+             "   xr    1,%1\n"
+             "   nr    2,1\n"
+             "   srl   1,3(0)\n"
+             "   la    1,0(1,%2)\n"
+             "   ic    %0,0(0,1)\n"
+             "   srl   %0,0(2)\n"
+             "   n     %0,%4\n"
+             "   la    2,0(2,%3)\n"
+             "   oc    0(1,1),0(2)"
+             : "=d&" (oldbit) : "r" (nr), "a" (addr),
+               "a" (&_oi_bitmap), "m" (mask)
+             : "cc", "memory", "1", "2" );
+        return oldbit;
+}
+
+/*
+ * fast, non-SMP test_and_clear_bit routine
+ */
+extern __inline__ int test_and_clear_bit_simple(int nr, volatile void * addr)
+{
+        static const int mask = 1;
+        int oldbit;
+
+        __asm__ __volatile__(
+             "   lhi   1,24\n"
+             "   lhi   2,7\n"
+             "   xr    1,%1\n"
+             "   nr    2,1\n"
+             "   srl   1,3(0)\n"
+             "   la    1,0(1,%2)\n"
+             "   ic    %0,0(0,1)\n"
+             "   srl   %0,0(2)\n"
+             "   n     %0,%4\n"
+             "   la    2,0(2,%3)\n"
+             "   nc    0(1,1),0(2)"
+             : "=d&" (oldbit) : "r" (nr), "a" (addr),
+               "a" (&_ni_bitmap), "m" (mask)
+             : "cc", "memory", "1", "2" );
+        return oldbit;
+}
+
+/*
+ * fast, non-SMP test_and_change_bit routine
+ */
+extern __inline__ int test_and_change_bit_simple(int nr, volatile void * addr)
+{
+        static const int mask = 1;
+        int oldbit;
+
+        __asm__ __volatile__(
+             "   lhi   1,24\n"
+             "   lhi   2,7\n"
+             "   xr    1,%1\n"
+             "   nr    2,1\n"
+             "   srl   1,3(0)\n"
+             "   la    1,0(1,%2)\n"
+             "   ic    %0,0(0,1)\n"
+             "   srl   %0,0(2)\n"
+             "   n     %0,%4\n"
+             "   la    2,0(2,%3)\n"
+             "   xc    0(1,1),0(2)"
+             : "=d&" (oldbit) : "r" (nr), "a" (addr),
+               "a" (&_oi_bitmap), "m" (mask)
+             : "cc", "memory", "1", "2" );
+        return oldbit;
+}
+
+#ifdef __SMP__
+#define set_bit             set_bit_cs
+#define clear_bit           clear_bit_cs
+#define change_bit          change_bit_cs
+#define test_and_set_bit    test_and_set_bit_cs
+#define test_and_clear_bit  test_and_clear_bit_cs
+#define test_and_change_bit test_and_change_bit_cs
+#else
+#define set_bit             set_bit_simple
+#define clear_bit           clear_bit_simple
+#define change_bit          change_bit_simple
+#define test_and_set_bit    test_and_set_bit_simple
+#define test_and_clear_bit  test_and_clear_bit_simple
+#define test_and_change_bit test_and_change_bit_simple
+#endif
+
+
+/*
+ * This routine doesn't need to be atomic.
+ */
+
+extern __inline__ int __test_bit(int nr, volatile void * addr)
+{
+        static const int mask = 1;
+        int oldbit;
+
+        __asm__ __volatile__(
+             "   lhi   2,24\n"
+             "   lhi   1,7\n"
+             "   xr    2,%1\n"
+             "   nr    1,%1\n"
+             "   srl   2,3\n"
+             "   ic    %0,0(2,%2)\n"
+             "   srl   %0,0(1)\n"
+             "   n     %0,%3"
+             : "=d&" (oldbit) : "r" (nr), "a" (addr),
+               "m" (mask)
+             : "cc", "1", "2" );
+        return oldbit;
+}
+
+extern __inline__ int __constant_test_bit(int nr, volatile void * addr) {
+    return (((volatile char *) addr)[(nr>>3)^3] & (1<<(nr&7))) != 0;
+}
+
+#define test_bit(nr,addr) \
+(__builtin_constant_p((nr)) ? \
+ __constant_test_bit((nr),(addr)) : \
+ __test_bit((nr),(addr)) )
+
+/*
+ * Find-bit routines..
+ */
+extern __inline__ int find_first_zero_bit(void * addr, unsigned size)
+{
+        static const int mask = 0xffL;
+        int res;
+
+        if (!size)
+                return 0;
+        __asm__("   lhi  0,-1\n"
+                "   lr   1,%1\n"
+                "   ahi  1,31\n"
+                "   srl  1,5\n"
+                "   sr   2,2\n"
+                "0: c    0,0(2,%2)\n"
+                "   jne  1f\n"
+                "   ahi  2,4\n"
+                "   brct 1,0b\n"
+                "   lr   2,%1\n"
+                "   j    4f\n"
+                "1: l    1,0(2,%2)\n"
+                "   sll  2,3(0)\n"
+                "   tml  1,0xFFFF\n"
+                "   jno  2f\n"
+                "   ahi  2,16\n"
+                "   srl  1,16\n"
+                "2: tml  1,0x00FF\n"
+                "   jno  3f\n"
+                "   ahi  2,8\n"
+                "   srl  1,8\n"
+                "3: n    1,%3\n"
+                "   ic   1,0(1,%4)\n"
+                "   n    1,%3\n"
+                "   ar   2,1\n"
+                "4: lr   %0,2"
+                : "=d" (res) : "a" (size), "a" (addr),
+                  "m" (mask), "a" (&_zb_findmap)
+                : "cc", "0", "1", "2" );
+        return (res < size) ? res : size;
+}
+
+extern __inline__ int find_next_zero_bit (void * addr, int size, int offset)
+{
+        static const int mask = 0xffL;
+        unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
+        unsigned long bitvec;
+        int set, bit = offset & 31, res;
+
+        if (bit) {
+                /*
+                 * Look for zero in first word
+                 */
+                bitvec = (*p) >> bit;
+                __asm__("   lr   1,%1\n"
+                        "   sr   %0,%0\n"
+                        "   tml  1,0xFFFF\n"
+                        "   jno  0f\n"
+                        "   ahi  %0,16\n"
+                        "   srl  1,16\n"
+                        "0: tml  1,0x00FF\n"
+                        "   jno  1f\n"
+                        "   ahi  %0,8\n"
+                        "   srl  1,8\n"
+                        "1: n    1,%2\n"
+                        "   ic   1,0(1,%3)\n"
+                        "   n    1,%2\n"
+                        "   ar   %0,1"
+                        : "=d&" (set) : "d" (bitvec),
+                          "m" (mask), "a" (&_zb_findmap)
+                          : "cc", "1" );
+                if (set < (32 - bit))
+                        return set + offset;
+                offset += 32 - bit;
+                p++;
+        }
+        /*
+         * No zero yet, search remaining full words for a zero
+         */
+        res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr));
+        return (offset + res);
+}
+
+/*
+ * ffz = Find First Zero in word. Undefined if no zero exists,
+ * so code should check against ~0UL first..
+ */
+extern __inline__ unsigned long ffz(unsigned long word)
+{
+        static const int mask = 0xffL;
+        int result;
+
+        __asm__("   lr   1,%1\n"
+                "   sr   %0,%0\n"
+                "   tml  1,0xFFFF\n"
+                "   jno  0f\n"
+                "   ahi  %0,16\n"
+                "   srl  1,16\n"
+                "0: tml  1,0x00FF\n"
+                "   jno  1f\n"
+                "   ahi  %0,8\n"
+                "   srl  1,8\n"
+                "1: n    1,%2\n"
+                "   ic   1,0(1,%3)\n"
+                "   n    1,%2\n"
+                "   ar   %0,1"
+                : "=d&" (result) : "d" (word), 
+                  "m" (mask), "a" (&_zb_findmap)
+                : "cc", "1" );
+
+        return result;
+}
+
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+extern int __inline__ ffs (int x)
+{
+        int r;
+
+        if (x == 0)
+          return 0;
+        __asm__("    lr   %%r1,%1\n"
+                "    sr   %0,%0\n"
+                "    tmh  %%r1,0xFFFF\n"
+                "    jz   0f\n"
+                "    ahi  %0,16\n"
+                "    srl  %%r1,16\n"
+                "0:  tml  %%r1,0xFF00\n"
+                "    jz   1f\n"
+                "    ahi  %0,8\n"
+                "    srl  %%r1,8\n"
+                "1:  tml  %%r1,0x00F0\n"
+                "    jz   2f\n"
+                "    ahi  %0,4\n"
+                "    srl  %%r1,4\n"
+                "2:  tml  %%r1,0x000C\n"
+                "    jz   3f\n"
+                "    ahi  %0,2\n"
+                "    srl  %%r1,2\n"
+                "3:  tml  %%r1,0x0002\n"
+                "    jz   4f\n"
+                "    ahi  %0,1\n"
+                "4:"
+                : "=&d" (r) : "d" (x) : "cc", "1" );
+        return r+1;
+}
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+
+#ifdef __KERNEL__
+
+/*
+ * ATTENTION: intel byte ordering convention for ext2 and minix !!
+ * bit 0 is the LSB of addr; bit 31 is the MSB of addr;
+ * bit 32 is the LSB of (addr+4).
+ * That combined with the little endian byte order of Intel gives the
+ * following bit order in memory:
+ *    07 06 05 04 03 02 01 00 15 14 13 12 11 10 09 08 \
+ *    23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24
+ */
+
+#define ext2_set_bit(nr, addr)       test_and_set_bit((nr)^24, addr)
+#define ext2_clear_bit(nr, addr)     test_and_clear_bit((nr)^24, addr)
+#define ext2_test_bit(nr, addr)      test_bit((nr)^24, addr)
+extern __inline__ int ext2_find_first_zero_bit(void *vaddr, unsigned size)
+{
+        static const int mask = 0xffL;
+        int res;
+
+        if (!size)
+                return 0;
+        __asm__("   lhi  0,-1\n"
+                "   lr   1,%1\n"
+                "   ahi  1,31\n"
+                "   srl  1,5\n"
+                "   sr   2,2\n"
+                "0: c    0,0(2,%2)\n"
+                "   jne  1f\n"
+                "   ahi  2,4\n"
+                "   brct 1,0b\n"
+                "   lr   2,%1\n"
+                "   j    4f\n"
+                "1: l    1,0(2,%2)\n"
+                "   sll  2,3(0)\n"
+                "   ahi  2,24\n"
+                "   tmh  1,0xFFFF\n"
+                "   jo   2f\n"
+                "   ahi  2,-16\n"
+                "   srl  1,16\n"
+                "2: tml  1,0xFF00\n"
+                "   jo   3f\n"
+                "   ahi  2,-8\n"
+                "   srl  1,8\n"
+                "3: n    1,%3\n"
+                "   ic   1,0(1,%4)\n"
+                "   n    1,%3\n"
+                "   ar   2,1\n"
+                "4: lr   %0,2"
+                : "=d" (res) : "a" (size), "a" (vaddr),
+                  "m" (mask), "a" (&_zb_findmap)
+                  : "cc", "0", "1", "2" );
+        return (res < size) ? res : size;
+}
+
+extern __inline__ int 
+ext2_find_next_zero_bit(void *vaddr, unsigned size, unsigned offset)
+{
+        static const int mask = 0xffL;
+        static unsigned long orword[32] = {
+		0x00000000, 0x01000000, 0x03000000, 0x07000000,
+		0x0f000000, 0x1f000000, 0x3f000000, 0x7f000000,
+		0xff000000, 0xff010000, 0xff030000, 0xff070000,
+                0xff0f0000, 0xff1f0000, 0xff3f0000, 0xff7f0000,
+		0xffff0000, 0xffff0100, 0xffff0300, 0xffff0700,
+		0xffff0f00, 0xffff1f00, 0xffff3f00, 0xffff7f00,
+		0xffffff00, 0xffffff01, 0xffffff03, 0xffffff07,
+		0xffffff0f, 0xffffff1f, 0xffffff3f, 0xffffff7f
+	};
+        unsigned long *addr = vaddr;
+        unsigned long *p = addr + (offset >> 5);
+        unsigned long word;
+        int bit = offset & 31UL, res;
+
+        if (offset >= size)
+                return size;
+
+        if (bit) {
+		word = *p | orword[bit];
+                /* Look for zero in first longword */
+                __asm__("   lhi  %0,24\n"
+                	"   tmh  %1,0xFFFF\n"
+                	"   jo   0f\n"
+                	"   ahi  %0,-16\n"
+                	"   srl  %1,16\n"
+                	"0: tml  %1,0xFF00\n"
+                	"   jo   1f\n"
+                	"   ahi  %0,-8\n"
+                	"   srl  %1,8\n"
+                	"1: n    %1,%2\n"
+                	"   ic   %1,0(%1,%3)\n"
+                	"   alr  %0,%1"
+                	: "=&d" (res), "+&d" (word)
+                  	: "m" (mask), "a" (&_zb_findmap)
+                	: "cc" );
+                if (res < 32)
+			return (p - addr)*32 + res;
+                p++;
+        }
+        /* No zero yet, search remaining full bytes for a zero */
+        res = ext2_find_first_zero_bit (p, size - 32 * (p - addr));
+        return (p - addr) * 32 + res;
+}
+
+/* Bitmap functions for the minix filesystem.  */
+/* FIXME !!! */
+#define minix_set_bit(nr,addr) test_and_set_bit(nr,addr)
+#define minix_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
+#define minix_test_bit(nr,addr) test_bit(nr,addr)
+#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
+
+#endif /* __KERNEL__ */
+
+#endif /* _S390_BITOPS_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/bugs.h linux.14p16/include/asm-s390/bugs.h
--- linux.vanilla/include/asm-s390/bugs.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/bugs.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,22 @@
+/*
+ *  include/asm-s390/bugs.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *  Derived from "include/asm-i386/bugs.h"
+ *    Copyright (C) 1994  Linus Torvalds
+ */
+
+/*
+ * This is included by init/main.c to check for architecture-dependent bugs.
+ *
+ * Needs:
+ *      void check_bugs(void);
+ */
+
+__initfunc(static void check_bugs(void))
+{
+  /* s390 has no bugs ... */
+}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/byteorder.h linux.14p16/include/asm-s390/byteorder.h
--- linux.vanilla/include/asm-s390/byteorder.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/byteorder.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,103 @@
+#ifndef _S390_BYTEORDER_H
+#define _S390_BYTEORDER_H
+
+/*
+ *  include/asm-s390/byteorder.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+
+#include <asm/types.h>
+
+#ifdef __GNUC__
+
+static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
+{
+  __u32 temp;
+
+  __asm__ __volatile__ (
+          "        st    %0,0(%1)\n"
+          "        icm   %0,8,3(%1)\n"
+          "        icm   %0,4,2(%1)\n"
+          "        icm   %0,2,1(%1)\n"
+          "        ic    %0,0(%1)"
+          : "+&d" (x) : "a" (&temp) : "memory" );
+  return x;
+}
+
+static __inline__ __const__ __u32 ___arch__swab32p(__u32 *x)
+{
+  __u32 result;
+
+  __asm__ __volatile__ (
+          "        icm   %0,8,3(%1)\n"
+          "        icm   %0,4,2(%1)\n"
+          "        icm   %0,2,1(%1)\n"
+          "        ic    %0,0(%1)"
+          : "=&d" (result) : "a" (x) );
+  return result;
+}
+
+static __inline__ void ___arch__swab32s(__u32 *x)
+{
+  __asm__ __volatile__ (
+          "        icm   0,8,3(%0)\n"
+          "        icm   0,4,2(%0)\n"
+          "        icm   0,2,1(%0)\n"
+          "        ic    0,0(%0)\n"
+          "        st    0,0(%0)"
+          : : "a" (x) : "0", "memory");
+}
+
+static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
+{
+  __u16 temp;
+
+  __asm__ __volatile__ (
+          "        sth   %0,0(%1)\n"
+          "        icm   %0,2,1(%1)\n"
+          "        ic    %0,0(%1)\n"
+          : "+&d" (x) : "a" (&temp) : "memory");
+  return x;
+}
+
+static __inline__ __const__ __u16 ___arch__swab16p(__u16 *x)
+{
+  __u16 result;
+
+  __asm__ __volatile__ (
+          "        sr    %0,%0\n"
+          "        icm   %0,2,1(%1)\n"
+          "        ic    %0,0(%1)\n"
+          : "=&d" (result) : "a" (x) );
+  return result;
+}
+
+static __inline__ void ___arch__swab16s(__u16 *x)
+{
+  __asm__ __volatile__(
+          "        icm   0,2,1(%0)\n"
+          "        ic    0,0(%0)\n"
+          "        sth   0,0(%0)"
+          : : "a" (x) : "0", "memory");
+}
+
+#define __arch__swab32(x) ___arch__swab32(x)
+#define __arch__swab16(x) ___arch__swab16(x)
+#define __arch__swab32p(x) ___arch__swab32p(x)
+#define __arch__swab16p(x) ___arch__swab16p(x)
+#define __arch__swab32s(x) ___arch__swab32s(x)
+#define __arch__swab16s(x) ___arch__swab16s(x)
+
+#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+#  define __BYTEORDER_HAS_U64__
+#  define __SWAB_64_THRU_32__
+#endif
+
+#endif /* __GNUC__ */
+
+#include <linux/byteorder/big_endian.h>
+
+#endif /* _S390_BYTEORDER_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/cache.h linux.14p16/include/asm-s390/cache.h
--- linux.vanilla/include/asm-s390/cache.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/cache.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,19 @@
+/*
+ *  include/asm-s390/cache.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *
+ *  Derived from "include/asm-i386/cache.h"
+ *    Copyright (C) 1992, Linus Torvalds
+ */
+
+#ifndef __ARCH_S390_CACHE_H
+#define __ARCH_S390_CACHE_H
+
+#define L1_CACHE_BYTES     16
+
+#define L1_CACHE_ALIGN(x)  (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
+#define	SMP_CACHE_BYTES    L1_CACHE_BYTES
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/checksum.h linux.14p16/include/asm-s390/checksum.h
--- linux.vanilla/include/asm-s390/checksum.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/checksum.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,188 @@
+#ifndef _S390_CHECKSUM_H
+#define _S390_CHECKSUM_H
+
+/*
+ *  include/asm-s390/checksum.h
+ *    S390 fast network checksum routines
+ *    see also arch/S390/lib/checksum.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Ulrich Hild        (first version)
+ *               Martin Schwidefsky (heavily optimized CKSM version)
+ *               D.J. Barrow        (third attempt) 
+ */
+
+#include <asm/uaccess.h>
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+unsigned int
+csum_partial(const unsigned char * buff, int len, unsigned int sum);
+
+/*
+ * csum_partial as an inline function
+ */
+extern inline unsigned int 
+csum_partial_inline(const unsigned char * buff, int len, unsigned int sum)
+{
+	__asm__ __volatile__ (
+		"    lr   2,%1\n"    /* address in gpr 2 */
+		"    lr   3,%2\n"    /* length in gpr 3 */
+		"0:  cksm %0,2\n"    /* do checksum on longs */
+		"    jo   0b\n"
+                : "+&d" (sum)
+		: "d" (buff), "d" (len)
+                : "cc", "2", "3" );
+	return sum;
+}
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+extern inline unsigned int 
+csum_partial_copy(const char *src, char *dst, int len,unsigned int sum)
+{
+	memcpy(dst,src,len);
+        return csum_partial_inline(dst, len, sum);
+}
+
+/*
+ * the same as csum_partial_copy, but copies from user space.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+extern inline unsigned int 
+csum_partial_copy_from_user(const char *src, char *dst,
+                            int len, unsigned int sum, int *errp)
+{
+	if (copy_from_user(dst, src, len)) {
+		*errp = -EFAULT;
+		memset(dst, 0, len);
+		return sum;
+        }
+        return csum_partial(dst, len, sum);
+}
+
+extern inline unsigned int
+csum_partial_copy_nocheck (const char *src, char *dst, int len, unsigned int sum)
+{
+        memcpy(dst,src,len);
+        return csum_partial_inline(dst, len, sum);
+}
+
+/*
+ *      Fold a partial checksum without adding pseudo headers
+ */
+#if 1
+unsigned short csum_fold(unsigned int sum);
+#else
+extern inline unsigned short
+csum_fold(unsigned int sum)
+{
+	__asm__ __volatile__ (
+		"    sr   3,3\n"   /* %0 = H*65536 + L */
+		"    lr   2,%0\n"  /* %0 = H L, R2/R3 = H L / 0 0 */
+		"    srdl 2,16\n"  /* %0 = H L, R2/R3 = 0 H / L 0 */
+		"    alr  2,3\n"   /* %0 = H L, R2/R3 = L H / L 0 */
+		"    alr  %0,2\n"  /* %0 = H+L+C L+H */
+                "    srl  %0,16\n" /* %0 = H+L+C */
+		: "+&d" (sum) : : "cc", "2", "3");
+	return ((unsigned short) ~sum);
+}
+#endif
+
+/*
+ *	This is a version of ip_compute_csum() optimized for IP headers,
+ *	which always checksum on 4 octet boundaries.
+ *
+ */
+extern inline unsigned short
+ip_fast_csum(unsigned char *iph, unsigned int ihl)
+{
+	unsigned long sum;
+
+        __asm__ __volatile__ (
+		"    sr   %0,%0\n"   /* set sum to zero */
+                "    lr   2,%1\n"    /* address in gpr 2 */
+                "    lr   3,%2\n"    /* length in gpr 3 */
+                "0:  cksm %0,2\n"    /* do checksum on longs */
+                "    jo   0b\n"
+                : "=&d" (sum)
+                : "d" (iph), "d" (ihl*4)
+                : "cc", "2", "3" );
+        return csum_fold(sum);
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 32-bit checksum
+ */
+extern inline unsigned int 
+csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr,
+                   unsigned short len, unsigned short proto,
+                   unsigned int sum)
+{
+	__asm__ __volatile__ (
+		"    sll   %3,16\n"
+		"    or    %3,%4\n"  /* newproto=proto<<16 in hiword, len in lowword */
+		"    alr   %1,%2\n"  /* saddr+=daddr */
+		"    brc   12,0f\n"
+		"    ahi   %1,1\n"   /* add carry */
+		"0:  alr   %1,%3\n"  /* add saddr+=newproto */
+		"    brc   12,1f\n"
+		"    ahi   %1,1\n"   /* add carry again */
+		"1:  alr   %0,%1\n"  /* sum+=saddr */
+		"    brc   12,2f\n"
+		"    ahi   %0,1\n"   /* add carry again */
+		"2:"
+		: "+&d" (sum)
+		: "d" (saddr), "d" (daddr), "d" (proto), "d" (len)
+		: "cc" );
+	return sum;
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+
+extern inline unsigned short int
+csum_tcpudp_magic(unsigned long saddr, unsigned long daddr,
+                  unsigned short len, unsigned short proto,
+                  unsigned int sum)
+{
+	return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+
+extern inline unsigned short
+ip_compute_csum(unsigned char * buff, int len)
+{
+	return csum_fold(csum_partial(buff, len, 0));
+}
+
+#endif /* _S390_CHECKSUM_H */
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/current.h linux.14p16/include/asm-s390/current.h
--- linux.vanilla/include/asm-s390/current.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/current.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,31 @@
+/*
+ *  include/asm-s390/current.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *  Derived from "include/asm-i386/current.h"
+ */
+
+#ifndef _S390_CURRENT_H
+#define _S390_CURRENT_H
+
+#ifdef __KERNEL__
+
+struct task_struct;
+
+static inline struct task_struct * get_current(void)
+{
+        struct task_struct *current;
+        __asm__("lhi   %0,-8192\n\t"
+                "nr    %0,15"
+                : "=r" (current) );
+        return current;
+ }
+
+#define current get_current()
+
+#endif
+
+#endif /* !(_S390_CURRENT_H) */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/delay.h linux.14p16/include/asm-s390/delay.h
--- linux.vanilla/include/asm-s390/delay.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/delay.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,25 @@
+/*
+ *  include/asm-s390/delay.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *  Derived from "include/asm-i386/delay.h"
+ *    Copyright (C) 1993 Linus Torvalds
+ *
+ *  Delay routines calling functions in arch/i386/lib/delay.c
+ */
+ 
+#ifndef _S390_DELAY_H
+#define _S390_DELAY_H
+
+extern void __udelay(unsigned long usecs);
+extern void __const_udelay(unsigned long usecs);
+extern void __delay(unsigned long loops);
+
+#define udelay(n) (__builtin_constant_p(n) ? \
+	__const_udelay((n) * 0x10c6ul) : \
+	__udelay(n))
+
+#endif /* defined(_S390_DELAY_H) */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/dma.h linux.14p16/include/asm-s390/dma.h
--- linux.vanilla/include/asm-s390/dma.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/dma.h	Wed Dec 15 22:32:45 1999
@@ -0,0 +1,17 @@
+/*
+ *  include/asm-s390/delay.h
+ *
+ *  S390 version
+ *
+ *  This file exists so that an #include <dma.h> doesn't break anything.
+ *
+ *  -AC- we now rely on the lack of the maximum DMA channel definition to
+ * cleanly support platforms with no DMA.
+ */
+
+#ifndef _ASM_DMA_H
+#define _ASM_DMA_H
+
+#include <asm/io.h>		/* need byte IO */
+
+#endif /* _ASM_DMA_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/ebcdic.h linux.14p16/include/asm-s390/ebcdic.h
--- linux.vanilla/include/asm-s390/ebcdic.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/ebcdic.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,51 @@
+/*
+ *  include/asm-s390/ebcdic.h
+ *    EBCDIC -> ASCII, ASCII -> EBCDIC conversion routines.
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#ifndef _EBCDIC_H
+#define _EBCDIC_H
+
+#ifndef _S390_TYPES_H
+#include <types.h>
+#endif
+
+extern __u8 _ascebc[];   /* ASCII -> EBCDIC conversion table */
+extern __u8 _ebcasc[];   /* EBCDIC -> ASCII conversion table */
+extern __u8 _ebc_tolower[]; /* EBCDIC -> lowercase */
+extern __u8 _ebc_toupper[]; /* EBCDIC -> uppercase */
+
+extern __inline__ 
+void codepage_convert(const __u8 *codepage, volatile __u8 * addr, int nr)
+{
+        static const __u16 tr_op[] = { 0xDC00, 0x1000,0x3000 };
+        __asm__ __volatile__(
+                "   lr    1,%0\n"
+                "   lr    2,%1\n"
+                "   lr    3,%2\n"
+                "   ahi   2,-256\n"
+                "   jm    1f\n"
+                "0: tr    0(256,1),0(3)\n"
+                "   ahi   1,256\n"
+                "   ahi   2,-256\n"
+                "   jp    0b\n"
+                "1: ahi   2,255\n"
+                "   jm    2f\n"
+                "   ex    2,%3\n"
+                "2:"
+                : /* no output */ 
+                : "a" (addr), "d" (nr), "a" (codepage), "m" (tr_op[0])
+                : "cc", "memory", "1", "2", "3" );
+}
+
+#define ASCEBC(addr,nr) codepage_convert(_ascebc, addr, nr)
+#define EBCASC(addr,nr) codepage_convert(_ebcasc, addr, nr)
+#define EBC_TOLOWER(addr,nr) codepage_convert(_ebc_tolower, addr, nr)
+#define EBC_TOUPPER(addr,nr) codepage_convert(_ebc_toupper, addr, nr)
+
+#endif
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/elf.h linux.14p16/include/asm-s390/elf.h
--- linux.vanilla/include/asm-s390/elf.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/elf.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,80 @@
+/*
+ *  include/asm-s390/elf.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/elf.h"
+ */
+
+#ifndef __ASMS390_ELF_H
+#define __ASMS390_ELF_H
+
+/*
+ * ELF register definitions..
+ */
+
+#include <asm/ptrace.h>
+#include <asm/user.h>
+
+
+typedef s390_fp_regs elf_fpregset_t;
+typedef s390_regs elf_gregset_t;
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ((x) == EM_S390) 
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS	ELFCLASS32
+#define ELF_DATA	ELFDATA2MSB
+#define ELF_ARCH	EM_S390
+
+/* For SVR4/S390 the function pointer to be registered with `atexit` is
+   passed in R14. */
+#define ELF_PLAT_INIT(_r) \
+	_r->gprs[14] = 0
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE	4096
+
+/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
+   use of this is to invoke "./ld.so someprog" to test out a new version of
+   the loader.  We need to make sure that it is out of the way of the program
+   that it will "exec", and that there is sufficient room for the brk.  */
+
+#define ELF_ET_DYN_BASE         ((TASK_SIZE & 0x80000000) \
+                                ? TASK_SIZE / 3 * 2 \
+                                : 2 * TASK_SIZE / 3)
+
+/* Wow, the "main" arch needs arch dependent functions too.. :) */
+
+/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
+   now struct_user_regs, they are different) */
+
+#define ELF_CORE_COPY_REGS(pr_reg, regs)	\
+	memcpy(&pr_reg,regs,sizeof(elf_gregset_t)); \
+
+
+
+/* This yields a mask that user programs can use to figure out what
+   instruction set this CPU supports. */
+
+#define ELF_HWCAP (0)
+
+/* This yields a string that ld.so will use to load implementation
+   specific libraries for optimization.  This is more specific in
+   intent than poking at uname or /proc/cpuinfo.
+
+   For the moment, we have only optimizations for the Intel generations,
+   but that could change... */
+
+#define ELF_PLATFORM (NULL)
+
+#ifdef __KERNEL__
+#define SET_PERSONALITY(ex, ibcs2) \
+	current->personality = (ibcs2 ? PER_SVR4 : PER_LINUX)
+#endif
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/errno.h linux.14p16/include/asm-s390/errno.h
--- linux.vanilla/include/asm-s390/errno.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/errno.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,140 @@
+/*
+ *  include/asm-s390/errno.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/errno.h"
+ */
+
+#ifndef _S390_ERRNO_H
+#define _S390_ERRNO_H
+
+#define	EPERM		 1	/* Operation not permitted */
+#define	ENOENT		 2	/* No such file or directory */
+#define	ESRCH		 3	/* No such process */
+#define	EINTR		 4	/* Interrupted system call */
+#define	EIO		 5	/* I/O error */
+#define	ENXIO		 6	/* No such device or address */
+#define	E2BIG		 7	/* Arg list too long */
+#define	ENOEXEC		 8	/* Exec format error */
+#define	EBADF		 9	/* Bad file number */
+#define	ECHILD		10	/* No child processes */
+#define	EAGAIN		11	/* Try again */
+#define	ENOMEM		12	/* Out of memory */
+#define	EACCES		13	/* Permission denied */
+#define	EFAULT		14	/* Bad address */
+#define	ENOTBLK		15	/* Block device required */
+#define	EBUSY		16	/* Device or resource busy */
+#define	EEXIST		17	/* File exists */
+#define	EXDEV		18	/* Cross-device link */
+#define	ENODEV		19	/* No such device */
+#define	ENOTDIR		20	/* Not a directory */
+#define	EISDIR		21	/* Is a directory */
+#define	EINVAL		22	/* Invalid argument */
+#define	ENFILE		23	/* File table overflow */
+#define	EMFILE		24	/* Too many open files */
+#define	ENOTTY		25	/* Not a typewriter */
+#define	ETXTBSY		26	/* Text file busy */
+#define	EFBIG		27	/* File too large */
+#define	ENOSPC		28	/* No space left on device */
+#define	ESPIPE		29	/* Illegal seek */
+#define	EROFS		30	/* Read-only file system */
+#define	EMLINK		31	/* Too many links */
+#define	EPIPE		32	/* Broken pipe */
+#define	EDOM		33	/* Math argument out of domain of func */
+#define	ERANGE		34	/* Math result not representable */
+#define	EDEADLK		35	/* Resource deadlock would occur */
+#define	ENAMETOOLONG	36	/* File name too long */
+#define	ENOLCK		37	/* No record locks available */
+#define	ENOSYS		38	/* Function not implemented */
+#define	ENOTEMPTY	39	/* Directory not empty */
+#define	ELOOP		40	/* Too many symbolic links encountered */
+#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
+#define	ENOMSG		42	/* No message of desired type */
+#define	EIDRM		43	/* Identifier removed */
+#define	ECHRNG		44	/* Channel number out of range */
+#define	EL2NSYNC	45	/* Level 2 not synchronized */
+#define	EL3HLT		46	/* Level 3 halted */
+#define	EL3RST		47	/* Level 3 reset */
+#define	ELNRNG		48	/* Link number out of range */
+#define	EUNATCH		49	/* Protocol driver not attached */
+#define	ENOCSI		50	/* No CSI structure available */
+#define	EL2HLT		51	/* Level 2 halted */
+#define	EBADE		52	/* Invalid exchange */
+#define	EBADR		53	/* Invalid request descriptor */
+#define	EXFULL		54	/* Exchange full */
+#define	ENOANO		55	/* No anode */
+#define	EBADRQC		56	/* Invalid request code */
+#define	EBADSLT		57	/* Invalid slot */
+
+#define	EDEADLOCK	EDEADLK
+
+#define	EBFONT		59	/* Bad font file format */
+#define	ENOSTR		60	/* Device not a stream */
+#define	ENODATA		61	/* No data available */
+#define	ETIME		62	/* Timer expired */
+#define	ENOSR		63	/* Out of streams resources */
+#define	ENONET		64	/* Machine is not on the network */
+#define	ENOPKG		65	/* Package not installed */
+#define	EREMOTE		66	/* Object is remote */
+#define	ENOLINK		67	/* Link has been severed */
+#define	EADV		68	/* Advertise error */
+#define	ESRMNT		69	/* Srmount error */
+#define	ECOMM		70	/* Communication error on send */
+#define	EPROTO		71	/* Protocol error */
+#define	EMULTIHOP	72	/* Multihop attempted */
+#define	EDOTDOT		73	/* RFS specific error */
+#define	EBADMSG		74	/* Not a data message */
+#define	EOVERFLOW	75	/* Value too large for defined data type */
+#define	ENOTUNIQ	76	/* Name not unique on network */
+#define	EBADFD		77	/* File descriptor in bad state */
+#define	EREMCHG		78	/* Remote address changed */
+#define	ELIBACC		79	/* Can not access a needed shared library */
+#define	ELIBBAD		80	/* Accessing a corrupted shared library */
+#define	ELIBSCN		81	/* .lib section in a.out corrupted */
+#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
+#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
+#define	EILSEQ		84	/* Illegal byte sequence */
+#define	ERESTART	85	/* Interrupted system call should be restarted */
+#define	ESTRPIPE	86	/* Streams pipe error */
+#define	EUSERS		87	/* Too many users */
+#define	ENOTSOCK	88	/* Socket operation on non-socket */
+#define	EDESTADDRREQ	89	/* Destination address required */
+#define	EMSGSIZE	90	/* Message too long */
+#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
+#define	ENOPROTOOPT	92	/* Protocol not available */
+#define	EPROTONOSUPPORT	93	/* Protocol not supported */
+#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
+#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
+#define	EPFNOSUPPORT	96	/* Protocol family not supported */
+#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
+#define	EADDRINUSE	98	/* Address already in use */
+#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
+#define	ENETDOWN	100	/* Network is down */
+#define	ENETUNREACH	101	/* Network is unreachable */
+#define	ENETRESET	102	/* Network dropped connection because of reset */
+#define	ECONNABORTED	103	/* Software caused connection abort */
+#define	ECONNRESET	104	/* Connection reset by peer */
+#define	ENOBUFS		105	/* No buffer space available */
+#define	EISCONN		106	/* Transport endpoint is already connected */
+#define	ENOTCONN	107	/* Transport endpoint is not connected */
+#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
+#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
+#define	ETIMEDOUT	110	/* Connection timed out */
+#define	ECONNREFUSED	111	/* Connection refused */
+#define	EHOSTDOWN	112	/* Host is down */
+#define	EHOSTUNREACH	113	/* No route to host */
+#define	EALREADY	114	/* Operation already in progress */
+#define	EINPROGRESS	115	/* Operation now in progress */
+#define	ESTALE		116	/* Stale NFS file handle */
+#define	EUCLEAN		117	/* Structure needs cleaning */
+#define	ENOTNAM		118	/* Not a XENIX named type file */
+#define	ENAVAIL		119	/* No XENIX semaphores available */
+#define	EISNAM		120	/* Is a named type file */
+#define	EREMOTEIO	121	/* Remote I/O error */
+#define	EDQUOT		122	/* Quota exceeded */
+
+#define	ENOMEDIUM	123	/* No medium found */
+#define	EMEDIUMTYPE	124	/* Wrong medium type */
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/fcntl.h linux.14p16/include/asm-s390/fcntl.h
--- linux.vanilla/include/asm-s390/fcntl.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/fcntl.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,72 @@
+/*
+ *  include/asm-s390/fcntl.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/fcntl.h"
+ */
+#ifndef _S390_FCNTL_H
+#define _S390_FCNTL_H
+
+/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
+   located on an ext2 file system */
+#define O_ACCMODE	   0003
+#define O_RDONLY	     00
+#define O_WRONLY	     01
+#define O_RDWR		     02
+#define O_CREAT		   0100	/* not fcntl */
+#define O_EXCL		   0200	/* not fcntl */
+#define O_NOCTTY	   0400	/* not fcntl */
+#define O_TRUNC		  01000	/* not fcntl */
+#define O_APPEND	  02000
+#define O_NONBLOCK	  04000
+#define O_NDELAY	O_NONBLOCK
+#define O_SYNC		 010000
+#define FASYNC		 020000	/* fcntl, for BSD compatibility */
+#define O_DIRECT	 040000	/* direct disk access hint - currently ignored */
+#define O_LARGEFILE	0100000
+#define O_DIRECTORY	0200000	/* must be a directory */
+#define O_NOFOLLOW	0400000 /* don't follow links */
+
+#define F_DUPFD		0	/* dup */
+#define F_GETFD		1	/* get f_flags */
+#define F_SETFD		2	/* set f_flags */
+#define F_GETFL		3	/* more flags (cloexec) */
+#define F_SETFL		4
+#define F_GETLK		5
+#define F_SETLK		6
+#define F_SETLKW	7
+
+#define F_SETOWN	8	/*  for sockets. */
+#define F_GETOWN	9	/*  for sockets. */
+#define F_SETSIG	10	/*  for sockets. */
+#define F_GETSIG	11	/*  for sockets. */
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC	1	/* actually anything with low bit set goes */
+
+/* for posix fcntl() and lockf() */
+#define F_RDLCK		0
+#define F_WRLCK		1
+#define F_UNLCK		2
+
+/* for old implementation of bsd flock () */
+#define F_EXLCK		4	/* or 3 */
+#define F_SHLCK		8	/* or 4 */
+
+/* operations for bsd flock(), also used by the kernel implementation */
+#define LOCK_SH		1	/* shared lock */
+#define LOCK_EX		2	/* exclusive lock */
+#define LOCK_NB		4	/* or'd with one of the above to prevent
+				   blocking */
+#define LOCK_UN		8	/* remove lock */
+
+struct flock {
+	short l_type;
+	short l_whence;
+	off_t l_start;
+	off_t l_len;
+	pid_t l_pid;
+};
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/gdb-stub.h linux.14p16/include/asm-s390/gdb-stub.h
--- linux.vanilla/include/asm-s390/gdb-stub.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/gdb-stub.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,18 @@
+/*
+ *  include/asm-s390/gdb-stub.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ */
+
+#ifndef __S390_GDB_STUB__
+#define __S390_GDB_STUB__
+#include <linux/config.h>
+#if CONFIG_REMOTE_DEBUG
+#include <asm/s390-gdbregs.h>
+#include <asm/ptrace.h>
+extern int    gdb_stub_initialised;
+extern void gdb_stub_handle_exception(gdb_pt_regs *regs,int sigval);
+#endif
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/hardirq.h linux.14p16/include/asm-s390/hardirq.h
--- linux.vanilla/include/asm-s390/hardirq.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/hardirq.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,75 @@
+/*
+ *  include/asm-s390/hardirq.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *
+ *  Derived from "include/asm-i386/hardirq.h"
+ */
+
+#ifndef __ASM_HARDIRQ_H
+#define __ASM_HARDIRQ_H
+
+#include <linux/tasks.h>
+#include <asm/lowcore.h>
+#include <linux/sched.h>
+/*
+ * Are we in an interrupt context? Either doing bottom half
+ * or hardware interrupt processing?
+ */
+#define in_interrupt() ((atomic_read(&S390_lowcore.local_irq_count) + atomic_read(&S390_lowcore.local_bh_count)) != 0)
+
+#ifndef __SMP__
+
+#define hardirq_trylock(cpu)	(atomic_read(&S390_lowcore.local_irq_count) == 0)
+#define hardirq_endlock(cpu)	do { } while (0)
+
+#define hardirq_enter(cpu)	(atomic_inc(&S390_lowcore.local_irq_count))
+#define hardirq_exit(cpu)	(atomic_dec(&S390_lowcore.local_irq_count))
+
+#define synchronize_irq()	do { } while (0)
+
+#else
+
+#include <asm/atomic.h>
+#include <asm/smp.h>
+
+extern atomic_t global_irq_holder;
+extern atomic_t global_irq_lock;
+extern atomic_t global_irq_count;
+
+static inline void release_irqlock(int cpu)
+{
+	/* if we didn't own the irq lock, just ignore.. */
+	if (atomic_read(&global_irq_holder) ==  cpu) {
+		atomic_set(&global_irq_holder,NO_PROC_ID);
+		clear_bit(0,&global_irq_lock);
+	}
+}
+
+static inline void hardirq_enter(int cpu)
+{
+        atomic_inc(&safe_get_cpu_lowcore(cpu).local_irq_count);
+	atomic_inc(&global_irq_count);
+}
+
+static inline void hardirq_exit(int cpu)
+{
+	atomic_dec(&global_irq_count);
+        atomic_dec(&safe_get_cpu_lowcore(cpu).local_irq_count);
+}
+
+static inline int hardirq_trylock(int cpu)
+{
+	return !atomic_read(&global_irq_count) && !test_bit(0,&global_irq_lock);
+}
+
+#define hardirq_endlock(cpu)	do { } while (0)
+
+extern void synchronize_irq(void);
+
+#endif /* __SMP__ */
+
+#endif /* __ASM_HARDIRQ_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/init.h linux.14p16/include/asm-s390/init.h
--- linux.vanilla/include/asm-s390/init.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/init.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,29 @@
+/*
+ *  include/asm-s390/init.h
+ *
+ *  S390 version
+ */
+
+#ifndef _S390_INIT_H
+#define _S390_INIT_H
+
+#define __init __attribute__ ((constructor))
+
+/* don't know, if need on S390 */
+#define __initdata
+#define __initfunc(__arginit) \
+        __arginit __init; \
+        __arginit
+/* For assembly routines
+ * need to define ?
+ */
+/*
+#define __INIT          .section        ".text.init",#alloc,#execinstr
+#define __FINIT .previous
+#define __INITDATA      .section        ".data.init",#alloc,#write
+*/
+
+#define __cacheline_aligned __attribute__ ((__aligned__(16)))
+
+#endif
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/io.h linux.14p16/include/asm-s390/io.h
--- linux.vanilla/include/asm-s390/io.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/io.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,92 @@
+/*
+ *  include/asm-s390/io.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *  Derived from "include/asm-i386/io.h"
+ */
+
+#ifndef _S390_IO_H
+#define _S390_IO_H
+
+#ifdef __KERNEL__
+
+#include <linux/vmalloc.h>
+#include <asm/page.h>
+
+#define __io_virt(x)            ((void *)(PAGE_OFFSET | (unsigned long)(x)))
+#define __io_phys(x)            ((unsigned long)(x) & ~PAGE_OFFSET)
+/*
+ * Change virtual addresses to physical addresses and vv.
+ * These are pretty trivial
+ */
+extern inline unsigned long virt_to_phys(volatile void * address)
+{
+	unsigned long real_address;
+	__asm__ ("   lra    %0,0(0,%1)\n"
+                 "   jz     0f\n"
+                 "   sr     %0,%0\n"
+                 "0:"
+                 : "=a" (real_address) : "a" (address) );
+        return real_address;
+}
+
+extern inline void * phys_to_virt(unsigned long address)
+{
+        return __io_virt(address);
+}
+
+extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+
+extern inline void * ioremap (unsigned long offset, unsigned long size)
+{
+        return __ioremap(offset, size, 0);
+}
+
+/*
+ * This one maps high address device memory and turns off caching for that area.
+ * it's useful if some control registers are in such an area and write combining
+ * or read caching is not desirable:
+ */
+extern inline void * ioremap_nocache (unsigned long offset, unsigned long size)
+{
+        return __ioremap(offset, size, 0);
+}
+
+extern void iounmap(void *addr);
+
+/*
+ * IO bus memory addresses are also 1:1 with the physical address
+ */
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+
+/*
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently.
+ */
+
+#define readb(addr) (*(volatile unsigned char *) __io_virt(addr))
+#define readw(addr) (*(volatile unsigned short *) __io_virt(addr))
+#define readl(addr) (*(volatile unsigned int *) __io_virt(addr))
+
+#define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b))
+#define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b))
+#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))
+
+#define memset_io(a,b,c)        memset(__io_virt(a),(b),(c))
+#define memcpy_fromio(a,b,c)    memcpy((a),__io_virt(b),(c))
+#define memcpy_toio(a,b,c)      memcpy(__io_virt(a),(b),(c))
+
+#define inb_p(addr) readb(addr)
+#define inb(addr) readb(addr)
+
+#define outb(x,addr) ((void) writeb(x,addr))
+#define outb_p(x,addr) outb(x,addr)
+
+#endif /* __KERNEL__ */
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/ioctl.h linux.14p16/include/asm-s390/ioctl.h
--- linux.vanilla/include/asm-s390/ioctl.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/ioctl.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,78 @@
+/*
+ *  include/asm-s390/ioctl.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/ioctl.h"
+ */
+
+#ifndef _S390_IOCTL_H
+#define _S390_IOCTL_H
+
+/* ioctl command encoding: 32 bits total, command in lower 16 bits,
+ * size of the parameter structure in the lower 14 bits of the
+ * upper 16 bits.
+ * Encoding the size of the parameter structure in the ioctl request
+ * is useful for catching programs compiled with old versions
+ * and to avoid overwriting user space outside the user buffer area.
+ * The highest 2 bits are reserved for indicating the ``access mode''.
+ * NOTE: This limits the max parameter size to 16kB -1 !
+ */
+
+/*
+ * The following is for compatibility across the various Linux
+ * platforms.  The i386 ioctl numbering scheme doesn't really enforce
+ * a type field.  De facto, however, the top 8 bits of the lower 16
+ * bits are indeed used as a type field, so we might just as well make
+ * this explicit here.  Please be sure to use the decoding macros
+ * below from now on.
+ */
+#define _IOC_NRBITS	8
+#define _IOC_TYPEBITS	8
+#define _IOC_SIZEBITS	14
+#define _IOC_DIRBITS	2
+
+#define _IOC_NRMASK	((1 << _IOC_NRBITS)-1)
+#define _IOC_TYPEMASK	((1 << _IOC_TYPEBITS)-1)
+#define _IOC_SIZEMASK	((1 << _IOC_SIZEBITS)-1)
+#define _IOC_DIRMASK	((1 << _IOC_DIRBITS)-1)
+
+#define _IOC_NRSHIFT	0
+#define _IOC_TYPESHIFT	(_IOC_NRSHIFT+_IOC_NRBITS)
+#define _IOC_SIZESHIFT	(_IOC_TYPESHIFT+_IOC_TYPEBITS)
+#define _IOC_DIRSHIFT	(_IOC_SIZESHIFT+_IOC_SIZEBITS)
+
+/*
+ * Direction bits.
+ */
+#define _IOC_NONE	0U
+#define _IOC_WRITE	1U
+#define _IOC_READ	2U
+
+#define _IOC(dir,type,nr,size) \
+	(((dir)  << _IOC_DIRSHIFT) | \
+	 ((type) << _IOC_TYPESHIFT) | \
+	 ((nr)   << _IOC_NRSHIFT) | \
+	 ((size) << _IOC_SIZESHIFT))
+
+/* used to create numbers */
+#define _IO(type,nr)		_IOC(_IOC_NONE,(type),(nr),0)
+#define _IOR(type,nr,size)	_IOC(_IOC_READ,(type),(nr),sizeof(size))
+#define _IOW(type,nr,size)	_IOC(_IOC_WRITE,(type),(nr),sizeof(size))
+#define _IOWR(type,nr,size)	_IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
+
+/* used to decode ioctl numbers.. */
+#define _IOC_DIR(nr)		(((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+#define _IOC_TYPE(nr)		(((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
+#define _IOC_NR(nr)		(((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
+#define _IOC_SIZE(nr)		(((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
+
+/* ...and for the drivers/sound files... */
+
+#define IOC_IN		(_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT		(_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT	((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK	(_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT	(_IOC_SIZESHIFT)
+
+#endif /* _S390_IOCTL_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/ioctls.h linux.14p16/include/asm-s390/ioctls.h
--- linux.vanilla/include/asm-s390/ioctls.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/ioctls.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,88 @@
+/*
+ *  include/asm-s390/ioctls.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/ioctls.h"
+ */
+
+#ifndef __ARCH_S390_IOCTLS_H__
+#define __ARCH_S390_IOCTLS_H__
+
+#include <asm/ioctl.h>
+
+/* 0x54 is just a magic number to make these relatively unique ('T') */
+
+#define TCGETS		0x5401
+#define TCSETS		0x5402
+#define TCSETSW		0x5403
+#define TCSETSF		0x5404
+#define TCGETA		0x5405
+#define TCSETA		0x5406
+#define TCSETAW		0x5407
+#define TCSETAF		0x5408
+#define TCSBRK		0x5409
+#define TCXONC		0x540A
+#define TCFLSH		0x540B
+#define TIOCEXCL	0x540C
+#define TIOCNXCL	0x540D
+#define TIOCSCTTY	0x540E
+#define TIOCGPGRP	0x540F
+#define TIOCSPGRP	0x5410
+#define TIOCOUTQ	0x5411
+#define TIOCSTI		0x5412
+#define TIOCGWINSZ	0x5413
+#define TIOCSWINSZ	0x5414
+#define TIOCMGET	0x5415
+#define TIOCMBIS	0x5416
+#define TIOCMBIC	0x5417
+#define TIOCMSET	0x5418
+#define TIOCGSOFTCAR	0x5419
+#define TIOCSSOFTCAR	0x541A
+#define FIONREAD	0x541B
+#define TIOCINQ		FIONREAD
+#define TIOCLINUX	0x541C
+#define TIOCCONS	0x541D
+#define TIOCGSERIAL	0x541E
+#define TIOCSSERIAL	0x541F
+#define TIOCPKT		0x5420
+#define FIONBIO		0x5421
+#define TIOCNOTTY	0x5422
+#define TIOCSETD	0x5423
+#define TIOCGETD	0x5424
+#define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TIOCTTYGSTRUCT	0x5426  /* For debugging only */
+#define TIOCSBRK	0x5427  /* BSD compatibility */
+#define TIOCCBRK	0x5428  /* BSD compatibility */
+#define TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
+#define FIOCLEX		0x5451
+#define FIOASYNC	0x5452
+#define TIOCSERCONFIG	0x5453
+#define TIOCSERGWILD	0x5454
+#define TIOCSERSWILD	0x5455
+#define TIOCGLCKTRMIOS	0x5456
+#define TIOCSLCKTRMIOS	0x5457
+#define TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+
+/* Used for packet mode */
+#define TIOCPKT_DATA		 0
+#define TIOCPKT_FLUSHREAD	 1
+#define TIOCPKT_FLUSHWRITE	 2
+#define TIOCPKT_STOP		 4
+#define TIOCPKT_START		 8
+#define TIOCPKT_NOSTOP		16
+#define TIOCPKT_DOSTOP		32
+
+#define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/ipc.h linux.14p16/include/asm-s390/ipc.h
--- linux.vanilla/include/asm-s390/ipc.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/ipc.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,39 @@
+/*
+ *  include/asm-s390/ipc.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/ipc.h"
+ */
+
+#ifndef __s390_IPC_H__
+#define __s390_IPC_H__
+
+/* 
+ * These are used to wrap system calls on S390.
+ *
+ * See arch/s390/kernel/sys_s390.c for ugly details..
+ */
+struct ipc_kludge {
+	struct msgbuf *msgp;
+	long msgtyp;
+};
+
+#define SEMOP		 1
+#define SEMGET		 2
+#define SEMCTL		 3
+#define MSGSND		11
+#define MSGRCV		12
+#define MSGGET		13
+#define MSGCTL		14
+#define SHMAT		21
+#define SHMDT		22
+#define SHMGET		23
+#define SHMCTL		24
+
+/* Used by the DIPC package, try and avoid reusing it */
+#define DIPC            25
+
+#define IPCCALL(version,op)	((version)<<16 | (op))
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/irq.h linux.14p16/include/asm-s390/irq.h
--- linux.vanilla/include/asm-s390/irq.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/irq.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,24 @@
+/*
+ *  include/asm-s390/irq.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *
+ *  Derived from "include/asm-i386/irq.h"
+ *    Copyright (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
+ */
+
+#ifndef _ASM_IRQ_H
+#define _ASM_IRQ_H
+
+#define TIMER_IRQ 0x1005
+
+/*
+ * How many IRQ's for S390 ?!?
+ */
+#define NR_IRQS 1024
+
+extern int disable_irq(unsigned int);
+extern int enable_irq(unsigned int);
+
+#endif /* _ASM_IRQ_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/irqextras390.h linux.14p16/include/asm-s390/irqextras390.h
--- linux.vanilla/include/asm-s390/irqextras390.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/irqextras390.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,151 @@
+/*
+ *  include/asm-s390/irqextras390.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ */
+
+#ifndef __irqextras390_h
+#define __irqextras390_h
+
+/*
+  irqextras390.h by D.J. Barrow
+  if you are a bitfield fan &  are paranoid that ansi dosen't
+  give hard definitions about the size of an int or long you might
+  prefer these definitions as an alternative.
+
+*/
+
+#include <linux/types.h>
+
+typedef struct 
+{
+      unsigned key:4;
+      unsigned s:1;
+      unsigned l:1;
+      unsigned cc:2;
+      unsigned f:1;
+      unsigned p:1;
+      unsigned i:1;
+      unsigned a:1;
+      unsigned u:1;
+      unsigned z:1;
+      unsigned e:1;
+      unsigned n:1;
+      unsigned zero:1;
+      
+      unsigned fc_start:1;
+      unsigned fc_halt:1;
+      unsigned fc_clear:1;
+      
+      unsigned ac_resume_pending:1;
+      unsigned ac_start_pending:1;
+      unsigned ac_halt_pending:1;
+      unsigned ac_clear_pending:1;
+      unsigned ac_subchannel_active:1;
+      unsigned ac_device_active:1;
+      unsigned ac_suspended:1;
+      
+      unsigned sc_alert:1;
+      unsigned sc_intermediate:1;
+      unsigned sc_primary:1;
+      unsigned sc_seconary:1;
+      unsigned sc_status_pending:1;
+      
+      __u32	   ccw_address;
+      
+      unsigned dev_status_attention:1;
+      unsigned dev_status_modifier:1;
+      unsigned dev_status_control_unit_end:1;
+      unsigned dev_status_busy:1;
+      unsigned dev_status_channel_end:1;
+      unsigned dev_status_device_end:1;
+      unsigned dev_status_unit_check:1;
+      unsigned dev_status_unit_exception:1;
+      
+      unsigned sch_status_program_cont_int:1;
+      unsigned sch_status_incorrect_length:1;
+      unsigned sch_status_program_check:1;
+      unsigned sch_status_protection_check:1;
+      unsigned sch_status_channel_data_check:1;
+      unsigned sch_status_channel_control_check:1;
+      unsigned sch_status_interface_control_check:1;
+      unsigned sch_status_chaining_check:1;
+     
+      __u16	   byte_count;
+} scsw_bits_t __attribute__((packed));
+
+typedef struct
+{
+  __u32      flags;
+  __u32      ccw_address;
+  __u8       dev_status;
+  __u8       sch_status;
+  __u16      byte_count;
+} scsw_words_t __attribute__((packed));
+
+typedef struct
+{
+      __u8     cmd_code;
+      
+      unsigned cd:1;
+      unsigned cc:1;
+      unsigned sli:1;
+      unsigned skip:1;
+      unsigned pci:1;
+      unsigned ida:1;
+      unsigned s:1;
+      unsigned res1:1;
+
+      __u16	count;
+
+      void	*ccw_data_address;
+} ccw1_bits_t __attribute__((packed,aligned(8)));
+
+typedef struct
+{
+      __u32		interruption_parm;
+      unsigned key:4;
+      unsigned s:1;
+      unsigned res1:3;
+      unsigned f:1;
+      unsigned p:1;
+      unsigned i:1;
+      unsigned a:1;
+      unsigned u:1;
+      __u8	   lpm;
+      unsigned l:1;
+      unsigned res2:7;
+      ccw1_bits_t	*ccw_program_address;
+} orb_bits_t __attribute__((packed));
+
+void fixchannelprogram(orb_bits_t *orbptr);
+void fixccws(ccw1_bits_t *ccwptr);
+enum
+{
+   ccw_write=0x1,
+   ccw_read=0x2,
+   ccw_read_backward=0xc,
+   ccw_control=0x3,
+   ccw_sense=0x4,
+   ccw_sense_id=0xe4,
+   ccw_transfer_in_channel0=0x8,
+   ccw_transfer_in_channel1=0x8,
+   ccw_set_x_mode=0xc3,		// according to uli's lan notes
+   ccw_nop=0x3			// according to uli's notes again
+                                        // n.b. ccw_control clashes with this
+                                        // so I presume its a special case of
+					// control
+};
+
+
+
+#endif
+
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/lowcore.h linux.14p16/include/asm-s390/lowcore.h
--- linux.vanilla/include/asm-s390/lowcore.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/lowcore.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,176 @@
+/*
+ *  include/asm-s390/lowcore.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Hartmut Penner (hp@de.ibm.com),
+ *               Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ */
+
+#ifndef _ASM_S390_LOWCORE_H
+#define _ASM_S390_LOWCORE_H
+
+#define __LC_EXT_OLD_PSW                0x018
+#define __LC_SVC_OLD_PSW                0x020
+#define __LC_PGM_OLD_PSW                0x028
+#define __LC_MCK_OLD_PSW                0x030
+#define __LC_IO_OLD_PSW                 0x038
+#define __LC_EXT_NEW_PSW                0x058
+#define __LC_SVC_NEW_PSW                0x060
+#define __LC_PGM_NEW_PSW                0x068
+#define __LC_MCK_NEW_PSW                0x070
+#define __LC_IO_NEW_PSW                 0x078
+#define __LC_EXT_PARAMS                 0x080
+#define __LC_CPU_ADDRESS                0x084
+#define __LC_EXT_INT_CODE               0x086
+#define __LC_SVC_INT_CODE               0x08B
+#define __LC_PGM_ILC                    0x08C
+#define __LC_PGM_INT_CODE               0x08E
+#define __LC_TRANS_EXC_ADDR             0x090
+#define __LC_SUBCHANNEL_NR              0x0BA
+#define __LC_IO_INT_PARM                0x0BC
+#define __LC_MCCK_CODE                  0x0E8
+#define __LC_CREGS_SAVE_AREA            0x1C0
+#define __LC_AREGS_SAVE_AREA            0x120
+
+#define __LC_SYNC_IO_WORD               0x400
+
+#define __LC_SAVE_AREA                  0xC00
+#define __LC_KERNEL_STACK               0xC40
+#define __LC_KERNEL_LEVEL               0xC44
+#define __LC_CPUID                      0xC50
+#define __LC_CPUADDR                    0xC58
+#define __LC_IPLDEV                     0xC6C
+
+
+/* interrupt handler start with all io, external and mcck interrupt disabled */
+
+#define _RESTART_PSW_MASK    0x00080000
+#define _EXT_PSW_MASK        0x04080000
+#define _PGM_PSW_MASK        0x04080000
+#define _SVC_PSW_MASK        0x04080000
+#define _MCCK_PSW_MASK       0x040A0000
+#define _IO_PSW_MASK         0x04080000
+#define _USER_PSW_MASK       0x070DC000/* DAT, IO, EXT, Home-space         */
+#define _PSW_IO_WAIT         0x020A0000/* IO, Wait */
+#define _WAIT_PSW_MASK       0x070EC000/* DAT, IO, EXT, Wait, Home-space   */
+#define _DW_PSW_MASK         0x000A0000/* disabled wait PSW mask           */
+#define _PRIMARY_MASK        0x0000    /* MASK for SACF                    */
+#define _SECONDARY_MASK      0x0100    /* MASK for SACF                    */
+#define _ACCESS_MASK         0x0200    /* MASK for SACF                    */
+#define _HOME_MASK           0x0300    /* MASK for SACF                    */
+
+#define _PSW_PRIM_SPACE_MODE 0x04000000
+#define _PSW_SEC_SPACE_MODE  0x04008000
+#define _PSW_ACC_REG_MODE    0x04004000
+#define _PSW_HOME_SPACE_MODE 0x0400C000
+
+#define _PSW_WAIT_MASK_BIT   0x00020000
+#define _PSW_IO_MASK_BIT     0x02000000
+
+/* we run in 31 Bit mode */
+#define _ADDR_31             0x80000000
+
+#ifndef __ASSEMBLY__
+
+#include <asm/processor.h>
+#include <linux/types.h>
+#include <asm/atomic.h>
+#include <asm/sigp.h>
+
+
+struct _lowcore
+{
+        /* prefix area: defined by architecture */
+	psw_t        restart_psw;              /* 0x000 */
+	__u32        ccw2[4];                  /* 0x008 */
+	psw_t        external_old_psw;         /* 0x018 */
+	psw_t        svc_old_psw;              /* 0x020 */
+	psw_t        program_old_psw;          /* 0x028 */
+	psw_t        mcck_old_psw;             /* 0x030 */
+	psw_t        io_old_psw;               /* 0x038 */
+	__u8         pad1[0x58-0x40];          /* 0x040 */
+	psw_t        external_new_psw;         /* 0x058 */
+	psw_t        svc_new_psw;              /* 0x060 */
+	psw_t        program_new_psw;          /* 0x068 */
+	psw_t        mcck_new_psw;             /* 0x070 */
+	psw_t        io_new_psw;               /* 0x078 */
+	__u32        ext_params;               /* 0x080 */
+	__u16        cpu_addr;                 /* 0x084 */
+	__u16        ext_int_code;             /* 0x086 */
+        __u16        svc_ilc;                  /* 0x088 */
+        __u16        scv_code;                 /* 0x08a */
+        __u16        pgm_ilc;                  /* 0x08c */
+        __u16        pgm_code;                 /* 0x08e */
+	__u32        trans_exc_code;           /* 0x090 */
+	__u16        mon_class_num;            /* 0x094 */
+	__u16        per_perc_atmid;           /* 0x096 */
+	__u32        per_address;              /* 0x098 */
+	__u32        monitor_code;             /* 0x09c */
+	__u8         exc_access_id;            /* 0x0a0 */
+	__u8         per_access_id;            /* 0x0a1 */
+	__u8         pad2[0xB8-0xA2];          /* 0x0a2 */
+	__u16        subchannel_id;            /* 0x0b8 */
+	__u16        subchannel_nr;            /* 0x0ba */
+	__u32        io_int_parm;              /* 0x0bc */
+	__u8         pad3[0xD8-0xC0];          /* 0x0c0 */
+	__u32        cpu_timer_save_area[2];   /* 0x0d8 */
+	__u32        clock_comp_save_area[2];  /* 0x0e0 */
+	__u32        mcck_interuption_code[2]; /* 0x0e8 */
+	__u8         pad4[0xf4-0xf0];          /* 0x0f0 */
+	__u32        external_damage_code;     /* 0x0f4 */
+	__u32        failing_storage_address;  /* 0x0f8 */
+	__u8         pad5[0x100-0xfc];         /* 0x0fc */
+	__u32        st_status_fixed_logout[4];/* 0x100 */
+	__u8         pad6[0x120-0x110];        /* 0x110 */
+	__u32        access_regs_save_area[16];/* 0x120 */
+	__u32        floating_pt_save_area[8]; /* 0x160 */
+	__u32        gpregs_save_area[16];     /* 0x180 */
+	__u32        cregs_save_area[16];      /* 0x1c0 */
+	
+	__u8         pad7[0x400-0x200];        /* 0x200 */
+
+	__u32        sync_io_word;	       /* 0x400 */
+
+        __u8         pad8[0xc00-0x404];        /* 0x404 */
+
+        /* System info area */
+	__u32        save_area[16];            /* 0xc00 */
+	__u32        kernel_stack;             /* 0xc40 */
+	__u32        kernel_level;             /* 0xc44 */
+	atomic_t     local_bh_count;           /* 0xc48 */
+	atomic_t     local_irq_count;          /* 0xc4c */
+	struct       cpuinfo_S390 cpu_data;    /* 0xc50 */
+	__u32        ipl_device;               /* 0xc6c */
+
+        /* SMP info area: defined by DJB */
+        __u64        jiffy_timer_cc;           /* 0xc70 */
+	atomic_t     ext_call_fast;            /* 0xc78 */
+	atomic_t     ext_call_queue;           /* 0xc7c */
+        atomic_t     ext_call_count;           /* 0xc80 */
+
+        /* Align SMP info to the top 1k of prefix area */
+	__u8         pad10[0x1000-0xc84];      /* 0xc84 */
+} __attribute__((packed)); /* End structure*/
+
+extern __inline__ void set_prefix(__u32 address)
+{
+        __asm__ __volatile__ ("spx %0" : : "m" (address) : "memory" );
+}
+
+#define S390_lowcore (*((struct _lowcore *) 0))
+extern struct _lowcore *lowcore_ptr[];
+
+#ifndef __SMP__
+#define get_cpu_lowcore(cpu)    S390_lowcore
+#define safe_get_cpu_lowcore(cpu) S390_lowcore
+#else
+#define get_cpu_lowcore(cpu)    (*lowcore_ptr[cpu])
+#define safe_get_cpu_lowcore(cpu) \
+        ((cpu)==smp_processor_id() ? S390_lowcore:(*lowcore_ptr[(cpu)]))
+#endif
+#endif /* __ASSEMBLY__ */
+
+#endif
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/mathemu.h linux.14p16/include/asm-s390/mathemu.h
--- linux.vanilla/include/asm-s390/mathemu.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/mathemu.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,48 @@
+/*
+ *  arch/s390/kernel/mathemu.h
+ *    IEEE floating point emulation.
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+
+#ifndef __MATHEMU__
+#define __MATHEMU__
+
+extern int math_emu_b3(__u8 *, struct pt_regs *);
+extern int math_emu_ed(__u8 *, struct pt_regs *);
+extern void math_emu_ldr(__u8 *);
+extern void math_emu_ler(__u8 *);
+extern void math_emu_std(__u8 *, struct pt_regs *);
+extern void math_emu_ld(__u8 *, struct pt_regs *);
+extern void math_emu_ste(__u8 *, struct pt_regs *);
+extern void math_emu_le(__u8 *, struct pt_regs *);
+extern int math_emu_lfpc(__u8 *, struct pt_regs *);
+extern int math_emu_stfpc(__u8 *, struct pt_regs *);
+extern int math_emu_srnm(__u8 *, struct pt_regs *);
+
+
+extern __u64 __adddf3(__u64,__u64);
+extern __u64 __subdf3(__u64,__u64);
+extern __u64 __muldf3(__u64,__u64);
+extern __u64 __divdf3(__u64,__u64);
+extern long  __cmpdf2(__u64,__u64);
+extern __u64 __negdf2(__u64);
+extern __u64 __absdf2(__u64);
+extern __u32 __addsf3(__u32,__u32);
+extern __u32 __subsf3(__u32,__u32);
+extern __u32 __mulsf3(__u32,__u32);
+extern __u32 __divsf3(__u32,__u32);
+extern __u32 __negsf2(__u32);
+extern __u32 __abssf2(__u32);
+extern long  __cmpsf2(__u32,__u32);
+extern __u32 __truncdfsf2(__u64);
+extern __u32 __fixsfsi(__u32);
+extern __u32 __fixdfsi(__u64);
+extern __u64  __floatsidf(__u32);
+extern __u32  __floatsisf(__u32);
+extern __u64  __extendsfdf2(__u32);
+
+#endif                                 /* __MATHEMU__                      */
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/md.h linux.14p16/include/asm-s390/md.h
--- linux.vanilla/include/asm-s390/md.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/md.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,16 @@
+/*
+ *  include/asm-s390/md.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386md/.h"
+ */
+ 
+#ifndef __ASM_MD_H
+#define __ASM_MD_H
+
+/* #define HAVE_ARCH_XORBLOCK */
+
+#define MD_XORBLOCK_ALIGNMENT	sizeof(long)
+
+#endif /* __ASM_MD_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/misc390.h linux.14p16/include/asm-s390/misc390.h
--- linux.vanilla/include/asm-s390/misc390.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/misc390.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,14 @@
+/*
+ *  include/asm-s390/misc390.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ */
+
+#define	allocaligned2(type,name,number,align)				\
+   __u8	name##buff[(sizeof(type)*(number+1))-1]; 	                \
+   type	*name=(type *)(((__u32)(&name##buff[align-1]))&(-align))
+
+#define	allocaligned(type,name,number)  allocaligned2(type,name,number,__alignof__(type))
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/mman.h linux.14p16/include/asm-s390/mman.h
--- linux.vanilla/include/asm-s390/mman.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/mman.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,40 @@
+/*
+ *  include/asm-s390/mman.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/mman.h"
+ */
+
+#ifndef __S390_MMAN_H__
+#define __S390_MMAN_H__
+
+#define PROT_READ	0x1		/* page can be read */
+#define PROT_WRITE	0x2		/* page can be written */
+#define PROT_EXEC	0x4		/* page can be executed */
+#define PROT_NONE	0x0		/* page can not be accessed */
+
+#define MAP_SHARED	0x01		/* Share changes */
+#define MAP_PRIVATE	0x02		/* Changes are private */
+#define MAP_TYPE	0x0f		/* Mask for type of mapping */
+#define MAP_FIXED	0x10		/* Interpret addr exactly */
+#define MAP_ANONYMOUS	0x20		/* don't use a file */
+
+#define MAP_GROWSDOWN	0x0100		/* stack-like segment */
+#define MAP_DENYWRITE	0x0800		/* ETXTBSY */
+#define MAP_EXECUTABLE	0x1000		/* mark it as an executable */
+#define MAP_LOCKED	0x2000		/* pages are locked */
+#define MAP_NORESERVE	0x4000		/* don't check for reservations */
+
+#define MS_ASYNC	1		/* sync memory asynchronously */
+#define MS_INVALIDATE	2		/* invalidate the caches */
+#define MS_SYNC		4		/* synchronous memory sync */
+
+#define MCL_CURRENT	1		/* lock all current mappings */
+#define MCL_FUTURE	2		/* lock all future mappings */
+
+/* compatibility flags */
+#define MAP_ANON	MAP_ANONYMOUS
+#define MAP_FILE	0
+
+#endif /* __S390_MMAN_H__ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/mmu_context.h linux.14p16/include/asm-s390/mmu_context.h
--- linux.vanilla/include/asm-s390/mmu_context.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/mmu_context.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,21 @@
+/*
+ *  include/asm-s390/mmu_context.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/mmu_context.h"
+ */
+
+#ifndef __S390_MMU_CONTEXT_H
+#define __S390_MMU_CONTEXT_H
+
+/*
+ * get a new mmu context.. S390 don't know about contexts.
+ */
+#define get_mmu_context(x) do { } while (0)
+
+#define init_new_context(mm)	do { } while(0)
+#define destroy_context(mm)	do { } while(0)
+#define activate_context(tsk)	do { } while(0)
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/namei.h linux.14p16/include/asm-s390/namei.h
--- linux.vanilla/include/asm-s390/namei.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/namei.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,22 @@
+/*
+ *  include/asm-s390/namei.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/namei.h"
+ *
+ *  Included from linux/fs/namei.c
+ */
+
+#ifndef __S390_NAMEI_H
+#define __S390_NAMEI_H
+
+/* This dummy routine maybe changed to something useful
+ * for /usr/gnemul/ emulation stuff.
+ * Look at asm-sparc/namei.h for details.
+ */
+
+#define __prefix_lookup_dentry(name, lookup_flags) \
+        do {} while (0)
+
+#endif /* __S390_NAMEI_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/page.h linux.14p16/include/asm-s390/page.h
--- linux.vanilla/include/asm-s390/page.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/page.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,96 @@
+/*
+ *  include/asm-s390/page.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Hartmut Penner (hp@de.ibm.com)
+ */
+
+#ifndef _S390_PAGE_H
+#define _S390_PAGE_H
+
+/* PAGE_SHIFT determines the page size */
+#define PAGE_SHIFT      12
+#define PAGE_SIZE       (1UL << PAGE_SHIFT)
+#define PAGE_MASK       (~(PAGE_SIZE-1))
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#define STRICT_MM_TYPECHECKS
+
+/*
+ * gcc uses builtin, i.e. MVCLE for both operations
+ */
+
+#define clear_page(page)        memset((void *)(page), 0, PAGE_SIZE)
+#define copy_page(to,from)      memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+
+#ifdef STRICT_MM_TYPECHECKS
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long pmd; } pmd_t;
+typedef struct {
+        unsigned long pgd0;
+        unsigned long pgd1;
+        unsigned long pgd2;
+        unsigned long pgd3;
+        } pgd_t;
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+#define pte_val(x)      ((x).pte)
+#define pmd_val(x)      ((x).pmd)
+#define pgd_val(x)      ((x).pgd0)
+#define pgprot_val(x)   ((x).pgprot)
+
+#define __pte(x)        ((pte_t) { (x) } )
+#define __pmd(x)        ((pmd_t) { (x) } )
+#define __pgd(x)        ((pgd_t) { (x) } )
+#define __pgprot(x)     ((pgprot_t) { (x) } )
+
+#else
+/*
+ * .. while these make it easier on the compiler
+ */
+typedef unsigned long pte_t;
+typedef unsigned long pmd_t;
+typedef struct {
+        unsigned long pgd0;
+        unsigned long pgd1;
+        unsigned long pgd2;
+        unsigned long pgd3;
+        } pgd_t;
+typedef unsigned long pgprot_t;
+
+#define pte_val(x)      (x)
+#define pmd_val(x)      (x)
+#define pgd_val(x)      (x)
+#define pgprot_val(x)   (x)
+
+#define __pte(x)        (x)
+#define __pmd(x)        (x)
+#define __pgd(x)        (x)
+#define __pgprot(x)     (x)
+
+#endif
+#endif                                 /* !__ASSEMBLY__                    */
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr)        (((addr)+PAGE_SIZE-1)&PAGE_MASK)
+
+/*
+ *
+ *
+ */
+
+#define __PAGE_OFFSET           (0x0)
+#define PAGE_OFFSET             ((unsigned long)__PAGE_OFFSET)
+#define __pa(x)                 ((unsigned long)(x)-PAGE_OFFSET)
+#define __va(x)                 ((void *)((unsigned long)(x)+PAGE_OFFSET))
+#define MAP_NR(addr)            (__pa(addr) >> PAGE_SHIFT)
+
+#endif                                 /* __KERNEL__                       */
+
+#endif                                 /* _S390_PAGE_H                     */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/param.h linux.14p16/include/asm-s390/param.h
--- linux.vanilla/include/asm-s390/param.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/param.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,28 @@
+/*
+ *  include/asm-s390/param.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/param.h"
+ */
+
+#ifndef _ASMS390_PARAM_H
+#define _ASMS390_PARAM_H
+
+#ifndef HZ
+#define HZ 100
+#endif
+
+#define EXEC_PAGESIZE	4096
+
+#ifndef NGROUPS
+#define NGROUPS		32
+#endif
+
+#ifndef NOGROUP
+#define NOGROUP		(-1)
+#endif
+
+#define MAXHOSTNAMELEN	64	/* max length of hostname */
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/pgtable.h linux.14p16/include/asm-s390/pgtable.h
--- linux.vanilla/include/asm-s390/pgtable.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/pgtable.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,711 @@
+/*
+ *  include/asm-s390/pgtable.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Hartmut Penner
+ *
+ *  Derived from "include/asm-i386/pgtable.h"
+ */
+
+#ifndef _ASM_S390_PGTABLE_H
+#define _ASM_S390_PGTABLE_H
+
+#include <linux/config.h>
+
+/*
+ * The Linux memory management assumes a three-level page table setup. On
+ * the S390, we use that, but "fold" the mid level into the top-level page
+ * table, so that we physically have the same two-level page table as the
+ * S390 mmu expects.
+ *
+ * This file contains the functions and defines necessary to modify and use
+ * the S390 page table tree.
+ */
+#ifndef __ASSEMBLY__
+#include <asm/processor.h>
+#include <linux/tasks.h>
+
+/* Caches aren't brain-dead on S390. */
+#define flush_cache_all()                       do { } while (0)
+#define flush_cache_mm(mm)                      do { } while (0)
+#define flush_cache_range(mm, start, end)       do { } while (0)
+#define flush_cache_page(vma, vmaddr)           do { } while (0)
+#define flush_page_to_ram(page)                 do { } while (0)
+#define flush_icache_range(start, end)          do { } while (0)
+
+/*
+ * TLB flushing:
+ *
+ *  - flush_tlb() flushes the current mm struct TLBs
+ *  - flush_tlb_all() flushes all processes TLBs 
+ *    called only from vmalloc/vfree
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *
+ */
+
+
+/*
+ * s390 has two ways of flushing TLBs
+ * 'ptlb' does a flush of the local processor
+ * 'ipte' invalidates a pte in a page table and flushes that out of 
+ * the TLBs of all PUs of a SMP 
+ */
+
+#define __flush_tlb() \
+do {  __asm__ __volatile__("ptlb": : :"memory"); } while (0)
+
+
+static inline void __flush_global_tlb(void) 
+{
+	int cs1=0,dum=0;
+	int *adr;
+	long long dummy=0;
+	adr = (int*) (((int)(((int*) &dummy)+1) & 0xfffffffc)|1);
+	__asm__ __volatile__("lr    2,%0\n\t"
+			     "lr    3,%1\n\t"
+			     "lr    4,%2\n\t"
+			     ".long 0xb2500024" :
+			     : "d" (cs1), "d" (dum), "d" (adr)
+			     : "2", "3", "4");
+}
+
+static inline void __flush_tlb_one(struct mm_struct *mm,
+                                   unsigned long addr);
+
+
+#ifndef __SMP__
+
+#define flush_tlb()       __flush_tlb()
+#define flush_tlb_all()   __flush_tlb()
+#define local_flush_tlb() __flush_tlb()
+
+/*
+ * We always need to flush, since s390 does not flush tlb
+ * on each context switch
+ */
+
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+        __flush_tlb();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+        unsigned long addr)
+{
+        __flush_tlb_one(vma->vm_mm,addr);
+}
+
+static inline void flush_tlb_range(struct mm_struct *mm,
+        unsigned long start, unsigned long end)
+{
+        __flush_tlb();
+}
+
+#else
+
+/*
+ * We aren't very clever about this yet -  SMP could certainly
+ * avoid some global flushes..
+ */
+
+#include <asm/smp.h>
+
+#define local_flush_tlb() \
+        __flush_tlb()
+
+/*
+ *      We only have to do global flush of tlb if process run since last
+ *      flush on any other pu than current. 
+ *      If we have threads (mm->count > 1) we always do a global flush, 
+ *      since the process runs on more than one processor at the same time.
+ */
+
+static inline void flush_tlb_current_task(void)
+{
+	if ((atomic_read(&current->mm->count) != 1) ||
+	    (current->mm->cpu_vm_mask != (1UL << smp_processor_id()))) {
+		current->mm->cpu_vm_mask = (1UL << smp_processor_id());
+		__flush_global_tlb();
+	} else {                 
+		local_flush_tlb();
+	}
+}
+
+#define flush_tlb() flush_tlb_current_task()
+
+#define flush_tlb_all() __flush_global_tlb()
+
+static inline void flush_tlb_mm(struct mm_struct * mm)
+{
+	if ((atomic_read(&mm->count) != 1) ||
+	    (mm->cpu_vm_mask != (1UL << smp_processor_id()))) {
+		mm->cpu_vm_mask = (1UL << smp_processor_id());
+		__flush_global_tlb();
+	} else {                 
+		local_flush_tlb();
+	}
+}
+
+static inline void flush_tlb_page(struct vm_area_struct * vma,
+        unsigned long va)
+{
+	__flush_tlb_one(vma->vm_mm,va);
+}
+
+static inline void flush_tlb_range(struct mm_struct * mm,
+				   unsigned long start, unsigned long end)
+{
+	if ((atomic_read(&mm->count) != 1) ||
+	    (mm->cpu_vm_mask != (1UL << smp_processor_id()))) {
+		mm->cpu_vm_mask = (1UL << smp_processor_id());
+		__flush_global_tlb();
+	} else {                 
+		local_flush_tlb();
+	}
+}
+
+#endif
+#endif                                 /* !__ASSEMBLY__                    */
+
+
+/* Certain architectures need to do special things when PTEs
+ * within a page table are directly modified.  Thus, the following
+ * hook is made available.
+ */
+#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
+
+/* PMD_SHIFT determines the size of the area a second-level page table can map */
+#define PMD_SHIFT       22
+#define PMD_SIZE        (1UL << PMD_SHIFT)
+#define PMD_MASK        (~(PMD_SIZE-1))
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define PGDIR_SHIFT     22
+#define PGDIR_SIZE      (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK      (~(PGDIR_SIZE-1))
+
+/*
+ * entries per page directory level: the S390 is two-level, so
+ * we don't really have any PMD directory physically.
+ * for S390 segment-table entries are combined to one PGD
+ * that leads to 1024 pte per pgd
+ */
+#define PTRS_PER_PTE    1024
+#define PTRS_PER_PMD    1
+#define PTRS_PER_PGD    512
+
+
+/*
+ * pgd entries used up by user/kernel:
+ */
+#define USER_PTRS_PER_PGD  512
+#define USER_PGD_PTRS      512
+#define KERNEL_PGD_PTRS    512
+#ifndef __ASSEMBLY__
+/* Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET  (8*1024*1024)
+#define VMALLOC_START   (((unsigned long) high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END     (0x7fffffffL)
+
+
+/*
+ * A pagetable entry of S390 has following format:
+ *
+ *  |   PFRA          |    |  OS  |
+ * 0                   0IP0
+ * 00000000001111111111222222222233
+ * 01234567890123456789012345678901
+ *
+ * I Page-Invalid Bit:    Page is not available for address-translation
+ * P Page-Protection Bit: Store access not possible for page
+ */
+
+/*
+ * A segmenttable entry of S390 has following format:
+ *
+ *  |   P-table origin      |  |PTL
+ * 0                         IC
+ * 00000000001111111111222222222233
+ * 01234567890123456789012345678901
+ *
+ * I Segment-Invalid Bit:    Segment is not available for address-translation
+ * C Common-Segment Bit:     Segment is not private (PoP 3-30)
+ * PTL Page-Table-Length:    Length of Page-table (PTL+1*16 entries -> up to 256 entries)
+ */
+
+/*
+ * The segmenttable origin of S390 has following format:
+ *
+ *  |S-table origin   |     | STL |
+ * X                   **GPS
+ * 00000000001111111111222222222233
+ * 01234567890123456789012345678901
+ *
+ * X Space-Switch event:
+ * G Segment-Invalid Bit:     *
+ * P Private-Space Bit:       Segment is not private (PoP 3-30)
+ * S Storage-Alteration:
+ * STL Segment-Table-Length:  Length of Page-table (STL+1*16 entries -> up to 2048 entries)
+ */
+
+#define _PAGE_PRESENT   0x001          /* Software                         */
+#define _PAGE_ACCESSED  0x002          /* Software accessed                */
+#define _PAGE_DIRTY     0x004          /* Software dirty                   */
+#define _PAGE_RO        0x200          /* HW read-only                     */
+#define _PAGE_INVALID   0x400          /* HW invalid                       */
+
+#define _PAGE_TABLE_LEN 0xf            /* only full page-tables            */
+#define _PAGE_TABLE_COM 0x10           /* common page-table                */
+#define _PAGE_TABLE_INV 0x20           /* invalid page-table               */
+#define _SEG_PRESENT    0x001          /* Software (overlap with PTL)      */
+
+#define _USER_SEG_TABLE_LEN    0x7f    /* user-segment-table up to 2 GB    */
+#define _KERNEL_SEG_TABLE_LEN  0x7f    /* kernel-segment-table up to 2 GB  */
+
+/*
+ * User and Kernel pagetables are identical
+ */
+
+#define _PAGE_TABLE     (_PAGE_TABLE_LEN )
+#define _KERNPG_TABLE   (_PAGE_TABLE_LEN )
+
+/*
+ * The Kernel segment-tables includes the User segment-table
+ */
+
+#define _SEGMENT_TABLE  (_USER_SEG_TABLE_LEN)
+#define _KERNSEG_TABLE  (_KERNEL_SEG_TABLE_LEN)
+/*
+ * No mapping available
+ */
+#define PAGE_NONE       __pgprot(_PAGE_INVALID )
+
+#define PAGE_SHARED     __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+#define PAGE_COPY       __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_RO)
+#define PAGE_READONLY   __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_RO)
+#define PAGE_KERNEL     __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY)
+
+/*
+ * The S390 can't do page protection for execute, and considers that the same are read.
+ * Also, write permissions imply read permissions. This is the closest we can get..
+ */
+#define __P000  PAGE_NONE
+#define __P001  PAGE_READONLY
+#define __P010  PAGE_COPY
+#define __P011  PAGE_COPY
+#define __P100  PAGE_READONLY
+#define __P101  PAGE_READONLY
+#define __P110  PAGE_COPY
+#define __P111  PAGE_COPY
+
+#define __S000  PAGE_NONE
+#define __S001  PAGE_READONLY
+#define __S010  PAGE_SHARED
+#define __S011  PAGE_SHARED
+#define __S100  PAGE_READONLY
+#define __S101  PAGE_READONLY
+#define __S110  PAGE_SHARED
+#define __S111  PAGE_SHARED
+
+/*
+ * Define this if things work differently on an i386 and an i486:
+ * it will (on an i486) warn about kernel memory accesses that are
+ * done without a 'verify_area(VERIFY_WRITE,..)'
+ *
+ * Kernel and User memory-access are done equal, so we don't need verify
+ */
+#undef TEST_VERIFY_AREA
+
+/* page table for 0-4MB for everybody */
+
+extern unsigned long pg0[1024];
+
+/* zero page used for uninitialized stuff */
+extern unsigned long empty_zero_page[1024];
+
+/*
+ * BAD_PAGETABLE is used when we need a bogus page-table, while
+ * BAD_PAGE is used for a bogus page.
+ *
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern pte_t __bad_page(void);
+extern pte_t * __bad_pagetable(void);
+
+#define BAD_PAGETABLE __bad_pagetable()
+#define BAD_PAGE __bad_page()
+#define ZERO_PAGE(vaddr) ((unsigned long) empty_zero_page)
+
+/* number of bits that fit into a memory pointer */
+#define BITS_PER_PTR                    (8*sizeof(unsigned long))
+
+/* to align the pointer to a pointer address */
+#define PTR_MASK                        (~(sizeof(void*)-1))
+
+/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
+/* 64-bit machines, beware!  SRB. */
+#define SIZEOF_PTR_LOG2                 2
+
+/* to find an entry in a page-table */
+#define PAGE_PTR(address) \
+((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
+
+
+
+/* 
+ * CR 7 (SPST) and cr 13 (HPST) are set to the user pgdir. 
+ * Kernel is running in its own, disjunct address space,
+ * running in primary address space.
+ * Copy to/from user is done via access register mode with
+ * access registers set to 0 or 1. For that purpose we need 
+ * set up CR 7 with the user pgd.  
+ * 
+ */
+
+#define SET_PAGE_DIR(tsk,pgdir)                                                 \
+do {                                                                            \
+        unsigned long __pgdir = (__pa(pgdir) & PAGE_MASK ) | _SEGMENT_TABLE; \
+        (tsk)->tss.user_seg = __pgdir;                                        \
+        if ((tsk) == current) {                                               \
+                __asm__ __volatile__("lctl  7,7,%0": :"m" (__pgdir));         \
+                __asm__ __volatile__("lctl  13,13,%0": :"m" (__pgdir));       \
+        }                                                                     \
+} while (0)
+
+
+extern inline int pte_none(pte_t pte)           { return ((pte_val(pte) & (_PAGE_INVALID | _PAGE_RO)) ==  
+							  _PAGE_INVALID); } 
+extern inline int pte_present(pte_t pte)        { return pte_val(pte) & _PAGE_PRESENT; }
+extern inline void pte_clear(pte_t *ptep)       { pte_val(*ptep) = _PAGE_INVALID; }
+
+extern inline int pmd_none(pmd_t pmd)           { return pmd_val(pmd) & _PAGE_TABLE_INV; }
+extern inline int pmd_bad(pmd_t pmd)            { return (pmd_val(pmd) == 0); }
+extern inline int pmd_present(pmd_t pmd)        { return pmd_val(pmd) & _SEG_PRESENT; }
+extern inline void pmd_clear(pmd_t * pmdp)      {
+                                                        pmd_val(pmdp[0]) = _PAGE_TABLE_INV;
+                                                        pmd_val(pmdp[1]) = _PAGE_TABLE_INV;
+                                                        pmd_val(pmdp[2]) = _PAGE_TABLE_INV;
+                                                        pmd_val(pmdp[3]) = _PAGE_TABLE_INV;
+                                                }
+
+/*
+ * The "pgd_xxx()" functions here are trivial for a folded two-level
+ * setup: the pgd is never bad, and a pmd always exists (as it's folded
+ * into the pgd entry)
+ */
+extern inline int pgd_none(pgd_t pgd)           { return 0; }
+extern inline int pgd_bad(pgd_t pgd)            { return 0; }
+extern inline int pgd_present(pgd_t pgd)        { return 1; }
+extern inline void pgd_clear(pgd_t * pgdp)      { }
+
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+extern inline int pte_write(pte_t pte)          { return !(pte_val(pte) & _PAGE_RO); }
+extern inline int pte_dirty(pte_t pte)          { return pte_val(pte) & _PAGE_DIRTY; }
+extern inline int pte_young(pte_t pte)          { return pte_val(pte) & _PAGE_ACCESSED; }
+
+/* who needs that
+extern inline int pte_read(pte_t pte)           { return !(pte_val(pte) & _PAGE_INVALID); }
+extern inline int pte_exec(pte_t pte)           { return !(pte_val(pte) & _PAGE_INVALID); }
+extern inline pte_t pte_rdprotect(pte_t pte)    { pte_val(pte) |= _PAGE_INVALID; return pte; }
+extern inline pte_t pte_exprotect(pte_t pte)    { pte_val(pte) |= _PAGE_INVALID; return pte; }
+extern inline pte_t pte_mkread(pte_t pte)       { pte_val(pte) &= _PAGE_INVALID; return pte; }
+extern inline pte_t pte_mkexec(pte_t pte)       { pte_val(pte) &= _PAGE_INVALID; return pte; }
+*/
+
+extern inline pte_t pte_wrprotect(pte_t pte)    { pte_val(pte) |= _PAGE_RO; return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte)      { pte_val(pte) &= ~_PAGE_RO ; return pte; }
+
+extern inline pte_t pte_mkclean(pte_t pte)      { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
+extern inline pte_t pte_mkdirty(pte_t pte)      { pte_val(pte) |= _PAGE_DIRTY; return pte; }
+
+extern inline pte_t pte_mkold(pte_t pte)        { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+extern inline pte_t pte_mkyoung(pte_t pte)      { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+#define mk_pte(page, pgprot) \
+({ pte_t __pte; pte_val(__pte) = __pa(page) + pgprot_val(pgprot); __pte; })
+
+/* This takes a physical page address that is used by the remapping functions */
+#define mk_pte_phys(physpage, pgprot) \
+({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; })
+
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{ pte_val(pte) = (pte_val(pte) & PAGE_MASK) | pgprot_val(newprot); return pte; }
+
+#define pte_page(pte) \
+((unsigned long) __va(pte_val(pte) & PAGE_MASK))
+
+#define pmd_page(pmd) \
+((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+
+/* to find an entry in a page-table-directory */
+#define pgd_offset(mm, address) \
+((mm)->pgd + ((address) >> PGDIR_SHIFT))
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+/* Find an entry in the second-level page table.. */
+extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+{
+        return (pmd_t *) dir;
+}
+
+/* Find an entry in the third-level page table.. */
+#define pte_offset(pmd, address) \
+((pte_t *) (pmd_page(*pmd) + ((address>>10) & ((PTRS_PER_PTE-1)<<2))))
+
+
+static inline void __flush_tlb_one(struct mm_struct *mm,
+                                   unsigned long addr)
+{
+	pgd_t * pgdir;
+	pmd_t * pmd;
+	pte_t * pte, *pto;
+	
+	pgdir = pgd_offset(mm, addr);
+	if (pgd_none(*pgdir) || pgd_bad(*pgdir))
+		return;
+	pmd = pmd_offset(pgdir, addr);
+	if (pmd_none(*pmd) || pmd_bad(*pmd))
+		return;
+	pte = pte_offset(pmd,addr);
+
+	/*
+	 * S390 has 1mb segments, we are emulating 4MB segments
+	 */
+
+	pto = (pte_t*) (((unsigned long) pte) & 0x7ffffc00);
+	       
+       	__asm__ __volatile("    ic   0,2(%0)\n"
+			   "    ipte %1,%2\n"
+			   "    stc  0,2(%0)"
+			   : : "a" (pte), "a" (pto), "a" (addr): "0");
+}
+
+/*
+ * Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on ASN bits
+ * if any.
+ */
+
+#define pgd_quicklist (S390_lowcore.cpu_data.pgd_quick)
+#define pmd_quicklist ((unsigned long *)0)
+#define pte_quicklist (S390_lowcore.cpu_data.pte_quick)
+#define pgtable_cache_size (S390_lowcore.cpu_data.pgtable_cache_sz)
+
+extern __inline__ pgd_t* get_pgd_slow(void)
+{
+        int i;
+        pgd_t *pgd,*ret = (pgd_t *)__get_free_pages(GFP_KERNEL,2);
+	if (ret)
+		for (i=0,pgd=ret;i<USER_PTRS_PER_PGD;i++,pgd++)
+			pmd_clear(pmd_offset(pgd,i*PGDIR_SIZE));
+        return ret;
+}
+
+extern __inline__ pgd_t* get_pgd_fast(void)
+{
+        unsigned long *ret;
+	
+        if((ret = pgd_quicklist) != NULL) {
+                pgd_quicklist = (unsigned long *)(*ret);
+                ret[0] = ret[1];
+                pgtable_cache_size--;
+		/*
+		 * Need to flush tlb, since private page tables
+		 * are unique thru address of pgd and virtual address.
+		 * If we reuse pgd we need to be sure no tlb entry
+		 * with that pdg is left -> global flush
+		 *
+		 * Fixme: To avoid this global flush we should
+		 * use pdg_quicklist as fix lenght fifo list
+		 * and not as stack
+		 */
+        } else
+                ret = (unsigned long *)get_pgd_slow();
+        return (pgd_t *)ret;
+}
+
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
+{
+        *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+        pgd_quicklist = (unsigned long *) pgd;
+        pgtable_cache_size++;
+}
+
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
+{
+        free_pages((unsigned long)pgd,2);
+}
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted);
+
+extern __inline__ pte_t* get_pte_fast(void)
+{
+        unsigned long *ret;
+
+        if((ret = (unsigned long *)pte_quicklist) != NULL) {
+                pte_quicklist = (unsigned long *)(*ret);
+                ret[0] = ret[1];
+                pgtable_cache_size--;
+        }
+        return (pte_t *)ret;
+}
+
+extern __inline__ void free_pte_fast(pte_t *pte)
+{
+        *(unsigned long *)pte = (unsigned long) pte_quicklist;
+        pte_quicklist = (unsigned long *) pte;
+        pgtable_cache_size++;
+}
+
+extern __inline__ void free_pte_slow(pte_t *pte)
+{
+        free_page((unsigned long)pte);
+}
+
+/* We don't use pmd cache, so these are dummy routines */
+extern __inline__ pmd_t *get_pmd_fast(void)
+{
+        return (pmd_t *)0;
+}
+
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
+{
+}
+
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
+{
+}
+
+extern void __bad_pte(pmd_t *pmd);
+extern void __bad_pte_kernel(pmd_t *pmd);
+
+#define pte_free_kernel(pte)    free_pte_fast(pte)
+#define pte_free(pte)           free_pte_fast(pte)
+#define pgd_free(pgd)           free_pgd_fast(pgd)
+#define pgd_alloc()             get_pgd_fast()
+
+extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
+{
+        address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+        if (pmd_none(*pmd)) {
+                pte_t * page = (pte_t *) get_pte_fast();
+
+                if (!page)
+                        return get_pte_kernel_slow(pmd, address);
+                pmd_val(pmd[0]) = _KERNPG_TABLE + __pa(page);
+                pmd_val(pmd[1]) = _KERNPG_TABLE + __pa(page+1024);
+                pmd_val(pmd[2]) = _KERNPG_TABLE + __pa(page+2048);
+                pmd_val(pmd[3]) = _KERNPG_TABLE + __pa(page+3072);
+                return page + address;
+        }
+        if (pmd_bad(*pmd)) {
+                __bad_pte_kernel(pmd);
+                return NULL;
+        }
+        return (pte_t *) pmd_page(*pmd) + address;
+}
+
+extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
+{
+        address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+
+        if (pmd_none(*pmd))
+                goto getnew;
+        if (pmd_bad(*pmd))
+                goto fix;
+        return (pte_t *) pmd_page(*pmd) + address;
+getnew:
+{
+        unsigned long page = (unsigned long) get_pte_fast();
+
+        if (!page)
+                return get_pte_slow(pmd, address);
+        pmd_val(pmd[0]) = _PAGE_TABLE + __pa(page);
+        pmd_val(pmd[1]) = _PAGE_TABLE + __pa(page+1024);
+        pmd_val(pmd[2]) = _PAGE_TABLE + __pa(page+2048);
+        pmd_val(pmd[3]) = _PAGE_TABLE + __pa(page+3072);
+        return (pte_t *) page + address;
+}
+fix:
+        __bad_pte(pmd);
+        return NULL;
+}
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+extern inline void pmd_free(pmd_t * pmd)
+{
+}
+
+extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
+{
+        return (pmd_t *) pgd;
+}
+
+#define pmd_free_kernel         pmd_free
+#define pmd_alloc_kernel        pmd_alloc
+
+extern int do_check_pgt_cache(int, int);
+
+#define set_pgdir(addr,entry) do { } while(0)
+
+extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096)));
+
+/*
+ * The S390 doesn't have any external MMU info: the kernel page
+ * tables contain all the necessary information.
+ */
+extern inline void update_mmu_cache(struct vm_area_struct * vma,
+        unsigned long address, pte_t pte)
+{
+}
+
+/*
+ * a page-table entry has only 19 bit for offset and 7 bit for type
+ * if bits 0, 20 or 23 are set, a translation specification exceptions occures, and it's
+ * hard to find out the failing address
+ * therefor, we zero out this bits
+ */
+
+#define SWP_TYPE(entry) (((entry) >> 1) & 0x3f)
+#define SWP_OFFSET(entry) (((entry) >> 12) & 0x7FFFF )
+#define SWP_ENTRY(type,offset) ((((type) << 1) | ((offset) << 12) |  \
+				 _PAGE_INVALID | _PAGE_RO) & 0x7FFFF6FE)
+
+#define module_map      vmalloc
+#define module_unmap    vfree
+
+#endif /* !__ASSEMBLY__ */
+
+/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
+#define PageSkip(page)          (0)
+#define kern_addr_valid(addr)   (1)
+
+#endif /* _S390_PAGE_H */
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/poll.h linux.14p16/include/asm-s390/poll.h
--- linux.vanilla/include/asm-s390/poll.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/poll.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,33 @@
+/*
+ *  include/asm-s390/poll.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/poll.h"
+ */
+
+#ifndef __S390_POLL_H
+#define __S390_POLL_H
+
+/* These are specified by iBCS2 */
+#define POLLIN          0x0001
+#define POLLPRI         0x0002
+#define POLLOUT         0x0004
+#define POLLERR         0x0008
+#define POLLHUP         0x0010
+#define POLLNVAL        0x0020
+
+/* The rest seem to be more-or-less nonstandard. Check them! */
+#define POLLRDNORM	0x0040
+#define POLLRDBAND	0x0080
+#define POLLWRNORM	0x0100
+#define POLLWRBAND	0x0200
+#define POLLMSG		0x0400
+
+struct pollfd {
+	int fd;
+	short events;
+	short revents;
+};
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/posix_types.h linux.14p16/include/asm-s390/posix_types.h
--- linux.vanilla/include/asm-s390/posix_types.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/posix_types.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,69 @@
+/*
+ *  include/asm-s390/posix_types.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/posix_types.h"
+ */
+
+#ifndef __ARCH_S390_POSIX_TYPES_H
+#define __ARCH_S390_POSIX_TYPES_H
+
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc.  Also, we cannot
+ * assume GCC is being used.
+ */
+
+typedef unsigned short  __kernel_dev_t;
+typedef unsigned long   __kernel_ino_t;
+typedef unsigned short  __kernel_mode_t;
+typedef unsigned short  __kernel_nlink_t;
+typedef long            __kernel_off_t;
+typedef int             __kernel_pid_t;
+typedef unsigned short  __kernel_ipc_pid_t;
+typedef unsigned short  __kernel_uid_t;
+typedef unsigned short  __kernel_gid_t;
+typedef unsigned long   __kernel_size_t;
+typedef int             __kernel_ssize_t;
+typedef int             __kernel_ptrdiff_t;
+typedef long            __kernel_time_t;
+typedef long            __kernel_suseconds_t;
+typedef long            __kernel_clock_t;
+typedef int             __kernel_daddr_t;
+typedef char *          __kernel_caddr_t;
+
+#ifdef __GNUC__
+typedef long long       __kernel_loff_t;
+#endif
+
+typedef struct {
+#if defined(__KERNEL__) || defined(__USE_ALL)
+        int     val[2];
+#else                        /* !defined(__KERNEL__) && !defined(__USE_ALL)*/
+        int     __val[2];
+#endif                       /* !defined(__KERNEL__) && !defined(__USE_ALL)*/
+} __kernel_fsid_t;
+
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
+#ifndef _S390_BITOPS_H
+#include <asm/bitops.h>
+#endif
+
+#undef  __FD_SET
+#define __FD_SET(fd,fdsetp)  set_bit(fd,fdsetp)
+
+#undef  __FD_CLR
+#define __FD_CLR(fd,fdsetp)  clear_bit(fd,fdsetp)
+
+#undef  __FD_ISSET
+#define __FD_ISSET(fd,fdsetp)  test_bit(fd,fdsetp)
+
+#undef  __FD_ZERO
+#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp)))
+
+#endif     /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)*/
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/processor.h linux.14p16/include/asm-s390/processor.h
--- linux.vanilla/include/asm-s390/processor.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/processor.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,176 @@
+/*
+ *  include/asm-s390/processor.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Hartmut Penner (hp@de.ibm.com),
+ *               Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *  Derived from "include/asm-i386/processor.h"
+ *    Copyright (C) 1994, Linus Torvalds
+ */
+
+#ifndef __ASM_S390_PROCESSOR_H
+#define __ASM_S390_PROCESSOR_H
+
+#include <asm/page.h>
+#include <asm/ptrace.h>
+
+/*
+ *  CPU type and hardware bug flags. Kept separately for each CPU.
+ *  Members of this structure are referenced in head.S, so think twice
+ *  before touching them. [mj]
+ */
+
+typedef struct
+{
+        unsigned int version :  8;
+        unsigned int ident   : 24;
+        unsigned int machine : 16;
+        unsigned int unused  : 16;
+} __attribute__ ((packed)) cpuid_t;
+
+struct cpuinfo_S390
+{
+        cpuid_t  cpu_id;
+        __u16    cpu_addr;
+        __u16    cpu_nr;
+        unsigned long loops_per_sec;
+        unsigned long *pgd_quick;
+        unsigned long *pte_quick;
+        unsigned long pgtable_cache_sz;
+};
+
+extern void print_cpu_info(struct cpuinfo_S390 *);
+
+/* Lazy FPU handling on uni-processor */
+extern struct task_struct *last_task_used_math;
+
+/*
+ * User space process size: 2GB (default).
+ */
+#define TASK_SIZE       (0x80000000)
+/* This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE      (TASK_SIZE / 2)
+
+typedef struct {
+        unsigned long seg;
+        unsigned long acc4;
+} mm_segment_t;
+
+
+/* if you change the thread_struct structure, you must
+ * update the _TSS_* defines in entry.S
+ */
+
+
+
+struct thread_struct
+ {
+
+        struct pt_regs *regs;         /* the user registers can be found on*/
+	s390_fp_regs fp_regs;
+        __u32   ar2;                   /* kernel access register 2         */
+        __u32   ar4;                   /* kernel access register 4         */
+        __u32   ksp;                   /* kernel stack pointer             */
+        __u32   user_seg;              /* HSTD                             */
+        __u32   error_code;            /* error-code of last prog-excep.   */
+        __u32   prot_addr;             /* address of protection-excep.     */
+        __u32   trap_no;
+        /* perform syscall argument validation (get/set_fs) */
+        mm_segment_t fs;
+        per_struct per_info;/* Must be aligned on an 4 byte boundary*/
+};
+
+typedef struct thread_struct thread_struct;
+
+#define INIT_MMAP \
+{ &init_mm, 0, 0, NULL, PAGE_SHARED, \
+VM_READ | VM_WRITE | VM_EXEC, 1, NULL, &init_mm.mmap }
+
+#define INIT_TSS  { (struct pt_regs *) 0,                         \
+                    { 0,{{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}, \
+			    {0},{0},{0},{0},{0},{0}}},            \
+                     0, 0,                                        \
+                    sizeof(init_stack) + (__u32) &init_stack,     \
+              (__pa((__u32) &swapper_pg_dir[0]) + _SEGMENT_TABLE),\
+                     0,0,0,                                       \
+                     (mm_segment_t) { 0,1},                       \
+                     (per_struct) {{{{0,}}},0,0,0,0,{{0,}}}       \
+}
+
+/* need to define ... */
+#define start_thread(regs, new_psw, new_stackp) do {            \
+        unsigned long *u_stack = new_stackp;                    \
+        regs->psw.mask  = _USER_PSW_MASK;                       \
+        regs->psw.addr  = new_psw | 0x80000000 ;                \
+        get_user(regs->gprs[2],u_stack);                        \
+        get_user(regs->gprs[3],u_stack+1);                      \
+        get_user(regs->gprs[4],u_stack+2);                      \
+        regs->gprs[15]  = new_stackp ;                          \
+} while (0)
+
+/* Forward declaration, a strange C thing */
+struct mm_struct;
+
+/* Free all resources held by a thread. */
+extern void release_thread(struct task_struct *);
+extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+
+/* Copy and release all segment info associated with a VM */
+#define copy_segments(nr, tsk, mm)      do { } while (0)
+#define release_segments(mm)            do { } while (0)
+#define forget_segments()               do { } while (0)
+
+
+/*
+ * Return saved PC of a blocked thread. used in kernel/sched
+ */
+extern inline unsigned long thread_saved_pc(struct thread_struct *t)
+{
+        return (t->regs) ? ((unsigned long)t->regs->psw.addr) : 0;
+}
+
+/* Allocation and freeing of basic task resources. */
+/*
+ * NOTE! The task struct and the stack go together
+ */
+#define alloc_task_struct() \
+        ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
+#define free_task_struct(p)     free_pages((unsigned long)(p),1)
+
+#define init_task       (init_task_union.task)
+#define init_stack      (init_task_union.stack)
+
+/*
+ * Set of msr bits that gdb can change on behalf of a process.
+ */
+/* Only let our hackers near the condition codes */
+#define PSW_MASK_DEBUGCHANGE    0x00003000UL
+/* Don't let em near the addressing mode either */    
+#define PSW_ADDR_DEBUGCHANGE    0x7FFFFFFFUL
+#define PSW_ADDR_MASK           0x7FFFFFFFUL
+/* Program event recording mask */    
+#define PSW_PER_MASK            0x40000000UL
+#define USER_STD_MASK           0x00000080UL
+#define PSW_PROBLEM_STATE       0x00010000UL
+
+/*
+ * Function to drop a processor into disabled wait state
+ */
+
+static inline void disabled_wait(unsigned long code)
+{
+        char psw_buffer[2*sizeof(psw_t)];
+        psw_t *dw_psw = (psw_t *)(((unsigned long) &psw_buffer+sizeof(psw_t)-1)
+                                  & -sizeof(psw_t));
+
+        dw_psw->mask = 0x000a0000;
+        dw_psw->addr = code;
+        /* load disabled wait psw, the processor is dead afterwards */
+        asm volatile ("lpsw 0(%0)" : : "a" (dw_psw));
+}
+
+#endif                                 /* __ASM_S390_PROCESSOR_H           */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/ptrace.h linux.14p16/include/asm-s390/ptrace.h
--- linux.vanilla/include/asm-s390/ptrace.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/ptrace.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,326 @@
+/*
+ *  include/asm-s390/ptrace.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ */
+
+#ifndef _S390_PTRACE_H
+#define _S390_PTRACE_H
+#include <asm/s390-regs-common.h>
+#include <asm/current.h>
+#include <linux/types.h>
+#include <asm/setup.h>
+#include <linux/stddef.h>
+
+
+#define S390_REGS   \
+S390_REGS_COMMON    \
+__u32 orig_gpr2;
+
+typedef struct
+{
+	S390_REGS
+} s390_regs;
+
+struct pt_regs 
+{
+	S390_REGS
+	long trap;
+};
+
+#if CONFIG_REMOTE_DEBUG
+typedef struct
+{
+	S390_REGS
+	long  trap;
+	__u32 crs[16];
+	s390_fp_regs fp_regs;
+} gdb_pt_regs;
+#endif
+
+
+typedef struct
+{
+			__u32   cr[3];
+} per_cr_words  __attribute__((packed));
+
+#define PER_EM_MASK 0xE8000000
+typedef	struct
+{
+	unsigned    em_branching:1;
+	unsigned    em_instruction_fetch:1;
+	/* Switching on storage alteration automatically fixes
+	   the storage alteration event bit in the users std. */
+	unsigned    em_storage_alteration:1;
+	unsigned    em_gpr_alt_unused:1;
+	unsigned    em_store_real_address:1;
+	unsigned    :3;
+	unsigned    branch_addr_ctl:1;
+	unsigned    :1;
+	unsigned    storage_alt_space_ctl:1;
+	unsigned    :5;
+	unsigned    :16;
+	__u32   starting_addr;
+	__u32   ending_addr;
+} per_cr_bits  __attribute__((packed));
+
+typedef struct
+{
+	__u16          perc_atmid;          /* 0x096 */
+	__u32          address;             /* 0x098 */
+	__u8           access_id;           /* 0x0a1 */
+} per_lowcore_words  __attribute__((packed));
+
+typedef struct
+{
+	unsigned       perc_branching:1;               /* 0x096 */
+	unsigned       perc_instruction_fetch:1;
+	unsigned       perc_storage_alteration:1;
+	unsigned       perc_gpr_alt_unused:1;
+	unsigned       perc_store_real_address:1;
+	unsigned       :3;
+	unsigned       :1;
+	unsigned       atmid:5;
+	unsigned       si:2;
+	__u32          address;              /* 0x098 */
+	unsigned       :4;                   /* 0x0a1 */
+	unsigned       access_id:4;           
+} per_lowcore_bits __attribute__((packed));
+
+typedef struct
+{
+	union
+	{
+		per_cr_words   words;
+		per_cr_bits    bits;
+	} control_regs  __attribute__((packed));
+	/* Use these flags instead of setting em_instruction_fetch */
+	/* directly they are used so that single stepping can be */
+	/* switched on & off while not affecting other tracing */
+	unsigned  single_step:1;
+	unsigned  instruction_fetch:1;
+	unsigned  :30;
+	/* These addresses are copied into cr10 & cr11 if single stepping
+	   is switched off */
+	__u32     starting_addr;
+	__u32     ending_addr;
+	union
+	{
+		per_lowcore_words words;
+		per_lowcore_bits  bits;
+	} lowcore; 
+} per_struct __attribute__((packed));
+
+
+
+/* this struct defines the way the registers are stored on the
+   stack during a system call. If you change the pt_regs structure,
+   you'll need to change user.h too. 
+
+   N.B. if you modify the pt_regs struct the strace command also has to be
+   modified & recompiled  ( just wait till we have gdb going ).
+
+*/
+
+struct user_regs_struct
+{
+	S390_REGS
+	s390_fp_regs fp_regs;
+/* These per registers are in here so that gdb can modify them itself
+ * as there is no "official" ptrace interface for hardware watchpoints.
+ * this is the way intel does it
+ */
+	per_struct per_info;
+};
+
+typedef struct user_regs_struct user_regs_struct;
+
+typedef struct pt_regs pt_regs;
+
+#ifdef __KERNEL__
+#define user_mode(regs) ((regs)->psw.mask & PSW_PROBLEM_STATE)
+#define instruction_pointer(regs) ((regs)->psw.addr)
+
+struct thread_struct;
+extern int sprintf_regs(int line,char *buff,struct task_struct * task,
+			struct thread_struct *tss,struct pt_regs * regs);
+extern void show_regs(struct task_struct * task,struct thread_struct *tss,
+		      struct pt_regs * regs);
+#endif
+
+
+
+
+
+#define FIX_PSW(addr) ((unsigned long)(addr)|0x80000000UL)
+
+#define MULT_PROCPTR_TYPES    ((CONFIG_BINFMT_ELF)&&(CONFIG_BINFMT_TOC))
+
+typedef struct
+{
+  long addr;
+  long toc;
+} routine_descriptor;
+extern void fix_routine_descriptor_regs(routine_descriptor *rdes,pt_regs *regs);
+extern __inline__ void 
+fix_routine_descriptor_regs(routine_descriptor *rdes,pt_regs *regs)
+{
+  regs->psw.addr=FIX_PSW(rdes->addr);
+  regs->gprs[12]=rdes->toc;
+}
+
+/*
+ * Compiler optimisation should save this stuff from being non optimal
+ * & remove uneccessary code ( isnt gcc great DJB. )
+ */
+
+/*I'm just using this an indicator of what binformat we are using
+ * (DJB) N.B. this needs to stay a macro unfortunately as I am otherwise
+ * dereferencing incomplete pointer types in with load_toc_binary
+ */
+#if MULT_PROCPTR_TYPES
+#define uses_routine_descriptors() \
+(current->binfmt->load_binary==load_toc_binary)
+#else
+#if CONFIG_BINFMT_TOC
+#define uses_routine_descriptors() 1
+#else
+#define uses_routine_descriptors() 0
+#endif
+#endif
+
+#define pt_off(ptreg)   offsetof(user_regs_struct,ptreg)
+enum
+{
+	PT_PSWMASK=pt_off(psw.mask),
+	PT_PSWADDR=pt_off(psw.addr),
+	PT_GPR0=pt_off(gprs[0]),
+	PT_GPR1=pt_off(gprs[1]),
+	PT_GPR2=pt_off(gprs[2]),
+	PT_GPR3=pt_off(gprs[3]),
+	PT_GPR4=pt_off(gprs[4]),
+	PT_GPR5=pt_off(gprs[5]),
+	PT_GPR6=pt_off(gprs[6]),
+	PT_GPR7=pt_off(gprs[7]),
+	PT_GPR8=pt_off(gprs[8]),
+	PT_GPR9=pt_off(gprs[9]),
+	PT_GPR10=pt_off(gprs[10]),
+	PT_GPR11=pt_off(gprs[11]),
+	PT_GPR12=pt_off(gprs[12]),
+	PT_GPR13=pt_off(gprs[13]),
+	PT_GPR14=pt_off(gprs[14]),
+	PT_GPR15=pt_off(gprs[15]),
+        PT_ACR0=pt_off(acrs[0]),
+        PT_ACR1=pt_off(acrs[1]),
+        PT_ACR2=pt_off(acrs[2]),
+        PT_ACR3=pt_off(acrs[3]),
+        PT_ACR4=pt_off(acrs[4]),
+        PT_ACR5=pt_off(acrs[5]),
+        PT_ACR6=pt_off(acrs[6]),
+        PT_ACR7=pt_off(acrs[7]),
+        PT_ACR8=pt_off(acrs[8]),
+        PT_ACR9=pt_off(acrs[9]),
+        PT_ACR10=pt_off(acrs[10]),
+        PT_ACR11=pt_off(acrs[11]),
+        PT_ACR12=pt_off(acrs[12]),
+        PT_ACR13=pt_off(acrs[13]),
+        PT_ACR14=pt_off(acrs[14]),
+        PT_ACR15=pt_off(acrs[15]),
+	PT_ORIGGPR2=pt_off(orig_gpr2),
+	PT_FPC=pt_off(fp_regs.fpc),
+/*
+ *      A nasty fact of life that the ptrace api
+ *      only supports passing of longs.
+ */
+	PT_FPR0_HI=pt_off(fp_regs.fprs[0].fp.hi),
+	PT_FPR0_LO=pt_off(fp_regs.fprs[0].fp.lo),
+	PT_FPR1_HI=pt_off(fp_regs.fprs[1].fp.hi),
+	PT_FPR1_LO=pt_off(fp_regs.fprs[1].fp.lo),
+	PT_FPR2_HI=pt_off(fp_regs.fprs[2].fp.hi),
+	PT_FPR2_LO=pt_off(fp_regs.fprs[2].fp.lo),
+	PT_FPR3_HI=pt_off(fp_regs.fprs[3].fp.hi),
+	PT_FPR3_LO=pt_off(fp_regs.fprs[3].fp.lo),
+	PT_FPR4_HI=pt_off(fp_regs.fprs[4].fp.hi),
+	PT_FPR4_LO=pt_off(fp_regs.fprs[4].fp.lo),
+	PT_FPR5_HI=pt_off(fp_regs.fprs[5].fp.hi),
+	PT_FPR5_LO=pt_off(fp_regs.fprs[5].fp.lo),
+	PT_FPR6_HI=pt_off(fp_regs.fprs[6].fp.hi),
+	PT_FPR6_LO=pt_off(fp_regs.fprs[6].fp.lo),
+	PT_FPR7_HI=pt_off(fp_regs.fprs[7].fp.hi),
+	PT_FPR7_LO=pt_off(fp_regs.fprs[7].fp.lo),
+	PT_FPR8_HI=pt_off(fp_regs.fprs[8].fp.hi),
+	PT_FPR8_LO=pt_off(fp_regs.fprs[8].fp.lo),
+	PT_FPR9_HI=pt_off(fp_regs.fprs[9].fp.hi),
+	PT_FPR9_LO=pt_off(fp_regs.fprs[9].fp.lo),
+	PT_FPR10_HI=pt_off(fp_regs.fprs[10].fp.hi),
+	PT_FPR10_LO=pt_off(fp_regs.fprs[10].fp.lo),
+	PT_FPR11_HI=pt_off(fp_regs.fprs[11].fp.hi),
+	PT_FPR11_LO=pt_off(fp_regs.fprs[11].fp.lo),
+	PT_FPR12_HI=pt_off(fp_regs.fprs[12].fp.hi),
+	PT_FPR12_LO=pt_off(fp_regs.fprs[12].fp.lo),
+	PT_FPR13_HI=pt_off(fp_regs.fprs[13].fp.hi),
+	PT_FPR13_LO=pt_off(fp_regs.fprs[13].fp.lo),
+	PT_FPR14_HI=pt_off(fp_regs.fprs[14].fp.hi),
+	PT_FPR14_LO=pt_off(fp_regs.fprs[14].fp.lo),
+	PT_FPR15_HI=pt_off(fp_regs.fprs[15].fp.hi),
+	PT_FPR15_LO=pt_off(fp_regs.fprs[15].fp.lo),
+	PT_CR_9=pt_off(per_info.control_regs.words.cr[0]),
+	PT_CR_10=pt_off(per_info.control_regs.words.cr[1]),
+	PT_CR_11=pt_off(per_info.control_regs.words.cr[2]),
+	PT_LASTOFF=PT_CR_11,
+	PT_ENDREGS=offsetof(user_regs_struct,per_info.lowcore.words.perc_atmid)
+};
+
+#define PTRACE_AREA \
+__u32 len;          \
+addr_t  kernel_addr; \
+addr_t  process_addr;
+
+typedef struct
+{
+	 PTRACE_AREA
+} ptrace_area;
+
+/*
+  390 specific non posix ptrace requests
+  I chose unusual values so they are unlikely to clash with future ptrace definitions.
+ */
+#define PTRACE_PEEKUSR_AREA           0x5000
+#define PTRACE_POKEUSR_AREA           0x5001
+#define PTRACE_PEEKTEXT_AREA	      0x5002
+#define PTRACE_PEEKDATA_AREA	      0x5003
+#define PTRACE_POKETEXT_AREA	      0x5004
+#define PTRACE_POKEDATA_AREA 	      0x5005
+/* PT_PROT definition is loosely based on hppa bsd definition in gdb/hppab-nat.c */
+#define PTRACE_PROT                       21
+
+typedef enum
+{
+	ptprot_set_access_watchpoint,
+	ptprot_set_write_watchpoint,
+	ptprot_disable_watchpoint
+} ptprot_flags;
+
+typedef struct
+{
+	addr_t           lowaddr;
+	addr_t           hiaddr;
+	ptprot_flags     prot;
+} ptprot_area;                     
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/queue.h linux.14p16/include/asm-s390/queue.h
--- linux.vanilla/include/asm-s390/queue.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/queue.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,64 @@
+/*
+ *  include/asm-s390/queue.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *
+ *  A little set of queue utilies.
+ */
+#include <linux/stddef.h>
+
+typedef struct queue
+{
+	struct queue *next;	
+} queue;
+
+typedef struct
+{
+	queue *head;
+	queue *tail;
+} qheader;
+
+static __inline__ void init_queue(qheader *qhead)
+{
+	memset(qhead,0,sizeof(*qhead));
+}
+
+static __inline__ void enqueue_tail(qheader *qhead,queue *member)
+{
+	queue *tail=qhead->tail;
+	member->next=NULL;
+	
+	if(member)
+	{
+		if(tail)
+			tail->next=member;
+		else
+			
+			qhead->head=member;
+		qhead->tail=member;
+		member->next=NULL;
+	}
+} 
+
+static __inline__ queue *dequeue_head(qheader *qhead)
+{
+	queue *head=qhead->head,*next_head;
+
+	if(head)
+	{
+		next_head=head->next;
+		qhead->head=next_head;
+	        if(!next_head)
+			qhead->tail=NULL;
+	}
+	return(head);
+}
+
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/resource.h linux.14p16/include/asm-s390/resource.h
--- linux.vanilla/include/asm-s390/resource.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/resource.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,48 @@
+/*
+ *  include/asm-s390/resource.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/resources.h"
+ */
+
+#ifndef _S390_RESOURCE_H
+#define _S390_RESOURCE_H
+
+/*
+ * Resource limits
+ */
+
+#define RLIMIT_CPU	0		/* CPU time in ms */
+#define RLIMIT_FSIZE	1		/* Maximum filesize */
+#define RLIMIT_DATA	2		/* max data size */
+#define RLIMIT_STACK	3		/* max stack size */
+#define RLIMIT_CORE	4		/* max core file size */
+#define RLIMIT_RSS	5		/* max resident set size */
+#define RLIMIT_NPROC	6		/* max number of processes */
+#define RLIMIT_NOFILE	7		/* max number of open files */
+#define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
+#define RLIMIT_AS	9		/* address space limit */
+
+#define RLIM_NLIMITS	10
+
+#ifdef __KERNEL__
+
+#define INIT_RLIMITS					\
+{							\
+	{ LONG_MAX, LONG_MAX },				\
+	{ LONG_MAX, LONG_MAX },				\
+	{ LONG_MAX, LONG_MAX },				\
+	{ _STK_LIM, LONG_MAX },				\
+	{        0, LONG_MAX },				\
+	{ LONG_MAX, LONG_MAX },				\
+	{ MAX_TASKS_PER_USER, MAX_TASKS_PER_USER },	\
+	{ INR_OPEN, INR_OPEN },                         \
+	{ LONG_MAX, LONG_MAX },				\
+	{ LONG_MAX, LONG_MAX },				\
+}
+
+#endif /* __KERNEL__ */
+
+#endif
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/s390-gdbregs.h linux.14p16/include/asm-s390/s390-gdbregs.h
--- linux.vanilla/include/asm-s390/s390-gdbregs.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/s390-gdbregs.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,84 @@
+/*
+ *  include/asm-s390/s390-gdbregs.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *
+ *  used both by the linux kernel for remote debugging & gdb 
+ */
+
+/* Say how long (ordinary) registers are.  This is a piece of bogosity
+   used in push_word and a few other places; REGISTER_RAW_SIZE is the
+   real way to know how big a register is.  */
+#ifndef _S390_GDBREGS_H
+#define _S390_GDBREGS_H
+
+#include <asm/s390-regs-common.h>
+#define S390_MAX_INSTR_SIZE 6
+#define NUM_REGS      (2+NUM_GPRS+NUM_ACRS+NUM_CRS+1+NUM_FPRS)
+#define FIRST_ACR     (2+NUM_GPRS)
+#define LAST_ACR      (FIRST_ACR+NUM_ACRS-1)
+#define FIRST_CR      (FIRST_ACR+NUM_ACRS)
+#define LAST_CR       (FIRST_CR+NUM_CRS-1)
+
+#define PSWM_REGNUM    0
+#define PC_REGNUM      1
+#define	GP0_REGNUM     2		    /* GPR register 0 */ 
+#define GP_LAST_REGNUM (GP0_REGNUM+NUM_GPRS-1)
+#define RETADDR_REGNUM (GP0_REGNUM+14)                   /* Usually return address */
+#define SP_REGNUM      (GP0_REGNUM+15)	    /* Contains address of top of stack */
+#define FP_REGNUM     SP_REGNUM /* needed in findvar.c still */
+#define FRAME_REGNUM  (GP0_REGNUM+11)
+#define FPC_REGNUM    (GP0_REGNUM+NUM_GPRS+NUM_ACRS+NUM_CRS)
+#define FP0_REGNUM    (FPC_REGNUM+1) /* FPR (Floating point) register 0 */
+#define FPLAST_REGNUM (FP0_REGNUM+NUM_FPRS-1)	/* Last floating point register */
+
+/* The top of this structure is as similar as possible to a pt_regs structure to */
+/* simplify code */
+typedef struct
+{
+	S390_REGS_COMMON
+	__u32         crs[NUM_CRS];
+	s390_fp_regs  fp_regs;
+} s390_gdb_regs __attribute__((packed));
+
+#define REGISTER_NAMES                                           \
+{                                                                \
+"pswm","pswa",                                                   \
+"gpr0","gpr1","gpr2","gpr3","gpr4","gpr5","gpr6","gpr7",         \
+"gpr8","gpr9","gpr10","gpr11","gpr12","gpr13","gpr14","gpr15",   \
+"acr0","acr1","acr2","acr3","acr4","acr5","acr6","acr7",         \
+"acr8","acr9","acr10","acr11","acr12","acr13","acr14","acr15",   \
+"cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7",                 \
+"cr8","cr9","cr10","cr11","cr12","cr13","cr14","cr15",           \
+"fpc",                                                           \
+"fpr0","fpr1","fpr2","fpr3","fpr4","fpr5","fpr6","fpr7",         \
+"fpr8","fpr9","fpr10","fpr11","fpr12","fpr13","fpr14","fpr15"    \
+}
+
+/* Index within `registers' of the first byte of the space for
+   register N.  */
+
+#define FP0_OFFSET ((PSW_MASK_SIZE+PSW_ADDR_SIZE)+ \
+(GPR_SIZE*NUM_GPRS)+(ACR_SIZE+NUM_ACRS)+ \
+(CR_SIZE*NUM_CRS)+(FPC_SIZE+FPC_PAD_SIZE))
+
+#define REGISTER_BYTES    \
+((FP0_OFFSET)+(FPR_SIZE*NUM_FPRS))
+
+#define REGISTER_BYTE(N)  ((N) < FP0_REGNUM ? (N)*4:(FP0_OFFSET+((N)-FP0_REGNUM)*FPR_SIZE))
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/s390-regs-common.h linux.14p16/include/asm-s390/s390-regs-common.h
--- linux.vanilla/include/asm-s390/s390-regs-common.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/s390-regs-common.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,99 @@
+/*
+ *  include/asm-s390/s390-regs-common.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *
+ *  this file is designed to keep as much compatibility between
+ *  gdb's representation of registers & the kernels representation of registers
+ *  as possible so as to minimise translation between gdb registers &
+ *  kernel registers please keep this matched with gdb & strace 
+ */
+
+#ifndef _S390_REGS_COMMON_H
+#define _S390_REGS_COMMON_H
+#ifndef __ASSEMBLY__
+#include <asm/types.h>
+#endif
+
+#define REGISTER_SIZE 4
+#define NUM_GPRS      16
+#define GPR_SIZE      4
+#define PSW_MASK_SIZE 4
+#define PSW_ADDR_SIZE 4
+#define NUM_FPRS      16
+#define FPR_SIZE      8
+#define FPC_SIZE      4
+#define FPC_PAD_SIZE  4 /* gcc insists on aligning the fpregs */
+#define NUM_CRS       16
+#define CR_SIZE       4
+#define NUM_ACRS      16
+#define ACR_SIZE      4
+
+#define STACK_FRAME_OVERHEAD    96      /* size of minimum stack frame */
+
+#ifndef __ASSEMBLY__
+/* this typedef defines how a Program Status Word looks like */
+typedef struct 
+{
+        __u32   mask;
+        __u32   addr;
+} psw_t __attribute__ ((aligned(8)));
+
+/* 2 __u32's are used for floats instead to compile  with a __STRICT_ANSI__ defined */ 
+typedef union
+{
+#ifdef __KERNEL__ 
+	__u64   d; /* mathemu.h gets upset otherwise */
+#else
+	double  d; /* ansi c dosen't like long longs & make sure that */
+	/* alignments are identical for both compiles */ 
+#endif
+       struct
+       {
+	       __u32 hi;
+	       __u32 lo;
+       } fp;
+       __u32    f; 
+} freg_t;
+
+typedef struct
+{
+/*
+  The compiler appears to like aligning freg_t on an 8 byte boundary
+  so I always access fpregs, this was causing fun when I was doing
+  coersions.
+ */
+	__u32   fpc;
+	freg_t  fprs[NUM_FPRS];              
+} s390_fp_regs;
+
+/*
+  gdb structures & the kernel have this much always in common
+ */
+#define S390_REGS_COMMON       \
+psw_t psw;                     \
+__u32 gprs[NUM_GPRS];          \
+__u32  acrs[NUM_ACRS];         \
+
+typedef struct
+{
+	S390_REGS_COMMON
+} s390_regs_common;
+
+
+/* Sequence of bytes for breakpoint illegal instruction.  */
+#define BREAKPOINT {0x0,0x1}
+#define BREAKPOINT_U16 ((__u16)0x0001)
+#endif
+#endif
+
+
+
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/segment.h linux.14p16/include/asm-s390/segment.h
--- linux.vanilla/include/asm-s390/segment.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/segment.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,4 @@
+#ifndef _ASM_SEGMENT_H
+#define _ASM_SEGMENT_H
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/semaphore-helper.h linux.14p16/include/asm-s390/semaphore-helper.h
--- linux.vanilla/include/asm-s390/semaphore-helper.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/semaphore-helper.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,100 @@
+/*
+ *  include/asm-s390/semaphore-helper.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *
+ *  Derived from "include/asm-i386/semaphore-helper.h"
+ *    (C) Copyright 1996 Linus Torvalds
+ *    (C) Copyright 1999 Andrea Arcangeli
+ */
+
+#ifndef _S390_SEMAPHORE_HELPER_H
+#define _S390_SEMAPHORE_HELPER_H
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ *
+ * This is trivially done with load_locked/store_cond,
+ * but on the x86 we need an external synchronizer.
+ */
+static inline void wake_one_more(struct semaphore * sem)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	sem->waking++;
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+}
+
+static inline int waking_non_zero(struct semaphore *sem)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (sem->waking > 0) {
+		sem->waking--;
+		ret = 1;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+	return ret;
+}
+
+/*
+ * waking_non_zero_interruptible:
+ *	1	got the lock
+ *	0	go to sleep
+ *	-EINTR	interrupted
+ *
+ * If we give up we must undo our count-decrease we previously did in down().
+ * Subtle: up() can continue to happens and increase the semaphore count
+ * even during our critical section protected by the spinlock. So
+ * we must remeber to undo the sem->waking that will be run from
+ * wake_one_more() some time soon, if the semaphore count become > 0.
+ */
+static inline int waking_non_zero_interruptible(struct semaphore *sem,
+						struct task_struct *tsk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (sem->waking > 0) {
+		sem->waking--;
+		ret = 1;
+	} else if (signal_pending(tsk)) {
+               if (atomic_inc_and_test_greater_zero(&sem->count))
+                       sem->waking--;
+		ret = -EINTR;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+	return ret;
+}
+
+/*
+ * waking_non_zero_trylock:
+ *	1	failed to lock
+ *	0	got the lock
+ *
+ * Implementation details are the same of the interruptible case.
+ */
+static inline int waking_non_zero_trylock(struct semaphore *sem)
+{
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (sem->waking <= 0)
+        {
+                if (atomic_inc_and_test_greater_zero(&sem->count))
+                        sem->waking--;
+        } else {
+		sem->waking--;
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+	return ret;
+}
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/semaphore.h linux.14p16/include/asm-s390/semaphore.h
--- linux.vanilla/include/asm-s390/semaphore.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/semaphore.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,73 @@
+/*
+ *  include/asm-s390/semaphore.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *
+ *  Derived from "include/asm-i386/semaphore.h"
+ *    (C) Copyright 1996 Linus Torvalds
+ */
+
+#ifndef _S390_SEMAPHORE_H
+#define _S390_SEMAPHORE_H
+
+#include <linux/linkage.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/spinlock.h>
+
+struct semaphore {
+        atomic_t count;
+        int waking;
+        struct wait_queue * wait;
+};
+
+#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), 0, NULL })
+#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), 0, NULL })
+
+asmlinkage void __down_failed(void /* special register calling convention */);
+asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
+asmlinkage int  __down_failed_trylock(void  /* params in registers */);
+asmlinkage void __up_wakeup(void /* special register calling convention */);
+
+asmlinkage void __down(struct semaphore * sem);
+asmlinkage int  __down_interruptible(struct semaphore * sem);
+asmlinkage int  __down_trylock(struct semaphore * sem);
+asmlinkage void __up(struct semaphore * sem);
+
+extern spinlock_t semaphore_wake_lock;
+
+#define sema_init(sem, val)     atomic_set(&((sem)->count), (val))
+
+extern inline void down(struct semaphore * sem)
+{
+	if (atomic_dec_return(&sem->count) < 0)
+		__down(sem);
+}
+
+extern inline int down_interruptible(struct semaphore * sem)
+{
+	int ret = 0;
+
+	if (atomic_dec_return(&sem->count) < 0)
+		ret = __down_interruptible(sem);
+	return ret;
+}
+
+extern inline int down_trylock(struct semaphore * sem)
+{
+        int ret = 0;
+
+        if (atomic_dec_return(&sem->count) < 0)
+                ret = __down_trylock(sem);
+        return ret;
+}
+
+extern inline void up(struct semaphore * sem)
+{
+	if (atomic_inc_return(&sem->count) <= 0)
+		__up(sem);
+}
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/setup.h linux.14p16/include/asm-s390/setup.h
--- linux.vanilla/include/asm-s390/setup.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/setup.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,51 @@
+/*
+ *  include/asm-s390/setup.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ */
+
+#ifndef _ASM_S390_SETUP_H
+#define _ASM_S390_SETUP_H
+
+#define PARMAREA 0x10400
+
+#ifndef __ASSEMBLER__
+
+#define ORIG_ROOT_DEV     (*(unsigned long *) (0x10400))
+#define MOUNT_ROOT_RDONLY (*(unsigned short *) (0x10404))
+#define MEMORY_SIZE       (*(unsigned long *)  (0x10406))
+#define MACHINE_FLAGS     (*(unsigned long *)  (0x1040a))
+#define INITRD_START      (*(unsigned long *)  (0x1040e))
+#define INITRD_SIZE       (*(unsigned long *)  (0x10412))
+#define RAMDISK_FLAGS     (*(unsigned short *) (0x10416))
+#define COMMAND_LINE      ((char *)            (0x10480))
+
+#else 
+
+#define ORIG_ROOT_DEV     0x10400
+#define MOUNT_ROOT_RDONLY 0x10404
+#define MEMORY_SIZE       0x10406
+#define MACHINE_FLAGS     0x1040a
+#define INITRD_START      0x1040e
+#define INITRD_SIZE       0x10412
+#define RAMDISK_FLAGS     0x10416
+#define COMMAND_LINE      0x10480
+
+#endif
+
+#define COMMAND_LINE_SIZE 896
+/*
+ * Machine features detected in head.S
+ */
+#define MACHINE_IS_VM    (MACHINE_FLAGS & 1)
+#define MACHINE_HAS_IEEE (MACHINE_FLAGS & 2)
+
+#define RAMDISK_ORIGIN            0x800000
+#define RAMDISK_BLKSIZE           0x1000
+#define RAMDISK_IMAGE_START_MASK  0x07FF
+#define RAMDISK_PROMPT_FLAG       0x8000
+#define RAMDISK_LOAD_FLAG         0x4000
+
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/shmparam.h linux.14p16/include/asm-s390/shmparam.h
--- linux.vanilla/include/asm-s390/shmparam.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/shmparam.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,53 @@
+/*
+ *  include/asm-s390/shmparam.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/shmparam.h"
+ */
+#ifndef _ASM_S390_SHMPARAM_H
+#define _ASM_S390_SHMPARAM_H
+
+/* address range for shared memory attaches if no address passed to shmat() */
+#define SHM_RANGE_START	0x50000000
+#define SHM_RANGE_END	0x60000000
+
+/*
+ * Format of a swap-entry for shared memory pages currently out in
+ * swap space (see also mm/swap.c).
+ *
+ * SWP_TYPE = SHM_SWP_TYPE
+ * SWP_OFFSET is used as follows:
+ *
+ *  bits 0..6 : id of shared memory segment page belongs to (SHM_ID)
+ *  bits 7..21: index of page within shared memory segment (SHM_IDX)
+ *		(actually fewer bits get used since SHMMAX is so low)
+ */
+
+/*
+ * Keep _SHM_ID_BITS as low as possible since SHMMNI depends on it and
+ * there is a static array of size SHMMNI.
+ */
+#define _SHM_ID_BITS	7
+#define SHM_ID_MASK	((1<<_SHM_ID_BITS)-1)
+
+#define SHM_IDX_SHIFT	(_SHM_ID_BITS)
+#define _SHM_IDX_BITS	15
+#define SHM_IDX_MASK	((1<<_SHM_IDX_BITS)-1)
+
+/*
+ * _SHM_ID_BITS + _SHM_IDX_BITS must be <= 24 on the i386 and
+ * SHMMAX <= (PAGE_SIZE << _SHM_IDX_BITS).
+ */
+
+#define SHMMAX 0x2000000		/* max shared seg size (bytes) */
+/* Try not to change the default shipped SHMMAX - people rely on it */
+
+#define SHMMIN 1 /* really PAGE_SIZE */	/* min shared seg size (bytes) */
+#define SHMMNI (1<<_SHM_ID_BITS)	/* max num of segs system wide */
+#define SHMALL				/* max shm system wide (pages) */ \
+	(1<<(_SHM_IDX_BITS+_SHM_ID_BITS))
+#define	SHMLBA PAGE_SIZE		/* attach addr a multiple of this */
+#define SHMSEG SHMMNI			/* max shared segs per process */
+
+#endif /* _ASM_S390_SHMPARAM_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/sigcontext.h linux.14p16/include/asm-s390/sigcontext.h
--- linux.vanilla/include/asm-s390/sigcontext.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/sigcontext.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,30 @@
+/*
+ *  include/asm-s390/sigcontext.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ */
+
+#ifndef _ASM_S390_SIGCONTEXT_H
+#define _ASM_S390_SIGCONTEXT_H
+
+#include <asm/ptrace.h>
+
+
+/*
+  Has to be at least _NSIG_WORDS from asm/signal.h
+ */
+#define _SIGCONTEXT_NSIG      64
+#define _SIGCONTEXT_NSIG_BPW  32
+/* Size of stack frame allocated when calling signal handler. */
+#define __SIGNAL_FRAMESIZE      STACK_FRAME_OVERHEAD
+#define _SIGCONTEXT_NSIG_WORDS  (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
+#define SIGMASK_COPY_SIZE       (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
+struct sigcontext_struct {
+	int		signal;
+	unsigned long	handler;
+	user_regs_struct *regs;
+	unsigned long	oldmask[_SIGCONTEXT_NSIG_WORDS];
+};
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/siginfo.h linux.14p16/include/asm-s390/siginfo.h
--- linux.vanilla/include/asm-s390/siginfo.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/siginfo.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,205 @@
+/*
+ *  include/asm-s390/siginfo.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/siginfo.h"
+ */
+
+#ifndef _S390_SIGINFO_H
+#define _S390_SIGINFO_H
+
+#include <linux/types.h>
+
+/* XXX: This structure was copied from the Alpha; is there an iBCS version?  */
+
+typedef union sigval {
+	int sival_int;
+	void *sival_ptr;
+} sigval_t;
+
+#define SI_MAX_SIZE	128
+#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
+
+typedef struct siginfo {
+	int si_signo;
+	int si_errno;
+	int si_code;
+
+	union {
+		int _pad[SI_PAD_SIZE];
+
+		/* kill() */
+		struct {
+			pid_t _pid;		/* sender's pid */
+			uid_t _uid;		/* sender's uid */
+		} _kill;
+
+		/* POSIX.1b timers */
+		struct {
+			unsigned int _timer1;
+			unsigned int _timer2;
+		} _timer;
+
+		/* POSIX.1b signals */
+		struct {
+			pid_t _pid;		/* sender's pid */
+			uid_t _uid;		/* sender's uid */
+			sigval_t _sigval;
+		} _rt;
+
+		/* SIGCHLD */
+		struct {
+			pid_t _pid;		/* which child */
+			uid_t _uid;		/* sender's uid */
+			int _status;		/* exit code */
+			clock_t _utime;
+			clock_t _stime;
+		} _sigchld;
+
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		struct {
+			void *_addr; /* faulting insn/memory ref. */
+		} _sigfault;
+
+		/* SIGPOLL */
+		struct {
+			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			int _fd;
+		} _sigpoll;
+	} _sifields;
+} siginfo_t;
+
+/*
+ * How these fields are to be accessed.
+ */
+#define si_pid		_sifields._kill._pid
+#define si_uid		_sifields._kill._uid
+#define si_status	_sifields._sigchld._status
+#define si_utime	_sifields._sigchld._utime
+#define si_stime	_sifields._sigchld._stime
+#define si_value	_sifields._rt._sigval
+#define si_int		_sifields._rt._sigval.sival_int
+#define si_ptr		_sifields._rt._sigval.sival_ptr
+#define si_addr		_sifields._sigfault._addr
+#define si_band		_sifields._sigpoll._band
+#define si_fd		_sifields._sigpoll._fd
+
+/*
+ * si_code values
+ * Digital reserves positive values for kernel-generated signals.
+ */
+#define SI_USER		0	/* sent by kill, sigsend, raise */
+#define SI_KERNEL	0x80	/* sent by the kernel from somewhere */
+#define SI_QUEUE	-1	/* sent by sigqueue */
+#define SI_TIMER	-2	/* sent by timer expiration */
+#define SI_MESGQ	-3	/* sent by real time mesq state change */
+#define SI_ASYNCIO	-4	/* sent by AIO completion */
+#define SI_SIGIO	-5	/* sent by queued SIGIO */
+
+#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
+#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
+
+/*
+ * SIGILL si_codes
+ */
+#define ILL_ILLOPC	1	/* illegal opcode */
+#define ILL_ILLOPN	2	/* illegal operand */
+#define ILL_ILLADR	3	/* illegal addressing mode */
+#define ILL_ILLTRP	4	/* illegal trap */
+#define ILL_PRVOPC	5	/* privileged opcode */
+#define ILL_PRVREG	6	/* privileged register */
+#define ILL_COPROC	7	/* coprocessor error */
+#define ILL_BADSTK	8	/* internal stack error */
+#define NSIGILL		8
+
+/*
+ * SIGFPE si_codes
+ */
+#define FPE_INTDIV	1	/* integer divide by zero */
+#define FPE_INTOVF	2	/* integer overflow */
+#define FPE_FLTDIV	3	/* floating point divide by zero */
+#define FPE_FLTOVF	4	/* floating point overflow */
+#define FPE_FLTUND	5	/* floating point underflow */
+#define FPE_FLTRES	6	/* floating point inexact result */
+#define FPE_FLTINV	7	/* floating point invalid operation */
+#define FPE_FLTSUB	8	/* subscript out of range */
+#define NSIGFPE		8
+
+/*
+ * SIGSEGV si_codes
+ */
+#define SEGV_MAPERR	1	/* address not mapped to object */
+#define SEGV_ACCERR	2	/* invalid permissions for mapped object */
+#define NSIGSEGV	2
+
+/*
+ * SIGBUS si_codes
+ */
+#define BUS_ADRALN	1	/* invalid address alignment */
+#define BUS_ADRERR	2	/* non-existant physical address */
+#define BUS_OBJERR	3	/* object specific hardware error */
+#define NSIGBUS		3
+
+/*
+ * SIGTRAP si_codes
+ */
+#define TRAP_BRKPT	1	/* process breakpoint */
+#define TRAP_TRACE	2	/* process trace trap */
+#define NSIGTRAP	2
+
+/*
+ * SIGCHLD si_codes
+ */
+#define CLD_EXITED	1	/* child has exited */
+#define CLD_KILLED	2	/* child was killed */
+#define CLD_DUMPED	3	/* child terminated abnormally */
+#define CLD_TRAPPED	4	/* traced child has trapped */
+#define CLD_STOPPED	5	/* child has stopped */
+#define CLD_CONTINUED	6	/* stopped child has continued */
+#define NSIGCHLD
+
+/*
+ * SIGPOLL si_codes
+ */
+#define POLL_IN		1	/* data input available */
+#define POLL_OUT	2	/* output buffers available */
+#define POLL_MSG	3	/* input message available */
+#define POLL_ERR	4	/* i/o error */
+#define POLL_PRI	5	/* high priority input available */
+#define POLL_HUP	6	/* device disconnected */
+#define NSIGPOLL	6
+
+/*
+ * sigevent definitions
+ * 
+ * It seems likely that SIGEV_THREAD will have to be handled from 
+ * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
+ * thread manager then catches and does the appropriate nonsense.
+ * However, everything is written out here so as to not get lost.
+ */
+#define SIGEV_SIGNAL	0	/* notify via signal */
+#define SIGEV_NONE	1	/* other notification: meaningless */
+#define SIGEV_THREAD	2	/* deliver via thread creation */
+
+#define SIGEV_MAX_SIZE	64
+#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
+
+typedef struct sigevent {
+	sigval_t sigev_value;
+	int sigev_signo;
+	int sigev_notify;
+	union {
+		int _pad[SIGEV_PAD_SIZE];
+
+		struct {
+			void (*_function)(sigval_t);
+			void *_attribute;	/* really pthread_attr_t */
+		} _sigev_thread;
+	} _sigev_un;
+} sigevent_t;
+
+#define sigev_notify_function	_sigev_un._sigev_thread._function
+#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/signal.h linux.14p16/include/asm-s390/signal.h
--- linux.vanilla/include/asm-s390/signal.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/signal.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,185 @@
+/*
+ *  include/asm-s390/signal.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/signal.h"
+ */
+
+#ifndef _ASMS390_SIGNAL_H
+#define _ASMS390_SIGNAL_H
+
+#include <linux/types.h>
+
+/* Avoid too many header ordering problems.  */
+struct siginfo;
+
+#ifdef __KERNEL__
+/* Most things should be clean enough to redefine this at will, if care
+   is taken to make libc match.  */
+#include <asm/sigcontext.h>
+#define _NSIG           _SIGCONTEXT_NSIG
+#define _NSIG_BPW       _SIGCONTEXT_NSIG_BPW
+#define _NSIG_WORDS     _SIGCONTEXT_NSIG_WORDS
+
+typedef unsigned long old_sigset_t;             /* at least 32 bits */
+
+typedef struct {
+        unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+#else
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+#define NSIG            32
+typedef unsigned long sigset_t;
+
+#endif /* __KERNEL__ */
+
+#define SIGHUP           1
+#define SIGINT           2
+#define SIGQUIT          3
+#define SIGILL           4
+#define SIGTRAP          5
+#define SIGABRT          6
+#define SIGIOT           6
+#define SIGBUS           7
+#define SIGFPE           8
+#define SIGKILL          9
+#define SIGUSR1         10
+#define SIGSEGV         11
+#define SIGUSR2         12
+#define SIGPIPE         13
+#define SIGALRM         14
+#define SIGTERM         15
+#define SIGSTKFLT       16
+#define SIGCHLD         17
+#define SIGCONT         18
+#define SIGSTOP         19
+#define SIGTSTP         20
+#define SIGTTIN         21
+#define SIGTTOU         22
+#define SIGURG          23
+#define SIGXCPU         24
+#define SIGXFSZ         25
+#define SIGVTALRM       26
+#define SIGPROF         27
+#define SIGWINCH        28
+#define SIGIO           29
+#define SIGPOLL         SIGIO
+/*
+#define SIGLOST         29
+*/
+#define SIGPWR          30
+#define SIGUNUSED       31
+
+/* These should not be considered constants from userland.  */
+#define SIGRTMIN        32
+#define SIGRTMAX        (_NSIG-1)
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP    0x00000001
+#define SA_NOCLDWAIT    0x00000002 /* not supported yet */
+#define SA_SIGINFO      0x00000004
+#define SA_ONSTACK      0x08000000
+#define SA_RESTART      0x10000000
+#define SA_NODEFER      0x40000000
+#define SA_RESETHAND    0x80000000
+
+#define SA_NOMASK       SA_NODEFER
+#define SA_ONESHOT      SA_RESETHAND
+#define SA_INTERRUPT    0x20000000 /* dummy -- ignored */
+
+#define SA_RESTORER     0x04000000
+
+/*
+ * sigaltstack controls
+ */
+#define SS_ONSTACK      1
+#define SS_DISABLE      2
+
+#define MINSIGSTKSZ     2048
+#define SIGSTKSZ        8192
+
+#ifdef __KERNEL__
+
+/*
+ * These values of sa_flags are used only by the kernel as part of the
+ * irq handling routines.
+ *
+ * SA_INTERRUPT is also used by the irq handling routines.
+ * SA_SHIRQ is for shared interrupt support on PCI and EISA.
+ */
+#define SA_PROBE                SA_ONESHOT
+#define SA_SAMPLE_RANDOM        SA_RESTART
+#define SA_SHIRQ                0x04000000
+#endif
+
+#define SIG_BLOCK          0    /* for blocking signals */
+#define SIG_UNBLOCK        1    /* for unblocking signals */
+#define SIG_SETMASK        2    /* for setting the signal mask */
+
+/* Type of a signal handler.  */
+typedef void (*__sighandler_t)(int);
+
+#define SIG_DFL ((__sighandler_t)0)     /* default signal handling */
+#define SIG_IGN ((__sighandler_t)1)     /* ignore signal */
+#define SIG_ERR ((__sighandler_t)-1)    /* error return from signal */
+
+#ifdef __KERNEL__
+struct old_sigaction {
+        __sighandler_t sa_handler;
+        old_sigset_t sa_mask;
+        unsigned long sa_flags;
+        void (*sa_restorer)(void);
+};
+
+struct sigaction {
+        __sighandler_t sa_handler;
+        unsigned long sa_flags;
+        void (*sa_restorer)(void);
+        sigset_t sa_mask;               /* mask last for extensibility */
+};
+
+struct k_sigaction {
+        struct sigaction sa;
+};
+#else
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+struct sigaction {
+        union {
+          __sighandler_t _sa_handler;
+          void (*_sa_sigaction)(int, struct siginfo *, void *);
+        } _u;
+        sigset_t sa_mask;
+        unsigned long sa_flags;
+        void (*sa_restorer)(void);
+};
+
+#define sa_handler      _u._sa_handler
+#define sa_sigaction    _u._sa_sigaction
+
+#endif /* __KERNEL__ */
+
+typedef struct sigaltstack {
+        void *ss_sp;
+        int ss_flags;
+        size_t ss_size;
+} stack_t;
+
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/sigp.h linux.14p16/include/asm-s390/sigp.h
--- linux.vanilla/include/asm-s390/sigp.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/sigp.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,254 @@
+/*
+ *  include/asm-s390/sigp.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *               Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *  sigp.h by D.J. Barrow (c) IBM 1999
+ *  contains routines / structures for signalling other S/390 processors in an
+ *  SMP configuration.
+ */
+
+#ifndef __SIGP__
+#define __SIGP__
+
+#include <asm/ptrace.h>
+#include <asm/misc390.h>
+#include <asm/atomic.h>
+
+/* get real cpu address from logical cpu number */
+extern volatile int __cpu_logical_map[];
+
+typedef enum
+{
+	sigp_unassigned=0x0,
+	sigp_sense,
+	sigp_external_call,
+	sigp_emergency_signal,
+	sigp_start,
+	sigp_stop,
+	sigp_restart,
+	sigp_unassigned1,
+	sigp_unassigned2,
+	sigp_stop_and_store_status,
+	sigp_unassigned3,
+	sigp_initial_cpu_reset,
+	sigp_cpu_reset,
+	sigp_set_prefix,
+	sigp_store_status_at_address,
+	sigp_store_extended_status_at_address
+} sigp_order_code;
+
+#if 0
+/*
+ * these definitions are not used at the moment, but we might need
+ * them in future.
+ */
+typedef struct
+{
+        __u64   cpu_timer;
+        psw_t   current_psw;
+        __u32   prefix;
+        __u32   access_regs[16];
+        __u64   float_regs[4];
+        __u32   gpr_regs[16];
+        __u32   control_regs[16];
+} sigp_status __attribute__((packed));
+
+typedef struct
+{
+        __u8    unused1[216];
+        __u64   cpu_timer;
+        psw_t   current_psw;
+        __u32   prefix;
+        __u32   access_regs[16];
+        __u64   float_regs[4];
+        __u32   gpr_regs[16];
+        __u32   control_regs[16];
+} sigp_status_512 __attribute__((packed));
+
+typedef struct
+{
+        __u32   extended_save_area_address;
+        __u64   cpu_timer;
+        psw_t   current_psw;
+        __u32   prefix;
+        __u32   access_regs[16];
+        __u64   float_regs[4];
+        __u32   gpr_regs[16];
+        __u32   control_regs[16];
+} sigp_extended_status __attribute__((packed));
+
+typedef struct
+{
+        __u8    unused1[212];
+        __u32   extended_save_area_address;
+        __u64   cpu_timer;
+        psw_t   current_psw;
+        __u32   prefix;
+        __u32   access_regs[16];
+        __u64   float_regs[4];
+        __u32   gpr_regs[16];
+        __u32   control_regs[16];
+} sigp_extended_status_512 __attribute__((packed));
+
+typedef struct
+{
+	__u64   bfp_float_regs[16];
+	__u32   bfp_float_control_reg;
+	__u8    reserved[12];                     
+} sigp_extended_save_area __attribute__ ((packed));
+
+typedef struct
+{
+	unsigned equipment_check:1;
+	unsigned unassigned1:20;
+	unsigned incorrect_state:1;
+	unsigned invalid_parameter:1;
+	unsigned external_call_pending:1;
+	unsigned stopped:1;
+	unsigned operator_intervening:1;
+	unsigned check_stop:1;
+	unsigned unassigned2:1;
+	unsigned inoperative:1;
+	unsigned invalid_order:1;
+	unsigned receiver_check:1;
+} sigp_status_bits __attribute__((packed));
+#endif
+
+typedef __u32 sigp_status_word;
+
+typedef enum
+{
+        sigp_order_code_accepted=0,
+	sigp_status_stored,
+	sigp_busy,
+	sigp_not_operational
+} sigp_ccode;
+
+
+/*
+ * Definitions for the external call
+ */
+
+/* 'Bit' signals, asynchronous */
+typedef enum
+{
+	ec_schedule=0,
+        ec_restart,
+        ec_halt,
+        ec_power_off,
+	ec_bit_last
+} ec_bit_sig;
+
+/* Signals which come with a parameter area, synchronous */
+typedef enum
+{
+	ec_set_ctl,
+	ec_get_ctl,
+	ec_set_ctl_masked,
+        ec_cmd_last
+} ec_cmd_sig;
+
+/* state information for synchronous signals */
+typedef enum
+{
+	ec_pending,
+	ec_executing,
+	ec_done
+} ec_state;
+
+/* header for the queuing of signals with a parameter area */
+typedef struct ec_ext_call
+{
+	ec_cmd_sig cmd;
+	atomic_t status;
+	struct ec_ext_call *next;
+	void *parms;
+} ec_ext_call;
+
+/* parameter area for the ec_set_ctl and ec_get_ctl signal */
+typedef struct
+{
+	__u16 start_ctl;
+	__u16 end_ctl;
+	__u32 cregs[16];
+} ec_creg_parms;
+
+/* parameter area for the ec_set_ctl_masked signal */
+typedef struct
+{
+	__u16 start_ctl;
+	__u16 end_ctl;
+	__u32 orvals[16];
+	__u32 andvals[16];
+} ec_creg_mask_parms;
+
+/*
+ * Signal processor
+ */
+extern __inline__ sigp_ccode
+signal_processor(__u16 cpu_addr, sigp_order_code order_code)
+{
+	sigp_ccode ccode;
+
+	__asm__ __volatile__(
+		"    sr     1,1\n"        /* parameter=0 in gpr 1 */
+		"    sigp   1,%1,0(%2)\n"
+		"    ipm    %0\n"
+		"    srl    %0,28\n"
+		: "=d" (ccode)
+		: "d" (__cpu_logical_map[cpu_addr]), "a" (order_code)
+		: "cc" , "memory", "1" );
+	return ccode;
+}
+
+/*
+ * Signal processor with parameter
+ */
+extern __inline__ sigp_ccode
+signal_processor_p(__u32 parameter,__u16 cpu_addr,sigp_order_code order_code)
+{
+	sigp_ccode ccode;
+	
+	__asm__ __volatile__(
+		"    lr     1,%1\n"       /* parameter in gpr 1 */
+		"    sigp   1,%2,0(%3)\n"
+		"    ipm    %0\n"
+		"    srl    %0,28\n"
+		: "=d" (ccode)
+		: "d" (parameter), "d" (__cpu_logical_map[cpu_addr]),
+                  "a" (order_code)
+		: "cc" , "memory", "1" );
+	return ccode;
+}
+
+/*
+ * Signal processor with parameter and return status
+ */
+extern __inline__ sigp_ccode
+signal_processor_ps(__u32 *statusptr, __u32 parameter,
+		    __u16 cpu_addr, sigp_order_code order_code)
+{
+	sigp_ccode ccode;
+	
+	__asm__ __volatile__(
+		"    sr     2,2\n"        /* clear status so it doesn't contain rubbish if not saved. */
+		"    lr     3,%2\n"       /* parameter in gpr 3 */
+		"    sigp   2,%3,0(%4)\n"
+		"    st     2,%1\n"
+		"    ipm    %0\n"
+		"    srl    %0,28\n"
+		: "=d" (ccode), "=m" (*statusptr)
+		: "d" (parameter), "d" (__cpu_logical_map[cpu_addr]),
+                  "a" (order_code)
+		: "cc" , "memory", "2" , "3"
+		);
+   return ccode;
+}
+
+#endif __SIGP__
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/smp.h linux.14p16/include/asm-s390/smp.h
--- linux.vanilla/include/asm-s390/smp.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/smp.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,69 @@
+/*
+ *  include/asm-s390/smp.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *               Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+#ifndef __ASM_SMP_H
+#define __ASM_SMP_H
+#ifdef __SMP__
+#ifndef __ASSEMBLY__
+
+#include <asm/lowcore.h>
+#include <linux/tasks.h>    // FOR NR_CPUS definition only.
+#include <linux/kernel.h>   // FOR FASTCALL definition
+
+#define smp_processor_id() (current->processor)
+#define NO_PROC_ID		0xFF		/* No processor magic marker */
+
+/*
+ *	This magic constant controls our willingness to transfer
+ *	a process across CPUs. Such a transfer incurs misses on the L1
+ *	cache, and on a P6 or P5 with multiple L2 caches L2 hits. My
+ *	gut feeling is this will vary by board in value. For a board
+ *	with separate L2 cache it probably depends also on the RSS, and
+ *	for a board with shared L2 cache it ought to decay fast as other
+ *	processes are run.
+ */
+ 
+#define PROC_CHANGE_PENALTY	20		/* Schedule penalty */
+
+extern volatile int cpu_number_map[NR_CPUS]; // used by sched.h
+extern unsigned long ipi_count;
+extern void count_cpus(void);
+
+extern __inline__ __u16 hard_smp_processor_id(void)
+{
+        __u16 cpu_address;
+ 
+        __asm__ ("stap %0\n" : "=m" (cpu_address));
+        return cpu_address;
+}
+
+#define cpu_logical_map(cpu) (cpu)
+
+void smp_local_timer_interrupt(struct pt_regs * regs);
+
+/*
+  s390 specific smp.c headers
+ */
+typedef struct
+{
+	int        intresting;
+	sigp_ccode ccode; 
+	__u32      status;
+	__u16      cpu;
+} sigp_info;
+
+sigp_ccode smp_ext_call_sync(int cpu, ec_cmd_sig cmd,void *parms);
+sigp_ccode smp_ext_call_async(int cpu, ec_bit_sig sig);
+void smp_ext_call_sync_others(ec_cmd_sig cmd, void *parms);
+void smp_ext_call_async_others(ec_bit_sig sig);
+
+int smp_signal_others(sigp_order_code order_code,__u32 parameter,
+                      int spin,sigp_info *info);
+#endif
+#endif
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/smplock.h linux.14p16/include/asm-s390/smplock.h
--- linux.vanilla/include/asm-s390/smplock.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/smplock.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,60 @@
+/*
+ *  include/asm-s390/smplock.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/smplock.h"
+ */
+
+#include <linux/interrupt.h>
+#include <asm/spinlock.h>
+
+extern spinlock_t kernel_flag;
+
+/*
+ * Release global kernel lock and global interrupt lock
+ */
+#define release_kernel_lock(task, cpu)     \
+do {                                       \
+	if (task->lock_depth >= 0)         \
+		spin_unlock(&kernel_flag); \
+	release_irqlock(cpu);              \
+	__sti();                           \
+} while (0)
+
+/*
+ * Re-acquire the kernel lock
+ */
+#define reacquire_kernel_lock(task)        \
+do {                                       \
+	if (task->lock_depth >= 0)         \
+		spin_lock(&kernel_flag);   \
+} while (0)
+
+
+/*
+ * Getting the big kernel lock.
+ *
+ * This cannot happen asynchronously,
+ * so we only need to worry about other
+ * CPU's.
+ */
+/*
+ * Getting the big kernel lock.
+ *
+ * This cannot happen asynchronously,
+ * so we only need to worry about other
+ * CPU's.
+ */
+extern __inline__ void lock_kernel(void)
+{
+        if (!++current->lock_depth)
+                spin_lock(&kernel_flag);
+}
+
+extern __inline__ void unlock_kernel(void)
+{
+        if (--current->lock_depth < 0)
+                spin_unlock(&kernel_flag);
+}
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/socket.h linux.14p16/include/asm-s390/socket.h
--- linux.vanilla/include/asm-s390/socket.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/socket.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,64 @@
+/*
+ *  include/asm-s390/socket.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/socket.h"
+ */
+
+#ifndef _ASM_SOCKET_H
+#define _ASM_SOCKET_H
+
+#include <asm/sockios.h>
+
+/* For setsockoptions(2) */
+#define SOL_SOCKET	1
+
+#define SO_DEBUG	1
+#define SO_REUSEADDR	2
+#define SO_TYPE		3
+#define SO_ERROR	4
+#define SO_DONTROUTE	5
+#define SO_BROADCAST	6
+#define SO_SNDBUF	7
+#define SO_RCVBUF	8
+#define SO_KEEPALIVE	9
+#define SO_OOBINLINE	10
+#define SO_NO_CHECK	11
+#define SO_PRIORITY	12
+#define SO_LINGER	13
+#define SO_BSDCOMPAT	14
+/* To add :#define SO_REUSEPORT 15 */
+#define SO_PASSCRED	16
+#define SO_PEERCRED	17
+#define SO_RCVLOWAT	18
+#define SO_SNDLOWAT	19
+#define SO_RCVTIMEO	20
+#define SO_SNDTIMEO	21
+
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION		22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT	23
+#define SO_SECURITY_ENCRYPTION_NETWORK		24
+
+#ifdef __KERNEL__
+/* Socket types. */
+#define SOCK_STREAM    1               /* stream (connection) socket   */
+#define SOCK_DGRAM     2               /* datagram (conn.less) socket  */
+#define SOCK_RAW       3               /* raw socket                   */
+#define SOCK_RDM       4               /* reliably-delivered message   */
+#define SOCK_SEQPACKET 5               /* sequential packet socket     */
+#define SOCK_PACKET    10              /* linux specific way of        */
+                                       /* getting packets at the dev   */
+                                       /* level.  For writing rarp and */
+                                       /* other similar things on the  */
+                                       /* user level.                  */
+#endif
+
+#define SO_BINDTODEVICE	25
+
+/* Socket filtering */
+#define SO_ATTACH_FILTER        26
+#define SO_DETACH_FILTER        27
+
+#endif /* _ASM_SOCKET_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/sockios.h linux.14p16/include/asm-s390/sockios.h
--- linux.vanilla/include/asm-s390/sockios.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/sockios.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,20 @@
+/*
+ *  include/asm-s390/sockios.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/sockios.h"
+ */
+
+#ifndef __ARCH_S390_SOCKIOS__
+#define __ARCH_S390_SOCKIOS__
+
+/* Socket-level I/O control calls. */
+#define FIOSETOWN 	0x8901
+#define SIOCSPGRP	0x8902
+#define FIOGETOWN	0x8903
+#define SIOCGPGRP	0x8904
+#define SIOCATMARK	0x8905
+#define SIOCGSTAMP	0x8906		/* Get stamp */
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/softirq.h linux.14p16/include/asm-s390/softirq.h
--- linux.vanilla/include/asm-s390/softirq.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/softirq.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,149 @@
+/*
+ *  include/asm-s390/softirq.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/softirq.h"
+ */
+
+#ifndef __ASM_SOFTIRQ_H
+#define __ASM_SOFTIRQ_H
+
+#ifndef __LINUX_SMP_H
+#include <linux/smp.h>
+#endif
+
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+#include <asm/lowcore.h>
+
+#define get_active_bhs()        (bh_mask & bh_active)
+#define clear_active_bhs(x)     atomic_clear_mask((x),(atomic_t*) &bh_active)
+
+#ifdef __SMP__
+
+/*
+ * The locking mechanism for base handlers, to prevent re-entrancy,
+ * is entirely private to an implementation, it should not be
+ * referenced at all outside of this file.
+ */
+extern atomic_t global_bh_lock;
+extern atomic_t global_bh_count;
+extern spinlock_t s390_bh_lock;
+
+extern void synchronize_bh(void);
+
+static inline void start_bh_atomic(void)
+{
+	atomic_inc(&global_bh_lock);
+	synchronize_bh();
+}
+
+static inline void end_bh_atomic(void)
+{
+	atomic_dec(&global_bh_lock);
+}
+
+/* These are for the IRQs testing the lock */
+static inline int softirq_trylock(int cpu)
+{
+	if (!test_and_set_bit(0,&global_bh_count)) {
+		if (atomic_read(&global_bh_lock) == 0) {
+                        atomic_inc(&safe_get_cpu_lowcore(cpu).local_bh_count);
+			return 1;
+		}
+		clear_bit(0,&global_bh_count);
+	}
+	return 0;
+}
+
+static inline void softirq_endlock(int cpu)
+{
+        atomic_dec(&safe_get_cpu_lowcore(cpu).local_bh_count);
+	clear_bit(0,&global_bh_count);
+}
+
+#else
+
+extern inline void start_bh_atomic(void)
+{
+        atomic_inc(&S390_lowcore.local_bh_count);
+	barrier();
+}
+
+extern inline void end_bh_atomic(void)
+{
+	barrier();
+        atomic_dec(&S390_lowcore.local_bh_count);
+}
+
+/* These are for the irq's testing the lock */
+#define softirq_trylock(cpu)	(atomic_compare_and_swap(0,1,&S390_lowcore.local_bh_count) == 0)
+
+#define softirq_endlock(cpu)   atomic_set(&S390_lowcore.local_bh_count,0);
+#define synchronize_bh()       barrier()
+
+#endif	/* SMP */
+
+extern inline void init_bh(int nr, void (*routine)(void))
+{
+        unsigned long flags;
+
+        bh_base[nr] = routine;
+        atomic_set(&bh_mask_count[nr], 0);
+
+        spin_lock_irqsave(&s390_bh_lock, flags);
+        bh_mask |= 1 << nr;
+        spin_unlock_irqrestore(&s390_bh_lock, flags);
+}
+
+extern inline void remove_bh(int nr)
+{
+        unsigned long flags;
+
+        spin_lock_irqsave(&s390_bh_lock, flags);
+        bh_mask &= ~(1 << nr);
+        spin_unlock_irqrestore(&s390_bh_lock, flags);
+
+        synchronize_bh();
+        bh_base[nr] = NULL;
+}
+
+extern inline void mark_bh(int nr)
+{
+        set_bit(nr, &bh_active);
+}
+
+/*
+ * These use a mask count to correctly handle
+ * nested disable/enable calls
+ */
+extern inline void disable_bh(int nr)
+{
+        unsigned long flags;
+
+        spin_lock_irqsave(&s390_bh_lock, flags);
+        bh_mask &= ~(1 << nr);
+        atomic_inc(&bh_mask_count[nr]);
+        spin_unlock_irqrestore(&s390_bh_lock, flags);
+        synchronize_bh();
+}
+
+extern inline void enable_bh(int nr)
+{
+        unsigned long flags;
+
+        spin_lock_irqsave(&s390_bh_lock, flags);
+        if (atomic_dec_and_test(&bh_mask_count[nr]))
+                bh_mask |= 1 << nr;
+        spin_unlock_irqrestore(&s390_bh_lock, flags);
+}
+
+#endif	/* __ASM_SOFTIRQ_H */
+
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/spinlock.h linux.14p16/include/asm-s390/spinlock.h
--- linux.vanilla/include/asm-s390/spinlock.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/spinlock.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,215 @@
+/*
+ *  include/asm-s390/spinlock.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *  Derived from "include/asm-i386/spinlock.h"
+ */
+
+#ifndef __ASM_SPINLOCK_H
+#define __ASM_SPINLOCK_H
+
+#ifndef __SMP__
+
+/*
+ * Your basic spinlocks, allowing only a single CPU anywhere
+ *
+ * Gcc-2.7.x has a nasty bug with empty initializers.
+ */
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+typedef struct { } spinlock_t;
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
+#else
+  typedef struct { int gcc_is_buggy; } spinlock_t;
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
+#endif
+
+#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_irq(lock)	cli()
+#define spin_unlock_irq(lock)	sti()
+
+#define spin_lock_irqsave(lock, flags) \
+	do { save_flags(flags); cli(); } while (0)
+#define spin_unlock_irqrestore(lock, flags) \
+	restore_flags(flags)
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * NOTE! it is quite common to have readers in interrupts
+ * but no interrupt writers. For those circumstances we
+ * can "mix" irq-safe locks - any writer needs to get a
+ * irq-safe write-lock, but readers can get non-irqsafe
+ * read-locks.
+ *
+ * Gcc-2.7.x has a nasty bug with empty initializers.
+ */
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+  typedef struct { } rwlock_t;
+  #define RW_LOCK_UNLOCKED (rwlock_t) { }
+#else
+  typedef struct { int gcc_is_buggy; } rwlock_t;
+  #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
+#endif
+
+#define read_lock(lock)		do { } while(0)
+#define read_unlock(lock)	do { } while(0)
+#define write_lock(lock)	do { } while(0)
+#define write_unlock(lock)	do { } while(0)
+#define read_lock_irq(lock)	cli()
+#define read_unlock_irq(lock)	sti()
+#define write_lock_irq(lock)	cli()
+#define write_unlock_irq(lock)	sti()
+
+#define read_lock_irqsave(lock, flags)	\
+	do { save_flags(flags); cli(); } while (0)
+#define read_unlock_irqrestore(lock, flags) \
+	restore_flags(flags)
+#define write_lock_irqsave(lock, flags)	\
+	do { save_flags(flags); cli(); } while (0)
+#define write_unlock_irqrestore(lock, flags) \
+	restore_flags(flags)
+
+#else /* __SMP__ */
+
+/* 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.
+ */
+
+typedef struct {
+	volatile unsigned long lock;
+} spinlock_t;
+
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
+#define spin_lock_init(lp) do { (lp)->lock = 0; } while(0)
+#define spin_unlock_wait(lp)	do { barrier(); } while((lp)->lock)
+
+extern inline void spin_lock(spinlock_t *lp)
+{
+	__asm__ __volatile("    lhi   1,-1\n"
+			   "0:  slr   0,0\n"
+			   "    cs    0,1,%1\n"
+			   "    jl    0b"
+			   : "=m" (lp->lock)
+			   : "0" (lp->lock) : "0", "1");
+}
+
+extern inline int spin_trylock(spinlock_t *lp)
+{
+	unsigned long result;
+	__asm__ __volatile("    slr   %1,%1\n"
+			   "    lhi   0,-1\n"
+			   "0:  cs    %1,0,%0"
+			   : "=m" (lp->lock), "=&d" (result)
+			   : "0" (lp->lock) : "0");
+	return !result;
+}
+
+
+
+extern inline void spin_unlock(spinlock_t *lp)
+{
+	__asm__ __volatile("    xc 0(4,%0),0(%0)\n"
+                           "    bcr 15,0"
+			   : /* no output */ : "a" (lp) );
+}
+		
+#define spin_lock_irq(lock) \
+	do { __cli(); spin_lock(lock); } while (0)
+#define spin_unlock_irq(lock) \
+	do { spin_unlock(lock); __sti(); } while (0)
+
+#define spin_lock_irqsave(lock, flags) \
+	do { __save_flags(flags); __cli(); spin_lock(lock); } while (0)
+#define spin_unlock_irqrestore(lock, flags) \
+	do { spin_unlock(lock); __restore_flags(flags); } while (0)
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * NOTE! it is quite common to have readers in interrupts
+ * but no interrupt writers. For those circumstances we
+ * can "mix" irq-safe locks - any writer needs to get a
+ * irq-safe write-lock, but readers can get non-irqsafe
+ * read-locks.
+ */
+typedef struct {
+	volatile unsigned long lock;
+	volatile unsigned long owner_pc;
+} rwlock_t;
+
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+
+extern void _read_lock(rwlock_t *rw);
+extern void _read_unlock(rwlock_t *rw);
+extern void _write_lock(rwlock_t *rw);
+extern void _write_unlock(rwlock_t *rw);
+
+#define read_lock(rw)   \
+        asm volatile("   l     2,%0\n"   \
+                     "0: sll   2,1\n"    \
+                     "   srl   2,1\n"     /* clear high (=write) bit */ \
+                     "   lr    3,2\n"    \
+                     "   ahi   3,1\n"     /* one more reader */ \
+                     "   cs    2,3,%0\n"  /* try to write new value */ \
+                     "   jl    0b"       \
+                     : "+m" ((rw)->lock) : : "2", "3" );
+
+#define read_unlock(rw) \
+        asm volatile("   l     2,%0\n"   \
+                     "0: lr    3,2\n"    \
+                     "   ahi   3,-1\n"    /* one less reader */ \
+                     "   cs    2,3,%0\n" \
+                     "   jl    0b"       \
+                     : "+m" ((rw)->lock) : : "2", "3" );
+
+#define write_lock(rw) \
+        asm volatile("   lhi   3,1\n"    \
+                     "   sll   3,31\n"    /* new lock value = 0x80000000 */ \
+                     "0: slr   2,2\n"     /* old lock value must be 0 */ \
+                     "   cs    2,3,%0\n" \
+                     "   jl    0b"       \
+                     : "+m" ((rw)->lock) : : "2", "3" );
+
+#define write_unlock(rw) \
+        asm volatile("   slr   3,3\n"     /* new lock value = 0 */ \
+                     "0: lhi   2,1\n"    \
+                     "   sll   2,31\n"    /* old lock value must be 0x80000000 */ \
+                     "   cs    2,3,%0\n" \
+                     "   jl    0b"       \
+                     : "+m" ((rw)->lock) : : "2", "3" );
+
+#define read_lock_irq(lock)	do { __cli(); read_lock(lock); } while (0)
+#define read_unlock_irq(lock)	do { read_unlock(lock); __sti(); } while (0)
+#define write_lock_irq(lock)	do { __cli(); write_lock(lock); } while (0)
+#define write_unlock_irq(lock)	do { write_unlock(lock); __sti(); } while (0)
+
+#define read_lock_irqsave(lock, flags)	\
+	do { __save_flags(flags); __cli(); read_lock(lock); } while (0)
+#define read_unlock_irqrestore(lock, flags) \
+	do { read_unlock(lock); __restore_flags(flags); } while (0)
+#define write_lock_irqsave(lock, flags)	\
+	do { __save_flags(flags); __cli(); write_lock(lock); } while (0)
+#define write_unlock_irqrestore(lock, flags) \
+	do { write_unlock(lock); __restore_flags(flags); } while (0)
+
+#endif /* SMP */
+#endif /* __ASM_SPINLOCK_H */
+
+
+
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/stat.h linux.14p16/include/asm-s390/stat.h
--- linux.vanilla/include/asm-s390/stat.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/stat.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,49 @@
+/*
+ *  include/asm-s390/stat.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/stat.h"
+ */
+
+#ifndef _S390_STAT_H
+#define _S390_STAT_H
+
+struct __old_kernel_stat {
+        unsigned short st_dev;
+        unsigned short st_ino;
+        unsigned short st_mode;
+        unsigned short st_nlink;
+        unsigned short st_uid;
+        unsigned short st_gid;
+        unsigned short st_rdev;
+        unsigned long  st_size;
+        unsigned long  st_atime;
+        unsigned long  st_mtime;
+        unsigned long  st_ctime;
+};
+
+struct stat {
+        unsigned short st_dev;
+        unsigned short __pad1;
+        unsigned long st_ino;
+        unsigned short st_mode;
+        unsigned short st_nlink;
+        unsigned short st_uid;
+        unsigned short st_gid;
+        unsigned short st_rdev;
+        unsigned short __pad2;
+        unsigned long  st_size;
+        unsigned long  st_blksize;
+        unsigned long  st_blocks;
+        unsigned long  st_atime;
+        unsigned long  __unused1;
+        unsigned long  st_mtime;
+        unsigned long  __unused2;
+        unsigned long  st_ctime;
+        unsigned long  __unused3;
+        unsigned long  __unused4;
+        unsigned long  __unused5;
+};
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/statfs.h linux.14p16/include/asm-s390/statfs.h
--- linux.vanilla/include/asm-s390/statfs.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/statfs.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,33 @@
+/*
+ *  include/asm-s390/statfs.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/statfs.h"
+ */
+
+#ifndef _S390_STATFS_H
+#define _S390_STATFS_H
+
+#ifndef __KERNEL_STRICT_NAMES
+
+#include <linux/types.h>
+
+typedef __kernel_fsid_t	fsid_t;
+
+#endif
+
+struct statfs {
+	long f_type;
+	long f_bsize;
+	long f_blocks;
+	long f_bfree;
+	long f_bavail;
+	long f_files;
+	long f_ffree;
+	__kernel_fsid_t f_fsid;
+	long f_namelen;
+	long f_spare[6];
+};
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/string.h linux.14p16/include/asm-s390/string.h
--- linux.vanilla/include/asm-s390/string.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/string.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,107 @@
+/*
+ *  include/asm-s390/string.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+#ifndef _S390_STRING_H_
+#define _S390_STRING_H_
+
+#ifdef __KERNEL__
+
+#ifndef _LINUX_TYPES_H
+#include <linux/types.h>
+#endif
+
+#define __HAVE_ARCH_MEMCHR
+#define __HAVE_ARCH_MEMCPY
+#define __HAVE_ARCH_MEMSET
+#define __HAVE_ARCH_STRCAT
+#define __HAVE_ARCH_STRCMP
+#define __HAVE_ARCH_STRCPY
+#define __HAVE_ARCH_STRLEN
+#define __HAVE_ARCH_STRNCPY
+
+#undef __HAVE_ARCH_MEMMOVE
+#undef __HAVE_ARCH_STRNICMP
+#undef __HAVE_ARCH_STRNCAT
+#undef __HAVE_ARCH_STRNCMP
+#undef __HAVE_ARCH_STRCHR
+#undef __HAVE_ARCH_STRRCHR
+#undef __HAVE_ARCH_STRNLEN
+#undef __HAVE_ARCH_STRSPN
+#undef __HAVE_ARCH_STRPBRK
+#undef __HAVE_ARCH_STRTOK
+#undef __HAVE_ARCH_BCOPY
+#undef __HAVE_ARCH_MEMCMP
+#undef __HAVE_ARCH_MEMSCAN
+#undef __HAVE_ARCH_STRSTR
+
+extern void *memset(void *, int, size_t);
+
+extern inline void * memchr(const void * cs,int c,size_t count)
+{
+    void *ptr;
+
+    __asm__ __volatile__ ("   lr    0,%2\n"
+                          "   la    %0,0(%3,%1)\n"
+                          "0: srst  %0,%1\n"
+                          "   jo    0b\n"
+                          "   brc   13,1f\n"
+                          "   slr   %0,%0\n"
+                          "1:"
+                          : "=a" (ptr) : "a" (cs), "d" (c), "d" (count)
+                          : "cc", "0" );
+    return ptr;
+}
+
+extern __inline__ char *strcpy(char *dest, const char *src)
+{
+    char *tmp = dest;
+
+    __asm__ __volatile__ ("   sr    0,0\n"
+                          "0: mvst  %0,%1\n"
+                          "   jo    0b"
+                          : "+&a" (dest), "+&a" (src) :
+                          : "cc", "memory", "0" );
+    return tmp;
+}
+
+extern __inline__ size_t strlen(const char *s)
+{
+    size_t len;
+
+    __asm__ __volatile__ ("   sr    0,0\n"
+                          "   lr    %0,%1\n"
+                          "0: srst  0,%0\n"
+                          "   jo    0b\n"
+                          "   lr    %0,0\n"
+                          "   sr    %0,%1"
+                          : "=&a" (len) : "a" (s) 
+                          : "cc", "0" );
+    return len;
+}
+
+extern __inline__ char *strcat(char *dest, const char *src)
+{
+    char *tmp = dest;
+
+    __asm__ __volatile__ ("   sr    0,0\n"
+                          "0: srst  0,%0\n"
+                          "   jo    0b\n"
+                          "   lr    %0,0\n"
+                          "   sr    0,0\n"
+                          "1: mvst  %0,%1\n"
+                          "   jo    1b"
+                          : "+&a" (dest), "+&a" (src) :
+                          : "cc", "memory", "0" );
+    return tmp;
+}
+
+
+#endif /* __KERNEL__ */
+
+#endif /* __S390_STRING_H_ */
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/system.h linux.14p16/include/asm-s390/system.h
--- linux.vanilla/include/asm-s390/system.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/system.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,215 @@
+/*
+ *  include/asm-s390/system.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ *  Derived from "include/asm-i386/system.h"
+ */
+
+#ifndef __ASM_SYSTEM_H
+#define __ASM_SYSTEM_H
+
+#ifdef __KERNEL__
+#include <asm/lowcore.h>
+#endif
+#include <linux/kernel.h>
+
+
+struct task_struct;
+
+#define nop() __asm__ __volatile__ ("nop")
+
+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+
+static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
+{
+        switch (size) {
+                case 1:
+                        asm volatile (
+                                "   lhi   1,3\n"
+                                "   nr    1,%0\n"     /* isolate last 2 bits */
+                                "   xr    1,%0\n"     /* align ptr */
+                                "   bras  2,0f\n"
+                                "   icm   1,8,%1\n"   /* for ptr&3 == 0 */
+                                "   stcm  0,8,%1\n"
+                                "   icm   1,4,%1\n"   /* for ptr&3 == 1 */
+                                "   stcm  0,4,%1\n"
+                                "   icm   1,2,%1\n"   /* for ptr&3 == 2 */
+                                "   stcm  0,2,%1\n"
+                                "   icm   1,1,%1\n"   /* for ptr&3 == 3 */
+                                "   stcm  0,1,%1\n"
+                                "0: sll   1,3\n"
+                                "   la    2,0(1,2)\n" /* r2 points to an icm */
+                                "   l     0,%1\n"     /* get fullword */
+                                "1: lr    1,0\n"      /* cs loop */
+                                "   ex    0,0(2)\n"   /* insert x */
+                                "   cs    0,1,%1\n"
+                                "   jl    1b\n"
+                                "   ex    0,4(2)"     /* store *ptr to x */
+                                : "+a&" (ptr) : "m" (x)
+                                : "memory", "0", "1", "2");
+                case 2:
+                        if(((__u32)ptr)&1)
+                                panic("misaligned (__u16 *) in __xchg\n");
+                        asm volatile (
+                                "   lhi   1,2\n"
+                                "   nr    1,%0\n"     /* isolate bit 2^1 */
+                                "   xr    1,%0\n"     /* align ptr */
+                                "   bras  2,0f\n"
+                                "   icm   1,12,%1\n"   /* for ptr&2 == 0 */
+                                "   stcm  0,12,%1\n"
+                                "   icm   1,3,%1\n"    /* for ptr&2 == 1 */
+                                "   stcm  0,3,%1\n"
+                                "0: sll   1,2\n"
+                                "   la    2,0(1,2)\n" /* r2 points to an icm */
+                                "   l     0,%1\n"     /* get fullword */
+                                "1: lr    1,0\n"      /* cs loop */
+                                "   ex    0,0(2)\n"   /* insert x */
+                                "   cs    0,1,%1\n"
+                                "   jl    1b\n"
+                                "   ex    0,4(2)"     /* store *ptr to x */
+                                : "+a&" (ptr) : "m" (x)
+                                : "memory", "0", "1", "2");
+                        break;
+                case 4:
+                        if(((__u32)ptr)&3)
+                                panic("misaligned (__u32 *) in __xchg\n");
+                        asm volatile (
+                                "    l   0,0(%1)\n"
+                                "0:  cs  0,%0,0(%1)\n"
+                                "    jl  0b\n"
+                                "    lr  %0,0\n"
+                                : "+d&" (x) : "a" (ptr)
+                                : "memory", "0" );
+                        break;
+               default:
+                        abort();
+        }
+        return x;
+}
+
+/*
+ * Force strict CPU ordering.
+ * And yes, this is required on UP too when we're talking
+ * to devices.
+ */
+/* This is very similar to the ppc eieio/sync instruction in that is
+ * does a checkpoint syncronisation & makes sure that 
+ * all memory ops have completed wrt other CPU's ( see 7-15 POP  DJB ).
+ */
+#define eieio()  __asm__ __volatile__ ("BCR 15,0") 
+# define SYNC_OTHER_CORES(x)   eieio() 
+#define mb()    eieio()
+#define wmb()   eieio()
+
+#define __sti() ({ \
+        __u8 dummy; \
+        __asm__ __volatile__ ( \
+                "stosm %0,0x03" : "=m" (dummy) : : "memory"); \
+        })
+
+#define __cli() ({ \
+        __u8 dummy; \
+        __asm__ __volatile__ ( \
+                "stnsm %0,0xFC" : "=m" (dummy) : : "memory"); \
+        })
+
+#define __save_flags(x) \
+        __asm__ __volatile__("stosm %0,0" : "=m" (x) : : "memory")
+
+#define __restore_flags(x) \
+        __asm__ __volatile__("ssm   %0" : : "m" (x) : "memory")
+
+#define __ctl_set_bit(cr, bit) ({ \
+        __u8 dummy[16]; \
+        __asm__ __volatile__ ( \
+                "    la    1,%0\n"       /* align to 8 byte */ \
+                "    ahi   1,7\n" \
+                "    srl   1,3\n" \
+                "    sll   1,3\n" \
+                "    bras  2,0f\n"       /* skip indirect insns */ \
+                "    stctl 0,0,0(1)\n" \
+                "    lctl  0,0,0(1)\n" \
+                "0:  ex    %1,0(2)\n"    /* execute stctl */ \
+                "    l     0,0(1)\n" \
+                "    or    0,%2\n"       /* set the bit */ \
+                "    st    0,0(1)\n" \
+                "1:  ex    %1,4(2)"      /* execute lctl */ \
+                : "=m" (dummy) : "a" (cr*17), "a" (1<<(bit)) \
+                : "0", "1", "2"); \
+        })
+
+#define __ctl_clear_bit(cr, bit) ({ \
+        __u8 dummy[16]; \
+        __asm__ __volatile__ ( \
+                "    la    1,%0\n"       /* align to 8 byte */ \
+                "    ahi   1,7\n" \
+                "    srl   1,3\n" \
+                "    sll   1,3\n" \
+                "    bras  2,0f\n"       /* skip indirect insns */ \
+                "    stctl 0,0,0(1)\n" \
+                "    lctl  0,0,0(1)\n" \
+                "0:  ex    %1,0(2)\n"    /* execute stctl */ \
+                "    l     0,0(1)\n" \
+                "    nr    0,%2\n"       /* set the bit */ \
+                "    st    0,0(1)\n" \
+                "1:  ex    %1,4(2)"      /* execute lctl */ \
+                : "=m" (dummy) : "a" (cr*17), "a" (~(1<<(bit))) \
+                : "0", "1", "2"); \
+        })
+
+#ifdef __SMP__
+
+extern void __global_cli(void);
+extern void __global_sti(void);
+
+extern unsigned long __global_save_flags(void);
+extern void __global_restore_flags(unsigned long);
+#define cli() __global_cli()
+#define sti() __global_sti()
+#define save_flags(x) ((x)=__global_save_flags())
+#define restore_flags(x) __global_restore_flags(x)
+
+extern void smp_ctl_set_bit(int cr, int bit);
+extern void smp_ctl_clear_bit(int cr, int bit);
+#define ctl_set_bit(cr, bit) smp_ctl_set_bit(cr, bit)
+#define ctl_clear_bit(cr, bit) smp_ctl_clear_bit(cr, bit)
+
+#else
+
+#define cli() __cli()
+#define sti() __sti()
+#define save_flags(x) __save_flags(x)
+#define restore_flags(x) __restore_flags(x)
+
+#define ctl_set_bit(cr, bit) __ctl_set_bit(cr, bit)
+#define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit)
+
+
+#endif
+
+#ifdef __KERNEL__
+extern struct task_struct *resume(void *,void *);
+
+extern int save_fp_regs1(s390_fp_regs *fpregs);
+extern void save_fp_regs(s390_fp_regs *fpregs);
+extern int restore_fp_regs1(s390_fp_regs *fpregs);
+extern void restore_fp_regs(s390_fp_regs *fpregs);
+extern void show_crashed_task_info(void);
+#endif
+
+#define switch_to(prev,next,last) do {                                       \
+        if (prev == next)                                                    \
+                break;                                                       \
+	save_fp_regs1(&prev->tss.fp_regs);                                   \
+	restore_fp_regs1(&next->tss.fp_regs);              		     \
+	(next)->mm->cpu_vm_mask |= (1UL << smp_processor_id());		     \
+	last = resume(&prev->tss,&next->tss);                                \
+} while (0)
+#endif
+
+
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/termbits.h linux.14p16/include/asm-s390/termbits.h
--- linux.vanilla/include/asm-s390/termbits.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/termbits.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,180 @@
+/*
+ *  include/asm-s390/termbits.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/termbits.h"
+ */
+
+#ifndef __ARCH_S390_TERMBITS_H__
+#define __ARCH_S390_TERMBITS_H__
+
+#include <linux/posix_types.h>
+
+typedef unsigned char	cc_t;
+typedef unsigned int	speed_t;
+typedef unsigned int	tcflag_t;
+
+#define NCCS 19
+struct termios {
+	tcflag_t c_iflag;		/* input mode flags */
+	tcflag_t c_oflag;		/* output mode flags */
+	tcflag_t c_cflag;		/* control mode flags */
+	tcflag_t c_lflag;		/* local mode flags */
+	cc_t c_line;			/* line discipline */
+	cc_t c_cc[NCCS];		/* control characters */
+};
+
+/* c_cc characters */
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VTIME 5
+#define VMIN 6
+#define VSWTC 7
+#define VSTART 8
+#define VSTOP 9
+#define VSUSP 10
+#define VEOL 11
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE 14
+#define VLNEXT 15
+#define VEOL2 16
+
+/* c_iflag bits */
+#define IGNBRK	0000001
+#define BRKINT	0000002
+#define IGNPAR	0000004
+#define PARMRK	0000010
+#define INPCK	0000020
+#define ISTRIP	0000040
+#define INLCR	0000100
+#define IGNCR	0000200
+#define ICRNL	0000400
+#define IUCLC	0001000
+#define IXON	0002000
+#define IXANY	0004000
+#define IXOFF	0010000
+#define IMAXBEL	0020000
+
+/* c_oflag bits */
+#define OPOST	0000001
+#define OLCUC	0000002
+#define ONLCR	0000004
+#define OCRNL	0000010
+#define ONOCR	0000020
+#define ONLRET	0000040
+#define OFILL	0000100
+#define OFDEL	0000200
+#define NLDLY	0000400
+#define   NL0	0000000
+#define   NL1	0000400
+#define CRDLY	0003000
+#define   CR0	0000000
+#define   CR1	0001000
+#define   CR2	0002000
+#define   CR3	0003000
+#define TABDLY	0014000
+#define   TAB0	0000000
+#define   TAB1	0004000
+#define   TAB2	0010000
+#define   TAB3	0014000
+#define   XTABS	0014000
+#define BSDLY	0020000
+#define   BS0	0000000
+#define   BS1	0020000
+#define VTDLY	0040000
+#define   VT0	0000000
+#define   VT1	0040000
+#define FFDLY	0100000
+#define   FF0	0000000
+#define   FF1	0100000
+
+/* c_cflag bit meaning */
+#define CBAUD	0010017
+#define  B0	0000000		/* hang up */
+#define  B50	0000001
+#define  B75	0000002
+#define  B110	0000003
+#define  B134	0000004
+#define  B150	0000005
+#define  B200	0000006
+#define  B300	0000007
+#define  B600	0000010
+#define  B1200	0000011
+#define  B1800	0000012
+#define  B2400	0000013
+#define  B4800	0000014
+#define  B9600	0000015
+#define  B19200	0000016
+#define  B38400	0000017
+#define EXTA B19200
+#define EXTB B38400
+#define CSIZE	0000060
+#define   CS5	0000000
+#define   CS6	0000020
+#define   CS7	0000040
+#define   CS8	0000060
+#define CSTOPB	0000100
+#define CREAD	0000200
+#define PARENB	0000400
+#define PARODD	0001000
+#define HUPCL	0002000
+#define CLOCAL	0004000
+#define CBAUDEX 0010000
+#define  B57600  0010001
+#define  B115200 0010002
+#define  B230400 0010003
+#define  B460800 0010004
+#define   B500000 0010005
+#define   B576000 0010006
+#define   B921600 0010007
+#define  B1000000 0010010
+#define  B1152000 0010011
+#define  B1500000 0010012
+#define  B2000000 0010013
+#define  B2500000 0010014
+#define  B3000000 0010015
+#define  B3500000 0010016
+#define  B4000000 0010017
+#define CIBAUD	  002003600000	/* input baud rate (not used) */
+#define CMSPAR	  010000000000		/* mark or space (stick) parity */
+#define CRTSCTS	  020000000000		/* flow control */
+
+/* c_lflag bits */
+#define ISIG	0000001
+#define ICANON	0000002
+#define XCASE	0000004
+#define ECHO	0000010
+#define ECHOE	0000020
+#define ECHOK	0000040
+#define ECHONL	0000100
+#define NOFLSH	0000200
+#define TOSTOP	0000400
+#define ECHOCTL	0001000
+#define ECHOPRT	0002000
+#define ECHOKE	0004000
+#define FLUSHO	0010000
+#define PENDIN	0040000
+#define IEXTEN	0100000
+
+/* tcflow() and TCXONC use these */
+#define	TCOOFF		0
+#define	TCOON		1
+#define	TCIOFF		2
+#define	TCION		3
+
+/* tcflush() and TCFLSH use these */
+#define	TCIFLUSH	0
+#define	TCOFLUSH	1
+#define	TCIOFLUSH	2
+
+/* tcsetattr uses these */
+#define	TCSANOW		0
+#define	TCSADRAIN	1
+#define	TCSAFLUSH	2
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/termios.h linux.14p16/include/asm-s390/termios.h
--- linux.vanilla/include/asm-s390/termios.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/termios.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,112 @@
+/*
+ *  include/asm-s390/termios.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/termios.h"
+ */
+
+#ifndef _S390_TERMIOS_H
+#define _S390_TERMIOS_H
+
+#include <asm/termbits.h>
+#include <asm/ioctls.h>
+
+
+struct winsize {
+	unsigned short ws_row;
+	unsigned short ws_col;
+	unsigned short ws_xpixel;
+	unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+	unsigned short c_iflag;		/* input mode flags */
+	unsigned short c_oflag;		/* output mode flags */
+	unsigned short c_cflag;		/* control mode flags */
+	unsigned short c_lflag;		/* local mode flags */
+	unsigned char c_line;		/* line discipline */
+	unsigned char c_cc[NCC];	/* control characters */
+};
+
+/* modem lines */
+#define TIOCM_LE	0x001
+#define TIOCM_DTR	0x002
+#define TIOCM_RTS	0x004
+#define TIOCM_ST	0x008
+#define TIOCM_SR	0x010
+#define TIOCM_CTS	0x020
+#define TIOCM_CAR	0x040
+#define TIOCM_RNG	0x080
+#define TIOCM_DSR	0x100
+#define TIOCM_CD	TIOCM_CAR
+#define TIOCM_RI	TIOCM_RNG
+#define TIOCM_OUT1	0x2000
+#define TIOCM_OUT2	0x4000
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
+/* line disciplines */
+#define N_TTY		0
+#define N_SLIP		1
+#define N_MOUSE		2
+#define N_PPP		3
+#define N_STRIP		4
+#define N_AX25		5
+#define N_X25		6	/* X.25 async */
+#define N_6PACK		7
+#define N_MASC		8	/* Reserved for Mobitex module <kaz@cafe.net> */
+#define N_R3964		9	/* Reserved for Simatic R3964 module */
+#define N_PROFIBUS_FDL	10	/* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA		11	/* Linux IR - http://www.cs.uit.no/~dagb/irda/irda.html */
+#define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
+#define N_HDLC         13	/* synchronous HDLC */
+
+#ifdef __KERNEL__
+
+/*	intr=^C		quit=^\		erase=del	kill=^U
+	eof=^D		vtime=\0	vmin=\1		sxtc=\0
+	start=^Q	stop=^S		susp=^Z		eol=\0
+	reprint=^R	discard=^U	werase=^W	lnext=^V
+	eol2=\0
+*/
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+
+/*
+ * Translate a "termio" structure into a "termios". Ugh.
+ */
+#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
+	unsigned short __tmp; \
+	get_user(__tmp,&(termio)->x); \
+	*(unsigned short *) &(termios)->x = __tmp; \
+}
+
+#define user_termio_to_kernel_termios(termios, termio) \
+({ \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
+	copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+})
+
+/*
+ * Translate a "termios" structure into a "termio". Ugh.
+ */
+#define kernel_termios_to_user_termio(termio, termios) \
+({ \
+	put_user((termios)->c_iflag, &(termio)->c_iflag); \
+	put_user((termios)->c_oflag, &(termio)->c_oflag); \
+	put_user((termios)->c_cflag, &(termio)->c_cflag); \
+	put_user((termios)->c_lflag, &(termio)->c_lflag); \
+	put_user((termios)->c_line,  &(termio)->c_line); \
+	copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
+})
+
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+
+#endif	/* __KERNEL__ */
+
+#endif	/* _S390_TERMIOS_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/timex.h linux.14p16/include/asm-s390/timex.h
--- linux.vanilla/include/asm-s390/timex.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/timex.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,29 @@
+/*
+ *  include/asm-s390/timex.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *
+ *  Derived from "include/asm-i386/timex.h"
+ *    Copyright (C) 1992, Linus Torvalds
+ */
+
+#ifndef _ASM_S390_TIMEX_H
+#define _ASM_S390_TIMEX_H
+
+#define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
+#define CLOCK_TICK_FACTOR	20	/* Factor of both 1000000 and CLOCK_TICK_RATE */
+#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
+	(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
+		<< (SHIFT_SCALE-SHIFT_HZ)) / HZ)
+
+typedef unsigned long cycles_t;
+
+extern cycles_t cacheflush_time;
+
+static inline cycles_t get_cycles(void)
+{
+        return 0;
+}
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/types.h linux.14p16/include/asm-s390/types.h
--- linux.vanilla/include/asm-s390/types.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/types.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,63 @@
+/*
+ *  include/asm-s390/types.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/types.h"
+ */
+
+#ifndef _S390_TYPES_H
+#define _S390_TYPES_H
+
+typedef unsigned short umode_t;
+
+/*
+ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
+ * header files exported to user space
+ */
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+typedef __signed__ long long __s64;
+typedef unsigned long long __u64;
+#endif
+/* A address type so that arithmetic can be done on it & it can be upgraded to
+   64 bit when neccessary 
+*/
+typedef __u32  addr_t; 
+typedef __s32  saddr_t;
+/*
+ * These aren't exported outside the kernel to avoid name space clashes
+ */
+#ifdef __KERNEL__
+
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+#define BITS_PER_LONG 32
+
+#endif                                 /* __KERNEL__                       */
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/uaccess.h linux.14p16/include/asm-s390/uaccess.h
--- linux.vanilla/include/asm-s390/uaccess.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/uaccess.h	Wed Dec 15 22:21:21 1999
@@ -0,0 +1,520 @@
+/*
+ *  include/asm-s390/uaccess.h
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Hartmut Penner (hp@de.ibm.com),
+ *               Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *  Derived from "include/asm-i386/uaccess.h"
+ */
+#ifndef __S390_UACCESS_H
+#define __S390_UACCESS_H
+
+/*
+ * User space memory access functions
+ */
+#include <linux/sched.h>
+#if 0
+#include <asm/segment.h>
+#endif
+#define VERIFY_READ     0
+#define VERIFY_WRITE    1
+
+
+/*
+ * The fs value determines whether argument validity checking should be
+ * performed or not.  If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons, these macros are grossly misnamed.
+ */
+
+#define MAKE_MM_SEG(s,a)  ((mm_segment_t) { (s),(a) })
+
+
+#define KERNEL_DS       MAKE_MM_SEG(0x7FFFFFFF,0)
+#define USER_DS         MAKE_MM_SEG(PAGE_OFFSET,1)
+
+#define get_ds()        (KERNEL_DS)
+#define get_fs()        (current->tss.fs)
+#define set_fs(x)       ({asm volatile("sar   4,%0"::"a" (x.acc4)); \
+                         current->tss.fs = (x);})
+
+#define segment_eq(a,b) ((a).acc4 == (b).acc4)
+
+
+#define __access_ok(addr,size) ((((long) addr + size)&0x7FFFFFFFL) < current->addr_limit.seg)
+
+#define access_ok(type,addr,size) __access_ok(addr,size)
+
+extern inline int verify_area(int type, const void * addr, unsigned long size)
+{
+        return access_ok(type,addr,size)?0:-EFAULT;
+}
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue.  No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path.  This means when everything is well,
+ * we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry
+{
+        unsigned long insn, fixup;
+};
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+
+/*
+ * These are the main single-value transfer routines.  They automatically
+ * use the right size if we just have the right pointer type.
+ */
+
+extern inline int __put_user_asm_4(__u32 x, void *ptr)
+{
+        int err;
+
+        __asm__ __volatile__ (  "   iac   1\n"
+				"   sr    %1,%1\n"
+				"   la    4,%0\n"
+                                "   sacf  512\n"
+                                "0: st    %2,0(4)\n"
+                                "   sacf  0(1)\n"
+				"1:\n"
+				".section .fixup,\"ax\"\n"
+				"2: sacf  0(1)\n"
+				"   lhi   %1,%h3\n"
+				"   bras  4,3f\n"
+				"   .long 1b\n"
+				"3: l     4,0(4)\n"
+				"   br    4\n"
+				".previous\n"
+				".section __ex_table,\"a\"\n"
+				"   .align 4\n"
+				"   .long  0b,2b\n"
+				".previous"
+                                : "=m" (*((__u32*) ptr)) , "=&d" (err)
+                                : "d" (x), "K" (-EFAULT)
+                                : "1", "4" );
+        return err;
+}
+
+extern inline int __put_user_asm_2(__u16 x, void *ptr)
+{
+        int err;
+
+        __asm__ __volatile__ (  "   iac   1\n"
+				"   sr    %1,%1\n"
+				"   la    4,%0\n"
+                                "   sacf  512\n"
+                                "0: sth   %2,0(4)\n"
+                                "   sacf  0(1)\n"
+				"1:\n"
+				".section .fixup,\"ax\"\n"
+				"2: sacf  0(1)\n"
+				"   lhi   %1,%h3\n"
+				"   bras  4,3f\n"
+				"   .long 1b\n"
+				"3: l     4,0(4)\n"
+				"   br    4\n"
+				".previous\n"
+				".section __ex_table,\"a\"\n"
+				"   .align 4\n"
+				"   .long  0b,2b\n"
+				".previous"
+                                : "=m" (*((__u16*) ptr)) , "=&d" (err)
+                                : "d" (x), "K" (-EFAULT)
+                                : "1", "4" );
+        return err;
+}
+
+extern inline int __put_user_asm_1(__u8 x, void *ptr)
+{
+        int err;
+
+        __asm__ __volatile__ (  "   iac   1\n"
+				"   sr    %1,%1\n"
+				"   la    4,%0\n"
+                                "   sacf  512\n"
+                                "0: stc   %2,0(4)\n"
+                                "   sacf  0(1)\n"
+				"1:\n"
+				".section .fixup,\"ax\"\n"
+				"2: sacf  0(1)\n"
+				"   lhi   %1,%h3\n"
+				"   bras  4,3f\n"
+				"   .long 1b\n"
+				"3: l     4,0(4)\n"
+				"   br    4\n"
+				".previous\n"
+				".section __ex_table,\"a\"\n"
+				"   .align 4\n"
+				"   .long  0b,2b\n"
+				".previous"
+                                : "=m" (*((__u8*) ptr)) , "=&d" (err)
+                                : "d" (x), "K" (-EFAULT)
+                                : "1", "4" );
+        return err;
+}
+
+/*
+ * (u8)(u32) ... autsch, but that the only way we can suppress the
+ * warnings when compiling binfmt_elf.c
+ */
+#define __put_user(x, ptr)                                      \
+({                                                              \
+        int __pu_err;                                           \
+        switch (sizeof (*(ptr))) {                              \
+                case 1:                                         \
+                        __pu_err = __put_user_asm_1((__u8)(__u32)x,ptr);\
+                        break;                                  \
+                case 2:                                         \
+                        __pu_err = __put_user_asm_2((__u16)(__u32)x,ptr);\
+                        break;                                  \
+                case 4:                                         \
+                        __pu_err = __put_user_asm_4((__u32) x,ptr);\
+                        break;                                  \
+                default:                                        \
+                __pu_err = __put_user_bad();                    \
+                break;                                          \
+         }                                                      \
+        __pu_err;                                               \
+})
+
+#define put_user(x, ptr)                                        \
+({                                                              \
+        long __pu_err = -EFAULT;                                \
+        __typeof__(*(ptr)) *__pu_addr = (ptr);                  \
+        __typeof__(x) __x = (x);                                \
+        if (__access_ok((long)__pu_addr,sizeof(*(ptr)))) {      \
+                __pu_err = 0;                                   \
+                __put_user((__x), (__pu_addr));                 \
+        }                                                       \
+        __pu_err;                                               \
+})
+
+extern int __put_user_bad(void);
+
+
+#define __get_user_asm_4(x, ptr, err)                                   \
+({                                                                      \
+        __asm__ __volatile__ (  "   iac   1\n"                          \
+                                "   sr    %1,%1\n"                      \
+                                "   la    4,%2\n"                       \
+                                "   sacf  512\n"                        \
+                                "0: l     %0,0(4)\n"                    \
+                                "   sacf  0(1)\n"                       \
+                                "1:\n"                                  \
+                                ".section .fixup,\"ax\"\n"              \
+                                "2: sacf  0(1)\n"                       \
+                                "   lhi   %1,%h3\n"                     \
+                                "   bras  4,3f\n"                       \
+                                "   .long 1b\n"                         \
+                                "3: l     4,0(4)\n"                     \
+                                "   br    4\n"                          \
+                                ".previous\n"                           \
+                                ".section __ex_table,\"a\"\n"           \
+                                "   .align 4\n"                         \
+                                "   .long 0b,2b\n"                      \
+                                ".previous"                             \
+                                : "=d" (x) , "=&d" (err)                \
+                                : "m" (*(__u32*) ptr), "K" (-EFAULT)    \
+                                : "1", "4" );                           \
+})
+
+#define __get_user_asm_2(x, ptr, err)                                   \
+({                                                                      \
+        __asm__ __volatile__ (  "   iac   1\n"                          \
+                                "   sr    %1,%1\n"                      \
+                                "   la    4,%2\n"                       \
+                                "   sacf  512\n"                        \
+                                "0: lh    %0,0(4)\n"                    \
+                                "   sacf  0(1)\n"                       \
+                                "1:\n"                                  \
+                                ".section .fixup,\"ax\"\n"              \
+                                "2: sacf  0(1)\n"                       \
+                                "   lhi   %1,%h3\n"                     \
+                                "   bras  4,3f\n"                       \
+                                "   .long 1b\n"                         \
+                                "3: l     4,0(4)\n"                     \
+                                "   br    4\n"                          \
+                                ".previous\n"                           \
+                                ".section __ex_table,\"a\"\n"           \
+                                "   .align 4\n"                         \
+                                "   .long 0b,2b\n"                      \
+                                ".previous"                             \
+                                : "=d" (x) , "=&d" (err)                \
+                                : "m" (*(__u16*) ptr), "K" (-EFAULT)    \
+                                : "1", "4" );                           \
+})
+
+#define __get_user_asm_1(x, ptr, err)                                   \
+({                                                                      \
+        __asm__ __volatile__ (  "   iac   1\n"                          \
+                                "   sr    %1,%1\n"                      \
+                                "   la    4,%2\n"                       \
+                                "   sr    %0,%0\n"                      \
+                                "   sacf  512\n"                        \
+                                "0: ic    %0,0(4)\n"                    \
+                                "   sacf  0(1)\n"                       \
+                                "1:\n"                                  \
+                                ".section .fixup,\"ax\"\n"              \
+                                "2: sacf  0(1)\n"                       \
+                                "   lhi   %1,%h3\n"                     \
+                                "   bras  4,3f\n"                       \
+                                "   .long 1b\n"                         \
+                                "3: l     4,0(4)\n"                     \
+                                "   br    4\n"                          \
+                                ".previous\n"                           \
+                                ".section __ex_table,\"a\"\n"           \
+                                "   .align 4\n"                         \
+                                "   .long 0b,2b\n"                      \
+                                ".previous"                             \
+                                : "=d" (x) , "=&d" (err)                \
+                                : "m" (*(__u8*) ptr), "K" (-EFAULT)     \
+                                : "1", "4" );                           \
+})
+
+#define __get_user(x, ptr)                                      \
+({                                                              \
+        int __gu_err;                                           \
+        switch (sizeof(*(ptr))) {                               \
+                case 1:                                         \
+                        __get_user_asm_1(x,ptr,__gu_err);       \
+                        break;                                  \
+                case 2:                                         \
+                        __get_user_asm_2(x,ptr,__gu_err);       \
+                        break;                                  \
+                case 4:                                         \
+                        __get_user_asm_4(x,ptr,__gu_err);       \
+                        break;                                  \
+                default:                                        \
+                        (x) = 0;                                \
+                        __gu_err = __get_user_bad();            \
+                break;                                          \
+        }                                                       \
+        __gu_err;                                               \
+})
+
+#define get_user(x, ptr)                                        \
+({                                                              \
+        long __gu_err = -EFAULT;                                \
+        __typeof__(*(ptr)) *__gu_addr = (ptr);                  \
+        __typeof__(x) __x;                                      \
+        if (__access_ok((long)__gu_addr,sizeof(*(ptr)))) {      \
+                __gu_err = 0;                                   \
+                __get_user((__x), (__gu_addr));                 \
+                (x) = __x;                                      \
+        }                                                       \
+        else                                                    \
+                (x) = 0;                                        \
+        __gu_err;                                               \
+})
+
+extern int __get_user_bad(void);
+
+/*
+ * access register are set up, that 4 points to secondary (user) , 2 to primary (kernel)
+ */
+
+extern inline unsigned long
+__copy_to_user_asm(void* to, const void* from,  long n)
+{
+
+        __asm__ __volatile__ (  "   iac   1\n"
+                                "   lr    2,%2\n"
+                                "   lr    4,%1\n"
+                                "   lr    3,%0\n"
+                                "   lr    5,3\n"
+                                "   sacf  512\n"
+                                "0: mvcle 4,2,0\n"
+                                "   jo    0b\n"
+                                "1: sacf  0(1)\n"
+                                "   lr    %0,3\n"
+				".section __ex_table,\"a\"\n"
+				"   .align 4\n"
+				"   .long  0b,1b\n"
+				".previous"
+                                : "+&d" (n) : "d" (to), "d" (from)
+                                : "1", "2", "3", "4", "5" );
+        return n;
+}
+
+#define __copy_to_user(to, from, n)                             \
+({                                                              \
+        __copy_to_user_asm(to,from,n);                          \
+})
+
+#define copy_to_user(to, from, n)                               \
+({                                                              \
+        long err = 0;                                           \
+        __typeof__(n) __n = (n);                                \
+        if (__access_ok(to,__n)) {                              \
+                err = __copy_to_user_asm(to,from,__n);          \
+        }                                                       \
+        else                                                    \
+                err = __n;                                      \
+        err;                                                    \
+})
+
+extern inline unsigned long
+__copy_from_user_asm(void* to, const void* from,  long n)
+{
+        __asm__ __volatile__ (  "   iac   1\n"
+				"   lr    2,%1\n"
+                                "   lr    4,%2\n"
+                                "   lr    3,%0\n"
+                                "   lr    5,3\n"
+                                "   sacf  512\n"
+                                "0: mvcle 2,4,0\n"
+                                "   jo    0b\n"
+                                "1: sacf  0(1)\n"
+                                "   lr    %0,3\n"
+				".section __ex_table,\"a\"\n"
+				"   .align 4\n"
+				"   .long  0b,1b\n"
+				".previous"
+                                : "+&d" (n) : "d" (to), "d" (from)
+                                : "1", "2", "3", "4", "5" );
+        return n;
+}
+
+
+#define __copy_from_user(to, from, n)                           \
+({                                                              \
+        __copy_from_user_asm(to,from,n);                        \
+})
+
+#define copy_from_user(to, from, n)                             \
+({                                                              \
+        long err = 0;                                           \
+        __typeof__(n) __n = (n);                                \
+        if (__access_ok(from,__n)) {                            \
+                err = __copy_from_user_asm(to,from,__n);        \
+        }                                                       \
+        else                                                    \
+                err = __n;                                      \
+        err;                                                    \
+})
+
+#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; })
+
+#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; })
+
+/*
+ * Copy a null terminated string from userspace.
+ */
+
+static inline long
+strncpy_from_user(char *dst, const char *src, long count)
+{
+        int len;
+        __asm__ __volatile__ (  "   iac   1\n"
+				"   slr   %0,%0\n"
+				"   lr    2,%1\n"
+                                "   lr    4,%2\n"
+                                "   slr   3,3\n"
+                                "   sacf  512\n"
+                                "0: ic    3,0(%0,4)\n"
+                                "1: stc   3,0(%0,2)\n"
+                                "   ahi   %0,1\n"
+                                "   cr    %0,%3\n"
+                                "   je    2f\n"
+                                "   ltr   3,3\n"
+                                "   jne   0b\n"
+                                "2: sacf  0(1)\n"
+				"3:\n"
+				".section .fixup,\"ax\"\n"
+				"4: sacf  0(1)\n"
+                                "   lhi   %0,%h4\n"
+				"   bras  3,5f\n"
+				"   .long 3b\n"
+				"5: l     3,0(3)\n"
+				"   br    3\n"
+				".previous\n"
+				".section __ex_table,\"a\"\n"
+				"   .align 4\n"
+				"   .long  0b,4b\n"
+				"   .long  1b,4b\n"
+				".previous"
+                                : "=&a" (len)
+                                : "a"  (dst), "d" (src), "d" (count),
+                                  "K" (-EFAULT)
+                                : "1", "2" ,"3", "4" );
+        return len;
+}
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 for error
+ */
+static inline long strnlen_user(const char * src, long n)
+{
+	__asm__ __volatile__ ("   iac   1\n"
+                              "   alr   %0,%1\n"
+			      "   slr   0,0\n"
+			      "   lr    4,%1\n"
+			      "   sacf  512\n"
+			      "0: srst  %0,4\n"
+			      "   jo    0b\n"
+			      "   slr   %0,%1\n"
+			      "   ahi   %0,1\n"
+			      "   sacf  0(1)\n"
+                              "1:\n"
+                              ".section .fixup,\"ax\"\n"
+                              "2: sacf  0(1)\n"
+                              "   slr   %0,%0\n"
+                              "   bras  4,3f\n"
+                              "   .long 1b\n"
+                              "3: l     4,0(4)\n"
+                              "   br    4\n"
+                              ".previous\n"
+			      ".section __ex_table,\"a\"\n"
+			      "   .align 4\n"
+			      "   .long  0b,2b\n"
+			      ".previous"
+			      : "+&a" (n) : "d" (src)
+			      : "cc", "0", "1", "4" );
+        return n;
+}
+#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
+
+/*
+ * Zero Userspace
+ */
+
+static inline unsigned long
+clear_user(void *to, unsigned long n)
+{
+        __asm__ __volatile__ (  "   iac   1\n"
+                                "   sacf  512\n"
+                                "   lr    4,%1\n"
+                                "   lr    5,%0\n"
+                                "   sr    2,2\n"
+                                "   sr    3,3\n"
+                                "0: mvcle 4,2,0\n"
+                                "   jo    0b\n"
+                                "1: sacf  0(1)\n"
+                                "   lr    %0,3\n"
+				".section __ex_table,\"a\"\n"
+				"   .align 4\n"
+				"   .long  0b,1b\n"
+				".previous"
+                                : "+&a" (n)
+                                : "a"   (to)
+                                : "cc", "1", "2", "3", "4", "5" );
+        return n;
+}
+
+#endif                                 /* _S390_UACCESS_H                  */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/ucontext.h linux.14p16/include/asm-s390/ucontext.h
--- linux.vanilla/include/asm-s390/ucontext.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/ucontext.h	Wed Dec 15 22:21:44 1999
@@ -0,0 +1,19 @@
+/*
+ *  include/asm-s390/ucontext.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/ucontext.h"
+ */
+
+#ifndef _ASM_S390_UCONTEXT_H
+#define _ASM_S390_UCONTEXT_H
+
+struct ucontext {
+	unsigned long	  uc_flags;
+	struct ucontext  *uc_link;
+	stack_t		  uc_stack;
+	sigset_t	  uc_sigmask;	/* mask last for extensibility */
+};
+
+#endif /* !_ASM_S390_UCONTEXT_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/unaligned.h linux.14p16/include/asm-s390/unaligned.h
--- linux.vanilla/include/asm-s390/unaligned.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/unaligned.h	Wed Dec 15 22:21:44 1999
@@ -0,0 +1,24 @@
+/*
+ *  include/asm-s390/unaligned.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/unaligned.h"
+ */
+
+#ifndef __S390_UNALIGNED_H
+#define __S390_UNALIGNED_H
+
+/*
+ * The S390 can do unaligned accesses itself. 
+ *
+ * The strange macros are there to make sure these can't
+ * be misused in a way that makes them not work on other
+ * architectures where unaligned accesses aren't as simple.
+ */
+
+#define get_unaligned(ptr) (*(ptr))
+
+#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/unistd.h linux.14p16/include/asm-s390/unistd.h
--- linux.vanilla/include/asm-s390/unistd.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/unistd.h	Wed Dec 15 22:21:44 1999
@@ -0,0 +1,362 @@
+/*
+ *  include/asm-s390/unistd.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/unistd.h"
+ */
+
+#ifndef _ASM_S390_UNISTD_H_
+#define _ASM_S390_UNISTD_H_
+
+/*
+ * This file contains the system call numbers.
+ */
+
+#define __NR_exit                 1
+#define __NR_fork                 2
+#define __NR_read                 3
+#define __NR_write                4
+#define __NR_open                 5
+#define __NR_close                6
+#define __NR_waitpid              7
+#define __NR_creat                8
+#define __NR_link                 9
+#define __NR_unlink              10
+#define __NR_execve              11
+#define __NR_chdir               12
+#define __NR_time                13
+#define __NR_mknod               14
+#define __NR_chmod               15
+#define __NR_lchown              16
+#define __NR_break               17
+#define __NR_oldstat             18
+#define __NR_lseek               19
+#define __NR_getpid              20
+#define __NR_mount               21
+#define __NR_umount              22
+#define __NR_setuid              23
+#define __NR_getuid              24
+#define __NR_stime               25
+#define __NR_ptrace              26
+#define __NR_alarm               27
+#define __NR_oldfstat            28
+#define __NR_pause               29
+#define __NR_utime               30
+#define __NR_stty                31
+#define __NR_gtty                32
+#define __NR_access              33
+#define __NR_nice                34
+#define __NR_ftime               35
+#define __NR_sync                36
+#define __NR_kill                37
+#define __NR_rename              38
+#define __NR_mkdir               39
+#define __NR_rmdir               40
+#define __NR_dup                 41
+#define __NR_pipe                42
+#define __NR_times               43
+#define __NR_prof                44
+#define __NR_brk                 45
+#define __NR_setgid              46
+#define __NR_getgid              47
+#define __NR_signal              48
+#define __NR_geteuid             49
+#define __NR_getegid             50
+#define __NR_acct                51
+#define __NR_umount2             52
+#define __NR_lock                53
+#define __NR_ioctl               54
+#define __NR_fcntl               55
+#define __NR_mpx                 56
+#define __NR_setpgid             57
+#define __NR_ulimit              58
+#define __NR_oldolduname         59
+#define __NR_umask               60
+#define __NR_chroot              61
+#define __NR_ustat               62
+#define __NR_dup2                63
+#define __NR_getppid             64
+#define __NR_getpgrp             65
+#define __NR_setsid              66
+#define __NR_sigaction           67
+#define __NR_sgetmask            68
+#define __NR_ssetmask            69
+#define __NR_setreuid            70
+#define __NR_setregid            71
+#define __NR_sigsuspend          72
+#define __NR_sigpending          73
+#define __NR_sethostname         74
+#define __NR_setrlimit           75
+#define __NR_getrlimit           76
+#define __NR_getrusage           77
+#define __NR_gettimeofday        78
+#define __NR_settimeofday        79
+#define __NR_getgroups           80
+#define __NR_setgroups           81
+#define __NR_select              82
+#define __NR_symlink             83
+#define __NR_oldlstat            84
+#define __NR_readlink            85
+#define __NR_uselib              86
+#define __NR_swapon              87
+#define __NR_reboot              88
+#define __NR_readdir             89
+#define __NR_mmap                90
+#define __NR_munmap              91
+#define __NR_truncate            92
+#define __NR_ftruncate           93
+#define __NR_fchmod              94
+#define __NR_fchown              95
+#define __NR_getpriority         96
+#define __NR_setpriority         97
+#define __NR_profil              98
+#define __NR_statfs              99
+#define __NR_fstatfs            100
+#define __NR_ioperm             101
+#define __NR_socketcall         102
+#define __NR_syslog             103
+#define __NR_setitimer          104
+#define __NR_getitimer          105
+#define __NR_stat               106
+#define __NR_lstat              107
+#define __NR_fstat              108
+#define __NR_olduname           109
+#define __NR_iopl               110
+#define __NR_vhangup            111
+#define __NR_idle               112
+#define __NR_vm86old            113
+#define __NR_wait4              114
+#define __NR_swapoff            115
+#define __NR_sysinfo            116
+#define __NR_ipc                117
+#define __NR_fsync              118
+#define __NR_sigreturn          119
+#define __NR_clone              120
+#define __NR_setdomainname      121
+#define __NR_uname              122
+#define __NR_modify_ldt         123
+#define __NR_adjtimex           124
+#define __NR_mprotect           125
+#define __NR_sigprocmask        126
+#define __NR_create_module      127
+#define __NR_init_module        128
+#define __NR_delete_module      129
+#define __NR_get_kernel_syms    130
+#define __NR_quotactl           131
+#define __NR_getpgid            132
+#define __NR_fchdir             133
+#define __NR_bdflush            134
+#define __NR_sysfs              135
+#define __NR_personality        136
+#define __NR_afs_syscall        137 /* Syscall for Andrew File System */
+#define __NR_setfsuid           138
+#define __NR_setfsgid           139
+#define __NR__llseek            140
+#define __NR_getdents           141
+#define __NR__newselect         142
+#define __NR_flock              143
+#define __NR_msync              144
+#define __NR_readv              145
+#define __NR_writev             146
+#define __NR_getsid             147
+#define __NR_fdatasync          148
+#define __NR__sysctl            149
+#define __NR_mlock              150
+#define __NR_munlock            151
+#define __NR_mlockall           152
+#define __NR_munlockall         153
+#define __NR_sched_setparam             154
+#define __NR_sched_getparam             155
+#define __NR_sched_setscheduler         156
+#define __NR_sched_getscheduler         157
+#define __NR_sched_yield                158
+#define __NR_sched_get_priority_max     159
+#define __NR_sched_get_priority_min     160
+#define __NR_sched_rr_get_interval      161
+#define __NR_nanosleep          162
+#define __NR_mremap             163
+#define __NR_setresuid          164
+#define __NR_getresuid          165
+#define __NR_vm86               166
+#define __NR_query_module       167
+#define __NR_poll               168
+#define __NR_nfsservctl         169
+#define __NR_setresgid          170
+#define __NR_getresgid          171
+#define __NR_prctl              172
+#define __NR_rt_sigreturn       173
+#define __NR_rt_sigaction       174
+#define __NR_rt_sigprocmask     175
+#define __NR_rt_sigpending      176
+#define __NR_rt_sigtimedwait    177
+#define __NR_rt_sigqueueinfo    178
+#define __NR_rt_sigsuspend      179
+#define __NR_pread              180
+#define __NR_pwrite             181
+#define __NR_chown              182
+#define __NR_getcwd             183
+#define __NR_capget             184
+#define __NR_capset             185
+#define __NR_sigaltstack        186
+#define __NR_sendfile           187
+#define __NR_getpmsg		188	/* some people actually want streams */
+#define __NR_putpmsg		189	/* some people actually want streams */
+#define __NR_vfork		190
+
+/* user-visible error numbers are in the range -1 - -122: see <asm-s390/errno.h> */
+
+#define __syscall_return(type, res)                          \
+do {                                                         \
+        if ((unsigned long)(res) >= (unsigned long)(-125)) { \
+                errno = -(res);                              \
+                res = -1;                                    \
+        }                                                    \
+        return (type) (res);                                 \
+} while (0)
+
+#define _svc_clobber "cc", "memory"
+
+#define _syscall0(type,name)                                 \
+type name(void) {                                            \
+        long __res;                                          \
+        __asm__ __volatile__ (                               \
+                "    svc %b1\n"                              \
+                "    lr  %0,2"                               \
+                : "=d" (__res)                               \
+                : "i" (__NR_##name)                          \
+                : _svc_clobber );                            \
+        __syscall_return(type,__res);                        \
+}
+
+#define _syscall1(type,name,type1,arg1)                      \
+type name(type1 arg1) {                                      \
+        register type1 __arg1 asm("2") = arg1;               \
+        long __res;                                          \
+        __asm__ __volatile__ (                               \
+                "    svc %b1\n"                              \
+                "    lr  %0,2"                               \
+                : "=d" (__res)                               \
+                : "i" (__NR_##name),                         \
+                  "d" (__arg1)                               \
+                : _svc_clobber );                            \
+        __syscall_return(type,__res);                        \
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2)           \
+type name(type1 arg1, type2 arg2) {                          \
+        register type1 __arg1 asm("2") = arg1;               \
+        register type2 __arg2 asm("3") = arg2;               \
+        long __res;                                          \
+        __asm__ __volatile__ (                               \
+                "    svc %b1\n"                              \
+                "    lr  %0,2"                               \
+                : "=d" (__res)                               \
+                : "i" (__NR_##name),                         \
+                  "d" (__arg1),                              \
+                  "d" (__arg2)                               \
+                : _svc_clobber );                            \
+        __syscall_return(type,__res);                        \
+}
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)\
+type name(type1 arg1, type2 arg2, type3 arg3) {              \
+        register type1 __arg1 asm("2") = arg1;               \
+        register type2 __arg2 asm("3") = arg2;               \
+        register type3 __arg3 asm("4") = arg3;               \
+        long __res;                                          \
+        __asm__ __volatile__ (                               \
+                "    svc %b1\n"                              \
+                "    lr  %0,2"                               \
+                : "=d" (__res)                               \
+                : "i" (__NR_##name),                         \
+                  "d" (__arg1),                              \
+                  "d" (__arg2),                              \
+                  "d" (__arg3)                               \
+                : _svc_clobber );                            \
+        __syscall_return(type,__res);                        \
+}
+
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,\
+                  type4,name4)                               \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) {  \
+        register type1 __arg1 asm("2") = arg1;               \
+        register type2 __arg2 asm("3") = arg2;               \
+        register type3 __arg3 asm("4") = arg3;               \
+        register type4 __arg4 asm("5") = arg4;               \
+        long __res;                                          \
+        __asm__ __volatile__ (                               \
+                "    svc %b1\n"                              \
+                "    lr  %0,2"                               \
+                : "=d" (__res)                               \
+                : "i" (__NR_##name),                         \
+                  "d" (__arg1),                              \
+                  "d" (__arg2),                              \
+                  "d" (__arg3),                              \
+                  "d" (__arg4)                               \
+                : _svc_clobber );                            \
+        __syscall_return(type,__res);                        \
+}
+
+#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,\
+                  type4,name4,type5,name5)                   \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4,    \
+          type5 arg5) {                                      \
+        register type1 __arg1 asm("2") = arg1;               \
+        register type2 __arg2 asm("3") = arg2;               \
+        register type3 __arg3 asm("4") = arg3;               \
+        register type4 __arg4 asm("5") = arg4;               \
+        register type5 __arg5 asm("6") = arg5;               \
+        long __res;                                          \
+        __asm__ __volatile__ (                               \
+                "    svc %b1\n"                              \
+                "    lr  %0,2"                               \
+                : "=d" (__res)                               \
+                : "i" (__NR_##name),                         \
+                  "d" (__arg1),                              \
+                  "d" (__arg2),                              \
+                  "d" (__arg3),                              \
+                  "d" (__arg4),                              \
+                  "d" (__arg5)                               \
+                : _svc_clobber );                            \
+        __syscall_return(type,__res);                        \
+}
+
+#ifdef __KERNEL_SYSCALLS__
+
+/*
+ * we need this inline - forking from kernel space will result
+ * in NO COPY ON WRITE (!!!), until an execve is executed. This
+ * is no problem, but for the stack. This is handled by not letting
+ * main() use the stack at all after fork(). Thus, no function
+ * calls - which means inline code for fork too, as otherwise we
+ * would use the stack upon exit from 'fork()'.
+ *
+ * Actually only pause and fork are needed inline, so that there
+ * won't be any messing with the stack from main(), but we define
+ * some others too.
+ */
+#define __NR__exit __NR_exit
+static inline _syscall0(int,idle)
+static inline _syscall0(int,pause)
+static inline _syscall0(int,sync)
+static inline _syscall0(pid_t,setsid)
+static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
+static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
+static inline _syscall1(int,dup,int,fd)
+static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
+static inline _syscall1(int,close,int,fd)
+static inline _syscall1(int,_exit,int,exitcode)
+static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+static inline _syscall1(int,delete_module,const char *,name)
+
+static inline pid_t wait(int * wait_stat)
+{
+        return waitpid(-1,wait_stat,0);
+}
+
+#endif
+
+#endif /* _ASM_S390_UNISTD_H_ */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-s390/user.h linux.14p16/include/asm-s390/user.h
--- linux.vanilla/include/asm-s390/user.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/asm-s390/user.h	Wed Dec 15 22:21:44 1999
@@ -0,0 +1,77 @@
+/*
+ *  include/asm-s390/user.h
+ *
+ *  S390 version
+ *
+ *  Derived from "include/asm-i386/usr.h"
+ */
+
+#ifndef _S390_USER_H
+#define _S390_USER_H
+
+#include <asm/page.h>
+#include <linux/ptrace.h>
+/* Core file format: The core file is written in such a way that gdb
+   can understand it and provide useful information to the user (under
+   linux we use the 'trad-core' bfd).  There are quite a number of
+   obstacles to being able to view the contents of the floating point
+   registers, and until these are solved you will not be able to view the
+   contents of them.  Actually, you can read in the core file and look at
+   the contents of the user struct to find out what the floating point
+   registers contain.
+   The actual file contents are as follows:
+   UPAGE: 1 page consisting of a user struct that tells gdb what is present
+   in the file.  Directly after this is a copy of the task_struct, which
+   is currently not used by gdb, but it may come in useful at some point.
+   All of the registers are stored as part of the upage.  The upage should
+   always be only one page.
+   DATA: The data area is stored.  We use current->end_text to
+   current->brk to pick up all of the user variables, plus any memory
+   that may have been malloced.  No attempt is made to determine if a page
+   is demand-zero or if a page is totally unused, we just cover the entire
+   range.  All of the addresses are rounded in such a way that an integral
+   number of pages is written.
+   STACK: We need the stack information in order to get a meaningful
+   backtrace.  We need to write the data from (esp) to
+   current->start_stack, so we round each of these off in order to be able
+   to write an integer number of pages.
+   The minimum core file size is 3 pages, or 12288 bytes.
+*/
+
+
+/*
+ * This is the old layout of "struct pt_regs", and
+ * is still the layout used by user mode (the new
+ * pt_regs doesn't have all registers as the kernel
+ * doesn't use the extra segment registers)
+ */
+
+/* When the kernel dumps core, it starts by dumping the user struct -
+   this will be used by gdb to figure out where the data and stack segments
+   are within the file, and what virtual addresses to use. */
+struct user {
+/* We start with the registers, to mimic the way that "memory" is returned
+   from the ptrace(3,...) function.  */
+  struct user_regs_struct regs;		/* Where the registers are actually stored */
+/* The rest of this junk is to help gdb figure out what goes where */
+  unsigned long int u_tsize;	/* Text segment size (pages). */
+  unsigned long int u_dsize;	/* Data segment size (pages). */
+  unsigned long int u_ssize;	/* Stack segment size (pages). */
+  unsigned long start_code;     /* Starting virtual address of text. */
+  unsigned long start_stack;	/* Starting virtual address of stack area.
+				   This is actually the bottom of the stack,
+				   the top of the stack is always found in the
+				   esp register.  */
+  long int signal;     		/* Signal that caused the core dump. */
+  struct user_regs_struct *u_ar0;
+				/* Used by gdb to help find the values for */
+				/* the registers. */
+  unsigned long magic;		/* To uniquely identify a core file */
+  char u_comm[32];		/* User command that was responsible */
+};
+#define NBPG PAGE_SIZE
+#define UPAGES 1
+#define HOST_TEXT_START_ADDR (u.start_code)
+#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+
+#endif /* _S390_USER_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc/asm_offsets.h linux.14p16/include/asm-sparc/asm_offsets.h
--- linux.vanilla/include/asm-sparc/asm_offsets.h	Thu Mar 11 00:53:37 1999
+++ linux.14p16/include/asm-sparc/asm_offsets.h	Thu Dec  9 15:32:51 1999
@@ -182,6 +182,10 @@
 #define ASIZ_task_sas_ss_sp	0x00000004
 #define AOFF_task_sas_ss_size	0x00000598
 #define ASIZ_task_sas_ss_size	0x00000004
+#define AOFF_task_parent_exec_id	0x0000059c
+#define ASIZ_task_parent_exec_id	0x00000004
+#define AOFF_task_self_exec_id	0x000005a0
+#define ASIZ_task_self_exec_id	0x00000004
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000004
 #define AOFF_mm_mmap_avl	0x00000004
@@ -457,6 +461,10 @@
 #define ASIZ_task_sas_ss_sp	0x00000004
 #define AOFF_task_sas_ss_size	0x00000694
 #define ASIZ_task_sas_ss_size	0x00000004
+#define AOFF_task_parent_exec_id	0x00000698
+#define ASIZ_task_parent_exec_id	0x00000004
+#define AOFF_task_self_exec_id	0x0000069c
+#define ASIZ_task_self_exec_id	0x00000004
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000004
 #define AOFF_mm_mmap_avl	0x00000004
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc/head.h linux.14p16/include/asm-sparc/head.h
--- linux.vanilla/include/asm-sparc/head.h	Wed Oct 20 01:12:50 1999
+++ linux.14p16/include/asm-sparc/head.h	Thu Dec  9 15:32:51 1999
@@ -1,4 +1,4 @@
-/* $Id: head.h,v 1.36.2.1 1999/09/22 11:37:45 jj Exp $ */
+/* $Id: head.h,v 1.36.2.2 1999/12/01 23:55:47 davem Exp $ */
 #ifndef __SPARC_HEAD_H
 #define __SPARC_HEAD_H
 
@@ -92,6 +92,10 @@
 /* The Set Condition Codes software trap for userland. */
 #define SETCC_TRAP \
         b setcc_trap_handler; mov %psr, %l0; nop; nop;
+
+/* The Get PSR software trap for userland. */
+#define GETPSR_TRAP \
+	mov %psr, %o0; jmpl %l2, %g0; rett %l2 + 4; nop;
 
 /* This is for hard interrupts from level 1-14, 15 is non-maskable (nmi) and
  * gets handled with another macro.
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc/ioctl.h linux.14p16/include/asm-sparc/ioctl.h
--- linux.vanilla/include/asm-sparc/ioctl.h	Sat Nov  9 08:29:28 1996
+++ linux.14p16/include/asm-sparc/ioctl.h	Thu Dec  9 15:32:51 1999
@@ -1,4 +1,4 @@
-/* $Id: ioctl.h,v 1.5 1996/05/17 03:31:09 davem Exp $ */
+/* $Id: ioctl.h,v 1.5.12.1 1999/12/01 23:57:52 davem Exp $ */
 #ifndef _SPARC_IOCTL_H
 #define _SPARC_IOCTL_H
 
@@ -39,5 +39,13 @@
 #define _IOC_TYPE(nr)       (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
 #define _IOC_NR(nr)         (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
 #define _IOC_SIZE(nr)       (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
+
+/* ...and for the PCMCIA... */
+
+#define IOC_IN          (_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT         (_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT       ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK    (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT   (_IOC_SIZESHIFT)
 
 #endif /* !(_SPARC_IOCTL_H) */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc/shmparam.h linux.14p16/include/asm-sparc/shmparam.h
--- linux.vanilla/include/asm-sparc/shmparam.h	Sun Oct  4 18:22:44 1998
+++ linux.14p16/include/asm-sparc/shmparam.h	Thu Dec  9 15:32:51 1999
@@ -1,4 +1,4 @@
-/* $Id: shmparam.h,v 1.4 1998/09/28 07:15:01 jj Exp $ */
+/* $Id: shmparam.h,v 1.4.2.1 1999/09/29 18:00:44 davem Exp $ */
 #ifndef _ASMSPARC_SHMPARAM_H
 #define _ASMSPARC_SHMPARAM_H
 
@@ -39,7 +39,12 @@
 #define SHMMNI (1<<_SHM_ID_BITS)	/* max num of segs system wide */
 #define SHMALL				/* max shm system wide (pages) */ \
 	(1<<(_SHM_IDX_BITS+_SHM_ID_BITS))
-#define	SHMLBA PAGE_SIZE		/* attach addr a multiple of this */
+
+extern int vac_cache_size;
+#define SHMLBA (vac_cache_size ? vac_cache_size : \
+		(sparc_cpu_model == sun4c ? (64 * 1024) : \
+		 (sparc_cpu_model == sun4 ? (128 * 1024) : PAGE_SIZE)))
+
 #define SHMSEG SHMMNI			/* max shared segs per process */
 
 #endif /* _ASMSPARC_SHMPARAM_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc64/asm_offsets.h linux.14p16/include/asm-sparc64/asm_offsets.h
--- linux.vanilla/include/asm-sparc64/asm_offsets.h	Thu Mar 11 00:53:38 1999
+++ linux.14p16/include/asm-sparc64/asm_offsets.h	Thu Dec  9 15:32:56 1999
@@ -182,6 +182,10 @@
 #define ASIZ_task_sas_ss_sp	0x00000008
 #define AOFF_task_sas_ss_size	0x00000820
 #define ASIZ_task_sas_ss_size	0x00000008
+#define AOFF_task_parent_exec_id	0x00000828
+#define ASIZ_task_parent_exec_id	0x00000004
+#define AOFF_task_self_exec_id	0x0000082c
+#define ASIZ_task_self_exec_id	0x00000004
 #define ASIZ_task	0x00000830
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
@@ -468,6 +472,10 @@
 #define ASIZ_task_sas_ss_sp	0x00000008
 #define AOFF_task_sas_ss_size	0x00000a10
 #define ASIZ_task_sas_ss_size	0x00000008
+#define AOFF_task_parent_exec_id	0x00000a18
+#define ASIZ_task_parent_exec_id	0x00000004
+#define AOFF_task_self_exec_id	0x00000a1c
+#define ASIZ_task_self_exec_id	0x00000004
 #define ASIZ_task	0x00000a20
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
@@ -752,7 +760,11 @@
 #define ASIZ_task_sas_ss_sp	0x00000008
 #define AOFF_task_sas_ss_size	0x00000a18
 #define ASIZ_task_sas_ss_size	0x00000008
-#define ASIZ_task	0x00000a20
+#define AOFF_task_parent_exec_id	0x00000a20
+#define ASIZ_task_parent_exec_id	0x00000004
+#define AOFF_task_self_exec_id	0x00000a24
+#define ASIZ_task_self_exec_id	0x00000004
+#define ASIZ_task	0x00000a30
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
 #define AOFF_mm_mmap_avl	0x00000008
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc64/mmu_context.h linux.14p16/include/asm-sparc64/mmu_context.h
--- linux.vanilla/include/asm-sparc64/mmu_context.h	Sat Aug 14 02:26:21 1999
+++ linux.14p16/include/asm-sparc64/mmu_context.h	Thu Dec  9 15:32:56 1999
@@ -1,9 +1,10 @@
-/* $Id: mmu_context.h,v 1.35 1999/05/08 03:03:20 davem Exp $ */
+/* $Id: mmu_context.h,v 1.35.2.1 1999/09/29 20:22:02 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
 /* Derived heavily from Linus's Alpha/AXP ASN code... */
 
+#include <asm/spinlock.h>
 #include <asm/system.h>
 #include <asm/spitfire.h>
 #include <asm/spinlock.h>
@@ -12,6 +13,7 @@
 
 #ifndef __ASSEMBLY__
 
+extern spinlock_t ctx_alloc_lock;
 extern unsigned long tlb_context_cache;
 extern unsigned long mmu_context_bmap[];
 
@@ -35,11 +37,13 @@
  * the final reference to the address space.
  */
 #define destroy_context(__mm)	do { 						\
+	spin_lock(&ctx_alloc_lock);						\
 	if ((__mm)->context != NO_CONTEXT &&					\
 	    atomic_read(&(__mm)->count) == 1) { 				\
 		if (!(((__mm)->context ^ tlb_context_cache) & CTX_VERSION_MASK))\
-			clear_bit((__mm)->context & ~(CTX_VERSION_MASK),	\
-				  mmu_context_bmap);				\
+		{	unsigned long nr = (__mm)->context & ~CTX_VERSION_MASK;	\
+			mmu_context_bmap[nr>>6] &= ~(1UL << (nr & 63));		\
+		}								\
 		(__mm)->context = NO_CONTEXT; 					\
 		if(current->mm == (__mm)) {					\
 			current->tss.ctx = 0;					\
@@ -47,6 +51,7 @@
 			__asm__ __volatile__("flush %g6");			\
 		}								\
 	} 									\
+	spin_unlock(&ctx_alloc_lock);						\
 } while (0)
 
 /* This routine must called with interrupts off,
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc64/oplib.h linux.14p16/include/asm-sparc64/oplib.h
--- linux.vanilla/include/asm-sparc64/oplib.h	Wed Oct 20 01:12:50 1999
+++ linux.14p16/include/asm-sparc64/oplib.h	Thu Dec  9 15:32:56 1999
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.10.2.1 1999/08/19 01:11:21 davem Exp $
+/* $Id: oplib.h,v 1.10.2.2 1999/10/24 17:29:38 davem Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -222,6 +222,24 @@
 extern long prom_dtlb_load(unsigned long index,
 			   unsigned long tte_data,
 			   unsigned long vaddr);
+
+/* Map/Unmap client program address ranges.  First the format of
+ * the mapping mode argument.
+ */
+#define PROM_MAP_WRITE	0x0001 /* Writable */
+#define PROM_MAP_READ	0x0002 /* Readable - sw */
+#define PROM_MAP_EXEC	0x0004 /* Executable - sw */
+#define PROM_MAP_LOCKED	0x0010 /* Locked, use i/dtlb load calls for this instead */
+#define PROM_MAP_CACHED	0x0020 /* Cacheable in both L1 and L2 caches */
+#define PROM_MAP_SE	0x0040 /* Side-Effects */
+#define PROM_MAP_GLOB	0x0080 /* Global */
+#define PROM_MAP_IE	0x0100 /* Invert-Endianness */
+#define PROM_MAP_DEFAULT (PROM_MAP_WRITE | PROM_MAP_READ | PROM_MAP_EXEC | PROM_MAP_CACHED)
+
+extern int prom_map(int mode, unsigned long size,
+		    unsigned long vaddr, unsigned long paddr);
+extern void prom_unmap(unsigned long size, unsigned long vaddr);
+
 
 /* PROM device tree traversal functions... */
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc64/pgtable.h linux.14p16/include/asm-sparc64/pgtable.h
--- linux.vanilla/include/asm-sparc64/pgtable.h	Sat Aug 14 02:27:38 1999
+++ linux.14p16/include/asm-sparc64/pgtable.h	Thu Dec  9 15:32:56 1999
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.103.2.1 1999/08/07 10:52:55 davem Exp $
+/* $Id: pgtable.h,v 1.103.2.2 1999/12/05 07:24:45 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -332,7 +332,7 @@
 #else
 extern struct pgtable_cache_struct {
 	unsigned long *pgd_cache;
-	unsigned long *pte_cache;
+	unsigned long *pte_cache[2];
 	unsigned int pgcache_size;
 	unsigned int pgdcache_size;
 } pgt_quicklists;
@@ -429,9 +429,12 @@
 extern __inline__ pmd_t *get_pmd_fast(void)
 {
 	unsigned long *ret;
+	int color = 0;
 
-	if((ret = (unsigned long *)pte_quicklist) != NULL) {
-		pte_quicklist = (unsigned long *)(*ret);
+	if (pte_quicklist[color] == NULL)
+		color = 1;
+	if((ret = (unsigned long *)pte_quicklist[color]) != NULL) {
+		pte_quicklist[color] = (unsigned long *)(*ret);
 		ret[0] = 0;
 		pgtable_cache_size--;
 	}
@@ -440,8 +443,10 @@
 
 extern __inline__ void free_pmd_fast(pgd_t *pmd)
 {
-	*(unsigned long *)pmd = (unsigned long) pte_quicklist;
-	pte_quicklist = (unsigned long *) pmd;
+	int color = (int) (((long)pmd >> PAGE_SHIFT) & 0x1);
+
+	*(unsigned long *)pmd = (unsigned long) pte_quicklist[color];
+	pte_quicklist[color] = (unsigned long *) pmd;
 	pgtable_cache_size++;
 }
 
@@ -450,14 +455,15 @@
 	free_page((unsigned long)pmd);
 }
 
-extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted,
+			   unsigned long color);
 
-extern __inline__ pte_t *get_pte_fast(void)
+extern __inline__ pte_t *get_pte_fast(unsigned long color)
 {
 	unsigned long *ret;
 
-	if((ret = (unsigned long *)pte_quicklist) != NULL) {
-		pte_quicklist = (unsigned long *)(*ret);
+	if((ret = (unsigned long *)pte_quicklist[color]) != NULL) {
+		pte_quicklist[color] = (unsigned long *)(*ret);
 		ret[0] = 0;
 		pgtable_cache_size--;
 	}
@@ -466,8 +472,9 @@
 
 extern __inline__ void free_pte_fast(pte_t *pte)
 {
-	*(unsigned long *)pte = (unsigned long) pte_quicklist;
-	pte_quicklist = (unsigned long *) pte;
+	unsigned long color = (((unsigned long)pte >> PAGE_SHIFT) & 0x1);
+	*(unsigned long *)pte = (unsigned long) pte_quicklist[color];
+	pte_quicklist[color] = (unsigned long *) pte;
 	pgtable_cache_size++;
 }
 
@@ -487,10 +494,12 @@
 {
 	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
 	if (pmd_none(*pmd)) {
-		pte_t *page = get_pte_fast();
+		/* Be careful, address can be just about anything... */
+		unsigned long color = (((unsigned long)pmd)>>2UL) & 0x1UL;
+		pte_t *page = get_pte_fast(color);
 
 		if (!page)
-			return get_pte_slow(pmd, address);
+			return get_pte_slow(pmd, address, color);
 		pmd_set(pmd, page);
 		return page + address;
 	}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc64/smp.h linux.14p16/include/asm-sparc64/smp.h
--- linux.vanilla/include/asm-sparc64/smp.h	Sun Mar 28 18:07:47 1999
+++ linux.14p16/include/asm-sparc64/smp.h	Thu Dec  9 15:32:56 1999
@@ -33,19 +33,19 @@
 /* Keep this a multiple of 64-bytes for cache reasons. */
 struct cpuinfo_sparc {
 	/* Dcache line 1 */
-	unsigned long	irq_count;
-	unsigned long	bh_count;
+	unsigned int	irq_count;
+	unsigned int	bh_count;
 	unsigned int	multiplier;
 	unsigned int	counter;
+	unsigned int	idle_volume;
+	unsigned int	__pad;
 	unsigned long	udelay_val;
 
 	/* Dcache line 2 */
 	unsigned int	pgcache_size;
 	unsigned int	pgdcache_size;
-	unsigned long	*pte_cache;
+	unsigned long	*pte_cache[2];
 	unsigned long	*pgd_cache;
-	unsigned int	idle_volume;
-	unsigned int	__pad;
 
 	/* Dcache lines 3 and 4 */
 	unsigned int	irq_worklists[16];
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc64/ttable.h linux.14p16/include/asm-sparc64/ttable.h
--- linux.vanilla/include/asm-sparc64/ttable.h	Wed Oct 20 01:12:50 1999
+++ linux.14p16/include/asm-sparc64/ttable.h	Thu Dec  9 15:32:56 1999
@@ -1,4 +1,4 @@
-/* $Id: ttable.h,v 1.11.2.2 1999/09/22 11:37:47 jj Exp $ */
+/* $Id: ttable.h,v 1.11.2.3 1999/10/07 20:48:25 davem Exp $ */
 #ifndef _SPARC64_TTABLE_H
 #define _SPARC64_TTABLE_H
 
@@ -163,6 +163,20 @@
 	        
 /* Before touching these macros, you owe it to yourself to go and
  * see how arch/sparc64/kernel/winfixup.S works... -DaveM
+ *
+ * For the user cases we used to use the %asi register, but
+ * it turns out that the "wr xxx, %asi" costs ~30 cycles, so
+ * now we use immediate ASI loads and stores instead.  Kudos
+ * to Greg Onufer for pointing out this performance anomaly.
+ *
+ * Further note that we cannot use the g2, g4, g5, and g7 alternate
+ * globals in the spill routines, check out the save instruction in
+ * arch/sparc64/kernel/etrap.S to see what I mean about g2, and
+ * g4/g5 are the globals which are preserved by etrap processing
+ * for the caller of it.  The g7 register is the return pc for
+ * etrap.  Finally, g6 is the current thread register so we cannot
+ * us it in the spill handlers either.  Most of these rules do not
+ * apply to fill processing, only g6 is not usable.
  */
 
 /* Normal kernel spill */
@@ -187,52 +201,67 @@
 	nop; nop; nop; nop; nop; nop; nop; nop;
 
 /* Normal 64bit spill */
-#define SPILL_1_GENERIC(xxx)				\
-	wr	%g0, xxx, %asi;				\
-	stxa	%l0, [%sp + STACK_BIAS + 0x00] %asi;	\
-	stxa	%l1, [%sp + STACK_BIAS + 0x08] %asi;	\
-	stxa	%l2, [%sp + STACK_BIAS + 0x10] %asi;	\
-	stxa	%l3, [%sp + STACK_BIAS + 0x18] %asi;	\
-	stxa	%l4, [%sp + STACK_BIAS + 0x20] %asi;	\
-	stxa	%l5, [%sp + STACK_BIAS + 0x28] %asi;	\
-	stxa	%l6, [%sp + STACK_BIAS + 0x30] %asi;	\
-	stxa	%l7, [%sp + STACK_BIAS + 0x38] %asi;	\
-	stxa	%i0, [%sp + STACK_BIAS + 0x40] %asi;	\
-	stxa	%i1, [%sp + STACK_BIAS + 0x48] %asi;	\
-	stxa	%i2, [%sp + STACK_BIAS + 0x50] %asi;	\
-	stxa	%i3, [%sp + STACK_BIAS + 0x58] %asi;	\
-	stxa	%i4, [%sp + STACK_BIAS + 0x60] %asi;	\
-	stxa	%i5, [%sp + STACK_BIAS + 0x68] %asi;	\
-	stxa	%i6, [%sp + STACK_BIAS + 0x70] %asi;	\
-	stxa	%i7, [%sp + STACK_BIAS + 0x78] %asi;	\
-	saved; retry; nop; nop; nop; nop; nop; nop;	\
-	nop; nop; nop; nop;				\
+#define SPILL_1_GENERIC(ASI)				\
+	add	%sp, STACK_BIAS + 0x00, %g1;		\
+	stxa	%l0, [%g1 + %g0] ASI;			\
+	mov	0x08, %g3;				\
+	stxa	%l1, [%g1 + %g3] ASI;			\
+	add	%g1, 0x10, %g1;				\
+	stxa	%l2, [%g1 + %g0] ASI;			\
+	stxa	%l3, [%g1 + %g3] ASI;			\
+	add	%g1, 0x10, %g1;				\
+	stxa	%l4, [%g1 + %g0] ASI;			\
+	stxa	%l5, [%g1 + %g3] ASI;			\
+	add	%g1, 0x10, %g1;				\
+	stxa	%l6, [%g1 + %g0] ASI;			\
+	stxa	%l7, [%g1 + %g3] ASI;			\
+	add	%g1, 0x10, %g1;				\
+	stxa	%i0, [%g1 + %g0] ASI;			\
+	stxa	%i1, [%g1 + %g3] ASI;			\
+	add	%g1, 0x10, %g1;				\
+	stxa	%i2, [%g1 + %g0] ASI;			\
+	stxa	%i3, [%g1 + %g3] ASI;			\
+	add	%g1, 0x10, %g1;				\
+	stxa	%i4, [%g1 + %g0] ASI;			\
+	stxa	%i5, [%g1 + %g3] ASI;			\
+	add	%g1, 0x10, %g1;				\
+	stxa	%i6, [%g1 + %g0] ASI;			\
+	stxa	%i7, [%g1 + %g3] ASI;			\
+	saved;						\
+	retry; nop; nop;				\
 	b,a,pt	%xcc, spill_fixup_dax;			\
 	b,a,pt	%xcc, spill_fixup_mna;			\
 	b,a,pt	%xcc, spill_fixup;
 
 /* Normal 32bit spill */
-#define SPILL_2_GENERIC(xxx)				\
-	wr	%g0, xxx, %asi;				\
+#define SPILL_2_GENERIC(ASI)				\
 	srl	%sp, 0, %sp;				\
-	stwa	%l0, [%sp + 0x00] %asi;			\
-	stwa	%l1, [%sp + 0x04] %asi;			\
-	stwa	%l2, [%sp + 0x08] %asi;			\
-	stwa	%l3, [%sp + 0x0c] %asi;			\
-	stwa	%l4, [%sp + 0x10] %asi;			\
-	stwa	%l5, [%sp + 0x14] %asi;			\
-	stwa	%l6, [%sp + 0x18] %asi;			\
-	stwa	%l7, [%sp + 0x1c] %asi;			\
-	stwa	%i0, [%sp + 0x20] %asi;			\
-	stwa	%i1, [%sp + 0x24] %asi;			\
-	stwa	%i2, [%sp + 0x28] %asi;			\
-	stwa	%i3, [%sp + 0x2c] %asi;			\
-	stwa	%i4, [%sp + 0x30] %asi;			\
-	stwa	%i5, [%sp + 0x34] %asi;			\
-	stwa	%i6, [%sp + 0x38] %asi;			\
-	stwa	%i7, [%sp + 0x3c] %asi;			\
-	saved; retry; nop; nop; nop; nop;		\
-	nop; nop; nop; nop; nop;			\
+	stwa	%l0, [%sp + %g0] ASI;			\
+	mov	0x04, %g3;				\
+	stwa	%l1, [%sp + %g3] ASI;			\
+	add	%sp, 0x08, %g1;				\
+	stwa	%l2, [%g1 + %g0] ASI;			\
+	stwa	%l3, [%g1 + %g3] ASI;			\
+	add	%g1, 0x08, %g1;				\
+	stwa	%l4, [%g1 + %g0] ASI;			\
+	stwa	%l5, [%g1 + %g3] ASI;			\
+	add	%g1, 0x08, %g1;				\
+	stwa	%l6, [%g1 + %g0] ASI;			\
+	stwa	%l7, [%g1 + %g3] ASI;			\
+	add	%g1, 0x08, %g1;				\
+	stwa	%i0, [%g1 + %g0] ASI;			\
+	stwa	%i1, [%g1 + %g3] ASI;			\
+	add	%g1, 0x08, %g1;				\
+	stwa	%i2, [%g1 + %g0] ASI;			\
+	stwa	%i3, [%g1 + %g3] ASI;			\
+	add	%g1, 0x08, %g1;				\
+	stwa	%i4, [%g1 + %g0] ASI;			\
+	stwa	%i5, [%g1 + %g3] ASI;			\
+	add	%g1, 0x08, %g1;				\
+	stwa	%i6, [%g1 + %g0] ASI;			\
+	stwa	%i7, [%g1 + %g3] ASI;			\
+	saved;						\
+        retry; nop; nop;				\
 	b,a,pt	%xcc, spill_fixup_dax;			\
 	b,a,pt	%xcc, spill_fixup_mna;			\
 	b,a,pt	%xcc, spill_fixup;
@@ -276,52 +305,63 @@
 	nop; nop; nop; nop; nop; nop; nop; nop;
 
 /* Normal 64bit fill */
-#define FILL_1_GENERIC(xxx)				\
-	wr	%g0, xxx, %asi;				\
-	ldxa	[%sp + STACK_BIAS + 0x00] %asi, %l0;	\
-	ldxa	[%sp + STACK_BIAS + 0x08] %asi, %l1;	\
-	ldxa	[%sp + STACK_BIAS + 0x10] %asi, %l2;	\
-	ldxa	[%sp + STACK_BIAS + 0x18] %asi, %l3;	\
-	ldxa	[%sp + STACK_BIAS + 0x20] %asi, %l4;	\
-	ldxa	[%sp + STACK_BIAS + 0x28] %asi, %l5;	\
-	ldxa	[%sp + STACK_BIAS + 0x30] %asi, %l6;	\
-	ldxa	[%sp + STACK_BIAS + 0x38] %asi, %l7;	\
-	ldxa	[%sp + STACK_BIAS + 0x40] %asi, %i0;	\
-	ldxa	[%sp + STACK_BIAS + 0x48] %asi, %i1;	\
-	ldxa	[%sp + STACK_BIAS + 0x50] %asi, %i2;	\
-	ldxa	[%sp + STACK_BIAS + 0x58] %asi, %i3;	\
-	ldxa	[%sp + STACK_BIAS + 0x60] %asi, %i4;	\
-	ldxa	[%sp + STACK_BIAS + 0x68] %asi, %i5;	\
-	ldxa	[%sp + STACK_BIAS + 0x70] %asi, %i6;	\
-	ldxa	[%sp + STACK_BIAS + 0x78] %asi, %i7;	\
-	restored; retry; nop; nop; nop; nop; nop; nop;	\
-	nop; nop; nop; nop;				\
+#define FILL_1_GENERIC(ASI)				\
+	add	%sp, STACK_BIAS + 0x00, %g1;		\
+	ldxa	[%g1 + %g0] ASI, %l0;			\
+	mov	0x08, %g2;				\
+	mov	0x10, %g3;				\
+	ldxa	[%g1 + %g2] ASI, %l1;			\
+	mov	0x18, %g5;				\
+	ldxa	[%g1 + %g3] ASI, %l2;			\
+	ldxa	[%g1 + %g5] ASI, %l3;			\
+	add	%g1, 0x20, %g1;				\
+	ldxa	[%g1 + %g0] ASI, %l4;			\
+	ldxa	[%g1 + %g2] ASI, %l5;			\
+	ldxa	[%g1 + %g3] ASI, %l6;			\
+	ldxa	[%g1 + %g5] ASI, %l7;			\
+	add	%g1, 0x20, %g1;				\
+	ldxa	[%g1 + %g0] ASI, %i0;			\
+	ldxa	[%g1 + %g2] ASI, %i1;			\
+	ldxa	[%g1 + %g3] ASI, %i2;			\
+	ldxa	[%g1 + %g5] ASI, %i3;			\
+	add	%g1, 0x20, %g1;				\
+	ldxa	[%g1 + %g0] ASI, %i4;			\
+	ldxa	[%g1 + %g2] ASI, %i5;			\
+	ldxa	[%g1 + %g3] ASI, %i6;			\
+	ldxa	[%g1 + %g5] ASI, %i7;			\
+	restored;					\
+	retry; nop; nop; nop; nop;			\
 	b,a,pt	%xcc, fill_fixup_dax;			\
 	b,a,pt	%xcc, fill_fixup_mna;			\
 	b,a,pt	%xcc, fill_fixup;
 
 /* Normal 32bit fill */
-#define FILL_2_GENERIC(xxx)				\
-	wr	%g0, xxx, %asi;				\
+#define FILL_2_GENERIC(ASI)				\
 	srl	%sp, 0, %sp;				\
-	lduwa	[%sp + 0x00] %asi, %l0;			\
-	lduwa	[%sp + 0x04] %asi, %l1;			\
-	lduwa	[%sp + 0x08] %asi, %l2;			\
-	lduwa	[%sp + 0x0c] %asi, %l3;			\
-	lduwa	[%sp + 0x10] %asi, %l4;			\
-	lduwa	[%sp + 0x14] %asi, %l5;			\
-	lduwa	[%sp + 0x18] %asi, %l6;			\
-	lduwa	[%sp + 0x1c] %asi, %l7;			\
-	lduwa	[%sp + 0x20] %asi, %i0;			\
-	lduwa	[%sp + 0x24] %asi, %i1;			\
-	lduwa	[%sp + 0x28] %asi, %i2;			\
-	lduwa	[%sp + 0x2c] %asi, %i3;			\
-	lduwa	[%sp + 0x30] %asi, %i4;			\
-	lduwa	[%sp + 0x34] %asi, %i5;			\
-	lduwa	[%sp + 0x38] %asi, %i6;			\
-	lduwa	[%sp + 0x3c] %asi, %i7;			\
-	restored; retry; nop; nop; nop; nop;		\
-	nop; nop; nop; nop; nop;			\
+	lduwa	[%sp + %g0] ASI, %l0;			\
+	mov	0x04, %g2;				\
+	mov	0x08, %g3;				\
+	lduwa	[%sp + %g2] ASI, %l1;			\
+	mov	0x0c, %g5;				\
+	lduwa	[%sp + %g3] ASI, %l2;			\
+	lduwa	[%sp + %g5] ASI, %l3;			\
+	add	%sp, 0x10, %g1;				\
+	lduwa	[%g1 + %g0] ASI, %l4;			\
+	lduwa	[%g1 + %g2] ASI, %l5;			\
+	lduwa	[%g1 + %g3] ASI, %l6;			\
+	lduwa	[%g1 + %g5] ASI, %l7;			\
+	add	%g1, 0x10, %g1;				\
+	lduwa	[%g1 + %g0] ASI, %i0;			\
+	lduwa	[%g1 + %g2] ASI, %i1;			\
+	lduwa	[%g1 + %g3] ASI, %i2;			\
+	lduwa	[%g1 + %g5] ASI, %i3;			\
+	add	%g1, 0x10, %g1;				\
+	lduwa	[%g1 + %g0] ASI, %i4;			\
+	lduwa	[%g1 + %g2] ASI, %i5;			\
+	lduwa	[%g1 + %g3] ASI, %i6;			\
+	lduwa	[%g1 + %g5] ASI, %i7;			\
+	restored;					\
+	retry; nop; nop; nop; nop;			\
 	b,a,pt	%xcc, fill_fixup_dax;			\
 	b,a,pt	%xcc, fill_fixup_mna;			\
 	b,a,pt	%xcc, fill_fixup;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/apm_bios.h linux.14p16/include/linux/apm_bios.h
--- linux.vanilla/include/linux/apm_bios.h	Wed Oct 20 01:12:50 1999
+++ linux.14p16/include/linux/apm_bios.h	Mon Dec 13 19:35:55 1999
@@ -3,7 +3,7 @@
 
 /*
  * Include file for the interface to an APM BIOS
- * Copyright 1994-1998 Stephen Rothwell (Stephen.Rothwell@canb.auug.org.au)
+ * Copyright 1994-1999 Stephen Rothwell (sfr@linuxcare.com)
  *
  * 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
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/blk.h linux.14p16/include/linux/blk.h
--- linux.vanilla/include/linux/blk.h	Sat Aug 14 02:27:39 1999
+++ linux.14p16/include/linux/blk.h	Wed Dec 15 23:12:57 1999
@@ -64,6 +64,11 @@
 extern int bpcd_init(void);
 extern int ps2esdi_init(void);
 
+#ifdef CONFIG_ARCH_S390
+extern int mdisk_init(void);
+extern int dasd_init(void);
+#endif /* CONFIG_ARCH_S390 */
+
 extern void set_device_ro(kdev_t dev,int flag);
 void add_blkdev_randomness(int major);
 
@@ -366,6 +371,23 @@
 #define DEVICE_NAME "nbd"
 #define DEVICE_REQUEST do_nbd_request
 #define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device) 
+#define DEVICE_OFF(device)
+
+
+#elif (MAJOR_NR == MDISK_MAJOR)
+
+#define DEVICE_NAME "mdisk"
+#define DEVICE_REQUEST mdisk_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device) 
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == DASD_MAJOR)
+
+#define DEVICE_NAME "dasd"
+#define DEVICE_REQUEST do_dasd_request
+#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS)
 #define DEVICE_ON(device) 
 #define DEVICE_OFF(device)
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/dcache.h linux.14p16/include/linux/dcache.h
--- linux.vanilla/include/linux/dcache.h	Sat Aug 14 02:26:21 1999
+++ linux.14p16/include/linux/dcache.h	Mon Dec 13 18:41:46 1999
@@ -133,15 +133,14 @@
 
 /* allocate/de-allocate */
 extern struct dentry * d_alloc(struct dentry * parent, const struct qstr *name);
-extern void prune_dcache(int);
+extern int prune_dcache(int, int);
 extern void shrink_dcache_sb(struct super_block *);
 extern void shrink_dcache_parent(struct dentry *);
 extern int d_invalidate(struct dentry *);
 
-#define shrink_dcache() prune_dcache(0)
+#define shrink_dcache() prune_dcache(0, -1)
 
 /* dcache memory management */
-extern int  select_dcache(int, int);
 extern void shrink_dcache_memory(int, unsigned int);
 extern void check_dcache_memory(void);
 extern void free_inode_memory(int);	/* defined in fs/inode.c */
@@ -151,6 +150,9 @@
 
 /* test whether root is busy without destroying dcache */
 extern int is_root_busy(struct dentry *);
+
+/* test whether we have any submounts in a subdir tree */
+extern int have_submounts(struct dentry *);
 
 /*
  * This adds the entry to the hash queues.
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/elf.h linux.14p16/include/linux/elf.h
--- linux.vanilla/include/linux/elf.h	Sat Aug 14 02:27:39 1999
+++ linux.14p16/include/linux/elf.h	Wed Dec 15 22:23:43 1999
@@ -74,6 +74,10 @@
  */
 #define EM_ALPHA	0x9026
 
+/*
+ * This is an interim value for S390 architecture
+ */
+#define EM_S390         0xA390
 
 /* This is the info that is needed to parse the dynamic section of the file */
 #define DT_NULL		0
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/errqueue.h linux.14p16/include/linux/errqueue.h
--- linux.vanilla/include/linux/errqueue.h	Mon Oct  5 20:28:08 1998
+++ linux.14p16/include/linux/errqueue.h	Mon Dec 13 18:50:28 1999
@@ -1,7 +1,9 @@
 #ifndef _LINUX_ERRQUEUE_H
 #define _LINUX_ERRQUEUE_H 1
 
+#ifdef __KERNEL__
 #include <linux/config.h>
+#endif
 
 struct sock_extended_err
 {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/fb.h linux.14p16/include/linux/fb.h
--- linux.vanilla/include/linux/fb.h	Sat Aug 14 02:26:01 1999
+++ linux.14p16/include/linux/fb.h	Thu Dec  9 15:32:49 1999
@@ -26,6 +26,7 @@
 /* #define FBIOSWITCH_MONIBIT	0x460E */
 #define FBIOGET_CON2FBMAP	0x460F
 #define FBIOPUT_CON2FBMAP	0x4610
+#define FBIOBLANK		0x4611		/* arg: 0 or vesa level + 1 */
 
 #define FB_TYPE_PACKED_PIXELS		0	/* Packed Pixels	*/
 #define FB_TYPE_PLANES			1	/* Non interleaved planes */
@@ -72,6 +73,7 @@
 #define FB_ACCEL_SUN_BWTWO	23	/* Sun bwtwo			 */
 #define FB_ACCEL_SUN_CGTHREE	24	/* Sun cgthree			 */
 #define FB_ACCEL_SUN_TCX	25	/* Sun tcx			 */
+#define FB_ACCEL_MATROX_MGAG400 26	/* Matrox G400                   */
 
 struct fb_fix_screeninfo {
 	char id[16];			/* identification string eg "TT Builtin" */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/fs.h linux.14p16/include/linux/fs.h
--- linux.vanilla/include/linux/fs.h	Wed Oct 20 01:12:50 1999
+++ linux.14p16/include/linux/fs.h	Mon Dec 13 19:35:54 1999
@@ -753,7 +753,7 @@
 extern int try_to_free_buffers(struct page *);
 
 extern int nr_buffers;
-extern int buffermem;
+extern long buffermem;
 extern int nr_buffer_heads;
 
 #define BUF_CLEAN	0
@@ -783,7 +783,9 @@
 extern int check_disk_change(kdev_t dev);
 extern int invalidate_inodes(struct super_block * sb);
 extern void invalidate_inode_pages(struct inode *);
-extern void invalidate_buffers(kdev_t dev);
+#define invalidate_buffers(dev)	__invalidate_buffers((dev), 0)
+#define destroy_buffers(dev)	__invalidate_buffers((dev), 1)
+extern void __invalidate_buffers(kdev_t dev, int);
 extern int floppy_is_wp(int minor);
 extern void sync_inodes(kdev_t dev);
 extern void write_inode_now(struct inode *inode);
@@ -837,6 +839,7 @@
 extern struct inode * igrab(struct inode *inode);
 extern ino_t iunique(struct super_block *, ino_t);
 extern struct inode * iget(struct super_block *, unsigned long);
+extern struct inode * iget_in_use (struct super_block *, unsigned long);
 extern void clear_inode(struct inode *);
 extern struct inode * get_empty_inode(void);
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/genhd.h linux.14p16/include/linux/genhd.h
--- linux.vanilla/include/linux/genhd.h	Sat Aug 14 02:27:39 1999
+++ linux.14p16/include/linux/genhd.h	Mon Dec 13 19:35:55 1999
@@ -42,7 +42,7 @@
 #endif
 
 #define DM6_PARTITION		0x54	/* has DDO: use xlated geom & offset */
-#define EZD_PARTITION		0x55	/* EZ-DRIVE:  same as DM6 (we think) */
+#define EZD_PARTITION		0x55	/* EZ-DRIVE: remap sector 1 to 0 */
 #define DM6_AUX1PARTITION	0x51	/* no DDO:  use xlated geom */
 #define DM6_AUX3PARTITION	0x53	/* no DDO:  use xlated geom */
 	
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/hfs_fs.h linux.14p16/include/linux/hfs_fs.h
--- linux.vanilla/include/linux/hfs_fs.h	Sat Aug 14 02:26:33 1999
+++ linux.14p16/include/linux/hfs_fs.h	Wed Dec 15 23:16:07 1999
@@ -140,6 +140,19 @@
 			*order[HFS_HDR_MAX];	/* 'descr' ordered by offset */
 };
 
+/* header layout for netatalk's v1 appledouble file format */
+struct hfs_nat_hdr {
+	hfs_lword_t	magic;
+	hfs_lword_t	version;
+	hfs_byte_t	homefs[16];
+	hfs_word_t	entries;
+	hfs_byte_t	descrs[12*5];
+	hfs_byte_t	real_name[255];	/* id=3 */
+	hfs_byte_t	comment[200];	/* id=4 XXX: not yet implemented */
+	hfs_byte_t	old_info[16];	/* id=7 */
+	hfs_u8		finderinfo[32]; /* id=9 */
+};
+
 /* 
  * Default header layout for Netatalk and AppleDouble
  */
@@ -161,7 +174,6 @@
 	hfs_u8          short_name[12]; /* id=13 */
 	hfs_u8          prodosi[8];     /* id=11 */
 };
-
 
 /* finder metadata for CAP */
 struct hfs_cap_info {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/i2c.h linux.14p16/include/linux/i2c.h
--- linux.vanilla/include/linux/i2c.h	Wed Oct 20 01:12:50 1999
+++ linux.14p16/include/linux/i2c.h	Tue Dec 21 00:51:08 1999
@@ -40,6 +40,7 @@
 	/* 2 is used in 2.3.x */
 #define I2C_BUSID_BUZ		3	/* I2C bus on a BUZ */
 #define I2C_BUSID_ZORAN		4	/* I2C bus on a Zoran */
+#define I2C_BUSID_SGIVWFB	5	/* Moved to be unique */
 
 /*
  * struct for a driver for a i2c chip (tuner, soundprocessor,
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/if.h linux.14p16/include/linux/if.h
--- linux.vanilla/include/linux/if.h	Mon Dec 28 06:18:31 1998
+++ linux.14p16/include/linux/if.h	Mon Dec 13 19:37:34 1999
@@ -45,31 +45,6 @@
 #define IFF_AUTOMEDIA	0x4000		/* auto media select active	*/
 #define IFF_DYNAMIC	0x8000		/* dialup device with changing addresses*/
 
-#ifdef __KERNEL__
-/*
- * The ifaddr structure contains information about one address
- * of an interface.  They are maintained by the different address
- * families, are allocated and attached when an address is set,
- * and are linked together so all addresses for an interface can
- * be located.
- */
- 
-struct ifaddr 
-{
-	struct sockaddr	ifa_addr;	/* address of interface		*/
-	union {
-		struct sockaddr	ifu_broadaddr;
-		struct sockaddr	ifu_dstaddr;
-	} ifa_ifu;
-	struct iface		*ifa_ifp;	/* back-pointer to interface	*/
-	struct ifaddr		*ifa_next;	/* next address for interface	*/
-};
-
-#define	ifa_broadaddr	ifa_ifu.ifu_broadaddr	/* broadcast address	*/
-#define	ifa_dstaddr	ifa_ifu.ifu_dstaddr	/* other end of link	*/
-
-#endif /* __KERNEL__ */ 
-
 /*
  *	Device mapping structure. I'd just gone off and designed a 
  *	beautiful scheme using only loadable modules with arguments
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/inetdevice.h linux.14p16/include/linux/inetdevice.h
--- linux.vanilla/include/linux/inetdevice.h	Mon Jan  4 23:31:35 1999
+++ linux.14p16/include/linux/inetdevice.h	Mon Dec 13 18:50:28 1999
@@ -16,6 +16,7 @@
 	int	log_martians;
 	int	forwarding;
 	int	mc_forwarding;
+	int	hidden;
 	void	*sysctl;
 };
 
@@ -40,6 +41,7 @@
 
 #define IN_DEV_LOG_MARTIANS(in_dev)	(ipv4_devconf.log_martians || (in_dev)->cnf.log_martians)
 #define IN_DEV_PROXY_ARP(in_dev)	(ipv4_devconf.proxy_arp || (in_dev)->cnf.proxy_arp)
+#define IN_DEV_HIDDEN(in_dev)		((in_dev)->cnf.hidden && ipv4_devconf.hidden)
 #define IN_DEV_SHARED_MEDIA(in_dev)	(ipv4_devconf.shared_media || (in_dev)->cnf.shared_media)
 #define IN_DEV_TX_REDIRECTS(in_dev)	(ipv4_devconf.send_redirects || (in_dev)->cnf.send_redirects)
 #define IN_DEV_SEC_REDIRECTS(in_dev)	(ipv4_devconf.secure_redirects || (in_dev)->cnf.secure_redirects)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/ip.h linux.14p16/include/linux/ip.h
--- linux.vanilla/include/linux/ip.h	Sun Mar 28 19:04:21 1999
+++ linux.14p16/include/linux/ip.h	Mon Dec 13 19:39:46 1999
@@ -88,6 +88,8 @@
 #define	IPOPT_TS_TSANDADDR	1		/* timestamps and addresses */
 #define	IPOPT_TS_PRESPEC	3		/* specified modules only */
 
+#ifdef __KERNEL__
+
 struct ip_options {
   __u32		faddr;				/* Saved first hop address */
   unsigned char	optlen;
@@ -108,7 +110,6 @@
   unsigned char __data[0];
 };
 
-#ifdef __KERNEL__
 #define optlength(opt) (sizeof(struct ip_options) + opt->optlen)
 #endif
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/isdn.h linux.14p16/include/linux/isdn.h
--- linux.vanilla/include/linux/isdn.h	Wed Oct 20 01:12:50 1999
+++ linux.14p16/include/linux/isdn.h	Wed Dec 15 23:33:00 1999
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.76 1999/09/14 10:16:21 keil Exp $
+/* $Id: isdn.h,v 1.81 1999/10/27 21:21:18 detabc Exp $
  *
  * Main header for the Linux ISDN subsystem (linklevel).
  *
@@ -21,6 +21,31 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn.h,v $
+ * Revision 1.81  1999/10/27 21:21:18  detabc
+ * Added support for building logically-bind-group's per interface.
+ * usefull for outgoing call's with more then one isdn-card.
+ *
+ * Switchable support to dont reset the hangup-timeout for
+ * receive frames. Most part's of the timru-rules for receiving frames
+ * are now obsolete. If the input- or forwarding-firewall deny
+ * the frame, the line will be not hold open.
+ *
+ * Revision 1.80  1999/10/26 21:09:29  armin
+ * New bufferlen for phonenumber only with kernel 2.3.x
+ *
+ * Revision 1.79  1999/10/16 17:52:38  keil
+ * Changing the MSN length need new data versions
+ *
+ * Revision 1.78  1999/10/08 18:59:33  armin
+ * Bugfix of too small MSN buffer and checking phone number
+ * in isdn_tty_getdial()
+ *
+ * Revision 1.77  1999/09/23 22:22:42  detabc
+ * added tcp-keepalive-detect with local response (ipv4 only)
+ * added host-only-interface support
+ * (source ipaddr == interface ipaddr) (ipv4 only)
+ * ok with kernel 2.3.18 and 2.2.12
+ *
  * Revision 1.76  1999/09/14 10:16:21  keil
  * change ABC include
  *
@@ -301,9 +326,13 @@
 #undef CONFIG_ISDN_WITH_ABC_CALLB
 #undef CONFIG_ISDN_WITH_ABC_UDP_CHECK
 #undef CONFIG_ISDN_WITH_ABC_UDP_CHECK_HANGUP
+#undef CONFIG_ISDN_WITH_ABC_UDP_CHECK_DIAL
 #undef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
-#undef CONFIG_ISDN_WITH_ABC_CALL_CHECK_SYNCRO
 #undef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
+#undef CONFIG_ISDN_WITH_ABC_IPV4_TCP_KEEPALIVE
+#undef CONFIG_ISDN_WITH_ABC_IPV4_DYNADDR
+#undef CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
+#undef CONFIG_ISDN_WITH_ABC_ICALL_BIND
 
 
 /* New ioctl-codes */
@@ -363,10 +392,15 @@
 #define ISDN_USAGE_OUTGOING 128 /* This bit is set, if channel is outgoing  */
 
 #define ISDN_MODEM_ANZREG    24        /* Number of Modem-Registers        */
-#define ISDN_MSNLEN          20
 #define ISDN_LMSNLEN         255 /* Length of tty's Listen-MSN string */
 #define ISDN_CMSGLEN	     50	 /* Length of CONNECT-Message to add for Modem */
 
+#define ISDN_MSNLEN          20
+#define NET_DV 0x05  /* Data version for isdn_net_ioctl_cfg   */
+#define TTY_DV 0x05  /* Data version for iprofd etc.          */
+
+#define INF_DV 0x01  /* Data version for /dev/isdninfo        */
+
 typedef struct {
   char drvid[25];
   unsigned long arg;
@@ -384,10 +418,6 @@
   int  outgoing;
 } isdn_net_ioctl_phone;
 
-#define NET_DV 0x05  /* Data version for isdn_net_ioctl_cfg   */
-#define TTY_DV 0x05  /* Data version for iprofd etc.          */
-#define INF_DV 0x01  /* Data version for /dev/isdninfo        */
-
 typedef struct {
   char name[10];     /* Name of interface                     */
   char master[10];   /* Name of Master for Bundling           */
@@ -896,6 +926,7 @@
 } isdn_dev;
 
 extern isdn_dev *dev;
+
 
 
 /* Utility-Macros */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/isdnif.h linux.14p16/include/linux/isdnif.h
--- linux.vanilla/include/linux/isdnif.h	Wed Oct 20 01:12:50 1999
+++ linux.14p16/include/linux/isdnif.h	Wed Dec 15 23:33:00 1999
@@ -1,4 +1,4 @@
-/* $Id: isdnif.h,v 1.31 1999/09/06 07:29:36 fritz Exp $
+/* $Id: isdnif.h,v 1.32 1999/10/11 22:03:00 keil Exp $
  *
  * Linux ISDN subsystem
  *
@@ -22,6 +22,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdnif.h,v $
+ * Revision 1.32  1999/10/11 22:03:00  keil
+ * COMPAT_NEED_UACCESS (no include in isdn_compat.h)
+ *
  * Revision 1.31  1999/09/06 07:29:36  fritz
  * Changed my mail-address.
  *
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/joystick.h linux.14p16/include/linux/joystick.h
--- linux.vanilla/include/linux/joystick.h	Sun Mar 28 19:04:27 1999
+++ linux.14p16/include/linux/joystick.h	Tue Dec 21 00:51:08 1999
@@ -4,7 +4,9 @@
 /*
  * /usr/include/linux/joystick.h  Version 1.2
  *
- * Copyright (C) 1996-1998 Vojtech Pavlik
+ * Copyright (C) 1996-1999 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
  */
 
 /*
@@ -23,7 +25,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  */
 
@@ -34,7 +36,7 @@
  * Version
  */
 
-#define JS_VERSION		0x01020d
+#define JS_VERSION		0x01020f
 
 /*
  * Types and constants for reading from /dev/js
@@ -128,75 +130,62 @@
 
 #include <linux/version.h>
 
-#ifndef KERNEL_VERSION
-#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
+#error "You need to use at least v2.2 Linux kernel."
 #endif
 
-#ifndef LINUX_VERSION_CODE
-#error "You need to use at least 2.0 Linux kernel."
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,0,0)
-#error "You need to use at least 2.0 Linux kernel."
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-#define JS_HAS_RDTSC (current_cpu_data.x86_capability & 0x10)
-#include <linux/init.h>
-#else
-#ifdef MODULE
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,35)
-#define JS_HAS_RDTSC (x86_capability & 0x10)
-#else
-#define JS_HAS_RDTSC 0
-#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#include <asm/spinlock.h>
+typedef struct wait_queue *wait_queue_head_t;
+#define __setup(a,b)
+#define BASE_ADDRESS(x,i)	((x)->base_address[i])
+#define DECLARE_WAITQUEUE(x,y)	struct wait_queue x = { y, NULL }
+#define init_waitqueue_head(x)	do { *(x) = NULL; } while (0)
+#define __set_current_state(x)	current->state = x
+#define SETUP_PARAM		char *str, int *ints
+#define SETUP_PARSE(x)		do {} while (0)
 #else
-#define JS_HAS_RDTSC (x86_capability & 0x10)
-#endif
-#define __initdata
-#define __init
-#define __cli cli
-#define __save_flags(flags) save_flags(flags)
-#define __restore_flags(flags)	restore_flags(flags)
-#define spin_lock_irqsave(x, flags) do { save_flags(flags); cli(); } while (0)
-#define spin_unlock_irqrestore(x, flags) restore_flags(flags)
-#define spin_lock_init(x) do { } while (0)
-typedef struct { int something; } spinlock_t;
-#define SPIN_LOCK_UNLOCKED { 0 }
-#define MODULE_AUTHOR(x)
-#define MODULE_PARM(x,y)
-#define MODULE_SUPPORTED_DEVICE(x)
-#define signal_pending(x) (((x)->signal) & ~((x)->blocked))
+#include <linux/spinlock.h>
+#define BASE_ADDRESS(x,i)	((x)->resource[i].start)
+#define SETUP_PARAM		char *str
+#define SETUP_PARSE(x)		int ints[x]; get_options(str, x, ints)
 #endif
 
+#define PCI_VENDOR_ID_AUREAL	0x12eb
+
 /*
  * Parport stuff
  */
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-#define USE_PARPORT
-#endif
-
-#ifdef USE_PARPORT
 #include <linux/parport.h>
+
+#define JS_PAR_STATUS_INVERT	(0x80)
+#define JS_PAR_CTRL_INVERT	(0x04)
 #define JS_PAR_DATA_IN(y)	parport_read_data(y->port)
 #define JS_PAR_DATA_OUT(x,y)	parport_write_data(y->port, x)
 #define JS_PAR_STATUS(y)	parport_read_status(y->port)
+
+#ifndef PARPORT_NEED_GENERIC_OPS
 #define JS_PAR_CTRL_IN(y)	parport_read_control(y->port)
+#else
+#define JS_PAR_CTRL_IN(y)	inb(y->port->base+2) 
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
 #define JS_PAR_CTRL_OUT(x,y)	parport_write_control(y->port, x)
 #define JS_PAR_ECTRL_OUT(x,y)	parport_write_econtrol(y->port, x)
 #else
-#define JS_PAR_DATA_IN(y)	inb(y)
-#define JS_PAR_DATA_OUT(x,y)	outb(x,y)
-#define JS_PAR_STATUS(y)	inb(y+1)
-#define JS_PAR_CTRL_IN(y)	inb(y+2)
-#define JS_PAR_CTRL_OUT(x,y)	outb(x,y+2)
-#define JS_PAR_ECTRL_OUT(x,y)	outb(x,y+0x402)
+#define JS_PAR_CTRL_OUT(x,y)					\
+	do {							\
+		if ((x) & 0x20) parport_data_reverse(y->port);	\
+		else parport_data_forward(y->port);		\
+		parport_write_control(y->port, (x) & ~0x20);	\
+	} while (0)
+#define JS_PAR_ECTRL_OUT(x,y)	/*parport sets PS/2 mode on ECR chips */
+#define PARPORT_MODE_PCPS2	PARPORT_MODE_TRISTATE
+#define PARPORT_MODE_PCECPPS2	PARPORT_MODE_TRISTATE
 #endif
 
-#define JS_PAR_STATUS_INVERT	(0x80)
-#define JS_PAR_CTRL_INVERT	(0x04)
-
 /*
  * Internal types
  */
@@ -204,8 +193,6 @@
 struct js_dev;
 
 typedef int (*js_read_func)(void *info, int **axes, int **buttons);
-typedef unsigned int (*js_time_func)(void);
-typedef int (*js_delta_func)(unsigned int x, unsigned int y);
 typedef int (*js_ops_func)(struct js_dev *dev);
 
 struct js_data {
@@ -217,7 +204,7 @@
 	struct js_dev *next;
 	struct js_list *list;
 	struct js_port *port;
-	struct wait_queue *wait;
+	wait_queue_head_t wait;
 	struct js_data cur;
 	struct js_data new;
 	struct js_corr *corr;
@@ -249,20 +236,14 @@
 	struct js_corr **corr;
 	void *info;
 	int ndevs;
+	int fail;
+	int total;
 };
 
 /*
  * Sub-module interface
  */
 
-extern unsigned int js_time_speed;
-extern js_time_func js_get_time;
-extern js_delta_func js_delta;
-
-extern unsigned int js_time_speed_a;
-extern js_time_func js_get_time_a;
-extern js_delta_func js_delta_a;
-
 extern struct js_port *js_register_port(struct js_port *port, void *info,
 	int devs, int infos, js_read_func read);
 extern struct js_port *js_unregister_port(struct js_port *port);
@@ -280,19 +261,19 @@
 extern int js_an_init(void);
 extern int js_as_init(void);
 extern int js_console_init(void);
+extern int js_cr_init(void);
 extern int js_db9_init(void);
 extern int js_gr_init(void);
 extern int js_l4_init(void);
 extern int js_lt_init(void);
+extern int js_mag_init(void);
+extern int js_pci_init(void);
 extern int js_sw_init(void);
+extern int js_sball_init(void);
+extern int js_orb_init(void);
 extern int js_tm_init(void);
-
-extern void js_am_setup(char *str, int *ints);
-extern void js_an_setup(char *str, int *ints);
-extern void js_as_setup(char *str, int *ints);
-extern void js_console_setup(char *str, int *ints);
-extern void js_db9_setup(char *str, int *ints);
-extern void js_l4_setup(char *str, int *ints);
+extern int js_tg_init(void);
+extern int js_war_init(void);
 
 #endif /* __KERNEL__ */
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/lockd/syscall.h linux.14p16/include/linux/lockd/syscall.h
--- linux.vanilla/include/linux/lockd/syscall.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/linux/lockd/syscall.h	Mon Dec 13 19:39:04 1999
@@ -0,0 +1,26 @@
+/*
+ * include/linux/lockd/syscall.h
+ *
+ * This file holds all declarations for the knfsd/lockd syscall
+ * interface.
+ *
+ */
+
+#ifndef LOCKD_SYSCALL_H
+#define LOCKD_SYSCALL_H
+
+#include <linux/nfsd/syscall.h>
+
+#define LOCKDCTL_SVC NFSCTL_LOCKD
+
+#ifdef __KERNEL__
+/*
+ * Kernel syscall implementation.
+ */
+#if defined(CONFIG_LOCKD) || defined(CONFIG_LOCKD_MODULE)
+extern int	lockdctl(int, void *, void *);
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* LOCKD_SYSCALL_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/lp.h linux.14p16/include/linux/lp.h
--- linux.vanilla/include/linux/lp.h	Sat Aug 14 02:26:51 1999
+++ linux.14p16/include/linux/lp.h	Thu Dec  9 15:32:48 1999
@@ -19,7 +19,7 @@
 #define LP_NOPA  0x0010
 #define LP_ERR   0x0020
 #define LP_ABORT 0x0040
-#define LP_CAREFUL 0x0080 /* obsoleted -arca */
+#define LP_CAREFUL 0x0080
 #define LP_ABORTOPEN 0x0100
 #define	LP_TRUST_IRQ 0x0200
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/major.h linux.14p16/include/linux/major.h
--- linux.vanilla/include/linux/major.h	Sat Aug 28 20:00:59 1999
+++ linux.14p16/include/linux/major.h	Wed Dec 15 22:23:53 1999
@@ -105,7 +105,11 @@
 #define SPECIALIX_NORMAL_MAJOR 75
 #define SPECIALIX_CALLOUT_MAJOR 76
 
+#define DASD_MAJOR      94	/* Official assignations from Peter */
+
 #define LVM_CHAR_MAJOR	109	/* Logical Volume Manager */
+
+#define MDISK_MAJOR     95	/* Official assignations from Peter */
 
 #define AURORA_MAJOR 79
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/mm.h linux.14p16/include/linux/mm.h
--- linux.vanilla/include/linux/mm.h	Sat Aug 28 20:00:59 1999
+++ linux.14p16/include/linux/mm.h	Wed Dec 15 23:12:57 1999
@@ -292,7 +292,7 @@
 
 extern void vmtruncate(struct inode * inode, unsigned long offset);
 extern int handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access);
-extern void make_pages_present(unsigned long addr, unsigned long end);
+extern int make_pages_present(unsigned long addr, unsigned long end);
 
 extern int pgt_cache_water[2];
 extern int check_pgt_cache(void);
@@ -300,7 +300,6 @@
 extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem);
 extern void mem_init(unsigned long start_mem, unsigned long end_mem);
 extern void show_mem(void);
-extern void oom(struct task_struct * tsk);
 extern void si_meminfo(struct sysinfo * val);
 
 /* mmap.c */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/msg.h linux.14p16/include/linux/msg.h
--- linux.vanilla/include/linux/msg.h	Mon Dec 28 06:19:28 1998
+++ linux.14p16/include/linux/msg.h	Mon Dec 13 19:41:49 1999
@@ -49,6 +49,7 @@
 #define MSGMNI   128   /* <= 1K */     /* max # of msg queue identifiers */
 #define MSGMAX  4056   /* <= 4056 */   /* max size of message (bytes) */
 #define MSGMNB 16384   /* ? */        /* default max size of a message queue */
+#define MSGQNUM 1024   /* <=65535 */	  /* Max messages in flight / queue */
 
 /* unused */
 #define MSGPOOL (MSGMNI*MSGMNB/1024)  /* size in kilobytes of message pool */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/netdevice.h linux.14p16/include/linux/netdevice.h
--- linux.vanilla/include/linux/netdevice.h	Sat Aug 28 20:00:59 1999
+++ linux.14p16/include/linux/netdevice.h	Wed Dec 15 23:14:06 1999
@@ -24,7 +24,9 @@
 #ifndef _LINUX_NETDEVICE_H
 #define _LINUX_NETDEVICE_H
 
+#ifdef __KERNEL__
 #include <linux/config.h>
+#endif
 #include <linux/if.h>
 #include <linux/if_ether.h>
 #include <linux/if_packet.h>
@@ -266,6 +268,9 @@
 	struct Qdisc		*qdisc_list;
 	unsigned long		tx_queue_len;	/* Max frames per queue allowed */
 
+	/* Bridge stuff */
+	int			bridge_port_id;		
+	
 	/* Pointers to interface service routines.	*/
 	int			(*open)(struct device *dev);
 	int			(*stop)(struct device *dev);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/nfsd/nfsfh.h linux.14p16/include/linux/nfsd/nfsfh.h
--- linux.vanilla/include/linux/nfsd/nfsfh.h	Wed Oct 20 01:12:51 1999
+++ linux.14p16/include/linux/nfsd/nfsfh.h	Mon Dec 13 19:39:03 1999
@@ -107,6 +107,7 @@
 void	fh_put(struct svc_fh *);
 void	nfsd_fh_flush(kdev_t);
 void	nfsd_fh_init(void);
+void	nfsd_fh_shutdown(void);
 void	nfsd_fh_free(void);
 
 void	expire_all(void);
@@ -181,6 +182,11 @@
 		up(&inode->i_sem);
 	}
 }
+
+/*
+ * This is a long term cache to help find renamed files.
+ */
+void add_to_rename_cache(ino_t new_dirino, kdev_t dev, ino_t dirino, ino_t ino);
 
 #endif /* __KERNEL__ */
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/nfsd/stats.h linux.14p16/include/linux/nfsd/stats.h
--- linux.vanilla/include/linux/nfsd/stats.h	Wed Nov 26 21:08:38 1997
+++ linux.14p16/include/linux/nfsd/stats.h	Thu Dec  9 15:32:49 1999
@@ -18,6 +18,7 @@
 	unsigned int	fh_fixup;	/* dentry fixup validated */
 	unsigned int	fh_lookup;	/* new lookup required */
 	unsigned int	fh_stale;	/* FH stale error */
+	unsigned int    fh_concurrent;	/* concurrent request */
 };
 
 #ifdef __KERNEL__
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/nfsd/syscall.h linux.14p16/include/linux/nfsd/syscall.h
--- linux.vanilla/include/linux/nfsd/syscall.h	Mon Dec 28 22:10:01 1998
+++ linux.14p16/include/linux/nfsd/syscall.h	Mon Dec 13 19:39:04 1999
@@ -35,6 +35,9 @@
 #define NFSCTL_GETFH		6	/* get an fh by ino (used by mountd) */
 #define NFSCTL_GETFD		7	/* get an fh by path (used by mountd) */
 
+/* Above this is for lockd. */
+#define NFSCTL_LOCKD		0x10000
+
 /* SVC */
 struct nfsctl_svc {
 	unsigned short		svc_port;
@@ -121,11 +124,7 @@
 /*
  * Kernel syscall implementation.
  */
-#if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
 extern asmlinkage int	sys_nfsservctl(int, void *, void *);
-#else
-#define sys_nfsservctl		sys_ni_syscall
-#endif
 extern int		exp_addclient(struct nfsctl_client *ncp);
 extern int		exp_delclient(struct nfsctl_client *ncp);
 extern int		exp_export(struct nfsctl_export *nxp);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/openpic.h linux.14p16/include/linux/openpic.h
--- linux.vanilla/include/linux/openpic.h	Fri Mar 19 18:51:42 1999
+++ linux.14p16/include/linux/openpic.h	Thu Dec  9 15:32:49 1999
@@ -50,10 +50,9 @@
      *  Vector numbers
      */
 
-#define OPENPIC_VEC_SOURCE      0x10    /* and up */
-#define OPENPIC_VEC_TIMER       0x40    /* and up */
-#define OPENPIC_VEC_IPI         0x50    /* and up */
-#define OPENPIC_VEC_SPURIOUS    99
+#define OPENPIC_VEC_TIMER       64    /* and up */
+#define OPENPIC_VEC_IPI         70    /* and up */
+#define OPENPIC_VEC_SPURIOUS    127
 
 
     /*
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/pagemap.h linux.14p16/include/linux/pagemap.h
--- linux.vanilla/include/linux/pagemap.h	Wed Oct 20 01:12:51 1999
+++ linux.14p16/include/linux/pagemap.h	Wed Dec 15 23:12:57 1999
@@ -38,11 +38,15 @@
  */
 #define page_cache_entry(x)	(mem_map + MAP_NR(x))
 
-#define PAGE_HASH_BITS 12
-#define PAGE_HASH_SIZE (1 << PAGE_HASH_BITS)
+#define PAGE_HASH_BITS page_hash_bits
+#define PAGE_HASH_MASK page_hash_mask
 
 extern unsigned long page_cache_size; /* # of pages currently in the hash table */
-extern struct page * page_hash_table[PAGE_HASH_SIZE];
+extern unsigned int page_hash_bits;
+extern unsigned int page_hash_mask;
+extern struct page **page_hash_table;
+
+extern void page_cache_init(unsigned long);
 
 /*
  * We use a power-of-two hash table to avoid a modulus,
@@ -53,12 +57,10 @@
 static inline unsigned long _page_hashfn(struct inode * inode, unsigned long offset)
 {
 #define i (((unsigned long) inode)/(sizeof(struct inode) & ~ (sizeof(struct inode) - 1)))
-#define o (offset >> PAGE_SHIFT)
-#define s(x) ((x)+((x)>>PAGE_HASH_BITS))
-	return s(i+o) & (PAGE_HASH_SIZE-1);
+#define o ((offset >> PAGE_SHIFT) + (offset & ~PAGE_MASK))
+	return ((i+o) & PAGE_HASH_MASK);
 #undef i
 #undef o
-#undef s
 }
 
 #define page_hash(inode,offset) (page_hash_table+_page_hashfn(inode,offset))
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/parport.h linux.14p16/include/linux/parport.h
--- linux.vanilla/include/linux/parport.h	Sun Mar 28 19:04:25 1999
+++ linux.14p16/include/linux/parport.h	Wed Dec 15 23:13:55 1999
@@ -209,6 +209,9 @@
 	spinlock_t pardevice_lock;
 	spinlock_t waitlist_lock;
 	rwlock_t cad_lock;
+
+	/* PCI parallel I/O card support. */
+	unsigned long base_hi;  /* base address (hi - ECR) */
 };
 
 /* parport_register_port registers a new parallel port at the given address (if
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/parport_pc.h linux.14p16/include/linux/parport_pc.h
--- linux.vanilla/include/linux/parport_pc.h	Sat Aug 14 02:26:21 1999
+++ linux.14p16/include/linux/parport_pc.h	Wed Dec 15 23:13:55 1999
@@ -5,14 +5,15 @@
 
 /* --- register definitions ------------------------------- */
 
-#define ECONTROL 0x402
-#define CONFIGB  0x401
-#define CONFIGA  0x400
-#define EPPDATA  0x4
-#define EPPADDR  0x3
-#define CONTROL  0x2
-#define STATUS   0x1
-#define DATA     0
+#define ECONTROL(p) ((p)->base_hi + 0x2)
+#define CONFIGB(p)  ((p)->base_hi + 0x1)
+#define CONFIGA(p)  ((p)->base_hi + 0x0)
+#define FIFO(p)     ((p)->base_hi + 0x0)
+#define EPPDATA(p)  ((p)->base    + 0x4)
+#define EPPADDR(p)  ((p)->base    + 0x3)
+#define CONTROL(p)  ((p)->base    + 0x2)
+#define STATUS(p)   ((p)->base    + 0x1)
+#define DATA(p)     ((p)->base    + 0x0)
 
 /* Private data for PC low-level driver. */
 struct parport_pc_private {
@@ -26,27 +27,27 @@
 
 extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+EPPDATA);
+	outb(d, EPPDATA(p));
 }
 
 extern __inline__ unsigned char parport_pc_read_epp(struct parport *p)
 {
-	return inb(p->base+EPPDATA);
+	return inb(EPPDATA(p));
 }
 
 extern __inline__ void parport_pc_write_epp_addr(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+EPPADDR);
+	outb(d, EPPADDR(p));
 }
 
 extern __inline__ unsigned char parport_pc_read_epp_addr(struct parport *p)
 {
-	return inb(p->base+EPPADDR);
+	return inb(EPPADDR(p));
 }
 
 extern __inline__ int parport_pc_check_epp_timeout(struct parport *p)
 {
-	if (!(inb(p->base+STATUS) & 1))
+	if (!(inb(STATUS(p)) & 1))
 		return 0;
 	parport_pc_epp_clear_timeout(p);
 	return 1;
@@ -54,24 +55,24 @@
 
 extern __inline__ unsigned char parport_pc_read_configb(struct parport *p)
 {
-	return inb(p->base+CONFIGB);
+	return inb(CONFIGB(p));
 }
 
 extern __inline__ void parport_pc_write_data(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+DATA);
+	outb(d, DATA(p));
 }
 
 extern __inline__ unsigned char parport_pc_read_data(struct parport *p)
 {
-	return inb(p->base+DATA);
+	return inb(DATA(p));
 }
 
 extern __inline__ void parport_pc_write_control(struct parport *p, unsigned char d)
 {
 	struct parport_pc_private *priv = p->private_data;
 	priv->ctr = d;/* update soft copy */
-	outb(d, p->base+CONTROL);
+	outb(d, CONTROL(p));
 }
 
 extern __inline__ unsigned char parport_pc_read_control(struct parport *p)
@@ -85,34 +86,34 @@
 	struct parport_pc_private *priv = p->private_data;
 	unsigned char ctr = priv->ctr;
 	ctr = (ctr & ~mask) ^ val;
-	outb (ctr, p->base+CONTROL);
+	outb (ctr, CONTROL(p));
 	return priv->ctr = ctr; /* update soft copy */
 }
 
 extern __inline__ void parport_pc_write_status(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+STATUS);
+	outb(d, STATUS(p));
 }
 
 extern __inline__ unsigned char parport_pc_read_status(struct parport *p)
 {
-	return inb(p->base+STATUS);
+	return inb(STATUS(p));
 }
 
 extern __inline__ void parport_pc_write_econtrol(struct parport *p, unsigned char d)
 {
-	outb(d, p->base+ECONTROL);
+	outb(d, ECONTROL(p));
 }
 
 extern __inline__ unsigned char parport_pc_read_econtrol(struct parport *p)
 {
-	return inb(p->base+ECONTROL);
+	return inb(ECONTROL(p));
 }
 
 extern __inline__ unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask,  unsigned char val)
 {
-	unsigned char old = inb(p->base+ECONTROL);
-	outb(((old & ~mask) ^ val), p->base+ECONTROL);
+	unsigned char old = inb(ECONTROL(p));
+	outb(((old & ~mask) ^ val), ECONTROL(p));
 	return old;
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/pci.h linux.14p16/include/linux/pci.h
--- linux.vanilla/include/linux/pci.h	Wed Oct 20 01:12:51 1999
+++ linux.14p16/include/linux/pci.h	Mon Dec 13 19:35:55 1999
@@ -831,10 +831,10 @@
 #define PCI_DEVICE_ID_ALLIANCE_AT24	0x6424
 #define PCI_DEVICE_ID_ALLIANCE_AT3D	0x643d
 
-#define PCI_VENDOR_ID_SK		0x1148
-#define PCI_DEVICE_ID_SK_FP		0x4000
-#define PCI_DEVICE_ID_SK_TR		0x4200
-#define PCI_DEVICE_ID_SK_GE		0x4300
+#define PCI_VENDOR_ID_SYSKONNECT	0x1148
+#define PCI_DEVICE_ID_SYSKONNECT_FP	0x4000
+#define PCI_DEVICE_ID_SYSKONNECT_TR	0x4200
+#define PCI_DEVICE_ID_SYSKONNECT_GE	0x4300
 
 #define PCI_VENDOR_ID_VMIC		0x114a
 #define PCI_DEVICE_ID_VMIC_VME		0x7587
@@ -993,9 +993,35 @@
 #define PCI_VENDOR_ID_CBOARDS		0x1307
 #define PCI_DEVICE_ID_CBOARDS_DAS1602_16 0x0001
 
+#define PCI_VENDOR_ID_SIIG		0x131f
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_550	0x1010
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_650	0x1011
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_850	0x1012
+#define PCI_DEVICE_ID_SIIG_1P_10x	0x1020
+#define PCI_DEVICE_ID_SIIG_2P_10x	0x1021
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_550	0x1034
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_650	0x1035
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_850	0x1036
+#define PCI_DEVICE_ID_SIIG_1P_20x	0x2020
+#define PCI_DEVICE_ID_SIIG_2P_20x	0x2021
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_550	0x2040
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_650	0x2041
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_850	0x2042
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_550	0x2010
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_650	0x2011
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_850	0x2012
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_550	0x2060
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_650	0x2061
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_850	0x2062
+
 #define PCI_VENDOR_ID_NETGEAR		0x1385
 #define PCI_DEVICE_ID_NETGEAR_GA620	0x620a
 
+#define PCI_VENDOR_ID_LAVA		0x1407
+#define PCI_DEVICE_ID_LAVA_PARALLEL	0x8000
+#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A	0x8002 /* The Lava Dual Parallel is */
+#define PCI_DEVICE_ID_LAVA_DUAL_PAR_B	0x8003 /* two PCI devices on a card */
+
 #define PCI_VENDOR_ID_SYMPHONY		0x1c1c
 #define PCI_DEVICE_ID_SYMPHONY_101	0x0001
 
@@ -1008,6 +1034,9 @@
 #define PCI_DEVICE_ID_3DLABS_DELTA	0x0003
 #define PCI_DEVICE_ID_3DLABS_PERMEDIA	0x0004
 #define PCI_DEVICE_ID_3DLABS_MX		0x0006
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA2	0x0007
+#define PCI_DEVICE_ID_3DLABS_GAMMA	0x0008
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA2V	0x0009
 
 #define PCI_VENDOR_ID_AVANCE		0x4005
 #define PCI_DEVICE_ID_AVANCE_ALG2064	0x2064
@@ -1067,6 +1096,7 @@
 #define PCI_DEVICE_ID_INTEL_82441	0x1237
 #define PCI_DEVICE_ID_INTEL_82380FB	0x124b
 #define PCI_DEVICE_ID_INTEL_82439	0x1250
+#define PCI_DEVICE_ID_INTEL_MEGARAID	0x1960
 #define PCI_DEVICE_ID_INTEL_82371SB_0	0x7000
 #define PCI_DEVICE_ID_INTEL_82371SB_1	0x7010
 #define PCI_DEVICE_ID_INTEL_82371SB_2	0x7020
@@ -1076,17 +1106,19 @@
 #define PCI_DEVICE_ID_INTEL_82371AB	0x7111
 #define PCI_DEVICE_ID_INTEL_82371AB_2	0x7112
 #define PCI_DEVICE_ID_INTEL_82371AB_3	0x7113
-#define PCI_VENDOR_ID_COMPUTONE		0x8e0e
-#define PCI_DEVICE_ID_COMPUTONE_IP2EX	0x0291
-
 #define PCI_DEVICE_ID_INTEL_82443LX_0	0x7180
 #define PCI_DEVICE_ID_INTEL_82443LX_1	0x7181
 #define PCI_DEVICE_ID_INTEL_82443BX_0	0x7190
 #define PCI_DEVICE_ID_INTEL_82443BX_1	0x7191
 #define PCI_DEVICE_ID_INTEL_82443BX_2	0x7192
 #define PCI_DEVICE_ID_INTEL_P6		0x84c4
-#define PCI_DEVICE_ID_INTEL_82450GX	0x84c5
+#define PCI_DEVICE_ID_INTEL_82450GX	0x84c4
+#define PCI_DEVICE_ID_INTEL_82453GX	0x84c5
 #define PCI_DEVICE_ID_INTEL_82451NX	0x84ca
+#define PCI_DEVICE_ID_INTEL_82454NX	0x84cb
+
+#define PCI_VENDOR_ID_COMPUTONE		0x8e0e
+#define PCI_DEVICE_ID_COMPUTONE_IP2EX	0x0291
 
 #define PCI_VENDOR_ID_KTI		0x8e2e
 #define PCI_DEVICE_ID_KTI_ET32P2	0x3000
@@ -1317,6 +1349,9 @@
 
 extern inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn)
 { return NULL; }
+
+extern inline void pci_set_master(struct pci_dev *dev)
+{ return; }
 
 #endif /* !CONFIG_PCI */
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/phonedev.h linux.14p16/include/linux/phonedev.h
--- linux.vanilla/include/linux/phonedev.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/linux/phonedev.h	Tue Dec 21 01:11:39 1999
@@ -0,0 +1,26 @@
+#ifndef __LINUX_PHONEDEV_H
+#define __LINUX_PHONEDEV_H
+
+#include <linux/types.h>
+#include <linux/version.h>
+
+#ifdef __KERNEL__
+
+#include <linux/poll.h>
+
+struct phone_device {
+	struct phone_device *next;
+	struct file_operations *f_op;
+	int (*open) (struct phone_device *, struct file *);
+	int board;		/* Device private index */
+	int minor;
+};
+
+extern int phonedev_init(void);
+#define PHONE_MAJOR	100
+extern int phone_register_device(struct phone_device *, int unit);
+#define PHONE_UNIT_ANY	-1
+extern void phone_unregister_device(struct phone_device *);
+
+#endif
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/proc_fs.h linux.14p16/include/linux/proc_fs.h
--- linux.vanilla/include/linux/proc_fs.h	Wed Oct 20 01:12:51 1999
+++ linux.14p16/include/linux/proc_fs.h	Wed Dec 15 23:12:57 1999
@@ -466,6 +466,7 @@
 extern inline void proc_tty_register_driver(struct tty_driver *driver) {};
 extern inline void proc_tty_unregister_driver(struct tty_driver *driver) {};
 
+extern struct proc_dir_entry proc_root;
 
-#endif
+#endif /* CONFIG_PROC_FS */
 #endif /* _LINUX_PROC_FS_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/rtnetlink.h linux.14p16/include/linux/rtnetlink.h
--- linux.vanilla/include/linux/rtnetlink.h	Sun Mar 21 15:22:00 1999
+++ linux.14p16/include/linux/rtnetlink.h	Mon Dec 13 18:50:28 1999
@@ -1,7 +1,9 @@
 #ifndef __LINUX_RTNETLINK_H
 #define __LINUX_RTNETLINK_H
 
+#ifdef __KERNEL__
 #include <linux/config.h>
+#endif
 #include <linux/netlink.h>
 
 #define RTNL_DEBUG 1
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sched.h linux.14p16/include/linux/sched.h
--- linux.vanilla/include/linux/sched.h	Wed Oct 20 01:12:51 1999
+++ linux.14p16/include/linux/sched.h	Wed Dec 15 23:12:57 1999
@@ -3,7 +3,7 @@
 
 #include <asm/param.h>	/* for HZ */
 
-extern unsigned long event;
+extern unsigned long global_event;
 
 #include <linux/binfmts.h>
 #include <linux/personality.h>
@@ -657,12 +657,12 @@
 	
 	if (nr >= files->max_fdset) {
 		expand = 1;
-		if ((err = expand_fdset(files, nr)))
+		if ((err = expand_fdset(files, nr + 1)))
 			goto out;
 	}
 	if (nr >= files->max_fds) {
 		expand = 1;
-		if ((err = expand_fd_array(files, nr)))
+		if ((err = expand_fd_array(files, nr + 1)))
 			goto out;
 	}
 	err = expand;
@@ -737,6 +737,7 @@
 	add_wait_queue(&wq, &__wait);					\
 	for (;;) {							\
 		current->state = TASK_UNINTERRUPTIBLE;			\
+		mb();							\
 		if (condition)						\
 			break;						\
 		schedule();						\
@@ -760,6 +761,7 @@
 	add_wait_queue(&wq, &__wait);					\
 	for (;;) {							\
 		current->state = TASK_INTERRUPTIBLE;			\
+		mb();							\
 		if (condition)						\
 			break;						\
 		if (!signal_pending(current)) {				\
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sdla_chdlc.h linux.14p16/include/linux/sdla_chdlc.h
--- linux.vanilla/include/linux/sdla_chdlc.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/linux/sdla_chdlc.h	Wed Dec 15 16:11:36 1999
@@ -0,0 +1,808 @@
+/*************************************************************************
+ sdla_chdlc.h	Sangoma Cisco HDLC firmware API definitions
+
+ Author:      	Gideon Hack
+		Nenad Corbic <ncorbic@sangoma.com>	
+
+ Copyright:	(c) 1995-1999 Sangoma Technologies Inc.
+
+		This program is free software; you can redistribute it and/or
+		modify it under the term 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.
+
+===========================================================================
+  Oct 04, 1999  Nenad Corbic    Updated API support
+  Jun 02, 1999  Gideon Hack     Changes for S514 usage.
+  Oct 28, 1998	Jaspreet Singh	Made changes for Dual Port CHDLC.
+  Jun 11, 1998	David Fong	Initial version.
+===========================================================================
+
+ Organization
+	- Compatibility notes
+	- Constants defining the shared memory control block (mailbox)
+	- Interface commands
+	- Return code from interface commands
+	- Constants for the commands (structures for casting data)
+	- UDP Management constants and structures
+
+*************************************************************************/
+
+#ifndef _SDLA_CHDLC_H
+#  define _SDLC_CHDLC_H
+
+/*------------------------------------------------------------------------
+   Notes:
+
+	All structres defined in this file are byte-aligned.  
+
+	Compiler	Platform
+	------------------------
+	GNU C		Linux
+
+------------------------------------------------------------------------*/
+
+#ifndef	PACKED
+#define	PACKED __attribute__((packed))
+#endif	/* PACKED */
+
+
+/* ----------------------------------------------------------------------------
+ *        Constants defining the shared memory control block (mailbox)
+ * --------------------------------------------------------------------------*/
+
+#define PRI_BASE_ADDR_MB_STRUCT 	0xE000 	/* the base address of the mailbox structure on the adapter */
+#define SEC_BASE_ADDR_MB_STRUCT 	0xE800 	/* the base address of the mailbox structure on the adapter */
+#define SIZEOF_MB_DATA_BFR		2032	/* the size of the actual mailbox data area */
+#define NUMBER_MB_RESERVED_BYTES	0x0B	/* the number of reserved bytes in the mailbox header area */
+
+
+#define MIN_LGTH_CHDLC_DATA_CFG  	300 	/* min length of the CHDLC data field (for configuration purposes) */
+#define PRI_MAX_NO_DATA_BYTES_IN_FRAME  15354 /* PRIMARY - max length of the CHDLC data field */
+
+typedef struct {
+	unsigned char opp_flag PACKED;			/* the opp flag */
+	unsigned char command PACKED;			/* the user command */
+	unsigned short buffer_length PACKED;		/* the data length */
+  	unsigned char return_code PACKED;		/* the return code */
+	unsigned char MB_reserved[NUMBER_MB_RESERVED_BYTES] PACKED;	/* reserved for later */
+	unsigned char data[SIZEOF_MB_DATA_BFR] PACKED;	/* the data area */
+} CHDLC_MAILBOX_STRUCT;
+
+typedef struct {
+        pid_t                   pid_num PACKED;
+        CHDLC_MAILBOX_STRUCT     cmdarea PACKED;
+
+} CMDBLOCK_STRUCT;
+
+
+
+
+/* ----------------------------------------------------------------------------
+ *                        Interface commands
+ * --------------------------------------------------------------------------*/
+
+/* global interface commands */
+#define READ_GLOBAL_EXCEPTION_CONDITION	0x01
+#define SET_GLOBAL_CONFIGURATION	0x02
+#define READ_GLOBAL_CONFIGURATION	0x03
+#define READ_GLOBAL_STATISTICS		0x04
+#define FLUSH_GLOBAL_STATISTICS		0x05
+#define SET_MODEM_STATUS		0x06	/* set status of DTR or RTS */
+#define READ_MODEM_STATUS		0x07	/* read status of CTS and DCD */
+#define READ_COMMS_ERROR_STATS		0x08	
+#define FLUSH_COMMS_ERROR_STATS		0x09
+#define SET_TRACE_CONFIGURATION		0x0A	/* set the line trace config */
+#define READ_TRACE_CONFIGURATION	0x0B	/* read the line trace config */
+#define READ_TRACE_STATISTICS		0x0C	/* read the trace statistics */
+#define FLUSH_TRACE_STATISTICS		0x0D	/* flush the trace statistics */
+#define FT1_MONITOR_STATUS_CTRL		0x1C	/* set the status of the S508/FT1 monitoring */
+#define SET_FT1_CONFIGURATION		0x18	/* set the FT1 configuration */
+#define READ_FT1_CONFIGURATION		0x19	/* read the FT1 configuration */
+#define TRANSMIT_ASYNC_DATA_TO_FT1	0x1A	/* output asynchronous data to the FT1 */
+#define RECEIVE_ASYNC_DATA_FROM_FT1	0x1B	/* receive asynchronous data from the FT1 */
+#define FT1_MONITOR_STATUS_CTRL		0x1C	/* set the status of the FT1 monitoring */
+
+#define READ_FT1_OPERATIONAL_STATS	0x1D	/* read the S508/FT1 operational statistics */
+#define SET_FT1_MODE			0x1E	/* set the operational mode of the S508/FT1 module */
+
+/* CHDLC-level interface commands */
+#define READ_CHDLC_CODE_VERSION		0x20	
+#define READ_CHDLC_EXCEPTION_CONDITION	0x21	/* read exception condition from the adapter */
+#define SET_CHDLC_CONFIGURATION		0x22
+#define READ_CHDLC_CONFIGURATION	0x23
+#define ENABLE_CHDLC_COMMUNICATIONS	0x24
+#define DISABLE_CHDLC_COMMUNICATIONS	0x25
+#define READ_CHDLC_LINK_STATUS		0x26
+#define READ_CHDLC_OPERATIONAL_STATS	0x27
+#define FLUSH_CHDLC_OPERATIONAL_STATS	0x28
+#define SET_CHDLC_INTERRUPT_TRIGGERS	0x30	/* set application interrupt triggers */
+#define READ_CHDLC_INTERRUPT_TRIGGERS	0x31	/* read application interrupt trigger configuration */
+
+/* Special UDP drivers management commands */
+#define CPIPE_ENABLE_TRACING				0x50
+#define CPIPE_DISABLE_TRACING				0x51
+#define CPIPE_GET_TRACE_INFO				0x52
+#define CPIPE_GET_IBA_DATA				0x53
+#define CPIPE_FT1_READ_STATUS				0x54
+#define CPIPE_DRIVER_STAT_IFSEND			0x55
+#define CPIPE_DRIVER_STAT_INTR				0x56
+#define CPIPE_DRIVER_STAT_GEN				0x57
+#define CPIPE_FLUSH_DRIVER_STATS			0x58
+#define CPIPE_ROUTER_UP_TIME				0x59
+
+/* Driver specific commands for API */
+#define	CHDLC_READ_TRACE_DATA		0xE4	/* read trace data */
+#define TRACE_ALL                       0x00
+#define TRACE_PROT			0x01
+#define TRACE_DATA			0x02
+
+/* ----------------------------------------------------------------------------
+ *                     Return codes from interface commands
+ * --------------------------------------------------------------------------*/
+
+#define COMMAND_OK				0x00
+
+/* return codes from global interface commands */
+#define NO_GLOBAL_EXCEP_COND_TO_REPORT		0x01	/* there is no CHDLC exception condition to report */
+#define LGTH_GLOBAL_CFG_DATA_INVALID		0x01	/* the length of the passed global configuration data is invalid */
+#define LGTH_TRACE_CFG_DATA_INVALID		0x01	/* the length of the passed trace configuration data is invalid */
+#define IRQ_TIMEOUT_VALUE_INVALID		0x02	/* an invalid application IRQ timeout value was selected */
+#define TRACE_CONFIG_INVALID			0x02	/* the passed line trace configuration is invalid */
+#define ADAPTER_OPERATING_FREQ_INVALID		0x03	/* an invalid adapter operating frequency was selected */
+#define TRC_DEAC_TMR_INVALID			0x03	/* the trace deactivation timer is invalid */
+#define S508_FT1_ADPTR_NOT_PRESENT		0x0C	/* the S508/FT1 adapter is not present */
+#define INVALID_FT1_STATUS_SELECTION            0x0D    /* the S508/FT1 status selection is invalid */
+#define FT1_OP_STATS_NOT_ENABLED		0x0D    /* the FT1 operational statistics have not been enabled */
+#define FT1_OP_STATS_NOT_AVAILABLE		0x0E    /* the FT1 operational statistics are not currently available */
+#define S508_FT1_MODE_SELECTION_BUSY		0x0E	/* the S508/FT1 adapter is busy selecting the operational mode */
+
+/* return codes from command READ_GLOBAL_EXCEPTION_CONDITION */
+#define EXCEP_MODEM_STATUS_CHANGE		0x10		/* a modem status change occurred */
+#define EXCEP_TRC_DISABLED			0x11		/* the trace has been disabled */
+#define EXCEP_IRQ_TIMEOUT			0x12		/* IRQ timeout */
+
+/* return codes from CHDLC-level interface commands */
+#define NO_CHDLC_EXCEP_COND_TO_REPORT		0x21	/* there is no CHDLC exception condition to report */
+#define CHDLC_COMMS_DISABLED			0x21	/* communications are not currently enabled */
+#define CHDLC_COMMS_ENABLED			0x21	/* communications are currently enabled */
+#define DISABLE_CHDLC_COMMS_BEFORE_CFG		0x21	/* CHDLC communications must be disabled before setting the configuration */
+#define ENABLE_CHDLC_COMMS_BEFORE_CONN		0x21	/* communications must be enabled before using the CHDLC_CONNECT conmmand */
+#define CHDLC_CFG_BEFORE_COMMS_ENABLED		0x22	/* perform a SET_CHDLC_CONFIGURATION before enabling comms */
+#define LGTH_CHDLC_CFG_DATA_INVALID 		0x22	/* the length of the passed CHDLC configuration data is invalid */
+#define LGTH_INT_TRIGGERS_DATA_INVALID		0x22	/* the length of the passed interrupt trigger data is invalid */
+#define INVALID_IRQ_SELECTED			0x23	/* in invalid IRQ was selected in the SET_CHDLC_INTERRUPT_TRIGGERS */
+#define INVALID_CHDLC_CFG_DATA			0x23	/* the passed CHDLC configuration data is invalid */
+#define IRQ_TMR_VALUE_INVALID			0x24	/* an invalid application IRQ timer value was selected */
+#define LARGER_PERCENT_TX_BFR_REQUIRED		0x24	/* a larger Tx buffer percentage is required */
+#define LARGER_PERCENT_RX_BFR_REQUIRED		0x25	/* a larger Rx buffer percentage is required */
+#define S514_BOTH_PORTS_SAME_CLK_MODE		0x26	/* S514 - both ports must have same clock mode */
+#define INVALID_CMND_HDLC_STREAM_MODE           0x4E    /* the CHDLC interface command is invalid for HDLC streaming mode */
+#define INVALID_CHDLC_COMMAND			0x4F	/* the defined CHDLC interface command is invalid */
+
+/* return codes from command READ_CHDLC_EXCEPTION_CONDITION */
+#define EXCEP_LINK_ACTIVE			0x30	/* the CHDLC link has become active */
+#define EXCEP_LINK_INACTIVE_MODEM		0x31	/* the CHDLC link has become inactive (modem status) */
+#define EXCEP_LINK_INACTIVE_KPALV		0x32	/* the CHDLC link has become inactive (keepalive status) */
+#define EXCEP_IP_ADDRESS_DISCOVERED		0x33	/* the IP address has been discovered */
+#define EXCEP_LOOPBACK_CONDITION		0x34	/* a loopback condition has occurred */
+
+
+/* return code from command CHDLC_SEND_WAIT and CHDLC_SEND_NO_WAIT */
+#define LINK_DISCONNECTED			0x21
+#define NO_TX_BFRS_AVAIL			0x24
+
+
+/* ----------------------------------------------------------------------------
+ * Constants for the SET_GLOBAL_CONFIGURATION/READ_GLOBAL_CONFIGURATION commands
+ * --------------------------------------------------------------------------*/
+
+/* the global configuration structure */
+typedef struct {
+	unsigned short adapter_config_options PACKED;	/* adapter config options */
+	unsigned short app_IRQ_timeout PACKED;		/* application IRQ timeout */
+	unsigned long adapter_operating_frequency PACKED;	/* adapter operating frequency */
+} GLOBAL_CONFIGURATION_STRUCT;
+
+/* settings for the 'app_IRQ_timeout' */
+#define MAX_APP_IRQ_TIMEOUT_VALUE	5000	/* the maximum permitted IRQ timeout */
+
+
+
+/* ----------------------------------------------------------------------------
+ *             Constants for the READ_GLOBAL_STATISTICS command
+ * --------------------------------------------------------------------------*/
+
+/* the global statistics structure */
+typedef struct {
+	unsigned short app_IRQ_timeout_count PACKED;
+} GLOBAL_STATS_STRUCT;
+
+
+
+/* ----------------------------------------------------------------------------
+ *             Constants for the READ_COMMS_ERROR_STATS command
+ * --------------------------------------------------------------------------*/
+
+/* the communications error statistics structure */
+typedef struct {
+	unsigned short Rx_overrun_err_count PACKED;
+	unsigned short CRC_err_count PACKED;	/* receiver CRC error count */
+	unsigned short Rx_abort_count PACKED; 	/* abort frames recvd count */
+	unsigned short Rx_dis_pri_bfrs_full_count PACKED;/* receiver disabled */
+	unsigned short comms_err_stat_reserved_1 PACKED;/* reserved for later */
+	unsigned short sec_Tx_abort_msd_Tx_int_count PACKED; /* secondary - abort frames transmitted count (missed Tx interrupt) */
+	unsigned short missed_Tx_und_int_count PACKED;	/* missed tx underrun interrupt count */
+        unsigned short sec_Tx_abort_count PACKED;   /*secondary-abort frames tx count */
+	unsigned short DCD_state_change_count PACKED; /* DCD state change */
+	unsigned short CTS_state_change_count PACKED; /* CTS state change */
+} COMMS_ERROR_STATS_STRUCT;
+
+
+
+/* ----------------------------------------------------------------------------
+ *                  Constants used for line tracing
+ * --------------------------------------------------------------------------*/
+
+/* the trace configuration structure (SET_TRACE_CONFIGURATION/READ_TRACE_CONFIGURATION commands) */
+typedef struct {
+	unsigned char trace_config PACKED;		/* trace configuration */
+	unsigned short trace_deactivation_timer PACKED;	/* trace deactivation timer */
+	unsigned long ptr_trace_stat_el_cfg_struct PACKED;	/* a pointer to the line trace element configuration structure */
+} LINE_TRACE_CONFIG_STRUCT;
+
+/* 'trace_config' bit settings */
+#define TRACE_INACTIVE		0x00	/* trace is inactive */
+#define TRACE_ACTIVE		0x01	/* trace is active */
+#define TRACE_DELAY_MODE	0x04	/* operate the trace in delay mode */
+#define TRACE_DATA_FRAMES	0x08	/* trace Data frames */
+#define TRACE_SLARP_FRAMES	0x10	/* trace SLARP frames */
+#define TRACE_CDP_FRAMES	0x20	/* trace CDP frames */
+
+/* the line trace status element configuration structure */
+typedef struct {
+	unsigned short number_trace_status_elements PACKED;	/* number of line trace elements */
+	unsigned long base_addr_trace_status_elements PACKED;	/* base address of the trace element list */
+	unsigned long next_trace_element_to_use PACKED;	/* pointer to the next trace element to be used */
+	unsigned long base_addr_trace_buffer PACKED;		/* base address of the trace data buffer */
+	unsigned long end_addr_trace_buffer PACKED;		/* end address of the trace data buffer */
+} TRACE_STATUS_EL_CFG_STRUCT;
+
+/* the line trace status element structure */
+typedef struct {
+	unsigned char opp_flag PACKED;			/* opp flag */
+	unsigned short trace_length PACKED;		/* trace length */
+	unsigned char trace_type PACKED;		/* trace type */
+	unsigned short trace_time_stamp PACKED;	/* time stamp */
+	unsigned short trace_reserved_1 PACKED;	/* reserved for later use */
+	unsigned long trace_reserved_2 PACKED;		/* reserved for later use */
+	unsigned long ptr_data_bfr PACKED;		/* ptr to the trace data buffer */
+} TRACE_STATUS_ELEMENT_STRUCT;
+
+/* "trace_type" bit settings */
+#define TRACE_INCOMING 			0x00
+#define TRACE_OUTGOINGING 		0x01
+#define TRACE_INCOMING_ABORTED 		0x10
+#define TRACE_INCOMING_CRC_ERROR 	0x20
+#define TRACE_INCOMING_OVERRUN_ERROR 	0x40
+
+
+
+/* the line trace statistics structure */
+typedef struct {
+	unsigned long frames_traced_count PACKED;	/* number of frames traced */
+	unsigned long trc_frms_not_recorded_count PACKED;	/* number of trace frames discarded */
+} LINE_TRACE_STATS_STRUCT;
+
+
+/* ----------------------------------------------------------------------------
+ *               Constants for the FT1_MONITOR_STATUS_CTRL command
+ * --------------------------------------------------------------------------*/
+
+#define DISABLE_FT1_STATUS_STATISTICS	0x00    /* disable the FT1 status and statistics monitoring */
+#define ENABLE_READ_FT1_STATUS		0x01    /* read the FT1 operational status */
+#define ENABLE_READ_FT1_OP_STATS	0x02    /* read the FT1 operational statistics */
+#define FLUSH_FT1_OP_STATS		0x04 	/* flush the FT1 operational statistics */
+
+
+
+
+/* ----------------------------------------------------------------------------
+ *               Constants for the SET_CHDLC_CONFIGURATION command
+ * --------------------------------------------------------------------------*/
+
+/* the CHDLC configuration structure */
+typedef struct {
+	unsigned long baud_rate PACKED;		/* the baud rate */	
+	unsigned short line_config_options PACKED;	/* line configuration options */
+	unsigned short modem_config_options PACKED;	/* modem configration options */
+	unsigned short modem_status_timer PACKED;	/* timer for monitoring modem status changes */
+	unsigned short CHDLC_API_options PACKED;	/* CHDLC API options */
+	unsigned short CHDLC_protocol_options PACKED;	/* CHDLC protocol options */
+	unsigned short percent_data_buffer_for_Tx PACKED;	/* percentage data buffering used for Tx */
+	unsigned short CHDLC_statistics_options PACKED;	/* CHDLC operational statistics options */
+	unsigned short max_CHDLC_data_field_length PACKED;	/* the maximum length of the CHDLC Data field */
+	unsigned short transmit_keepalive_timer PACKED;		/* the transmit keepalive timer */
+	unsigned short receive_keepalive_timer PACKED;		/* the receive keepalive timer */
+	unsigned short keepalive_error_tolerance PACKED;	/* the receive keepalive error tolerance */
+	unsigned short SLARP_request_timer PACKED;		/* the SLARP request timer */
+	unsigned long IP_address PACKED;			/* the IP address */
+	unsigned long IP_netmask PACKED;			/* the IP netmask */
+	unsigned long ptr_shared_mem_info_struct PACKED;	/* a pointer to the shared memory area information structure */
+	unsigned long ptr_CHDLC_Tx_stat_el_cfg_struct PACKED;	/* a pointer to the transmit status element configuration structure */
+	unsigned long ptr_CHDLC_Rx_stat_el_cfg_struct PACKED;	/* a pointer to the receive status element configuration structure */
+} CHDLC_CONFIGURATION_STRUCT;
+
+/* settings for the 'line_config_options' */
+#define INTERFACE_LEVEL_V35					0x0000 /* V.35 interface level */
+#define INTERFACE_LEVEL_RS232					0x0001 /* RS-232 interface level */
+
+/* settings for the 'modem_config_options' */
+
+#define DONT_RAISE_DTR_RTS_ON_EN_COMMS		0x0001
+/* don't automatically raise DTR and RTS when performing an
+   ENABLE_CHDLC_COMMUNICATIONS command */
+
+#define DONT_REPORT_CHG_IN_MODEM_STAT 		0x0002
+/* don't report changes in modem status to the application */
+
+
+/* bit settings for the 'CHDLC_protocol_options' byte */
+
+#define IGNORE_DCD_FOR_LINK_STAT		0x0001
+/* ignore DCD in determining the CHDLC link status */
+
+#define IGNORE_CTS_FOR_LINK_STAT		0x0002
+/* ignore CTS in determining the CHDLC link status */
+
+#define IGNORE_KPALV_FOR_LINK_STAT		0x0004
+/* ignore keepalive frames in determining the CHDLC link status */ 
+
+#define HDLC_STREAMING_MODE			0x8000
+
+/*   settings for the 'CHDLC_statistics_options' */
+
+#define CHDLC_TX_DATA_BYTE_COUNT_STAT		0x0001
+/* record the number of Data bytes transmitted */
+
+#define CHDLC_RX_DATA_BYTE_COUNT_STAT		0x0002
+/* record the number of Data bytes received */
+
+#define CHDLC_TX_THROUGHPUT_STAT		0x0004
+/* compute the Data frame transmit throughput */
+
+#define CHDLC_RX_THROUGHPUT_STAT		0x0008
+/* compute the Data frame receive throughput */
+
+
+/* permitted minimum and maximum values for setting the CHDLC configuration */
+#define PRI_MAX_BAUD_RATE_S508	2666666 /* PRIMARY   - maximum baud rate (S508) */
+#define SEC_MAX_BAUD_RATE_S508	258064 	/* SECONDARY - maximum baud rate (S508) */
+#define PRI_MAX_BAUD_RATE_S514  2750000 /* PRIMARY   - maximum baud rate (S508) */
+#define SEC_MAX_BAUD_RATE_S514  515625  /* SECONDARY - maximum baud rate (S508) */
+ 
+#define MIN_MODEM_TIMER	0			/* minimum modem status timer */
+#define MAX_MODEM_TIMER	5000			/* maximum modem status timer */
+
+#define SEC_MAX_NO_DATA_BYTES_IN_FRAME  2048 /* SECONDARY - max length of the CHDLC data field */
+
+#define MIN_Tx_KPALV_TIMER	0	  /* minimum transmit keepalive timer */
+#define MAX_Tx_KPALV_TIMER	60000	  /* maximum transmit keepalive timer */
+#define DEFAULT_Tx_KPALV_TIMER	10000	  /* default transmit keepalive timer */
+
+#define MIN_Rx_KPALV_TIMER	10	  /* minimum receive keepalive timer */
+#define MAX_Rx_KPALV_TIMER	60000	  /* maximum receive keepalive timer */
+#define DEFAULT_Rx_KPALV_TIMER	10000	  /* default receive keepalive timer */
+
+#define MIN_KPALV_ERR_TOL	1	  /* min kpalv error tolerance count */
+#define MAX_KPALV_ERR_TOL	20	  /* max kpalv error tolerance count */
+#define DEFAULT_KPALV_ERR_TOL	3	  /* default value */
+
+#define MIN_SLARP_REQ_TIMER	0	  /* min transmit SLARP Request timer */
+#define MAX_SLARP_REQ_TIMER	60000	  /* max transmit SLARP Request timer */
+#define DEFAULT_SLARP_REQ_TIMER	0	  /* default value -- no SLARP */
+
+
+
+/* ----------------------------------------------------------------------------
+ *             Constants for the READ_CHDLC_LINK_STATUS command
+ * --------------------------------------------------------------------------*/
+
+/* the CHDLC status structure */
+typedef struct {
+	unsigned char CHDLC_link_status PACKED;	/* CHDLC link status */
+	unsigned char no_Data_frms_for_app PACKED;	/* number of Data frames available for the application */
+	unsigned char receiver_status PACKED;	/* enabled/disabled */
+	unsigned char SLARP_state PACKED;	/* internal SLARP state */
+} CHDLC_LINK_STATUS_STRUCT;
+
+/* settings for the 'CHDLC_link_status' variable */
+#define CHDLC_LINK_INACTIVE		0x00	/* the CHDLC link is inactive */
+#define CHDLC_LINK_ACTIVE		0x01	/* the CHDLC link is active */
+
+
+
+/* ----------------------------------------------------------------------------
+ *           Constants for the READ_CHDLC_OPERATIONAL_STATS command
+ * --------------------------------------------------------------------------*/
+
+/* the CHDLC operational statistics structure */
+typedef struct {
+
+	/* Data frame transmission statistics */
+	unsigned long Data_frames_Tx_count PACKED;	/* # of frames transmitted */
+	unsigned long Data_bytes_Tx_count PACKED; 	/* # of bytes transmitted */
+	unsigned long Data_Tx_throughput PACKED;	/* transmit throughput */
+	unsigned long no_ms_for_Data_Tx_thruput_comp PACKED;	/* millisecond time used for the Tx throughput computation */
+	unsigned long Tx_Data_discard_lgth_err_count PACKED;	/* number of Data frames discarded (length error) */
+	unsigned long reserved_Data_frm_Tx_stat1 PACKED;	/* reserved for later */
+	unsigned long reserved_Data_frm_Tx_stat2 PACKED;	/* reserved for later */
+	unsigned long reserved_Data_frm_Tx_stat3 PACKED;	/* reserved for later */
+
+	/* Data frame reception statistics */
+	unsigned long Data_frames_Rx_count PACKED;	/* number of frames received */
+	unsigned long Data_bytes_Rx_count PACKED;	/* number of bytes received */
+	unsigned long Data_Rx_throughput PACKED;	/* receive throughput */
+	unsigned long no_ms_for_Data_Rx_thruput_comp PACKED;	/* millisecond time used for the Rx throughput computation */
+	unsigned long Rx_Data_discard_short_count PACKED;	/* received Data frames discarded (too short) */
+	unsigned long Rx_Data_discard_long_count PACKED;	/* received Data frames discarded (too long) */
+	unsigned long Rx_Data_discard_inactive_count PACKED;	/* received Data frames discarded (link inactive) */
+	unsigned long reserved_Data_frm_Rx_stat1 PACKED;	/* reserved for later */
+
+	/* SLARP frame transmission/reception statistics */
+	unsigned long CHDLC_SLARP_REQ_Tx_count PACKED;		/* number of SLARP Request frames transmitted */
+	unsigned long CHDLC_SLARP_REQ_Rx_count PACKED;		/* number of SLARP Request frames received */
+	unsigned long CHDLC_SLARP_REPLY_Tx_count PACKED;	/* number of SLARP Reply frames transmitted */
+	unsigned long CHDLC_SLARP_REPLY_Rx_count PACKED;	/* number of SLARP Reply frames received */
+	unsigned long CHDLC_SLARP_KPALV_Tx_count PACKED;	/* number of SLARP keepalive frames transmitted */
+	unsigned long CHDLC_SLARP_KPALV_Rx_count PACKED;	/* number of SLARP keepalive frames received */
+	unsigned long reserved_SLARP_stat1 PACKED;		/* reserved for later */
+	unsigned long reserved_SLARP_stat2 PACKED;		/* reserved for later */
+
+	/* CDP frame transmission/reception statistics */
+	unsigned long CHDLC_CDP_Tx_count PACKED;		/* number of CDP frames transmitted */
+	unsigned long CHDLC_CDP_Rx_count PACKED;		/* number of CDP frames received */
+	unsigned long reserved_CDP_stat1 PACKED;		/* reserved for later */
+	unsigned long reserved_CDP_stat2 PACKED;		/* reserved for later */
+	unsigned long reserved_CDP_stat3 PACKED;		/* reserved for later */
+	unsigned long reserved_CDP_stat4 PACKED;		/* reserved for later */
+	unsigned long reserved_CDP_stat5 PACKED;		/* reserved for later */
+	unsigned long reserved_CDP_stat6 PACKED;		/* reserved for later */
+
+	/* Incomming frames with a format error statistics */
+	unsigned short Rx_frm_incomp_CHDLC_hdr_count PACKED;	/* frames received of with incomplete Cisco HDLC header */
+	unsigned short Rx_frms_too_long_count PACKED;		/* frames received of excessive length count */
+	unsigned short Rx_invalid_CHDLC_addr_count PACKED;	/* frames received with an invalid CHDLC address count */
+	unsigned short Rx_invalid_CHDLC_ctrl_count PACKED;	/* frames received with an invalid CHDLC control field count */
+	unsigned short Rx_invalid_CHDLC_type_count PACKED;	/* frames received of an invalid CHDLC frame type count */
+	unsigned short Rx_SLARP_invalid_code_count PACKED;	/* SLARP frame received with an invalid packet code */
+	unsigned short Rx_SLARP_Reply_bad_IP_addr PACKED;	/* SLARP Reply received - bad IP address */
+	unsigned short Rx_SLARP_Reply_bad_netmask PACKED;	/* SLARP Reply received - bad netmask */
+	unsigned long reserved_frm_format_err1 PACKED;		/* reserved for later */
+	unsigned long reserved_frm_format_err2 PACKED;		/* reserved for later */
+	unsigned long reserved_frm_format_err3 PACKED;		/* reserved for later */
+	unsigned long reserved_frm_format_err4 PACKED;		/* reserved for later */
+
+	/* CHDLC timeout/retry statistics */
+	unsigned short SLARP_Rx_keepalive_TO_count PACKED;	/* timeout count for incomming SLARP frames */
+	unsigned short SLARP_Request_TO_count PACKED;		/* timeout count for SLARP Request frames */
+	unsigned long To_retry_reserved_stat1 PACKED;		/* reserved for later */
+	unsigned long To_retry_reserved_stat2 PACKED;		/* reserved for later */
+	unsigned long To_retry_reserved_stat3 PACKED;		/* reserved for later */
+
+	/* CHDLC link active/inactive and loopback statistics */
+	unsigned short link_active_count PACKED;		/* number of times that the link went active */
+	unsigned short link_inactive_modem_count PACKED;	/* number of times that the link went inactive (modem failure) */
+	unsigned short link_inactive_keepalive_count PACKED;	/* number of times that the link went inactive (keepalive failure) */
+	unsigned short link_looped_count PACKED;		/* link looped count */
+	unsigned long link_status_reserved_stat1 PACKED;	/* reserved for later use */
+	unsigned long link_status_reserved_stat2 PACKED;	/* reserved for later use */
+
+	/* miscellaneous statistics */
+	unsigned long reserved_misc_stat1 PACKED;		/* reserved for later */
+	unsigned long reserved_misc_stat2 PACKED;		/* reserved for later */
+	unsigned long reserved_misc_stat3 PACKED;		/* reserved for later */
+	unsigned long reserved_misc_stat4 PACKED;		/* reserved for later */
+
+} CHDLC_OPERATIONAL_STATS_STRUCT;
+
+
+
+/* ----------------------------------------------------------------------------
+ *                 Constants for using application interrupts
+ * --------------------------------------------------------------------------*/
+
+/* the structure used for the SET_CHDLC_INTERRUPT_TRIGGERS/READ_CHDLC_INTERRUPT_TRIGGERS command */
+typedef struct {
+	unsigned char CHDLC_interrupt_triggers PACKED;	/* CHDLC interrupt trigger configuration */
+	unsigned char IRQ PACKED;			/* IRQ to be used */
+	unsigned short interrupt_timer PACKED;		/* interrupt timer */
+	unsigned short misc_interrupt_bits PACKED;	/* miscellaneous bits */
+} CHDLC_INT_TRIGGERS_STRUCT;
+
+/* 'CHDLC_interrupt_triggers' bit settings */
+#define APP_INT_ON_RX_FRAME		0x01	/* interrupt on Data frame reception */
+#define APP_INT_ON_TX_FRAME		0x02	/* interrupt when an Data frame may be transmitted */
+#define APP_INT_ON_COMMAND_COMPLETE	0x04	/* interrupt when an interface command is complete */
+#define APP_INT_ON_TIMER		0x08	/* interrupt on a defined millisecond timeout */
+#define APP_INT_ON_GLOBAL_EXCEP_COND 	0x10	/* interrupt on a global exception condition */
+#define APP_INT_ON_CHDLC_EXCEP_COND	0x20	/* interrupt on an CHDLC exception condition */
+#define APP_INT_ON_TRACE_DATA_AVAIL	0x80	/* interrupt when trace data is available */
+
+/* interrupt types indicated at 'interrupt_type' byte of the INTERRUPT_INFORMATION_STRUCT */
+#define NO_APP_INTS_PEND		0x00	/* no interrups are pending */
+#define RX_APP_INT_PEND			0x01	/* a receive interrupt is pending */
+#define TX_APP_INT_PEND			0x02	/* a transmit interrupt is pending */
+#define COMMAND_COMPLETE_APP_INT_PEND	0x04	/* a 'command complete' interrupt is pending */
+#define TIMER_APP_INT_PEND		0x08	/* a timer interrupt is pending */
+#define GLOBAL_EXCEP_COND_APP_INT_PEND 	0x10	/* a global exception condition interrupt is pending */
+#define CHDLC_EXCEP_COND_APP_INT_PEND 	0x20	/* an CHDLC exception condition interrupt is pending */
+#define TRACE_DATA_AVAIL_APP_INT_PEND	0x80	/* a trace data available interrupt is pending */
+
+
+/* modem status changes */
+#define DCD_HIGH			0x08
+#define CTS_HIGH			0x20
+
+
+/* ----------------------------------------------------------------------------
+ *                   Constants for Data frame transmission
+ * --------------------------------------------------------------------------*/
+
+/* the Data frame transmit status element configuration structure */
+typedef struct {
+	unsigned short number_Tx_status_elements PACKED;	/* number of transmit status elements */
+	unsigned long base_addr_Tx_status_elements PACKED;	/* base address of the transmit element list */
+	unsigned long next_Tx_status_element_to_use PACKED;	/* pointer to the next transmit element to be used */
+} CHDLC_TX_STATUS_EL_CFG_STRUCT;
+
+/* the Data frame transmit status element structure */
+typedef struct {
+	unsigned char opp_flag PACKED;		/* opp flag */
+	unsigned short frame_length PACKED;	/* length of the frame to be transmitted */
+	unsigned char reserved_1 PACKED;	/* reserved for internal use */
+	unsigned long reserved_2 PACKED;	/* reserved for internal use */
+	unsigned long reserved_3 PACKED;	/* reserved for internal use */
+	unsigned long ptr_data_bfr PACKED;	/* pointer to the data area */
+} CHDLC_DATA_TX_STATUS_EL_STRUCT;
+
+
+
+/* ----------------------------------------------------------------------------
+ *                   Constants for Data frame reception
+ * --------------------------------------------------------------------------*/
+
+/* the Data frame receive status element configuration structure */
+typedef struct {
+	unsigned short number_Rx_status_elements PACKED;	/* number of receive status elements */
+	unsigned long base_addr_Rx_status_elements PACKED;	/* base address of the receive element list */
+	unsigned long next_Rx_status_element_to_use PACKED;	/* pointer to the next receive element to be used */
+	unsigned long base_addr_Rx_buffer PACKED;		/* base address of the receive data buffer */
+	unsigned long end_addr_Rx_buffer PACKED;		/* end address of the receive data buffer */
+} CHDLC_RX_STATUS_EL_CFG_STRUCT;
+
+/* the Data frame receive status element structure */
+typedef struct {
+	unsigned char opp_flag PACKED;		/* opp flag */
+	unsigned short frame_length PACKED;   /* length of the received frame */
+        unsigned char error_flag PACKED; /* frame errors (HDLC_STREAMING_MODE)*/
+        unsigned short time_stamp PACKED; /* receive time stamp (HDLC_STREAMING_MODE) */
+        unsigned long reserved_1 PACKED; 	/* reserved for internal use */
+        unsigned short reserved_2 PACKED; 	/* reserved for internal use */
+        unsigned long ptr_data_bfr PACKED;	/* pointer to the data area */
+} CHDLC_DATA_RX_STATUS_EL_STRUCT;
+
+
+
+/* ----------------------------------------------------------------------------
+ *         Constants defining the shared memory information area
+ * --------------------------------------------------------------------------*/
+
+/* the global information structure */
+typedef struct {
+ 	unsigned char global_status PACKED;		/* global status */
+ 	unsigned char modem_status PACKED;		/* current modem status */
+ 	unsigned char global_excep_conditions PACKED;	/* global exception conditions */
+	unsigned char glob_info_reserved[5] PACKED;	/* reserved */
+	unsigned char codename[4] PACKED;		/* Firmware name */
+	unsigned char codeversion[4] PACKED;		/* Firmware version */
+} GLOBAL_INFORMATION_STRUCT;
+
+/* the CHDLC information structure */
+typedef struct {
+	unsigned char CHDLC_status PACKED;		/* CHDLC status */
+ 	unsigned char CHDLC_excep_conditions PACKED;	/* CHDLC exception conditions */
+	unsigned char CHDLC_info_reserved[14] PACKED;	/* reserved */
+} CHDLC_INFORMATION_STRUCT;
+
+/* the interrupt information structure */
+typedef struct {
+ 	unsigned char interrupt_type PACKED;		/* type of interrupt triggered */
+ 	unsigned char interrupt_permission PACKED;	/* interrupt permission mask */
+	unsigned char int_info_reserved[14] PACKED;	/* reserved */
+} INTERRUPT_INFORMATION_STRUCT;
+
+/* the S508/FT1 information structure */
+typedef struct {
+ 	unsigned char parallel_port_A_input PACKED;	/* input - parallel port A */
+ 	unsigned char parallel_port_B_input PACKED;	/* input - parallel port B */
+	unsigned char FT1_info_reserved[14] PACKED;	/* reserved */
+} FT1_INFORMATION_STRUCT;
+
+/* the shared memory area information structure */
+typedef struct {
+	GLOBAL_INFORMATION_STRUCT global_info_struct PACKED;		/* the global information structure */
+	CHDLC_INFORMATION_STRUCT CHDLC_info_struct PACKED;		/* the CHDLC information structure */
+	INTERRUPT_INFORMATION_STRUCT interrupt_info_struct PACKED;	/* the interrupt information structure */
+	FT1_INFORMATION_STRUCT FT1_info_struct PACKED;			/* the S508/FT1 information structure */
+} SHARED_MEMORY_INFO_STRUCT;
+
+/* ----------------------------------------------------------------------------
+ *        UDP Management constants and structures 
+ * --------------------------------------------------------------------------*/
+
+/* The embedded control block for UDP mgmt 
+   This is essentially a mailbox structure, without the large data field */
+
+typedef struct {
+        unsigned char  opp_flag PACKED;                  /* the opp flag */
+        unsigned char  command PACKED;                   /* the user command */
+        unsigned short buffer_length PACKED;             /* the data length */
+        unsigned char  return_code PACKED;               /* the return code */
+	unsigned char  MB_reserved[NUMBER_MB_RESERVED_BYTES] PACKED;	/* reserved for later */
+} cblock_t;
+
+
+/* UDP management packet layout (data area of ip packet) */
+/*
+typedef struct {
+	unsigned char		signature[8]	PACKED;
+	unsigned char		request_reply	PACKED;
+	unsigned char		id		PACKED;
+	unsigned char		reserved[6]	PACKED;
+	cblock_t		cblock		PACKED;
+	unsigned char		num_frames	PACKED;
+	unsigned char		ismoredata	PACKED;
+	unsigned char 		data[SIZEOF_MB_DATA_BFR] 	PACKED;
+} udp_management_packet_t;
+
+*/
+
+typedef struct {
+	unsigned char		num_frames	PACKED;
+	unsigned char		ismoredata	PACKED;
+} trace_info_t;
+
+typedef struct {
+	ip_pkt_t 		ip_pkt		PACKED;
+	udp_pkt_t		udp_pkt		PACKED;
+	wp_mgmt_t		wp_mgmt		PACKED;
+	cblock_t                cblock          PACKED;
+	trace_info_t       	trace_info      PACKED;
+	unsigned char           data[SIZEOF_MB_DATA_BFR]      PACKED;
+} chdlc_udp_pkt_t;
+
+typedef struct ft1_exec_cmd{
+	unsigned char  command PACKED;                   /* the user command */
+        unsigned short buffer_length PACKED;             /* the data length */
+        unsigned char  return_code PACKED;               /* the return code */
+	unsigned char  MB_reserved[NUMBER_MB_RESERVED_BYTES] PACKED;
+} ft1_exec_cmd_t;
+
+typedef struct {
+	unsigned char  opp_flag 			PACKED;
+	ft1_exec_cmd_t cmd				PACKED;
+	unsigned char  data[SIZEOF_MB_DATA_BFR]      	PACKED;
+} ft1_exec_t;
+
+#define UDPMGMT_SIGNATURE	"CTPIPEAB"
+
+
+/* UDP/IP packet (for UDP management) layout */
+/*
+typedef struct {
+	unsigned char	reserved[2]	PACKED;
+	unsigned short	ip_length	PACKED;
+	unsigned char	reserved2[4]	PACKED;
+	unsigned char	ip_ttl		PACKED;
+	unsigned char	ip_protocol	PACKED;
+	unsigned short	ip_checksum	PACKED;
+	unsigned long	ip_src_address	PACKED;
+	unsigned long	ip_dst_address	PACKED;
+	unsigned short	udp_src_port	PACKED;
+	unsigned short	udp_dst_port	PACKED;
+	unsigned short	udp_length	PACKED;
+	unsigned short	udp_checksum	PACKED;
+	udp_management_packet_t um_packet PACKED;
+} ip_packet_t;
+*/
+
+/* valid ip_protocol for UDP management */
+#define UDPMGMT_UDP_PROTOCOL 0x11
+
+
+typedef struct {
+	unsigned char	status		PACKED;
+	unsigned char	data_avail	PACKED;
+	unsigned short	real_length	PACKED;
+	unsigned short	time_stamp	PACKED;
+	unsigned char	data[1]		PACKED;
+} trace_pkt_t;
+
+typedef struct {
+	unsigned char	error_flag	PACKED;
+	unsigned short	time_stamp	PACKED;
+	unsigned char	reserved[13]	PACKED;
+} api_rx_hdr_t;
+
+typedef struct {
+        api_rx_hdr_t	api_rx_hdr      PACKED;
+        void *   	data    	PACKED;
+} api_rx_element_t;
+
+typedef struct {
+	unsigned char 	attr		PACKED;
+	unsigned char  	reserved[15]	PACKED;
+} api_tx_hdr_t;
+
+typedef struct {
+	api_tx_hdr_t 	api_tx_hdr	PACKED;
+	void *		data		PACKED;
+} api_tx_element_t;
+
+/* ----------------------------------------------------------------------------
+ *   Constants for the SET_FT1_CONFIGURATION/READ_FT1_CONFIGURATION command
+ * --------------------------------------------------------------------------*/
+
+/* the FT1 configuration structure */
+typedef struct {
+	unsigned short framing_mode;
+	unsigned short encoding_mode;
+	unsigned short line_build_out;
+	unsigned short channel_base;
+	unsigned short baud_rate_kbps;					/* the baud rate (in kbps) */	
+	unsigned short clock_mode;
+} ft1_config_t;
+
+/* settings for the 'framing_mode' */
+#define ESF_FRAMING 	0x00	/* ESF framing */
+#define D4_FRAMING  	0x01	/* D4 framing */
+
+/* settings for the 'encoding_mode' */
+#define B8ZS_ENCODING 	0x00	/* B8ZS encoding */
+#define AMI_ENCODING	0x01	/* AMI encoding */
+
+/* settings for the 'line_build_out' */
+#define LN_BLD_CSU_0dB_DSX1_0_to_133	0x00	/* set build out to CSU (0db) or DSX-1 (0-133ft) */
+#define LN_BLD_DSX1_133_to_266		0x01	/* set build out DSX-1 (133-266ft) */
+#define LN_BLD_DSX1_266_to_399		0x02	/* set build out DSX-1 (266-399ft) */
+#define LN_BLD_DSX1_399_to_533		0x03	/* set build out DSX-1 (399-533ft) */
+#define LN_BLD_DSX1_533_to_655		0x04	/* set build out DSX-1 (533-655ft) */
+#define LN_BLD_CSU_NEG_7dB		0x05	/* set build out to CSU (-7.5db) */
+#define LN_BLD_CSU_NEG_15dB		0x06	/* set build out to CSU (-15db) */
+#define LN_BLD_CSU_NEG_22dB		0x07	/* set build out to CSU (-22.5db) */
+
+/* settings for the 'channel_base' */
+#define MIN_CHANNEL_BASE_VALUE		1		/* the minimum permitted channel base value */
+#define MAX_CHANNEL_BASE_VALUE		24		/* the maximum permitted channel base value */
+
+/* settings for the 'baud_rate_kbps' */
+#define MIN_BAUD_RATE_KBPS		0		/* the minimum permitted baud rate (kbps) */
+#define MAX_BAUD_RATE_KBPS 		1536	/* the maximum permitted baud rate (kbps) */
+#define BAUD_RATE_FT1_AUTO_CONFIG	0xFFFF /* the baud rate used to trigger an automatic FT1 configuration */
+
+/* settings for the 'clock_mode' */
+#define CLOCK_MODE_NORMAL		0x00	/* clock mode set to normal (slave) */
+#define CLOCK_MODE_MASTER		0x01	/* clock mode set to master */
+
+
+#define BAUD_RATE_FT1_AUTO_CONFIG   	0xFFFF
+#define AUTO_FT1_CONFIG_NOT_COMPLETE	0x08
+#define AUTO_FT1_CFG_FAIL_OP_MODE	0x0C
+#define AUTO_FT1_CFG_FAIL_INVALID_LINE 	0x0D
+
+ 
+#ifdef		_MSC_
+#  pragma	pack()
+#endif
+#endif	/* _SDLA_CHDLC_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sdla_fr.h linux.14p16/include/linux/sdla_fr.h
--- linux.vanilla/include/linux/sdla_fr.h	Mon Jan 12 22:46:26 1998
+++ linux.14p16/include/linux/sdla_fr.h	Wed Dec 15 16:11:19 1999
@@ -1,16 +1,18 @@
 /*****************************************************************************
 * sdla_fr.h	Sangoma frame relay firmware API definitions.
 *
-* Author:	Jaspreet Singh  <jaspreet@sangoma.com>
-*		Gene Kozin	<74604.152@compuserve.com>
+* Author:       Gideon Hack  	
+*		Nenad Corbic <ncorbic@sangoma.com> 	
 *
-* Copyright:	(c) 1995-1996 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-1999 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.
 * ============================================================================
+* Oct 04, 1999  Gideon Hack     Updated API structures
+* Jun 02, 1999  Gideon Hack 	Modifications for S514 support
 * Oct 12, 1997	Jaspreet Singh	Added FR_READ_DLCI_IB_MAPPING
 * Jul 21, 1997 	Jaspreet Singh	Changed FRRES_TOO_LONG and FRRES_TOO_MANY to 
 *				0x05 and 0x06 respectively.
@@ -24,26 +26,16 @@
 /*----------------------------------------------------------------------------
  * 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:
+ * 1. All structures defined in this file are byte-alined.  
  *
- *	Compiler	Platform	Define		Use option
- *	--------	--------	------		----------
- *	GNU C		Linux		_GNUC_		-
- *	Microsoft C	DOS/Windows	_MSC_		-
+ *	Compiler	Platform
+ *	--------	--------
+ *	GNU C		Linux
  */
 
-#ifdef		_GNUC_
-#  ifndef	PACKED
+#ifndef	PACKED
 #    define	PACKED	__attribute__((packed))
-#  endif	/* PACKED */
-#else
-#  define	PACKED
-#endif
-#ifdef		_MSC_
-#  pragma	pack(1)
-#endif
+#endif	/* PACKED */
 
 /* Adapter memory layout */
 #define	FR_MB_VECTOR	0xE000	/* mailbox window vector */
@@ -59,6 +51,11 @@
 /* Important constants */
 #define FR502_MAX_DATA	4096	/* maximum data buffer length */
 #define FR508_MAX_DATA	4080	/* maximum data buffer length */
+#define MIN_LGTH_FR_DATA_CFG         300     /* min Information frame length
+(for configuration purposes) */
+#define FR_MAX_NO_DATA_BYTES_IN_FRAME  15354 	/* max Information frame length */
+ 
+#define HIGHEST_VALID_DLCI	991
 
 /****** Data Structures *****************************************************/
 
@@ -90,6 +87,7 @@
 #define FR_FLUSH_STATISTICS	0x16
 #define	FR_LIST_ACTIVE_DLCI	0x17
 #define FR_FLUSH_DATA_BUFFERS	0x18
+#define FR_READ_ADD_DLC_STATS	0x19
 #define	FR_ADD_DLCI		0x20
 #define	FR_DELETE_DLCI		0x21
 #define	FR_ACTIVATE_DLCI	0x22
@@ -102,6 +100,20 @@
 #define FR_READ_CODE_VERSION	0x40
 #define	FR_SET_INTR_MODE	0x50
 #define	FR_READ_INTR_MODE	0x51
+#define FR_SET_TRACE_CONFIG	0x60
+#define FR_FT1_STATUS_CTRL 	0x80
+#define FR_SET_FT1_MODE		0x81
+
+/* Special UDP drivers management commands */
+#define FPIPE_ENABLE_TRACING          	0x41
+#define FPIPE_DISABLE_TRACING		0x42
+#define FPIPE_GET_TRACE_INFO            0x43
+#define FPIPE_FT1_READ_STATUS           0x44
+#define FPIPE_DRIVER_STAT_IFSEND        0x45
+#define FPIPE_DRIVER_STAT_INTR          0x46
+#define FPIPE_DRIVER_STAT_GEN           0x47
+#define FPIPE_FLUSH_DRIVER_STATS        0x48
+#define FPIPE_ROUTER_UP_TIME            0x49
 
 /* 'result' field defines */
 #define FRRES_OK		0x00	/* command executed successfully */
@@ -169,7 +181,7 @@
 } fr508_flags_t;
 
 /* 'event' field defines */
-#define	FR_EVENT_STATUS		0x01	/* channel status change ??? */
+#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 */
@@ -185,6 +197,8 @@
 #define	FR_INTR_READY		0x08	/* interface command completed */
 #define	FR_INTR_DLC		0x10	/* DLC status change */
 #define	FR_INTR_TIMER		0x20	/* millisecond timer */
+#define FR_INTR_TX_MULT_DLCIs	0x80	/* Tx interrupt on multiple DLCIs */
+
 
 /*----------------------------------------------------------------------------
  * Receive Buffer Configuration Info. S508 only!
@@ -206,7 +220,7 @@
  *	'rse_base' field of the frBufInfo_t structure into absolute adapter
  *	memory address space.
  */
-typedef struct	fr_buf_ctl
+typedef struct	fr_rx_buf_ctl
 {
 	unsigned char flag	PACKED;	/* 00h: ready flag */
 	unsigned short length	PACKED;	/* 01h: frame length */
@@ -215,7 +229,18 @@
 	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;
+} fr_rx_buf_ctl_t;
+
+typedef struct  fr_tx_buf_ctl
+{
+        unsigned char flag      PACKED; /* 00h: ready flag */
+	unsigned short rsrv0[2]	PACKED;	/* 01h: */
+        unsigned short length   PACKED; /* 05h: frame length */
+        unsigned short dlci     PACKED; /* 07h: DLCI */
+        unsigned char attr      PACKED; /* 09h: FECN/BECN/DE/CR */
+        unsigned short rsrv1 	PACKED; /* 0Ah:  */
+        unsigned long offset    PACKED; /* 0Ch: buffer absolute address */
+} fr_tx_buf_ctl_t;
 
 /*----------------------------------------------------------------------------
  * Global Configuration Block. Passed to FR_SET_CONFIG command when dlci == 0.
@@ -271,6 +296,52 @@
 #define	FRCFG_MODE_V35		0x0000	/* S508 only */
 #define	FRCFG_MODE_RS232	0x0002	/* S508 only */
 
+/* defines for line tracing */
+
+/* the line trace status element presented by the frame relay code */
+typedef struct {
+        unsigned char flag      PACKED; /* ready flag */
+        unsigned short length   PACKED; /* trace length */
+        unsigned char rsrv0[2]  PACKED; /* reserved */
+        unsigned char attr      PACKED; /* trace attributes */
+        unsigned short tmstamp  PACKED; /* time stamp */
+        unsigned char rsrv1[4]  PACKED; /* reserved */
+        unsigned long offset    PACKED; /* buffer absolute address */
+} fr_trc_el_t;
+
+typedef struct {
+        unsigned char status    	PACKED; /* status flag */
+	unsigned char data_passed	PACKED;	/* 0 if no data passed, 1 if */
+						/* data passed */
+        unsigned short length   	PACKED; /* frame length */
+        unsigned short tmstamp  	PACKED; /* time stamp */
+} fpipemon_trc_hdr_t;
+
+typedef struct {
+	fpipemon_trc_hdr_t fpipemon_trc_hdr			PACKED;
+        unsigned char data[FR_MAX_NO_DATA_BYTES_IN_FRAME]	PACKED;
+} fpipemon_trc_t;
+
+/* bit settings for the 'status' byte  - note that bits 1, 2 and 3 are used */
+/* for returning the number of frames being passed to fpipemon */
+#define TRC_OUTGOING_FRM	0x01
+#define TRC_ABORT_ERROR         0x10
+#define TRC_CRC_ERROR           0x20
+#define TRC_OVERRUN_ERROR       0x40
+#define MORE_TRC_DATA		0x80
+
+#define MAX_FRMS_TRACED		0x07
+
+#define NO_TRC_ELEMENTS_OFF		0x9000
+#define BASE_TRC_ELEMENTS_OFF		0x9002
+#define TRC_ACTIVE			0x01
+#define FLUSH_TRC_BUFFERS 		0x02
+#define FLUSH_TRC_STATISTICS		0x04
+#define TRC_SIGNALLING_FRMS		0x10
+#define TRC_INFO_FRMS			0x20
+#define ACTIVATE_TRC	(TRC_ACTIVE | TRC_SIGNALLING_FRMS | TRC_INFO_FRMS)
+#define RESET_TRC	(FLUSH_TRC_BUFFERS | FLUSH_TRC_STATISTICS)
+
 /*----------------------------------------------------------------------------
  * Channel configuration.
  *	This structure is passed to the FR_SET_CONFIG command when dlci != 0.
@@ -414,6 +485,151 @@
  */
 #define	FR_ISF_LVE	2		/* issue Link Verification Enquiry */
 #define	FR_ISF_FSE	3		/* issue Full Status Enquiry */
+
+/*----------------------------------------------------------------------------
+ * Frame Relay ARP Header -- Used for Dynamic route creation with InvARP 
+ */
+
+typedef struct arphdr_fr
+	{
+	unsigned short ar_hrd PACKED;		/* format of hardware addr */
+	unsigned short ar_pro PACKED;		/* format of protocol addr */
+	unsigned char  ar_hln PACKED;		/* length of hardware addr */	
+	unsigned char  ar_pln PACKED;		/* length of protocol addr */
+	unsigned short ar_op  PACKED;		/* ARP opcode		   */
+	unsigned short ar_sha PACKED;		/* Sender DLCI addr 2 bytes */
+	unsigned long  ar_sip PACKED;		/* Sender IP   addr 4 bytes */
+	unsigned short ar_tha PACKED;		/* Target DLCI addr 2 bytes */
+	unsigned long  ar_tip PACKED;		/* Target IP   addr 4 bytes */
+	} arphdr_fr_t;
+
+/*----------------------------------------------------------------------------
+ * Frame Relay RFC 1490 SNAP Header -- Used to check for ARP packets
+ */
+typedef struct arphdr_1490
+	{
+	unsigned char control PACKED;		/* UI, etc...  */
+	unsigned char pad     PACKED;		/* Pad */
+	unsigned char NLPID   PACKED;		/* SNAP */
+	unsigned char OUI[3]  PACKED;		/* Ethertype, etc... */
+	unsigned short PID    PACKED;		/* ARP, IP, etc... */
+	}  arphdr_1490_t;
+
+/* UDP/IP packet (for UDP management) layout */
+
+/* The embedded control block for UDP mgmt
+   This is essentially a mailbox structure, without the large data field */
+
+typedef struct {
+        unsigned char  opp_flag PACKED; /* the opp flag */
+        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 */
+} cblock_t;
+
+
+/* UDP management packet layout (data area of ip packet) */
+
+typedef struct {
+        unsigned char   control                 PACKED;
+        unsigned char   NLPID                   PACKED;
+} fr_encap_hdr_t;
+
+typedef struct {
+	fr_encap_hdr_t 		fr_encap_hdr	PACKED;
+	ip_pkt_t 		ip_pkt		PACKED;
+	udp_pkt_t		udp_pkt		PACKED;
+	wp_mgmt_t 		wp_mgmt       	PACKED;
+        cblock_t                cblock          PACKED;
+        unsigned char           data[4080]      PACKED;
+} fr_udp_pkt_t;
+
+
+/* valid ip_protocol for UDP management */
+#define UDPMGMT_UDP_PROTOCOL 0x11
+
+#define UDPMGMT_FPIPE_SIGNATURE         "FPIPE8ND"
+#define UDPMGMT_DRVRSTATS_SIGNATURE     "DRVSTATS"
+
+/* values for request/reply byte */
+#define UDPMGMT_REQUEST	0x01
+#define UDPMGMT_REPLY	0x02
+#define UDP_OFFSET	12
+
+typedef struct {
+        unsigned long if_send_entry;
+        unsigned long if_send_skb_null;
+        unsigned long if_send_broadcast;
+        unsigned long if_send_multicast;
+        unsigned long if_send_critical_ISR;
+        unsigned long if_send_critical_non_ISR;
+        unsigned long if_send_busy;
+        unsigned long if_send_busy_timeout;
+	unsigned long if_send_DRVSTATS_request;
+        unsigned long if_send_FPIPE_request;
+        unsigned long if_send_wan_disconnected;
+        unsigned long if_send_dlci_disconnected;
+        unsigned long if_send_no_bfrs;
+        unsigned long if_send_adptr_bfrs_full;
+        unsigned long if_send_bfrs_passed_to_adptr;
+	unsigned long if_send_consec_send_fail;
+} drvstats_if_send_t; 
+
+typedef struct {
+        unsigned long rx_intr_no_socket;
+        unsigned long rx_intr_dev_not_started;
+        unsigned long rx_intr_DRVSTATS_request;
+        unsigned long rx_intr_FPIPE_request;
+        unsigned long rx_intr_bfr_not_passed_to_stack;
+        unsigned long rx_intr_bfr_passed_to_stack;
+ } drvstats_rx_intr_t;
+
+typedef struct {
+        unsigned long UDP_FPIPE_mgmt_kmalloc_err;
+        unsigned long UDP_FPIPE_mgmt_direction_err;
+        unsigned long UDP_FPIPE_mgmt_adptr_type_err;
+        unsigned long UDP_FPIPE_mgmt_adptr_cmnd_OK;
+        unsigned long UDP_FPIPE_mgmt_adptr_cmnd_timeout;
+        unsigned long UDP_FPIPE_mgmt_adptr_send_passed;
+        unsigned long UDP_FPIPE_mgmt_adptr_send_failed;
+        unsigned long UDP_FPIPE_mgmt_not_passed_to_stack;
+        unsigned long UDP_FPIPE_mgmt_passed_to_stack;
+        unsigned long UDP_FPIPE_mgmt_no_socket;
+        unsigned long UDP_DRVSTATS_mgmt_kmalloc_err;
+        unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
+        unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
+        unsigned long UDP_DRVSTATS_mgmt_adptr_send_passed;
+        unsigned long UDP_DRVSTATS_mgmt_adptr_send_failed;
+        unsigned long UDP_DRVSTATS_mgmt_not_passed_to_stack;
+        unsigned long UDP_DRVSTATS_mgmt_passed_to_stack;
+        unsigned long UDP_DRVSTATS_mgmt_no_socket;
+} drvstats_gen_t;
+
+typedef struct {
+        unsigned char   attr      	PACKED;
+        unsigned short  time_stamp      PACKED;
+        unsigned char   reserved[13]    PACKED;
+} api_rx_hdr_t;
+
+typedef struct {
+        api_rx_hdr_t    api_rx_hdr      PACKED;
+        void *          data            PACKED;
+} api_rx_element_t;
+
+typedef struct {
+        unsigned char   attr            PACKED;
+        unsigned char   reserved[15]    PACKED;
+} api_tx_hdr_t;
+
+typedef struct {
+        api_tx_hdr_t    api_tx_hdr      PACKED;
+        void *          data            PACKED;
+} api_tx_element_t;
 
 #ifdef		_MSC_
 #  pragma	pack()
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sdla_ppp.h linux.14p16/include/linux/sdla_ppp.h
--- linux.vanilla/include/linux/sdla_ppp.h	Sun Feb  2 13:18:47 1997
+++ linux.14p16/include/linux/sdla_ppp.h	Wed Dec 15 16:11:36 1999
@@ -19,38 +19,25 @@
 /*----------------------------------------------------------------------------
  * 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:
+ * 1. All structures defined in this file are byte-alined.  
  *
- *	Compiler	Platform	Define		Use option
- *	--------	--------	------		----------
- *	GNU C		Linux		_GNUC_		-
- *	Microsoft C	DOS/Windows	_MSC_		-
+ *	Compiler	Platform
+ *	--------	--------
+ *	GNU C		Linux		
  */
 
-#ifdef		_GNUC_
-#  ifndef	PACKED
+#ifndef	PACKED
 #    define	PACKED	__attribute__((packed))
-#  endif	/* PACKED */
-#else
-#  define	PACKED
-#endif
-#ifdef		_MSC_
-#  pragma	pack(1)
-#endif
+#endif	/* PACKED */
 
 /* 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_MB_OFFS	0		/* mailbox offset */
 #define	PPP508_FLG_OFFS	0x1000	/* status flags offset */
 #define	PPP508_BUF_OFFS	0x1100	/* buffer info block offset */
+#define PPP514_MB_OFFS  0xE000  /* mailbox offset */
+#define PPP514_FLG_OFFS 0xF000  /* status flags offset */
+#define PPP514_BUF_OFFS 0xF100  /* buffer info block offset */
 
 #define PPP_MAX_DATA	1008	/* command block data buffer length */
 
@@ -59,14 +46,46 @@
 /*----------------------------------------------------------------------------
  * PPP Command Block.
  */
-typedef struct ppp_cmd
-{
+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;
 
+typedef struct cblock{
+	unsigned char  opp_flag	PACKED;
+	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 */
+} cblock_t;
+
+typedef struct ppp_udp_pkt{
+	ip_pkt_t 	ip_pkt	PACKED;
+	udp_pkt_t	udp_pkt	PACKED;
+	wp_mgmt_t	wp_mgmt PACKED;
+	cblock_t	cblock  PACKED;
+	unsigned char   data[MAX_LGTH_UDP_MGNT_PKT] PACKED;
+} ppp_udp_pkt_t;	
+
+typedef struct {
+	unsigned char	status		PACKED;
+	unsigned char	data_avail	PACKED;
+	unsigned short	real_length	PACKED;
+	unsigned short	time_stamp	PACKED;
+	unsigned char	data[1]		PACKED;
+} trace_pkt_t;
+
+
+typedef struct {
+	unsigned char 	opp_flag	PACKED;
+	unsigned char	trace_type	PACKED;
+	unsigned short 	trace_length	PACKED;
+	unsigned short 	trace_data_ptr	PACKED;
+	unsigned short  trace_time_stamp PACKED;
+} trace_element_t;
+
 /* 'command' field defines */
 #define PPP_READ_CODE_VERSION	0x10	/* configuration commands */
 #define PPP_SET_CONFIG		0x05
@@ -145,26 +164,46 @@
 #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 */
+#define PPP_INTR_TIMER          0x80    /* timer interrupt */
+
 
 /* '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;
+/* 'disc_cause' defines */
+#define PPP_LOCAL_TERMINATION   0x0001	/* Local Request by PPP termination phase */
+#define PPP_DCD_CTS_DROP        0x0002  /* DCD and/or CTS dropped. Link down */
+#define PPP_REMOTE_TERMINATION	0x0800	/* Remote Request by PPP termination phase */
+
+/* 'misc_config_bits' defines */
+#define DONT_RE_TX_ABORTED_I_FRAMES 	0x01
+#define TX_FRM_BYTE_COUNT_STATS         0x02
+#define RX_FRM_BYTE_COUNT_STATS         0x04
+#define TIME_STAMP_IN_RX_FRAMES         0x08
+#define NON_STD_ADPTR_FREQ              0x10
+#define INTERFACE_LEVEL_RS232           0x20
+#define AUTO_LINK_RECOVERY              0x100
+#define DONT_TERMINATE_LNK_MAX_CONFIG   0x200                    
+
+/* 'authentication options' defines */
+#define NO_AUTHENTICATION	0x00
+#define INBOUND_AUTH		0x80
+#define PAP_AUTH		0x01
+#define CHAP_AUTH		0x02		
+
+/* 'ip options' defines */
+#define L_AND_R_IP_NO_ASSIG	0x00
+#define L_IP_LOCAL_ASSIG    	0x01
+#define L_IP_REMOTE_ASSIG   	0x02
+#define R_IP_LOCAL_ASSIG        0x04
+#define R_IP_REMOTE_ASSIG       0x08
+#define ENABLE_IP		0x80
+
+/* 'ipx options' defines */
+#define ROUTING_PROT_DEFAULT    0x20
+#define ENABLE_IPX		0x80
+#define DISABLE_IPX		0x00
 
 /*----------------------------------------------------------------------------
  * PPP Buffer Info.
@@ -203,37 +242,6 @@
 } 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
@@ -255,8 +263,8 @@
 	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 long  ip_local		PACKED;	/* 22: local IP address */
+	unsigned long  ip_remote	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*/
@@ -265,6 +273,25 @@
 	unsigned long  alt_cpu_clock	PACKED;	/* 6B:  */
 } ppp508_conf_t;
 
+/*----------------------------------------------------------------------------
+ * S508 Adapter Read Connection Information Block 
+ *    Returned by the PPP_GET_CONNECTION_INFO command
+ */
+typedef struct	ppp508_connect_info
+{
+	unsigned short 	mru		PACKED;	/* 00-01 Remote Max Rec' Unit */
+	unsigned char  	ip_options 	PACKED; /* 02: Negotiated ip options  */
+	unsigned long  	ip_local	PACKED;	/* 03-06: local IP address    */
+	unsigned long  	ip_remote	PACKED;	/* 07-0A: remote IP address   */
+	unsigned char	ipx_options	PACKED; /* 0B: Negotiated ipx options */
+	unsigned char  	ipx_netno[4]	PACKED;	/* 0C-0F: IPX net number      */
+	unsigned char  	ipx_local[6]	PACKED;	/* 10-1F: local IPX node #    */
+	unsigned char  	ipx_remote[6]	PACKED;	/* 16-1B: remote IPX node #   */
+	unsigned char  	ipx_router[48]	PACKED;	/* 1C-4B: IPX router name     */
+	unsigned char	auth_status	PACKED; /* 4C: Authentication Status  */
+	unsigned char 	inbd_auth_peerID[1] PACKED; /* 4D: variable length inbound authenticated peer ID */
+} ppp508_connect_info_t;
+
 /* 'line_speed' field */
 #define	PPP_BITRATE_1200	0x01
 #define	PPP_BITRATE_2400	0x02
@@ -303,16 +330,6 @@
 #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
@@ -324,20 +341,6 @@
 } 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
@@ -529,6 +532,40 @@
 	unsigned char  auth_status	PACKED;	/* 4C:  */
 	unsigned char  peer_id[0]	PACKED;	/* 4D:  */
 } ppp_conn_info_t;
+
+/* Data structure for SET_TRIGGER_INTR command
+ */
+
+typedef struct ppp_intr_info{
+	unsigned char  i_enable		PACKED; /* 0 Interrupt enable bits */
+	unsigned char  irq              PACKED; /* 1 Irq number */
+	unsigned short timer_len        PACKED; /* 2 Timer delay */
+} ppp_intr_info_t;
+
+
+#define FT1_MONITOR_STATUS_CTRL                         0x80
+#define SET_FT1_MODE                                    0x81
+
+
+
+/* Special UDP drivers management commands */
+#define PPIPE_ENABLE_TRACING                            0x20
+#define PPIPE_DISABLE_TRACING                           0x21
+#define PPIPE_GET_TRACE_INFO                            0x22
+#define PPIPE_GET_IBA_DATA                              0x23
+#define PPIPE_KILL_BOARD     				0x24
+#define PPIPE_FT1_READ_STATUS                           0x25
+#define PPIPE_DRIVER_STAT_IFSEND                        0x26
+#define PPIPE_DRIVER_STAT_INTR                          0x27
+#define PPIPE_DRIVER_STAT_GEN                           0x28
+#define PPIPE_FLUSH_DRIVER_STATS                        0x29
+#define PPIPE_ROUTER_UP_TIME                            0x30
+
+#define DISABLE_TRACING 				0x00
+#define TRACE_SIGNALLING_FRAMES				0x01
+#define TRACE_DATA_FRAMES				0x02
+
+
 
 #ifdef		_MSC_
 #  pragma	pack()
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sdladrv.h linux.14p16/include/linux/sdladrv.h
--- linux.vanilla/include/linux/sdladrv.h	Fri Oct  9 19:56:59 1998
+++ linux.14p16/include/linux/sdladrv.h	Tue Dec 21 01:01:35 1999
@@ -1,15 +1,16 @@
 /*****************************************************************************
 * sdladrv.h	SDLA Support Module.  Kernel API Definitions.
 *
-* Author:	Gene Kozin	<genek@compuserve.com>
+* Author: 	Gideon Hack	
 *
-* Copyright:	(c) 1995-1996 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-1999 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.
 * ============================================================================
+* Jun 02, 1999 	Gideon Hack	Added support for the S514 PCI adapter.
 * 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.
@@ -18,6 +19,11 @@
 #ifndef	_SDLADRV_H
 #define	_SDLADRV_H
 
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= 0x020100
+#define LINUX_2_1
+#endif
+
 #define	SDLA_MAXIORANGE	4	/* maximum I/O port range */
 #define	SDLA_WINDOWSIZE	0x2000	/* default dual-port memory window size */
 
@@ -33,6 +39,14 @@
 	unsigned fwid;			/* firmware ID */
 	unsigned port;			/* adapter I/O port base */
 	int irq;			/* interrupt request level */
+	char S514_cpu_no[1];		/* PCI CPU Number */
+	unsigned char S514_slot_no;	/* PCI Slot Number */
+#ifdef LINUX_2_1
+	struct pci_dev *pci_dev;	/* PCI device */
+#else
+	unsigned char pci_bus;		/* PCI bus number */
+	unsigned char pci_dev_func;	/* PCI device/function number */
+#endif
 	void * dpmbase;			/* dual-port memory base */
 	unsigned dpmsize;		/* dual-port memory size */
 	unsigned pclk;			/* CPU clock rate, kHz */
@@ -50,6 +64,8 @@
 extern int sdla_inten	(sdlahw_t* hw);
 extern int sdla_intde	(sdlahw_t* hw);
 extern int sdla_intack	(sdlahw_t* hw);
+extern void S514_intack  (sdlahw_t* hw, u32 int_status);
+extern void read_S514_int_stat (sdlahw_t* hw, u32* int_status);
 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,
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sdlapci.h linux.14p16/include/linux/sdlapci.h
--- linux.vanilla/include/linux/sdlapci.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/linux/sdlapci.h	Wed Dec 15 16:10:51 1999
@@ -0,0 +1,68 @@
+/*****************************************************************************
+* sdlapci.h	WANPIPE(tm) Multiprotocol WAN Link Driver.
+*		Definitions for the SDLA PCI adapter.
+*
+* Author:	Gideon Hack	<ghack@sangoma.com>
+*
+* Copyright:	(c) 1999 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.
+* ============================================================================
+* Jun 02, 1999	Gideon Hack	Initial version.
+*****************************************************************************/
+#ifndef	_SDLAPCI_H
+#define	_SDLAPCI_H
+
+/****** Defines *************************************************************/
+
+/* Definitions for identifying and finding S514 PCI adapters */
+#define V3_VENDOR_ID		0x11B0		/* V3 vendor ID number */
+#define V3_DEVICE_ID  		0x0002		/* V3 device ID number */
+#define SANGOMA_SUBSYS_VENDOR 	0x4753		/* ID for Sangoma */
+#define PCI_DEV_SLOT_MASK	0x1F		/* mask for slot numbering */
+#define PCI_IRQ_NOT_ALLOCATED	0xFF		/* interrupt line for no IRQ */
+
+/* Local PCI register offsets */ 
+#define PCI_VENDOR_ID_WORD	0x00		/* vendor ID */
+#define PCI_IO_BASE_DWORD	0x10		/* IO base */	
+#define PCI_MEM_BASE0_DWORD	0x14		/* memory base - apperture 0 */
+#define PCI_MEM_BASE1_DWORD     0x18		/* memory base - apperture 1 */
+#define PCI_SUBSYS_VENDOR_WORD 	0x2C		/* subsystem vendor ID */
+#define PCI_INT_LINE_BYTE	0x3C		/* interrupt line */
+#define PCI_INT_PIN_BYTE	0x3D		/* interrupt pin */
+#define PCI_MAP0_DWORD		0x40		/* PCI to local bus address 0 */
+#define PCI_MAP1_DWORD          0x44		/* PCI to local bus address 1 */
+#define PCI_INT_STATUS          0x48		/* interrupt status */
+#define PCI_INT_CONFIG		0x4C		/* interrupt configuration */
+  
+/* Local PCI register usage */
+#define PCI_MEMORY_ENABLE	0x00000003	/* enable PCI memory */
+#define PCI_CPU_A_MEM_DISABLE	0x00000002	/* disable CPU A memory */
+#define PCI_CPU_B_MEM_DISABLE  	0x00100002	/* disable CPU B memory */
+#define PCI_ENABLE_IRQ_CPU_A	0x005A0004	/* enable IRQ for CPU A */
+#define PCI_ENABLE_IRQ_CPU_B    0x005A0008	/* enable IRQ for CPU B */
+#define PCI_DISABLE_IRQ_CPU_A   0x00000004	/* disable IRQ for CPU A */
+#define PCI_DISABLE_IRQ_CPU_B   0x00000008	/* disable IRQ for CPU B */
+ 
+/* Setting for the Interrupt Status register */  
+#define IRQ_CPU_A               0x04            /* IRQ for CPU A */
+#define IRQ_CPU_B               0x08		/* IRQ for CPU B */
+
+/* The maximum size of the S514 memory */
+#define MAX_SIZEOF_S514_MEMORY	(256 * 1024)
+
+/* S514 control register offsets within the memory address space */
+#define S514_CTRL_REG_BYTE	0x80000
+ 
+/* S514 adapter control bytes */
+#define S514_CPU_HALT 		0x00
+#define S514_CPU_START		0x01
+
+/* The maximum number of S514 adapters supported */
+#define MAX_S514_CARDS		8
+
+#endif	/* _SDLAPCI_H */
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sdlasfm.h linux.14p16/include/linux/sdlasfm.h
--- linux.vanilla/include/linux/sdlasfm.h	Sun Feb  2 13:18:47 1997
+++ linux.14p16/include/linux/sdlasfm.h	Wed Dec 15 16:10:51 1999
@@ -2,15 +2,16 @@
 * sdlasfm.h	WANPIPE(tm) Multiprotocol WAN Link Driver.
 *		Definitions for the SDLA Firmware Module (SFM).
 *
-* Author:	Gene Kozin	<74604.152@compuserve.com>
+* Author: 	Gideon Hack 	
 *
-* Copyright:	(c) 1995-1996 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-1999 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.
 * ============================================================================
+* Jun 02, 1999  Gideon Hack	Added support for the S514 adapter.
 * 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
@@ -36,6 +37,12 @@
 #define SDLA_S508	5080
 #define SDLA_S507	5070
 #define SDLA_S509	5090
+#define SDLA_S514	5140
+
+/* S514 PCI adapter CPU numbers */
+#define S514_CPU_A	'A'
+#define S514_CPU_B	'B'
+
 
 /* Firmware identification numbers:
  *    0  ..  999	Test & Diagnostics
@@ -46,6 +53,7 @@
  *  5000 .. 5999	X.25
  *  6000 .. 6999	Frame Relay
  *  7000 .. 7999	PPP
+ *  8000 .. 8999        Cisco HDLC
  */
 #define	SFID_CALIB502	 200
 #define	SFID_STRM502	1200
@@ -53,12 +61,16 @@
 #define	SFID_BSC502	2200
 #define	SFID_SDLC502	3200
 #define	SFID_HDLC502	4200
+#define	SFID_HDLC508	4800
 #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
+#define SFID_PPP514	7140
+#define	SFID_CHDLC508	8800
+#define SFID_CHDLC514	8140
 
 /****** Data Types **********************************************************/
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/socket.h linux.14p16/include/linux/socket.h
--- linux.vanilla/include/linux/socket.h	Sat Aug 14 02:27:40 1999
+++ linux.14p16/include/linux/socket.h	Mon Dec 13 19:35:54 1999
@@ -106,7 +106,7 @@
 
 	__ptr = (struct cmsghdr*)(((unsigned char *) __cmsg) +  CMSG_ALIGN(__cmsg->cmsg_len));
 	if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
-		return NULL;
+		return (struct cmsghdr*)0;
 
 	return __ptr;
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sunrpc/svc.h linux.14p16/include/linux/sunrpc/svc.h
--- linux.vanilla/include/linux/sunrpc/svc.h	Sun Mar 28 19:03:50 1999
+++ linux.14p16/include/linux/sunrpc/svc.h	Mon Dec 13 19:39:03 1999
@@ -13,6 +13,7 @@
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/xdr.h>
 #include <linux/sunrpc/svcauth.h>
+#include <asm/atomic.h>
 
 /*
  * RPC service.
@@ -29,7 +30,7 @@
 	struct svc_sock *	sv_sockets;	/* pending sockets */
 	struct svc_program *	sv_program;	/* RPC program */
 	struct svc_stat *	sv_stats;	/* RPC statistics */
-	unsigned int		sv_nrthreads;	/* # of server threads */
+	atomic_t		sv_nrthreads;	/* # of server threads */
 	unsigned int		sv_bufsz;	/* datagram buffer size */
 	unsigned int		sv_xdrsize;	/* XDR buffer size */
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sunrpc/svcsock.h linux.14p16/include/linux/sunrpc/svcsock.h
--- linux.vanilla/include/linux/sunrpc/svcsock.h	Sun Mar 28 19:03:53 1999
+++ linux.14p16/include/linux/sunrpc/svcsock.h	Mon Dec 13 19:39:07 1999
@@ -10,6 +10,7 @@
 #define SUNRPC_SVCSOCK_H
 
 #include <linux/sunrpc/svc.h>
+#include <asm/atomic.h>
 
 /*
  * RPC server socket.
@@ -23,7 +24,7 @@
 	struct sock *		sk_sk;		/* INET layer */
 
 	struct svc_serv *	sk_server;	/* service for this socket */
-	unsigned char		sk_inuse;	/* use count */
+	atomic_t		sk_inuse;	/* use count */
 	unsigned char		sk_busy;	/* enqueued/receiving */
 	unsigned char		sk_conn;	/* conn pending */
 	unsigned char		sk_close;	/* dead or dying */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sunrpc/xprt.h linux.14p16/include/linux/sunrpc/xprt.h
--- linux.vanilla/include/linux/sunrpc/xprt.h	Sun Mar 28 19:03:27 1999
+++ linux.14p16/include/linux/sunrpc/xprt.h	Mon Dec 13 19:38:54 1999
@@ -124,8 +124,10 @@
 struct rpc_xprt {
 	struct rpc_xprt *	link;		/* list of all clients */
 	struct rpc_xprt *	rx_pending;	/* receive pending list */
+	struct rpc_xprt *	tx_pending;	/* transmit pending list */
 	
-	int 			rx_pending_flag;/* are we on the pending list ? */
+	int 			rx_pending_flag;/* are we on the rcv pending list ? */
+	int 			tx_pending_flag;/* are we on the xmit pending list ? */
 
 	struct file *		file;		/* VFS layer */
 	struct socket *		sock;		/* BSD socket layer */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/swap.h linux.14p16/include/linux/swap.h
--- linux.vanilla/include/linux/swap.h	Sun Mar 28 19:03:26 1999
+++ linux.14p16/include/linux/swap.h	Mon Dec 13 19:36:00 1999
@@ -68,7 +68,7 @@
 extern atomic_t nr_async_pages;
 extern struct inode swapper_inode;
 extern unsigned long page_cache_size;
-extern int buffermem;
+extern long buffermem;
 
 /* Incomplete types for prototype declarations: */
 struct task_struct;
@@ -91,8 +91,8 @@
 extern void swap_after_unlock_page (unsigned long entry);
 
 /* linux/mm/page_alloc.c */
-extern void swap_in(struct task_struct *, struct vm_area_struct *,
-		    pte_t *, unsigned long, int);
+extern int swap_in(struct task_struct *, struct vm_area_struct *,
+		   pte_t *, unsigned long, int);
 
 
 /* linux/mm/swap_state.c */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sysctl.h linux.14p16/include/linux/sysctl.h
--- linux.vanilla/include/linux/sysctl.h	Wed Oct 20 01:12:51 1999
+++ linux.14p16/include/linux/sysctl.h	Mon Dec 13 18:50:28 1999
@@ -104,7 +104,8 @@
 	KERN_MSGMNB=36,         /* int: Maximum message queue size */
 	KERN_MSGPOOL=37,         /* int: Maximum system message pool size */
 	KERN_SYSRQ=38,		/* int: Sysreq enable */
-	KERN_SHMALL=41		/* int: maximum size of shared memory */
+	KERN_SHMALL=41,		/* int: maximum size of shared memory */
+	KERN_SPARC_STOP_A=44,	/* int: Sparc Stop-A enable */
 };
 
 
@@ -267,7 +268,8 @@
 	NET_IPV4_CONF_RP_FILTER=8,
 	NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE=9,
 	NET_IPV4_CONF_BOOTP_RELAY=10,
-	NET_IPV4_CONF_LOG_MARTIANS=11
+	NET_IPV4_CONF_LOG_MARTIANS=11,
+	NET_IPV4_CONF_HIDDEN=12
 };
 
 /* /proc/sys/net/ipv6 */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/telephony.h linux.14p16/include/linux/telephony.h
--- linux.vanilla/include/linux/telephony.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/linux/telephony.h	Fri Dec 17 18:59:59 1999
@@ -0,0 +1,200 @@
+/*
+ *              telephony.h
+ *
+ *              Basic Linux Telephony Interface
+ *
+ *              (c) Copyright 1999 Quicknet 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.
+ *
+ * Authors:       Ed Okerson, <eokerson@quicknet.net>
+ *                Greg Herlein, <gherlein@quicknet.net>
+ *
+ * Contributors:  Alan Cox, <acox@redhat.com>
+ *                David Erhart, <derhart@quicknet.net>
+ *
+ * Version:       0.1.0 - December 19, 1999
+ *
+ * Fixes:
+ */
+
+#ifndef TELEPHONY_H
+#define TELEPHONY_H
+
+/* vendor identification numbers */
+#define PHONE_VENDOR_IXJ          1
+#define PHONE_VENDOR_QUICKNET     PHONE_IXJ
+#define PHONE_VENDOR_VOICETRONIX  2
+#define PHONE_VENDOR_ACULAB       3
+#define PHONE_VENDOR_DIGI         4
+#define PHONE_VENDOR_FRANKLIN     5
+
+/******************************************************************************
+ *  Vendor Summary Information Area
+ *
+ *  Quicknet Technologies, Inc. - makes low density analog telephony cards
+ *    with audio compression, POTS and PSTN interfaces (www.quicknet.net)
+ *
+ *  (other vendors following this API shuld add a short description of
+ *  the telephony products they support under Linux)
+ *
+ *****************************************************************************/
+
+ 
+/******************************************************************************
+*
+* The capabilities ioctls can inform you of the capabilities of each phone
+* device installed in your system.  The PHONECTL_CAPABILITIES ioctl
+* returns an integer value indicating the number of capabilities the   
+* device has.  The PHONECTL_CAPABILITIES_LIST will fill an array of 
+* capability structs with all of it's capabilities.  The
+* PHONECTL_CAPABILITIES_CHECK takes a single capability struct and returns
+* a TRUE if the device has that capability, otherwise it returns false.
+* 
+******************************************************************************/
+typedef enum {
+	vendor = 0,
+	device,
+	port,
+	codec,
+	dsp
+} phone_cap;
+
+struct phone_capability {
+	char desc[80];
+	phone_cap captype;
+	int cap;
+	int handle;
+};
+
+typedef enum {
+	pots = 0,
+	pstn,
+	handset,
+	speaker
+} phone_ports;
+
+#define PHONE_CAPABILITIES              _IO  ('q', 0x80)
+#define PHONE_CAPABILITIES_LIST         _IOR ('q', 0x81, struct phone_capability *)
+#define PHONE_CAPABILITIES_CHECK        _IOW ('q', 0x82, struct phone_capability *)
+
+#define PHONE_RING			_IO  ('q', 0x83)
+#define PHONE_HOOKSTATE			_IO  ('q', 0x84)
+#define PHONE_MAXRINGS			_IOW ('q', 0x85, char)
+#define PHONE_RING_CADENCE		_IOW ('q', 0x86, short)
+#define PHONE_RING_START		_IO  ('q', 0x87)
+#define PHONE_RING_STOP			_IO  ('q', 0x88)
+
+#define USA_RING_CADENCE	 0xC0C0
+
+#define PHONE_REC_CODEC			_IOW ('q', 0x89, int)
+#define PHONE_REC_START			_IO  ('q', 0x8A)
+#define PHONE_REC_STOP			_IO  ('q', 0x8B)
+#define PHONE_REC_DEPTH			_IOW ('q', 0x8C, int)
+#define PHONE_FRAME			_IOW ('q', 0x8D, int)
+#define PHONE_REC_VOLUME		_IOW ('q', 0x8E, int)
+#define PHONE_REC_LEVEL			_IO  ('q', 0x8F)
+
+#define PHONE_PLAY_CODEC		_IOW ('q', 0x90, int)
+#define PHONE_PLAY_START		_IO  ('q', 0x91)
+#define PHONE_PLAY_STOP			_IO  ('q', 0x92)
+#define PHONE_PLAY_DEPTH		_IOW ('q', 0x93, int)
+#define PHONE_PLAY_VOLUME		_IOW ('q', 0x94, int)
+#define PHONE_PLAY_LEVEL		_IO  ('q', 0x95)
+#define PHONE_DTMF_READY		_IOR ('q', 0x96, int)
+#define PHONE_GET_DTMF			_IOR ('q', 0x97, int)
+#define PHONE_GET_DTMF_ASCII		_IOR ('q', 0x98, int)
+#define PHONE_DTMF_OOB			_IOW ('q', 0x99, int)
+#define PHONE_EXCEPTION			_IOR ('q', 0x9A, int)
+#define PHONE_PLAY_TONE			_IOW ('q', 0x9B, char)
+#define PHONE_SET_TONE_ON_TIME		_IOW ('q', 0x9C, int)
+#define PHONE_SET_TONE_OFF_TIME		_IOW ('q', 0x9D, int)
+#define PHONE_GET_TONE_ON_TIME		_IO  ('q', 0x9E)
+#define PHONE_GET_TONE_OFF_TIME		_IO  ('q', 0x9F)
+#define PHONE_GET_TONE_STATE		_IO  ('q', 0xA0)
+#define PHONE_BUSY			_IO  ('q', 0xA1)
+#define PHONE_RINGBACK			_IO  ('q', 0xA2)
+#define PHONE_DIALTONE			_IO  ('q', 0xA3)
+#define PHONE_CPT_STOP			_IO  ('q', 0xA4)
+
+#define PHONE_PSTN_SET_STATE		_IOW ('q', 0xA4, int)
+#define PHONE_PSTN_GET_STATE		_IO  ('q', 0xA5)
+
+#define PSTN_ON_HOOK		0
+#define PSTN_RINGING		1
+#define PSTN_OFF_HOOK		2
+#define PSTN_PULSE_DIAL		3
+
+/******************************************************************************
+* 
+* The wink duration is tunable with this ioctl.  The default wink duration  
+* is 320ms.  You do not need to use this ioctl if you do not require a
+* different wink duration.
+* 
+******************************************************************************/
+#define PHONE_WINK_DURATION		_IOW ('q', 0xA6, int)
+
+
+/******************************************************************************
+* 
+*  Codec Definitions
+* 
+******************************************************************************/
+typedef enum {
+	G723_63 = 1,
+	G723_53 = 2,
+	TS85 = 3,
+	TS48 = 4,
+	TS41 = 5,
+	G728 = 6,
+	G729 = 7,
+	ULAW = 8,
+	ALAW = 9,
+	LINEAR16 = 10,
+	LINEAR8 = 11,
+	WSS = 12
+} phone_codec;
+
+/******************************************************************************
+*
+* The exception structure allows us to multiplex multiple events onto the
+* select() exception set.  If any of these flags are set select() will
+* return with a positive indication on the exception set.  The dtmf_ready
+* bit indicates if there is data waiting in the DTMF buffer.  The
+* hookstate bit is set if there is a change in hookstate status, it does not
+* indicate the current state of the hookswitch.  The pstn_ring bit
+* indicates that the DAA on a LineJACK card has detected ring voltage on
+* the PSTN port.  The caller_id bit indicates that caller_id data has been
+* recieved and is available.  The pstn_wink bit indicates that the DAA on
+* the LineJACK has recieved a wink from the telco switch.  The f0, f1, f2
+* and f3 bits indicate that the filter has been triggered by detecting the
+* frequency programmed into that filter.
+*
+* The remaining bits should be set to zero. They will become defined over time
+* for other interface cards and their needs.
+*
+******************************************************************************/
+struct phone_except
+{
+	unsigned int dtmf_ready:1;
+	unsigned int hookstate:1;
+	unsigned int pstn_ring:1;
+	unsigned int caller_id:1;
+	unsigned int pstn_wink:1;
+	unsigned int f0:1;
+	unsigned int f1:1;
+	unsigned int f2:1;
+	unsigned int f3:1;
+	unsigned int reserved:23;
+};
+
+union telephony_exception {
+	struct phone_except bits;
+	unsigned int bytes;
+};
+
+
+#endif				/* TELEPHONY_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/wanpipe.h linux.14p16/include/linux/wanpipe.h
--- linux.vanilla/include/linux/wanpipe.h	Mon Jan 12 22:46:27 1998
+++ linux.14p16/include/linux/wanpipe.h	Tue Dec 21 01:04:21 1999
@@ -2,16 +2,23 @@
 * wanpipe.h	WANPIPE(tm) Multiprotocol WAN Link Driver.
 *		User-level API definitions.
 *
-* Author:	Gene Kozin	<genek@compuserve.com>
-*		Jaspreet Singh	<jaspreet@sangoma.com>
+* Author: 	Nenad Corbic <ncorbic@sangoma.com>
+*		Gideon Hack  	
 *
-* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-1999 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.
 * ============================================================================
+* Oct 04, 1999  Nenad Corbic    New CHDLC and FRAME RELAY code, SMP support
+* Jun 02, 1999  Gideon Hack	Added 'update_call_count' for Cisco HDLC 
+*				support
+* Jun 26, 1998	David Fong	Added 'ip_mode' in sdla_t.u.p for dynamic IP
+*				routing mode configuration
+* Jun 12, 1998	David Fong	Added Cisco HDLC union member in sdla_t
+* Dec 08, 1997	Jaspreet Singh  Added 'authenticator' in union of 'sdla_t' 
 * Nov 26, 1997	Jaspreet Singh	Added 'load_sharing' structure.  Also added 
 *				'devs_struct','dev_to_devtint_next' to 'sdla_t'	
 * Nov 24, 1997	Jaspreet Singh	Added 'irq_dis_if_send_count', 
@@ -28,6 +35,10 @@
 #ifndef	_WANPIPE_H
 #define	_WANPIPE_H
 
+#ifdef __SMP__
+#include <asm/spinlock.h>       /* Support for SMP Locking */
+#endif
+
 #include <linux/wanrouter.h>
 
 /* Defines */
@@ -42,6 +53,16 @@
 #define	WANPIPE_DUMP	(ROUTER_USER+0)	/* dump adapter's memory */
 #define	WANPIPE_EXEC	(ROUTER_USER+1)	/* execute firmware command */
 
+#define TRACE_ALL                       0x00
+#define TRACE_PROT			0x01
+#define TRACE_DATA			0x02
+
+/* values for request/reply byte */
+#define UDPMGMT_REQUEST	0x01
+#define UDPMGMT_REPLY	0x02
+#define UDP_OFFSET	12
+
+
 /*
  * Data structures for IOCTL calls.
  */
@@ -97,16 +118,86 @@
 
 } global_stats_t;
 
-/* This structure is used for maitaining a circular linked list of all
- * interfaces(devices) per card. It is used in the Interrupt Service routine
- * for a transmit interrupt where the start of the loop to dev_tint all
- * interfaces changes.
- */
-typedef struct load_sharing
-{
-        struct device*  dev_ptr;
-        struct load_sharing* next;
-} load_sharing_t;
+
+typedef struct{
+	unsigned short	udp_src_port		PACKED;
+	unsigned short	udp_dst_port		PACKED;
+	unsigned short	udp_length		PACKED;
+	unsigned short	udp_checksum		PACKED;
+} udp_pkt_t;
+
+
+typedef struct {
+	unsigned char	ver_inet_hdr_length	PACKED;
+	unsigned char	service_type		PACKED;
+	unsigned short	total_length		PACKED;
+	unsigned short	identifier		PACKED;
+	unsigned short	flags_frag_offset	PACKED;
+	unsigned char	ttl			PACKED;
+	unsigned char	protocol		PACKED;
+	unsigned short	hdr_checksum		PACKED;
+	unsigned long	ip_src_address		PACKED;
+	unsigned long	ip_dst_address		PACKED;
+} ip_pkt_t;
+
+
+typedef struct {
+        unsigned char           signature[8]    PACKED;
+        unsigned char           request_reply   PACKED;
+        unsigned char           id              PACKED;
+        unsigned char           reserved[6]     PACKED;
+} wp_mgmt_t;
+
+/*************************************************************************
+ Data Structure for if_send  statistics
+*************************************************************************/  
+typedef struct if_send_stat{
+	unsigned long if_send_entry;
+	unsigned long if_send_skb_null;
+	unsigned long if_send_broadcast;
+	unsigned long if_send_multicast;
+	unsigned long if_send_critical_ISR;
+	unsigned long if_send_critical_non_ISR;
+	unsigned long if_send_tbusy;
+	unsigned long if_send_tbusy_timeout;
+	unsigned long if_send_PIPE_request;
+	unsigned long if_send_wan_disconnected;
+	unsigned long if_send_dlci_disconnected;
+	unsigned long if_send_no_bfrs;
+	unsigned long if_send_adptr_bfrs_full;
+	unsigned long if_send_bfr_passed_to_adptr;
+	unsigned long if_send_protocol_error;
+       	unsigned long if_send_bfr_not_passed_to_adptr;
+       	unsigned long if_send_tx_int_enabled;
+        unsigned long if_send_consec_send_fail; 
+} if_send_stat_t;
+
+typedef struct rx_intr_stat{
+	unsigned long rx_intr_no_socket;
+	unsigned long rx_intr_dev_not_started;
+	unsigned long rx_intr_PIPE_request;
+	unsigned long rx_intr_bfr_not_passed_to_stack;
+	unsigned long rx_intr_bfr_passed_to_stack;
+} rx_intr_stat_t;	
+
+typedef struct pipe_mgmt_stat{
+	unsigned long UDP_PIPE_mgmt_kmalloc_err;
+	unsigned long UDP_PIPE_mgmt_direction_err;
+	unsigned long UDP_PIPE_mgmt_adptr_type_err;
+	unsigned long UDP_PIPE_mgmt_adptr_cmnd_OK;
+	unsigned long UDP_PIPE_mgmt_adptr_cmnd_timeout;
+	unsigned long UDP_PIPE_mgmt_adptr_send_passed;
+	unsigned long UDP_PIPE_mgmt_adptr_send_failed;
+	unsigned long UDP_PIPE_mgmt_not_passed_to_stack;
+	unsigned long UDP_PIPE_mgmt_passed_to_stack;
+	unsigned long UDP_PIPE_mgmt_no_socket;
+        unsigned long UDP_PIPE_mgmt_passed_to_adptr;
+} pipe_mgmt_stat_t;
+
+
+
+#define MAX_LGTH_UDP_MGNT_PKT 2000
+ 
 
 /* This is used for interrupt testing */
 #define INTR_TEST_MODE	0x02
@@ -154,23 +245,23 @@
 	char in_isr;			/* interrupt-in-service flag */
 	char buff_int_mode_unbusy;	/* flag for carrying out dev_tint */  
 	char dlci_int_mode_unbusy;	/* flag for carrying out dev_tint */
+	char configured;		/* flag for previous configurations */
 	unsigned short irq_dis_if_send_count; /* Disabling irqs in if_send*/
 	unsigned short irq_dis_poll_count;   /* Disabling irqs in poll routine*/
+	unsigned short force_enable_irq;
+	char TracingEnabled;		/* flag for enabling trace */
 	global_stats_t statistics;	/* global statistics */
-	
-	/* The following is used as  a pointer to the structure in our 
-	   circular linked list which changes the start of the loop for 
-	   dev_tint of all interfaces */
-	
-	load_sharing_t* dev_to_devtint_next;
-	load_sharing_t* devs_struct;	
-
+#ifdef __SMP__
+	spinlock_t lock;                /* Support for SMP Locking */
+#endif
 	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);
+
+	struct sdla *next;		/* Secondary Port Device: Piggibacking */
 	union
 	{
 		struct
@@ -188,6 +279,19 @@
 			unsigned rx_top;	/* S508 receive buffer end */
 			unsigned short node_dlci[100];
 			unsigned short dlci_num;
+                        struct device *dlci_to_dev_map[991 + 1];
+                        unsigned tx_interrupts_pending;
+                        unsigned short timer_int_enabled;
+                        unsigned short udp_pkt_lgth;
+                        int udp_type;
+                        char udp_pkt_src;
+                        unsigned udp_dlci;
+                        char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT];
+                        void* trc_el_base;      /* first trace element */
+                        void* trc_el_last;      /* last trace element */
+                        void *curr_trc_el;      /* current trace element */
+                        unsigned short trc_bfr_space; /* trace buffer space */
+			unsigned char  update_comms_stats;
 		} f;
 		struct			/****** PPP-specific data ***********/
 		{
@@ -199,7 +303,53 @@
 			void* rxbuf_last;	/* -> last Rx buffer */
 			unsigned rx_base;	/* S508 receive buffer base */
 			unsigned rx_top;	/* S508 receive buffer end */
+			char ip_mode;		/* STATIC/HOST/PEER IP Mode */
+			char authenticator;	/* Authenticator for PAP/CHAP */
 		} p;
+		struct			/* Cisco HDLC-specific data */
+		{
+			char if_name[WAN_IFNAME_SZ+1];	/* interface name */
+			unsigned char comm_port;/* Communication Port O or 1 */
+			unsigned char usedby;  /* Used by WANPIPE or API */
+			void* rxmb;		/* Receive mail box */
+			void* flags;		/* flags */
+			void* tx_status;	/* Tx status element */
+			void* rx_status;	/* Rx status element */
+			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 */
+			unsigned short protocol_options;
+			unsigned short kpalv_tx;	/* Tx kpalv timer */
+			unsigned short kpalv_rx;	/* Rx kpalv timer */
+			unsigned short kpalv_err;	/* Error tolerance */
+			unsigned short slarp_timer;	/* SLARP req timer */
+			unsigned state;			/* state of the link */
+			unsigned char api_status;
+			unsigned char update_call_count;
+		} c;
+		struct
+		{
+			void* tx_status;	/* Tx status element */
+			void* rx_status;	/* Rx status element */
+			void* trace_status;	/* Trace status element */
+			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 */
+			void* tracebuf;		/* -> current Trace buffer */
+			void* tracebuf_base;	/* -> current Trace buffer */
+			void* tracebuf_last;	/* -> current Trace buffer */
+			unsigned rx_base;	/* receive buffer base */
+			unsigned rx_end;	/* receive buffer end */
+			unsigned trace_base;	/* trace buffer base */
+			unsigned trace_end;	/* trace buffer end */
+
+		} h;
 	} u;
 } sdla_t;
 
@@ -212,6 +362,10 @@
 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 */
+int wpc_init (sdla_t* card, wandev_conf_t* conf); /* Cisco HDLC */
+int bsc_init (sdla_t* card, wandev_conf_t* conf);	/* BSC streaming */
+int hdlc_init(sdla_t* card, wandev_conf_t* conf);	/* HDLC support */
+int wpft1_init (sdla_t* card, wandev_conf_t* conf);     /* FT1 Config support */
 
 #endif	/* __KERNEL__ */
 #endif	/* _WANPIPE_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/wanrouter.h linux.14p16/include/linux/wanrouter.h
--- linux.vanilla/include/linux/wanrouter.h	Sun Mar 28 19:05:17 1999
+++ linux.14p16/include/linux/wanrouter.h	Tue Dec 21 00:52:36 1999
@@ -1,23 +1,32 @@
 /*****************************************************************************
-* router.h	Definitions for the WAN Multiprotocol Router Module.
+* 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>
-*		Jaspreet Singh	<jaspreet@sangoma.com>
+* Author: 	Nenad Corbic <ncorbic@sangoma.com>
+*		Gideon Hack 	
 *
-* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-1999 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.
 * ============================================================================
+* Oct 04, 1999  Nenad Corbic 	Updated for 2.1.0 release
+* Jun 02, 1999  Gideon Hack	Added support for the S514 adapter.
+* Jul 20, 1998	David Fong	Added Inverse ARP options to 'wanif_conf_t'
+* Jun 12, 1998	David Fong	Added Cisco HDLC support.
+* Dec 16, 1997	Jaspreet Singh	Moved 'enable_IPX' and 'network_number' to
+*				'wanif_conf_t'
+* Dec 05, 1997	Jaspreet Singh	Added 'pap', 'chap' to 'wanif_conf_t'
+*				Added 'authenticator' to 'wan_ppp_conf_t'
 * Nov 06, 1997	Jaspreet Singh	Changed Router Driver version to 1.1 from 1.0
 * Oct 20, 1997	Jaspreet Singh	Added 'cir','bc','be' and 'mc' to 'wanif_conf_t'
 *				Added 'enable_IPX' and 'network_number' to 
 *				'wan_device_t'.  Also added defines for
-*				UDP PACKET TYPE, Interrupt test, critical values*				for RACE conditions.
+*				UDP PACKET TYPE, Interrupt test, critical values
+*				for RACE conditions.
 * Oct 05, 1997	Jaspreet Singh	Added 'dlci_num' and 'dlci[100]' to 
 *				'wan_fr_conf_t' to configure a list of dlci(s)
 *				for a NODE 
@@ -28,6 +37,12 @@
 * Jan 16, 1997	Gene Kozin	router_devlist made public
 * Jan 02, 1997	Gene Kozin	Initial version (based on wanpipe.h).
 *****************************************************************************/
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= 0x020100
+#define LINUX_2_1
+#endif
+
 #ifndef	_ROUTER_H
 #define	_ROUTER_H
 
@@ -50,6 +65,10 @@
 	ROUTER_USER_MAX	= (ROUTER_IOCTL<<8)+31
 };
 
+/* identifiers for displaying proc file data for dual port adapters */
+#define PROC_DATA_PORT_0 0x8000	/* the data is for port 0 */
+#define PROC_DATA_PORT_1 0x8001	/* the data is for port 1 */
+
 /* NLPID for packet encapsulation (ISO/IEC TR 9577) */
 #define	NLPID_IP	0xCC	/* Internet Protocol Datagram */
 #define	NLPID_SNAP	0x80	/* IEEE Subnetwork Access Protocol */
@@ -62,12 +81,14 @@
 #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 */
+#define USED_BY_FIELD	8	/* max length of the used by field */
 
 /* Defines for UDP PACKET TYPE */
 #define UDP_PTPIPE_TYPE 	0x01
 #define UDP_FPIPE_TYPE		0x02
-#define UDP_DRVSTATS_TYPE 	0x03
-#define UDP_INVALID_TYPE  	0x04
+#define UDP_CPIPE_TYPE		0x03
+#define UDP_DRVSTATS_TYPE 	0x04
+#define UDP_INVALID_TYPE  	0x05
 
 /* Command return code */
 #define CMD_OK		0		/* normal firmware return code */
@@ -145,9 +166,27 @@
 	unsigned auth_retry;	/* max. retry */
 	unsigned auth_options;	/* authentication opt. */
 	unsigned ip_options;	/* IP options */
+	char	authenticator;	/* AUTHENTICATOR or not */
+	char	ip_mode;	/* Static/Host/Peer */
 } wan_ppp_conf_t;
 
 /*----------------------------------------------------------------------------
+ * CHDLC-specific link-level configuration.
+ */
+typedef struct wan_chdlc_conf
+{
+	unsigned char ignore_dcd;	/* Protocol options:		*/
+	unsigned char ignore_cts;	/*  Ignore these to determine	*/
+	unsigned char ignore_keepalive;	/*  link status (Yes or No)	*/
+	unsigned char hdlc_streaming;	/*  hdlc_streaming mode (Y/N) */
+	unsigned keepalive_tx_tmr;	/* transmit keepalive timer */
+	unsigned keepalive_rx_tmr;	/* receive  keepalive timer */
+	unsigned keepalive_err_margin;	/* keepalive_error_tolerance */
+	unsigned slarp_timer;		/* SLARP request timer */
+} wan_chdlc_conf_t;
+
+
+/*----------------------------------------------------------------------------
  * WAN device configuration. Passed to ROUTER_SETUP IOCTL.
  */
 typedef struct wandev_conf
@@ -160,18 +199,21 @@
 	unsigned msize;		/* dual-port memory size */
 	int irq;		/* interrupt request level */
 	int dma;		/* DMA request level */
+        char S514_CPU_no[1];	/* S514 PCI adapter CPU number ('A' or 'B') */
+        unsigned PCI_slot_no;	/* S514 PCI adapter slot number */
+	char comm_port;		/* Communication Port (PRI=0, SEC=1) */ 
 	unsigned bps;		/* data transfer rate */
 	unsigned mtu;		/* maximum transmit unit size */
         unsigned udp_port;      /* UDP port for management */
 	unsigned char ttl;	/* Time To Live for UDP security */
+	unsigned char ft1;	/* FT1 Configurator Option */
         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 */
+	char read_mode;		/* read mode: Polling or interrupt */
 	unsigned hw_opt[4];	/* other hardware options */
-	unsigned char enable_IPX;	/* Enable or Disable IPX */
-	unsigned long network_number;	/* Network Number for IPX */
 	unsigned reserved[4];
 				/****** arbitrary data ***************/
 	unsigned data_size;	/* data buffer size */
@@ -181,6 +223,7 @@
 		wan_x25_conf_t x25;	/* X.25 configuration */
 		wan_ppp_conf_t ppp;	/* PPP configuration */
 		wan_fr_conf_t fr;	/* frame relay configuration */
+		wan_chdlc_conf_t chdlc;	/* Cisco HDLC configuration */
 	} u;
 } wandev_conf_t;
 
@@ -188,6 +231,9 @@
 #define	WANCONFIG_X25	101	/* X.25 link */
 #define	WANCONFIG_FR	102	/* frame relay link */
 #define	WANCONFIG_PPP	103	/* synchronous PPP link */
+#define WANCONFIG_CHDLC	104	/* Cisco HDLC Link */
+#define WANCONFIG_BSC	105	/* BiSync Streaming */
+#define WANCONFIG_HDLC	106	/* HDLC Support */
 
 /*
  * Configuration options defines.
@@ -230,9 +276,29 @@
 #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 */
+#define	WANOPT_FR_ANSI		1	/* ANSI T1.617 Annex D */
+#define	WANOPT_FR_Q933		2	/* ITU Q.933A */
+#define	WANOPT_FR_LMI		3	/* LMI */
+
+/* PPP IP Mode Options */
+#define	WANOPT_PPP_STATIC	0
+#define	WANOPT_PPP_HOST		1
+#define	WANOPT_PPP_PEER		2
+
+/* CHDLC Protocol Options */
+/* DF Commmented out for now.
+
+#define WANOPT_CHDLC_NO_DCD		IGNORE_DCD_FOR_LINK_STAT
+#define WANOPT_CHDLC_NO_CTS		IGNORE_CTS_FOR_LINK_STAT
+#define WANOPT_CHDLC_NO_KEEPALIVE	IGNORE_KPALV_FOR_LINK_STAT
+*/
+
+/* Port options */
+#define WANOPT_PRI 0
+#define WANOPT_SEC 1
+/* read mode */
+#define	WANOPT_INTR	0
+#define WANOPT_POLL	1
 
 /*----------------------------------------------------------------------------
  * WAN Link Status Info (for ROUTER_STAT IOCTL).
@@ -274,7 +340,8 @@
 	WAN_DISCONNECTED,	/* link/channel is disconnected */
 	WAN_CONNECTING,		/* connection is in progress */
 	WAN_CONNECTED,		/* link/channel is operational */
-	WAN_LIMIT		/* for verification only */
+	WAN_LIMIT,		/* for verification only */
+	WAN_DUALPORT		/* for Dual Port cards */
 };
 
 /* 'modem_status' masks */
@@ -292,13 +359,35 @@
 	unsigned config_id;		/* configuration identifier */
 	char name[WAN_IFNAME_SZ+1];	/* interface name, ASCIIZ */
 	char addr[WAN_ADDRESS_SZ+1];	/* media address, ASCIIZ */
+	char usedby[USED_BY_FIELD];	/* used by API or WANPIPE */
 	unsigned idle_timeout;		/* sec, before disconnecting */
 	unsigned hold_timeout;		/* sec, before re-connecting */
 	unsigned cir;			/* Committed Information Rate fwd,bwd*/
 	unsigned bc;			/* Committed Burst Size fwd, bwd */
 	unsigned be;			/* Excess Burst Size fwd, bwd */ 
+	unsigned char enable_IPX;	/* Enable or Disable IPX */
+	unsigned char inarp;		/* Send Inverse ARP requests Y/N */
+	unsigned inarp_interval;	/* sec, between InARP requests */
+	unsigned long network_number;	/* Network Number for IPX */
 	char mc;			/* Multicast on or off */
-	int reserved[8];		/* reserved for future extensions */
+	char pap;			/* PAP enabled or disabled */
+	char chap;			/* CHAP enabled or disabled */
+	unsigned char userid[511];	/* List of User Id */
+	unsigned char passwd[511];	/* List of passwords */
+	unsigned char sysname[31];	/* Name of the system */
+	unsigned char ignore_dcd;	/* Protocol options: */
+	unsigned char ignore_cts;	/*  Ignore these to determine */
+	unsigned char ignore_keepalive;	/*  link status (Yes or No) */
+	unsigned char hdlc_streaming;	/*  Hdlc streaming mode (Y/N) */
+	unsigned keepalive_tx_tmr;	/* transmit keepalive timer */
+	unsigned keepalive_rx_tmr;	/* receive  keepalive timer */
+	unsigned keepalive_err_margin;	/* keepalive_error_tolerance */
+	unsigned slarp_timer;		/* SLARP request timer */
+	unsigned char ttl;		/* Time To Live for UDP security */
+	char interface;			/* RS-232/V.35, etc. */
+	char clocking;			/* external/internal */
+	unsigned bps;			/* data transfer rate */
+	unsigned mtu;			/* maximum transmit unit size */
 } wanif_conf_t;
 
 #ifdef	__KERNEL__
@@ -308,7 +397,6 @@
 #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.
  */
@@ -317,9 +405,12 @@
 	unsigned magic;			/* magic number */
 	char* name;			/* -> WAN device name (ASCIIZ) */
 	void* private;			/* -> driver private data */
+	unsigned config_id;		/* Configuration ID */
 					/****** hardware configuration ******/
 	unsigned ioport;		/* adapter I/O port base #1 */
-	void * maddr;			/* dual-port memory address */
+	char S514_cpu_no[1];		/* PCI CPU Number */
+	unsigned char S514_slot_no;	/* PCI Slot Number */
+	unsigned long maddr;		/* dual-port memory address */
 	unsigned msize;			/* dual-port memory size */
 	int irq;			/* interrupt request level */
 	int dma;			/* DMA request level */
@@ -333,24 +424,31 @@
 	char line_coding;		/* NRZ/NRZI/FM0/FM1, etc. */
 	char station;			/* DTE/DCE, primary/secondary, etc. */
 	char connection;		/* permanent/switched/on-demand */
+	char signalling;		/* Signalling RS232 or V35 */
+	char read_mode;			/* read mode: Polling or interrupt */
+	char new_if_cnt;                /* Number of interfaces per wanpipe */ 
+	char del_if_cnt;		/* Number of times del_if() gets called */
+	unsigned char piggyback;        /* Piggibacking a port */
 	unsigned hw_opt[4];		/* other hardware options */
-	unsigned char enable_IPX;	/* Enable or Disable IPX */
-	unsigned long network_number;	/* Network Number for IPX */
 					/****** status and statistics *******/
 	char state;			/* device state */
-	unsigned modem_status;		/* modem status */
+	char api_status;		/* device api status */
+#ifdef LINUX_2_1
+	struct net_device_stats stats; 	/* interface statistics */
+#else
 	struct enet_statistics stats;	/* interface statistics */
+#endif
 	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,
+	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);
+	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 */
@@ -359,23 +457,20 @@
 } wan_device_t;
 
 /* 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);
+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)
-;
+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);
 
 /* Public Data */
-extern wan_device_t* router_devlist;	/* list of registered devices */
+extern wan_device_t *router_devlist;	/* list of registered devices */
 
 #endif	/* __KERNEL__ */
 #endif	/* _ROUTER_H */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/wireless.h linux.14p16/include/linux/wireless.h
--- linux.vanilla/include/linux/wireless.h	Sat Aug 14 02:27:40 1999
+++ linux.14p16/include/linux/wireless.h	Mon Dec 13 19:39:56 1999
@@ -1,7 +1,7 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :	8	28.7.99
+ * Version :	9	16.10.99
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  */
@@ -63,7 +63,7 @@
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT	8
+#define WIRELESS_EXT	9
 
 /*
  * Changes :
@@ -96,6 +96,14 @@
  *	- Changed my e-mail address
  *	- More 802.11 support (nickname, rate, rts, frag)
  *	- List index in frequencies
+ *
+ * V8 to V9
+ * --------
+ *	- Support for 'mode of operation' (ad-hoc, managed...)
+ *	- Support for unicast and multicast power saving
+ *	- Change encoding to support larger tokens (>64 bits)
+ *	- Updated iw_params (disable, flags) and use it for NWID
+ *	- Extracted iw_point from iwreq for clarity
  */
 
 /* -------------------------- IOCTL LIST -------------------------- */
@@ -103,12 +111,12 @@
 /* Basic operations */
 #define SIOCSIWNAME	0x8B00		/* Unused ??? */
 #define SIOCGIWNAME	0x8B01		/* get name */
-#define SIOCSIWNWID	0x8B02		/* set network id */
+#define SIOCSIWNWID	0x8B02		/* set network id (the cell) */
 #define SIOCGIWNWID	0x8B03		/* get network id */
 #define SIOCSIWFREQ	0x8B04		/* set channel/frequency */
 #define SIOCGIWFREQ	0x8B05		/* get channel/frequency */
-#define SIOCSIWENCODE	0x8B06		/* set encoding info */
-#define SIOCGIWENCODE	0x8B07		/* get encoding info */
+#define SIOCSIWMODE	0x8B06		/* set operation mode */
+#define SIOCGIWMODE	0x8B07		/* get operation mode */
 #define SIOCSIWSENS	0x8B08		/* set sensitivity */
 #define SIOCGIWSENS	0x8B09		/* get sensitivity */
 
@@ -146,11 +154,18 @@
 #define SIOCSIWFRAG	0x8B24		/* set fragmentation thr (bytes) */
 #define SIOCGIWFRAG	0x8B25		/* get fragmentation thr (bytes) */
 
+/* Encoding stuff (scrambling, hardware security, WEP...) */
+#define SIOCSIWENCODE	0x8B2A		/* set encoding token & mode */
+#define SIOCGIWENCODE	0x8B2B		/* get encoding token & mode */
+/* Power saving stuff (power management, unicast and multicast) */
+#define SIOCSIWPOWER	0x8B2C		/* set Power Management settings */
+#define SIOCGIWPOWER	0x8B2D		/* get Power Management settings */
+
 /* ------------------------- IOCTL STUFF ------------------------- */
 
 /* The first and the last (range) */
 #define SIOCIWFIRST	0x8B00
-#define SIOCIWLAST	0x8B25
+#define SIOCIWLAST	0x8B30
 
 /* Even : get (world access), odd : set (root access) */
 #define IW_IS_SET(cmd)	(!((cmd) & 0x1))
@@ -200,10 +215,67 @@
 /* Maximum size of the ESSID and NICKN strings */
 #define IW_ESSID_MAX_SIZE	32
 
+/* Modes of operation */
+#define IW_MODE_AUTO	0	/* Let the driver decides */
+#define IW_MODE_ADHOC	1	/* Single cell network */
+#define IW_MODE_INFRA	2	/* Multi cell network, roaming, ... */
+#define IW_MODE_MASTER	3	/* Synchronisation master or Access Point */
+#define IW_MODE_REPEAT	4	/* Wireless Repeater (forwarder) */
+#define IW_MODE_SECOND	5	/* Secondary master/repeater (backup) */
+
+/* Maximum number of size of encoding token available
+ * they are listed in the range structure */
+#define IW_MAX_ENCODING_SIZES	8
+
+/* Maximum size of the encoding token in bytes */
+#define IW_ENCODING_TOKEN_MAX	32	/* 256 bits (for now) */
+
+/* Flags for encoding (along with the token) */
+#define IW_ENCODE_INDEX		0x00FF	/* Token index (if needed) */
+#define IW_ENCODE_FLAGS		0xF000	/* Flags defined below */
+#define IW_ENCODE_DISABLED	0x8000	/* Encoding disabled */
+#define IW_ENCODE_ENABLED	0x0000	/* Encoding enabled */
+#define IW_ENCODE_RESTRICTED	0x4000	/* Refuse non-encoded packets */
+#define IW_ENCODE_OPEN		0x2000	/* Accept non-encoded packets */
+
+/* Power management flags available (along with the value, if any) */
+#define IW_POWER_ON		0x0000	/* No details... */
+#define IW_POWER_TYPE		0xF000	/* Type of parameter */
+#define IW_POWER_PERIOD		0x1000	/* Value is a period/duration of  */
+#define IW_POWER_TIMEOUT	0x2000	/* Value is a timeout (to go asleep) */
+#define IW_POWER_MODE		0x0F00	/* Power Management mode */
+#define IW_POWER_UNICAST_R	0x0100	/* Receive only unicast messages */
+#define IW_POWER_MULTICAST_R	0x0200	/* Receive only multicast messages */
+#define IW_POWER_ALL_R		0x0300	/* Receive all messages though PM */
+#define IW_POWER_FORCE_S	0x0400	/* Force PM procedure for sending unicast */
+#define IW_POWER_REPEATER	0x0800	/* Repeat broadcast messages in PM period */
+
 /****************************** TYPES ******************************/
 
 /* --------------------------- SUBTYPES --------------------------- */
 /*
+ *	Generic format for most parameters that fit in an int
+ */
+struct	iw_param
+{
+  __s32		value;		/* The value of the parameter itself */
+  __u8		fixed;		/* Hardware should not use auto select */
+  __u8		disabled;	/* Disable the feature */
+  __u16		flags;		/* Various specifc flags (if any) */
+};
+
+/*
+ *	For all data larger than 16 octets, we need to use a
+ *	pointer to memory alocated in user space.
+ */
+struct	iw_point
+{
+  caddr_t	pointer;	/* Pointer to the data  (in user space) */
+  __u16		length;		/* number of fields or size in bytes */
+  __u16		flags;		/* Optional params */
+};
+
+/*
  *	A frequency
  *	For numbers lower than 10^9, we encode the number in 'm' and
  *	set 'e' to 0
@@ -223,7 +295,7 @@
  */
 struct	iw_quality
 {
-	__u8		qual;		/* link quality (SNR or better...) */
+	__u8		qual;		/* link quality (%retries, SNR or better...) */
 	__u8		level;		/* signal level */
 	__u8		noise;		/* noise level */
 	__u8		updated;	/* Flags to know if updated */
@@ -240,33 +312,13 @@
 	__u32		misc;		/* Others cases */
 };
 
-/*
- *	Encoding information (setting and so on)
- *	Encoding might be hardware encryption, scrambing or others
- */
-struct	iw_encoding
-{
-  __u8	method;			/* Algorithm number / key used */
-  __u64	code;			/* Data/key used for algorithm */
-};
-
-/*
- *	Generic format for parameters
- */
-struct	iw_param
-{
-  __s32		value;		/* The value of the parameter itself */
-  __u8		fixed;		/* Hardware should not use auto select */
-};
-
-
 /* ------------------------ WIRELESS STATS ------------------------ */
 /*
  * Wireless statistics (used for /proc/net/wireless)
  */
 struct	iw_statistics
 {
-	__u8		status;		/* Status
+	__u16		status;		/* Status
 					 * - device dependent for now */
 
 	struct iw_quality	qual;		/* Quality of the link
@@ -295,37 +347,28 @@
 	union
 	{
 		/* Config - generic */
-		char	name[IFNAMSIZ];
+		char		name[IFNAMSIZ];
 		/* Name : used to verify the presence of  wireless extensions.
 		 * Name of the protocol/provider... */
 
-		struct		/* network id (or domain) : used to to */
-		{		/* create logical channels on the air */
-			__u32	nwid;		/* value */
-			__u8	on;		/* active/unactive nwid */
-		}	nwid;
-
+		struct iw_point	essid;	/* Extended network name */
+		struct iw_param	nwid;	/* network id (or domain - the cell) */
 		struct iw_freq	freq;	/* frequency or channel :
 					 * 0-1000 = channel
 					 * > 1000 = frequency in Hz */
 
-		struct iw_encoding	encoding;	/* Encoding stuff */
-
-		__u32	sensitivity;		/* Obsolete, but compatible */
 		struct iw_param	sens;		/* signal level threshold */
 		struct iw_param	bitrate;	/* default bit rate */
 		struct iw_param	rts;		/* RTS threshold threshold */
 		struct iw_param	frag;		/* Fragmentation threshold */
+		__u32		mode;		/* Operation mode */
+
+		struct iw_point	encoding;	/* Encoding stuff : tokens */
+		struct iw_param	power;		/* PM duration/timeout */
 
 		struct sockaddr	ap_addr;	/* Access point address */
 
-		struct		/* For all data bigger than 16 octets */
-		{
-			caddr_t	pointer;	/* Pointer to the data
-						 * (in user space) */
-			__u16	length;		/* fields or byte size */
-			__u16	flags;		/* Optional params */
-		}	data;
+		struct iw_point	data;		/* Other large parameters */
 	}	u;
 };
 
@@ -366,9 +409,6 @@
 	/* Quality of link & SNR stuff */
 	struct iw_quality	max_qual;	/* Quality of the link */
 
-	/* Encoder stuff */
-	struct iw_encoding	max_encoding;	/* Encoding max range */
-
 	/* Rates */
 	__u8		num_bitrates;	/* Number of entries in the list */
 	__s32		bitrate[IW_MAX_BITRATES];	/* list, in bps */
@@ -380,6 +420,17 @@
 	/* Frag threshold */
 	__s32		min_frag;	/* Minimal frag threshold */
 	__s32		max_frag;	/* Maximal frag threshold */
+
+	/* Power Management duration & timeout */
+	__s32		min_pmd;	/* Minimal PM duration */
+	__s32		max_pmd;	/* Maximal PM duration */
+	__s32		min_pmt;	/* Minimal PM timeout */
+	__s32		max_pmt;	/* Maximal PM timeout */
+
+	/* Encoder stuff */
+	__u16	encoding_size[IW_MAX_ENCODING_SIZES];	/* Different token sizes */
+	__u8	num_encoding_sizes;	/* Number of entry in the list */
+	__u8	max_encoding_tokens;	/* Max number of tokens */
 };
 
 /*
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/math-emu/double.h linux.14p16/include/math-emu/double.h
--- linux.vanilla/include/math-emu/double.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/math-emu/double.h	Thu Dec  9 15:33:13 1999
@@ -0,0 +1,199 @@
+/* Software floating-point emulation.
+   Definitions for IEEE Double Precision
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+		  Jakub Jelinek (jj@ultra.linux.cz),
+		  David S. Miller (davem@redhat.com) and
+		  Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#if _FP_W_TYPE_SIZE < 32
+#error "Here's a nickel kid.  Go buy yourself a real computer."
+#endif
+
+#if _FP_W_TYPE_SIZE < 64
+#define _FP_FRACTBITS_D		(2 * _FP_W_TYPE_SIZE)
+#else
+#define _FP_FRACTBITS_D		_FP_W_TYPE_SIZE
+#endif
+
+#define _FP_FRACBITS_D		53
+#define _FP_FRACXBITS_D		(_FP_FRACTBITS_D - _FP_FRACBITS_D)
+#define _FP_WFRACBITS_D		(_FP_WORKBITS + _FP_FRACBITS_D)
+#define _FP_WFRACXBITS_D	(_FP_FRACTBITS_D - _FP_WFRACBITS_D)
+#define _FP_EXPBITS_D		11
+#define _FP_EXPBIAS_D		1023
+#define _FP_EXPMAX_D		2047
+
+#define _FP_QNANBIT_D		\
+	((_FP_W_TYPE)1 << (_FP_FRACBITS_D-2) % _FP_W_TYPE_SIZE)
+#define _FP_IMPLBIT_D		\
+	((_FP_W_TYPE)1 << (_FP_FRACBITS_D-1) % _FP_W_TYPE_SIZE)
+#define _FP_OVERFLOW_D		\
+	((_FP_W_TYPE)1 << _FP_WFRACBITS_D % _FP_W_TYPE_SIZE)
+
+#if _FP_W_TYPE_SIZE < 64
+
+union _FP_UNION_D
+{
+  double flt;
+  struct {
+#if __BYTE_ORDER == __BIG_ENDIAN
+    unsigned sign  : 1;
+    unsigned exp   : _FP_EXPBITS_D;
+    unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE;
+    unsigned frac0 : _FP_W_TYPE_SIZE;
+#else
+    unsigned frac0 : _FP_W_TYPE_SIZE;
+    unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE;
+    unsigned exp   : _FP_EXPBITS_D;
+    unsigned sign  : 1;
+#endif
+  } bits __attribute__((packed));
+};
+
+#define FP_DECL_D(X)		_FP_DECL(2,X)
+#define FP_UNPACK_RAW_D(X,val)	_FP_UNPACK_RAW_2(D,X,val)
+#define FP_UNPACK_RAW_DP(X,val)	_FP_UNPACK_RAW_2_P(D,X,val)
+#define FP_PACK_RAW_D(val,X)	_FP_PACK_RAW_2(D,val,X)
+#define FP_PACK_RAW_DP(val,X)		\
+  do {					\
+    if (!FP_INHIBIT_RESULTS)		\
+      _FP_PACK_RAW_2_P(D,val,X);	\
+  } while (0)
+
+#define FP_UNPACK_D(X,val)		\
+  do {					\
+    _FP_UNPACK_RAW_2(D,X,val);		\
+    _FP_UNPACK_CANONICAL(D,2,X);	\
+  } while (0)
+
+#define FP_UNPACK_DP(X,val)		\
+  do {					\
+    _FP_UNPACK_RAW_2_P(D,X,val);	\
+    _FP_UNPACK_CANONICAL(D,2,X);	\
+  } while (0)
+
+#define FP_PACK_D(val,X)		\
+  do {					\
+    _FP_PACK_CANONICAL(D,2,X);		\
+    _FP_PACK_RAW_2(D,val,X);		\
+  } while (0)
+
+#define FP_PACK_DP(val,X)		\
+  do {					\
+    _FP_PACK_CANONICAL(D,2,X);		\
+    if (!FP_INHIBIT_RESULTS)		\
+      _FP_PACK_RAW_2_P(D,val,X);	\
+  } while (0)
+
+#define FP_ISSIGNAN_D(X)		_FP_ISSIGNAN(D,2,X)
+#define FP_NEG_D(R,X)			_FP_NEG(D,2,R,X)
+#define FP_ADD_D(R,X,Y)			_FP_ADD(D,2,R,X,Y)
+#define FP_SUB_D(R,X,Y)			_FP_SUB(D,2,R,X,Y)
+#define FP_MUL_D(R,X,Y)			_FP_MUL(D,2,R,X,Y)
+#define FP_DIV_D(R,X,Y)			_FP_DIV(D,2,R,X,Y)
+#define FP_SQRT_D(R,X)			_FP_SQRT(D,2,R,X)
+#define _FP_SQRT_MEAT_D(R,S,T,X,Q)	_FP_SQRT_MEAT_2(R,S,T,X,Q)
+
+#define FP_CMP_D(r,X,Y,un)	_FP_CMP(D,2,r,X,Y,un)
+#define FP_CMP_EQ_D(r,X,Y)	_FP_CMP_EQ(D,2,r,X,Y)
+
+#define FP_TO_INT_D(r,X,rsz,rsg)	_FP_TO_INT(D,2,r,X,rsz,rsg)
+#define FP_TO_INT_ROUND_D(r,X,rsz,rsg)	_FP_TO_INT_ROUND(D,2,r,X,rsz,rsg)
+#define FP_FROM_INT_D(X,r,rs,rt)	_FP_FROM_INT(D,2,X,r,rs,rt)
+
+#define _FP_FRAC_HIGH_D(X)	_FP_FRAC_HIGH_2(X)
+#define _FP_FRAC_HIGH_RAW_D(X)	_FP_FRAC_HIGH_2(X)
+
+#else
+
+union _FP_UNION_D
+{
+  double flt;
+  struct {
+#if __BYTE_ORDER == __BIG_ENDIAN
+    unsigned sign : 1;
+    unsigned exp  : _FP_EXPBITS_D;
+    unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0);
+#else
+    unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0);
+    unsigned exp  : _FP_EXPBITS_D;
+    unsigned sign : 1;
+#endif
+  } bits __attribute__((packed));
+};
+
+#define FP_DECL_D(X)		_FP_DECL(1,X)
+#define FP_UNPACK_RAW_D(X,val)	_FP_UNPACK_RAW_1(D,X,val)
+#define FP_UNPACK_RAW_DP(X,val)	_FP_UNPACK_RAW_1_P(D,X,val)
+#define FP_PACK_RAW_D(val,X)	_FP_PACK_RAW_1(D,val,X)
+#define FP_PACK_RAW_DP(val,X)		\
+  do {					\
+    if (!FP_INHIBIT_RESULTS)		\
+      _FP_PACK_RAW_1_P(D,val,X);	\
+  } while (0)
+
+#define FP_UNPACK_D(X,val)		\
+  do {					\
+    _FP_UNPACK_RAW_1(D,X,val);		\
+    _FP_UNPACK_CANONICAL(D,1,X);	\
+  } while (0)
+
+#define FP_UNPACK_DP(X,val)		\
+  do {					\
+    _FP_UNPACK_RAW_1_P(D,X,val);	\
+    _FP_UNPACK_CANONICAL(D,1,X);	\
+  } while (0)
+
+#define FP_PACK_D(val,X)		\
+  do {					\
+    _FP_PACK_CANONICAL(D,1,X);		\
+    _FP_PACK_RAW_1(D,val,X);		\
+  } while (0)
+
+#define FP_PACK_DP(val,X)		\
+  do {					\
+    _FP_PACK_CANONICAL(D,1,X);		\
+    if (!FP_INHIBIT_RESULTS)		\
+      _FP_PACK_RAW_1_P(D,val,X);	\
+  } while (0)
+
+#define FP_ISSIGNAN_D(X)		_FP_ISSIGNAN(D,1,X)
+#define FP_NEG_D(R,X)			_FP_NEG(D,1,R,X)
+#define FP_ADD_D(R,X,Y)			_FP_ADD(D,1,R,X,Y)
+#define FP_SUB_D(R,X,Y)			_FP_SUB(D,1,R,X,Y)
+#define FP_MUL_D(R,X,Y)			_FP_MUL(D,1,R,X,Y)
+#define FP_DIV_D(R,X,Y)			_FP_DIV(D,1,R,X,Y)
+#define FP_SQRT_D(R,X)			_FP_SQRT(D,1,R,X)
+#define _FP_SQRT_MEAT_D(R,S,T,X,Q)	_FP_SQRT_MEAT_1(R,S,T,X,Q)
+
+/* The implementation of _FP_MUL_D and _FP_DIV_D should be chosen by
+   the target machine.  */
+
+#define FP_CMP_D(r,X,Y,un)	_FP_CMP(D,1,r,X,Y,un)
+#define FP_CMP_EQ_D(r,X,Y)	_FP_CMP_EQ(D,1,r,X,Y)
+
+#define FP_TO_INT_D(r,X,rsz,rsg)	_FP_TO_INT(D,1,r,X,rsz,rsg)
+#define FP_TO_INT_ROUND_D(r,X,rsz,rsg)	_FP_TO_INT_ROUND(D,1,r,X,rsz,rsg)
+#define FP_FROM_INT_D(X,r,rs,rt)	_FP_FROM_INT(D,1,X,r,rs,rt)
+
+#define _FP_FRAC_HIGH_D(X)	_FP_FRAC_HIGH_1(X)
+#define _FP_FRAC_HIGH_RAW_D(X)	_FP_FRAC_HIGH_1(X)
+
+#endif /* W_TYPE_SIZE < 64 */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/math-emu/extended.h linux.14p16/include/math-emu/extended.h
--- linux.vanilla/include/math-emu/extended.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/math-emu/extended.h	Thu Dec  9 15:33:13 1999
@@ -0,0 +1,390 @@
+/* Software floating-point emulation.
+   Definitions for IEEE Extended Precision.
+   Copyright (C) 1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek (jj@ultra.linux.cz).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#if _FP_W_TYPE_SIZE < 32
+#error "Here's a nickel, kid. Go buy yourself a real computer."
+#endif
+
+#if _FP_W_TYPE_SIZE < 64
+#define _FP_FRACTBITS_E         (4*_FP_W_TYPE_SIZE)
+#else
+#define _FP_FRACTBITS_E		(2*_FP_W_TYPE_SIZE)
+#endif
+
+#define _FP_FRACBITS_E		64
+#define _FP_FRACXBITS_E		(_FP_FRACTBITS_E - _FP_FRACBITS_E)
+#define _FP_WFRACBITS_E		(_FP_WORKBITS + _FP_FRACBITS_E)
+#define _FP_WFRACXBITS_E	(_FP_FRACTBITS_E - _FP_WFRACBITS_E)
+#define _FP_EXPBITS_E		15
+#define _FP_EXPBIAS_E		16383
+#define _FP_EXPMAX_E		32767
+
+#define _FP_QNANBIT_E		\
+	((_FP_W_TYPE)1 << (_FP_FRACBITS_E-2) % _FP_W_TYPE_SIZE)
+#define _FP_IMPLBIT_E		\
+	((_FP_W_TYPE)1 << (_FP_FRACBITS_E-1) % _FP_W_TYPE_SIZE)
+#define _FP_OVERFLOW_E		\
+	((_FP_W_TYPE)1 << (_FP_WFRACBITS_E % _FP_W_TYPE_SIZE))
+
+#if _FP_W_TYPE_SIZE < 64
+
+union _FP_UNION_E
+{
+   long double flt;
+   struct 
+   {
+#if __BYTE_ORDER == __BIG_ENDIAN
+      unsigned long pad1 : _FP_W_TYPE_SIZE;
+      unsigned long pad2 : (_FP_W_TYPE_SIZE - 1 - _FP_EXPBITS_E);
+      unsigned long sign : 1;
+      unsigned long exp : _FP_EXPBITS_E;
+      unsigned long frac1 : _FP_W_TYPE_SIZE;
+      unsigned long frac0 : _FP_W_TYPE_SIZE;
+#else
+      unsigned long frac0 : _FP_W_TYPE_SIZE;
+      unsigned long frac1 : _FP_W_TYPE_SIZE;
+      unsigned exp : _FP_EXPBITS_E;
+      unsigned sign : 1;
+#endif /* not bigendian */
+   } bits __attribute__((packed));
+};
+
+
+#define FP_DECL_E(X)		_FP_DECL(4,X)
+
+#define FP_UNPACK_RAW_E(X, val)				\
+  do {							\
+    union _FP_UNION_E _flo; _flo.flt = (val);		\
+							\
+    X##_f[2] = 0; X##_f[3] = 0;				\
+    X##_f[0] = _flo.bits.frac0;				\
+    X##_f[1] = _flo.bits.frac1;				\
+    X##_e  = _flo.bits.exp;				\
+    X##_s  = _flo.bits.sign;				\
+    if (!X##_e && (X##_f[1] || X##_f[0])		\
+        && !(X##_f[1] & _FP_IMPLBIT_E))			\
+      {							\
+        X##_e++;					\
+        FP_SET_EXCEPTION(FP_EX_DENORM);			\
+      }							\
+  } while (0)
+
+#define FP_UNPACK_RAW_EP(X, val)			\
+  do {							\
+    union _FP_UNION_E *_flo =				\
+    (union _FP_UNION_E *)(val);				\
+							\
+    X##_f[2] = 0; X##_f[3] = 0;				\
+    X##_f[0] = _flo->bits.frac0;			\
+    X##_f[1] = _flo->bits.frac1;			\
+    X##_e  = _flo->bits.exp;				\
+    X##_s  = _flo->bits.sign;				\
+    if (!X##_e && (X##_f[1] || X##_f[0])		\
+        && !(X##_f[1] & _FP_IMPLBIT_E))			\
+      {							\
+        X##_e++;					\
+        FP_SET_EXCEPTION(FP_EX_DENORM);			\
+      }							\
+  } while (0)
+
+#define FP_PACK_RAW_E(val, X)				\
+  do {							\
+    union _FP_UNION_E _flo;				\
+							\
+    if (X##_e) X##_f[1] |= _FP_IMPLBIT_E;		\
+    else X##_f[1] &= ~(_FP_IMPLBIT_E);			\
+    _flo.bits.frac0 = X##_f[0];				\
+    _flo.bits.frac1 = X##_f[1];				\
+    _flo.bits.exp   = X##_e;				\
+    _flo.bits.sign  = X##_s;				\
+							\
+    (val) = _flo.flt;					\
+  } while (0)
+
+#define FP_PACK_RAW_EP(val, X)				\
+  do {							\
+    if (!FP_INHIBIT_RESULTS)				\
+      {							\
+	union _FP_UNION_E *_flo =			\
+	  (union _FP_UNION_E *)(val);			\
+							\
+	if (X##_e) X##_f[1] |= _FP_IMPLBIT_E;		\
+	else X##_f[1] &= ~(_FP_IMPLBIT_E);		\
+	_flo->bits.frac0 = X##_f[0];			\
+	_flo->bits.frac1 = X##_f[1];			\
+	_flo->bits.exp   = X##_e;			\
+	_flo->bits.sign  = X##_s;			\
+      }							\
+  } while (0)
+
+#define FP_UNPACK_E(X,val)		\
+  do {					\
+    FP_UNPACK_RAW_E(X,val);		\
+    _FP_UNPACK_CANONICAL(E,4,X);	\
+  } while (0)
+
+#define FP_UNPACK_EP(X,val)		\
+  do {					\
+    FP_UNPACK_RAW_2_P(X,val);		\
+    _FP_UNPACK_CANONICAL(E,4,X);	\
+  } while (0)
+
+#define FP_PACK_E(val,X)		\
+  do {					\
+    _FP_PACK_CANONICAL(E,4,X);		\
+    FP_PACK_RAW_E(val,X);		\
+  } while (0)
+
+#define FP_PACK_EP(val,X)		\
+  do {					\
+    _FP_PACK_CANONICAL(E,4,X);		\
+    FP_PACK_RAW_EP(val,X);		\
+  } while (0)
+
+#define FP_ISSIGNAN_E(X)	_FP_ISSIGNAN(E,4,X)
+#define FP_NEG_E(R,X)		_FP_NEG(E,4,R,X)
+#define FP_ADD_E(R,X,Y)		_FP_ADD(E,4,R,X,Y)
+#define FP_SUB_E(R,X,Y)		_FP_SUB(E,4,R,X,Y)
+#define FP_MUL_E(R,X,Y)		_FP_MUL(E,4,R,X,Y)
+#define FP_DIV_E(R,X,Y)		_FP_DIV(E,4,R,X,Y)
+#define FP_SQRT_E(R,X)		_FP_SQRT(E,4,R,X)
+
+/*
+ * Square root algorithms:
+ * We have just one right now, maybe Newton approximation
+ * should be added for those machines where division is fast.
+ * This has special _E version because standard _4 square
+ * root would not work (it has to start normally with the
+ * second word and not the first), but as we have to do it
+ * anyway, we optimize it by doing most of the calculations
+ * in two UWtype registers instead of four.
+ */
+ 
+#define _FP_SQRT_MEAT_E(R, S, T, X, q)			\
+  do {							\
+    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);		\
+    _FP_FRAC_SRL_4(X, (_FP_WORKBITS));			\
+    while (q)						\
+      {							\
+	T##_f[1] = S##_f[1] + q;			\
+	if (T##_f[1] <= X##_f[1])			\
+	  {						\
+	    S##_f[1] = T##_f[1] + q;			\
+	    X##_f[1] -= T##_f[1];			\
+	    R##_f[1] += q;				\
+	  }						\
+	_FP_FRAC_SLL_2(X, 1);				\
+	q >>= 1;					\
+      }							\
+    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);		\
+    while (q)						\
+      {							\
+	T##_f[0] = S##_f[0] + q;			\
+	T##_f[1] = S##_f[1];				\
+	if (T##_f[1] < X##_f[1] || 			\
+	    (T##_f[1] == X##_f[1] &&			\
+	     T##_f[0] <= X##_f[0]))			\
+	  {						\
+	    S##_f[0] = T##_f[0] + q;			\
+	    S##_f[1] += (T##_f[0] > S##_f[0]);		\
+	    _FP_FRAC_DEC_2(X, T);			\
+	    R##_f[0] += q;				\
+	  }						\
+	_FP_FRAC_SLL_2(X, 1);				\
+	q >>= 1;					\
+      }							\
+    _FP_FRAC_SLL_4(R, (_FP_WORKBITS));			\
+    if (X##_f[0] | X##_f[1])				\
+      {							\
+	if (S##_f[1] < X##_f[1] || 			\
+	    (S##_f[1] == X##_f[1] &&			\
+	     S##_f[0] < X##_f[0]))			\
+	  R##_f[0] |= _FP_WORK_ROUND;			\
+	R##_f[0] |= _FP_WORK_STICKY;			\
+      }							\
+  } while (0)
+
+#define FP_CMP_E(r,X,Y,un)	_FP_CMP(E,4,r,X,Y,un)
+#define FP_CMP_EQ_E(r,X,Y)	_FP_CMP_EQ(E,4,r,X,Y)
+
+#define FP_TO_INT_E(r,X,rsz,rsg)	_FP_TO_INT(E,4,r,X,rsz,rsg)
+#define FP_TO_INT_ROUND_E(r,X,rsz,rsg)	_FP_TO_INT_ROUND(E,4,r,X,rsz,rsg)
+#define FP_FROM_INT_E(X,r,rs,rt)	_FP_FROM_INT(E,4,X,r,rs,rt)
+
+#define _FP_FRAC_HIGH_E(X)	(X##_f[2])
+#define _FP_FRAC_HIGH_RAW_E(X)	(X##_f[1])
+
+#else   /* not _FP_W_TYPE_SIZE < 64 */
+union _FP_UNION_E
+{
+  long double flt /* __attribute__((mode(TF))) */ ;
+  struct {
+#if __BYTE_ORDER == __BIG_ENDIAN
+    unsigned long pad : (_FP_W_TYPE_SIZE - 1 - _FP_EXPBITS_E);
+    unsigned sign  : 1;
+    unsigned exp   : _FP_EXPBITS_E;
+    unsigned long frac : _FP_W_TYPE_SIZE;
+#else
+    unsigned long frac : _FP_W_TYPE_SIZE;
+    unsigned exp   : _FP_EXPBITS_E;
+    unsigned sign  : 1;
+#endif
+  } bits;
+};
+
+#define FP_DECL_E(X)		_FP_DECL(2,X)
+
+#define FP_UNPACK_RAW_E(X, val)					\
+  do {								\
+    union _FP_UNION_E _flo; _flo.flt = (val);			\
+								\
+    X##_f0 = _flo.bits.frac;					\
+    X##_f1 = 0;							\
+    X##_e = _flo.bits.exp;					\
+    X##_s = _flo.bits.sign;					\
+    if (!X##_e && X##_f0 && !(X##_f0 & _FP_IMPLBIT_E))		\
+      {								\
+        X##_e++;						\
+        FP_SET_EXCEPTION(FP_EX_DENORM);				\
+      }								\
+  } while (0)
+
+#define FP_UNPACK_RAW_EP(X, val)				\
+  do {								\
+    union _FP_UNION_E *_flo =					\
+      (union _FP_UNION_E *)(val);				\
+								\
+    X##_f0 = _flo->bits.frac;					\
+    X##_f1 = 0;							\
+    X##_e = _flo->bits.exp;					\
+    X##_s = _flo->bits.sign;					\
+    if (!X##_e && X##_f0 && !(X##_f0 & _FP_IMPLBIT_E))		\
+      {								\
+        X##_e++;						\
+        FP_SET_EXCEPTION(FP_EX_DENORM);				\
+      }								\
+  } while (0)
+
+#define FP_PACK_RAW_E(val, X)					\
+  do {								\
+    union _FP_UNION_E _flo;					\
+								\
+    if (X##_e) X##_f0 |= _FP_IMPLBIT_E;				\
+    else X##_f0 &= ~(_FP_IMPLBIT_E);				\
+    _flo.bits.frac = X##_f0;					\
+    _flo.bits.exp  = X##_e;					\
+    _flo.bits.sign = X##_s;					\
+								\
+    (val) = _flo.flt;						\
+  } while (0)
+
+#define FP_PACK_RAW_EP(fs, val, X)				\
+  do {								\
+    if (!FP_INHIBIT_RESULTS)					\
+      {								\
+	union _FP_UNION_E *_flo =				\
+	  (union _FP_UNION_E *)(val);				\
+								\
+	if (X##_e) X##_f0 |= _FP_IMPLBIT_E;			\
+	else X##_f0 &= ~(_FP_IMPLBIT_E);			\
+	_flo->bits.frac = X##_f0;				\
+	_flo->bits.exp  = X##_e;				\
+	_flo->bits.sign = X##_s;				\
+      }								\
+  } while (0)
+
+
+#define FP_UNPACK_E(X,val)		\
+  do {					\
+    FP_UNPACK_RAW_E(X,val);		\
+    _FP_UNPACK_CANONICAL(E,2,X);	\
+  } while (0)
+
+#define FP_UNPACK_EP(X,val)		\
+  do {					\
+    FP_UNPACK_RAW_EP(X,val);		\
+    _FP_UNPACK_CANONICAL(E,2,X);	\
+  } while (0)
+
+#define FP_PACK_E(val,X)		\
+  do {					\
+    _FP_PACK_CANONICAL(E,2,X);		\
+    FP_PACK_RAW_E(val,X);		\
+  } while (0)
+
+#define FP_PACK_EP(val,X)		\
+  do {					\
+    _FP_PACK_CANONICAL(E,2,X);		\
+    FP_PACK_RAW_EP(val,X);		\
+  } while (0)
+
+#define FP_ISSIGNAN_E(X)	_FP_ISSIGNAN(E,2,X)
+#define FP_NEG_E(R,X)		_FP_NEG(E,2,R,X)
+#define FP_ADD_E(R,X,Y)		_FP_ADD(E,2,R,X,Y)
+#define FP_SUB_E(R,X,Y)		_FP_SUB(E,2,R,X,Y)
+#define FP_MUL_E(R,X,Y)		_FP_MUL(E,2,R,X,Y)
+#define FP_DIV_E(R,X,Y)		_FP_DIV(E,2,R,X,Y)
+#define FP_SQRT_E(R,X)		_FP_SQRT(E,2,R,X)
+
+/*
+ * Square root algorithms:
+ * We have just one right now, maybe Newton approximation
+ * should be added for those machines where division is fast.
+ * We optimize it by doing most of the calculations
+ * in one UWtype registers instead of two, although we don't
+ * have to.
+ */
+#define _FP_SQRT_MEAT_E(R, S, T, X, q)			\
+  do {							\
+    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);		\
+    _FP_FRAC_SRL_2(X, (_FP_WORKBITS));			\
+    while (q)						\
+      {							\
+        T##_f0 = S##_f0 + q;				\
+        if (T##_f0 <= X##_f0)				\
+          {						\
+            S##_f0 = T##_f0 + q;			\
+            X##_f0 -= T##_f0;				\
+            R##_f0 += q;				\
+          }						\
+        _FP_FRAC_SLL_1(X, 1);				\
+        q >>= 1;					\
+      }							\
+    _FP_FRAC_SLL_2(R, (_FP_WORKBITS));			\
+    if (X##_f0)						\
+      {							\
+	if (S##_f0 < X##_f0)				\
+	  R##_f0 |= _FP_WORK_ROUND;			\
+	R##_f0 |= _FP_WORK_STICKY;			\
+      }							\
+  } while (0)
+ 
+#define FP_CMP_E(r,X,Y,un)	_FP_CMP(E,2,r,X,Y,un)
+#define FP_CMP_EQ_E(r,X,Y)	_FP_CMP_EQ(E,2,r,X,Y)
+
+#define FP_TO_INT_E(r,X,rsz,rsg)	_FP_TO_INT(E,2,r,X,rsz,rsg)
+#define FP_TO_INT_ROUND_E(r,X,rsz,rsg)	_FP_TO_INT_ROUND(E,2,r,X,rsz,rsg)
+#define FP_FROM_INT_E(X,r,rs,rt)	_FP_FROM_INT(E,2,X,r,rs,rt)
+
+#define _FP_FRAC_HIGH_E(X)	(X##_f1)
+#define _FP_FRAC_HIGH_RAW_E(X)	(X##_f0)
+
+#endif /* not _FP_W_TYPE_SIZE < 64 */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/math-emu/op-1.h linux.14p16/include/math-emu/op-1.h
--- linux.vanilla/include/math-emu/op-1.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/math-emu/op-1.h	Thu Dec  9 15:33:13 1999
@@ -0,0 +1,297 @@
+/* Software floating-point emulation.
+   Basic one-word fraction declaration and manipulation.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+		  Jakub Jelinek (jj@ultra.linux.cz),
+		  David S. Miller (davem@redhat.com) and
+		  Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#define _FP_FRAC_DECL_1(X)	_FP_W_TYPE X##_f
+#define _FP_FRAC_COPY_1(D,S)	(D##_f = S##_f)
+#define _FP_FRAC_SET_1(X,I)	(X##_f = I)
+#define _FP_FRAC_HIGH_1(X)	(X##_f)
+#define _FP_FRAC_LOW_1(X)	(X##_f)
+#define _FP_FRAC_WORD_1(X,w)	(X##_f)
+
+#define _FP_FRAC_ADDI_1(X,I)	(X##_f += I)
+#define _FP_FRAC_SLL_1(X,N)			\
+  do {						\
+    if (__builtin_constant_p(N) && (N) == 1)	\
+      X##_f += X##_f;				\
+    else					\
+      X##_f <<= (N);				\
+  } while (0)
+#define _FP_FRAC_SRL_1(X,N)	(X##_f >>= N)
+
+/* Right shift with sticky-lsb.  */
+#define _FP_FRAC_SRS_1(X,N,sz)	__FP_FRAC_SRS_1(X##_f, N, sz)
+
+#define __FP_FRAC_SRS_1(X,N,sz)						\
+   (X = (X >> (N) | (__builtin_constant_p(N) && (N) == 1		\
+		     ? X & 1 : (X << (_FP_W_TYPE_SIZE - (N))) != 0)))
+
+#define _FP_FRAC_ADD_1(R,X,Y)	(R##_f = X##_f + Y##_f)
+#define _FP_FRAC_SUB_1(R,X,Y)	(R##_f = X##_f - Y##_f)
+#define _FP_FRAC_DEC_1(X,Y)	(X##_f -= Y##_f)
+#define _FP_FRAC_CLZ_1(z, X)	__FP_CLZ(z, X##_f)
+
+/* Predicates */
+#define _FP_FRAC_NEGP_1(X)	((_FP_WS_TYPE)X##_f < 0)
+#define _FP_FRAC_ZEROP_1(X)	(X##_f == 0)
+#define _FP_FRAC_OVERP_1(fs,X)	(X##_f & _FP_OVERFLOW_##fs)
+#define _FP_FRAC_EQ_1(X, Y)	(X##_f == Y##_f)
+#define _FP_FRAC_GE_1(X, Y)	(X##_f >= Y##_f)
+#define _FP_FRAC_GT_1(X, Y)	(X##_f > Y##_f)
+
+#define _FP_ZEROFRAC_1		0
+#define _FP_MINFRAC_1		1
+#define _FP_MAXFRAC_1		(~(_FP_WS_TYPE)0)
+
+/*
+ * Unpack the raw bits of a native fp value.  Do not classify or
+ * normalize the data.
+ */
+
+#define _FP_UNPACK_RAW_1(fs, X, val)				\
+  do {								\
+    union _FP_UNION_##fs _flo; _flo.flt = (val);		\
+								\
+    X##_f = _flo.bits.frac;					\
+    X##_e = _flo.bits.exp;					\
+    X##_s = _flo.bits.sign;					\
+  } while (0)
+
+#define _FP_UNPACK_RAW_1_P(fs, X, val)				\
+  do {								\
+    union _FP_UNION_##fs *_flo =				\
+      (union _FP_UNION_##fs *)(val);				\
+								\
+    X##_f = _flo->bits.frac;					\
+    X##_e = _flo->bits.exp;					\
+    X##_s = _flo->bits.sign;					\
+  } while (0)
+
+/*
+ * Repack the raw bits of a native fp value.
+ */
+
+#define _FP_PACK_RAW_1(fs, val, X)				\
+  do {								\
+    union _FP_UNION_##fs _flo;					\
+								\
+    _flo.bits.frac = X##_f;					\
+    _flo.bits.exp  = X##_e;					\
+    _flo.bits.sign = X##_s;					\
+								\
+    (val) = _flo.flt;						\
+  } while (0)
+
+#define _FP_PACK_RAW_1_P(fs, val, X)				\
+  do {								\
+    union _FP_UNION_##fs *_flo =				\
+      (union _FP_UNION_##fs *)(val);				\
+								\
+    _flo->bits.frac = X##_f;					\
+    _flo->bits.exp  = X##_e;					\
+    _flo->bits.sign = X##_s;					\
+  } while (0)
+
+
+/*
+ * Multiplication algorithms:
+ */
+
+/* Basic.  Assuming the host word size is >= 2*FRACBITS, we can do the
+   multiplication immediately.  */
+
+#define _FP_MUL_MEAT_1_imm(wfracbits, R, X, Y)				\
+  do {									\
+    R##_f = X##_f * Y##_f;						\
+    /* Normalize since we know where the msb of the multiplicands	\
+       were (bit B), we know that the msb of the of the product is	\
+       at either 2B or 2B-1.  */					\
+    _FP_FRAC_SRS_1(R, wfracbits-1, 2*wfracbits);			\
+  } while (0)
+
+/* Given a 1W * 1W => 2W primitive, do the extended multiplication.  */
+
+#define _FP_MUL_MEAT_1_wide(wfracbits, R, X, Y, doit)			\
+  do {									\
+    _FP_W_TYPE _Z_f0, _Z_f1;						\
+    doit(_Z_f1, _Z_f0, X##_f, Y##_f);					\
+    /* Normalize since we know where the msb of the multiplicands	\
+       were (bit B), we know that the msb of the of the product is	\
+       at either 2B or 2B-1.  */					\
+    _FP_FRAC_SRS_2(_Z, wfracbits-1, 2*wfracbits);			\
+    R##_f = _Z_f0;							\
+  } while (0)
+
+/* Finally, a simple widening multiply algorithm.  What fun!  */
+
+#define _FP_MUL_MEAT_1_hard(wfracbits, R, X, Y)				\
+  do {									\
+    _FP_W_TYPE _xh, _xl, _yh, _yl, _z_f0, _z_f1, _a_f0, _a_f1;		\
+									\
+    /* split the words in half */					\
+    _xh = X##_f >> (_FP_W_TYPE_SIZE/2);					\
+    _xl = X##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1);		\
+    _yh = Y##_f >> (_FP_W_TYPE_SIZE/2);					\
+    _yl = Y##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1);		\
+									\
+    /* multiply the pieces */						\
+    _z_f0 = _xl * _yl;							\
+    _a_f0 = _xh * _yl;							\
+    _a_f1 = _xl * _yh;							\
+    _z_f1 = _xh * _yh;							\
+									\
+    /* reassemble into two full words */				\
+    if ((_a_f0 += _a_f1) < _a_f1)					\
+      _z_f1 += (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2);			\
+    _a_f1 = _a_f0 >> (_FP_W_TYPE_SIZE/2);				\
+    _a_f0 = _a_f0 << (_FP_W_TYPE_SIZE/2);				\
+    _FP_FRAC_ADD_2(_z, _z, _a);						\
+									\
+    /* normalize */							\
+    _FP_FRAC_SRS_2(_z, wfracbits - 1, 2*wfracbits);			\
+    R##_f = _z_f0;							\
+  } while (0)
+
+
+/*
+ * Division algorithms:
+ */
+
+/* Basic.  Assuming the host word size is >= 2*FRACBITS, we can do the
+   division immediately.  Give this macro either _FP_DIV_HELP_imm for
+   C primitives or _FP_DIV_HELP_ldiv for the ISO function.  Which you
+   choose will depend on what the compiler does with divrem4.  */
+
+#define _FP_DIV_MEAT_1_imm(fs, R, X, Y, doit)		\
+  do {							\
+    _FP_W_TYPE _q, _r;					\
+    X##_f <<= (X##_f < Y##_f				\
+	       ? R##_e--, _FP_WFRACBITS_##fs		\
+	       : _FP_WFRACBITS_##fs - 1);		\
+    doit(_q, _r, X##_f, Y##_f);				\
+    R##_f = _q | (_r != 0);				\
+  } while (0)
+
+/* GCC's longlong.h defines a 2W / 1W => (1W,1W) primitive udiv_qrnnd
+   that may be useful in this situation.  This first is for a primitive
+   that requires normalization, the second for one that does not.  Look
+   for UDIV_NEEDS_NORMALIZATION to tell which your machine needs.  */
+
+#define _FP_DIV_MEAT_1_udiv_norm(fs, R, X, Y)				\
+  do {									\
+    _FP_W_TYPE _nh, _nl, _q, _r;					\
+									\
+    /* Normalize Y -- i.e. make the most significant bit set.  */	\
+    Y##_f <<= _FP_WFRACXBITS_##fs - 1;					\
+									\
+    /* Shift X op correspondingly high, that is, up one full word.  */	\
+    if (X##_f <= Y##_f)							\
+      {									\
+	_nl = 0;							\
+	_nh = X##_f;							\
+      }									\
+    else								\
+      {									\
+	R##_e++;							\
+	_nl = X##_f << (_FP_W_TYPE_SIZE-1);				\
+	_nh = X##_f >> 1;						\
+      }									\
+    									\
+    udiv_qrnnd(_q, _r, _nh, _nl, Y##_f);				\
+    R##_f = _q | (_r != 0);						\
+  } while (0)
+
+#define _FP_DIV_MEAT_1_udiv(fs, R, X, Y)		\
+  do {							\
+    _FP_W_TYPE _nh, _nl, _q, _r;			\
+    if (X##_f < Y##_f)					\
+      {							\
+	R##_e--;					\
+	_nl = X##_f << _FP_WFRACBITS_##fs;		\
+	_nh = X##_f >> _FP_WFRACXBITS_##fs;		\
+      }							\
+    else						\
+      {							\
+	_nl = X##_f << (_FP_WFRACBITS_##fs - 1);	\
+	_nh = X##_f >> (_FP_WFRACXBITS_##fs + 1);	\
+      }							\
+    udiv_qrnnd(_q, _r, _nh, _nl, Y##_f);		\
+    R##_f = _q | (_r != 0);				\
+  } while (0)
+  
+  
+/*
+ * Square root algorithms:
+ * We have just one right now, maybe Newton approximation
+ * should be added for those machines where division is fast.
+ */
+ 
+#define _FP_SQRT_MEAT_1(R, S, T, X, q)			\
+  do {							\
+    while (q != _FP_WORK_ROUND)				\
+      {							\
+        T##_f = S##_f + q;				\
+        if (T##_f <= X##_f)				\
+          {						\
+            S##_f = T##_f + q;				\
+            X##_f -= T##_f;				\
+            R##_f += q;					\
+          }						\
+        _FP_FRAC_SLL_1(X, 1);				\
+        q >>= 1;					\
+      }							\
+    if (X##_f)						\
+      {							\
+	if (S##_f < X##_f)				\
+	  R##_f |= _FP_WORK_ROUND;			\
+	R##_f |= _FP_WORK_STICKY;			\
+      }							\
+  } while (0)
+
+/*
+ * Assembly/disassembly for converting to/from integral types.  
+ * No shifting or overflow handled here.
+ */
+
+#define _FP_FRAC_ASSEMBLE_1(r, X, rsize)	(r = X##_f)
+#define _FP_FRAC_DISASSEMBLE_1(X, r, rsize)	(X##_f = r)
+
+
+/*
+ * Convert FP values between word sizes
+ */
+
+#define _FP_FRAC_CONV_1_1(dfs, sfs, D, S)				\
+  do {									\
+    D##_f = S##_f;							\
+    if (_FP_WFRACBITS_##sfs > _FP_WFRACBITS_##dfs)			\
+      {									\
+	if (S##_c != FP_CLS_NAN)					\
+	  _FP_FRAC_SRS_1(D, (_FP_WFRACBITS_##sfs-_FP_WFRACBITS_##dfs),	\
+			 _FP_WFRACBITS_##sfs);				\
+	else								\
+	  _FP_FRAC_SRL_1(D, (_FP_WFRACBITS_##sfs-_FP_WFRACBITS_##dfs));	\
+      }									\
+    else								\
+      D##_f <<= _FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs;		\
+  } while (0)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/math-emu/op-2.h linux.14p16/include/math-emu/op-2.h
--- linux.vanilla/include/math-emu/op-2.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/math-emu/op-2.h	Thu Dec  9 15:33:13 1999
@@ -0,0 +1,608 @@
+/* Software floating-point emulation.
+   Basic two-word fraction declaration and manipulation.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+		  Jakub Jelinek (jj@ultra.linux.cz),
+		  David S. Miller (davem@redhat.com) and
+		  Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#define _FP_FRAC_DECL_2(X)	_FP_W_TYPE X##_f0, X##_f1
+#define _FP_FRAC_COPY_2(D,S)	(D##_f0 = S##_f0, D##_f1 = S##_f1)
+#define _FP_FRAC_SET_2(X,I)	__FP_FRAC_SET_2(X, I)
+#define _FP_FRAC_HIGH_2(X)	(X##_f1)
+#define _FP_FRAC_LOW_2(X)	(X##_f0)
+#define _FP_FRAC_WORD_2(X,w)	(X##_f##w)
+
+#define _FP_FRAC_SLL_2(X,N)						\
+  do {									\
+    if ((N) < _FP_W_TYPE_SIZE)						\
+      {									\
+	if (__builtin_constant_p(N) && (N) == 1) 			\
+	  {								\
+	    X##_f1 = X##_f1 + X##_f1 + (((_FP_WS_TYPE)(X##_f0)) < 0);	\
+	    X##_f0 += X##_f0;						\
+	  }								\
+	else								\
+	  {								\
+	    X##_f1 = X##_f1 << (N) | X##_f0 >> (_FP_W_TYPE_SIZE - (N));	\
+	    X##_f0 <<= (N);						\
+	  }								\
+      }									\
+    else								\
+      {									\
+	X##_f1 = X##_f0 << ((N) - _FP_W_TYPE_SIZE);			\
+	X##_f0 = 0;							\
+      }									\
+  } while (0)
+
+#define _FP_FRAC_SRL_2(X,N)						\
+  do {									\
+    if ((N) < _FP_W_TYPE_SIZE)						\
+      {									\
+	X##_f0 = X##_f0 >> (N) | X##_f1 << (_FP_W_TYPE_SIZE - (N));	\
+	X##_f1 >>= (N);							\
+      }									\
+    else								\
+      {									\
+	X##_f0 = X##_f1 >> ((N) - _FP_W_TYPE_SIZE);			\
+	X##_f1 = 0;							\
+      }									\
+  } while (0)
+
+/* Right shift with sticky-lsb.  */
+#define _FP_FRAC_SRS_2(X,N,sz)						\
+  do {									\
+    if ((N) < _FP_W_TYPE_SIZE)						\
+      {									\
+	X##_f0 = (X##_f1 << (_FP_W_TYPE_SIZE - (N)) | X##_f0 >> (N) |	\
+		  (__builtin_constant_p(N) && (N) == 1			\
+		   ? X##_f0 & 1						\
+		   : (X##_f0 << (_FP_W_TYPE_SIZE - (N))) != 0));	\
+	X##_f1 >>= (N);							\
+      }									\
+    else								\
+      {									\
+	X##_f0 = (X##_f1 >> ((N) - _FP_W_TYPE_SIZE) |			\
+		  (((X##_f1 << (sz - (N))) | X##_f0) != 0));		\
+	X##_f1 = 0;							\
+      }									\
+  } while (0)
+
+#define _FP_FRAC_ADDI_2(X,I)	\
+  __FP_FRAC_ADDI_2(X##_f1, X##_f0, I)
+
+#define _FP_FRAC_ADD_2(R,X,Y)	\
+  __FP_FRAC_ADD_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0)
+
+#define _FP_FRAC_SUB_2(R,X,Y)	\
+  __FP_FRAC_SUB_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0)
+
+#define _FP_FRAC_DEC_2(X,Y)	\
+  __FP_FRAC_DEC_2(X##_f1, X##_f0, Y##_f1, Y##_f0)
+
+#define _FP_FRAC_CLZ_2(R,X)	\
+  do {				\
+    if (X##_f1)			\
+      __FP_CLZ(R,X##_f1);	\
+    else 			\
+    {				\
+      __FP_CLZ(R,X##_f0);	\
+      R += _FP_W_TYPE_SIZE;	\
+    }				\
+  } while(0)
+
+/* Predicates */
+#define _FP_FRAC_NEGP_2(X)	((_FP_WS_TYPE)X##_f1 < 0)
+#define _FP_FRAC_ZEROP_2(X)	((X##_f1 | X##_f0) == 0)
+#define _FP_FRAC_OVERP_2(fs,X)	(_FP_FRAC_HIGH_##fs(X) & _FP_OVERFLOW_##fs)
+#define _FP_FRAC_EQ_2(X, Y)	(X##_f1 == Y##_f1 && X##_f0 == Y##_f0)
+#define _FP_FRAC_GT_2(X, Y)	\
+  (X##_f1 > Y##_f1 || X##_f1 == Y##_f1 && X##_f0 > Y##_f0)
+#define _FP_FRAC_GE_2(X, Y)	\
+  (X##_f1 > Y##_f1 || X##_f1 == Y##_f1 && X##_f0 >= Y##_f0)
+
+#define _FP_ZEROFRAC_2		0, 0
+#define _FP_MINFRAC_2		0, 1
+#define _FP_MAXFRAC_2		(~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0)
+
+/*
+ * Internals 
+ */
+
+#define __FP_FRAC_SET_2(X,I1,I0)	(X##_f0 = I0, X##_f1 = I1)
+
+#define __FP_CLZ_2(R, xh, xl)	\
+  do {				\
+    if (xh)			\
+      __FP_CLZ(R,xh);		\
+    else 			\
+    {				\
+      __FP_CLZ(R,xl);		\
+      R += _FP_W_TYPE_SIZE;	\
+    }				\
+  } while(0)
+
+#if 0
+
+#ifndef __FP_FRAC_ADDI_2
+#define __FP_FRAC_ADDI_2(xh, xl, i)	\
+  (xh += ((xl += i) < i))
+#endif
+#ifndef __FP_FRAC_ADD_2
+#define __FP_FRAC_ADD_2(rh, rl, xh, xl, yh, yl)	\
+  (rh = xh + yh + ((rl = xl + yl) < xl))
+#endif
+#ifndef __FP_FRAC_SUB_2
+#define __FP_FRAC_SUB_2(rh, rl, xh, xl, yh, yl)	\
+  (rh = xh - yh - ((rl = xl - yl) > xl))
+#endif
+#ifndef __FP_FRAC_DEC_2
+#define __FP_FRAC_DEC_2(xh, xl, yh, yl)	\
+  do {					\
+    UWtype _t = xl;			\
+    xh -= yh + ((xl -= yl) > _t);	\
+  } while (0)
+#endif
+
+#else
+
+#undef __FP_FRAC_ADDI_2
+#define __FP_FRAC_ADDI_2(xh, xl, i)	add_ssaaaa(xh, xl, xh, xl, 0, i)
+#undef __FP_FRAC_ADD_2
+#define __FP_FRAC_ADD_2			add_ssaaaa
+#undef __FP_FRAC_SUB_2
+#define __FP_FRAC_SUB_2			sub_ddmmss
+#undef __FP_FRAC_DEC_2
+#define __FP_FRAC_DEC_2(xh, xl, yh, yl)	sub_ddmmss(xh, xl, xh, xl, yh, yl)
+
+#endif
+
+/*
+ * Unpack the raw bits of a native fp value.  Do not classify or
+ * normalize the data.
+ */
+
+#define _FP_UNPACK_RAW_2(fs, X, val)			\
+  do {							\
+    union _FP_UNION_##fs _flo; _flo.flt = (val);	\
+							\
+    X##_f0 = _flo.bits.frac0;				\
+    X##_f1 = _flo.bits.frac1;				\
+    X##_e  = _flo.bits.exp;				\
+    X##_s  = _flo.bits.sign;				\
+  } while (0)
+
+#define _FP_UNPACK_RAW_2_P(fs, X, val)			\
+  do {							\
+    union _FP_UNION_##fs *_flo =			\
+      (union _FP_UNION_##fs *)(val);			\
+							\
+    X##_f0 = _flo->bits.frac0;				\
+    X##_f1 = _flo->bits.frac1;				\
+    X##_e  = _flo->bits.exp;				\
+    X##_s  = _flo->bits.sign;				\
+  } while (0)
+
+
+/*
+ * Repack the raw bits of a native fp value.
+ */
+
+#define _FP_PACK_RAW_2(fs, val, X)			\
+  do {							\
+    union _FP_UNION_##fs _flo;				\
+							\
+    _flo.bits.frac0 = X##_f0;				\
+    _flo.bits.frac1 = X##_f1;				\
+    _flo.bits.exp   = X##_e;				\
+    _flo.bits.sign  = X##_s;				\
+							\
+    (val) = _flo.flt;					\
+  } while (0)
+
+#define _FP_PACK_RAW_2_P(fs, val, X)			\
+  do {							\
+    union _FP_UNION_##fs *_flo =			\
+      (union _FP_UNION_##fs *)(val);			\
+							\
+    _flo->bits.frac0 = X##_f0;				\
+    _flo->bits.frac1 = X##_f1;				\
+    _flo->bits.exp   = X##_e;				\
+    _flo->bits.sign  = X##_s;				\
+  } while (0)
+
+
+/*
+ * Multiplication algorithms:
+ */
+
+/* Given a 1W * 1W => 2W primitive, do the extended multiplication.  */
+
+#define _FP_MUL_MEAT_2_wide(wfracbits, R, X, Y, doit)			\
+  do {									\
+    _FP_FRAC_DECL_4(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c);	\
+									\
+    doit(_FP_FRAC_WORD_4(_z,1), _FP_FRAC_WORD_4(_z,0), X##_f0, Y##_f0);	\
+    doit(_b_f1, _b_f0, X##_f0, Y##_f1);					\
+    doit(_c_f1, _c_f0, X##_f1, Y##_f0);					\
+    doit(_FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2), X##_f1, Y##_f1);	\
+									\
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),	\
+		    _FP_FRAC_WORD_4(_z,1), 0, _b_f1, _b_f0,		\
+		    _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),	\
+		    _FP_FRAC_WORD_4(_z,1));				\
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),	\
+		    _FP_FRAC_WORD_4(_z,1), 0, _c_f1, _c_f0,		\
+		    _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),	\
+		    _FP_FRAC_WORD_4(_z,1));				\
+									\
+    /* Normalize since we know where the msb of the multiplicands	\
+       were (bit B), we know that the msb of the of the product is	\
+       at either 2B or 2B-1.  */					\
+    _FP_FRAC_SRS_4(_z, wfracbits-1, 2*wfracbits);			\
+    R##_f0 = _FP_FRAC_WORD_4(_z,0);					\
+    R##_f1 = _FP_FRAC_WORD_4(_z,1);					\
+  } while (0)
+
+/* Given a 1W * 1W => 2W primitive, do the extended multiplication.
+   Do only 3 multiplications instead of four. This one is for machines
+   where multiplication is much more expensive than subtraction.  */
+
+#define _FP_MUL_MEAT_2_wide_3mul(wfracbits, R, X, Y, doit)		\
+  do {									\
+    _FP_FRAC_DECL_4(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c);	\
+    _FP_W_TYPE _d;							\
+    int _c1, _c2;							\
+									\
+    _b_f0 = X##_f0 + X##_f1;						\
+    _c1 = _b_f0 < X##_f0;						\
+    _b_f1 = Y##_f0 + Y##_f1;						\
+    _c2 = _b_f1 < Y##_f0;						\
+    doit(_d, _FP_FRAC_WORD_4(_z,0), X##_f0, Y##_f0);			\
+    doit(_FP_FRAC_WORD_4(_z,2), _FP_FRAC_WORD_4(_z,1), _b_f0, _b_f1);	\
+    doit(_c_f1, _c_f0, X##_f1, Y##_f1);					\
+									\
+    _b_f0 &= -_c2;							\
+    _b_f1 &= -_c1;							\
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),	\
+		    _FP_FRAC_WORD_4(_z,1), (_c1 & _c2), 0, _d,		\
+		    0, _FP_FRAC_WORD_4(_z,2), _FP_FRAC_WORD_4(_z,1));	\
+    __FP_FRAC_ADDI_2(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),	\
+		     _b_f0);						\
+    __FP_FRAC_ADDI_2(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),	\
+		     _b_f1);						\
+    __FP_FRAC_DEC_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),	\
+		    _FP_FRAC_WORD_4(_z,1),				\
+		    0, _d, _FP_FRAC_WORD_4(_z,0));			\
+    __FP_FRAC_DEC_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),	\
+		    _FP_FRAC_WORD_4(_z,1), 0, _c_f1, _c_f0);		\
+    __FP_FRAC_ADD_2(_FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2),	\
+		    _c_f1, _c_f0,					\
+		    _FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2));	\
+									\
+    /* Normalize since we know where the msb of the multiplicands	\
+       were (bit B), we know that the msb of the of the product is	\
+       at either 2B or 2B-1.  */					\
+    _FP_FRAC_SRS_4(_z, wfracbits-1, 2*wfracbits);			\
+    R##_f0 = _FP_FRAC_WORD_4(_z,0);					\
+    R##_f1 = _FP_FRAC_WORD_4(_z,1);					\
+  } while (0)
+
+#define _FP_MUL_MEAT_2_gmp(wfracbits, R, X, Y)				\
+  do {									\
+    _FP_FRAC_DECL_4(_z);						\
+    _FP_W_TYPE _x[2], _y[2];						\
+    _x[0] = X##_f0; _x[1] = X##_f1;					\
+    _y[0] = Y##_f0; _y[1] = Y##_f1;					\
+									\
+    mpn_mul_n(_z_f, _x, _y, 2);						\
+									\
+    /* Normalize since we know where the msb of the multiplicands	\
+       were (bit B), we know that the msb of the of the product is	\
+       at either 2B or 2B-1.  */					\
+    _FP_FRAC_SRS_4(_z, wfracbits-1, 2*wfracbits);			\
+    R##_f0 = _z_f[0];							\
+    R##_f1 = _z_f[1];							\
+  } while (0)
+
+/* Do at most 120x120=240 bits multiplication using double floating
+   point multiplication.  This is useful if floating point
+   multiplication has much bigger throughput than integer multiply.
+   It is supposed to work for _FP_W_TYPE_SIZE 64 and wfracbits
+   between 106 and 120 only.  
+   Caller guarantees that X and Y has (1LLL << (wfracbits - 1)) set.
+   SETFETZ is a macro which will disable all FPU exceptions and set rounding
+   towards zero,  RESETFE should optionally reset it back.  */
+
+#define _FP_MUL_MEAT_2_120_240_double(wfracbits, R, X, Y, setfetz, resetfe)	\
+  do {										\
+    static const double _const[] = {						\
+      /* 2^-24 */ 5.9604644775390625e-08,					\
+      /* 2^-48 */ 3.5527136788005009e-15,					\
+      /* 2^-72 */ 2.1175823681357508e-22,					\
+      /* 2^-96 */ 1.2621774483536189e-29,					\
+      /* 2^28 */ 2.68435456e+08,						\
+      /* 2^4 */ 1.600000e+01,							\
+      /* 2^-20 */ 9.5367431640625e-07,						\
+      /* 2^-44 */ 5.6843418860808015e-14,					\
+      /* 2^-68 */ 3.3881317890172014e-21,					\
+      /* 2^-92 */ 2.0194839173657902e-28,					\
+      /* 2^-116 */ 1.2037062152420224e-35};					\
+    double _a240, _b240, _c240, _d240, _e240, _f240, 				\
+	   _g240, _h240, _i240, _j240, _k240;					\
+    union { double d; UDItype i; } _l240, _m240, _n240, _o240,			\
+				   _p240, _q240, _r240, _s240;			\
+    UDItype _t240, _u240, _v240, _w240, _x240, _y240 = 0;			\
+										\
+    if (wfracbits < 106 || wfracbits > 120)					\
+      abort();									\
+										\
+    setfetz;									\
+										\
+    _e240 = (double)(long)(X##_f0 & 0xffffff);					\
+    _j240 = (double)(long)(Y##_f0 & 0xffffff);					\
+    _d240 = (double)(long)((X##_f0 >> 24) & 0xffffff);				\
+    _i240 = (double)(long)((Y##_f0 >> 24) & 0xffffff);				\
+    _c240 = (double)(long)(((X##_f1 << 16) & 0xffffff) | (X##_f0 >> 48));	\
+    _h240 = (double)(long)(((Y##_f1 << 16) & 0xffffff) | (Y##_f0 >> 48));	\
+    _b240 = (double)(long)((X##_f1 >> 8) & 0xffffff);				\
+    _g240 = (double)(long)((Y##_f1 >> 8) & 0xffffff);				\
+    _a240 = (double)(long)(X##_f1 >> 32);					\
+    _f240 = (double)(long)(Y##_f1 >> 32);					\
+    _e240 *= _const[3];								\
+    _j240 *= _const[3];								\
+    _d240 *= _const[2];								\
+    _i240 *= _const[2];								\
+    _c240 *= _const[1];								\
+    _h240 *= _const[1];								\
+    _b240 *= _const[0];								\
+    _g240 *= _const[0];								\
+    _s240.d =							      _e240*_j240;\
+    _r240.d =						_d240*_j240 + _e240*_i240;\
+    _q240.d =				  _c240*_j240 + _d240*_i240 + _e240*_h240;\
+    _p240.d =		    _b240*_j240 + _c240*_i240 + _d240*_h240 + _e240*_g240;\
+    _o240.d = _a240*_j240 + _b240*_i240 + _c240*_h240 + _d240*_g240 + _e240*_f240;\
+    _n240.d = _a240*_i240 + _b240*_h240 + _c240*_g240 + _d240*_f240;		\
+    _m240.d = _a240*_h240 + _b240*_g240 + _c240*_f240;				\
+    _l240.d = _a240*_g240 + _b240*_f240;					\
+    _k240 =   _a240*_f240;							\
+    _r240.d += _s240.d;								\
+    _q240.d += _r240.d;								\
+    _p240.d += _q240.d;								\
+    _o240.d += _p240.d;								\
+    _n240.d += _o240.d;								\
+    _m240.d += _n240.d;								\
+    _l240.d += _m240.d;								\
+    _k240 += _l240.d;								\
+    _s240.d -= ((_const[10]+_s240.d)-_const[10]);				\
+    _r240.d -= ((_const[9]+_r240.d)-_const[9]);					\
+    _q240.d -= ((_const[8]+_q240.d)-_const[8]);					\
+    _p240.d -= ((_const[7]+_p240.d)-_const[7]);					\
+    _o240.d += _const[7];							\
+    _n240.d += _const[6];							\
+    _m240.d += _const[5];							\
+    _l240.d += _const[4];							\
+    if (_s240.d != 0.0) _y240 = 1;						\
+    if (_r240.d != 0.0) _y240 = 1;						\
+    if (_q240.d != 0.0) _y240 = 1;						\
+    if (_p240.d != 0.0) _y240 = 1;						\
+    _t240 = (DItype)_k240;							\
+    _u240 = _l240.i;								\
+    _v240 = _m240.i;								\
+    _w240 = _n240.i;								\
+    _x240 = _o240.i;								\
+    R##_f1 = (_t240 << (128 - (wfracbits - 1)))					\
+	     | ((_u240 & 0xffffff) >> ((wfracbits - 1) - 104));			\
+    R##_f0 = ((_u240 & 0xffffff) << (168 - (wfracbits - 1)))			\
+    	     | ((_v240 & 0xffffff) << (144 - (wfracbits - 1)))			\
+    	     | ((_w240 & 0xffffff) << (120 - (wfracbits - 1)))			\
+    	     | ((_x240 & 0xffffff) >> ((wfracbits - 1) - 96))			\
+    	     | _y240;								\
+    resetfe;									\
+  } while (0)
+
+/*
+ * Division algorithms:
+ */
+
+#define _FP_DIV_MEAT_2_udiv(fs, R, X, Y)				\
+  do {									\
+    _FP_W_TYPE _n_f2, _n_f1, _n_f0, _r_f1, _r_f0, _m_f1, _m_f0;		\
+    if (_FP_FRAC_GT_2(X, Y))						\
+      {									\
+	_n_f2 = X##_f1 >> 1;						\
+	_n_f1 = X##_f1 << (_FP_W_TYPE_SIZE - 1) | X##_f0 >> 1;		\
+	_n_f0 = X##_f0 << (_FP_W_TYPE_SIZE - 1);			\
+      }									\
+    else								\
+      {									\
+	R##_e--;							\
+	_n_f2 = X##_f1;							\
+	_n_f1 = X##_f0;							\
+	_n_f0 = 0;							\
+      }									\
+									\
+    /* Normalize, i.e. make the most significant bit of the 		\
+       denominator set. */						\
+    _FP_FRAC_SLL_2(Y, _FP_WFRACXBITS_##fs);				\
+									\
+    udiv_qrnnd(R##_f1, _r_f1, _n_f2, _n_f1, Y##_f1);			\
+    umul_ppmm(_m_f1, _m_f0, R##_f1, Y##_f0);				\
+    _r_f0 = _n_f0;							\
+    if (_FP_FRAC_GT_2(_m, _r))						\
+      {									\
+	R##_f1--;							\
+	_FP_FRAC_ADD_2(_r, Y, _r);					\
+	if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r))		\
+	  {								\
+	    R##_f1--;							\
+	    _FP_FRAC_ADD_2(_r, Y, _r);					\
+	  }								\
+      }									\
+    _FP_FRAC_DEC_2(_r, _m);						\
+									\
+    if (_r_f1 == Y##_f1)						\
+      {									\
+	/* This is a special case, not an optimization			\
+	   (_r/Y##_f1 would not fit into UWtype).			\
+	   As _r is guaranteed to be < Y,  R##_f0 can be either		\
+	   (UWtype)-1 or (UWtype)-2.  But as we know what kind		\
+	   of bits it is (sticky, guard, round),  we don't care.	\
+	   We also don't care what the reminder is,  because the	\
+	   guard bit will be set anyway.  -jj */			\
+	R##_f0 = -1;							\
+      }									\
+    else								\
+      {									\
+	udiv_qrnnd(R##_f0, _r_f1, _r_f1, _r_f0, Y##_f1);		\
+	umul_ppmm(_m_f1, _m_f0, R##_f0, Y##_f0);			\
+	_r_f0 = 0;							\
+	if (_FP_FRAC_GT_2(_m, _r))					\
+	  {								\
+	    R##_f0--;							\
+	    _FP_FRAC_ADD_2(_r, Y, _r);					\
+	    if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r))		\
+	      {								\
+		R##_f0--;						\
+		_FP_FRAC_ADD_2(_r, Y, _r);				\
+	      }								\
+	  }								\
+	if (!_FP_FRAC_EQ_2(_r, _m))					\
+	  R##_f0 |= _FP_WORK_STICKY;					\
+      }									\
+  } while (0)
+
+
+#define _FP_DIV_MEAT_2_gmp(fs, R, X, Y)					\
+  do {									\
+    _FP_W_TYPE _x[4], _y[2], _z[4];					\
+    _y[0] = Y##_f0; _y[1] = Y##_f1;					\
+    _x[0] = _x[3] = 0;							\
+    if (_FP_FRAC_GT_2(X, Y))						\
+      {									\
+	R##_e++;							\
+	_x[1] = (X##_f0 << (_FP_WFRACBITS_##fs-1 - _FP_W_TYPE_SIZE) |	\
+		 X##_f1 >> (_FP_W_TYPE_SIZE -				\
+			    (_FP_WFRACBITS_##fs-1 - _FP_W_TYPE_SIZE)));	\
+	_x[2] = X##_f1 << (_FP_WFRACBITS_##fs-1 - _FP_W_TYPE_SIZE);	\
+      }									\
+    else								\
+      {									\
+	_x[1] = (X##_f0 << (_FP_WFRACBITS_##fs - _FP_W_TYPE_SIZE) |	\
+		 X##_f1 >> (_FP_W_TYPE_SIZE -				\
+			    (_FP_WFRACBITS_##fs - _FP_W_TYPE_SIZE)));	\
+	_x[2] = X##_f1 << (_FP_WFRACBITS_##fs - _FP_W_TYPE_SIZE);	\
+      }									\
+									\
+    (void) mpn_divrem (_z, 0, _x, 4, _y, 2);				\
+    R##_f1 = _z[1];							\
+    R##_f0 = _z[0] | ((_x[0] | _x[1]) != 0);				\
+  } while (0)
+
+
+/*
+ * Square root algorithms:
+ * We have just one right now, maybe Newton approximation
+ * should be added for those machines where division is fast.
+ */
+ 
+#define _FP_SQRT_MEAT_2(R, S, T, X, q)			\
+  do {							\
+    while (q)						\
+      {							\
+	T##_f1 = S##_f1 + q;				\
+	if (T##_f1 <= X##_f1)				\
+	  {						\
+	    S##_f1 = T##_f1 + q;			\
+	    X##_f1 -= T##_f1;				\
+	    R##_f1 += q;				\
+	  }						\
+	_FP_FRAC_SLL_2(X, 1);				\
+	q >>= 1;					\
+      }							\
+    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);		\
+    while (q != _FP_WORK_ROUND)				\
+      {							\
+	T##_f0 = S##_f0 + q;				\
+	T##_f1 = S##_f1;				\
+	if (T##_f1 < X##_f1 || 				\
+	    (T##_f1 == X##_f1 && T##_f0 <= X##_f0))	\
+	  {						\
+	    S##_f0 = T##_f0 + q;			\
+	    S##_f1 += (T##_f0 > S##_f0);		\
+	    _FP_FRAC_DEC_2(X, T);			\
+	    R##_f0 += q;				\
+	  }						\
+	_FP_FRAC_SLL_2(X, 1);				\
+	q >>= 1;					\
+      }							\
+    if (X##_f0 | X##_f1)				\
+      {							\
+	if (S##_f1 < X##_f1 || 				\
+	    (S##_f1 == X##_f1 && S##_f0 < X##_f0))	\
+	  R##_f0 |= _FP_WORK_ROUND;			\
+	R##_f0 |= _FP_WORK_STICKY;			\
+      }							\
+  } while (0)
+
+
+/*
+ * Assembly/disassembly for converting to/from integral types.  
+ * No shifting or overflow handled here.
+ */
+
+#define _FP_FRAC_ASSEMBLE_2(r, X, rsize)	\
+  do {						\
+    if (rsize <= _FP_W_TYPE_SIZE)		\
+      r = X##_f0;				\
+    else					\
+      {						\
+	r = X##_f1;				\
+	r <<= _FP_W_TYPE_SIZE;			\
+	r += X##_f0;				\
+      }						\
+  } while (0)
+
+#define _FP_FRAC_DISASSEMBLE_2(X, r, rsize)				\
+  do {									\
+    X##_f0 = r;								\
+    X##_f1 = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE);	\
+  } while (0)
+
+/*
+ * Convert FP values between word sizes
+ */
+
+#define _FP_FRAC_CONV_1_2(dfs, sfs, D, S)				\
+  do {									\
+    if (S##_c != FP_CLS_NAN)						\
+      _FP_FRAC_SRS_2(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),	\
+		     _FP_WFRACBITS_##sfs);				\
+    else								\
+      _FP_FRAC_SRL_2(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs));	\
+    D##_f = S##_f0;							\
+  } while (0)
+
+#define _FP_FRAC_CONV_2_1(dfs, sfs, D, S)				\
+  do {									\
+    D##_f0 = S##_f;							\
+    D##_f1 = 0;								\
+    _FP_FRAC_SLL_2(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));	\
+  } while (0)
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/math-emu/op-4.h linux.14p16/include/math-emu/op-4.h
--- linux.vanilla/include/math-emu/op-4.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/math-emu/op-4.h	Thu Dec  9 15:33:13 1999
@@ -0,0 +1,661 @@
+/* Software floating-point emulation.
+   Basic four-word fraction declaration and manipulation.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+		  Jakub Jelinek (jj@ultra.linux.cz),
+		  David S. Miller (davem@redhat.com) and
+		  Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#define _FP_FRAC_DECL_4(X)	_FP_W_TYPE X##_f[4]
+#define _FP_FRAC_COPY_4(D,S)			\
+  (D##_f[0] = S##_f[0], D##_f[1] = S##_f[1],	\
+   D##_f[2] = S##_f[2], D##_f[3] = S##_f[3])
+#define _FP_FRAC_SET_4(X,I)	__FP_FRAC_SET_4(X, I)
+#define _FP_FRAC_HIGH_4(X)	(X##_f[3])
+#define _FP_FRAC_LOW_4(X)	(X##_f[0])
+#define _FP_FRAC_WORD_4(X,w)	(X##_f[w])
+
+#define _FP_FRAC_SLL_4(X,N)						\
+  do {									\
+    _FP_I_TYPE _up, _down, _skip, _i;					\
+    _skip = (N) / _FP_W_TYPE_SIZE;					\
+    _up = (N) % _FP_W_TYPE_SIZE;					\
+    _down = _FP_W_TYPE_SIZE - _up;					\
+    if (!_up)								\
+      for (_i = 3; _i >= _skip; --_i)					\
+	X##_f[_i] = X##_f[_i-_skip];					\
+    else								\
+      {									\
+	for (_i = 3; _i > _skip; --_i)					\
+	  X##_f[_i] = X##_f[_i-_skip] << _up				\
+		      | X##_f[_i-_skip-1] >> _down;			\
+	X##_f[_i--] = X##_f[0] << _up; 					\
+      }									\
+    for (; _i >= 0; --_i)						\
+      X##_f[_i] = 0;							\
+  } while (0)
+
+/* This one was broken too */
+#define _FP_FRAC_SRL_4(X,N)						\
+  do {									\
+    _FP_I_TYPE _up, _down, _skip, _i;					\
+    _skip = (N) / _FP_W_TYPE_SIZE;					\
+    _down = (N) % _FP_W_TYPE_SIZE;					\
+    _up = _FP_W_TYPE_SIZE - _down;					\
+    if (!_down)								\
+      for (_i = 0; _i <= 3-_skip; ++_i)					\
+	X##_f[_i] = X##_f[_i+_skip];					\
+    else								\
+      {									\
+	for (_i = 0; _i < 3-_skip; ++_i)				\
+	  X##_f[_i] = X##_f[_i+_skip] >> _down				\
+		      | X##_f[_i+_skip+1] << _up;			\
+	X##_f[_i++] = X##_f[3] >> _down;				\
+      }									\
+    for (; _i < 4; ++_i)						\
+      X##_f[_i] = 0;							\
+  } while (0)
+
+
+/* Right shift with sticky-lsb. 
+ * What this actually means is that we do a standard right-shift,
+ * but that if any of the bits that fall off the right hand side
+ * were one then we always set the LSbit.
+ */
+#define _FP_FRAC_SRS_4(X,N,size)					\
+  do {									\
+    _FP_I_TYPE _up, _down, _skip, _i;					\
+    _FP_W_TYPE _s;							\
+    _skip = (N) / _FP_W_TYPE_SIZE;					\
+    _down = (N) % _FP_W_TYPE_SIZE;					\
+    _up = _FP_W_TYPE_SIZE - _down;					\
+    for (_s = _i = 0; _i < _skip; ++_i)					\
+      _s |= X##_f[_i];							\
+    _s |= X##_f[_i] << _up;						\
+/* s is now != 0 if we want to set the LSbit */				\
+    if (!_down)								\
+      for (_i = 0; _i <= 3-_skip; ++_i)					\
+	X##_f[_i] = X##_f[_i+_skip];					\
+    else								\
+      {									\
+	for (_i = 0; _i < 3-_skip; ++_i)				\
+	  X##_f[_i] = X##_f[_i+_skip] >> _down				\
+		      | X##_f[_i+_skip+1] << _up;			\
+	X##_f[_i++] = X##_f[3] >> _down;				\
+      }									\
+    for (; _i < 4; ++_i)						\
+      X##_f[_i] = 0;							\
+    /* don't fix the LSB until the very end when we're sure f[0] is stable */	\
+    X##_f[0] |= (_s != 0);						\
+  } while (0)
+
+#define _FP_FRAC_ADD_4(R,X,Y)						\
+  __FP_FRAC_ADD_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0],		\
+		  X##_f[3], X##_f[2], X##_f[1], X##_f[0],		\
+		  Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
+
+#define _FP_FRAC_SUB_4(R,X,Y)						\
+  __FP_FRAC_SUB_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0],		\
+		  X##_f[3], X##_f[2], X##_f[1], X##_f[0],		\
+		  Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
+
+#define _FP_FRAC_DEC_4(X,Y)						\
+  __FP_FRAC_DEC_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0],		\
+		  Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
+
+#define _FP_FRAC_ADDI_4(X,I)						\
+  __FP_FRAC_ADDI_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], I)
+
+#define _FP_ZEROFRAC_4  0,0,0,0
+#define _FP_MINFRAC_4   0,0,0,1
+#define _FP_MAXFRAC_4	(~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0)
+
+#define _FP_FRAC_ZEROP_4(X)     ((X##_f[0] | X##_f[1] | X##_f[2] | X##_f[3]) == 0)
+#define _FP_FRAC_NEGP_4(X)      ((_FP_WS_TYPE)X##_f[3] < 0)
+#define _FP_FRAC_OVERP_4(fs,X)  (_FP_FRAC_HIGH_##fs(X) & _FP_OVERFLOW_##fs)
+
+#define _FP_FRAC_EQ_4(X,Y)				\
+ (X##_f[0] == Y##_f[0] && X##_f[1] == Y##_f[1]		\
+  && X##_f[2] == Y##_f[2] && X##_f[3] == Y##_f[3])
+
+#define _FP_FRAC_GT_4(X,Y)				\
+ (X##_f[3] > Y##_f[3] ||				\
+  (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] ||	\
+   (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] ||	\
+    (X##_f[1] == Y##_f[1] && X##_f[0] > Y##_f[0])	\
+   ))							\
+  ))							\
+ )
+
+#define _FP_FRAC_GE_4(X,Y)				\
+ (X##_f[3] > Y##_f[3] ||				\
+  (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] ||	\
+   (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] ||	\
+    (X##_f[1] == Y##_f[1] && X##_f[0] >= Y##_f[0])	\
+   ))							\
+  ))							\
+ )
+
+
+#define _FP_FRAC_CLZ_4(R,X)		\
+  do {					\
+    if (X##_f[3])			\
+    {					\
+	__FP_CLZ(R,X##_f[3]);		\
+    }					\
+    else if (X##_f[2])			\
+    {					\
+	__FP_CLZ(R,X##_f[2]);		\
+	R += _FP_W_TYPE_SIZE;		\
+    }					\
+    else if (X##_f[1])			\
+    {					\
+	__FP_CLZ(R,X##_f[2]);		\
+	R += _FP_W_TYPE_SIZE*2;		\
+    }					\
+    else				\
+    {					\
+	__FP_CLZ(R,X##_f[0]);		\
+	R += _FP_W_TYPE_SIZE*3;		\
+    }					\
+  } while(0)
+
+
+#define _FP_UNPACK_RAW_4(fs, X, val)				\
+  do {								\
+    union _FP_UNION_##fs _flo; _flo.flt = (val);		\
+    X##_f[0] = _flo.bits.frac0;					\
+    X##_f[1] = _flo.bits.frac1;					\
+    X##_f[2] = _flo.bits.frac2;					\
+    X##_f[3] = _flo.bits.frac3;					\
+    X##_e  = _flo.bits.exp;					\
+    X##_s  = _flo.bits.sign;					\
+  } while (0)
+
+#define _FP_UNPACK_RAW_4_P(fs, X, val)				\
+  do {								\
+    union _FP_UNION_##fs *_flo =				\
+      (union _FP_UNION_##fs *)(val);				\
+								\
+    X##_f[0] = _flo->bits.frac0;				\
+    X##_f[1] = _flo->bits.frac1;				\
+    X##_f[2] = _flo->bits.frac2;				\
+    X##_f[3] = _flo->bits.frac3;				\
+    X##_e  = _flo->bits.exp;					\
+    X##_s  = _flo->bits.sign;					\
+  } while (0)
+
+#define _FP_PACK_RAW_4(fs, val, X)				\
+  do {								\
+    union _FP_UNION_##fs _flo;					\
+    _flo.bits.frac0 = X##_f[0];					\
+    _flo.bits.frac1 = X##_f[1];					\
+    _flo.bits.frac2 = X##_f[2];					\
+    _flo.bits.frac3 = X##_f[3];					\
+    _flo.bits.exp   = X##_e;					\
+    _flo.bits.sign  = X##_s;					\
+    (val) = _flo.flt;				   		\
+  } while (0)
+
+#define _FP_PACK_RAW_4_P(fs, val, X)				\
+  do {								\
+    union _FP_UNION_##fs *_flo =				\
+      (union _FP_UNION_##fs *)(val);				\
+								\
+    _flo->bits.frac0 = X##_f[0];				\
+    _flo->bits.frac1 = X##_f[1];				\
+    _flo->bits.frac2 = X##_f[2];				\
+    _flo->bits.frac3 = X##_f[3];				\
+    _flo->bits.exp   = X##_e;					\
+    _flo->bits.sign  = X##_s;					\
+  } while (0)
+
+/*
+ * Multiplication algorithms:
+ */
+
+/* Given a 1W * 1W => 2W primitive, do the extended multiplication.  */
+
+#define _FP_MUL_MEAT_4_wide(wfracbits, R, X, Y, doit)			    \
+  do {									    \
+    _FP_FRAC_DECL_8(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c);	    \
+    _FP_FRAC_DECL_2(_d); _FP_FRAC_DECL_2(_e); _FP_FRAC_DECL_2(_f);	    \
+									    \
+    doit(_FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0), X##_f[0], Y##_f[0]); \
+    doit(_b_f1, _b_f0, X##_f[0], Y##_f[1]);				    \
+    doit(_c_f1, _c_f0, X##_f[1], Y##_f[0]);				    \
+    doit(_d_f1, _d_f0, X##_f[1], Y##_f[1]);				    \
+    doit(_e_f1, _e_f0, X##_f[0], Y##_f[2]);				    \
+    doit(_f_f1, _f_f0, X##_f[2], Y##_f[0]);				    \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2),	    \
+		    _FP_FRAC_WORD_8(_z,1), 0,_b_f1,_b_f0,		    \
+		    0,0,_FP_FRAC_WORD_8(_z,1));				    \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2),	    \
+		    _FP_FRAC_WORD_8(_z,1), 0,_c_f1,_c_f0,		    \
+		    _FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2),	    \
+		    _FP_FRAC_WORD_8(_z,1));				    \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3),	    \
+		    _FP_FRAC_WORD_8(_z,2), 0,_d_f1,_d_f0,		    \
+		    0,_FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2));	    \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3),	    \
+		    _FP_FRAC_WORD_8(_z,2), 0,_e_f1,_e_f0,		    \
+		    _FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3),	    \
+		    _FP_FRAC_WORD_8(_z,2));				    \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3),	    \
+		    _FP_FRAC_WORD_8(_z,2), 0,_f_f1,_f_f0,		    \
+		    _FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3),	    \
+		    _FP_FRAC_WORD_8(_z,2));				    \
+    doit(_b_f1, _b_f0, X##_f[0], Y##_f[3]);				    \
+    doit(_c_f1, _c_f0, X##_f[3], Y##_f[0]);				    \
+    doit(_d_f1, _d_f0, X##_f[1], Y##_f[2]);				    \
+    doit(_e_f1, _e_f0, X##_f[2], Y##_f[1]);				    \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),	    \
+		    _FP_FRAC_WORD_8(_z,3), 0,_b_f1,_b_f0,		    \
+		    0,_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3));	    \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),	    \
+		    _FP_FRAC_WORD_8(_z,3), 0,_c_f1,_c_f0,		    \
+		    _FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),	    \
+		    _FP_FRAC_WORD_8(_z,3));				    \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),	    \
+		    _FP_FRAC_WORD_8(_z,3), 0,_d_f1,_d_f0,		    \
+		    _FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),	    \
+		    _FP_FRAC_WORD_8(_z,3));				    \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),	    \
+		    _FP_FRAC_WORD_8(_z,3), 0,_e_f1,_e_f0,		    \
+		    _FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),	    \
+		    _FP_FRAC_WORD_8(_z,3));				    \
+    doit(_b_f1, _b_f0, X##_f[2], Y##_f[2]);				    \
+    doit(_c_f1, _c_f0, X##_f[1], Y##_f[3]);				    \
+    doit(_d_f1, _d_f0, X##_f[3], Y##_f[1]);				    \
+    doit(_e_f1, _e_f0, X##_f[2], Y##_f[3]);				    \
+    doit(_f_f1, _f_f0, X##_f[3], Y##_f[2]);				    \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5),	    \
+		    _FP_FRAC_WORD_8(_z,4), 0,_b_f1,_b_f0,		    \
+		    0,_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4));	    \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5),	    \
+		    _FP_FRAC_WORD_8(_z,4), 0,_c_f1,_c_f0,		    \
+		    _FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5),	    \
+		    _FP_FRAC_WORD_8(_z,4));				    \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5),	    \
+		    _FP_FRAC_WORD_8(_z,4), 0,_d_f1,_d_f0,		    \
+		    _FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5),	    \
+		    _FP_FRAC_WORD_8(_z,4));				    \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6),	    \
+		    _FP_FRAC_WORD_8(_z,5), 0,_e_f1,_e_f0,		    \
+		    0,_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5));	    \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6),	    \
+		    _FP_FRAC_WORD_8(_z,5), 0,_f_f1,_f_f0,		    \
+		    _FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6),	    \
+		    _FP_FRAC_WORD_8(_z,5));				    \
+    doit(_b_f1, _b_f0, X##_f[3], Y##_f[3]);				    \
+    __FP_FRAC_ADD_2(_FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6),	    \
+		    _b_f1,_b_f0,					    \
+		    _FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6));	    \
+									    \
+    /* Normalize since we know where the msb of the multiplicands	    \
+       were (bit B), we know that the msb of the of the product is	    \
+       at either 2B or 2B-1.  */					    \
+    _FP_FRAC_SRS_8(_z, wfracbits-1, 2*wfracbits);			    \
+    __FP_FRAC_SET_4(R, _FP_FRAC_WORD_8(_z,3), _FP_FRAC_WORD_8(_z,2),	    \
+		    _FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0));	    \
+  } while (0)
+
+#define _FP_MUL_MEAT_4_gmp(wfracbits, R, X, Y)				    \
+  do {									    \
+    _FP_FRAC_DECL_8(_z);						    \
+									    \
+    mpn_mul_n(_z_f, _x_f, _y_f, 4);					    \
+									    \
+    /* Normalize since we know where the msb of the multiplicands	    \
+       were (bit B), we know that the msb of the of the product is	    \
+       at either 2B or 2B-1.  */					    \
+    _FP_FRAC_SRS_8(_z, wfracbits-1, 2*wfracbits);	 		    \
+    __FP_FRAC_SET_4(R, _FP_FRAC_WORD_8(_z,3), _FP_FRAC_WORD_8(_z,2),	    \
+		    _FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0));	    \
+  } while (0)
+
+/*
+ * Helper utility for _FP_DIV_MEAT_4_udiv:
+ * pppp = m * nnn
+ */
+#define umul_ppppmnnn(p3,p2,p1,p0,m,n2,n1,n0)				    \
+  do {									    \
+    UWtype _t;								    \
+    umul_ppmm(p1,p0,m,n0);						    \
+    umul_ppmm(p2,_t,m,n1);						    \
+    __FP_FRAC_ADDI_2(p2,p1,_t);						    \
+    umul_ppmm(p3,_t,m,n2);						    \
+    __FP_FRAC_ADDI_2(p3,p2,_t);						    \
+  } while (0)
+
+/*
+ * Division algorithms:
+ */
+
+#define _FP_DIV_MEAT_4_udiv(fs, R, X, Y)				    \
+  do {									    \
+    int _i;								    \
+    _FP_FRAC_DECL_4(_n); _FP_FRAC_DECL_4(_m);				    \
+    _FP_FRAC_SET_4(_n, _FP_ZEROFRAC_4);					    \
+    if (_FP_FRAC_GT_4(X, Y))						    \
+      {									    \
+	_n_f[3] = X##_f[0] << (_FP_W_TYPE_SIZE - 1);			    \
+	_FP_FRAC_SRL_4(X, 1);						    \
+      }									    \
+    else								    \
+      R##_e--;								    \
+									    \
+    /* Normalize, i.e. make the most significant bit of the 		    \
+       denominator set. */						    \
+    _FP_FRAC_SLL_4(Y, _FP_WFRACXBITS_##fs);				    \
+									    \
+    for (_i = 3; ; _i--)						    \
+      {									    \
+        if (X##_f[3] == Y##_f[3])					    \
+          {								    \
+            /* This is a special case, not an optimization		    \
+               (X##_f[3]/Y##_f[3] would not fit into UWtype).		    \
+               As X## is guaranteed to be < Y,  R##_f[_i] can be either	    \
+               (UWtype)-1 or (UWtype)-2.  */				    \
+            R##_f[_i] = -1;						    \
+            if (!_i)							    \
+	      break;							    \
+            __FP_FRAC_SUB_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0],	    \
+			    Y##_f[2], Y##_f[1], Y##_f[0], 0,		    \
+			    X##_f[2], X##_f[1], X##_f[0], _n_f[_i]);	    \
+            _FP_FRAC_SUB_4(X, Y, X);					    \
+            if (X##_f[3] > Y##_f[3])					    \
+              {								    \
+                R##_f[_i] = -2;						    \
+                _FP_FRAC_ADD_4(X, Y, X);				    \
+              }								    \
+          }								    \
+        else								    \
+          {								    \
+            udiv_qrnnd(R##_f[_i], X##_f[3], X##_f[3], X##_f[2], Y##_f[3]);  \
+            umul_ppppmnnn(_m_f[3], _m_f[2], _m_f[1], _m_f[0],		    \
+			  R##_f[_i], Y##_f[2], Y##_f[1], Y##_f[0]);	    \
+            X##_f[2] = X##_f[1];					    \
+            X##_f[1] = X##_f[0];					    \
+            X##_f[0] = _n_f[_i];					    \
+            if (_FP_FRAC_GT_4(_m, X))					    \
+              {								    \
+                R##_f[_i]--;						    \
+                _FP_FRAC_ADD_4(X, Y, X);				    \
+                if (_FP_FRAC_GE_4(X, Y) && _FP_FRAC_GT_4(_m, X))	    \
+                  {							    \
+		    R##_f[_i]--;					    \
+		    _FP_FRAC_ADD_4(X, Y, X);				    \
+                  }							    \
+              }								    \
+            _FP_FRAC_DEC_4(X, _m);					    \
+            if (!_i)							    \
+	      {								    \
+		if (!_FP_FRAC_EQ_4(X, _m))				    \
+		  R##_f[0] |= _FP_WORK_STICKY;				    \
+		break;							    \
+	      }								    \
+          }								    \
+      }									    \
+  } while (0)
+
+
+/*
+ * Square root algorithms:
+ * We have just one right now, maybe Newton approximation
+ * should be added for those machines where division is fast.
+ */
+ 
+#define _FP_SQRT_MEAT_4(R, S, T, X, q)				\
+  do {								\
+    while (q)							\
+      {								\
+	T##_f[3] = S##_f[3] + q;				\
+	if (T##_f[3] <= X##_f[3])				\
+	  {							\
+	    S##_f[3] = T##_f[3] + q;				\
+	    X##_f[3] -= T##_f[3];				\
+	    R##_f[3] += q;					\
+	  }							\
+	_FP_FRAC_SLL_4(X, 1);					\
+	q >>= 1;						\
+      }								\
+    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);			\
+    while (q)							\
+      {								\
+	T##_f[2] = S##_f[2] + q;				\
+	T##_f[3] = S##_f[3];					\
+	if (T##_f[3] < X##_f[3] || 				\
+	    (T##_f[3] == X##_f[3] && T##_f[2] <= X##_f[2]))	\
+	  {							\
+	    S##_f[2] = T##_f[2] + q;				\
+	    S##_f[3] += (T##_f[2] > S##_f[2]);			\
+	    __FP_FRAC_DEC_2(X##_f[3], X##_f[2],			\
+			    T##_f[3], T##_f[2]);		\
+	    R##_f[2] += q;					\
+	  }							\
+	_FP_FRAC_SLL_4(X, 1);					\
+	q >>= 1;						\
+      }								\
+    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);			\
+    while (q)							\
+      {								\
+	T##_f[1] = S##_f[1] + q;				\
+	T##_f[2] = S##_f[2];					\
+	T##_f[3] = S##_f[3];					\
+	if (T##_f[3] < X##_f[3] || 				\
+	    (T##_f[3] == X##_f[3] && (T##_f[2] < X##_f[2] ||	\
+	     (T##_f[2] == X##_f[2] && T##_f[1] <= X##_f[1]))))	\
+	  {							\
+	    S##_f[1] = T##_f[1] + q;				\
+	    S##_f[2] += (T##_f[1] > S##_f[1]);			\
+	    S##_f[3] += (T##_f[2] > S##_f[2]);			\
+	    __FP_FRAC_DEC_3(X##_f[3], X##_f[2], X##_f[1],	\
+	    		    T##_f[3], T##_f[2], T##_f[1]);	\
+	    R##_f[1] += q;					\
+	  }							\
+	_FP_FRAC_SLL_4(X, 1);					\
+	q >>= 1;						\
+      }								\
+    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);			\
+    while (q != _FP_WORK_ROUND)					\
+      {								\
+	T##_f[0] = S##_f[0] + q;				\
+	T##_f[1] = S##_f[1];					\
+	T##_f[2] = S##_f[2];					\
+	T##_f[3] = S##_f[3];					\
+	if (_FP_FRAC_GE_4(X,T))					\
+	  {							\
+	    S##_f[0] = T##_f[0] + q;				\
+	    S##_f[1] += (T##_f[0] > S##_f[0]);			\
+	    S##_f[2] += (T##_f[1] > S##_f[1]);			\
+	    S##_f[3] += (T##_f[2] > S##_f[2]);			\
+	    _FP_FRAC_DEC_4(X, T);				\
+	    R##_f[0] += q;					\
+	  }							\
+	_FP_FRAC_SLL_4(X, 1);					\
+	q >>= 1;						\
+      }								\
+    if (!_FP_FRAC_ZEROP_4(X))					\
+      {								\
+	if (_FP_FRAC_GT_4(X,S))					\
+	  R##_f[0] |= _FP_WORK_ROUND;				\
+	R##_f[0] |= _FP_WORK_STICKY;				\
+      }								\
+  } while (0)
+
+
+/*
+ * Internals 
+ */
+
+#define __FP_FRAC_SET_4(X,I3,I2,I1,I0)					\
+  (X##_f[3] = I3, X##_f[2] = I2, X##_f[1] = I1, X##_f[0] = I0)
+
+#ifndef __FP_FRAC_ADD_3
+#define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)			\
+  (r0 = x0 + y0,							\
+   r1 = x1 + y1 + (r0 < x0),						\
+   r2 = x2 + y2 + (r1 < x1))
+#endif
+
+#ifndef __FP_FRAC_ADD_4
+#define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)		\
+  (r0 = x0 + y0,							\
+   r1 = x1 + y1 + (r0 < x0),						\
+   r2 = x2 + y2 + (r1 < x1),						\
+   r3 = x3 + y3 + (r2 < x2))
+#endif
+
+#ifndef __FP_FRAC_SUB_3
+#define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)			\
+  (r0 = x0 - y0,							\
+   r1 = x1 - y1 - (r0 > x0),						\
+   r2 = x2 - y2 - (r1 > x1))
+#endif
+
+#ifndef __FP_FRAC_SUB_4
+#define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)		\
+  (r0 = x0 - y0,							\
+   r1 = x1 - y1 - (r0 > x0),						\
+   r2 = x2 - y2 - (r1 > x1),						\
+   r3 = x3 - y3 - (r2 > x2))
+#endif
+
+#ifndef __FP_FRAC_DEC_3
+#define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0)				\
+  do {									\
+    UWtype _t0, _t1;							\
+    _t0 = x0;								\
+    x0 -= y0;								\
+    _t1 = x1;								\
+    x1 -= y1 + (x0 > _t0);						\
+    x2 -= y2 + (x1 > _t1);						\
+  } while (0)
+#endif
+
+#ifndef __FP_FRAC_DEC_4
+#define __FP_FRAC_DEC_4(x3,x2,x1,x0,y3,y2,y1,y0)			\
+  do {									\
+    UWtype _t0, _t1;							\
+    _t0 = x0;								\
+    x0 -= y0;								\
+    _t1 = x1;								\
+    x1 -= y1 + (x0 > _t0);						\
+    _t0 = x2;								\
+    x2 -= y2 + (x1 > _t1);						\
+    x3 -= y3 + (x2 > _t0);						\
+  } while (0)
+#endif
+
+#ifndef __FP_FRAC_ADDI_4
+#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i)					\
+  do {									\
+    UWtype _t;								\
+    _t = ((x0 += i) < i);						\
+    x1 += _t; _t = (x1 < _t);						\
+    x2 += _t; _t = (x2 < _t);						\
+    x3 += _t;								\
+  } while (0)
+#endif
+
+/* Convert FP values between word sizes. This appears to be more
+ * complicated than I'd have expected it to be, so these might be
+ * wrong... These macros are in any case somewhat bogus because they
+ * use information about what various FRAC_n variables look like 
+ * internally [eg, that 2 word vars are X_f0 and x_f1]. But so do
+ * the ones in op-2.h and op-1.h. 
+ */
+#define _FP_FRAC_CONV_1_4(dfs, sfs, D, S)				\
+   do {									\
+     if (S##_c != FP_CLS_NAN)						\
+       _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),	\
+			  _FP_WFRACBITS_##sfs);				\
+     else								\
+       _FP_FRAC_SRL_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs));	\
+     D##_f = S##_f[0];							\
+  } while (0)
+
+#define _FP_FRAC_CONV_2_4(dfs, sfs, D, S)				\
+   do {									\
+     if (S##_c != FP_CLS_NAN)						\
+       _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),	\
+		      _FP_WFRACBITS_##sfs);				\
+     else								\
+       _FP_FRAC_SRL_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs));	\
+     D##_f0 = S##_f[0];							\
+     D##_f1 = S##_f[1];							\
+  } while (0)
+
+/* Assembly/disassembly for converting to/from integral types.  
+ * No shifting or overflow handled here.
+ */
+/* Put the FP value X into r, which is an integer of size rsize. */
+#define _FP_FRAC_ASSEMBLE_4(r, X, rsize)				\
+  do {									\
+    if (rsize <= _FP_W_TYPE_SIZE)					\
+      r = X##_f[0];							\
+    else if (rsize <= 2*_FP_W_TYPE_SIZE)				\
+    {									\
+      r = X##_f[1];							\
+      r <<= _FP_W_TYPE_SIZE;						\
+      r += X##_f[0];							\
+    }									\
+    else								\
+    {									\
+      /* I'm feeling lazy so we deal with int == 3words (implausible)*/	\
+      /* and int == 4words as a single case.			 */	\
+      r = X##_f[3];							\
+      r <<= _FP_W_TYPE_SIZE;						\
+      r += X##_f[2];							\
+      r <<= _FP_W_TYPE_SIZE;						\
+      r += X##_f[1];							\
+      r <<= _FP_W_TYPE_SIZE;						\
+      r += X##_f[0];							\
+    }									\
+  } while (0)
+
+/* "No disassemble Number Five!" */
+/* move an integer of size rsize into X's fractional part. We rely on
+ * the _f[] array consisting of words of size _FP_W_TYPE_SIZE to avoid
+ * having to mask the values we store into it.
+ */
+#define _FP_FRAC_DISASSEMBLE_4(X, r, rsize)				\
+  do {									\
+    X##_f[0] = r;							\
+    X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE);	\
+    X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \
+    X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \
+  } while (0);
+
+#define _FP_FRAC_CONV_4_1(dfs, sfs, D, S)				\
+   do {									\
+     D##_f[0] = S##_f;							\
+     D##_f[1] = D##_f[2] = D##_f[3] = 0;				\
+     _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));	\
+   } while (0)
+
+#define _FP_FRAC_CONV_4_2(dfs, sfs, D, S)				\
+   do {									\
+     D##_f[0] = S##_f0;							\
+     D##_f[1] = S##_f1;							\
+     D##_f[2] = D##_f[3] = 0;						\
+     _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));	\
+   } while (0)
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/math-emu/op-8.h linux.14p16/include/math-emu/op-8.h
--- linux.vanilla/include/math-emu/op-8.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/math-emu/op-8.h	Thu Dec  9 15:33:13 1999
@@ -0,0 +1,103 @@
+/* Software floating-point emulation.
+   Basic eight-word fraction declaration and manipulation.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+		  Jakub Jelinek (jj@ultra.linux.cz) and
+		  Peter Maydell (pmaydell@chiark.greenend.org.uk).
+                                                         
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* We need just a few things from here for op-4, if we ever need some
+   other macros, they can be added. */
+#define _FP_FRAC_DECL_8(X)	_FP_W_TYPE X##_f[8]
+#define _FP_FRAC_HIGH_8(X)	(X##_f[7])
+#define _FP_FRAC_LOW_8(X)	(X##_f[0])
+#define _FP_FRAC_WORD_8(X,w)	(X##_f[w])
+
+#define _FP_FRAC_SLL_8(X,N)						\
+  do {									\
+    _FP_I_TYPE _up, _down, _skip, _i;					\
+    _skip = (N) / _FP_W_TYPE_SIZE;					\
+    _up = (N) % _FP_W_TYPE_SIZE;					\
+    _down = _FP_W_TYPE_SIZE - _up;					\
+    if (!_up)								\
+      for (_i = 7; _i >= _skip; --_i)					\
+	X##_f[_i] = X##_f[_i-_skip];					\
+    else								\
+      {									\
+	for (_i = 7; _i > _skip; --_i)					\
+	  X##_f[_i] = X##_f[_i-_skip] << _up				\
+		      | X##_f[_i-_skip-1] >> _down;			\
+	X##_f[_i--] = X##_f[0] << _up; 					\
+      }									\
+    for (; _i >= 0; --_i)						\
+      X##_f[_i] = 0;							\
+  } while (0)
+
+#define _FP_FRAC_SRL_8(X,N)						\
+  do {									\
+    _FP_I_TYPE _up, _down, _skip, _i;					\
+    _skip = (N) / _FP_W_TYPE_SIZE;					\
+    _down = (N) % _FP_W_TYPE_SIZE;					\
+    _up = _FP_W_TYPE_SIZE - _down;					\
+    if (!_down)								\
+      for (_i = 0; _i <= 7-_skip; ++_i)					\
+	X##_f[_i] = X##_f[_i+_skip];					\
+    else								\
+      {									\
+	for (_i = 0; _i < 7-_skip; ++_i)				\
+	  X##_f[_i] = X##_f[_i+_skip] >> _down				\
+		      | X##_f[_i+_skip+1] << _up;			\
+	X##_f[_i++] = X##_f[7] >> _down;				\
+      }									\
+    for (; _i < 8; ++_i)						\
+      X##_f[_i] = 0;							\
+  } while (0)
+
+
+/* Right shift with sticky-lsb. 
+ * What this actually means is that we do a standard right-shift,
+ * but that if any of the bits that fall off the right hand side
+ * were one then we always set the LSbit.
+ */
+#define _FP_FRAC_SRS_8(X,N,size)					\
+  do {									\
+    _FP_I_TYPE _up, _down, _skip, _i;					\
+    _FP_W_TYPE _s;							\
+    _skip = (N) / _FP_W_TYPE_SIZE;					\
+    _down = (N) % _FP_W_TYPE_SIZE;					\
+    _up = _FP_W_TYPE_SIZE - _down;					\
+    for (_s = _i = 0; _i < _skip; ++_i)					\
+      _s |= X##_f[_i];							\
+    _s |= X##_f[_i] << _up;						\
+/* s is now != 0 if we want to set the LSbit */				\
+    if (!_down)								\
+      for (_i = 0; _i <= 7-_skip; ++_i)					\
+	X##_f[_i] = X##_f[_i+_skip];					\
+    else								\
+      {									\
+	for (_i = 0; _i < 7-_skip; ++_i)				\
+	  X##_f[_i] = X##_f[_i+_skip] >> _down				\
+		      | X##_f[_i+_skip+1] << _up;			\
+	X##_f[_i++] = X##_f[7] >> _down;				\
+      }									\
+    for (; _i < 8; ++_i)						\
+      X##_f[_i] = 0;							\
+    /* don't fix the LSB until the very end when we're sure f[0] is stable */	\
+    X##_f[0] |= (_s != 0);						\
+  } while (0)
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/math-emu/op-common.h linux.14p16/include/math-emu/op-common.h
--- linux.vanilla/include/math-emu/op-common.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/math-emu/op-common.h	Thu Dec  9 15:33:13 1999
@@ -0,0 +1,848 @@
+/* Software floating-point emulation. Common operations.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+		  Jakub Jelinek (jj@ultra.linux.cz),
+		  David S. Miller (davem@redhat.com) and
+		  Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#define _FP_DECL(wc, X)			\
+  _FP_I_TYPE X##_c, X##_s, X##_e;	\
+  _FP_FRAC_DECL_##wc(X)
+
+/*
+ * Finish truely unpacking a native fp value by classifying the kind
+ * of fp value and normalizing both the exponent and the fraction.
+ */
+
+#define _FP_UNPACK_CANONICAL(fs, wc, X)					\
+do {									\
+  switch (X##_e)							\
+  {									\
+  default:								\
+    _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_IMPLBIT_##fs;			\
+    _FP_FRAC_SLL_##wc(X, _FP_WORKBITS);					\
+    X##_e -= _FP_EXPBIAS_##fs;						\
+    X##_c = FP_CLS_NORMAL;						\
+    break;								\
+									\
+  case 0:								\
+    if (_FP_FRAC_ZEROP_##wc(X))						\
+      X##_c = FP_CLS_ZERO;						\
+    else								\
+      {									\
+	/* a denormalized number */					\
+	_FP_I_TYPE _shift;						\
+	_FP_FRAC_CLZ_##wc(_shift, X);					\
+	_shift -= _FP_FRACXBITS_##fs;					\
+	_FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS));			\
+	X##_e -= _FP_EXPBIAS_##fs - 1 + _shift;				\
+	X##_c = FP_CLS_NORMAL;						\
+	FP_SET_EXCEPTION(FP_EX_DENORM);					\
+	if (FP_DENORM_ZERO)						\
+	  {								\
+	    FP_SET_EXCEPTION(FP_EX_INEXACT);				\
+	    X##_c = FP_CLS_ZERO;					\
+	  }								\
+      }									\
+    break;								\
+									\
+  case _FP_EXPMAX_##fs:							\
+    if (_FP_FRAC_ZEROP_##wc(X))						\
+      X##_c = FP_CLS_INF;						\
+    else								\
+      {									\
+	X##_c = FP_CLS_NAN;						\
+	/* Check for signaling NaN */					\
+	if (!(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))		\
+	  FP_SET_EXCEPTION(FP_EX_INVALID);				\
+      }									\
+    break;								\
+  }									\
+} while (0)
+
+/*
+ * Before packing the bits back into the native fp result, take care
+ * of such mundane things as rounding and overflow.  Also, for some
+ * kinds of fp values, the original parts may not have been fully
+ * extracted -- but that is ok, we can regenerate them now.
+ */
+
+#define _FP_PACK_CANONICAL(fs, wc, X)				\
+do {								\
+  switch (X##_c)						\
+  {								\
+  case FP_CLS_NORMAL:						\
+    X##_e += _FP_EXPBIAS_##fs;					\
+    if (X##_e > 0)						\
+      {								\
+	_FP_ROUND(wc, X);					\
+	if (_FP_FRAC_OVERP_##wc(fs, X))				\
+	  {							\
+	    _FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1));		\
+	    X##_e++;						\
+	  }							\
+	else							\
+	  _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);			\
+	if (X##_e >= _FP_EXPMAX_##fs)				\
+	  {							\
+	    /* overflow */					\
+	    switch (FP_ROUNDMODE)				\
+	      {							\
+	      case FP_RND_NEAREST:				\
+		X##_c = FP_CLS_INF;				\
+		break;						\
+	      case FP_RND_PINF:					\
+		if (!X##_s) X##_c = FP_CLS_INF;			\
+		break;						\
+	      case FP_RND_MINF:					\
+		if (X##_s) X##_c = FP_CLS_INF;			\
+		break;						\
+	      }							\
+	    if (X##_c == FP_CLS_INF)				\
+	      {							\
+		/* Overflow to infinity */			\
+		X##_e = _FP_EXPMAX_##fs;			\
+		_FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);	\
+	      }							\
+	    else						\
+	      {							\
+		/* Overflow to maximum normal */		\
+		X##_e = _FP_EXPMAX_##fs - 1;			\
+		_FP_FRAC_SET_##wc(X, _FP_MAXFRAC_##wc);		\
+	      }							\
+	    FP_SET_EXCEPTION(FP_EX_OVERFLOW);			\
+            FP_SET_EXCEPTION(FP_EX_INEXACT);			\
+	  }							\
+      }								\
+    else							\
+      {								\
+	/* we've got a denormalized number */			\
+	X##_e = -X##_e + 1;					\
+	if (X##_e <= _FP_WFRACBITS_##fs)			\
+	  {							\
+	    _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs);	\
+	    _FP_ROUND(wc, X);					\
+	    if (_FP_FRAC_HIGH_##fs(X)				\
+		& (_FP_OVERFLOW_##fs >> 1))			\
+	      {							\
+	        X##_e = 1;					\
+	        _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);	\
+	      }							\
+	    else						\
+	      {							\
+		X##_e = 0;					\
+		_FP_FRAC_SRL_##wc(X, _FP_WORKBITS);		\
+		FP_SET_EXCEPTION(FP_EX_UNDERFLOW);		\
+	      }							\
+	  }							\
+	else							\
+	  {							\
+	    /* underflow to zero */				\
+	    X##_e = 0;						\
+	    if (!_FP_FRAC_ZEROP_##wc(X))			\
+	      {							\
+	        _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);		\
+	        _FP_ROUND(wc, X);				\
+	        _FP_FRAC_LOW_##wc(X) >>= (_FP_WORKBITS);	\
+	      }							\
+	    FP_SET_EXCEPTION(FP_EX_UNDERFLOW);			\
+	  }							\
+      }								\
+    break;							\
+								\
+  case FP_CLS_ZERO:						\
+    X##_e = 0;							\
+    _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);			\
+    break;							\
+								\
+  case FP_CLS_INF:						\
+    X##_e = _FP_EXPMAX_##fs;					\
+    _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);			\
+    break;							\
+								\
+  case FP_CLS_NAN:						\
+    X##_e = _FP_EXPMAX_##fs;					\
+    if (!_FP_KEEPNANFRACP)					\
+      {								\
+	_FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs);			\
+	X##_s = _FP_NANSIGN_##fs;				\
+      }								\
+    else							\
+      _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_QNANBIT_##fs;		\
+    break;							\
+  }								\
+} while (0)
+
+/* This one accepts raw argument and not cooked,  returns
+ * 1 if X is a signaling NaN.
+ */
+#define _FP_ISSIGNAN(fs, wc, X)					\
+({								\
+  int __ret = 0;						\
+  if (X##_e == _FP_EXPMAX_##fs)					\
+    {								\
+      if (!_FP_FRAC_ZEROP_##wc(X)				\
+	  && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))	\
+	__ret = 1;						\
+    }								\
+  __ret;							\
+})
+
+
+
+
+
+/*
+ * Main addition routine.  The input values should be cooked.
+ */
+
+#define _FP_ADD_INTERNAL(fs, wc, R, X, Y, OP)				     \
+do {									     \
+  switch (_FP_CLS_COMBINE(X##_c, Y##_c))				     \
+  {									     \
+  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):			     \
+    {									     \
+      /* shift the smaller number so that its exponent matches the larger */ \
+      _FP_I_TYPE diff = X##_e - Y##_e;					     \
+									     \
+      if (diff < 0)							     \
+	{								     \
+	  diff = -diff;							     \
+	  if (diff <= _FP_WFRACBITS_##fs)				     \
+	    _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs);		     \
+	  else if (!_FP_FRAC_ZEROP_##wc(X))				     \
+	    _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);			     \
+	  R##_e = Y##_e;						     \
+	}								     \
+      else								     \
+	{								     \
+	  if (diff > 0)							     \
+	    {								     \
+	      if (diff <= _FP_WFRACBITS_##fs)				     \
+	        _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs);		     \
+	      else if (!_FP_FRAC_ZEROP_##wc(Y))				     \
+	        _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc);			     \
+	    }								     \
+	  R##_e = X##_e;						     \
+	}								     \
+									     \
+      R##_c = FP_CLS_NORMAL;						     \
+									     \
+      if (X##_s == Y##_s)						     \
+	{								     \
+	  R##_s = X##_s;						     \
+	  _FP_FRAC_ADD_##wc(R, X, Y);					     \
+	  if (_FP_FRAC_OVERP_##wc(fs, R))				     \
+	    {								     \
+	      _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs);		     \
+	      R##_e++;							     \
+	    }								     \
+	}								     \
+      else								     \
+	{								     \
+	  R##_s = X##_s;						     \
+	  _FP_FRAC_SUB_##wc(R, X, Y);					     \
+	  if (_FP_FRAC_ZEROP_##wc(R))					     \
+	    {								     \
+	      /* return an exact zero */				     \
+	      if (FP_ROUNDMODE == FP_RND_MINF)				     \
+		R##_s |= Y##_s;						     \
+	      else							     \
+		R##_s &= Y##_s;						     \
+	      R##_c = FP_CLS_ZERO;					     \
+	    }								     \
+	  else								     \
+	    {								     \
+	      if (_FP_FRAC_NEGP_##wc(R))				     \
+		{							     \
+		  _FP_FRAC_SUB_##wc(R, Y, X);				     \
+		  R##_s = Y##_s;					     \
+		}							     \
+									     \
+	      /* renormalize after subtraction */			     \
+	      _FP_FRAC_CLZ_##wc(diff, R);				     \
+	      diff -= _FP_WFRACXBITS_##fs;				     \
+	      if (diff)							     \
+		{							     \
+		  R##_e -= diff;					     \
+		  _FP_FRAC_SLL_##wc(R, diff);				     \
+		}							     \
+	    }								     \
+	}								     \
+      break;								     \
+    }									     \
+									     \
+  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):				     \
+    _FP_CHOOSENAN(fs, wc, R, X, Y, OP);					     \
+    break;								     \
+									     \
+  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):			     \
+    R##_e = X##_e;							     \
+  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):			     \
+  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):				     \
+  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):				     \
+    _FP_FRAC_COPY_##wc(R, X);						     \
+    R##_s = X##_s;							     \
+    R##_c = X##_c;							     \
+    break;								     \
+									     \
+  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):			     \
+    R##_e = Y##_e;							     \
+  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):			     \
+  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):				     \
+  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):				     \
+    _FP_FRAC_COPY_##wc(R, Y);						     \
+    R##_s = Y##_s;							     \
+    R##_c = Y##_c;							     \
+    break;								     \
+									     \
+  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):				     \
+    if (X##_s != Y##_s)							     \
+      {									     \
+	/* +INF + -INF => NAN */					     \
+	_FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);				     \
+	R##_s = _FP_NANSIGN_##fs;					     \
+	R##_c = FP_CLS_NAN;						     \
+	FP_SET_EXCEPTION(FP_EX_INVALID);				     \
+	break;								     \
+      }									     \
+    /* FALLTHRU */							     \
+									     \
+  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):			     \
+  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):				     \
+    R##_s = X##_s;							     \
+    R##_c = FP_CLS_INF;							     \
+    break;								     \
+									     \
+  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):			     \
+  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):				     \
+    R##_s = Y##_s;							     \
+    R##_c = FP_CLS_INF;							     \
+    break;								     \
+									     \
+  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):			     \
+    /* make sure the sign is correct */					     \
+    if (FP_ROUNDMODE == FP_RND_MINF)					     \
+      R##_s = X##_s | Y##_s;						     \
+    else								     \
+      R##_s = X##_s & Y##_s;						     \
+    R##_c = FP_CLS_ZERO;						     \
+    break;								     \
+									     \
+  default:								     \
+    abort();								     \
+  }									     \
+} while (0)
+
+#define _FP_ADD(fs, wc, R, X, Y) _FP_ADD_INTERNAL(fs, wc, R, X, Y, '+')
+#define _FP_SUB(fs, wc, R, X, Y)					     \
+  do {									     \
+    if (Y##_c != FP_CLS_NAN) Y##_s ^= 1;				     \
+    _FP_ADD_INTERNAL(fs, wc, R, X, Y, '-');				     \
+  } while (0)
+
+
+/*
+ * Main negation routine.  FIXME -- when we care about setting exception
+ * bits reliably, this will not do.  We should examine all of the fp classes.
+ */
+
+#define _FP_NEG(fs, wc, R, X)		\
+  do {					\
+    _FP_FRAC_COPY_##wc(R, X);		\
+    R##_c = X##_c;			\
+    R##_e = X##_e;			\
+    R##_s = 1 ^ X##_s;			\
+  } while (0)
+
+
+/*
+ * Main multiplication routine.  The input values should be cooked.
+ */
+
+#define _FP_MUL(fs, wc, R, X, Y)			\
+do {							\
+  R##_s = X##_s ^ Y##_s;				\
+  switch (_FP_CLS_COMBINE(X##_c, Y##_c))		\
+  {							\
+  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):	\
+    R##_c = FP_CLS_NORMAL;				\
+    R##_e = X##_e + Y##_e + 1;				\
+							\
+    _FP_MUL_MEAT_##fs(R,X,Y);				\
+							\
+    if (_FP_FRAC_OVERP_##wc(fs, R))			\
+      _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs);	\
+    else						\
+      R##_e--;						\
+    break;						\
+							\
+  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):		\
+    _FP_CHOOSENAN(fs, wc, R, X, Y, '*');		\
+    break;						\
+							\
+  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):	\
+  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):		\
+  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):		\
+    R##_s = X##_s;					\
+							\
+  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):		\
+  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):	\
+  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):	\
+  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):	\
+    _FP_FRAC_COPY_##wc(R, X);				\
+    R##_c = X##_c;					\
+    break;						\
+							\
+  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):	\
+  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):		\
+  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):		\
+    R##_s = Y##_s;					\
+							\
+  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):	\
+  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):	\
+    _FP_FRAC_COPY_##wc(R, Y);				\
+    R##_c = Y##_c;					\
+    break;						\
+							\
+  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):		\
+  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):		\
+    R##_s = _FP_NANSIGN_##fs;				\
+    R##_c = FP_CLS_NAN;					\
+    _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);		\
+    FP_SET_EXCEPTION(FP_EX_INVALID);			\
+    break;						\
+							\
+  default:						\
+    abort();						\
+  }							\
+} while (0)
+
+
+/*
+ * Main division routine.  The input values should be cooked.
+ */
+
+#define _FP_DIV(fs, wc, R, X, Y)			\
+do {							\
+  R##_s = X##_s ^ Y##_s;				\
+  switch (_FP_CLS_COMBINE(X##_c, Y##_c))		\
+  {							\
+  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):	\
+    R##_c = FP_CLS_NORMAL;				\
+    R##_e = X##_e - Y##_e;				\
+							\
+    _FP_DIV_MEAT_##fs(R,X,Y);				\
+    break;						\
+							\
+  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):		\
+    _FP_CHOOSENAN(fs, wc, R, X, Y, '/');		\
+    break;						\
+							\
+  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):	\
+  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):		\
+  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):		\
+    R##_s = X##_s;					\
+    _FP_FRAC_COPY_##wc(R, X);				\
+    R##_c = X##_c;					\
+    break;						\
+							\
+  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):	\
+  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):		\
+  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):		\
+    R##_s = Y##_s;					\
+    _FP_FRAC_COPY_##wc(R, Y);				\
+    R##_c = Y##_c;					\
+    break;						\
+							\
+  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):	\
+  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):		\
+  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):	\
+    R##_c = FP_CLS_ZERO;				\
+    break;						\
+							\
+  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):	\
+    FP_SET_EXCEPTION(FP_EX_DIVZERO);			\
+  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):		\
+  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):	\
+    R##_c = FP_CLS_INF;					\
+    break;						\
+							\
+  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):		\
+  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):	\
+    R##_s = _FP_NANSIGN_##fs;				\
+    R##_c = FP_CLS_NAN;					\
+    _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);		\
+    FP_SET_EXCEPTION(FP_EX_INVALID);			\
+    break;						\
+							\
+  default:						\
+    abort();						\
+  }							\
+} while (0)
+
+
+/*
+ * Main differential comparison routine.  The inputs should be raw not
+ * cooked.  The return is -1,0,1 for normal values, 2 otherwise.
+ */
+
+#define _FP_CMP(fs, wc, ret, X, Y, un)					\
+  do {									\
+    /* NANs are unordered */						\
+    if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X))		\
+	|| (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y)))	\
+      {									\
+	ret = un;							\
+      }									\
+    else								\
+      {									\
+	int __is_zero_x;						\
+	int __is_zero_y;						\
+									\
+	__is_zero_x = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0;	\
+	__is_zero_y = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0;	\
+									\
+	if (__is_zero_x && __is_zero_y)					\
+		ret = 0;						\
+	else if (__is_zero_x)						\
+		ret = Y##_s ? 1 : -1;					\
+	else if (__is_zero_y)						\
+		ret = X##_s ? -1 : 1;					\
+	else if (X##_s != Y##_s)					\
+	  ret = X##_s ? -1 : 1;						\
+	else if (X##_e > Y##_e)						\
+	  ret = X##_s ? -1 : 1;						\
+	else if (X##_e < Y##_e)						\
+	  ret = X##_s ? 1 : -1;						\
+	else if (_FP_FRAC_GT_##wc(X, Y))				\
+	  ret = X##_s ? -1 : 1;						\
+	else if (_FP_FRAC_GT_##wc(Y, X))				\
+	  ret = X##_s ? 1 : -1;						\
+	else								\
+	  ret = 0;							\
+      }									\
+  } while (0)
+
+
+/* Simplification for strict equality.  */
+
+#define _FP_CMP_EQ(fs, wc, ret, X, Y)					  \
+  do {									  \
+    /* NANs are unordered */						  \
+    if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X))		  \
+	|| (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y)))	  \
+      {									  \
+	ret = 1;							  \
+      }									  \
+    else								  \
+      {									  \
+	ret = !(X##_e == Y##_e						  \
+		&& _FP_FRAC_EQ_##wc(X, Y)				  \
+		&& (X##_s == Y##_s || !X##_e && _FP_FRAC_ZEROP_##wc(X))); \
+      }									  \
+  } while (0)
+
+/*
+ * Main square root routine.  The input value should be cooked.
+ */
+
+#define _FP_SQRT(fs, wc, R, X)						\
+do {									\
+    _FP_FRAC_DECL_##wc(T); _FP_FRAC_DECL_##wc(S);			\
+    _FP_W_TYPE q;							\
+    switch (X##_c)							\
+    {									\
+    case FP_CLS_NAN:							\
+	_FP_FRAC_COPY_##wc(R, X);					\
+	R##_s = X##_s;							\
+    	R##_c = FP_CLS_NAN;						\
+    	break;								\
+    case FP_CLS_INF:							\
+    	if (X##_s)							\
+    	  {								\
+    	    R##_s = _FP_NANSIGN_##fs;					\
+	    R##_c = FP_CLS_NAN; /* NAN */				\
+	    _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);			\
+	    FP_SET_EXCEPTION(FP_EX_INVALID);				\
+    	  }								\
+    	else								\
+    	  {								\
+    	    R##_s = 0;							\
+    	    R##_c = FP_CLS_INF; /* sqrt(+inf) = +inf */			\
+    	  }								\
+    	break;								\
+    case FP_CLS_ZERO:							\
+	R##_s = X##_s;							\
+	R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */			\
+	break;								\
+    case FP_CLS_NORMAL:							\
+    	R##_s = 0;							\
+        if (X##_s)							\
+          {								\
+	    R##_c = FP_CLS_NAN; /* sNAN */				\
+	    R##_s = _FP_NANSIGN_##fs;					\
+	    _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);			\
+	    FP_SET_EXCEPTION(FP_EX_INVALID);				\
+	    break;							\
+          }								\
+    	R##_c = FP_CLS_NORMAL;						\
+        if (X##_e & 1)							\
+          _FP_FRAC_SLL_##wc(X, 1);					\
+        R##_e = X##_e >> 1;						\
+        _FP_FRAC_SET_##wc(S, _FP_ZEROFRAC_##wc);			\
+        _FP_FRAC_SET_##wc(R, _FP_ZEROFRAC_##wc);			\
+        q = _FP_OVERFLOW_##fs >> 1;					\
+        _FP_SQRT_MEAT_##wc(R, S, T, X, q);				\
+    }									\
+  } while (0)
+
+/*
+ * Convert from FP to integer
+ */
+
+/* RSIGNED can have following values:
+ * 0:  the number is required to be 0..(2^rsize)-1, if not, NV is set plus
+ *     the result is either 0 or (2^rsize)-1 depending on the sign in such case.
+ * 1:  the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is
+ *     set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending
+ *     on the sign in such case.
+ * 2:  the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is
+ *     set plus the result is truncated to fit into destination.
+ * -1: the number is required to be -(2^(rsize-1))..(2^rsize)-1, if not, NV is
+ *     set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending
+ *     on the sign in such case.
+ */
+#define _FP_TO_INT(fs, wc, r, X, rsize, rsigned)				\
+  do {										\
+    switch (X##_c)								\
+      {										\
+      case FP_CLS_NORMAL:							\
+	if (X##_e < 0)								\
+	  {									\
+	    FP_SET_EXCEPTION(FP_EX_INEXACT);					\
+	  case FP_CLS_ZERO:							\
+	    r = 0;								\
+	  }									\
+	else if (X##_e >= rsize - (rsigned > 0 || X##_s)			\
+		 || (!rsigned && X##_s))					\
+	  {	/* overflow */							\
+	  case FP_CLS_NAN:                                                      \
+	  case FP_CLS_INF:							\
+	    if (rsigned == 2)							\
+	      {									\
+		if (X##_c != FP_CLS_NORMAL					\
+		    || X##_e >= rsize - 1 + _FP_WFRACBITS_##fs)			\
+		  r = 0;							\
+		else								\
+		  {								\
+		    _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1));	\
+		    _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);			\
+		  }								\
+	      }									\
+	    else if (rsigned)							\
+	      {									\
+		r = 1;								\
+		r <<= rsize - 1;						\
+		r -= 1 - X##_s;							\
+	      }									\
+	    else								\
+	      {									\
+		r = 0;								\
+		if (X##_s)							\
+		  r = ~r;							\
+	      }									\
+	    FP_SET_EXCEPTION(FP_EX_INVALID);					\
+	  }									\
+	else									\
+	  {									\
+	    if (_FP_W_TYPE_SIZE*wc < rsize)					\
+	      {									\
+		_FP_FRAC_ASSEMBLE_##wc(r, X, rsize);				\
+		r <<= X##_e - _FP_WFRACBITS_##fs;				\
+	      }									\
+	    else								\
+	      {									\
+		if (X##_e >= _FP_WFRACBITS_##fs)				\
+		  _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1));	\
+		else if (X##_e < _FP_WFRACBITS_##fs - 1)			\
+		  {								\
+		    _FP_FRAC_SRS_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 2),	\
+				      _FP_WFRACBITS_##fs);			\
+		    if (_FP_FRAC_LOW_##wc(X) & 1)				\
+		      FP_SET_EXCEPTION(FP_EX_INEXACT);				\
+		    _FP_FRAC_SRL_##wc(X, 1);					\
+		  }								\
+		_FP_FRAC_ASSEMBLE_##wc(r, X, rsize);				\
+	      }									\
+	    if (rsigned && X##_s)						\
+	      r = -r;								\
+	  }									\
+	break;									\
+      }										\
+  } while (0)
+
+#define _FP_TO_INT_ROUND(fs, wc, r, X, rsize, rsigned)				\
+  do {										\
+    r = 0;									\
+    switch (X##_c)								\
+      {										\
+      case FP_CLS_NORMAL:							\
+	if (X##_e >= _FP_FRACBITS_##fs - 1)					\
+	  {									\
+	    if (X##_e < rsize - 1 + _FP_WFRACBITS_##fs)				\
+	      {									\
+		if (X##_e >= _FP_WFRACBITS_##fs - 1)				\
+		  {								\
+		    _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);			\
+		    r <<= X##_e - _FP_WFRACBITS_##fs + 1;			\
+		  }								\
+		else								\
+		  {								\
+		    _FP_FRAC_SRL_##wc(X, _FP_WORKBITS - X##_e			\
+				      + _FP_FRACBITS_##fs - 1);			\
+		    _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);			\
+		  }								\
+	      }									\
+	  }									\
+	else									\
+	  {									\
+	    if (X##_e <= -_FP_WORKBITS - 1)					\
+	      _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);				\
+	    else								\
+	      _FP_FRAC_SRS_##wc(X, _FP_FRACBITS_##fs - 1 - X##_e,		\
+				_FP_WFRACBITS_##fs);				\
+	    _FP_ROUND(wc, X);							\
+	    _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);					\
+	    _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);				\
+	  }									\
+	if (rsigned && X##_s)							\
+	  r = -r;								\
+	if (X##_e >= rsize - (rsigned > 0 || X##_s)				\
+	    || (!rsigned && X##_s))						\
+	  {	/* overflow */							\
+	  case FP_CLS_NAN:                                                      \
+	  case FP_CLS_INF:							\
+	    if (!rsigned)							\
+	      {									\
+		r = 0;								\
+		if (X##_s)							\
+		  r = ~r;							\
+	      }									\
+	    else if (rsigned != 2)						\
+	      {									\
+		r = 1;								\
+		r <<= rsize - 1;						\
+		r -= 1 - X##_s;							\
+	      }									\
+	    FP_SET_EXCEPTION(FP_EX_INVALID);					\
+	  }									\
+	break;									\
+      case FP_CLS_ZERO:								\
+        break;									\
+      }										\
+  } while (0)
+
+#define _FP_FROM_INT(fs, wc, X, r, rsize, rtype)			\
+  do {									\
+    if (r)								\
+      {									\
+	X##_c = FP_CLS_NORMAL;						\
+									\
+	if ((X##_s = (r < 0)))						\
+	  r = -r;							\
+									\
+	if (rsize <= _FP_W_TYPE_SIZE)					\
+	  __FP_CLZ(X##_e, r);						\
+	else								\
+	  __FP_CLZ_2(X##_e, (_FP_W_TYPE)(r >> _FP_W_TYPE_SIZE), 	\
+		     (_FP_W_TYPE)r);					\
+	if (rsize < _FP_W_TYPE_SIZE)					\
+		X##_e -= (_FP_W_TYPE_SIZE - rsize);			\
+	X##_e = rsize - X##_e - 1;					\
+									\
+	if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e)	\
+	  __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs), rsize);	\
+	r &= ~((rtype)1 << X##_e);					\
+	_FP_FRAC_DISASSEMBLE_##wc(X, ((unsigned rtype)r), rsize);	\
+	_FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));		\
+      }									\
+    else								\
+      {									\
+	X##_c = FP_CLS_ZERO, X##_s = 0;					\
+      }									\
+  } while (0)
+
+
+#define FP_CONV(dfs,sfs,dwc,swc,D,S)			\
+  do {							\
+    _FP_FRAC_CONV_##dwc##_##swc(dfs, sfs, D, S);	\
+    D##_e = S##_e;					\
+    D##_c = S##_c;					\
+    D##_s = S##_s;					\
+  } while (0)
+
+/*
+ * Helper primitives.
+ */
+
+/* Count leading zeros in a word.  */
+
+#ifndef __FP_CLZ
+#if _FP_W_TYPE_SIZE < 64
+/* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */
+#define __FP_CLZ(r, x)				\
+  do {						\
+    _FP_W_TYPE _t = (x);			\
+    r = _FP_W_TYPE_SIZE - 1;			\
+    if (_t > 0xffff) r -= 16;			\
+    if (_t > 0xffff) _t >>= 16;			\
+    if (_t > 0xff) r -= 8;			\
+    if (_t > 0xff) _t >>= 8;			\
+    if (_t & 0xf0) r -= 4;			\
+    if (_t & 0xf0) _t >>= 4;			\
+    if (_t & 0xc) r -= 2;			\
+    if (_t & 0xc) _t >>= 2;			\
+    if (_t & 0x2) r -= 1;			\
+  } while (0)
+#else /* not _FP_W_TYPE_SIZE < 64 */
+#define __FP_CLZ(r, x)				\
+  do {						\
+    _FP_W_TYPE _t = (x);			\
+    r = _FP_W_TYPE_SIZE - 1;			\
+    if (_t > 0xffffffff) r -= 32;		\
+    if (_t > 0xffffffff) _t >>= 32;		\
+    if (_t > 0xffff) r -= 16;			\
+    if (_t > 0xffff) _t >>= 16;			\
+    if (_t > 0xff) r -= 8;			\
+    if (_t > 0xff) _t >>= 8;			\
+    if (_t & 0xf0) r -= 4;			\
+    if (_t & 0xf0) _t >>= 4;			\
+    if (_t & 0xc) r -= 2;			\
+    if (_t & 0xc) _t >>= 2;			\
+    if (_t & 0x2) r -= 1;			\
+  } while (0)
+#endif /* not _FP_W_TYPE_SIZE < 64 */
+#endif /* ndef __FP_CLZ */
+
+#define _FP_DIV_HELP_imm(q, r, n, d)		\
+  do {						\
+    q = n / d, r = n % d;			\
+  } while (0)
+
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/math-emu/quad.h linux.14p16/include/math-emu/quad.h
--- linux.vanilla/include/math-emu/quad.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/math-emu/quad.h	Thu Dec  9 15:33:13 1999
@@ -0,0 +1,203 @@
+/* Software floating-point emulation.
+   Definitions for IEEE Quad Precision.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+		  Jakub Jelinek (jj@ultra.linux.cz),
+		  David S. Miller (davem@redhat.com) and
+		  Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#if _FP_W_TYPE_SIZE < 32
+#error "Here's a nickel, kid. Go buy yourself a real computer."
+#endif
+
+#if _FP_W_TYPE_SIZE < 64
+#define _FP_FRACTBITS_Q         (4*_FP_W_TYPE_SIZE)
+#else
+#define _FP_FRACTBITS_Q		(2*_FP_W_TYPE_SIZE)
+#endif
+
+#define _FP_FRACBITS_Q		113
+#define _FP_FRACXBITS_Q		(_FP_FRACTBITS_Q - _FP_FRACBITS_Q)
+#define _FP_WFRACBITS_Q		(_FP_WORKBITS + _FP_FRACBITS_Q)
+#define _FP_WFRACXBITS_Q	(_FP_FRACTBITS_Q - _FP_WFRACBITS_Q)
+#define _FP_EXPBITS_Q		15
+#define _FP_EXPBIAS_Q		16383
+#define _FP_EXPMAX_Q		32767
+
+#define _FP_QNANBIT_Q		\
+	((_FP_W_TYPE)1 << (_FP_FRACBITS_Q-2) % _FP_W_TYPE_SIZE)
+#define _FP_IMPLBIT_Q		\
+	((_FP_W_TYPE)1 << (_FP_FRACBITS_Q-1) % _FP_W_TYPE_SIZE)
+#define _FP_OVERFLOW_Q		\
+	((_FP_W_TYPE)1 << (_FP_WFRACBITS_Q % _FP_W_TYPE_SIZE))
+
+#if _FP_W_TYPE_SIZE < 64
+
+union _FP_UNION_Q
+{
+   long double flt;
+   struct 
+   {
+#if __BYTE_ORDER == __BIG_ENDIAN
+      unsigned sign : 1;
+      unsigned exp : _FP_EXPBITS_Q;
+      unsigned long frac3 : _FP_FRACBITS_Q - (_FP_IMPLBIT_Q != 0)-(_FP_W_TYPE_SIZE * 3);
+      unsigned long frac2 : _FP_W_TYPE_SIZE;
+      unsigned long frac1 : _FP_W_TYPE_SIZE;
+      unsigned long frac0 : _FP_W_TYPE_SIZE;
+#else
+      unsigned long frac0 : _FP_W_TYPE_SIZE;
+      unsigned long frac1 : _FP_W_TYPE_SIZE;
+      unsigned long frac2 : _FP_W_TYPE_SIZE;
+      unsigned long frac3 : _FP_FRACBITS_Q - (_FP_IMPLBIT_Q != 0)-(_FP_W_TYPE_SIZE * 3);
+      unsigned exp : _FP_EXPBITS_Q;
+      unsigned sign : 1;
+#endif /* not bigendian */
+   } bits __attribute__((packed));
+};
+
+
+#define FP_DECL_Q(X)		_FP_DECL(4,X)
+#define FP_UNPACK_RAW_Q(X,val)	_FP_UNPACK_RAW_4(Q,X,val)
+#define FP_UNPACK_RAW_QP(X,val)	_FP_UNPACK_RAW_4_P(Q,X,val)
+#define FP_PACK_RAW_Q(val,X)	_FP_PACK_RAW_4(Q,val,X)
+#define FP_PACK_RAW_QP(val,X)		\
+  do {					\
+    if (!FP_INHIBIT_RESULTS)		\
+      _FP_PACK_RAW_4_P(Q,val,X);	\
+  } while (0)
+
+#define FP_UNPACK_Q(X,val)		\
+  do {					\
+    _FP_UNPACK_RAW_4(Q,X,val);		\
+    _FP_UNPACK_CANONICAL(Q,4,X);	\
+  } while (0)
+
+#define FP_UNPACK_QP(X,val)		\
+  do {					\
+    _FP_UNPACK_RAW_4_P(Q,X,val);	\
+    _FP_UNPACK_CANONICAL(Q,4,X);	\
+  } while (0)
+
+#define FP_PACK_Q(val,X)		\
+  do {					\
+    _FP_PACK_CANONICAL(Q,4,X);		\
+    _FP_PACK_RAW_4(Q,val,X);		\
+  } while (0)
+
+#define FP_PACK_QP(val,X)		\
+  do {					\
+    _FP_PACK_CANONICAL(Q,4,X);		\
+    if (!FP_INHIBIT_RESULTS)		\
+      _FP_PACK_RAW_4_P(Q,val,X);	\
+  } while (0)
+
+#define FP_ISSIGNAN_Q(X)		_FP_ISSIGNAN(Q,4,X)
+#define FP_NEG_Q(R,X)			_FP_NEG(Q,4,R,X)
+#define FP_ADD_Q(R,X,Y)			_FP_ADD(Q,4,R,X,Y)
+#define FP_SUB_Q(R,X,Y)			_FP_SUB(Q,4,R,X,Y)
+#define FP_MUL_Q(R,X,Y)			_FP_MUL(Q,4,R,X,Y)
+#define FP_DIV_Q(R,X,Y)			_FP_DIV(Q,4,R,X,Y)
+#define FP_SQRT_Q(R,X)			_FP_SQRT(Q,4,R,X)
+#define _FP_SQRT_MEAT_Q(R,S,T,X,Q)	_FP_SQRT_MEAT_4(R,S,T,X,Q)
+
+#define FP_CMP_Q(r,X,Y,un)	_FP_CMP(Q,4,r,X,Y,un)
+#define FP_CMP_EQ_Q(r,X,Y)	_FP_CMP_EQ(Q,4,r,X,Y)
+
+#define FP_TO_INT_Q(r,X,rsz,rsg)	_FP_TO_INT(Q,4,r,X,rsz,rsg)
+#define FP_TO_INT_ROUND_Q(r,X,rsz,rsg)	_FP_TO_INT_ROUND(Q,4,r,X,rsz,rsg)
+#define FP_FROM_INT_Q(X,r,rs,rt)	_FP_FROM_INT(Q,4,X,r,rs,rt)
+
+#define _FP_FRAC_HIGH_Q(X)	_FP_FRAC_HIGH_4(X)
+#define _FP_FRAC_HIGH_RAW_Q(X)	_FP_FRAC_HIGH_4(X)
+
+#else   /* not _FP_W_TYPE_SIZE < 64 */
+union _FP_UNION_Q
+{
+  long double flt /* __attribute__((mode(TF))) */ ;
+  struct {
+#if __BYTE_ORDER == __BIG_ENDIAN
+    unsigned sign  : 1;
+    unsigned exp   : _FP_EXPBITS_Q;
+    unsigned long frac1 : _FP_FRACBITS_Q-(_FP_IMPLBIT_Q != 0)-_FP_W_TYPE_SIZE;
+    unsigned long frac0 : _FP_W_TYPE_SIZE;
+#else
+    unsigned long frac0 : _FP_W_TYPE_SIZE;
+    unsigned long frac1 : _FP_FRACBITS_Q-(_FP_IMPLBIT_Q != 0)-_FP_W_TYPE_SIZE;
+    unsigned exp   : _FP_EXPBITS_Q;
+    unsigned sign  : 1;
+#endif
+  } bits;
+};
+
+#define FP_DECL_Q(X)		_FP_DECL(2,X)
+#define FP_UNPACK_RAW_Q(X,val)	_FP_UNPACK_RAW_2(Q,X,val)
+#define FP_UNPACK_RAW_QP(X,val)	_FP_UNPACK_RAW_2_P(Q,X,val)
+#define FP_PACK_RAW_Q(val,X)	_FP_PACK_RAW_2(Q,val,X)
+#define FP_PACK_RAW_QP(val,X)		\
+  do {					\
+    if (!FP_INHIBIT_RESULTS)		\
+      _FP_PACK_RAW_2_P(Q,val,X);	\
+  } while (0)
+
+#define FP_UNPACK_Q(X,val)		\
+  do {					\
+    _FP_UNPACK_RAW_2(Q,X,val);		\
+    _FP_UNPACK_CANONICAL(Q,2,X);	\
+  } while (0)
+
+#define FP_UNPACK_QP(X,val)		\
+  do {					\
+    _FP_UNPACK_RAW_2_P(Q,X,val);	\
+    _FP_UNPACK_CANONICAL(Q,2,X);	\
+  } while (0)
+
+#define FP_PACK_Q(val,X)		\
+  do {					\
+    _FP_PACK_CANONICAL(Q,2,X);		\
+    _FP_PACK_RAW_2(Q,val,X);		\
+  } while (0)
+
+#define FP_PACK_QP(val,X)		\
+  do {					\
+    _FP_PACK_CANONICAL(Q,2,X);		\
+    if (!FP_INHIBIT_RESULTS)		\
+      _FP_PACK_RAW_2_P(Q,val,X);	\
+  } while (0)
+
+#define FP_ISSIGNAN_Q(X)		_FP_ISSIGNAN(Q,2,X)
+#define FP_NEG_Q(R,X)			_FP_NEG(Q,2,R,X)
+#define FP_ADD_Q(R,X,Y)			_FP_ADD(Q,2,R,X,Y)
+#define FP_SUB_Q(R,X,Y)			_FP_SUB(Q,2,R,X,Y)
+#define FP_MUL_Q(R,X,Y)			_FP_MUL(Q,2,R,X,Y)
+#define FP_DIV_Q(R,X,Y)			_FP_DIV(Q,2,R,X,Y)
+#define FP_SQRT_Q(R,X)			_FP_SQRT(Q,2,R,X)
+#define _FP_SQRT_MEAT_Q(R,S,T,X,Q)	_FP_SQRT_MEAT_2(R,S,T,X,Q)
+
+#define FP_CMP_Q(r,X,Y,un)	_FP_CMP(Q,2,r,X,Y,un)
+#define FP_CMP_EQ_Q(r,X,Y)	_FP_CMP_EQ(Q,2,r,X,Y)
+
+#define FP_TO_INT_Q(r,X,rsz,rsg)	_FP_TO_INT(Q,2,r,X,rsz,rsg)
+#define FP_TO_INT_ROUND_Q(r,X,rsz,rsg)	_FP_TO_INT_ROUND(Q,2,r,X,rsz,rsg)
+#define FP_FROM_INT_Q(X,r,rs,rt)	_FP_FROM_INT(Q,2,X,r,rs,rt)
+
+#define _FP_FRAC_HIGH_Q(X)	_FP_FRAC_HIGH_2(X)
+#define _FP_FRAC_HIGH_RAW_Q(X)	_FP_FRAC_HIGH_2(X)
+
+#endif /* not _FP_W_TYPE_SIZE < 64 */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/math-emu/single.h linux.14p16/include/math-emu/single.h
--- linux.vanilla/include/math-emu/single.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/math-emu/single.h	Thu Dec  9 15:33:13 1999
@@ -0,0 +1,111 @@
+/* Software floating-point emulation.
+   Definitions for IEEE Single Precision.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+		  Jakub Jelinek (jj@ultra.linux.cz),
+		  David S. Miller (davem@redhat.com) and
+		  Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#if _FP_W_TYPE_SIZE < 32
+#error "Here's a nickel kid.  Go buy yourself a real computer."
+#endif
+
+#define _FP_FRACBITS_S		24
+#define _FP_FRACXBITS_S		(_FP_W_TYPE_SIZE - _FP_FRACBITS_S)
+#define _FP_WFRACBITS_S		(_FP_WORKBITS + _FP_FRACBITS_S)
+#define _FP_WFRACXBITS_S	(_FP_W_TYPE_SIZE - _FP_WFRACBITS_S)
+#define _FP_EXPBITS_S		8
+#define _FP_EXPBIAS_S		127
+#define _FP_EXPMAX_S		255
+#define _FP_QNANBIT_S		((_FP_W_TYPE)1 << (_FP_FRACBITS_S-2))
+#define _FP_IMPLBIT_S		((_FP_W_TYPE)1 << (_FP_FRACBITS_S-1))
+#define _FP_OVERFLOW_S		((_FP_W_TYPE)1 << (_FP_WFRACBITS_S))
+
+/* The implementation of _FP_MUL_MEAT_S and _FP_DIV_MEAT_S should be
+   chosen by the target machine.  */
+
+union _FP_UNION_S
+{
+  float flt;
+  struct {
+#if __BYTE_ORDER == __BIG_ENDIAN
+    unsigned sign : 1;
+    unsigned exp  : _FP_EXPBITS_S;
+    unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0);
+#else
+    unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0);
+    unsigned exp  : _FP_EXPBITS_S;
+    unsigned sign : 1;
+#endif
+  } bits __attribute__((packed));
+};
+
+#define FP_DECL_S(X)		_FP_DECL(1,X)
+#define FP_UNPACK_RAW_S(X,val)	_FP_UNPACK_RAW_1(S,X,val)
+#define FP_UNPACK_RAW_SP(X,val)	_FP_UNPACK_RAW_1_P(S,X,val)
+#define FP_PACK_RAW_S(val,X)	_FP_PACK_RAW_1(S,val,X)
+#define FP_PACK_RAW_SP(val,X)		\
+  do {					\
+    if (!FP_INHIBIT_RESULTS)		\
+      _FP_PACK_RAW_1_P(S,val,X);	\
+  } while (0)
+
+#define FP_UNPACK_S(X,val)		\
+  do {					\
+    _FP_UNPACK_RAW_1(S,X,val);		\
+    _FP_UNPACK_CANONICAL(S,1,X);	\
+  } while (0)
+
+#define FP_UNPACK_SP(X,val)		\
+  do {					\
+    _FP_UNPACK_RAW_1_P(S,X,val);	\
+    _FP_UNPACK_CANONICAL(S,1,X);	\
+  } while (0)
+
+#define FP_PACK_S(val,X)		\
+  do {					\
+    _FP_PACK_CANONICAL(S,1,X);		\
+    _FP_PACK_RAW_1(S,val,X);		\
+  } while (0)
+
+#define FP_PACK_SP(val,X)		\
+  do {					\
+    _FP_PACK_CANONICAL(S,1,X);		\
+    if (!FP_INHIBIT_RESULTS)		\
+      _FP_PACK_RAW_1_P(S,val,X);	\
+  } while (0)
+
+#define FP_ISSIGNAN_S(X)		_FP_ISSIGNAN(S,1,X)
+#define FP_NEG_S(R,X)			_FP_NEG(S,1,R,X)
+#define FP_ADD_S(R,X,Y)			_FP_ADD(S,1,R,X,Y)
+#define FP_SUB_S(R,X,Y)			_FP_SUB(S,1,R,X,Y)
+#define FP_MUL_S(R,X,Y)			_FP_MUL(S,1,R,X,Y)
+#define FP_DIV_S(R,X,Y)			_FP_DIV(S,1,R,X,Y)
+#define FP_SQRT_S(R,X)			_FP_SQRT(S,1,R,X)
+#define _FP_SQRT_MEAT_S(R,S,T,X,Q)	_FP_SQRT_MEAT_1(R,S,T,X,Q)
+
+#define FP_CMP_S(r,X,Y,un)	_FP_CMP(S,1,r,X,Y,un)
+#define FP_CMP_EQ_S(r,X,Y)	_FP_CMP_EQ(S,1,r,X,Y)
+
+#define FP_TO_INT_S(r,X,rsz,rsg)	_FP_TO_INT(S,1,r,X,rsz,rsg)
+#define FP_TO_INT_ROUND_S(r,X,rsz,rsg)	_FP_TO_INT_ROUND(S,1,r,X,rsz,rsg)
+#define FP_FROM_INT_S(X,r,rs,rt)	_FP_FROM_INT(S,1,X,r,rs,rt)
+
+#define _FP_FRAC_HIGH_S(X)	_FP_FRAC_HIGH_1(X)
+#define _FP_FRAC_HIGH_RAW_S(X)	_FP_FRAC_HIGH_1(X)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/math-emu/soft-fp.h linux.14p16/include/math-emu/soft-fp.h
--- linux.vanilla/include/math-emu/soft-fp.h	Thu Jan  1 01:00:00 1970
+++ linux.14p16/include/math-emu/soft-fp.h	Thu Dec  9 15:33:13 1999
@@ -0,0 +1,181 @@
+/* Software floating-point emulation.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+		  Jakub Jelinek (jj@ultra.linux.cz),
+		  David S. Miller (davem@redhat.com) and
+		  Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef SOFT_FP_H
+#define SOFT_FP_H
+
+#include "sfp-machine.h"
+
+/* Allow sfp-machine to have its own byte order definitions. */
+#ifndef __BYTE_ORDER
+#include <endian.h>
+#endif
+
+#define _FP_WORKBITS		3
+#define _FP_WORK_LSB		((_FP_W_TYPE)1 << 3)
+#define _FP_WORK_ROUND		((_FP_W_TYPE)1 << 2)
+#define _FP_WORK_GUARD		((_FP_W_TYPE)1 << 1)
+#define _FP_WORK_STICKY		((_FP_W_TYPE)1 << 0)
+
+#ifndef FP_RND_NEAREST
+# define FP_RND_NEAREST		0
+# define FP_RND_ZERO		1
+# define FP_RND_PINF		2
+# define FP_RND_MINF		3
+#ifndef FP_ROUNDMODE
+# define FP_ROUNDMODE		FP_RND_NEAREST
+#endif
+#endif
+
+/* By default don't care about exceptions. */
+#ifndef FP_EX_INVALID
+#define FP_EX_INVALID		0
+#endif
+#ifndef FP_EX_OVERFLOW
+#define FP_EX_OVERFLOW		0
+#endif
+#ifndef FP_EX_UNDERFLOW
+#define FP_EX_UNDERFLOW		
+#endif
+#ifndef FP_EX_DIVZERO
+#define FP_EX_DIVZERO		0
+#endif
+#ifndef FP_EX_INEXACT
+#define FP_EX_INEXACT		0
+#endif
+#ifndef FP_EX_DENORM
+#define FP_EX_DENORM		0
+#endif
+
+#ifdef _FP_DECL_EX
+#define FP_DECL_EX					\
+  int _fex = 0;						\
+  _FP_DECL_EX
+#else
+#define FP_DECL_EX int _fex = 0
+#endif
+  
+#ifndef FP_INIT_ROUNDMODE
+#define FP_INIT_ROUNDMODE do {} while (0)
+#endif
+
+#ifndef FP_HANDLE_EXCEPTIONS
+#define FP_HANDLE_EXCEPTIONS do {} while (0)
+#endif
+
+/* By default we never flush denormal input operands to signed zero. */
+#ifndef FP_DENORM_ZERO
+#define FP_DENORM_ZERO 0
+#endif
+
+#ifndef FP_INHIBIT_RESULTS
+/* By default we write the results always.
+ * sfp-machine may override this and e.g.
+ * check if some exceptions are unmasked
+ * and inhibit it in such a case.
+ */
+#define FP_INHIBIT_RESULTS 0
+#endif
+
+#define FP_SET_EXCEPTION(ex)				\
+  _fex |= (ex)
+  
+#define FP_UNSET_EXCEPTION(ex)				\
+  _fex &= ~(ex)
+
+#define FP_CLEAR_EXCEPTIONS				\
+  _fex = 0
+
+#define _FP_ROUND_NEAREST(wc, X)			\
+do {							\
+    if ((_FP_FRAC_LOW_##wc(X) & 15) != _FP_WORK_ROUND)	\
+      _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND);		\
+} while (0)
+
+#define _FP_ROUND_ZERO(wc, X)		0
+
+#define _FP_ROUND_PINF(wc, X)				\
+do {							\
+    if (!X##_s && (_FP_FRAC_LOW_##wc(X) & 7))		\
+      _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB);		\
+} while (0)
+
+#define _FP_ROUND_MINF(wc, X)				\
+do {							\
+    if (X##_s && (_FP_FRAC_LOW_##wc(X) & 7))		\
+      _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB);		\
+} while (0)
+
+#define _FP_ROUND(wc, X)			\
+do {						\
+	if (_FP_FRAC_LOW_##wc(X) & 7)		\
+	  FP_SET_EXCEPTION(FP_EX_INEXACT);	\
+	switch (FP_ROUNDMODE)			\
+	{					\
+	  case FP_RND_NEAREST:			\
+	    _FP_ROUND_NEAREST(wc,X);		\
+	    break;				\
+	  case FP_RND_ZERO:			\
+	    _FP_ROUND_ZERO(wc,X);		\
+	    break;				\
+	  case FP_RND_PINF:			\
+	    _FP_ROUND_PINF(wc,X);		\
+	    break;				\
+	  case FP_RND_MINF:			\
+	    _FP_ROUND_MINF(wc,X);		\
+	    break;				\
+	}					\
+} while (0)
+
+#define FP_CLS_NORMAL		0
+#define FP_CLS_ZERO		1
+#define FP_CLS_INF		2
+#define FP_CLS_NAN		3
+
+#define _FP_CLS_COMBINE(x,y)	(((x) << 2) | (y))
+
+#include "op-1.h"
+#include "op-2.h"
+#include "op-4.h"
+#include "op-8.h"
+#include "op-common.h"
+
+/* Sigh.  Silly things longlong.h needs.  */
+#define UWtype		_FP_W_TYPE
+#define W_TYPE_SIZE	_FP_W_TYPE_SIZE
+
+typedef int SItype __attribute__((mode(SI)));
+typedef int DItype __attribute__((mode(DI)));
+typedef unsigned int USItype __attribute__((mode(SI)));
+typedef unsigned int UDItype __attribute__((mode(DI)));
+#if _FP_W_TYPE_SIZE == 32
+typedef unsigned int UHWtype __attribute__((mode(HI)));
+#elif _FP_W_TYPE_SIZE == 64
+typedef USItype UHWtype;
+#endif
+
+#ifndef umul_ppmm
+#include <stdlib/longlong.h>
+#endif
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/net/br.h linux.14p16/include/net/br.h
--- linux.vanilla/include/net/br.h	Sat Aug 14 02:27:40 1999
+++ linux.14p16/include/net/br.h	Mon Dec 13 19:39:56 1999
@@ -19,7 +19,16 @@
 #define Forwarding	3			  /* (4 4 4)	 */
 #define Blocking	4			  /* (4.4.1)	 */
 
-#define No_of_ports 8
+
+/* MAG Yich! Easiest way of giving a configurable number of ports
+ * If you want more than 32, change BR_MAX_PORTS and recompile brcfg!
+ */
+#define BR_MAX_PORTS (32)
+#if CONFIG_BRIDGE_NUM_PORTS > BR_MAX_PORTS
+#undef CONFIG_BRIDGE_NUM_PORTS
+#define CONFIG_BRIDGE_NUM_PORTS BR_MAX_PORTS
+#endif
+#define No_of_ports CONFIG_BRIDGE_NUM_PORTS
 /* arbitrary choice, to allow the code below to compile */
 
 #define All_ports (No_of_ports + 1)
@@ -147,6 +156,7 @@
 	unsigned int     top_change;		  /* (4.5.3.12)	 */
 	unsigned short   topology_change_time;	  /* (4.5.3.13)	 */
 	unsigned short   hold_time;		  /* (4.5.3.14)	 */
+	unsigned int	 instance;
 } Bridge_data;
 
 /** Port Parameters (4.5.5) **/
@@ -160,7 +170,10 @@
 	unsigned short   designated_port;	  /* (4.5.5.7)	 */
 	unsigned int     top_change_ack;	  /* (4.5.5.8)	 */
 	unsigned int     config_pending;	  /* (4.5.5.9)	 */
-	struct device *dev;	
+        bridge_id_t      ifmac; 
+        unsigned int     admin_state;
+	char             ifname[IFNAMSIZ]; /* Make life easier for brcfg */
+        struct device *dev;	
 	struct fdb *fdb;	/* head of per port fdb chain */
 } Port_data;
 
@@ -245,13 +258,14 @@
 struct br_stat {
 	unsigned int flags;
 	Bridge_data bridge_data;
-	Port_data port_data[No_of_ports];
 	unsigned int policy;
 	unsigned int exempt_protocols;
 	unsigned short protocols[BR_MAX_PROTOCOLS];
 	unsigned short prot_id[BR_MAX_PROT_STATS];	/* Protocol encountered */
 	unsigned int prot_counter[BR_MAX_PROT_STATS];	/* How many packets ? */
 	br_stats_counter packet_cnts;
+	unsigned int	num_ports;
+	Port_data port_data[BR_MAX_PORTS + 1];
 };
 
 /* defined flags for br_stat.flags */
@@ -274,7 +288,7 @@
 #define	BRCMD_SET_BRIDGE_PRIORITY	5	/* arg1 = priority */
 #define	BRCMD_SET_PORT_PRIORITY	6	/* arg1 = port, arg2 = priority */
 #define	BRCMD_SET_PATH_COST	7	/* arg1 = port, arg2 = cost */
-#define	BRCMD_DISPLAY_FDB	8	/* arg1 = port */
+#define	BRCMD_DISPLAY_FDB	8
 #define	BRCMD_ENABLE_DEBUG	9
 #define	BRCMD_DISABLE_DEBUG	10
 #define BRCMD_SET_POLICY	11	/* arg1 = default policy (1==bridge all) */
@@ -283,14 +297,19 @@
 #define BRCMD_DISABLE_PROT_STATS 14
 #define BRCMD_ZERO_PROT_STATS	15
 #define BRCMD_TOGGLE_STP	16
+#define BRCMD_IF_ENABLE		17	/* arg1 = if_index */
+#define BRCMD_IF_DISABLE	18	/* arg1 = if_index */
+#define BRCMD_SET_IF_PRIORITY	19	/* arg1 = if_index, arg2 = priority */
+#define	BRCMD_SET_IF_PATH_COST	20	/* arg1 = if_index, arg2 = cost */
 
 /* prototypes of exported bridging functions... */
 
+#ifdef __KERNEL__
 void br_init(void);
 int br_receive_frame(struct sk_buff *skb);	/* 3.5 */
 int br_tx_frame(struct sk_buff *skb);
+int brg_init(void);
 int br_ioctl(unsigned int cmd, void *arg);
-int br_protocol_ok(unsigned short protocol);
 void requeue_fdb(struct fdb *node, int new_port);
 
 struct fdb *br_avl_find_addr(unsigned char addr[6]);
@@ -298,8 +317,15 @@
 void sprintf_avl (char **pbuffer, struct fdb * tree, off_t *pos,int* len, off_t offset, int length);
 int br_tree_get_info(char *buffer, char **start, off_t offset, int length, int dummy);
 void br_avl_delete_by_port(int port);
+int br_call_bridge(struct sk_buff *skb, unsigned short type);
+void br_spacedevice_register(void);
+
 /* externs */
 
 extern struct br_stat br_stats;
 extern Port_data port_info[];
 
+#endif
+
+
+ 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/net/tcp.h linux.14p16/include/net/tcp.h
--- linux.vanilla/include/net/tcp.h	Sat Aug 28 20:00:59 1999
+++ linux.14p16/include/net/tcp.h	Wed Dec 15 23:16:17 1999
@@ -24,22 +24,18 @@
 #include <net/checksum.h>
 
 /* This is for all connections with a full identity, no wildcards.
- * New scheme, half the table is for TIME_WAIT, the other half is
- * for the rest.  I'll experiment with dynamic table growth later.
+ * Half of the table is for TIME_WAIT, the other half is for the
+ * rest.
+ *
+ * This needs to be shared by v4 and v6 because the lookup and hashing
+ * code needs to work with different AF's yet the port space is
+ * shared.
  */
-#define TCP_HTABLE_SIZE		512
+extern unsigned int tcp_ehash_size;
+extern struct sock **tcp_ehash;
 
 /* This is for listening sockets, thus all sockets which possess wildcards. */
 #define TCP_LHTABLE_SIZE	32	/* Yes, really, this is all you need. */
-
-/* This is for all sockets, to keep track of the local port allocations. */
-#define TCP_BHTABLE_SIZE	512
-
-/* tcp_ipv4.c: These need to be shared by v4 and v6 because the lookup
- *             and hashing code needs to work with different AF's yet
- *             the port space is shared.
- */
-extern struct sock *tcp_established_hash[TCP_HTABLE_SIZE];
 extern struct sock *tcp_listening_hash[TCP_LHTABLE_SIZE];
 
 /* There are a few simple rules, which allow for local port reuse by
@@ -81,7 +77,8 @@
 	struct tcp_bind_bucket	**pprev;
 };
 
-extern struct tcp_bind_bucket *tcp_bound_hash[TCP_BHTABLE_SIZE];
+extern unsigned int tcp_bhash_size;
+extern struct tcp_bind_bucket **tcp_bhash;
 extern kmem_cache_t *tcp_bucket_cachep;
 extern struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum);
 extern void tcp_bucket_unlock(struct sock *sk);
@@ -109,7 +106,7 @@
 /* These are AF independent. */
 static __inline__ int tcp_bhashfn(__u16 lport)
 {
-	return (lport & (TCP_BHTABLE_SIZE - 1));
+	return (lport & (tcp_bhash_size - 1));
 }
 
 /* This is a TIME_WAIT bucket.  It works around the memory consumption
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/scsi/sg.h linux.14p16/include/scsi/sg.h
--- linux.vanilla/include/scsi/sg.h	Sat Aug 14 02:26:52 1999
+++ linux.14p16/include/scsi/sg.h	Thu Dec  9 15:32:53 1999
@@ -12,10 +12,17 @@
 *       Copyright (C) 1998, 1999 Douglas Gilbert
 
 
-    Version: 2.1.34 (990603)
-    This version for later 2.1.x and 2.2.x series kernels
+    Version: 2.1.36 (991008)
+    This version for 2.2.x series kernels
     D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au)
 
+    Changes since 2.1.34 (990603)
+        - skipped 2.1.35 (never fully released)
+        - add queuing info into struct sg_scsi_id
+        - block negative timeout and reply_len values
+        - protect scsi_allocate_device() call
+        - fix pack_id input to sg_read()
+        - add wake_up to mid-level on command release
     Changes since 2.1.33 (990521)
         - implement SG_SET_RESERVED_SIZE and associated memory re-org.
         - add SG_NEXT_CMD_LEN to override SCSI command lengths
@@ -144,9 +151,10 @@
     int scsi_id;        /* scsi id of target device */
     int lun;
     int scsi_type;      /* TYPE_... defined in scsi/scsi.h */
+    short h_cmd_per_lun;/* host (adapter) maximum commands per lun */
+    short d_queue_depth;/* device (or adapter) maximum queue length */
     int unused1;        /* probably find a good use, set 0 for now */
     int unused2;        /* ditto */
-    int unused3;  
 } Sg_scsi_id;
 
 /* IOCTLs: ( _GET_s yield result via 'int *' 3rd argument unless 
@@ -204,6 +212,10 @@
 #define SG_GET_VERSION_NUM 0x2282 /* Example: version 2.1.34 yields 20134 */
 #define SG_NEXT_CMD_LEN 0x2283  /* override SCSI command length with given
                    number on the next write() on this file descriptor */
+
+/* Returns -EBUSY if occupied else takes as input: 0 -> do nothing,
+   1 -> device reset or  2 -> bus reset (not operational yet) */
+#define SG_SCSI_RESET 0x2284
 
 
 #define SG_SCATTER_SZ (8 * 4096)  /* PAGE_SIZE not available to user */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/init/main.c linux.14p16/init/main.c
--- linux.vanilla/init/main.c	Wed Oct 20 01:12:51 1999
+++ linux.14p16/init/main.c	Tue Dec 21 00:31:12 1999
@@ -46,6 +46,10 @@
 #include <linux/apm_bios.h>
 #endif
 
+#ifdef CONFIG_DASD
+#include "../drivers/s390/block/dasd.h"
+#endif
+
 #ifdef CONFIG_MAC
 extern void nubus_init(void);
 #endif
@@ -113,21 +117,30 @@
 #ifdef CONFIG_JOY_ANALOG
 extern void js_an_setup(char *str, int *ints);
 #endif
-#ifdef CONFIG_JOY_ASSASIN
+#ifdef CONFIG_JOY_ASSASSIN
 extern void js_as_setup(char *str, int *ints);
 #endif
 #ifdef CONFIG_JOY_CONSOLE
 extern void js_console_setup(char *str, int *ints);
+extern void js_console_setup_2(char *str, int *ints);
+extern void js_console_setup_3(char *str, int *ints);
 #endif
 #ifdef CONFIG_JOY_DB9
 extern void js_db9_setup(char *str, int *ints);
+extern void js_db9_setup_2(char *str, int *ints);
+extern void js_db9_setup_3(char *str, int *ints);
 #endif
 #ifdef CONFIG_JOY_TURBOGRAFX
 extern void js_tg_setup(char *str, int *ints);
+extern void js_tg_setup_2(char *str, int *ints);
+extern void js_tg_setup_3(char *str, int *ints);
 #endif
 #ifdef CONFIG_JOY_LIGHTNING
 extern void js_l4_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_JOY_PCI
+extern void js_pci_setup(char *str, int *ints);
+#endif
 extern void eth_setup(char *str, int *ints);
 #ifdef CONFIG_ARCNET_COM20020
 extern void com20020_setup(char *str, int *ints);
@@ -135,6 +148,9 @@
 #ifdef CONFIG_ARCNET_RIM_I
 extern void arcrimi_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_CTC  
+extern void ctc_setup(char *str, int *ints);
+#endif
 #ifdef CONFIG_ARCNET_COM90xxIO
 extern void com90io_setup(char *str, int *ints);
 #endif
@@ -166,6 +182,12 @@
 #ifdef CONFIG_PARIDE_PCD
 extern void pcd_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_MDISK
+extern void mdisk_setup(char *str, int *ints);
+#endif
+#ifdef CONFIG_DASD
+extern void dasd_setup(char *str, int *ints);
+#endif
 extern void floppy_setup(char *str, int *ints);
 extern void st_setup(char *str, int *ints);
 extern void st0x_setup(char *str, int *ints);
@@ -328,6 +350,9 @@
 #ifdef CONFIG_FTAPE
 extern void ftape_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_3215_CONSOLE
+extern int con3215_activate(void);
+#endif
 #ifdef CONFIG_MDA_CONSOLE
 extern void mdacon_setup(char *str, int *ints);
 #endif
@@ -525,6 +550,26 @@
 #if CONFIG_DDV
 	{ "ddv", DDV_MAJOR << 8},
 #endif
+#ifdef CONFIG_MDISK
+        { "mnd0", (MDISK_MAJOR << MINORBITS)},
+        { "mnd1", (MDISK_MAJOR << MINORBITS) + 1},
+        { "mnd2", (MDISK_MAJOR << MINORBITS) + 2},
+        { "mnd3", (MDISK_MAJOR << MINORBITS) + 3},
+        { "mnd4", (MDISK_MAJOR << MINORBITS) + 4},
+        { "mnd5", (MDISK_MAJOR << MINORBITS) + 5},
+        { "mnd6", (MDISK_MAJOR << MINORBITS) + 6},
+        { "mnd7", (MDISK_MAJOR << MINORBITS) + 7},
+#endif
+#ifdef CONFIG_DASD
+       { "dasd0", (DASD_MAJOR << MINORBITS) },
+       { "dasd1", (DASD_MAJOR << MINORBITS) + (1 << 2) },
+       { "dasd2", (DASD_MAJOR << MINORBITS) + (2 << 2) },
+       { "dasd3", (DASD_MAJOR << MINORBITS) + (3 << 2) },
+       { "dasd4", (DASD_MAJOR << MINORBITS) + (4 << 2) },
+       { "dasd5", (DASD_MAJOR << MINORBITS) + (5 << 2) },
+       { "dasd6", (DASD_MAJOR << MINORBITS) + (6 << 2) },
+       { "dasd7", (DASD_MAJOR << MINORBITS) + (7 << 2) },
+#endif
 	{ NULL, 0 }
 };
 
@@ -589,7 +634,12 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 	{ "noinitrd", no_initrd },
 #endif
+
+#ifdef CONFIG_CTC
+        { "ctc=", ctc_setup } ,
 #endif
+#endif
+
 #ifdef CONFIG_FB
 	{ "video=", video_setup },
 #endif
@@ -639,31 +689,34 @@
 #ifdef CONFIG_JOY_ANALOG
 	{ "js_an=", js_an_setup },
 #endif
-#ifdef CONFIG_JOY_ASSASIN
+#ifdef CONFIG_JOY_ASSASSIN
 	{ "js_as=", js_as_setup },
 #endif
 #ifdef CONFIG_JOY_CONSOLE
 	{ "js_console=", js_console_setup },
-	{ "js_console2=", js_console_setup },
-	{ "js_console3=", js_console_setup },
+	{ "js_console2=", js_console_setup_2 },
+	{ "js_console3=", js_console_setup_3 },
 #endif
 #ifdef CONFIG_JOY_DB9
 	{ "js_db9=", js_db9_setup },
-	{ "js_db9_2=", js_db9_setup },
-	{ "js_db9_3=", js_db9_setup },
+	{ "js_db9_2=", js_db9_setup_2 },
+	{ "js_db9_3=", js_db9_setup_3 },
 #endif
 #ifdef CONFIG_JOY_TURBOGRAFX
 	{ "js_tg=", js_tg_setup },
-	{ "js_tg_2=", js_tg_setup },
-	{ "js_tg_3=", js_tg_setup },
+	{ "js_tg_2=", js_tg_setup_2 },
+	{ "js_tg_3=", js_tg_setup_3 },
+#endif
+#ifdef CONFIG_JOY_LIGHTNING
+	{ "js_l4=", js_l4_setup },
+#endif
+#ifdef CONFIG_JOY_PCI
+	{ "js_pci=", js_pci_setup },
 #endif
 #ifdef CONFIG_SCSI
 	{ "max_scsi_luns=", scsi_luns_setup },
 	{ "scsi_logging=", scsi_logging_setup },
 #endif
-#ifdef CONFIG_JOY_LIGHTNING
-	{ "js_l4=", js_l4_setup },
-#endif
 #ifdef CONFIG_SCSI_ADVANSYS
 	{ "advansys=", advansys_setup },
 #endif
@@ -928,6 +981,12 @@
 #ifdef CONFIG_APM
 	{ "apm=", apm_setup },
 #endif
+#ifdef CONFIG_MDISK
+        { "mdisk=", mdisk_setup },
+#endif
+#ifdef CONFIG_DASD
+        { "dasd=", dasd_setup },
+#endif
 	{ 0, 0 }
 };
 
@@ -1203,6 +1262,9 @@
 #endif
 	mem_init(memory_start,memory_end);
 	kmem_cache_sizes_init();
+#ifdef CONFIG_3215_CONSOLE
+        con3215_activate();
+#endif
 #ifdef CONFIG_PROC_FS
 	proc_root_init();
 #endif
@@ -1211,6 +1273,7 @@
 	dcache_init();
 	vma_init();
 	buffer_init(memory_end-memory_start);
+ 	page_cache_init(memory_end-memory_start);
 	signals_init();
 	inode_init();
 	file_table_init();
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/ipc/msg.c linux.14p16/ipc/msg.c
--- linux.vanilla/ipc/msg.c	Fri Nov 20 19:43:19 1998
+++ linux.14p16/ipc/msg.c	Thu Dec  9 15:33:26 1999
@@ -50,6 +50,7 @@
 	struct ipc_perm *ipcp;
 	struct msg *msgh;
 	long mtype;
+	int err;
 	
 	if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0)
 		return -EINVAL;
@@ -70,34 +71,38 @@
 	if (ipcperms(ipcp, S_IWUGO)) 
 		return -EACCES;
 	
-	if (msgsz + msq->msg_cbytes > msq->msg_qbytes) { 
-		if (msgsz + msq->msg_cbytes > msq->msg_qbytes) { 
-			/* still no space in queue */
-			if (msgflg & IPC_NOWAIT)
-				return -EAGAIN;
-			if (signal_pending(current))
-				return -EINTR;
-			interruptible_sleep_on (&msq->wwait);
-			goto slept;
-		}
+	if (msgsz + msq->msg_cbytes > msq->msg_qbytes || msq->msg_qnum>= MSGQNUM) { 
+		/* still no space in queue */
+		if (msgflg & IPC_NOWAIT)
+			return -EAGAIN;
+		if (signal_pending(current))
+			return -EINTR;
+		interruptible_sleep_on (&msq->wwait);
+		goto slept;
 	}
-	
-	/* allocate message header and text space*/ 
+
+	/* Charge first to avoid races */
+	msgbytes  += msgsz;
+	msghdrs++;
+	msq->msg_qnum++;
+	msq->msg_cbytes += msgsz;
+
+	/* allocate message header and text space */ 
+	err = -ENOMEM;
 	msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz, GFP_KERNEL);
-	if (!msgh)
-		return -ENOMEM;
+	if (!msgh) 
+		goto uncharge;
 	msgh->msg_spot = (char *) (msgh + 1);
 
-	if (copy_from_user(msgh->msg_spot, msgp->mtext, msgsz))
-	{
-		kfree(msgh);
-		return -EFAULT;
+	err = -EFAULT; 
+	if (copy_from_user(msgh->msg_spot, msgp->mtext, msgsz))	{
+		goto uncharge;
 	}
 	
+	err = -EIDRM; 
 	if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
 		|| msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
-		kfree(msgh);
-		return -EIDRM;
+		goto uncharge;
 	}
 
 	msgh->msg_next = NULL;
@@ -111,14 +116,19 @@
 		msq->msg_last->msg_next = msgh;
 		msq->msg_last = msgh;
 	}
-	msq->msg_cbytes += msgsz;
-	msgbytes  += msgsz;
-	msghdrs++;
-	msq->msg_qnum++;
 	msq->msg_lspid = current->pid;
 	msq->msg_stime = CURRENT_TIME;
 	wake_up (&msq->rwait);
 	return 0;
+
+uncharge:
+	msgbytes  -= msgsz;
+	msghdrs--;
+	msq->msg_qnum--;
+	msq->msg_cbytes -= msgsz;
+	if (msgh)
+		kfree(msgh); 
+	return err;
 }
 
 static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/ipc/sem.c linux.14p16/ipc/sem.c
--- linux.vanilla/ipc/sem.c	Sun Jan 10 03:16:44 1999
+++ linux.14p16/ipc/sem.c	Thu Dec  9 15:33:26 1999
@@ -694,7 +694,7 @@
                 interruptible_sleep_on(&queue.sleeper);
 
                 /*
-                 * If queue.status == 1 we where woken up and
+                 * If queue.status == 1 we were woken up and
                  * have to retry else we simply return.
                  * If an interrupt occurred we have to clean up the
                  * queue
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/ipc/shm.c linux.14p16/ipc/shm.c
--- linux.vanilla/ipc/shm.c	Wed Oct 20 01:12:51 1999
+++ linux.14p16/ipc/shm.c	Thu Dec  9 15:33:26 1999
@@ -639,10 +639,8 @@
 	pte = __pte(shp->shm_pages[idx]);
 	if (!pte_present(pte)) {
 		unsigned long page = get_free_page(GFP_USER);
-		if (!page) {
-			oom(current);
-			return 0;
-		}
+		if (!page)
+			return -1;
 		pte = __pte(shp->shm_pages[idx]);
 		if (pte_present(pte)) {
 			free_page (page); /* doesn't sleep */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/dma.c linux.14p16/kernel/dma.c
--- linux.vanilla/kernel/dma.c	Mon Oct 12 19:50:15 1998
+++ linux.14p16/kernel/dma.c	Wed Dec 15 22:34:02 1999
@@ -16,6 +16,7 @@
 #include <asm/system.h>
 #include <asm/spinlock.h>
 
+ 
 
 /* A note on resource allocation:
  *
@@ -35,6 +36,12 @@
 
 spinlock_t dma_spin_lock = SPIN_LOCK_UNLOCKED;
 
+/*
+ *	If our port doesn't define this it has no PC like DMA
+ */
+
+#ifdef MAX_DMA_CHANNELS
+
 
 /* Channel n is busy iff dma_chan_busy[n].lock != 0.
  * DMA0 used to be reserved for DRAM refresh, but apparently not any more...
@@ -100,3 +107,22 @@
 	}	
 
 } /* free_dma */
+
+#else
+
+int request_dma(unsigned int dmanr, const char *device_id)
+{
+	return -EINVAL;
+}
+
+int free_dma(unsigned int dmanr)
+{
+	return -EINVAL;
+}
+
+int get_dma_list(char *buf)
+{	
+	strcpy(buf, "No DMA\n");
+	return 7;
+}
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/exit.c linux.14p16/kernel/exit.c
--- linux.vanilla/kernel/exit.c	Wed Oct 20 01:12:51 1999
+++ linux.14p16/kernel/exit.c	Thu Dec  9 15:32:46 1999
@@ -232,18 +232,17 @@
 static inline void __exit_sighand(struct task_struct *tsk)
 {
 	struct signal_struct * sig = tsk->sig;
+	unsigned long flags;
 
+	spin_lock_irqsave(&tsk->sigmask_lock, flags);
 	if (sig) {
-		unsigned long flags;
-
-		spin_lock_irqsave(&tsk->sigmask_lock, flags);
 		tsk->sig = NULL;
-		spin_unlock_irqrestore(&tsk->sigmask_lock, flags);
 		if (atomic_dec_and_test(&sig->count))
 			kfree(sig);
 	}
 
 	flush_signals(tsk);
+	spin_unlock_irqrestore(&tsk->sigmask_lock, flags);
 }
 
 void exit_sighand(struct task_struct *tsk)
@@ -444,6 +443,13 @@
 	add_wait_queue(&current->wait_chldexit,&wait);
 repeat:
 	flag = 0;
+
+	/* The interruptible state must be set before looking at the
+	   children. This because we want to catch any racy exit from
+	   the children as do_exit() may run under us. The following
+	   read_lock will enforce SMP ordering at the CPU level. */
+	current->state = TASK_INTERRUPTIBLE;
+
 	read_lock(&tasklist_lock);
  	for (p = current->p_cptr ; p ; p = p->p_osptr) {
 		if (pid>0) {
@@ -510,13 +516,13 @@
 		retval = -ERESTARTSYS;
 		if (signal_pending(current))
 			goto end_wait4;
-		current->state=TASK_INTERRUPTIBLE;
 		schedule();
 		goto repeat;
 	}
 	retval = -ECHILD;
 end_wait4:
 	remove_wait_queue(&current->wait_chldexit,&wait);
+	current->state = TASK_RUNNING;
 	return retval;
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/kmod.c linux.14p16/kernel/kmod.c
--- linux.vanilla/kernel/kmod.c	Thu Nov 12 17:58:32 1998
+++ linux.14p16/kernel/kmod.c	Thu Dec  9 15:32:46 1999
@@ -23,22 +23,24 @@
 char modprobe_path[256] = "/sbin/modprobe";
 
 static inline void
-use_init_file_context(void)
+use_init_fs_context(void)
 {
 	struct fs_struct * fs;
 
-	lock_kernel();
-
 	/*
-	 * Don't use the user's root, use init's root instead.
+	 * Don't use the user's fs context, use init's instead.
 	 * Note that we can use "init_task" (which is not actually
 	 * the same as the user-level "init" process) because we
 	 * started "init" with a CLONE_FS
 	 */
-	exit_fs(current);	/* current->fs->count--; */
-	fs = init_task.fs;
-	current->fs = fs;
-	atomic_inc(&fs->count);
+
+	lock_kernel();
+
+	fs = current->fs;
+	dput(fs->root);
+	dput(fs->pwd);
+	fs->root = dget(init_task.fs->root);
+	fs->pwd = dget(init_task.fs->pwd);
 
 	unlock_kernel();
 }
@@ -49,8 +51,6 @@
 	char *argv[] = { modprobe_path, "-s", "-k", (char*)module_name, NULL };
 	int i;
 
-	use_init_file_context();
-
 	/* Prevent parent user process from sending signals to child.
 	   Otherwise, if the modprobe program does not exist, it might
 	   be possible to get a user defined signal handler to execute
@@ -62,6 +62,10 @@
 	flush_signal_handlers(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
+	/* Copy root dir and cwd from init */
+	use_init_fs_context();
+
+	/* Close our copies of user's open files */
 	for (i = 0; i < current->files->max_fds; i++ ) {
 		if (current->files->fd[i]) close(i);
 	}
@@ -104,7 +108,7 @@
 		return -EPERM;
 	}
 
-	pid = kernel_thread(exec_modprobe, (void*) module_name, CLONE_FS);
+	pid = kernel_thread(exec_modprobe, (void*) module_name, 0);
 	if (pid < 0) {
 		printk(KERN_ERR "request_module[%s]: fork failed, errno %d\n", module_name, -pid);
 		return pid;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/ksyms.c linux.14p16/kernel/ksyms.c
--- linux.vanilla/kernel/ksyms.c	Wed Oct 20 01:12:51 1999
+++ linux.14p16/kernel/ksyms.c	Wed Dec 15 22:33:43 1999
@@ -54,6 +54,9 @@
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 extern int (*do_nfsservctl)(int, void *, void *);
 #endif
+#if !defined(CONFIG_LOCKD) && defined(CONFIG_LOCKD_MODULE)
+extern int (*do_lockdctl)(int, void *, void *);
+#endif
 
 extern void *sys_call_table;
 
@@ -121,6 +124,7 @@
 EXPORT_SYMBOL(igrab);
 EXPORT_SYMBOL(iunique);
 EXPORT_SYMBOL(iget);
+EXPORT_SYMBOL(iget_in_use);
 EXPORT_SYMBOL(iput);
 EXPORT_SYMBOL(__namei);
 EXPORT_SYMBOL(lookup_dentry);
@@ -136,6 +140,7 @@
 EXPORT_SYMBOL(d_alloc);
 EXPORT_SYMBOL(d_lookup);
 EXPORT_SYMBOL(d_path);
+EXPORT_SYMBOL(have_submounts);
 EXPORT_SYMBOL(__mark_inode_dirty);
 EXPORT_SYMBOL(get_empty_filp);
 EXPORT_SYMBOL(init_private_file);
@@ -144,7 +149,7 @@
 EXPORT_SYMBOL(fput);
 EXPORT_SYMBOL(put_filp);
 EXPORT_SYMBOL(check_disk_change);
-EXPORT_SYMBOL(invalidate_buffers);
+EXPORT_SYMBOL(__invalidate_buffers);
 EXPORT_SYMBOL(invalidate_inodes);
 EXPORT_SYMBOL(invalidate_inode_pages);
 EXPORT_SYMBOL(truncate_inode_pages);
@@ -189,10 +194,14 @@
 EXPORT_SYMBOL(vfs_rename);
 EXPORT_SYMBOL(__pollwait);
 EXPORT_SYMBOL(ROOT_DEV);
+EXPORT_SYMBOL(inode_generation_count);
 
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 EXPORT_SYMBOL(do_nfsservctl);
 #endif
+#if !defined(CONFIG_LOCKD) && defined(CONFIG_LOCKD_MODULE)
+EXPORT_SYMBOL(do_lockdctl);
+#endif
 
 /* device registration */
 EXPORT_SYMBOL(register_chrdev);
@@ -270,8 +279,6 @@
 /* interrupt handling */
 EXPORT_SYMBOL(request_irq);
 EXPORT_SYMBOL(free_irq);
-EXPORT_SYMBOL(probe_irq_on);
-EXPORT_SYMBOL(probe_irq_off);
 EXPORT_SYMBOL(bh_active);
 EXPORT_SYMBOL(bh_mask);
 EXPORT_SYMBOL(bh_mask_count);
@@ -291,14 +298,23 @@
 EXPORT_SYMBOL(waitqueue_lock);
 #endif
 
+/*
+ *	S390 has no auto-irq
+ */
+ 
+#ifndef CONFIG_ARCH_S390
+EXPORT_SYMBOL(probe_irq_on);
+EXPORT_SYMBOL(probe_irq_off);
 /* autoirq from  drivers/net/auto_irq.c */
 EXPORT_SYMBOL(autoirq_setup);
 EXPORT_SYMBOL(autoirq_report);
+#endif
 
 /* dma handling */
 EXPORT_SYMBOL(request_dma);
 EXPORT_SYMBOL(free_dma);
 EXPORT_SYMBOL(dma_spin_lock);
+
 #ifdef HAVE_DISABLE_HLT
 EXPORT_SYMBOL(disable_hlt);
 EXPORT_SYMBOL(enable_hlt);
@@ -377,7 +393,7 @@
 EXPORT_SYMBOL(remove_inode_hash);
 EXPORT_SYMBOL(make_bad_inode);
 EXPORT_SYMBOL(is_bad_inode);
-EXPORT_SYMBOL(event);
+EXPORT_SYMBOL(global_event);
 EXPORT_SYMBOL(__down);
 EXPORT_SYMBOL(__down_interruptible);
 EXPORT_SYMBOL(__down_trylock);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/panic.c linux.14p16/kernel/panic.c
--- linux.vanilla/kernel/panic.c	Sat Aug 14 02:27:40 1999
+++ linux.14p16/kernel/panic.c	Wed Dec 15 22:25:45 1999
@@ -74,11 +74,19 @@
 		machine_restart(NULL);
 	}
 #ifdef __sparc__
-	printk("Press L1-A to return to the boot prom\n");
+	{
+		extern int stop_a_enabled;
+		/* Make sure the user can actually press L1-A */
+		stop_a_enabled = 1;
+		printk("Press L1-A to return to the boot prom\n");
+	}
 #endif
 #ifdef __alpha__
 	if (alpha_using_srm)
 		halt();
+#endif
+#ifdef CONFIG_ARCH_S390
+        disabled_wait(0x1234);
 #endif
 	sti();
 	for(;;) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/sched.c linux.14p16/kernel/sched.c
--- linux.vanilla/kernel/sched.c	Wed Oct 20 01:12:51 1999
+++ linux.14p16/kernel/sched.c	Wed Dec 15 22:25:54 1999
@@ -78,7 +78,7 @@
 long time_adjust = 0;
 long time_adjust_step = 0;
 
-unsigned long event = 0;
+unsigned long global_event = 0;
 
 extern int do_setitimer(int, struct itimerval *, struct itimerval *);
 unsigned int * prof_buffer = NULL;
@@ -862,7 +862,11 @@
 
 scheduling_in_interrupt:
 	printk("Scheduling in interrupt\n");
+#ifdef CONFIG_ARCH_S390
+	asm volatile ( ".word 0\n" );
+#else
 	*(int *)0 = 0;
+#endif /* CONFIG_ARCH_S390 */
 	return;
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/signal.c linux.14p16/kernel/signal.c
--- linux.vanilla/kernel/signal.c	Wed Oct 20 01:12:51 1999
+++ linux.14p16/kernel/signal.c	Thu Dec  9 15:32:46 1999
@@ -44,6 +44,8 @@
 
 /*
  * Flush all pending signals for a task.
+ * Callers must hold the sigmask_lock so that we do not race
+ * with dequeue_signal or send_sig_info.
  */
 
 void
@@ -270,12 +272,16 @@
 		goto out_nolock;
 
 	/* The null signal is a permissions and process existance probe.
-	   No signal is actually delivered.  Same goes for zombies. */
+	   No signal is actually delivered.  Same goes for zombies.
+	   We have to grab the spinlock now so that we do not race
+	   with flush_signals. */
 	ret = 0;
-	if (!sig || !t->sig)
+	spin_lock_irqsave(&t->sigmask_lock, flags);
+	if (!sig || !t->sig) {
+		spin_unlock_irqrestore(&t->sigmask_lock, flags);
 		goto out_nolock;
+	}
 
-	spin_lock_irqsave(&t->sigmask_lock, flags);
 	switch (sig) {
 	case SIGKILL: case SIGCONT:
 		/* Wake up the process if stopped.  */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/sysctl.c linux.14p16/kernel/sysctl.c
--- linux.vanilla/kernel/sysctl.c	Wed Oct 20 01:12:51 1999
+++ linux.14p16/kernel/sysctl.c	Thu Dec  9 15:32:46 1999
@@ -53,6 +53,7 @@
 
 #ifdef __sparc__
 extern char reboot_command [];
+extern int stop_a_enabled;
 #endif
 #ifdef __powerpc__
 extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap;
@@ -169,8 +170,10 @@
 	 0644, NULL, &proc_doutsstring, &sysctl_string},
 	{KERN_PANIC, "panic", &panic_timeout, sizeof(int),
 	 0644, NULL, &proc_dointvec},
+#ifdef CONFIG_PROC_FS	 
 	{KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
 	 0600, NULL, &proc_dointvec_bset},
+#endif	 
 #ifdef CONFIG_BLK_DEV_INITRD
 	{KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
 	 0644, NULL, &proc_dointvec},
@@ -184,6 +187,8 @@
 #ifdef __sparc__
 	{KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
 	 256, 0644, NULL, &proc_dostring, &sysctl_string },
+	{KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int),
+	 0644, NULL, &proc_dointvec},
 #endif
 #ifdef __powerpc__
 	{KERN_PPC_HTABRECLAIM, "htab-reclaim", &htab_reclaim_on, sizeof(int),
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/mm/filemap.c linux.14p16/mm/filemap.c
--- linux.vanilla/mm/filemap.c	Wed Oct 20 01:12:51 1999
+++ linux.14p16/mm/filemap.c	Thu Dec  9 15:32:48 1999
@@ -20,6 +20,7 @@
 #include <linux/file.h>
 #include <linux/swapctl.h>
 #include <linux/slab.h>
+#include <linux/init.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -32,7 +33,8 @@
  */
 
 unsigned long page_cache_size = 0;
-struct page * page_hash_table[PAGE_HASH_SIZE];
+unsigned int page_hash_bits, page_hash_mask;
+struct page **page_hash_table;
 
 /* 
  * Define a request structure for outstanding page write requests
@@ -985,7 +987,7 @@
 	if (no_share && !new_page) {
 		new_page = page_cache_alloc();
 		if (!new_page)
-			goto failure;
+			goto release_and_oom;
 	}
 
 	if (PageLocked(page))
@@ -1033,7 +1035,7 @@
 	if (!new_page)
 		new_page = page_cache_alloc();
 	if (!new_page)
-		goto no_page;
+		goto oom;
 
 	/*
 	 * During getting the above page we might have slept,
@@ -1087,6 +1089,11 @@
 		page_cache_free(new_page);
 no_page:
 	return 0;
+
+release_and_oom:
+	page_cache_release(page);
+oom:
+	return -1;
 }
 
 /*
@@ -1756,4 +1763,35 @@
 			kmem_cache_free(pio_request_cache, p);
 		}
 	}
+}
+
+void __init page_cache_init(unsigned long memory_size)
+{
+	unsigned long htable_size;
+	long order;
+
+	htable_size  = memory_size >> PAGE_SHIFT;
+	htable_size *= sizeof(struct page *);
+	for(order = 0; (PAGE_SIZE << order) < htable_size; order++)
+		;
+
+	do {
+		unsigned long tmp = (PAGE_SIZE << order) / sizeof(struct page *);
+
+		page_hash_mask = (tmp - 1UL);
+
+		page_hash_bits = 0;
+		while((tmp >>= 1UL) != 0UL)
+			page_hash_bits++;
+
+		page_hash_table = (struct page **)
+			__get_free_pages(GFP_ATOMIC, order);
+	} while(page_hash_table == NULL && --order >= 0L);
+
+	printk("Page cache hash table entries: %d (order %ld, %ldk)\n",
+	       (1 << page_hash_bits), order, (1UL << order) * PAGE_SIZE / 1024);
+	if (!page_hash_table)
+		panic("Failed to allocate page hash table\n");
+	memset(page_hash_table, 0,
+	       (PAGE_HASH_MASK + 1UL) * sizeof(struct page *));
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/mm/memory.c linux.14p16/mm/memory.c
--- linux.vanilla/mm/memory.c	Sat Aug 14 02:27:40 1999
+++ linux.14p16/mm/memory.c	Thu Dec  9 15:32:48 1999
@@ -62,16 +62,6 @@
 mem_map_t * mem_map = NULL;
 
 /*
- * oom() prints a message (so that the user knows why the process died),
- * and gives the process an untrappable SIGKILL.
- */
-void oom(struct task_struct * task)
-{
-	printk("\nOut of memory for %s.\n", task->comm);
-	force_sig(SIGKILL, task);
-}
-
-/*
  * Note: this doesn't free the actual pages themselves. That
  * has been handled earlier when unmapping all the memory regions.
  */
@@ -577,13 +567,13 @@
 	pmd = pmd_alloc(pgd, address);
 	if (!pmd) {
 		free_page(page);
-		oom(tsk);
+		force_sig(SIGKILL, tsk);
 		return 0;
 	}
 	pte = pte_alloc(pmd, address);
 	if (!pte) {
 		free_page(page);
-		oom(tsk);
+		force_sig(SIGKILL, tsk);
 		return 0;
 	}
 	if (!pte_none(*pte)) {
@@ -687,12 +677,11 @@
 
 bad_wp_page:
 	printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page);
-	send_sig(SIGKILL, tsk, 1);
 no_new_page:
 	unlock_kernel();
 	if (new_page)
 		free_page(new_page);
-	return 0;
+	return -1;
 }
 
 /*
@@ -789,8 +778,9 @@
 	struct vm_area_struct * vma, unsigned long address,
 	pte_t * page_table, pte_t entry, int write_access)
 {
+	int ret = 1;
 	if (!vma->vm_ops || !vma->vm_ops->swapin) {
-		swap_in(tsk, vma, page_table, pte_val(entry), write_access);
+		ret = swap_in(tsk, vma, page_table, pte_val(entry), write_access);
 		flush_page_to_ram(pte_page(*page_table));
 	} else {
 		pte_t page = vma->vm_ops->swapin(vma, address - vma->vm_start + vma->vm_offset, pte_val(entry));
@@ -807,7 +797,7 @@
 		}
 	}
 	unlock_kernel();
-	return 1;
+	return ret;
 }
 
 /*
@@ -819,7 +809,7 @@
 	if (write_access) {
 		unsigned long page = __get_free_page(GFP_USER);
 		if (!page)
-			return 0;
+			return -1;
 		clear_page(page);
 		entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
 		vma->vm_mm->rss++;
@@ -865,6 +855,8 @@
 	unlock_kernel();
 	if (!page)
 		return 0;
+	if (page == -1)
+		return -1;
 
 	++tsk->maj_flt;
 	++vma->vm_mm->rss;
@@ -937,25 +929,26 @@
 {
 	pgd_t *pgd;
 	pmd_t *pmd;
+	pte_t * pte;
+	int ret;
 
 	pgd = pgd_offset(vma->vm_mm, address);
 	pmd = pmd_alloc(pgd, address);
-	if (pmd) {
-		pte_t * pte = pte_alloc(pmd, address);
-		if (pte) {
-			if (handle_pte_fault(tsk, vma, address, write_access, pte)) {
-				update_mmu_cache(vma, address, *pte);
-				return 1;
-			}
-		}
-	}
-	return 0;
+	if (!pmd)
+		return -1;
+	pte = pte_alloc(pmd, address);
+	if (!pte)
+		return -1;
+	ret = handle_pte_fault(tsk, vma, address, write_access, pte);
+	if (ret > 0)
+		update_mmu_cache(vma, address, *pte);
+	return ret;
 }
 
 /*
  * Simplistic page force-in..
  */
-void make_pages_present(unsigned long addr, unsigned long end)
+int make_pages_present(unsigned long addr, unsigned long end)
 {
 	int write;
 	struct vm_area_struct * vma;
@@ -963,7 +956,9 @@
 	vma = find_vma(current->mm, addr);
 	write = (vma->vm_flags & VM_WRITE) != 0;
 	while (addr < end) {
-		handle_mm_fault(current, vma, addr, write);
+		if (handle_mm_fault(current, vma, addr, write) < 0)
+			return -1;
 		addr += PAGE_SIZE;
 	}
+	return 0;
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/mm/mmap.c linux.14p16/mm/mmap.c
--- linux.vanilla/mm/mmap.c	Wed Oct 20 01:12:52 1999
+++ linux.14p16/mm/mmap.c	Thu Dec  9 15:32:48 1999
@@ -186,7 +186,7 @@
 		return -EINVAL;
 
 	/* offset overflow? */
-	if (off + len < off)
+	if (off + len - 1 < off)
 		return -EINVAL;
 
 	/* Too many mappings? */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/mm/page_alloc.c linux.14p16/mm/page_alloc.c
--- linux.vanilla/mm/page_alloc.c	Wed Oct 20 01:12:52 1999
+++ linux.14p16/mm/page_alloc.c	Thu Dec  9 15:32:48 1999
@@ -388,7 +388,7 @@
  * Also, don't bother to add to the swap cache if this page-in
  * was due to a write access.
  */
-void swap_in(struct task_struct * tsk, struct vm_area_struct * vma,
+int swap_in(struct task_struct * tsk, struct vm_area_struct * vma,
 	pte_t * page_table, unsigned long entry, int write_access)
 {
 	unsigned long page;
@@ -401,14 +401,10 @@
 	if (pte_val(*page_table) != entry) {
 		if (page_map)
 			free_page_and_swap_cache(page_address(page_map));
-		return;
-	}
-	if (!page_map) {
-		set_pte(page_table, BAD_PAGE);
-		swap_free(entry);
-		oom(tsk);
-		return;
+		return 1;
 	}
+	if (!page_map)
+		return -1;
 
 	page = page_address(page_map);
 	vma->vm_mm->rss++;
@@ -417,7 +413,7 @@
 
 	if (!write_access || is_page_shared(page_map)) {
 		set_pte(page_table, mk_pte(page, vma->vm_page_prot));
-		return;
+		return 1;
 	}
 
 	/*
@@ -427,5 +423,5 @@
 	 */
 	delete_from_swap_cache(page_map);
 	set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))));
-  	return;
+  	return 1;
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/mm/swapfile.c linux.14p16/mm/swapfile.c
--- linux.vanilla/mm/swapfile.c	Sat Aug 14 02:27:41 1999
+++ linux.14p16/mm/swapfile.c	Thu Dec  9 15:32:48 1999
@@ -130,15 +130,17 @@
 	offset = SWP_OFFSET(entry);
 	if (offset >= p->max)
 		goto bad_offset;
-	if (offset < p->lowest_bit)
-		p->lowest_bit = offset;
-	if (offset > p->highest_bit)
-		p->highest_bit = offset;
 	if (!p->swap_map[offset])
 		goto bad_free;
 	if (p->swap_map[offset] < SWAP_MAP_MAX) {
 		if (!--p->swap_map[offset])
+		{
+			if (offset < p->lowest_bit)
+				p->lowest_bit = offset;
+			if (offset > p->highest_bit)
+				p->highest_bit = offset;
 			nr_swap_pages++;
+		}
 	}
 #ifdef DEBUG_SWAP
 	printk("DebugVM: swap_free(entry %08lx, count now %d)\n",
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/mm/vmscan.c linux.14p16/mm/vmscan.c
--- linux.vanilla/mm/vmscan.c	Sat Aug 14 02:26:01 1999
+++ linux.14p16/mm/vmscan.c	Mon Dec 13 18:26:29 1999
@@ -53,6 +53,7 @@
 		 * tables to the global page map.
 		 */
 		set_pte(page_table, pte_mkold(pte));
+		flush_tlb_page(vma, address);
 		set_bit(PG_referenced, &page_map->flags);
 		return 0;
 	}
@@ -95,6 +96,7 @@
 	 * some real work in the future in "shrink_mmap()".
 	 */
 	if (!pte_dirty(pte)) {
+		flush_cache_page(vma, address);
 		pte_clear(page_table);
 		goto drop_pte;
 	}
@@ -308,7 +310,8 @@
 static int swap_out(unsigned int priority, int gfp_mask)
 {
 	struct task_struct * p, * pbest;
-	int counter, assign, max_cnt;
+	int assign = 0, counter;
+	unsigned long max_cnt;
 
 	/* 
 	 * We make one or two passes through the task list, indexed by 
@@ -327,11 +330,8 @@
 	counter = nr_tasks / (priority+1);
 	if (counter < 1)
 		counter = 1;
-	if (counter > nr_tasks)
-		counter = nr_tasks;
 
 	for (; counter >= 0; counter--) {
-		assign = 0;
 		max_cnt = 0;
 		pbest = NULL;
 	select:
@@ -343,7 +343,7 @@
 	 		if (p->mm->rss <= 0)
 				continue;
 			/* Refresh swap_cnt? */
-			if (assign)
+			if (assign == 1)
 				p->mm->swap_cnt = p->mm->rss;
 			if (p->mm->swap_cnt > max_cnt) {
 				max_cnt = p->mm->swap_cnt;
@@ -351,6 +351,8 @@
 			}
 		}
 		read_unlock(&tasklist_lock);
+		if (assign == 1)
+			assign = 2;
 		if (!pbest) {
 			if (!assign) {
 				assign = 1;
@@ -435,7 +437,7 @@
        printk ("Starting kswapd v%.*s\n", i, s);
 }
 
-static struct task_struct *kswapd_process;
+static struct wait_queue * kswapd_wait = NULL;
 
 /*
  * The background pageout daemon, started as a kernel thread
@@ -455,7 +457,6 @@
 {
 	struct task_struct *tsk = current;
 
-	kswapd_process = tsk;
 	tsk->session = 1;
 	tsk->pgrp = 1;
 	strcpy(tsk->comm, "kswapd");
@@ -484,16 +485,18 @@
 		 * the processes needing more memory will wake us
 		 * up on a more timely basis.
 		 */
-		do {
-			if (nr_free_pages >= freepages.high)
-				break;
-
-			if (!do_try_to_free_pages(GFP_KSWAPD))
-				break;
-		} while (!tsk->need_resched);
-		run_task_queue(&tq_disk);
-		tsk->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(HZ);
+		interruptible_sleep_on_timeout(&kswapd_wait, HZ);
+		while (nr_free_pages < freepages.high)
+		{
+			if (do_try_to_free_pages(GFP_KSWAPD))
+			{
+				if (tsk->need_resched)
+					schedule();
+				continue;
+			}
+			tsk->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(10*HZ);
+		}
 	}
 }
 
@@ -516,7 +519,7 @@
 {
 	int retval = 1;
 
-	wake_up_process(kswapd_process);
+	wake_up_interruptible(&kswapd_wait);
 	if (gfp_mask & __GFP_WAIT)
 		retval = do_try_to_free_pages(gfp_mask);
 	return retval;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/802/fc.c linux.14p16/net/802/fc.c
--- linux.vanilla/net/802/fc.c	Sat Aug 28 20:00:59 1999
+++ linux.14p16/net/802/fc.c	Thu Dec  9 15:33:13 1999
@@ -90,7 +90,10 @@
 		printk("fc_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons(fcllc->ethertype));
 		return 0;
 	}
-
+#ifdef CONFIG_INET
 	return arp_find(fch->daddr, skb);
+#else
+	return 0; /* Cannot happen because of ETH_P_IP test */
+#endif	
 }
 	
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/Config.in linux.14p16/net/Config.in
--- linux.vanilla/net/Config.in	Thu Feb 25 18:46:47 1999
+++ linux.14p16/net/Config.in	Wed Dec 15 16:37:40 1999
@@ -39,6 +39,9 @@
   tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
   tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
   bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE
+  if [ "$CONFIG_BRIDGE" != "n" ]; then
+	int '  Maximum number of bridged interfaces' CONFIG_BRIDGE_NUM_PORTS 8
+  fi
   bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC
 #  if [ "$CONFIG_LLC" = "y" ]; then
 #   bool 'Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ax25/af_ax25.c linux.14p16/net/ax25/af_ax25.c
--- linux.vanilla/net/ax25/af_ax25.c	Wed Oct 20 01:12:52 1999
+++ linux.14p16/net/ax25/af_ax25.c	Mon Dec 13 18:35:05 1999
@@ -1266,8 +1266,6 @@
 	newsk->sleep = &newsock->wait;
 
 	/* Now attach up the new socket */
-	skb->sk = NULL;
-	skb->destructor = NULL;
 	kfree_skb(skb);
 	sk->ack_backlog--;
 	newsock->sk    = newsk;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ax25/ax25_ds_subr.c linux.14p16/net/ax25/ax25_ds_subr.c
--- linux.vanilla/net/ax25/ax25_ds_subr.c	Mon Jan 12 23:28:19 1998
+++ linux.14p16/net/ax25/ax25_ds_subr.c	Thu Dec  9 15:33:14 1999
@@ -150,6 +150,7 @@
 	if ((skb = alloc_skb(2, GFP_ATOMIC)) == NULL)
 		return;
 
+	skb->nh.raw = skb->data;
 	p = skb_put(skb, 2);
 
 	*p++ = cmd;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ax25/ax25_in.c linux.14p16/net/ax25/ax25_in.c
--- linux.vanilla/net/ax25/ax25_in.c	Fri Dec 18 21:56:21 1998
+++ linux.14p16/net/ax25/ax25_in.c	Thu Dec  9 15:33:14 1999
@@ -93,6 +93,7 @@
 
 					skbn->dev   = ax25->ax25_dev->dev;
 					skbn->h.raw = skbn->data;
+					skbn->nh.raw = skbn->data;
 
 					/* Copy data from the fragments */
 					while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ax25/ax25_ip.c linux.14p16/net/ax25/ax25_ip.c
--- linux.vanilla/net/ax25/ax25_ip.c	Fri Nov 13 18:29:43 1998
+++ linux.14p16/net/ax25/ax25_ip.c	Thu Dec  9 15:33:14 1999
@@ -161,6 +161,7 @@
 			dst_c = *dst;
 
 			skb_pull(ourskb, AX25_HEADER_LEN - 1);	/* Keep PID */
+			skb->nh.raw = skb->data;
 
 			ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c, 
 &dst_c, route->digipeat, dev);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ax25/ax25_out.c linux.14p16/net/ax25/ax25_out.c
--- linux.vanilla/net/ax25/ax25_out.c	Fri Dec 18 21:56:21 1998
+++ linux.14p16/net/ax25/ax25_out.c	Thu Dec  9 15:33:14 1999
@@ -174,7 +174,7 @@
 
 			if (ka9qfrag == 1) {
 				skb_reserve(skbn, frontlen + 2);
-
+				skbn->nh.raw = skbn->data + (skb->nh.raw - skb->data);
 				memcpy(skb_put(skbn, len), skb->data, len);
 				p = skb_push(skbn, 2);
 
@@ -187,6 +187,7 @@
 				}
 			} else {
 				skb_reserve(skbn, frontlen + 1);
+				skbn->nh.raw = skbn->data + (skb->nh.raw - skb->data);
 				memcpy(skb_put(skbn, len), skb->data, len);
 				p = skb_push(skbn, 1);
 				*p = AX25_P_TEXT;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ax25/ax25_subr.c linux.14p16/net/ax25/ax25_subr.c
--- linux.vanilla/net/ax25/ax25_subr.c	Wed Jul 22 21:45:58 1998
+++ linux.14p16/net/ax25/ax25_subr.c	Thu Dec  9 15:33:14 1999
@@ -240,7 +240,8 @@
 		return;	/* Next SABM will get DM'd */
 
 	skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(digi));
-
+	skb->nh.raw = skb->data;
+	
 	ax25_digi_invert(digi, &retdigi);
 
 	dptr = skb_put(skb, 1);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/bridge/br.c linux.14p16/net/bridge/br.c
--- linux.vanilla/net/bridge/br.c	Sat Aug 14 02:27:41 1999
+++ linux.14p16/net/bridge/br.c	Mon Dec 13 20:29:37 1999
@@ -40,10 +40,19 @@
  *			so blame me first if its broken ;)
  *
  *	Robert Pintarelli:	fixed bug in bpdu time values
+ *
+ *      Matthew Grant:  start ports disabled.  
+ *                      auto-promiscuous mode on port enable/disable
+ *                      fleshed out interface event handling, interfaces 
+ *                        now register with bridge on module load as well as ifup
+ *                      port control ioctls with ifindex support
+ *                      brg0 logical ethernet interface
+ *                      reworked brcfg to take interface arguments
+ *                      added support for changing the hardware address
+ *                      generally made bridge a lot more usable.
  *	
  *	Todo:
- *		Don't bring up devices automatically. Start ports disabled
- *	and use a netlink notifier so a daemon can maintain the bridge
+ *	Use a netlink notifier so a daemon can maintain the bridge
  *	port group (could we also do multiple groups ????).
  *		A nice /proc file interface.
  *		Put the path costs in the port info and devices.
@@ -53,6 +62,7 @@
  */
  
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -61,10 +71,13 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
+#include <linux/malloc.h>
 #include <linux/string.h>
 #include <linux/net.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/ip.h>
@@ -72,6 +85,7 @@
 #include <linux/init.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <linux/rtnetlink.h>
 #include <net/br.h>
 #include <linux/proc_fs.h>
 
@@ -145,11 +159,20 @@
 static int br_flood(struct sk_buff *skb, int port);
 static int br_drop(struct sk_buff *skb);
 static int br_learn(struct sk_buff *skb, int port);	/* 3.8 */
+static int br_protocol_ok(unsigned short protocol);
+static int br_find_port(int ifindex);
+static void br_get_ifnames(void);
+static int brg_rx(struct sk_buff *skb, int port);
 
 static unsigned char bridge_ula[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
 static Bridge_data     bridge_info;			  /* (4.5.3)	 */
 Port_data       port_info[All_ports];		  /* (4.5.5)	 */
 
+/* MAG: Maximum port registered - used to speed up flooding and to make
+ * have a large ports array more efficient
+ */
+static int max_port_used = 0; 
+
 /* JRP: fdb cache 1/port save kmalloc/kfree on every frame */
 struct fdb	*newfdb[All_ports];
 int allocated_fdb_cnt = 0;
@@ -190,6 +213,30 @@
 	0
 };
 
+
+/* 
+ * the following data is for the bridge network device
+ */
+struct brg_if {
+  struct device dev;
+  char name[IFNAMSIZ];
+};
+static struct brg_if brg_if;
+
+/* 
+ * Here to save linkage? problems
+ */
+
+static inline int find_port(struct device *dev)
+{
+	int i;
+
+	for (i = One; i <= No_of_ports; i++)
+		if (port_info[i].dev == dev)
+			return(i);
+	return(0);
+}
+
 /*
  * Implementation of Protocol specific bridging
  *
@@ -202,7 +249,7 @@
 
 /* Checks if that protocol type is to be bridged */
 
-int br_protocol_ok(unsigned short protocol)
+static int inline br_protocol_ok(unsigned short protocol)
 {
 	unsigned x;
 	
@@ -843,8 +890,14 @@
 {						  /* (4.8.1)	 */
 	int port_no;
 
-	printk(KERN_INFO "NET4: Ethernet Bridge 005 for NET4.0\n");
+	printk(KERN_INFO "NET4: Ethernet Bridge 007 for NET4.0\n");
+
+	/* Set up brg device information */
+	bridge_info.instance = 0;
+	brg_init();
 
+	max_port_used = 0;
+	
 	/*
 	 * Form initial topology change time.
 	 * The topology change timer is only used if this is the root bridge.
@@ -874,8 +927,8 @@
 	stop_topology_change_timer();
 	memset(newfdb, 0, sizeof(newfdb));
 	for (port_no = One; port_no <= No_of_ports; port_no++) {	/* (4.8.1.4) */
-		/* initial state = Enable */
-		user_port_state[port_no] = ~Disabled;
+		/* initial state = Disable */
+		user_port_state[port_no] = Disabled;
 		port_priority[port_no] = 128;
 		br_init_port(port_no);
 		disable_port(port_no);
@@ -1205,7 +1258,7 @@
   	memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
  
   	if (br_stats.flags & BR_DEBUG)
- 		printk("send_%s_bpdu: port %i src %02x:%02x:%02x:%02x:%02x:%02x\n",
+ 		printk(KERN_DEBUG "send_%s_bpdu: port %i src %02x:%02x:%02x:%02x:%02x:%02x\n",
  			pdu_name,
   			port_no,
   			eth->h_source[0],
@@ -1306,6 +1359,9 @@
 	if (dev->flags & IFF_LOOPBACK)
 		return(NOTIFY_DONE);
 
+	if (dev == &brg_if.dev)
+	  return(NOTIFY_DONE);	/* Don't attach the brg device to a port! */
+	
 	switch (event) 
 	{
 		case NETDEV_DOWN:
@@ -1335,6 +1391,9 @@
 				{
 					port_info[i].dev = dev;
 					port_info[i].port_id = i;
+					dev->bridge_port_id = i;
+					if( i > max_port_used ) 
+						max_port_used = i;
 					/* set bridge addr from 1st device addr */
 					if (((htonl(bridge_info.bridge_id.BRIDGE_ID[0])&0xffff) == 0) &&
 						(bridge_info.bridge_id.BRIDGE_ID[1] == 0)) 
@@ -1344,7 +1403,10 @@
 							bridge_info.bridge_id.BRIDGE_PRIORITY = htons(32768);
 						set_bridge_priority(&bridge_info.bridge_id);
 					}
+					/* Add local MAC address */
 					br_add_local_mac(dev->dev_addr);
+					/* Save MAC address for latter change address events */
+					memcpy(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6);
 					if((br_stats.flags & BR_UP) &&
 				   		(user_port_state[i] != Disabled)) 
 				   	{
@@ -1362,19 +1424,122 @@
 				}
 			}
 			break;
+	        case NETDEV_REGISTER:
+		        if (br_stats.flags & BR_DEBUG) 
+				printk(KERN_DEBUG "br_device_event: NETDEV_REGISTER...\n");
+			/* printk(KERN_ERR "br_device_event: NETDEV_REGISTER...\n"); */
+			/* printk(KERN_ERR "br_device_event: dev->type: 0x%X\n", dev->type); */
+			/* Only handle ethernet ports */
+			if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_LOOPBACK)
+				return NOTIFY_DONE;
+			/* printk(KERN_ERR "br_device_event: Looking for port...\n"); */
+			for (i = One; i <= No_of_ports; i++) 
+			{
+				if (port_info[i].dev == NULL || port_info[i].dev == dev) 
+				{
+				        /* printk(KERN_ERR "br_device_event: Found port %d\n", i); */
+					port_info[i].dev = dev;
+					port_info[i].port_id = i;
+					dev->bridge_port_id = i;
+					if( i > max_port_used )
+						max_port_used = i;
+					/* handle local MAC address minuplations */
+					br_add_local_mac(dev->dev_addr);
+					memcpy(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6);
+					return NOTIFY_DONE;
+					break;
+				}
+			}
+			break;
 		case NETDEV_UNREGISTER:
 			if (br_stats.flags & BR_DEBUG)
 				printk(KERN_DEBUG "br_device_event: NETDEV_UNREGISTER...\n");
                         i = find_port(dev);
                         if (i > 0) {
 				br_avl_delete_by_port(i);
+				memset(port_info[i].ifmac.BRIDGE_ID_ULA, 0, 6);
 				port_info[i].dev = NULL;
 			}
 			break;
+		case NETDEV_CHANGEADDR:
+			if (br_stats.flags & BR_DEBUG)
+				printk(KERN_DEBUG "br_device_event: NETDEV_CHANGEADDR...\n");
+                        i = find_port(dev);
+                        if (i <= 0)  
+			  break;
+			if (memcmp(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6) != 0)
+			  break; /* Don't worry about a change of hardware broadcast address! */
+			if (dev->start) {
+			  printk(KERN_CRIT "br_device_event: NETDEV_CHANGEADDR on busy device %s - FIX DRIVER!\n", 
+				 dev->name);
+			/*  return NOTIFY_BAD;  It SHOULD be this, but I want to be friendly... */
+			  return NOTIFY_DONE;
+			}
+			br_avl_delete_by_port(i);
+			memset(port_info[i].ifmac.BRIDGE_ID_ULA, 0, 6);
+			break;
 	}
 	return NOTIFY_DONE;
 }
 
+/* Routine to loop over device list and register 
+ * interfaces to bridge.  Called from last part of net_dev_init just before
+ * bootp/rarp interface setup
+ */
+void br_spacedevice_register(void) 
+{
+	struct device *dev;
+	for( dev = dev_base; dev != NULL; dev = dev->next)
+	{
+		br_device_event(NULL, NETDEV_REGISTER, dev);
+	}
+}	
+
+
+/* This is for SPEED in the kernel in net_bh.c */
+
+int br_call_bridge(struct sk_buff *skb, unsigned short type)
+{
+	int port;
+	struct device *dev;
+  
+#if 0  /* Checked first in handle_bridge to save expense of function call */ 
+	if(!(br_stats.flags & BR_UP))
+		return 0;
+#endif
+  
+	dev = skb->dev;
+
+	/* Check for brg0 device
+	 */
+	if (dev == &brg_if.dev)
+		return 0;
+		 
+	port = dev->bridge_port_id;
+
+	if(!port)
+		return 0;
+
+	/* Sanity - make sure we are not leaping off into fairy space! */
+	if ( port < 0 || port > max_port_used || port_info[port].dev != dev) {
+		if (net_ratelimit())
+			printk(KERN_CRIT "br_call_bridge: device %s has invalid port ID %d!\n",
+				dev->name,
+				dev->bridge_port_id);
+		return 0;
+	}
+
+	if(user_port_state[port] == Disabled)
+		return 0;
+  
+	if (!br_protocol_ok(ntohs(type)))
+		return 0;
+
+	return 1;
+
+}
+
+
 /*
  * following routine is called when a frame is received
  * from an interface, it returns 1 when it consumes the
@@ -1383,9 +1548,10 @@
 
 int br_receive_frame(struct sk_buff *skb)	/* 3.5 */
 {
-	int port;
+	int port, ret;
 	Port_data  *p;
 	struct ethhdr *eth;
+	struct device *dev;
 	
 	/* sanity */
 	if (!skb) {
@@ -1393,17 +1559,32 @@
 		return(1);
 	}
 
+	dev = skb->dev;
+
+	/* Check for brg0 device 
+	 */
+	if (dev == &brg_if.dev)
+		return 0;
+
 	skb->pkt_bridged = IS_BRIDGED;
 
 	/* check for loopback */
-	if (skb->dev->flags & IFF_LOOPBACK)
+	if (dev->flags & IFF_LOOPBACK)
 		return 0 ;
 
-	port = find_port(skb->dev);
+#if 0
+	port = find_port(dev);
+#else
+	port = dev->bridge_port_id;
+#endif
 	
 	if(!port)
 		return 0;
 	
+	/* Hand off to brg_rx BEFORE we screw up the skb */
+	if(brg_rx(skb, port))
+	  return(1);
+
 	skb->nh.raw = skb->mac.raw;
 	eth = skb->mac.ethernet;
 	p = &port_info[port];
@@ -1435,9 +1616,9 @@
 	switch (p->state) 
 	{
 		case Learning:
-			if(br_learn(skb, port)) 
+			if((ret = br_learn(skb, port))) 
 			{	/* 3.8 */
-				++br_stats_cnt.drop_multicast;
+				if (ret > 0) ++br_stats_cnt.drop_multicast;
 				return br_drop(skb);
 			}
 			/* fall through */
@@ -1452,8 +1633,8 @@
 		 */
 			break;
 		case Forwarding:
-			if(br_learn(skb, port)) {	/* 3.8 */
-				++br_stats_cnt.drop_multicast;
+			if((ret = br_learn(skb, port))) {	/* 3.8 */
+				if (ret > 0) ++br_stats_cnt.drop_multicast;
 				return br_drop(skb);
 			}
 			/* Now this frame came from one of bridged
@@ -1512,7 +1693,7 @@
 	eth = skb->mac.ethernet;
 	port = 0;	/* an impossible port (locally generated) */	
 	if (br_stats.flags & BR_DEBUG)
-		printk("br_tx_fr : port %i src %02x:%02x:%02x:%02x:%02x:%02x"
+		printk(KERN_DEBUG "br_tx_fr : port %i src %02x:%02x:%02x:%02x:%02x:%02x"
 	  		" dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
 			port,
 			eth->h_source[0],
@@ -1577,7 +1758,11 @@
 
 /*
  * this routine returns 0 when it learns (or updates) from the
- * frame, and 1 if we must dropped the frame.
+ * frame, and 1 if we must dropped the frame due to multicast
+ * limitations, or -1 because of not enough memory.
+ *
+ * NB Can be called when skb->nh.raw is NOT set up when
+ * receiving frames on brg0 via brg_rx
  */
 
 static int br_learn(struct sk_buff *skb, int port)	/* 3.8 */
@@ -1600,8 +1785,8 @@
 		newfdb[port] = f = (struct fdb *)kmalloc(sizeof(struct fdb), GFP_ATOMIC);
 		if (!f) 
 		{
-			printk(KERN_DEBUG "br_learn: unable to malloc fdb\n");
-			return(-1); /* this drop the frame */
+			printk(KERN_WARNING "br_learn: unable to malloc fdb\n");
+			return(-1); /* this drops the frame */
 		}
 	}
 	f->port = port;	/* source port */
@@ -1750,7 +1935,7 @@
 				/* timer expired, invalidate entry */
 				f->flags &= ~FDB_ENT_VALID;
 				if (br_stats.flags & BR_DEBUG)
-					printk("fdb entry expired...\n");
+					printk(KERN_DEBUG "fdb entry expired...\n");
 				/*
 				 *	Send flood and drop original
 				 */
@@ -1792,7 +1977,7 @@
 				/* timer expired, invalidate entry */
 				f->flags &= ~FDB_ENT_VALID;
 				if (br_stats.flags & BR_DEBUG)
-					printk("fdb entry expired...\n");
+					printk(KERN_DEBUG "fdb entry expired...\n");
 				++br_stats_cnt.drop_same_port_aged;
 			}
 			else ++br_stats_cnt.drop_same_port;
@@ -1819,6 +2004,9 @@
 	{
 		if (i == port)	/* don't send back where we got it */
 			continue;
+		if (i > max_port_used)
+			/* Don't go scanning empty port entries */
+			break;
 		if (port_info[i].state == Forwarding) 
 		{
 			nskb = skb_clone(skb, GFP_ATOMIC);
@@ -1831,7 +2019,7 @@
 			/* To get here we must have done ARP already,
 			   or have a received valid MAC header */
 			
-/*			printk("Flood to port %d\n",i);*/
+/*			printk(KERN_DEBUG "Flood to port %d\n",i);*/
 			nskb->nh.raw = nskb->data + ETH_HLEN;
 			nskb->priority = 1;
 			dev_queue_xmit(nskb);
@@ -1840,16 +2028,6 @@
 	return(0);
 }
 
-static int find_port(struct device *dev)
-{
-	int i;
-
-	for (i = One; i <= No_of_ports; i++)
-		if (port_info[i].dev == dev)
-			return(i);
-	return(0);
-}
-
 /*
  *	FIXME: This needs to come from the device structs, eg for
  *	10,100,1Gbit ethernet.
@@ -1956,17 +2134,62 @@
 	return fdbis;
 }
 
+
+/* Fill in interface names in port_info structure
+ */
+static void br_get_ifdata(void) {
+	int i;
+
+  	for(i=One;i<=No_of_ports; i++) {
+
+		port_info[i].admin_state = user_port_state[i]; 
+		
+		/* memset IS needed.  Kernel strncpy does NOT NULL terminate 
+		 * strings when limit reached 
+	 	 */
+		memset(port_info[i].ifname, 0, IFNAMSIZ); 
+		if( port_info[i].dev == 0 )
+			continue;
+		strncpy(port_info[i].ifname, port_info[i].dev->name, IFNAMSIZ-1);
+		/* Being paranoid */
+		port_info[i].ifname[IFNAMSIZ-1] = '\0';
+	}
+}
+
+/* Given an interface index, loop over port array to see if configured.  If
+   so, return port number, otherwise error */ 
+static int br_find_port(int ifindex) 
+{
+  int i;
+  
+  for(i=1; i <= No_of_ports; i++) {
+    if (port_info[i].dev == 0)
+      continue;
+    if (port_info[i].dev->ifindex == ifindex)
+      return(i);
+  }
+  
+  return -EUNATCH;  /* Tell me if this is incorrect error code for this case */
+} 
+
+
 int br_ioctl(unsigned int cmd, void *arg)
 {
-	int err, i;
+	int err, i, ifflags;
 	struct br_cf bcf;
 	bridge_id_t new_id;
-
+	struct device *dev;
+	
 	switch(cmd)
 	{
 		case SIOCGIFBR:	/* get bridging control blocks */
 			memcpy(&br_stats.bridge_data, &bridge_info, sizeof(Bridge_data));
-			memcpy(&br_stats.port_data, &port_info, sizeof(Port_data)*No_of_ports);
+
+			/* Fill in interface names in port_info*/
+			br_get_ifdata();
+			
+			br_stats.num_ports = No_of_ports;
+			memcpy(&br_stats.port_data, &port_info, sizeof(Port_data)*All_ports);
 
 			err = copy_to_user(arg, &br_stats, sizeof(struct br_stat));
 			if (err)
@@ -2032,16 +2255,28 @@
 					}
 					br_stats.flags ^= BR_STP_DISABLED;
 					break;
+			        case BRCMD_IF_ENABLE:
+				        bcf.arg1 = br_find_port(bcf.arg1);
+					if (bcf.arg1 < 0)
+						return(bcf.arg1);
 				case BRCMD_PORT_ENABLE:
 					if (port_info[bcf.arg1].dev == 0)
 						return(-EINVAL);
 					if (user_port_state[bcf.arg1] != Disabled)
 						return(-EALREADY);
 					printk(KERN_DEBUG "br: enabling port %i\n",bcf.arg1);
+					dev = port_info[bcf.arg1].dev;
+					ifflags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI))
+					  |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI)); 
+					dev_change_flags(dev, ifflags|IFF_PROMISC);
 					user_port_state[bcf.arg1] = ~Disabled;
 					if(br_stats.flags & BR_UP)
 						enable_port(bcf.arg1);
 					break;
+			        case BRCMD_IF_DISABLE:
+				        bcf.arg1 = br_find_port(bcf.arg1);
+					if (bcf.arg1 < 0)
+						return(bcf.arg1);
 				case BRCMD_PORT_DISABLE:
 					if (port_info[bcf.arg1].dev == 0)
 						return(-EINVAL);
@@ -2051,12 +2286,20 @@
 					user_port_state[bcf.arg1] = Disabled;
 					if(br_stats.flags & BR_UP)
 						disable_port(bcf.arg1);
+					dev = port_info[bcf.arg1].dev;
+					ifflags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI))
+					  |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI)); 
+					dev_change_flags(port_info[bcf.arg1].dev, ifflags & ~IFF_PROMISC);
 					break;
 				case BRCMD_SET_BRIDGE_PRIORITY:
 					new_id = bridge_info.bridge_id;
 					new_id.BRIDGE_PRIORITY = htons(bcf.arg1);
 					set_bridge_priority(&new_id);
 					break;
+			        case BRCMD_SET_IF_PRIORITY:
+				        bcf.arg1 = br_find_port(bcf.arg1);
+					if (bcf.arg1 < 0)
+						return(bcf.arg1);
 				case BRCMD_SET_PORT_PRIORITY:
 					if((port_info[bcf.arg1].dev == 0)
 					    || (bcf.arg2 & ~0xff))
@@ -2064,6 +2307,10 @@
 					port_priority[bcf.arg1] = bcf.arg2;
 					set_port_priority(bcf.arg1);
 					break;
+			        case BRCMD_SET_IF_PATH_COST:
+				        bcf.arg1 = br_find_port(bcf.arg1);
+					if (bcf.arg1 < 0)
+						return(bcf.arg1);
 				case BRCMD_SET_PATH_COST:
 					if (port_info[bcf.arg1].dev == 0)
 						return(-EINVAL);
@@ -2145,3 +2392,385 @@
 	}
 	return(0);
 }
+
+
+
+
+/* --------------------------------------------------------------------------------
+ *
+ *
+ *  Bridge network device here for future modularization - device structures
+ *  must be 'static' inside bridge instance
+ *  Modelled after sch_teql.c
+ * 
+ */
+
+
+
+/*
+ *	Index to functions.
+ */
+
+int	    brg_probe(struct device *dev);
+static int  brg_open(struct device *dev);
+static int  brg_start_xmit(struct sk_buff *skb, struct device *dev);
+static int  brg_close(struct device *dev);
+static struct net_device_stats *brg_get_stats(struct device *dev);
+static void brg_set_multicast_list(struct device *dev);
+
+/*
+ *	Board-specific info in dev->priv.
+ */
+
+struct net_local
+{
+	__u32		groups;
+	struct net_device_stats stats;
+};
+
+
+
+
+/*
+ *	To call this a probe is a bit misleading, however for real
+ *	hardware it would have to check what was present.
+ */
+ 
+__initfunc(int brg_probe(struct device *dev))
+{
+  unsigned int bogomips;
+  struct timeval utime;
+
+  printk(KERN_INFO "%s: network interface for Ethernet Bridge 007/NET4.0\n", dev->name);
+
+  /*
+   *	Initialize the device structure.
+   */
+  
+  dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+  if (dev->priv == NULL)
+    return -ENOMEM;
+  memset(dev->priv, 0, sizeof(struct net_local));
+
+  /* Set up MAC address based on BogoMIPs figure for first CPU and time
+   */ 
+  bogomips = (boot_cpu_data.loops_per_sec+2500)/500000 ;
+  get_fast_time(&utime);
+
+  /* Ummmm....  YES! */
+  dev->dev_addr[0] = '\xFE';
+  dev->dev_addr[1] = '\xFD';
+  dev->dev_addr[2] = (bridge_info.instance & 0x0F) << 4;
+  dev->dev_addr[2] |= ((utime.tv_sec & 0x000F0000) >> 16);
+  dev->dev_addr[3] = bogomips & 0xFF;
+  dev->dev_addr[4] = (utime.tv_sec & 0x0000FF00) >> 8;
+  dev->dev_addr[5] = (utime.tv_sec & 0x000000FF);
+  
+  printk(KERN_INFO "%s: generated MAC address %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", 
+	 dev->name,
+	 dev->dev_addr[0],
+	 dev->dev_addr[1],
+	 dev->dev_addr[2],
+	 dev->dev_addr[3],
+	 dev->dev_addr[4],
+	 dev->dev_addr[5]);
+
+  
+  printk(KERN_INFO "%s: attached to bridge instance %lu\n", dev->name, dev->base_addr);
+
+  /*
+   *	The brg specific entries in the device structure.
+   */
+
+  dev->open = brg_open;
+  dev->hard_start_xmit = brg_start_xmit;
+  dev->stop = brg_close;
+  dev->get_stats = brg_get_stats;
+  dev->set_multicast_list = brg_set_multicast_list;
+
+  /*
+   *	Setup the generic properties
+   */
+
+  ether_setup(dev);
+
+  dev->tx_queue_len = 0;
+
+  return 0;
+}
+
+/*
+ *	Open/initialize the board.
+ */
+
+static int brg_open(struct device *dev)
+{
+        if (br_stats.flags & BR_DEBUG)
+		printk(KERN_DEBUG "%s: Doing brg_open()...", dev->name);
+
+	if (memcmp(dev->dev_addr, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
+	  return -EFAULT;
+
+	dev->start = 1;
+	dev->tbusy = 0;
+	return 0;
+}
+
+static unsigned brg_mc_hash(__u8 *dest)
+{
+	unsigned idx = 0;
+	idx ^= dest[0];
+	idx ^= dest[1];
+	idx ^= dest[2];
+	idx ^= dest[3];
+	idx ^= dest[4];
+	idx ^= dest[5];
+	return 1U << (idx&0x1F);
+}
+
+static void brg_set_multicast_list(struct device *dev)
+{
+	unsigned groups = ~0;
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) {
+		struct dev_mc_list *dmi;
+
+		groups = brg_mc_hash(dev->broadcast);
+
+		for (dmi=dev->mc_list; dmi; dmi=dmi->next) {
+			if (dmi->dmi_addrlen != 6)
+				continue;
+			groups |= brg_mc_hash(dmi->dmi_addr);
+		}
+	}
+	lp->groups = groups;
+}
+
+/*
+ *	We transmit by throwing the packet at the bridge.
+ */
+ 
+static int brg_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	struct ethhdr *eth = (struct ethhdr*)skb->data;
+	int port;
+
+	/* Deal with the bridge being disabled */
+	if(!(br_stats.flags & BR_UP)) {
+		/* Either this */
+		/* lp->stats.tx_errors++; */ /* this condition is NOT an error */
+		/* or this  (implied by RFC 2233) */
+		lp->stats.tx_dropped++;
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	lp->stats.tx_bytes+=skb->len;
+	lp->stats.tx_packets++;
+
+#if 0
+	++br_stats_cnt.port_not_disable;
+#endif
+	skb->mac.raw = skb->nh.raw = skb->data;
+	eth = skb->mac.ethernet;
+	port = 0;	/* an impossible port (locally generated) */	
+
+	 if (br_stats.flags & BR_DEBUG)
+		printk(KERN_DEBUG "%s: brg_start_xmit - src %02x:%02x:%02x:%02x:%02x:%02x"
+	  		" dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
+		       dev->name,
+		       eth->h_source[0],
+		       eth->h_source[1],
+		       eth->h_source[2],
+		       eth->h_source[3],
+		       eth->h_source[4],
+		       eth->h_source[5],
+		       eth->h_dest[0],
+		       eth->h_dest[1],
+		       eth->h_dest[2],
+		       eth->h_dest[3],
+		       eth->h_dest[4],
+		       eth->h_dest[5]);
+	
+	/* Forward the packet ! */
+	if(br_forward(skb, port))
+	  return(0);
+    
+	/* Throw packet initially */
+	dev_kfree_skb(skb);
+	return 0;
+}
+
+
+/*
+ *	The typical workload of the driver:
+ *	Handle the ether interface interrupts.
+ *
+ *	(In this case handle the packets posted from the bridge)
+ */
+
+static int brg_rx(struct sk_buff *skb, int port)
+{
+        struct device *dev = &brg_if.dev;
+	struct net_local *lp = (struct net_local *)dev->priv;
+	struct ethhdr *eth = (struct ethhdr*)(skb->data);
+	int len = skb->len;
+	int clone = 0;
+
+	if (br_stats.flags & BR_DEBUG)
+		printk(KERN_DEBUG "%s: brg_rx()\n", dev->name);
+
+	/* Get out of here if the bridge interface is not up
+	 */
+	if(!(dev->flags & IFF_UP))
+	  return(0);
+	
+	/* Check that the port that this thing came off is in the forwarding state 
+	 * We sould only listen to the same address scope we will transmit to.
+	 */
+	if(port_info[port].state != Forwarding)
+	  return(0);
+
+	/* Is this for us? - broadcast/mulitcast/promiscuous packets need cloning,
+         * with uni-cast we eat the packet
+	 */
+	clone = 0;
+	if (dev->flags & IFF_PROMISC) {
+	  clone = 1;
+	}
+	else if (eth->h_dest[0]&1) {
+	  if (!(dev->flags&(IFF_ALLMULTI))
+	      && !(brg_mc_hash(eth->h_dest)&lp->groups))
+	    return(0);
+	  clone = 1;
+	}
+	else if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN) != 0) {
+	  return(0);
+	}
+
+	/* Clone things here - we want to be transparent before we check packet data 
+	 * integrity
+	 */
+	if(clone) {
+	  struct sk_buff *skb2 = skb;
+	  skb = skb_clone(skb2, GFP_ATOMIC);
+	  if (skb == NULL) {
+	    return(0);
+	  }
+	  
+	}
+	else {
+		/* Learn source addresses for unicast non-promiscuous 
+		 * frames for brg0
+		 */
+		if(br_learn(skb, port)) {
+			return br_drop(skb);
+		}
+	}
+
+	/* Check packet length 
+	 */
+	if (len < 16) {
+		printk(KERN_DEBUG "%s : rx len = %d\n", dev->name, len);
+		kfree_skb(skb);
+		return(!clone);
+	}
+
+	if (br_stats.flags & BR_DEBUG)
+	  printk(KERN_DEBUG "%s: brg_rx - src %02x:%02x:%02x:%02x:%02x:%02x"
+		 " dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
+		 dev->name,
+		 eth->h_source[0],
+		 eth->h_source[1],
+		 eth->h_source[2],
+		 eth->h_source[3],
+		 eth->h_source[4],
+		 eth->h_source[5],
+		 eth->h_dest[0],
+		 eth->h_dest[1],
+		 eth->h_dest[2],
+		 eth->h_dest[3],
+		 eth->h_dest[4],
+		 eth->h_dest[5]);
+
+	/* Do it */
+	skb->pkt_type = PACKET_HOST;
+	skb->dev = dev;
+	skb->protocol=eth_type_trans(skb,dev);
+	memset(skb->cb, 0, sizeof(skb->cb));
+	lp->stats.rx_packets++;
+	lp->stats.rx_bytes+=len;
+	netif_rx(skb);
+	return(!clone);
+}
+
+static int brg_close(struct device *dev)
+{
+	if (br_stats.flags & BR_DEBUG)
+		printk(KERN_DEBUG "%s: Shutting down.\n", dev->name);
+
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	return 0;
+}
+
+static struct net_device_stats *brg_get_stats(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	return &lp->stats;
+}
+
+/* 
+ *      
+ */
+
+__initfunc(int brg_init(void))
+{
+        int err;
+
+	memset(&brg_if, 0, sizeof(brg_if));
+
+        rtnl_lock();
+
+	brg_if.dev.base_addr = bridge_info.instance;
+	sprintf (brg_if.name, "brg%d", bridge_info.instance);
+	brg_if.dev.name = (void*)&brg_if.name;
+        if(dev_get(brg_if.name)) {
+               printk(KERN_INFO "%s already loaded.\n", brg_if.name);
+	       return -EBUSY;
+	}
+        brg_if.dev.init = brg_probe;
+
+        err = register_netdevice(&brg_if.dev);
+        rtnl_unlock();
+        return err;
+}
+
+
+#if 0				/* Its here if we ever need it... */
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+
+  /* 
+   * Unregister the device
+   */
+  rtnl_lock();
+  unregister_netdevice(&the_master.dev);
+  rtnl_unlock();
+
+  /*
+   *	Free up the private structure.
+   */
+  
+  kfree(brg_if.dev.priv);
+  brg_if.dev.priv = NULL;	/* gets re-allocated by brg_probe */
+}
+
+#endif /* MODULE */
+
+#endif
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/bridge/br_tree.c linux.14p16/net/bridge/br_tree.c
--- linux.vanilla/net/bridge/br_tree.c	Sun Mar  7 23:25:23 1999
+++ linux.14p16/net/bridge/br_tree.c	Thu Dec  9 15:33:20 1999
@@ -492,7 +492,8 @@
         port_info[port].fdb = NULL;
 
         /* remove the local mac too */
-        next = br_avl_find_addr(port_info[port].dev->dev_addr);
+/*        next = br_avl_find_addr(port_info[port].dev->dev_addr); */
+        next = br_avl_find_addr(port_info[port].ifmac.BRIDGE_ID_ULA);
         if (next != NULL)
                 br_avl_remove(next);
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/core/dev.c linux.14p16/net/core/dev.c
--- linux.vanilla/net/core/dev.c	Wed Oct 20 01:12:52 1999
+++ linux.14p16/net/core/dev.c	Thu Dec  9 15:33:15 1999
@@ -57,6 +57,8 @@
  *					A network device unload needs to purge
  *					the backlog queue.
  *	Paul Rusty Russel	:	SIOCSIFNAME
+ *	Andrea Arcangeli	:	dev_clear_backlog() needs the
+ *					skb_queue_lock held.
  */
 
 #include <asm/uaccess.h>
@@ -711,7 +713,8 @@
 
 static void dev_clear_backlog(struct device *dev)
 {
-	struct sk_buff *prev, *curr;
+	struct sk_buff *curr;
+	unsigned long flags;
 
 	/*
 	 *
@@ -719,27 +722,24 @@
 	 *
 	 *  We are competing here both with netif_rx() and net_bh().
 	 *  We don't want either of those to mess with skb ptrs
-	 *  while we work on them, thus cli()/sti().
-	 *
-	 *  It looks better to use net_bh trick, at least
-	 *  to be sure, that we keep interrupt latency really low. --ANK (980727)
+	 *  while we work on them, thus we must grab the
+	 *  skb_queue_lock.
 	 */ 
 
 	if (backlog.qlen) {
-		start_bh_atomic();
-		curr = backlog.next;
-		while ( curr != (struct sk_buff *)(&backlog) ) {
-			unsigned long flags;
-			curr=curr->next;
-			if ( curr->prev->dev == dev ) {
-				prev = curr->prev;
-				spin_lock_irqsave(&skb_queue_lock, flags);
-				__skb_unlink(prev, &backlog);
+	repeat:
+		spin_lock_irqsave(&skb_queue_lock, flags);
+		for (curr = backlog.next;
+		     curr != (struct sk_buff *)(&backlog);
+		     curr = curr->next)
+			if (curr->dev == dev)
+			{
+				__skb_unlink(curr, &backlog);
 				spin_unlock_irqrestore(&skb_queue_lock, flags);
-				kfree_skb(prev);
+				kfree_skb(curr);
+				goto repeat;
 			}
-		}
-		end_bh_atomic();
+		spin_unlock_irqrestore(&skb_queue_lock, flags);
 #ifdef CONFIG_NET_HW_FLOWCONTROL
 		if (netdev_dropping)
 			netdev_wakeup();
@@ -796,7 +796,11 @@
 #ifdef CONFIG_BRIDGE
 static inline void handle_bridge(struct sk_buff *skb, unsigned short type)
 {
-	if (br_stats.flags & BR_UP && br_protocol_ok(ntohs(type)))
+	/* 
+	 * The br_stats.flags is checked here to save the expense of a 
+	 * function call.
+	 */
+	if ((br_stats.flags & BR_UP) && br_call_bridge(skb, type))
 	{
 		/*
 		 *	We pass the bridge a complete frame. This means
@@ -820,7 +824,6 @@
 }
 #endif
 
-
 /*
  *	When we are called the queue is ready to grab, the interrupts are
  *	on and hardware can interrupt and queue to the receive queue as we
@@ -1275,8 +1278,9 @@
 	int size;
 
 	if(stats != (struct iw_statistics *) NULL)
+	{
 		size = sprintf(buffer,
-			       "%6s: %02x  %3d%c %3d%c  %3d%c %5d %5d %5d\n",
+			       "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d\n",
 			       dev->name,
 			       stats->status,
 			       stats->qual.qual,
@@ -1288,6 +1292,8 @@
 			       stats->discard.nwid,
 			       stats->discard.code,
 			       stats->discard.misc);
+		stats->qual.updated = 0;
+	}
 	else
 		size = 0;
 
@@ -1309,8 +1315,9 @@
 	struct device *	dev;
 
 	size = sprintf(buffer,
-		       "Inter-|sta|  Quality       |  Discarded packets\n"
-		       " face |tus|link level noise| nwid crypt  misc\n");
+		       "Inter-| sta-|   Quality        |   Discarded packets\n"
+		       " face | tus | link level noise |  nwid  crypt   misc\n"
+			);
 	
 	pos+=size;
 	len+=size;
@@ -1846,6 +1853,7 @@
 extern int bpq_init(void);
 extern int scc_init(void);
 extern void sdla_setup(void);
+extern void sdla_c_setup(void);
 extern void dlci_setup(void);
 extern int dmascc_init(void);
 extern int sm_init(void);
@@ -1855,6 +1863,7 @@
 extern int baycom_par_init(void);
 
 extern int lapbeth_init(void);
+extern int comx_init(void);
 extern void arcnet_init(void);
 extern void ip_auto_config(void);
 #ifdef CONFIG_8xx
@@ -1922,7 +1931,7 @@
 	dlci_setup();
 #endif
 #if defined(CONFIG_SDLA)
-	sdla_setup();
+	sdla_c_setup();
 #endif
 #if defined(CONFIG_BAYCOM_PAR)
 	baycom_par_init();
@@ -1948,6 +1957,9 @@
 #if defined(CONFIG_8xx)
         cpm_enet_init();
 #endif
+#if defined(CONFIG_COMX)
+	comx_init();
+#endif
 	/*
 	 *	SLHC if present needs attaching so other people see it
 	 *	even if not opened.
@@ -2017,6 +2029,13 @@
 	dev_boot_phase = 0;
 
 	dev_mcast_init();
+
+#ifdef CONFIG_BRIDGE
+	/*
+	 * Register any statically linked ethernet devices with the bridge
+	 */
+	br_spacedevice_register();
+#endif
 
 #ifdef CONFIG_IP_PNP
 	ip_auto_config();
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ethernet/eth.c linux.14p16/net/ethernet/eth.c
--- linux.vanilla/net/ethernet/eth.c	Mon Jan 12 23:28:25 1998
+++ linux.14p16/net/ethernet/eth.c	Thu Dec  9 15:33:17 1999
@@ -201,7 +201,7 @@
 	 *	seems to set IFF_PROMISC.
 	 */
 	 
-	else if(dev->flags&(IFF_PROMISC/*|IFF_ALLMULTI*/))
+	else if(1 /*dev->flags&IFF_PROMISC*/)
 	{
 		if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))
 			skb->pkt_type=PACKET_OTHERHOST;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/arp.c linux.14p16/net/ipv4/arp.c
--- linux.vanilla/net/ipv4/arp.c	Wed Oct 20 01:12:52 1999
+++ linux.14p16/net/ipv4/arp.c	Mon Dec 13 18:50:28 1999
@@ -1,6 +1,6 @@
 /* linux/net/inet/arp.c
  *
- * Version:	$Id: arp.c,v 1.77.2.1 1999/06/28 10:39:23 davem Exp $
+ * Version:	$Id: arp.c,v 1.77.2.4 1999/09/23 19:03:36 davem Exp $
  *
  * Copyright (C) 1994 by Florian  La Roche
  *
@@ -65,6 +65,8 @@
  *					clean up the APFDDI & gen. FDDI bits.
  *		Alexey Kuznetsov:	new arp state machine;
  *					now it is in net/core/neighbour.c.
+ *		Julian Anastasov:	"hidden" flag: hide the
+ *					interface and don't reply for it
  */
 
 /* RFC1122 Status:
@@ -308,10 +310,15 @@
 	u32 saddr;
 	u8  *dst_ha = NULL;
 	struct device *dev = neigh->dev;
+	struct device *dev2;
+	struct in_device *in_dev2;
 	u32 target = *(u32*)neigh->primary_key;
 	int probes = neigh->probes;
 
-	if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL)
+	if (skb &&
+	    (dev2 = ip_dev_find(skb->nh.iph->saddr)) != NULL &&
+	    (in_dev2 = dev2->ip_ptr) != NULL &&
+	    !IN_DEV_HIDDEN(in_dev2))
 		saddr = skb->nh.iph->saddr;
 	else
 		saddr = inet_select_addr(dev, target, RT_SCOPE_LINK);
@@ -653,8 +660,14 @@
 
 	/* Special case: IPv4 duplicate address detection packet (RFC2131) */
 	if (sip == 0) {
+		struct device *dev2;
+		struct in_device *in_dev2;
+
 		if (arp->ar_op == __constant_htons(ARPOP_REQUEST) &&
-		    inet_addr_type(tip) == RTN_LOCAL)
+		    (dev2 = ip_dev_find(tip)) != NULL &&
+		    (dev2 == dev ||
+		     ((in_dev2 = dev2->ip_ptr) != NULL &&
+		      !IN_DEV_HIDDEN(in_dev2))))
 			arp_send(ARPOP_REPLY,ETH_P_ARP,tip,dev,tip,sha,dev->dev_addr,dev->dev_addr);
 		goto out;
 	}
@@ -668,6 +681,20 @@
 		if (addr_type == RTN_LOCAL) {
 			n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
 			if (n) {
+				if (ipv4_devconf.hidden &&
+				    skb->pkt_type != PACKET_HOST) {
+					struct device *dev2;
+					struct in_device *in_dev2;
+
+					if ((dev2 = ip_dev_find(tip)) != NULL &&
+					    dev2 != dev &&
+					    (in_dev2 = dev2->ip_ptr) != NULL &&
+					    IN_DEV_HIDDEN(in_dev2)) {
+						neigh_release(n);
+						goto out;
+					}
+				}
+
 				arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
 				neigh_release(n);
 			}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/devinet.c linux.14p16/net/ipv4/devinet.c
--- linux.vanilla/net/ipv4/devinet.c	Sat Aug 14 02:27:41 1999
+++ linux.14p16/net/ipv4/devinet.c	Mon Dec 13 18:50:29 1999
@@ -658,7 +658,7 @@
 			addr = ifa->ifa_local;
 	} endfor_ifa(in_dev);
 	
-	if (addr || scope >= RT_SCOPE_LINK)
+	if (addr)
 		return addr;
 
 	/* Not loopback addresses on loopback should be preferred
@@ -670,7 +670,9 @@
 			continue;
 
 		for_primary_ifa(in_dev) {
-			if (ifa->ifa_scope <= scope)
+			if (!IN_DEV_HIDDEN(in_dev) &&
+			    ifa->ifa_scope <= scope &&
+			    ifa->ifa_scope != RT_SCOPE_LINK)
 				return ifa->ifa_local;
 		} endfor_ifa(in_dev);
 	}
@@ -923,7 +925,7 @@
 static struct devinet_sysctl_table
 {
 	struct ctl_table_header *sysctl_header;
-	ctl_table devinet_vars[12];
+	ctl_table devinet_vars[13];
 	ctl_table devinet_dev[2];
 	ctl_table devinet_conf_dir[2];
 	ctl_table devinet_proto_dir[2];
@@ -962,6 +964,9 @@
          &proc_dointvec},
         {NET_IPV4_CONF_LOG_MARTIANS, "log_martians",
          &ipv4_devconf.log_martians, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+	{NET_IPV4_CONF_HIDDEN, "hidden",
+         &ipv4_devconf.hidden, sizeof(int), 0644, NULL,
          &proc_dointvec},
 	 {0}},
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/icmp.c linux.14p16/net/ipv4/icmp.c
--- linux.vanilla/net/ipv4/icmp.c	Wed Oct 20 01:12:52 1999
+++ linux.14p16/net/ipv4/icmp.c	Thu Dec  9 15:33:17 1999
@@ -3,7 +3,7 @@
  *	
  *		Alan Cox, <alan@redhat.com>
  *
- *	Version: $Id: icmp.c,v 1.52.2.3 1999/09/22 16:33:02 davem Exp $
+ *	Version: $Id: icmp.c,v 1.52.2.4 1999/11/16 02:28:40 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/ip_forward.c linux.14p16/net/ipv4/ip_forward.c
--- linux.vanilla/net/ipv4/ip_forward.c	Sun Mar 21 15:22:00 1999
+++ linux.14p16/net/ipv4/ip_forward.c	Thu Dec  9 15:33:18 1999
@@ -5,11 +5,12 @@
  *
  *		The IP forwarding functionality.
  *		
- * Version:	$Id: ip_forward.c,v 1.43 1999/03/21 05:22:37 davem Exp $
+ * Version:	$Id: ip_forward.c,v 1.43.2.1 1999/11/16 06:33:43 davem Exp $
  *
  * Authors:	see ip.c
  *
  * Fixes:
+ *		Joseph Gooch	:	Removed maddr selection for ip_masq, now done in ip_masq.c
  *		Many		:	Split from ip.c , see ip_input.c for 
  *					history.
  *		Dave Gregorich	:	NULL ip_rt_put fix for multicast 
@@ -168,7 +169,6 @@
 		 *	and skip the firewall checks
 		 */
 		if (iph->protocol == IPPROTO_ICMP) {
-			__u32 maddr;
 #ifdef CONFIG_IP_MASQUERADE_ICMP
 			struct icmphdr *icmph = (struct icmphdr *)((char*)iph + (iph->ihl << 2));
 			if ((icmph->type==ICMP_DEST_UNREACH)||
@@ -176,8 +176,7 @@
 			    (icmph->type==ICMP_TIME_EXCEEDED))
 			{
 #endif
-				maddr = inet_select_addr(dev2, rt->rt_gateway, RT_SCOPE_UNIVERSE);
-				fw_res = ip_fw_masq_icmp(&skb, maddr);
+				fw_res = ip_fw_masquerade(&skb, 0);
 			        if (fw_res < 0) {
 					kfree_skb(skb);
 					return -1;
@@ -187,7 +186,7 @@
 					/* ICMP matched - skip firewall */
 					goto skip_call_fw_firewall;
 #ifdef CONFIG_IP_MASQUERADE_ICMP
-			       }
+			}
 #endif				
 		}
 		if (rt->rt_flags&RTCF_MASQ)
@@ -219,15 +218,11 @@
 	 */
 	if (!(IPCB(skb)->flags&IPSKB_MASQUERADED) &&
 	    (fw_res==FW_MASQUERADE || rt->rt_flags&RTCF_MASQ)) {
-		u32 maddr;
+		u32 maddr = 0;
 
 #ifdef CONFIG_IP_ROUTE_NAT
 		maddr = (rt->rt_flags&RTCF_MASQ) ? rt->rt_src_map : 0;
-
-		if (maddr == 0)
 #endif
-			maddr = inet_select_addr(dev2, rt->rt_gateway, RT_SCOPE_UNIVERSE);
-
 			if (ip_fw_masquerade(&skb, maddr) < 0) {
 				kfree_skb(skb);
 				return -1;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/ip_fw.c linux.14p16/net/ipv4/ip_fw.c
--- linux.vanilla/net/ipv4/ip_fw.c	Wed Oct 20 01:12:52 1999
+++ linux.14p16/net/ipv4/ip_fw.c	Thu Dec  9 15:33:17 1999
@@ -40,11 +40,12 @@
  * 23-Jul-1999: Fixed small fragment security exposure opened on 15-May-1998.
  *              John McDonald <jm@dataprotect.com>
  *              Thomas Lopatic <tl@dataprotect.com>
+ * 21-Oct-1999: Applied count fix by Emanuele Caratti <wiz@iol.it> --RR
  */
 
 /*
  *
- * The origina Linux port was done Alan Cox, with changes/fixes from
+ * The original Linux port was done Alan Cox, with changes/fixes from
  * Pauline Middlelink, Jos Vos, Thomas Quinot, Wouter Gadeyne, Juan
  * Jose Ciarlante, Bernd Eckenfels, Keith Owens and others.
  * 
@@ -86,6 +87,7 @@
 #include <net/udp.h>
 #include <net/sock.h>
 #include <net/icmp.h>
+#include <net/ip_masq.h>
 #include <linux/netlink.h>
 #include <linux/init.h>
 #include <linux/firewall.h>
@@ -228,6 +230,7 @@
 {
 	struct ip_chain *prevchain;	/* Pointer to referencing chain */
 	struct ip_fwkernel *prevrule;	/* Pointer to referencing rule */
+	unsigned int count;
 	struct ip_counters counters;
 };
 
@@ -488,7 +491,10 @@
                 static int enabled = 0;
 
                 if(!enabled)
+                {
+                	enabled=1;
                         sysctl_ip_always_defrag++;
+                }
 		*answer = FW_REDIRECT;
 		return 1;
 #endif
@@ -729,8 +735,8 @@
 	else FWC_HAVE_LOCK(fwc_rlocks);
 
 	f = chain->chain;
+	count = 0;
 	do {
-		count = 0;
 		for (; f; f = f->next) {
 			count++;
 			if (ip_rule_match(f,rif,ip,
@@ -768,10 +774,12 @@
 				else {
 					f->branch->reent[slot].prevchain 
 						= chain;
+					f->branch->reent[slot].count = count;
 					f->branch->reent[slot].prevrule 
 						= f->next;
 					chain = f->branch;
 					f = chain->chain;
+					count = 0;
 				}
 			}
 			else if (f->simplebranch == FW_SKIP) 
@@ -790,6 +798,7 @@
 			if (chain->reent[slot].prevchain) {
 				struct ip_chain *tmp = chain;
 				f = chain->reent[slot].prevrule;
+				count = chain->reent[slot].count;
 				chain = chain->reent[slot].prevchain;
 				tmp->reent[slot].prevchain = NULL;
 			}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/ip_input.c linux.14p16/net/ipv4/ip_input.c
--- linux.vanilla/net/ipv4/ip_input.c	Wed Oct 20 01:12:52 1999
+++ linux.14p16/net/ipv4/ip_input.c	Thu Dec  9 15:33:18 1999
@@ -97,6 +97,7 @@
  *		Alan Cox	:	Multicast routing hooks
  *		Jos Vos		:	Do accounting *before* call_in_firewall
  *	Willy Konynenberg	:	Transparent proxying support
+ *             Stephan Uphoff   :       Check IP header length field
  *
  *  
  *
@@ -421,12 +422,19 @@
 
 	if (skb->len < sizeof(struct iphdr))
 		goto inhdr_error; 
+
+	if (skb->len < (iph->ihl << 2))
+		goto inhdr_error;
+
 	if (iph->ihl < 5 || iph->version != 4 || ip_fast_csum((u8 *)iph, iph->ihl) != 0)
 		goto inhdr_error; 
 
 	{
 	__u32 len = ntohs(iph->tot_len); 
 	if (skb->len < len)
+		goto inhdr_error; 
+
+	if (len <  (iph->ihl << 2))
 		goto inhdr_error; 
 
 	/*
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/ip_masq.c linux.14p16/net/ipv4/ip_masq.c
--- linux.vanilla/net/ipv4/ip_masq.c	Wed Oct 20 01:12:52 1999
+++ linux.14p16/net/ipv4/ip_masq.c	Tue Dec 14 16:17:37 1999
@@ -10,6 +10,9 @@
  *	See ip_fw.c for original log
  *
  * Fixes:
+ *	Joseph Gooch		:	Modified ip_fw_masquerade() to do a ip_route_output()
+ *	 (help by Dan Drown)	:	to choose the proper local address.
+ *	 (and Alexey)		:
  *	Juan Jose Ciarlante	:	Modularized application masquerading (see ip_masq_app.c)
  *	Juan Jose Ciarlante	:	New struct ip_masq_seq that holds output/input delta seq.
  *	Juan Jose Ciarlante	:	Added hashed lookup by proto,maddr,mport and proto,saddr,sport
@@ -787,6 +790,8 @@
 	}
 }
 
+extern int sysctl_ip_always_defrag;
+
 static void masq_expire(unsigned long data)
 {
 	struct ip_masq *ms = (struct ip_masq *)data;
@@ -839,6 +844,7 @@
 	 */
 	if (atomic_read(&ms->refcnt) == 1) {
 		kfree_s(ms,sizeof(*ms));
+		sysctl_ip_always_defrag--;
 		MOD_DEC_USE_COUNT;
 		goto masq_expire_out;
 	}
@@ -880,8 +886,6 @@
  * 	Be careful, it can be called from u-space
  */
 
-extern int sysctl_ip_always_defrag;
-
 struct ip_masq * ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned mflags)
 {
         struct ip_masq *ms, *mst;
@@ -1139,6 +1143,23 @@
 		 *	invalid packets.
 		 */
 		return -1;
+	}
+
+	/* Lets determine our maddr now, shall we? */
+	if (maddr == 0) {
+		struct rtable *rt;
+		struct rtable *skb_rt = (struct rtable*)skb->dst;
+		struct device *skb_dev = skb_rt->u.dst.dev;
+
+		if (ip_route_output(&rt, iph->daddr, 0, RT_TOS(iph->tos)|RTO_CONN, skb_dev?skb_dev->ifindex:0)) {
+			/* Fallback on old method */
+			/* This really shouldn't happen... */
+			maddr = inet_select_addr(skb_dev, skb_rt->rt_gateway, RT_SCOPE_UNIVERSE);
+		} else {
+			/* Route lookup succeeded */
+			maddr = rt->rt_src;
+			ip_rt_put(rt);
+		}
 	}
 
 	switch (iph->protocol) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/ip_masq_user.c linux.14p16/net/ipv4/ip_masq_user.c
--- linux.vanilla/net/ipv4/ip_masq_user.c	Wed Oct 20 01:12:52 1999
+++ linux.14p16/net/ipv4/ip_masq_user.c	Thu Dec  9 15:33:18 1999
@@ -2,7 +2,7 @@
  *	IP_MASQ_USER user space control module
  *
  *
- *	$Id: ip_masq_user.c,v 1.1.2.2 1999/08/13 18:26:33 davem Exp $
+ *	$Id: ip_masq_user.c,v 1.1.2.3 1999/11/16 06:33:51 davem Exp $
  */
 
 #include <linux/config.h>
@@ -100,7 +100,7 @@
 		return ret;
 	}
 	dev = rt->u.dst.dev;
-	ums->maddr = ip_masq_select_addr(dev, rt->rt_gateway, RT_SCOPE_UNIVERSE);
+	ums->maddr = rt->rt_src;  /* Per Alexey */
 
 	IP_MASQ_DEBUG(1-debug, "did setup maddr=%lX\n", ntohl(ums->maddr));
 	ip_rt_put(rt);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/route.c linux.14p16/net/ipv4/route.c
--- linux.vanilla/net/ipv4/route.c	Wed Oct 20 01:12:52 1999
+++ linux.14p16/net/ipv4/route.c	Thu Dec  9 15:33:17 1999
@@ -5,7 +5,7 @@
  *
  *		ROUTE - implementation of the IP router.
  *
- * Version:	$Id: route.c,v 1.67.2.3 1999/08/08 08:43:12 davem Exp $
+ * Version:	$Id: route.c,v 1.67.2.4 1999/11/16 02:28:43 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/syncookies.c linux.14p16/net/ipv4/syncookies.c
--- linux.vanilla/net/ipv4/syncookies.c	Sat Aug 14 02:27:41 1999
+++ linux.14p16/net/ipv4/syncookies.c	Thu Dec  9 15:33:18 1999
@@ -9,7 +9,7 @@
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.
  * 
- *  $Id: syncookies.c,v 1.7.2.1 1999/08/08 08:43:13 davem Exp $
+ *  $Id: syncookies.c,v 1.7.2.3 1999/12/07 03:11:07 davem Exp $
  *
  *  Missing: IPv6 support. 
  */
@@ -184,8 +184,10 @@
 			    req->af.v4_req.loc_addr,
 			    sk->ip_tos | RTO_CONN,
 			    0)) { 
-	    tcp_openreq_free(req);
-	    return NULL; 
+		if (req->af.v4_req.opt)
+			kfree(req->af.v4_req.opt);
+		tcp_openreq_free(req);
+		return NULL; 
 	}
 
 	/* Try to redo what tcp_v4_send_synack did. */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/tcp.c linux.14p16/net/ipv4/tcp.c
--- linux.vanilla/net/ipv4/tcp.c	Sat Aug 14 02:27:41 1999
+++ linux.14p16/net/ipv4/tcp.c	Thu Dec  9 15:33:17 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.140.2.4 1999/08/09 03:13:12 davem Exp $
+ * Version:	$Id: tcp.c,v 1.140.2.5 1999/09/23 19:21:16 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1798,6 +1798,8 @@
 void __init tcp_init(void)
 {
 	struct sk_buff *skb = NULL;
+	unsigned long goal;
+	int order;
 
 	if(sizeof(struct tcp_skb_cb) > sizeof(skb->cb))
 		__skb_cb_too_small_for_tcp(sizeof(struct tcp_skb_cb),
@@ -1823,4 +1825,43 @@
 						NULL, NULL);
 	if(!tcp_timewait_cachep)
 		panic("tcp_init: Cannot alloc tcp_tw_bucket cache.");
+
+	/* Size and allocate TCP hash tables. */
+	goal = num_physpages >> (20 - PAGE_SHIFT);
+	for (order = 0; (1UL << order) < goal; order++)
+		;
+	do {
+		tcp_ehash_size = (1UL << order) * PAGE_SIZE /
+			sizeof(struct sock *);
+		tcp_ehash = (struct sock **)
+			__get_free_pages(GFP_ATOMIC, order);
+	} while (tcp_ehash == NULL && --order >= 0);
+
+	if (!tcp_ehash)
+		panic("Failed to allocate TCP established hash table\n");
+	memset(tcp_ehash, 0, tcp_ehash_size * sizeof(struct sock *));
+
+	goal = (((1UL << order) * PAGE_SIZE) / sizeof(struct tcp_bind_bucket *));
+	if (goal > (64 * 1024)) {
+		/* Don't size the bind-hash larger than the port
+		 * space, that is just silly.
+		 */
+		goal = (((64 * 1024) * sizeof(struct tcp_bind_bucket *)) / PAGE_SIZE);
+		for (order = 0; (1UL << order) < goal; order++)
+			;
+	}
+
+	do {
+		tcp_bhash_size = (1UL << order) * PAGE_SIZE /
+			sizeof(struct tcp_bind_bucket *);
+		tcp_bhash = (struct tcp_bind_bucket **)
+			__get_free_pages(GFP_ATOMIC, order);
+	} while (tcp_bhash == NULL && --order >= 0);
+
+	if (!tcp_bhash)
+		panic("Failed to allocate TCP bind hash table\n");
+	memset(tcp_bhash, 0, tcp_bhash_size * sizeof(struct tcp_bind_bucket *));
+
+	printk("TCP: Hash tables configured (ehash %d bhash %d)\n",
+	       tcp_ehash_size, tcp_bhash_size);
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/tcp_input.c linux.14p16/net/ipv4/tcp_input.c
--- linux.vanilla/net/ipv4/tcp_input.c	Sat Aug 28 20:00:59 1999
+++ linux.14p16/net/ipv4/tcp_input.c	Thu Dec  9 15:33:18 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.164.2.7 1999/08/13 16:14:27 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.164.2.8 1999/09/23 19:21:23 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1043,7 +1043,7 @@
 	sk->prot->inuse--;
 
 	/* Step 4: Hash TW into TIMEWAIT half of established hash table. */
-	head = &tcp_established_hash[sk->hashent + (TCP_HTABLE_SIZE/2)];
+	head = &tcp_ehash[sk->hashent + (tcp_ehash_size/2)];
 	sktw = (struct sock *)tw;
 	if((sktw->next = *head) != NULL)
 		(*head)->pprev = &sktw->next;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/tcp_ipv4.c linux.14p16/net/ipv4/tcp_ipv4.c
--- linux.vanilla/net/ipv4/tcp_ipv4.c	Wed Oct 20 01:12:52 1999
+++ linux.14p16/net/ipv4/tcp_ipv4.c	Thu Dec  9 15:33:18 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.175.2.10 1999/08/13 16:14:35 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.175.2.13 1999/11/16 06:33:53 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -90,12 +90,14 @@
  * First half of the table is for sockets not in TIME_WAIT, second half
  * is for TIME_WAIT sockets only.
  */
-struct sock *tcp_established_hash[TCP_HTABLE_SIZE];
+unsigned int tcp_ehash_size;
+struct sock **tcp_ehash;
 
 /* Ok, let's try this, I give up, we do need a local binding
  * TCP hash as well as the others for fast bind/connect.
  */
-struct tcp_bind_bucket *tcp_bound_hash[TCP_BHTABLE_SIZE];
+unsigned int tcp_bhash_size;
+struct tcp_bind_bucket **tcp_bhash;
 
 /* All sockets in TCP_LISTEN state will be in here.  This is the only table
  * where wildcard'd TCP sockets can exist.  Hash function here is just local
@@ -117,7 +119,7 @@
 static __inline__ int tcp_hashfn(__u32 laddr, __u16 lport,
 				 __u32 faddr, __u16 fport)
 {
-	return ((laddr ^ lport) ^ (faddr ^ fport)) & ((TCP_HTABLE_SIZE/2) - 1);
+	return ((laddr ^ lport) ^ (faddr ^ fport)) & ((tcp_ehash_size/2) - 1);
 }
 
 static __inline__ int tcp_sk_hashfn(struct sock *sk)
@@ -140,7 +142,7 @@
 	tb = kmem_cache_alloc(tcp_bucket_cachep, SLAB_ATOMIC);
 	if(tb != NULL) {
 		struct tcp_bind_bucket **head =
-			&tcp_bound_hash[tcp_bhashfn(snum)];
+			&tcp_bhash[tcp_bhashfn(snum)];
 		tb->port = snum;
 		tb->fastreuse = 0;
 		tb->owners = NULL;
@@ -162,7 +164,7 @@
 {
 	struct tcp_bind_bucket *tb;
 
-	tb = tcp_bound_hash[tcp_bhashfn(snum)];
+	tb = tcp_bhash[tcp_bhashfn(snum)];
 	for( ; (tb && (tb->port != snum)); tb = tb->next)
 		;
 	if (tb == NULL) {
@@ -180,8 +182,8 @@
 
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
 	if (child->num != sk->num) {
-		unsigned short snum = ntohs(child->num);
-		for(tb = tcp_bound_hash[tcp_bhashfn(snum)];
+		unsigned short snum = child->num;
+		for(tb = tcp_bhash[tcp_bhashfn(snum)];
 		    tb && tb->port != snum;
 		    tb = tb->next)
 			;
@@ -220,7 +222,7 @@
 		do {	rover++;
 			if ((rover < low) || (rover > high))
 				rover = low;
-			tb = tcp_bound_hash[tcp_bhashfn(rover)];
+			tb = tcp_bhash[tcp_bhashfn(rover)];
 			for ( ; tb; tb = tb->next)
 				if (tb->port == rover)
 					goto next;
@@ -237,7 +239,7 @@
 		snum = rover;
 		tb = NULL;
 	} else {
-		for (tb = tcp_bound_hash[tcp_bhashfn(snum)];
+		for (tb = tcp_bhash[tcp_bhashfn(snum)];
 		     tb != NULL;
 		     tb = tb->next)
 			if (tb->port == snum)
@@ -328,7 +330,7 @@
 	if(sk->state == TCP_LISTEN)
 		skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
 	else
-		skp = &tcp_established_hash[(sk->hashent = tcp_sk_hashfn(sk))];
+		skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))];
 
 	if((sk->next = *skp) != NULL)
 		(*skp)->pprev = &sk->next;
@@ -421,7 +423,7 @@
 	 * have wildcards anyways.
 	 */
 	hash = tcp_hashfn(daddr, hnum, saddr, sport);
-	for(sk = tcp_established_hash[hash]; sk; sk = sk->next) {
+	for(sk = tcp_ehash[hash]; sk; sk = sk->next) {
 		if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif)) {
 			if (sk->state == TCP_ESTABLISHED)
 				TCP_RHASH(sport) = sk;
@@ -429,7 +431,7 @@
 		}
 	}
 	/* Must check for a TIME_WAIT'er before going to listener hash. */
-	for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next)
+	for(sk = tcp_ehash[hash+(tcp_ehash_size/2)]; sk; sk = sk->next)
 		if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
 			goto hit;
 	sk = tcp_v4_lookup_listener(daddr, hnum, dif);
@@ -469,7 +471,7 @@
 
 	/* This code must run only from NET_BH. */
 	{
-		struct tcp_bind_bucket *tb = tcp_bound_hash[tcp_bhashfn(hnum)];
+		struct tcp_bind_bucket *tb = tcp_bhash[tcp_bhashfn(hnum)];
 		for( ; (tb && tb->port != hnum); tb = tb->next)
 			;
 		if(tb == NULL)
@@ -510,7 +512,7 @@
 	}
 next:
 	if(firstpass--) {
-		struct tcp_bind_bucket *tb = tcp_bound_hash[tcp_bhashfn(hpnum)];
+		struct tcp_bind_bucket *tb = tcp_bhash[tcp_bhashfn(hpnum)];
 		for( ; (tb && tb->port != hpnum); tb = tb->next)
 			;
 		if(tb) {
@@ -547,7 +549,7 @@
 
 	/* Freeze the hash while we snoop around. */
 	SOCKHASH_LOCK();
-	tb = tcp_bound_hash[tcp_bhashfn(snum)];
+	tb = tcp_bhash[tcp_bhashfn(snum)];
 	for(; tb; tb = tb->next) {
 		if(tb->port == snum && tb->owners != NULL) {
 			/* Almost certainly the re-use port case, search the real hashes
@@ -1615,7 +1617,8 @@
 			sk = tcp_check_req(sk, skb, req);
 		}
 #ifdef CONFIG_SYN_COOKIES
-		else if (flg == __constant_htonl(0x00120000))  {
+		else if ((flg & __constant_htonl(0x00120000))==__constant_htonl(0x00100000))
+		{
 			sk = cookie_v4_check(sk, skb, &(IPCB(skb)->opt));
 		}
 #endif
@@ -1793,7 +1796,7 @@
 
 static void __tcp_v4_rehash(struct sock *sk)
 {
-	struct sock **skp = &tcp_established_hash[(sk->hashent = tcp_sk_hashfn(sk))];
+	struct sock **skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))];
 
 	SOCKHASH_LOCK();
 	if(sk->pprev) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/tcp_timer.c linux.14p16/net/ipv4/tcp_timer.c
--- linux.vanilla/net/ipv4/tcp_timer.c	Sat Aug 14 02:27:41 1999
+++ linux.14p16/net/ipv4/tcp_timer.c	Thu Dec  9 15:33:18 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_timer.c,v 1.62.2.3 1999/06/20 20:14:30 davem Exp $
+ * Version:	$Id: tcp_timer.c,v 1.62.2.4 1999/09/23 19:21:39 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -363,8 +363,8 @@
 	int count = 0;
 	int i;
 	
-	for(i = chain_start; i < (chain_start + ((TCP_HTABLE_SIZE/2) >> 2)); i++) {
-		struct sock *sk = tcp_established_hash[i];
+	for(i = chain_start; i < (chain_start + ((tcp_ehash_size/2) >> 2)); i++) {
+		struct sock *sk = tcp_ehash[i];
 		while(sk) {
 			if(!atomic_read(&sk->sock_readers) && sk->keepopen) {
 				count += tcp_keepopen_proc(sk);
@@ -375,8 +375,8 @@
 		}
 	}
 out:
-	chain_start = ((chain_start + ((TCP_HTABLE_SIZE/2)>>2)) &
-		       ((TCP_HTABLE_SIZE/2) - 1));
+	chain_start = ((chain_start + ((tcp_ehash_size/2)>>2)) &
+		       ((tcp_ehash_size/2) - 1));
 }
 
 /*
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv6/README linux.14p16/net/ipv6/README
--- linux.vanilla/net/ipv6/README	Sat Apr 20 10:01:37 1996
+++ linux.14p16/net/ipv6/README	Thu Dec  9 15:33:19 1999
@@ -1,6 +1,6 @@
 To join in the work on Linux IPv6 send mail to:
 
-        majordomo@nuclecu.unam.mx
+        majordomo@oss.sgi.com
 
 and in the body of the message include:
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv6/addrconf.c linux.14p16/net/ipv6/addrconf.c
--- linux.vanilla/net/ipv6/addrconf.c	Sat Aug 14 02:27:43 1999
+++ linux.14p16/net/ipv6/addrconf.c	Mon Dec 13 18:50:36 1999
@@ -570,6 +570,21 @@
 	}
 	return -1;
 }
+
+static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
+{
+	int err = -1;
+	struct inet6_ifaddr *ifp;
+
+	for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
+		if (ifp->scope == IFA_LINK && !(ifp->flags&(ADDR_STATUS|DAD_STATUS))) {
+			memcpy(eui, ifp->addr.s6_addr+8, 8);
+			err = 0;
+			break;
+		}
+	}
+	return err;
+}
 #endif
 
 /*
@@ -742,7 +757,8 @@
 #ifdef CONFIG_IPV6_EUI64
 		if (pinfo->prefix_len == 64) {
 			memcpy(&addr, &pinfo->prefix, 8);
-			if (ipv6_generate_eui64(addr.s6_addr + 8, dev))
+			if (ipv6_generate_eui64(addr.s6_addr + 8, dev) &&
+			    ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev))
 				return;
 			goto ok;
 		}
@@ -1374,7 +1390,7 @@
 	 */
 
 	if (ifp->idev->cnf.forwarding == 0 &&
-	    (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) == 0 &&
+	    (dev->flags&IFF_LOOPBACK) == 0 &&
 	    (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) {
 		struct in6_addr all_routers;
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv6/tcp_ipv6.c linux.14p16/net/ipv6/tcp_ipv6.c
--- linux.vanilla/net/ipv6/tcp_ipv6.c	Sat Aug 28 20:00:59 1999
+++ linux.14p16/net/ipv6/tcp_ipv6.c	Thu Dec  9 15:33:19 1999
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.104.2.9 1999/08/13 18:49:56 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.104.2.10 1999/09/23 19:21:46 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -67,7 +67,7 @@
 	int hashent = (lport ^ fport);
 
 	hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
-	return (hashent & ((TCP_HTABLE_SIZE/2) - 1));
+	return (hashent & ((tcp_ehash_size/2) - 1));
 }
 
 static __inline__ int tcp_v6_sk_hashfn(struct sock *sk)
@@ -98,7 +98,7 @@
 		do {	rover++;
 			if ((rover < low) || (rover > high))
 				rover = low;
-			tb = tcp_bound_hash[tcp_bhashfn(rover)];
+			tb = tcp_bhash[tcp_bhashfn(rover)];
 			for ( ; tb; tb = tb->next)
 				if (tb->port == rover)
 					goto next;
@@ -115,7 +115,7 @@
 		snum = rover;
 		tb = NULL;
 	} else {
-		for (tb = tcp_bound_hash[tcp_bhashfn(snum)];
+		for (tb = tcp_bhash[tcp_bhashfn(snum)];
 		     tb != NULL;
 		     tb = tb->next)
 			if (tb->port == snum)
@@ -194,7 +194,7 @@
 		if(sk->state == TCP_LISTEN)
 			skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
 		else
-			skp = &tcp_established_hash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
+			skp = &tcp_ehash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
 
 		SOCKHASH_LOCK();
 		if((sk->next = *skp) != NULL)
@@ -276,7 +276,7 @@
 	 * have wildcards anyways.
 	 */
 	hash = tcp_v6_hashfn(daddr, hnum, saddr, sport);
-	for(sk = tcp_established_hash[hash]; sk; sk = sk->next) {
+	for(sk = tcp_ehash[hash]; sk; sk = sk->next) {
 		/* For IPV6 do the cheaper port and family tests first. */
 		if(TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif)) {
 			if (sk->state == TCP_ESTABLISHED)
@@ -285,7 +285,7 @@
 		}
 	}
 	/* Must check for a TIME_WAIT'er before going to listener hash. */
-	for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next) {
+	for(sk = tcp_ehash[hash+(tcp_ehash_size/2)]; sk; sk = sk->next) {
 		if(*((__u32 *)&(sk->dport))	== ports	&&
 		   sk->family			== PF_INET6) {
 			struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk;
@@ -336,7 +336,7 @@
 
 	/* Freeze the hash while we snoop around. */
 	SOCKHASH_LOCK();
-	tb = tcp_bound_hash[tcp_bhashfn(snum)];
+	tb = tcp_bhash[tcp_bhashfn(snum)];
 	for(; tb; tb = tb->next) {
 		if(tb->port == snum && tb->owners != NULL) {
 			/* Almost certainly the re-use port case, search the real hashes
@@ -632,7 +632,6 @@
 
 		if (dst == NULL) {
 			struct flowi fl;
-			struct dst_entry *dst;
 
 			/* BUGGG_FUTURE: Again, it is not clear how
 			   to handle rthdr case. Ignore this complexity
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/irda/irda_device.c linux.14p16/net/irda/irda_device.c
--- linux.vanilla/net/irda/irda_device.c	Sat Aug 14 02:26:52 1999
+++ linux.14p16/net/irda/irda_device.c	Thu Dec  9 15:33:24 1999
@@ -120,7 +120,7 @@
 #ifdef CONFIG_GIRBIL_DONGLE
 	girbil_init();
 #endif
-#ifdef CONFIG_GIRBIL_DONGLE
+#ifdef CONFIG_LITELINK_DONGLE
 	litelink_init();
 #endif
 
@@ -526,13 +526,13 @@
 		break;
 	case SIOCSIWNWID:
 		/* Set domain */
-		if (wrq->u.nwid.on) {
+		if (!wrq->u.nwid.disabled) {
 			
 		} break;
 	case SIOCGIWNWID:
 		/* Read domain*/
 /* 		wrq->u.nwid.nwid = domain; */
-/* 		wrq->u.nwid.on = 1; */
+/* 		wrq->u.nwid.disabled = 0; */
 		break;
 	case SIOCGIWENCODE:
 		/* Get scramble key */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/irda/irlan/irlan_eth.c linux.14p16/net/irda/irlan/irlan_eth.c
--- linux.vanilla/net/irda/irlan/irlan_eth.c	Sat Aug 14 02:26:52 1999
+++ linux.14p16/net/irda/irlan/irlan_eth.c	Thu Dec  9 15:33:24 1999
@@ -345,6 +345,7 @@
 	 * is useful if we have changed access points on the same
 	 * subnet.  
 	 */
+#ifdef CONFIG_INET	 
 	DEBUG(4, "IrLAN: Sending gratuitous ARP\n");
 	in_dev = dev->ip_ptr;
 	arp_send(ARPOP_REQUEST, ETH_P_ARP, 
@@ -352,6 +353,7 @@
 		 dev, 
 		 in_dev->ifa_list->ifa_address,
 		 NULL, dev->dev_addr, NULL);
+#endif /* CONFIG_INET */		 
 }
 
 /*
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/irda/irmod.c linux.14p16/net/irda/irmod.c
--- linux.vanilla/net/irda/irmod.c	Sat Aug 14 02:26:54 1999
+++ linux.14p16/net/irda/irmod.c	Thu Dec  9 15:33:24 1999
@@ -119,7 +119,9 @@
 EXPORT_SYMBOL(irda_notify_init);
 EXPORT_SYMBOL(irmanager_notify);
 EXPORT_SYMBOL(irda_lock);
+#ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(proc_irda);
+#endif
 
 /* IrIAP/IrIAS */
 EXPORT_SYMBOL(iriap_getvaluebyclass_request);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/netsyms.c linux.14p16/net/netsyms.c
--- linux.vanilla/net/netsyms.c	Wed Oct 20 01:12:52 1999
+++ linux.14p16/net/netsyms.c	Thu Dec  9 15:33:19 1999
@@ -225,7 +225,6 @@
 EXPORT_SYMBOL(inet_add_protocol);
 EXPORT_SYMBOL(inet_del_protocol);
 EXPORT_SYMBOL(rarp_ioctl_hook);
-EXPORT_SYMBOL(init_etherdev);
 EXPORT_SYMBOL(ip_route_output);
 EXPORT_SYMBOL(icmp_send);
 EXPORT_SYMBOL(ip_options_compile);
@@ -277,9 +276,11 @@
 EXPORT_SYMBOL(inet_recvmsg);
 
 /* Socket demultiplexing. */
-EXPORT_SYMBOL(tcp_established_hash);
+EXPORT_SYMBOL(tcp_ehash_size);
+EXPORT_SYMBOL(tcp_ehash);
 EXPORT_SYMBOL(tcp_listening_hash);
-EXPORT_SYMBOL(tcp_bound_hash);
+EXPORT_SYMBOL(tcp_bhash_size);
+EXPORT_SYMBOL(tcp_bhash);
 EXPORT_SYMBOL(udp_hash);
 
 EXPORT_SYMBOL(destroy_sock);
@@ -381,9 +382,6 @@
 EXPORT_SYMBOL(neigh_dump_info);
 #endif
 
-EXPORT_SYMBOL(dev_set_allmulti);
-EXPORT_SYMBOL(dev_set_promiscuity);
-EXPORT_SYMBOL(sklist_remove_socket);
 EXPORT_SYMBOL(rtnl_wait);
 EXPORT_SYMBOL(rtnl_rlockct);
 EXPORT_SYMBOL(rtnl_lock);
@@ -453,6 +451,10 @@
 EXPORT_SYMBOL(dev_new_index);
 EXPORT_SYMBOL(dev_get_by_index);
 EXPORT_SYMBOL(eth_type_trans);
+EXPORT_SYMBOL(init_etherdev);
+EXPORT_SYMBOL(dev_set_allmulti);
+EXPORT_SYMBOL(dev_set_promiscuity);
+EXPORT_SYMBOL(sklist_remove_socket);
 #ifdef CONFIG_FDDI
 EXPORT_SYMBOL(fddi_type_trans);
 EXPORT_SYMBOL(fddi_setup);
@@ -496,8 +498,10 @@
 EXPORT_SYMBOL(unregister_hipdev);
 #endif
 
+#ifdef CONFIG_INET
 EXPORT_SYMBOL(sysctl_wmem_max);
 EXPORT_SYMBOL(sysctl_rmem_max);
+#endif
 
 #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) 
 #include<linux/if_ltalk.h>
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/packet/af_packet.c linux.14p16/net/packet/af_packet.c
--- linux.vanilla/net/packet/af_packet.c	Sun Mar 21 15:22:00 1999
+++ linux.14p16/net/packet/af_packet.c	Thu Dec  9 15:33:23 1999
@@ -524,7 +524,7 @@
 
 	sk->timer.expires=jiffies+10*HZ;
 	add_timer(&sk->timer);
-	printk(KERN_DEBUG "packet sk destroy delayed\n");
+/*	printk(KERN_DEBUG "packet sk destroy delayed\n"); */
 }
 
 /*
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sunrpc/clnt.c linux.14p16/net/sunrpc/clnt.c
--- linux.vanilla/net/sunrpc/clnt.c	Tue Oct  6 17:39:44 1998
+++ linux.14p16/net/sunrpc/clnt.c	Thu Dec  9 15:33:23 1999
@@ -467,6 +467,9 @@
 		return;
 	}
 
+	/* Zero buffer so we have automatic zero-padding of opaque & string */
+	memset(task->tk_buffer, 0, bufsiz);
+
 	/* Encode header and provided arguments */
 	encode = rpcproc_encode(clnt, task->tk_proc);
 	if (!(p = call_header(task))) {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sunrpc/svc.c linux.14p16/net/sunrpc/svc.c
--- linux.vanilla/net/sunrpc/svc.c	Wed Oct 20 01:12:52 1999
+++ linux.14p16/net/sunrpc/svc.c	Thu Dec  9 15:33:23 1999
@@ -38,7 +38,7 @@
 
 	memset(serv, 0, sizeof(*serv));
 	serv->sv_program   = prog;
-	serv->sv_nrthreads = 1;
+	atomic_set(&serv->sv_nrthreads, 1);
 	serv->sv_stats     = prog->pg_stats;
 	serv->sv_bufsz	   = bufsize? bufsize : 4096;
 	serv->sv_xdrsize   = xdrsize;
@@ -61,10 +61,10 @@
 
 	dprintk("RPC: svc_destroy(%s, %d)\n",
 				serv->sv_program->pg_name,
-				serv->sv_nrthreads);
+				atomic_read (&serv->sv_nrthreads));
 
-	if (serv->sv_nrthreads) {
-		if (--(serv->sv_nrthreads) != 0)
+	if (atomic_read (&serv->sv_nrthreads)) {
+		if (!atomic_dec_and_test (&serv->sv_nrthreads))
 			return;
 	} else
 		printk("svc_destroy: no threads for serv=%p!\n", serv);
@@ -128,7 +128,7 @@
 	 || !svc_init_buffer(&rqstp->rq_defbuf, serv->sv_bufsz))
 		goto out_thread;
 
-	serv->sv_nrthreads++;
+	atomic_inc(&serv->sv_nrthreads);
 	rqstp->rq_server = serv;
 	error = kernel_thread((int (*)(void *)) func, rqstp, 0);
 	if (error < 0)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sunrpc/svcsock.c linux.14p16/net/sunrpc/svcsock.c
--- linux.vanilla/net/sunrpc/svcsock.c	Wed Oct 20 01:12:52 1999
+++ linux.14p16/net/sunrpc/svcsock.c	Thu Dec  9 15:33:23 1999
@@ -124,7 +124,7 @@
 				"svc_sock_enqueue: server %p, rq_sock=%p!\n",
 				rqstp, rqstp->rq_sock);
 		rqstp->rq_sock = svsk;
-		svsk->sk_inuse++;
+		atomic_inc(&svsk->sk_inuse);
 		wake_up(&rqstp->rq_wait);
 	} else {
 		dprintk("svc: socket %p put into queue\n", svsk->sk_sk);
@@ -148,7 +148,7 @@
 
 	if (svsk) {
 		dprintk("svc: socket %p dequeued, inuse=%d\n",
-			svsk->sk_sk, svsk->sk_inuse);
+			svsk->sk_sk, atomic_read(&svsk->sk_inuse));
 		svsk->sk_qued = 0;
 	}
 
@@ -206,7 +206,7 @@
 		return;
 	svc_release_skb(rqstp);
 	rqstp->rq_sock = NULL;
-	if (!--(svsk->sk_inuse) && svsk->sk_dead) {
+	if (atomic_dec_and_test(&svsk->sk_inuse) && svsk->sk_dead) {
 		dprintk("svc: releasing dead socket\n");
 		sock_release(svsk->sk_sock);
 		kfree(svsk);
@@ -766,7 +766,7 @@
 	start_bh_atomic();
 	if ((svsk = svc_sock_dequeue(serv)) != NULL) {
 		rqstp->rq_sock = svsk;
-		svsk->sk_inuse++;
+		atomic_inc(&svsk->sk_inuse);
 	} else {
 		/* No data pending. Go to sleep */
 		svc_serv_enqueue(serv, rqstp);
@@ -793,7 +793,7 @@
 	end_bh_atomic();
 
 	dprintk("svc: server %p, socket %p, inuse=%d\n",
-		 rqstp, svsk, svsk->sk_inuse);
+		 rqstp, svsk, atomic_read(&svsk->sk_inuse));
 	len = svsk->sk_recvfrom(rqstp);
 	dprintk("svc: got len=%d\n", len);
 
@@ -988,11 +988,12 @@
 		rpc_remove_list(&serv->sv_sockets, svsk);
 	svsk->sk_dead = 1;
 
-	if (!svsk->sk_inuse) {
+	if (!atomic_read(&svsk->sk_inuse)) {
 		sock_release(svsk->sk_sock);
 		kfree(svsk);
 	} else {
-		printk(KERN_NOTICE "svc: server socket destroy delayed\n");
+		printk(KERN_NOTICE "svc: server socket destroy delayed (sk_inuse: %d)\n",
+		       atomic_read(&svsk->sk_inuse));
 		/* svsk->sk_server = NULL; */
 	}
 }
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/sunrpc/xprt.c linux.14p16/net/sunrpc/xprt.c
--- linux.vanilla/net/sunrpc/xprt.c	Wed Oct 20 01:12:52 1999
+++ linux.14p16/net/sunrpc/xprt.c	Thu Dec  9 15:33:23 1999
@@ -743,11 +743,29 @@
 	return result;
 }
 
+static __inline__ void tcp_output_record(struct rpc_xprt *xprt)
+{
+	if(xprt->snd_sent && xprt->snd_task)
+		dprintk("RPC: write space\n");
+	if(xprt->write_space == 0)
+	{
+		xprt->write_space = 1;
+		if (xprt->snd_task && !RPC_IS_RUNNING(xprt->snd_task))
+		{
+			if(xprt->snd_sent)
+				dprintk("RPC: Write wakeup snd_sent =%d\n",
+					xprt->snd_sent);
+			rpc_wake_up_task(xprt->snd_task);			
+		}
+	}
+}
+
 /*
  *	TCP task queue stuff
  */
  
-static struct rpc_xprt *rpc_xprt_pending = NULL;	/* Chain by rx_pending of rpc_xprt's */
+static struct rpc_xprt *rpc_rx_xprt_pending = NULL;	/* Chain by rx_pending of rpc_xprt's */
+static struct rpc_xprt *rpc_tx_xprt_pending = NULL;	/* Chain by tx_pending of rpc_xprt's */
 
 /*
  *	This is protected from tcp_data_ready and the stack as its run
@@ -765,11 +783,11 @@
 	 *	Empty each pending socket
 	 */
 	 
-	while((xprt=rpc_xprt_pending)!=NULL)
+	while((xprt=rpc_rx_xprt_pending)!=NULL)
 	{
 		int safe_retry=0;
 		
-		rpc_xprt_pending=xprt->rx_pending;
+		rpc_rx_xprt_pending=xprt->rx_pending;
 		xprt->rx_pending_flag=0;
 		
 		dprintk("rpciod_tcp_dispatcher: Processing %p\n", xprt);
@@ -794,6 +812,13 @@
 					result);
 		}
 	}
+
+	while((xprt=rpc_tx_xprt_pending)!=NULL)
+	{
+		rpc_tx_xprt_pending = xprt->tx_pending;
+		xprt->tx_pending_flag = 0;
+		tcp_output_record(xprt);
+	}
 }
 
 
@@ -831,12 +856,12 @@
 	{
 		int start_queue=0;
 
-		dprintk("RPC:     xprt queue %p\n", rpc_xprt_pending);
-		if(rpc_xprt_pending==NULL)
+		dprintk("RPC:     xprt queue %p\n", rpc_rx_xprt_pending);
+		if(rpc_rx_xprt_pending==NULL)
 			start_queue=1;
 		xprt->rx_pending_flag=1;
-		xprt->rx_pending=rpc_xprt_pending;
-		rpc_xprt_pending=xprt;
+		xprt->rx_pending=rpc_rx_xprt_pending;
+		rpc_rx_xprt_pending=xprt;
 		if (start_queue)
 		  {
 		    tcp_rpciod_queue();
@@ -878,18 +903,16 @@
 
 	if (!(xprt = xprt_from_sock(sk)))
 		return;
-	if(xprt->snd_sent && xprt->snd_task)
-		dprintk("RPC: write space\n");
-	if(xprt->write_space == 0)
-	{
-		xprt->write_space = 1;
-		if (xprt->snd_task && !RPC_IS_RUNNING(xprt->snd_task))
-		{
-			if(xprt->snd_sent)
-				dprintk("RPC: Write wakeup snd_sent =%d\n",
-					xprt->snd_sent);
-			rpc_wake_up_task(xprt->snd_task);			
-		}
+	if (!xprt->tx_pending_flag) {
+		int start_queue = 0;
+
+		if (rpc_tx_xprt_pending == NULL)
+			start_queue = 1;
+		xprt->tx_pending_flag = 1;
+		xprt->tx_pending = rpc_tx_xprt_pending;
+		rpc_tx_xprt_pending = xprt;
+		if (start_queue)
+			tcp_rpciod_queue();
 	}
 }
 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/wanrouter/wanmain.c linux.14p16/net/wanrouter/wanmain.c
--- linux.vanilla/net/wanrouter/wanmain.c	Wed Dec 30 23:07:00 1998
+++ linux.14p16/net/wanrouter/wanmain.c	Wed Dec 15 16:14:02 1999
@@ -9,15 +9,16 @@
 *		 o Logical connection management (switched virtual circuits)
 *		 o Protocol encapsulation/decapsulation
 *
-* Author:	Gene Kozin	<genek@compuserve.com>
+* Author:	Gideon Hack	
 *
-* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-1999 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.
 * ============================================================================
+* Oct 01, 1999  Gideon Hack     Update for s514 PCI card
 * Dec 27, 1996	Gene Kozin	Initial version (based on Sangoma's WANPIPE)
 * Jan 16, 1997	Gene Kozin	router_devlist made public
 * Jan 31, 1997  Alan Cox	Hacked it about a bit for 2.1
@@ -30,8 +31,10 @@
 * Dec 22, 1998  Arnaldo Melo    vmalloc/vfree used in device_setup to allocate
 *                               kernel memory and copy configuration data to
 *                               kernel space (for big firmwares)
+* Jun 02, 1999  Gideon Hack	Updates for Linux 2.0.X and 2.2.X kernels.	
 *****************************************************************************/
 
+#include <linux/version.h>
 #include <linux/config.h>
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
@@ -40,14 +43,19 @@
 #include <linux/malloc.h>	/* kmalloc(), kfree() */
 #include <linux/mm.h>		/* verify_area(), etc. */
 #include <linux/string.h>	/* inline mem*, str* functions */
+
 #include <linux/vmalloc.h>	/* vmalloc, vfree */
+#include <asm/uaccess.h>        /* copy_to/from_user */
+#include <linux/init.h>         /* __initfunc et al. */
+
 #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 */
-#include <linux/init.h>		/* __initfunc et al. */
 
-/****** Defines and Macros **************************************************/
+
+/*
+ * 	Defines and Macros 
+ */
 
 #ifndef	min
 #define min(a,b) (((a)<(b))?(a):(b))
@@ -56,48 +64,49 @@
 #define max(a,b) (((a)>(b))?(a):(b))
 #endif
 
-/****** Function Prototypes *************************************************/
-
 /*
- *	Kernel loadable module interface.
+ * 	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);
-
-/*
+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);
+static wan_device_t *find_device (char *name);
+static int delete_interface (wan_device_t *wandev, char *name, int force);
 
 /*
  *	Global Data
  */
 
 static char fullname[]		= "WAN Router";
-static char copyright[]		= "(c) 1995-1997 Sangoma Technologies Inc.";
+static char copyright[]		= "(c) 1995-1999 Sangoma Technologies Inc.";
 static char modname[]		= ROUTER_NAME;	/* short module name */
-wan_device_t * router_devlist	= NULL;	/* list of registered devices */
-static int devcnt		= 0;
+wan_device_t* router_devlist 	= NULL;	/* list of registered devices */
+static int devcnt 		= 0;
 
-/*
- *	Organizationally Unique Identifiers for encapsulation/decapsulation
+/* 
+ *	Organize Unique Identifiers for encapsulation/decapsulation 
  */
- 
+
 static unsigned char oui_ether[] = { 0x00, 0x00, 0x00 };
 #if 0
 static unsigned char oui_802_2[] = { 0x00, 0x80, 0xC2 };
@@ -112,17 +121,19 @@
 
 	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);		
+		printk(KERN_ERR "%s: can't create entry in proc filesystem!\n", modname);
+
+        /*
+         *      Initialise compiled in boards
+         */
 
-	/*
-	 *	Initialise compiled in boards
-	 */		
-	 
 #ifdef CONFIG_VENDOR_SANGOMA
 	wanpipe_init();
 #endif	
+ 
 	return err;
 }
 
@@ -133,14 +144,14 @@
  */
 
 /*
- *	Module 'insert' entry point.
- *	o print announcement
- *	o initialize static data
- *	o create /proc/net/router directory and static entries
+ * 	Module 'insert' entry point.
+ * 	o print announcement
+ * 	o initialize static data
+ * 	o create /proc/net/router directory and static entries
  *
- *	Return:	0	Ok
+ * 	Return:	0	Ok
  *		< 0	error.
- *	Context:	process
+ * 	Context:	process
  */
 
 int init_module	(void)
@@ -156,10 +167,10 @@
 }
 
 /*
- *	Module 'remove' entry point.
- *	o delete /proc/net/router directory and static entries.
+ * 	Module 'remove' entry point.
+ * 	o delete /proc/net/router directory and static entries.
  */
- 
+
 void cleanup_module (void)
 {
 	wanrouter_proc_cleanup();
@@ -168,34 +179,34 @@
 #endif
 
 /*
- *	Kernel APIs
+ * 	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
+ * 	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.
+ * 	Return:
+ *	0	Ok
+ *	< 0	error.
  *
- *	Context:	process
+ * 	Context:	process
  */
 
 
-int register_wan_device(wan_device_t* wandev)
+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;
@@ -212,12 +223,10 @@
 	 *	Register /proc directory entry 
 	 */
 	err = wanrouter_proc_add(wandev);
-	if (err)
-	{
+	if (err) {
 		printk(KERN_ERR
 			"%s: can't create /proc/net/router/%s entry!\n",
-			modname, wandev->name)
-		;
+			modname, wandev->name);
 		return err;
 	}
 
@@ -247,8 +256,8 @@
  *	Context:	process
  */
 
- 
-int unregister_wan_device(char* name)
+
+int unregister_wan_device(char *name)
 {
 	wan_device_t *wandev, *prev;
 
@@ -266,8 +275,7 @@
 	printk(KERN_INFO "%s: unregistering WAN device %s\n", modname, name);
 #endif
 	
-	if (wandev->state != WAN_UNCONFIGURED)
-	{
+	if (wandev->state != WAN_UNCONFIGURED) {
 		while(wandev->dev)
 			delete_interface(wandev, wandev->dev->name, 1);
 		if (wandev->shutdown)	
@@ -294,12 +302,11 @@
  */
 
 
-int wanrouter_encapsulate (struct sk_buff* skb, struct device* dev)
+int wanrouter_encapsulate (struct sk_buff *skb, struct device *dev)
 {
 	int hdr_len = 0;
 
-	switch (skb->protocol)
-	{
+	switch (skb->protocol) {
 	case ETH_P_IP:		/* IP datagram encapsulation */
 		hdr_len += 1;
 		skb_push(skb, 1);
@@ -336,27 +343,24 @@
  */
 
 
-unsigned short wanrouter_type_trans (struct sk_buff* skb, struct device* dev)
+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])
-	{
+	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)))
-		{
+		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]);
@@ -368,8 +372,7 @@
 	default:
 		printk(KERN_INFO
 			"%s: unsupported NLPID 0x%02X on interface %s!\n",
-			modname, skb->data[cnt], dev->name)
-		;
+			modname, skb->data[cnt], dev->name);
 		return 0;
 	}
 	skb->protocol = ethertype;
@@ -379,18 +382,19 @@
 	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,
+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;
+	struct proc_dir_entry *dent;
+	wan_device_t *wandev;
 
 	if (!capable(CAP_NET_ADMIN)){
 		return -EPERM;
@@ -407,8 +411,7 @@
 	if (wandev->magic != ROUTER_MAGIC)
 		return -EINVAL;
 		
-	switch (cmd)
-	{
+	switch (cmd) {
 	case ROUTER_SETUP:
 		err = device_setup(wandev, (void*)arg);
 		break;
@@ -436,8 +439,7 @@
 		if ((cmd >= ROUTER_USER) &&
 		    (cmd <= ROUTER_USER_MAX) &&
 		    wandev->ioctl)
-			err = wandev->ioctl(wandev, cmd, arg)
-		;
+			err = wandev->ioctl(wandev, cmd, arg);
 		else err = -EINVAL;
 	}
 	return err;
@@ -455,51 +457,52 @@
  *	o call driver's setup() entry point
  */
 
-static int device_setup (wan_device_t* wandev, wandev_conf_t* u_conf)
+static int device_setup (wan_device_t *wandev, wandev_conf_t *u_conf)
 {
-	void* data;
+	void *data = NULL;
 	wandev_conf_t *conf;
-	int err= -EINVAL;
+	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)))
-	{
+
+	if(copy_from_user(conf, u_conf, sizeof(wandev_conf_t))) {
 		kfree(conf);
 		return -EFAULT;
 	}
 	
-	if (conf->magic != ROUTER_MAGIC)
-		goto bail;
+	if (conf->magic != ROUTER_MAGIC) {
+		kfree(conf);
+	        return -EINVAL; 
+	}
 
-	if (conf->data_size && conf->data)
-	{
-		if(conf->data_size > 128000 || conf->data_size < 0){
-			goto bail;
+	if (conf->data_size && conf->data) {
+		if(conf->data_size > 128000 || conf->data_size < 0) {
+			kfree(conf);
+		        return -EINVAL;;
 		}
+
 		data = vmalloc(conf->data_size);
-		if (data)
-		{
-			if(!copy_from_user(data, conf->data, conf->data_size))
-			{
+		if (data) {
+			if(!copy_from_user(data, conf->data, conf->data_size)){
 				conf->data=data;
 				err = wandev->setup(wandev,conf);
 			}
 			else 
 				err = -EFAULT;
 		}
-		else
+		else 
 			err = -ENOBUFS;
-			
+
 		if (data)
 			vfree(data);
+
 	}
-bail:
+
 	kfree(conf);
 	return err;
 }
@@ -510,15 +513,14 @@
  *	o call driver's shutdown() entry point
  */
  
-static int device_shutdown (wan_device_t* wandev)
+static int device_shutdown (wan_device_t *wandev)
 {
-	struct device* dev;
+	struct device *dev;
 
 	if (wandev->state == WAN_UNCONFIGURED)
 		return 0;
 		
-	for (dev = wandev->dev; dev;)
-	{
+	for (dev = wandev->dev; dev;) {
 		if (delete_interface(wandev, dev->name, 0))
 			dev = dev->slave;
 	}
@@ -534,7 +536,7 @@
  *	Get WAN device status & statistics.
  */
 
-static int device_stat (wan_device_t* wandev, wandev_stat_t* u_stat)
+static int device_stat (wan_device_t *wandev, wandev_stat_t *u_stat)
 {
 	wandev_stat_t stat;
 
@@ -550,6 +552,7 @@
 
 	if(copy_to_user(u_stat, &stat, sizeof(stat)))
 		return -EFAULT;
+
 	return 0;
 }
 
@@ -563,15 +566,15 @@
  *	o register network interface
  */
 
-static int device_new_if (wan_device_t* wandev, wanif_conf_t* u_conf)
+static int device_new_if (wan_device_t *wandev, wanif_conf_t *u_conf)
 {
 	wanif_conf_t conf;
-	struct device* dev;
+	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;
 		
@@ -584,8 +587,7 @@
 		
 	memset(dev, 0, sizeof(struct device));
 	err = wandev->new_if(wandev, dev, &conf);
-	if (!err)
-	{
+	if (!err) {
 		/* Register network interface. This will invoke init()
 		 * function supplied by the driver.  If device registered
 		 * successfully, add it to the interface list.
@@ -595,15 +597,13 @@
 			
 		else if (dev_get(dev->name))
 			err = -EEXIST;	/* name already exists */
-		else
-		{
+		else {
 #ifdef WANDEBUG		
 			printk(KERN_INFO "%s: registering interface %s...\n",
 				modname, dev->name);
 #endif				
 			err = register_netdev(dev);
-			if (!err)
-			{
+			if (!err) {
 				cli();	/***** critical section start *****/
 				dev->slave = wandev->dev;
 				wandev->dev = dev;
@@ -619,25 +619,28 @@
 	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)
+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
  */
@@ -647,9 +650,9 @@
  *	Return pointer to the WAN device data space or NULL if device not found.
  */
 
-static wan_device_t* find_device (char* name)
+static wan_device_t *find_device(char *name)
 {
-	wan_device_t* wandev;
+	wan_device_t *wandev;
 
 	for (wandev = router_devlist;wandev && strcmp(wandev->name, name);
 		wandev = wandev->next);
@@ -673,7 +676,7 @@
  *	sure that opened interfaces are not removed!
  */
 
-static int delete_interface (wan_device_t* wandev, char* name, int force)
+static int delete_interface (wan_device_t *wandev, char *name, int force)
 {
 	struct device *dev, *prev;
 
@@ -684,16 +687,16 @@
 	if (dev == NULL)
 		return -ENODEV;	/* interface not found */
 
-	if (dev->start)
-	{
-		if (force)
-		{
+	if (dev->start) {
+		if (force) {
 			printk(KERN_WARNING
-				"%s: deleting opened interface %s!\n",modname, name);
+				"%s: deleting opened interface %s!\n",
+				modname, name);
 		}
 		else
 			return -EBUSY;	/* interface in use */
 	}
+
 	if (wandev->del_if)
 		wandev->del_if(wandev, dev);
 
@@ -705,7 +708,7 @@
 	--wandev->ndev;
 	sti();			/****** critical section end ******/
 
-	printk("Unregistering '%s'\n", dev->name);
+	printk("Unregistering '%s'\n", dev->name); 
 	unregister_netdev(dev);
 	kfree(dev);
 	return 0;
@@ -719,4 +722,3 @@
 /*
  *	End
  */
-
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/wanrouter/wanproc.c linux.14p16/net/wanrouter/wanproc.c
--- linux.vanilla/net/wanrouter/wanproc.c	Sun Nov 15 17:52:29 1998
+++ linux.14p16/net/wanrouter/wanproc.c	Wed Dec 15 16:15:46 1999
@@ -4,21 +4,23 @@
 *		This module is completely hardware-independent and provides
 *		access to the router using Linux /proc filesystem.
 *
-* Author:	Gene Kozin	<genek@compuserve.com>
+* Author: 	Gideon Hack	
 *
-* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-1999 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.
 * ============================================================================
+* Jun 02, 1999  Gideon Hack	Updates for Linux 2.2.X kernels.
 * Jun 29, 1997	Alan Cox	Merged with 1.0.3 vendor code
 * Jan 29, 1997	Gene Kozin	v1.0.1. Implemented /proc read routines
 * Jan 30, 1997	Alan Cox	Hacked around for 2.1
 * Dec 13, 1996	Gene Kozin	Initial version (based on Sangoma's WANPIPE)
 *****************************************************************************/
 
+#include <linux/version.h>
 #include <linux/config.h>
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
@@ -27,15 +29,17 @@
 #include <linux/mm.h>		/* verify_area(), etc. */
 #include <linux/string.h>	/* inline mem*, str* functions */
 #include <linux/init.h>		/* __initfunc et al. */
+#include <asm/uaccess.h>        /* copy_to_user */
 #include <asm/segment.h>	/* kernel <-> user copy */
 #include <asm/byteorder.h>	/* htons(), etc. */
-#include <asm/uaccess.h>	/* copy_to_user */
 #include <asm/io.h>
 #include <linux/wanrouter.h>	/* WAN router API definitions */
 
 
 /****** Defines and Macros **************************************************/
 
+#define PROC_STATS_FORMAT "%30s: %12lu\n"
+
 #ifndef	min
 #define min(a,b) (((a)<(b))?(a):(b))
 #endif
@@ -45,11 +49,12 @@
 
 #define	PROC_BUFSZ	4000	/* buffer size for printing proc info */
 
+
 /****** Data Types **********************************************************/
 
 typedef struct wan_stat_entry
 {
-	struct wan_stat_entry *	next;
+	struct wan_stat_entry *next;
 	char *description;		/* description string */
 	void *data;			/* -> data */
 	unsigned data_type;		/* data type */
@@ -61,13 +66,15 @@
 
 /* Proc filesystem interface */
 static int router_proc_perms(struct inode *, int);
-static ssize_t router_proc_read(struct file* file, char* buf, size_t count, 					loff_t *ppos);
+static ssize_t router_proc_read(struct file *file, char *buf, size_t count, 					loff_t *ppos);
 
 /* Methods for preparing data for reading proc entries */
-
-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);
+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 */
 
@@ -95,7 +102,6 @@
 /*
  *	Generic /proc/net/router/<file> file and inode operations 
  */
-
 static struct file_operations router_fops =
 {
 	NULL,			/* lseek   */
@@ -179,7 +185,7 @@
 /*
  *	/proc/net/router 
  */
-
+ 
 static struct proc_dir_entry proc_router =
 {
 	0,			/* .low_ino */
@@ -267,8 +273,7 @@
 {
 	int err = proc_register(proc_net, &proc_router);
 
-	if (!err)
-	{
+	if (!err) {
 		proc_register(&proc_router, &proc_router_conf);
 		proc_register(&proc_router, &proc_router_stat);
 	}
@@ -294,7 +299,7 @@
 {
 	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;
@@ -331,7 +336,7 @@
 
 /*
  *	Read router proc directory entry.
- *	This is universal routine for reading all entries in /proc/net/router
+ *	This is universal routine for reading all entries in /proc/net/wanrouter
  *	directory.  Each directory entry contains a pointer to the 'method' for
  *	preparing data for that entry.
  *	o verify arguments
@@ -365,8 +370,7 @@
 		
 	pos = dent->get_info(page, dent->data, 0, 0, 0);
 	offs = file->f_pos;
-	if (offs < pos)
-	{
+	if (offs < pos) {
 		len = min(pos - offs, count);
 		if(copy_to_user(buf, (page + offs), len))
 			return -EFAULT;
@@ -391,15 +395,14 @@
 	strcpy(buf, conf_hdr);
 	for (wandev = router_devlist;
 	     wandev && (cnt < (PROC_BUFSZ - 120));
-	     wandev = wandev->next)
-	{
+	     wandev = wandev->next) {
 		if (wandev->state) cnt += sprintf(&buf[cnt],
 			"%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n",
 			wandev->name,
 			wandev->ioport,
 			wandev->irq,
 			wandev->dma,
-			virt_to_phys(wandev->maddr),
+			wandev->maddr,
 			wandev->msize,
 			wandev->hw_opt[0],
 			wandev->hw_opt[1],
@@ -418,13 +421,16 @@
 static int status_get_info(char* buf, char** start, off_t offs, int len, 
 			int dummy)
 {
-	int cnt = sizeof(stat_hdr) - 1;
+	int cnt = 0;
 	wan_device_t* wandev;
-	strcpy(buf, stat_hdr);
+
+	cnt += sprintf(&buf[cnt], "\nSTATUS FOR PORT 0\n\n");
+	strcpy(&buf[cnt], stat_hdr);
+	cnt += sizeof(stat_hdr) - 1;
+
 	for (wandev = router_devlist;
 	     wandev && (cnt < (PROC_BUFSZ - 80));
-	     wandev = wandev->next)
-	{
+	     wandev = wandev->next) {
 		if (!wandev->state) continue;
 		cnt += sprintf(&buf[cnt],
 			"%-15s|%-7s|%-9s|%-8s|%9u|%5u|%3u |",
@@ -434,10 +440,10 @@
 			wandev->clocking ? "internal" : "external",
 			wandev->bps,
 			wandev->mtu,
-			wandev->ndev)
-		;
-		switch (wandev->state)
-		{
+			wandev->ndev);
+
+		switch (wandev->state) {
+
 		case WAN_UNCONFIGURED:
 			cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured");
 			break;
@@ -475,68 +481,73 @@
 {
 	wan_device_t* wandev = (void*)start;
 	int cnt = 0;
+	int rslt = 0;
 
 	if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC))
 		return 0;
 	if (!wandev->state)
-		return sprintf(&buf[cnt], "device is not configured!\n")
-	;
+		return sprintf(&buf[cnt], "Device is not configured!\n");
 
 	/* Update device statistics */
-	if (wandev->update) wandev->update(wandev);
+	if (wandev->update) {
+
+		rslt = wandev->update(wandev);
+		if(rslt) {
+			switch (rslt) {
+			case -EAGAIN:
+				return sprintf(&buf[cnt], "Device is busy!\n");
+
+			default:
+				return sprintf(&buf[cnt],
+					"Device is not configured!\n");
+			}
+		}
+	}
+
+        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+                "total packets received", wandev->stats.rx_packets);
+	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+                "total packets transmitted", wandev->stats.tx_packets);
+        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+                "total bytes received", wandev->stats.rx_bytes);
+        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+                "total bytes transmitted", wandev->stats.tx_bytes);
+        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+                "bad packets received", wandev->stats.rx_errors);
+       	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+                "packet transmit problems", wandev->stats.tx_errors);
+	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+                "received frames dropped", wandev->stats.rx_dropped);
+        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+                "transmit frames dropped", wandev->stats.tx_dropped);
+	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+                "multicast packets received", wandev->stats.multicast);
+        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+                "transmit collisions", wandev->stats.collisions);
+        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+                "receive length errors", wandev->stats.rx_length_errors);
+	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+		"receiver overrun errors", wandev->stats.rx_over_errors);
+	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+		"CRC errors", wandev->stats.rx_crc_errors);
+	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+		"frame format errors (aborts)", wandev->stats.rx_frame_errors);
+        cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+                "receiver fifo overrun", wandev->stats.rx_fifo_errors);
+	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+		"receiver missed packet", wandev->stats.rx_missed_errors);
+	cnt += sprintf(&buf[cnt], PROC_STATS_FORMAT,
+		"aborted frames transmitted", wandev->stats.tx_aborted_errors);
 
-	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
-		"total frames received", wandev->stats.rx_packets)
-	;
-	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
-		"receiver overrun errors", wandev->stats.rx_over_errors)
-	;
-	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
-		"CRC errors", wandev->stats.rx_crc_errors)
-	;
-	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
-		"frame length errors", wandev->stats.rx_length_errors)
-	;
-	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
-		"frame format errors", wandev->stats.rx_frame_errors)
-	;
-	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
-		"aborted frames received", wandev->stats.rx_missed_errors)
-	;
-	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
-		"reveived frames dropped", wandev->stats.rx_dropped)
-	;
-	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
-		"other receive errors", wandev->stats.rx_errors)
-	;
-	cnt += sprintf(&buf[cnt], "\n%30s: %12lu\n",
-		"total frames transmitted", wandev->stats.tx_packets)
-	;
-	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
-		"aborted frames transmitted", wandev->stats.tx_aborted_errors)
-	;
-	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
-		"transmit frames dropped", wandev->stats.tx_dropped)
-	;
-	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
-		"transmit collisions", wandev->stats.collisions)
-	;
-	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
-		"other transmit errors", wandev->stats.tx_errors)
-	;
 	return cnt;
 }
 
-/*
- *	End
- */
- 
 #else
 
 /*
  *	No /proc - output stubs
  */
- 
+
 __initfunc(int wanrouter_proc_init(void))
 {
 	return 0;
@@ -558,3 +569,8 @@
 }
 
 #endif
+
+/*
+ *	End
+ */
+ 
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/scripts/Menuconfig linux.14p16/scripts/Menuconfig
--- linux.vanilla/scripts/Menuconfig	Sat Aug 14 02:26:22 1999
+++ linux.14p16/scripts/Menuconfig	Thu Dec  9 15:34:39 1999
@@ -54,7 +54,7 @@
 # Change a lot of places to call set_x_info uniformly.
 # Take out message about preparing version (old sound driver cruft).
 #
-# 13 Dec 1998, Riley H Williams (rhw@bigfoot.com)
+# 13 Dec 1998, Riley H Williams <rhw@memalpha.cx>
 # When an error occurs, actually display the error message as well as
 # our comments thereon.
 #
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/scripts/ver_linux linux.14p16/scripts/ver_linux
--- linux.vanilla/scripts/ver_linux	Sat Aug 14 02:27:46 1999
+++ linux.14p16/scripts/ver_linux	Thu Dec  9 15:34:39 1999
@@ -27,6 +27,6 @@
 # while console-tools needs 'loadkeys -V'.
 loadkeys -V 2>&1 | awk \
 '(NR==1 && ($2 ~ /console-tools/)) {print "Console-tools         ", $3}'
-expr --v | awk '{print "Sh-utils              ", $NF}'
+expr --v | awk 'NR==1{print "Sh-utils              ", $NF}'
 X=`cat /proc/modules | sed -e "s/ .*$//"`
 echo "Modules Loaded         "$X
